在运行时更改语言的正确方法

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

  1. 使用这样的递归手动设置所有控件
  2. 将语言选择保存到文件>重新启动应用程序>在InitializeComponent();之前加载语言选项InitializeComponent();
  3. 使用Form构造函数替换active的实例(如果这是可能的话)
  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"); } 

什么都不做,Form保留在我在InitializeComponent();之前设置的语言中InitializeComponent();

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

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

 public class LocalizedForm : Form { ///  /// Occurs when current UI culture is changed ///  [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; ///  /// Current culture of this form ///  [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()) { form.Culture = value; } Thread.CurrentThread.CurrentUICulture = value; } } } 

我找到了另一种方式:

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

 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(); } 

我希望这有帮助 ;-)

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

 static class Program { private static bool doNotExit = true; private static FormMain fm; ///  /// The main entry point for the application. ///  [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(); } } 

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

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

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

 _myHeader.Text = myResourceFileName.columnHeader_myHeader; 

这将根据当前的线程文化选择适当的语言。 Hans是正确的,因为在.NET中执行本地化似乎并不是一种万无一失的“正确”方式,尽管您可以使用各种工具。 对于像工作申请这样的东西,即使这个建议可能已经太晚了,我的建议是学习尽可能多的不同方法进行本地化,学习利弊,然后选择一个系统并且能够争论为什么你认为这是“适当的”选择。 他们可能更关心你的逻辑和推理以及先前经验的certificate,而不是实际的方法。

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

  1. 将一个公共var保存在将保存lang的main上。
  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(); }