web-dev-qa-db-fra.com

Manière appropriée de changer la langue au moment de l'exécution

Quelle est la bonne façon de changer la langue du formulaire lors de l'exécution?

  1. Définir tous les contrôles manuellement en utilisant la récursion comme this
  2. Enregistrer le choix de langue dans un fichier> Redémarrer l'application> Charger le choix de langue avant InitializeComponent();
  3. Utilisation du constructeur Form pour remplacer l'instance de active from (si cela est même possible)
  4. Autre chose

Il y a tellement de discussions à moitié écrites à ce sujet, mais aucune ne fournit de véritable réponse sur la bonne façon de le faire?

MISE À JOUR:
Pour clarifier ma question:

Faire quelque chose comme ça:

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

fonctionne bien et tous mes contrôles et tout le reste dans les ressources sont traduits correctement. Et faire quelque chose comme:

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

ne fait rien, Form reste dans la langue que j'ai configurée avant InitializeComponent();

22
formatc

Je pense que la solution présentée dans le commentaire de Hans Passant pourrait être la seule solution (générale).

Personnellement, j'utilise cette classe de base pour tous les formulaires qui doivent être localisés:

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

Ensuite, au lieu de changer directement Thread.CurrentThread.CurrentUICulture, j'utilise cette propriété dans la classe du gestionnaire statique pour changer la culture de l'interface utilisateur:

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

J'ai trouvé un autre moyen:

Déplacer le code du formulaire d'initialisation dans une méthode privée comme ci-dessous

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

Dans le constructeur de formulaire, utilisez-le comme ceci

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

Et à partir de Button, menuItem ou d'une autre méthode d'appel comme celle-ci

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

J'espère que ça aide ;-)

4
Bosshog

J'ai découvert ce genre d'approche il y a quelques minutes. Redémarrage rapide et simple du formulaire principal. Meybe ça va aider quelqu'un. L'événement est créé à l'intérieur du formulaire par moi-même, appelé lorsque l'utilisateur sélectionne la langue dans le menu mais après que le nom de la culture sélectionnée est enregistré dans les paramètres. Les noms de culture sont ensuite chargés à partir de ces paramètres. Fonctionne exactement comme j'ai besoin et ressemble à une solution appropriée.

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

En référence à votre bogue de framework ColumnHeader .NET, j'ai également découvert ce bogue récemment et publié une question à ce sujet (à laquelle je n'ai reçu aucune réponse). J'ai pu résoudre le problème en codant en dur les modifications pour les ColumnHeaders. Par exemple:

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

Vous remplacez simplement l'appel à .Name par une chaîne littérale du nom. J'ai testé cela et cela fonctionne. Malheureusement, cela signifie qu'il ne rentrera pas dans le code que vous utilisez pour modifier tous les contrôles. Vous devrez ajouter une ligne pour chaque objet ColumnHeader que vous devez modifier. Si vous avez une vue de liste avec un nombre variable de colonnes, cela pourrait devenir délicat. Une autre option consiste à créer des fichiers de ressources localisés. Je suppose que vous les avez probablement déjà pour des choses comme le texte de la boîte de message et d'autres chaînes. Ensuite, vous pouvez ajouter une entrée dans votre fichier de ressources comme "columnHeader_myHeader" et définir le texte de langue approprié pour chaque langue. Enfin, vous pouvez modifier manuellement le texte de vos en-têtes de colonne en utilisant:

_myHeader.Text = myResourceFileName.columnHeader_myHeader;

Cela sélectionnera la langue appropriée en fonction de la culture de thread actuelle. Hans avait raison, car il ne semble pas y avoir de méthode "appropriée" à toute épreuve pour effectuer la localisation dans .NET, bien qu'il existe une variété d'outils que vous pouvez utiliser. Pour quelque chose comme une demande d'emploi, même s'il est probablement déjà trop tard pour ce conseil, ma suggestion serait d'apprendre autant de méthodes différentes que possible pour la localisation, d'apprendre les avantages et les inconvénients, puis de choisir un système et de pouvoir pour expliquer pourquoi vous croyez que c'est le "bon" choix. Ils sont probablement plus concernés par votre logique et votre raisonnement et votre démonstration d'une expérience antérieure que par la méthode actuelle.

0
Vaughanabe13

J'espère que cela aiderait n'importe qui, je l'ai trouvé le mieux pour moi car j'avais besoin de changer l'emplacement des boutons en fonction de la langue (parcourir à droite ou à gauche de la zone de recherche et des étiquettes à côté des champs de texte).

  1. enregistrer une var publique sur le principal qui contiendra la langue.
  2. créé une classe qui gère la partie visuelle
  3. créé des fichiers xml qui contiendront toutes les données de langue et plus (dans mon nom de balise xml = nom de l'objet).
  4. envoyé le constructeur de cette classe le formulaire (pour enregistrer et travailler avec)
  5. se connecter à ce fichier xml actuel

Depuis le formulaire principal, appelez quand vous voulez initialView (partie de la classe view) et changez lang (et plus) à tout moment (connectez-vous simplement au bon fichier 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;
    }
}

Et ceci est un exemple de la facilité avec laquelle je suis à l'exécution:

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