22

実行時にフォーム言語を変更する適切な方法は何ですか?

  1. このような再帰を使用してすべてのコントロールを手動で設定する
  2. 言語選択をファイルに保存>アプリケーションを再起動>前に言語選択をロードInitializeComponent();
  3. Formコンストラクターを使用してアクティブな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

ハンス・パッサントのコメントに示されている解決策が唯一の(一般的な)解決策かもしれないと私は信じています。

個人的には、ローカライズする必要があるすべてのフォームにこの基本クラスを使用します。

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

私は数分前にこの種のアプローチを発見しました。メインフォームをすばやく簡単に再起動します。たぶんそれは誰かに役立つでしょう。イベントはフォーム内に独自に作成され、ユーザーがメニューから言語を選択したときに呼び出されますが、選択したカルチャの名前が設定に保存された後に呼び出されます。次に、カルチャ名がその設定からロードされます。必要に応じて正確に機能し、適切なソリューションのように見えます。

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 Frameworkのバグに関連して、最近このバグを発見し、それに関する質問を投稿しました(これに対する回答はありません)。ColumnHeadersの変更をハードコーディングすることで、問題を修正することができました。例えば:

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

基本的には、.Nameの呼び出しを名前のリテラル文字列に置き換えるだけです。私はこれをテストしました、そしてそれは働きます。残念ながら、これは、すべてのコントロールを変更するために使用するコードの一部としては適合しないことを意味します。変更する必要のあるColumnHeaderオブジェクトごとに行を追加する必要があります。列数が可変のリストビューがある場合は、注意が必要です。もう1つのオプションは、ローカライズされたリソースファイルを作成することです。メッセージボックスのテキストやその他の文字列などのために、おそらくすでにそれらを持っていると思います。次に、「columnHeader_myHeader」などのエントリをリソースファイルに追加し、各言語に適切な言語テキストを設定できます。最後に、以下を使用して、テキストを列ヘッダーに手動で変更できます。

_myHeader.Text = myResourceFileName.columnHeader_myHeader;

これにより、現在のスレッドカルチャに基づいて適切な言語が選択されます。ハンスは、使用できるさまざまなツールがありますが、.NETでローカリゼーションを実行するための絶対確実な「適切な」方法がないように見えるという点で正しかったです。求人応募のようなものについては、おそらくこのアドバイスにはもう手遅れですが、私の提案は、ローカリゼーションのためにできるだけ多くの異なる方法を学び、長所と短所を学び、そしてシステムを選んでできるようにすることですそれが「適切な」選択であるとあなたが信じる理由を議論すること。彼らはおそらく、実際の方法よりも、あなたの論理と推論、そして以前の経験のデモンストレーションに関心があります。

于 2013-02-14T15:01:13.323 に答える
0

これが誰かに役立つことを願っています。言語に応じてボタンの位置を変更する必要があったので、私にとって最適だと思いました(検索ボックスの右または左とテキストフィールドの横のラベルを参照してください)。

  1. langを保持するメインのパブリック変数を保存します。
  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 に答える