Подтвердить что ты не робот

Правильный способ изменения языка во время выполнения

Каков правильный способ изменить язык формы во время выполнения?

  • Настройка всех элементов управления вручную с помощью рекурсии, например
  • Сохранить выбор языка в файле > Перезапустить приложение > Загрузить язык выбор до InitializeComponent();
  • Использование конструктора форм для замены экземпляра active из (если это возможно)
  • Что-то еще

Существует так много наполовину написанных нитей об этом, но никто не дает реального ответа на то, что является правильным способом для этого?

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

ничего не делает, форма остается в языке, который я установил до InitializeComponent();

4b9b3361

Ответ 1

Я считаю, что решение, показанное в комментарии 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 я использую это свойство в классе статического менеджера для изменения культуры пользовательского интерфейса:

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

Ответ 2

Я нашел другой способ:

Переместить код формы инициализации в закрытый метод, как показано ниже

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

Я надеюсь, что это поможет; -)

Ответ 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();   
    }
}

Ответ 4

В связи с вашей ошибкой Framework ColumnHeader.NET я также обнаружил эту ошибку недавно и разместил вопрос об этом (на который я не получил никаких ответов). Я смог исправить проблему, скопировав изменения для ColumnHeaders. Например:

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

В основном вы просто заменяете вызов на .Name буквенной строкой имени. Я тестировал это, и он работает. К сожалению, это означает, что он не будет входить в состав кода, который вы используете для изменения всех элементов управления. Вам нужно будет добавить строку для каждого объекта ColumnHeader, который необходимо изменить. Если у вас есть listview с переменным числом столбцов, это может стать сложным. Другой вариант - создать локализованные файлы ресурсов. Я предполагаю, что вы, вероятно, уже имеете их для таких вещей, как текст окна сообщения и другие строки. Затем вы можете добавить запись в свой файл ресурсов, например "columnHeader_myHeader", и установить соответствующий язык для каждого языка. Наконец, вы можете вручную изменить текст в заголовки столбцов, используя:

_myHeader.Text = myResourceFileName.columnHeader_myHeader;

Это позволит выбрать соответствующий язык, основанный на текущей культуре потоков. Ганс был прав в том, что, похоже, нет надежного "правильного" способа выполнить локализацию в .NET, хотя есть множество инструментов, которые вы можете использовать. Для чего-то вроде приложения для работы, хотя, вероятно, уже слишком поздно для этого совета, мое предложение состояло бы в том, чтобы узнать как можно больше различных методов, например, для локализации, узнать плюсы и минусы, а затем просто выбрать систему и уметь спорить, почему вы считаете, что это "правильный" выбор. Вероятно, они больше связаны с вашей логикой, рассуждениями и демонстрацией предыдущего опыта, чем с фактическим методом.

Ответ 5

Надеюсь, это помогло бы кому-нибудь, я счел это лучшим для меня, потому что мне нужно было изменить расположение кнопок в соответствии с lang (просмотрите справа или слева от поля поиска и метки рядом с текстовыми полями).

  • сохранить публичный var на главном, который будет удерживать lang.
  • создал класс, который обрабатывает визуальную часть
  • созданный xml файл, в котором будут храниться любые языковые данные и более (в моем имени тега xml = имя объекта).
  • отправил этот конструктор класса в форму (для сохранения и работы)
  • подключиться к текущему файлу xml

От вызова основной формы всякий раз, когда вы хотите инициализировать (часть класса представления) и меняете 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();
}