22

在运行时更改表单语言的正确方法是什么?

  1. 像这样使用递归手动设置所有控件
  2. 将语言选择保存到文件 > 重新启动应用程序 > 加载语言选择之前InitializeComponent();
  3. 使用 Form 构造函数替换 active from 的实例(如果可能的话)
  4. 别的东西

关于这个有很多半写的线程,但没有一个提供真正的答案来说明什么是正确的方法?

更新:
澄清我的问题:

做这样的事情:

public Form1()
{
    Thread.CurrentThread.CurrentUICulture = new CultureInfo("de");
    this.InitializeComponent();
}

工作正常,我的所有控件和资源中的所有其他内容都得到正确翻译。并做类似的事情:

private void button1_Click(object sender, EventArgs e)
{
    Thread.CurrentThread.CurrentUICulture = new CultureInfo("en");
}

什么都不做,表单保持我之前设置的语言InitializeComponent();

4

5 回答 5

27

我相信 Hans Passant 的评论中显示的解决方案可能是唯一的(一般)解决方案。

就个人而言,我将这个基类用于所有需要本地化的表单:

public class LocalizedForm : Form
{
    /// <summary>
    /// Occurs when current UI culture is changed
    /// </summary>
    [Browsable(true)]
    [Description("Occurs when current UI culture is changed")]
    [EditorBrowsable(EditorBrowsableState.Advanced)]
    [Category("Property Changed")]
    public event EventHandler CultureChanged;

    protected CultureInfo culture;
    protected ComponentResourceManager resManager;

    /// <summary>
    /// Current culture of this form
    /// </summary>
    [Browsable(false)]
    [Description("Current culture of this form")]
    [EditorBrowsable(EditorBrowsableState.Never)]
    public CultureInfo Culture
    {
        get { return this.culture; }
        set
        {
            if (this.culture != value)
            {
                this.ApplyResources(this, value);

                this.culture = value;
                this.OnCultureChanged();
            }
        }
    }

    public LocalizedForm()
    {
        this.resManager = new ComponentResourceManager(this.GetType());
        this.culture = CultureInfo.CurrentUICulture;
    }

    private void ApplyResources(Control parent, CultureInfo culture)
    {
        this.resManager.ApplyResources(parent, parent.Name, culture);

        foreach (Control ctl in parent.Controls)
        {
            this.ApplyResources(ctl, culture);
        }
    }

    protected void OnCultureChanged()
    {
        var temp = this.CultureChanged;
        if (temp != null)
            temp(this, EventArgs.Empty);
    }
}

然后,我没有直接更改Thread.CurrentThread.CurrentUICulture,而是在静态管理器类中使用此属性来更改 UI 文化:

public static CultureInfo GlobalUICulture
{
    get { return Thread.CurrentThread.CurrentUICulture; }
    set
    {
        if (GlobalUICulture.Equals(value) == false)
        {
            foreach (var form in Application.OpenForms.OfType<LocalizedForm>())
            {
                form.Culture = value;
            }

            Thread.CurrentThread.CurrentUICulture = value;
        }
    }
}
于 2012-07-31T11:19:10.573 回答
6

我找到了另一种方法:

在私有方法中移动初始化表单代码,如下所示:

private void FormInitialize() {/*Your code here*/}

在表单构造函数中像这样使用它:

public Form1()
{
    InitializeComponent();
    FormInitialize();
}

从 Button、menuItem 或其他调用方法,如下所示:

private void ChangeCultureToFrench_Click(object sender, EventArgs e)
{
    Thread.CurrentThread.CurrentUICulture = new CultureInfo("fr");
    this.Controls.Clear();
    this.InitializeComponent();
    FormInitialize();
}

我希望这有帮助 ;-)

于 2013-09-27T10:32:11.973 回答
3

几分钟前我发现了这种方法。只需快速简单地重新启动主窗体。Meybe它会帮助某人。事件是在我自己的表单内创建的,当用户从菜单中选择语言但将所选文化的名称保存到设置中时调用。然后从该设置中加载文化名称。完全按照我的需要工作,看起来像正确的解决方案。

static class Program
{
    private static bool doNotExit = true;
    private static FormMain fm;
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {


        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        while(doNotExit)
        {
            System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo(Properties.Settings.Default.language);//
            System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo(Properties.Settings.Default.language);//

            doNotExit = false;
            fm = new FormMain();
            fm.lanugageChangedEvent += new EventHandler(main_LanugageChangedEvent);
            Application.Run(fm);
        }
    }



    static void main_LanugageChangedEvent(object sender, EventArgs e)
    {  
        doNotExit = true;
        fm.Close();   
    }
}
于 2013-05-05T23:44:11.900 回答
0

关于您的 ColumnHeader .NET 框架错误,我最近也发现了这个错误并发布了一个关于它的问题(我没有收到任何回复)。我能够通过硬编码 ColumnHeaders 的更改来解决问题。例如:

resources.ApplyResources(_myHeader, "_myHeader", culture);

您基本上只需用名称的文字字符串替换对 .Name 的调用。我已经对此进行了测试,并且可以正常工作。不幸的是,这意味着它不适合作为您用于更改所有控件的代码的一部分。您必须为需要更改的每个 ColumnHeader 对象添加一行。如果您有一个列数可变的列表视图,那可能会变得很棘手。另一种选择是创建本地化的资源文件。我假设您可能已经将它们用于消息框文本和其他字符串等内容。然后,您可以在资源文件中添加一个条目,例如“columnHeader_myHeader”,并为每种语言设置适当的语言文本。最后,您可以使用以下方法手动将文本更改为列标题:

_myHeader.Text = myResourceFileName.columnHeader_myHeader;

这将根据当前线程文化选择适当的语言。Hans 是正确的,在 .NET 中执行本地化似乎没有万无一失的“正确”方法,尽管您可以使用多种工具。对于工作申请之类的事情,即使这个建议可能已经太迟了,我的建议是尽可能多地学习不同的本地化方法,了解优缺点,然后选择一个系统并能够争论为什么你认为这是“正确”的选择。他们可能更关心你的逻辑、推理和对先前经验的证明,而不是实际的方法。

于 2013-02-14T15:01:13.323 回答
0

希望这对任何人都有帮助,我发现它最适合我,因为我需要根据语言更改按钮位置(在搜索框的右侧或左侧浏览以及文本字段旁边的标签)。

  1. 在将保存 lang 的 main 上保存一个公共 var。
  2. 创建了一个处理视觉部分的类
  3. 创建的 xml 文件将包含任何语言数据和更多(在我的 xml 标记名称=对象名称中)。
  4. 向该类的构造函数发送表单(以保存和使用)
  5. 连接到当前的 xml 文件

每当您想要initialView(视图类的一部分)并随时更改lang(以及更多)时,从主窗体调用(只需连接到正确的xml文件):

public void initialView()
{
    //Set rightToLeft values
    initialIndent(mainForm);

    //set visual text values
    initialTxt();
}

private void initialTxt()
{
    // Are there any more controls under mainObj (Form1)?
    Boolean endOfElemsUnderPnl = false;

    // The current Control im working on
    Object curObj = mainForm;

    do
    {
        // MenuStrip needs to be handled separately
        if (typeof(MenuStrip).ToString().Equals(curObj.GetType().ToString()))
        {
            foreach (ToolStripMenuItem miBase in ((MenuStrip)(curObj)).Items)
            {
                miBase.Text = mainForm.dbCon.getData(miBase.Name.ToString());
                foreach (ToolStripMenuItem miInnerNode in miBase.DropDownItems)
                {
                    miInnerNode.Text = mainForm.dbCon.getData(miInnerNode.Name.ToString());
                }
            }
        }

        // Any other Control i have on the form
        else
        {
            ((Control)(curObj)).Text = mainForm.dbCon.getData(((Control)(curObj)).Name.ToString());
        }

        curObj = mainForm.GetNextControl(((Control)(curObj)), true);

        // Are there any more controls under mainObj?
        if (null == curObj)
        {
            endOfElemsUnderPnl = true;
        }

    } while (!endOfElemsUnderPnl);
}

private void initialIndent(frmMyFileManager parent)
{
    if (parent.Language.Equals("Hebrew"))
    {
        parent.RightToLeft = RightToLeft.Yes;
    }
    else if (parent.Language.Equals("English"))
    {
        parent.RightToLeft = RightToLeft.No;
    }
    else
    {
        parent.RightToLeft = RightToLeft.No;
    }
}

这是我在运行时多么容易的一个例子:

private void selectLanguageToolStripMenuItem_Click(object sender, EventArgs e)
{
    DialogResult res = MessageBox.Show(this, "click yes for english and no for hebrew", "Select language", MessageBoxButtons.YesNoCancel);

    if (DialogResult.Yes == res)
    {
        Language = "English";
    }
    else if (DialogResult.No == res)
    {
        Language = "Hebrew";
    }
    dbCon = new CDBConnector("****\\lang" + Language + ".xml");
    view.initialView();
}
于 2013-12-06T00:21:28.080 回答