3

问题:

我有一个在 Windows 7 上开发的 C# .NET 2.0 应用程序,它已经翻译了多种语言的资源(例如zh-CHS用于中文,es用于西班牙语等)。

我有一个客户想要用英语运行他们的 Windows 7 操作系统,但用西班牙语 ( es ) 运行我的 .NET 应用程序。

我的应用程序是多线程的,所以仅仅改变主 GUI 线程的文化并不足以满足我的需求(相信我,我试过了)。这是因为通过 GUI 向用户显示的其他字符串是在其他线程上生成的。为了获得 100% 的完整覆盖率,我需要手动设置每个单独线程的文化,以确保资源文件中的所有文本都使用正确的语言。因为我的产品基本上是其他开发组编写的其他插件的框架,所以我无法控制在其他插件中创建的线程中执行的操作。因此,手动更改每个线程的区域性不是一个有效的选项。

我正在寻找的是一种为应用程序设置整体语言的方法,而无需更改任何操作系统用户设置。

在做一些研究时,我遇到了以下为进程设置首选 UI 语言的方法:SetProcessPreferredUILanguages

在阅读了这个之后,看来这个电话是我正在寻找的。但是,当我在 C# 应用程序的 Main 方法中实现此调用时,它似乎没有做任何事情。

以下代码的返回值为 true,但我从未看到我的 GUI 应用程序以西班牙语显示文本。

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

为了成功运行加载了西班牙资源的 GUI 应用程序,我还缺少其他什么吗?

我正在尝试为Building MUI Applications实现 MSDN 页面底部表格的第二个选项,其中我有特定于应用程序的 UI 语言设置,并希望实现资源加载所需的结果:

应用程序调用 MUI API 来设置应用程序特定的 UI 语言或进程首选的 UI 语言,然后调用标准资源加载函数。资源以应用程序或系统语言设置的语言返回。

我已调用成功设置流程首选 UI 语言,但我的资源没有以我期望的语言加载。一位评论者提到此调用仅适用于非托管资源,我无法 100% 验证,但行为似乎表明情况确实如此。

我不可能是唯一一个尝试过以这种方式实现 .NET 应用程序的人。令人沮丧的是,没有更多关于如何执行此操作的信息。

提前致谢,

凯尔

4

3 回答 3

0

根据此处的反馈和其他研究,我得出的结论是,使用 4.5 之前的 .NET 版本无法为多线程 .NET 应用程序设置独立于操作系统语言的文化。

这真是一种耻辱。

我们最近升级了我们的软件以使用 .NET 4.0。

于 2011-12-06T17:24:00.700 回答
0

您的代码有一些问题。不幸的是,问题的修复并没有带来所要求的行为。

代码应该是:

[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),字符串以零字符结尾(无需使用 unicode 转义序列),列表以双零字符结尾(因此是新的“空语言”;其他方法是将双 \0 放在最后一种语言)。我还添加了新的调试描述,以测试当前设置的语言,但不幸的是我无法在这里(工作中)测试它,因为该功能需要 Win7。


但是有一种完全不同的方法可以做到这一点。请参阅AppLocale

我不能保证它会在你的情况下工作。该应用程序需要Windows XP 及更新版本(在Windows 7 上安装有一个小问题;记得以管理员模式开始安装,否则无法运行)。该应用程序还有另一个更大的问题。从中欧转向西方是不可能的。但它适用于从中欧到希腊,以及其他具有不同特征的国家。

我使用此应用程序为某些国家/地区开发较旧的(非 unicode)应用程序。不幸的是,它在开始时给出了一个麻烦的警告......

于 2013-11-06T08:30:45.997 回答
0

从 .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 多线程应用程序。

我知道您不想改变每个新线程的文化,但我想不出任何其他有效的替代方案。

于 2012-08-10T15:06:23.763 回答