web-dev-qa-db-ja.com

実行時に言語を変更する適切な方法

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

  1. this のような再帰を使用してすべてのコントロールを手動で設定する
  2. 言語選択をファイルに保存>アプリケーションを再起動> InitializeComponent();の前に言語選択をロード
  3. Formコンストラクターを使用して、アクティブfromのインスタンスを置き換えます(可能な場合)
  4. 他の何か

これについて書かれたスレッドは非常に多くありますが、これを行う適切な方法について本当の答えを提供するものはありませんか?

UPDATE:
私の質問を明確にするには:

このようなことをする:

_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();の前に設定した言語のままです

22
formatc

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

別の方法を見つけました:

以下のようにプライベートメソッドで初期化フォームコードを移動します

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

これが役立つことを願っています;-)

4
Bosshog

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

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

ColumnHeader .NETフレームワークのバグを参照して、最近このバグを発見し、それについて質問を投稿しました(返信はありません)。 ColumnHeadersの変更をハードコーディングすることで問題を修正できました。例えば:

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

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

_myHeader.Text = myResourceFileName.columnHeader_myHeader;

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

0
Vaughanabe13

これが誰にも役立つことを願っていますが、私は言語に応じてボタンの場所を変更する必要があるため、私にとって最適であることがわかりました(検索ボックスの右側または左側のブラウズとテキストフィールドの隣のラベル)。

  1. 言語を保持するメインのパブリック変数を保存します。
  2. 視覚部分を処理するクラスを作成しました
  3. 言語データを保持するxmlファイルを作成しました以上(私のxmlタグ名=オブジェクト名)。
  4. そのクラスのコンストラクタにフォームを送信しました(保存して操作するため)
  5. その現在のxmlファイルに接続します

InitialView(ビュークラスの一部)およびlang(and more)をいつでも変更したい場合(メインの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();
}
0
Avishay