Как установить язык пользовательского интерфейса для многопоточного процесса .NET, независимо от языка ОС? - PullRequest
2 голосов
/ 29 ноября 2011

Проблема:

У меня есть приложение C # .NET 2.0, разработанное для Windows 7, которое переводит ресурсы на несколько языков (например, zh-CHS для китайского языка)., es для испанского и т. Д.).

У меня есть клиент, который хочет запустить свою ОС Windows 7 на английском языке, но запустить приложение .NET на испанском языке ( es ).

Мое приложение является многопоточным, поэтому простого изменения культуры основного потока графического интерфейса недостаточно для моих нужд (поверьте, я пытался).Это связано с тем, что другие строки, отображаемые пользователю через графический интерфейс, генерируются в других потоках.Чтобы получить 100% полное покрытие, мне нужно было бы вручную настроить культуру каждого отдельного потока, чтобы гарантировать, что весь текст из файлов ресурсов будет на правильном языке.Поскольку мой продукт в основном является основой для других плагинов, которые пишут другие группы разработчиков, я не могу контролировать действия, выполняемые в потоках, созданных в других плагинах.Из-за этого ручное изменение культуры для каждого потока недопустимо.

То, что я ищу, - это способ установки общего языка для приложения без необходимости изменениялюбые пользовательские настройки ОС.

В ходе некоторых исследований я наткнулся на следующий метод установки предпочтительного языка пользовательского интерфейса для процесса: SetProcessPreferredUILanguages ​​

После прочтения этого кажется, что этоЗвонок это то, что я ищу.Однако, когда я реализовал этот вызов в методе Main моего приложения C #, он, похоже, ничего не делает.

Возвращаемое значение из следующего кода - true, но я никогда не вижу, чтобы мое приложение с графическим интерфейсом отображалотекст на испанском языке.

    [DllImport("Kernel32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
    public static extern Boolean SetProcessPreferredUILanguages(UInt32 dwFlags, String pwszLanguagesBuffer, ref UInt32 pulNumLanguages);

    public void SetLanguages()
    {
        uint numLangs = 0;
        string[] langs = new string[3];
        uint MUI_LANGUAGE_NAME = 0x8; // Use ISO language (culture) name convention

        langs[0] = "es\u0000";
                langs[1] = "zh-CHS\u0000";
        langs[2] = "en-US\u0000";

        numLangs = (uint)langs.Length;

        if (SetProcessPreferredUILanguages(MUI_LANGUAGE_NAME, String.Concat(langs), ref numLangs))
        {
            Console.WriteLine("Successfully changed UI language");
        }
    }

Есть ли что-то еще, чего мне не хватает для успешного запуска моего приложения с графическим интерфейсом с загруженными испанскими ресурсами?

Я пытаюсь реализовать второй вариант таблицы в нижней части страницы MSDN для Создание приложений MUI , где у меня есть настройки языка пользовательского интерфейса для конкретного приложения и я хочу достичь желаемогорезультат для загрузки ресурса:

Приложение вызывает MUI API для установки специфичных для приложения языков пользовательского интерфейса или предпочитаемых процессом языков пользовательского интерфейса, а затем вызывает стандартные функции загрузки ресурса.Ресурсы возвращаются на языках, установленных языками приложения или системы.

Я позвонил, чтобы успешно установить предпочтительные языки пользовательского интерфейса процесса, но мои ресурсы не загружаются на этом языкеЯ бы ожидал.Комментатор упомянул, что этот вызов будет работать только для неуправляемых ресурсов, которые я не могу проверить на 100%, но поведение, по-видимому, указывает на то, что это так.

Я не могу быть единственным человеком, который когда-либо пытался реализовать приложение .NET таким способом.Обидно, что больше нет информации о том, как это сделать.

Заранее спасибо,

Кайл

Ответы [ 3 ]

0 голосов
/ 10 августа 2012

Начиная с .NET 4.5, свойство CultureInfo.DefaultThreadCurrentCulture позволяет установить культуру по умолчанию для потоков в текущем домене приложения.Кроме этого я не нашел способ сделать это элегантно.

Вот код, который покажет вам, как воспроизвести это поведение:

using System;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;

namespace SimpleMultithreadedTestForCulture {

  class Program {

    static void Main() {
      const double value = 12345.78;
      Console.WriteLine("Value from local thread - default culture: {0}", value.ToString("C"));
      CultureInfo myCulture = new CultureInfo(Thread.CurrentThread.CurrentUICulture.Name);
      myCulture.NumberFormat.CurrencySymbol = "₤";
      Thread.CurrentThread.CurrentUICulture = myCulture;
      Thread.CurrentThread.CurrentCulture = myCulture;
      Console.WriteLine("Value from local thread - 'my' culture: {0}", value.ToString("C"));
      Task.Factory.StartNew(() => Console.WriteLine("Value from a different thread: {0}", value.ToString("C")));
      Console.ReadKey();
    }

  }

}

Вывод:

Value from local thread - default culture: $12,345.78
Value from local thread - 'my' culture: £12,345.78
Value from a different thread: $12,345.78

Вот связанный вопрос с возможным решением для .NET 4.0 или более ранней версии, используя вспомогательный класс для создания ваших потоков.Несмотря на то, что там говорится о WPF, это относится и к другим многопоточным приложениям .NET.

Я знаю, что вы не хотели менять культуру для каждого из новых потоков, но я не могу думать ни о какихдругие эффективные альтернативы для него.

0 голосов
/ 06 ноября 2013

Ваш код имеет несколько проблем. К сожалению, исправление проблем не приносит запрашиваемого поведения.

Код должен быть:

[DllImport("Kernel32.dll", ExactSpelling = true, CharSet = CharSet.Unicode)]
public static extern Boolean SetProcessPreferredUILanguages(UInt32 dwFlags,
  String pwszLanguagesBuffer, ref UInt32 pulNumLanguages);

public void SetLanguages()
{
  uint numLangs = 0;
  string[] langs = new string[4];
  uint MUI_LANGUAGE_NAME = 0x8; // Use ISO language (culture) name convention

  langs[0] = "es\0";
  langs[1] = "zh-CHS\0";
  langs[2] = "en-US\0";
  langs[3] = "\0"; //double null ending

  numLangs = (uint)langs.Length;

  if (SetProcessPreferredUILanguages(MUI_LANGUAGE_NAME, String.Concat(langs), ref numLangs))
  {
    if (numLangs == langs.Length - 1)
      Console.WriteLine("Successfully changed UI language");
    else if (numLangs < 1)
      Console.WriteLine("No language could be set");
    else
      Console.WriteLine("Not all languages were set");
  }
  else
    Console.WriteLine("No language could be set");
}

pwszLanguagesBuffer определен как PCZZWSTR, и это означает список широкой строки (следовательно, Charset.Unicode) , конец строки нулевым символом ( нет необходимости использовать escape-последовательность Юникода) , список заканчивается двойным нулевым символом (поэтому новый «пустой язык»; другой способ - поставить двойной \ 0 на последний язык) . Я также добавил новое описание отладки, чтобы протестировать установленные на данный момент языки, но, к сожалению, я не могу проверить его здесь (на работе), потому что функция нуждается в Win7.


Но есть совершенно другой способ, как это сделать. См AppLocale

Не могу дать гарантию, что это будет работать в вашем случае. Приложению требуется Windows XP и новее (существует небольшая проблема при установке в Windows 7; не забудьте запустить установку в режиме администратора, иначе она не будет работать) . Приложение имеет еще одну, более серьезную проблему. Невозможно переключиться с Центральной Европы на Западную. Но он работает от Центральной Европы до Греции и других стран с разными персонажами.

Я использую это приложение для разработки более старого (не Unicode) приложения для некоторых стран. К сожалению, это дает неприятное предупреждение при запуске ...

0 голосов
/ 06 декабря 2011

Основываясь на полученных здесь отзывах и других исследованиях, я пришел к выводу, что установка культуры для многопоточного .NET-приложения, независимого от языка ОС, невозможна при использовании .NET-версий старше 4.5.

Это действительно позор.

Недавно мы обновили наше программное обеспечение до версии .NET 4.0.

...