2012-07-29 43 views
18

¿Cuál es la forma correcta de cambiar el idioma del formulario en el tiempo de ejecución?Forma correcta de cambiar el idioma en el tiempo de ejecución

  1. Ajuste todos los controles de forma manual utilizando la recursividad como this
  2. Guardar elección de idioma para presentar> Reiniciar aplicación> Carga Languge elección antes InitializeComponent();
  3. Usando Formulario constructor para sustituir a instancia de activo a partir de (si esto es posible)
  4. Algo más

Hay por lo tanto hilos medio escribir sobre esto, pero no proporcionan s respuesta real sobre cuál es la forma correcta de hacer esto?

ACTUALIZACIÓN:
Para aclarar mi pregunta:

Hacer algo como esto:

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

funciona bien y todos mis controles y todo lo demás en los recursos se traducen correctamente. Y hacer algo como:

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

no hace nada, la forma queda en la lengua He definido antes InitializeComponent();

+0

posible duplicado de [¿Cómo puedo cambiar la cultura de una aplicación WinForms en tiempo de ejecución] (http://stackoverflow.com/questions/7556367/how-do-i-change-the-culture-of-a- winforms-application-at-runtime) –

+2

@Hans Esto no es un duplicado, mi pregunta es: ¿cuál es la manera correcta de hacerlo? La pregunta a la que se vinculó solo ofrece una solución rápida y no es una respuesta real. – formatc

+1

¿Qué demonios está mal con una "solución rápida"? La mayoría de los programadores los favorecen con un rediseño completo del marco. Supongo que asumes que esto debería ser una función incorporada para Winforms. No lo es. Solo la capacidad de aplicar "soluciones rápidas" es una función de diseño. –

Respuesta

20

Creo que la solución que se muestra en el comentario de Hans Passant podría ser la única solución (general).

Personalmente, yo uso esta clase base para todas las formas que necesitan ser localizado:

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

A continuación, en lugar de cambiar directamente Thread.CurrentThread.CurrentUICulture, utilizo esta propiedad en la clase estática gestor de cambiar cultural de IU:

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; 
     } 
    } 
} 
+0

@mnm ¡Gracias, se ve bien! – formatc

+11

Tenga en cuenta que no recorre completamente el árbol de control si solo recorre "parent.Controls". Un TabControl por ejemplo mantiene sus tabPages en "parent.TabPages". Un MenuStrip tiene sus elementos en "parent.Items". Y así. – Chrigl

0

En relación a su ColumnHeader .NET insecto marco, también descubrió este error y recientemente ha publicado una pregunta al respecto (a la que no he recibido ninguna respuesta). Pude solucionar el problema codificando los cambios para ColumnHeaders. Por ejemplo:

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

Es, básicamente, basta con sustituir la llamada a .name con una cadena literal del nombre. Lo he probado y funciona. Desafortunadamente, esto significa que no se ajustará como parte del código que usa para cambiar todos los controles. Deberá agregar una línea para cada objeto ColumnHeader que necesite cambiar. Si tiene una vista de lista con una cantidad variable de columnas, podría ser complicado. Otra opción es crear archivos de recursos localizados. Supongo que probablemente ya los tengas para cosas como el texto del cuadro de mensaje y otras cadenas. Luego puede agregar una entrada en su archivo de recursos como "columnHeader_myHeader" y establecer el texto de idioma apropiado para cada idioma. Por último, puede cambiar manualmente el texto a sus títulos de las columnas mediante el uso de:

_myHeader.Text = myResourceFileName.columnHeader_myHeader; 

Esto seleccionará el idioma adecuado en función de la cultura hilo actual. Hans tenía razón en que no parece haber una manera "apropiada" de realizar la localización en forma infalible.NET, aunque hay una variedad de herramientas que puede usar. Para algo así como una solicitud de trabajo, aunque probablemente ya sea demasiado tarde para este consejo, mi sugerencia sería aprender tantos métodos diferentes como sea posible para la localización, conocer los pros y los contras, y luego simplemente elegir un sistema y poder para argumentar por qué cree que es la opción "correcta". Probablemente estén más preocupados con su lógica, razonamiento y demostración de experiencia previa que con el método real.

1

Descubrí este tipo de enfoque hace unos minutos. Solo reinicio rápido y simple del formulario principal. Meybe ayudará a alguien. El evento se crea dentro del formulario por mi cuenta, se llama cuando el usuario selecciona el idioma del menú, pero después de que el nombre de la cultura seleccionada se guarda en la configuración. Los nombres de cultura se cargan desde esa configuración. Funciona exactamente como lo necesito y se ve como una solución adecuada.

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

he encontrado otra manera:

Mover código del formulario de inicialización en la méthode privada, como a continuación

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

En forma constructor de utilizar de esta manera

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

Y desde Button, menuItem u otro método de llamada como esto

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

Espero que esto ayude ;-)

0

la esperanza que esto ayudaría a nadie, he encontrado que es mejor para mí porque yo tenía que cambiar los botones según la ubicación lang (ver a la derecha oa la izquierda de el cuadro de búsqueda y las etiquetas junto a los campos de texto).

  1. guarde una var pública en la principal que sostendrá la lang.
  2. creado una clase que se encarga de la parte visual
  3. archivos XML creados que contendrán todos los datos de lenguaje y más (en mi etiqueta XML name = nombre del objeto).
  4. envió el constructor de la clase la forma (para guardar y trabajar con)
  5. conectarse a ese archivo actual xml

De llamada principal forma cada vez que desee initialView (parte de la clase de vista) y cambie lang (y más) en cualquier momento (sólo tiene que conectar al archivo XML derecha):

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

y esto es un ejemplo de lo fácil que es para mi en tiempo de ejecución:

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