【问题标题】:C# Single-Assembly Multilanguage App - Resources not being loaded properlyC# 单程序集多语言应用程序 - 资源未正确加载
【发布时间】:2013-04-30 15:55:28
【问题描述】:

我正在开发一个简单的 C# .NET 4.0 应用程序,并希望将其本地化为多种语言。但是,为本地化创建的附属程序集(即 de/MyApp.resources.dll)会因为必须在这些 dll 及其文件夹周围拖动而破坏其简单性。

这就是为什么我寻找一种方法将这些 dll 包含到主(也是唯一的)程序集中,因此只需将可执行文件发送给最终用户。我遇到了this very promising question 并试了一下。

在采用建议的解决方案中的类后,我在预构建命令中使用 FART 将 .Designer.cs 文件中的所有 ResourceManager 替换为 SingleAssemblyResourceManager:

fart.exe "$(ProjectDir)*.Designer.cs "System.ComponentModel.ComponentResourceManager" "SingleAssemblyComponentResourceManager"

然后我像这样创建了一个批处理文件:

"%ProgramFiles%\ILRepack.exe" /t:exe /out:%1TempProg.exe %1%2.exe %1es\%2.resources.dll 
IF %ERRORLEVEL% NEQ 0 GOTO END

"%ProgramFiles%\ILRepack.exe" /t:exe /out:%1TempProg2.exe %1TempProg.exe %1de\%2.resources.dll
IF %ERRORLEVEL% NEQ 0 GOTO END

"%ProgramFiles%\ILRepack.exe" /t:exe /out:%1SA_%2.exe %1TempProg2.exe %1tr\%2.resources.dll 
IF %ERRORLEVEL% NEQ 0 GOTO END

del %1%2.exe 
del %1%2.pdb 
del %1TempProg.exe
del %1TempProg.pdb
del %1TempProg2.exe 
del %1TempProg2.pdb 
rmdir %1es /S /Q 
rmdir %1de /S /Q 
rmdir %1tr /S /Q 

:END 

并从构建后命令中调用它:

$(ProjectDir)postbuild.bat $(TargetDir) $(TargetName)

注意:在这种情况下,TargetName 和 ProjectName 是相同的。

已成功构建,但未按预期工作...表单应以 InstalledUICulture 语言(如果可用)显示。为此,我在 InitializeComponent() 之前添加了这一行:

Thread.CurrentThread.CurrentUICulture = CultureInfo.InstalledUICulture;

在程序的“标准”版本中发挥了作用。不再。然而!我还添加了一个小控件,通过 ComboBox 在运行时更改语言。代码如下:

private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
  if (comboBox1.SelectedItem.ToString() == "English (Default)")
    {
      Thread.CurrentThread.CurrentUICulture = new CultureInfo("en");
      ChangeLanguage("en");
    }
  else if (comboBox1.SelectedItem.ToString() == "Español")
    {
      Thread.CurrentThread.CurrentUICulture = new CultureInfo("es");
      ChangeLanguage("es");
    }
    else if (comboBox1.SelectedItem.ToString() == "Deutsch")
    {
      Thread.CurrentThread.CurrentUICulture = new CultureInfo("de");
      ChangeLanguage("de");
    }
    else if (comboBox1.SelectedItem.ToString() == "Turkce")
    {
      Thread.CurrentThread.CurrentUICulture = new CultureInfo("tr");
      ChangeLanguage("tr");
    }
}

private void ChangeLanguage(string lang)
{
  foreach (Control c in this.Controls)
  {
    SingleAssemblyComponentResourceManager resources = new SingleAssemblyComponentResourceManager(typeof(Form1));
    resources.ApplyResources(c, c.Name, new CultureInfo(lang));
    if (c.ToString().StartsWith("System.Windows.Forms.GroupBox"))
    {
      foreach (Control child in c.Controls)
      {
          SingleAssemblyComponentResourceManager resources_child = new SingleAssemblyComponentResourceManager(typeof(Form1));
          resources_child.ApplyResources(child, child.Name, new CultureInfo(lang));
      }
    }
  }
}

确实改变了表单语言。所以dll实际上包含在exe中。那么,为什么 InitializeComponent 不加载适当的资源呢?我检查了 Designer 代码,ResourceManager 已被 SingleAssemblyResourceManager 替换。

此外,除了表单按钮的文本之外,我还有一个针对 MessageBoxes 和诸如此类的语言的 strings.resx 文件,而且这两种方式似乎都不起作用。但这可能是另一个问题。

我知道最初的解决方案是为 NET 2.0 环境设计的,并且 ResourceSets 已经过时,但我的理解是它应该工作,即使它不推荐。

任何关于我应该研究的地方的指针都很棒。

【问题讨论】:

    标签: visual-studio-2010 .net-4.0 localization ilmerge resourcemanager


    【解决方案1】:

    事实证明,我最终能够使它工作,稍微修改 CurrentUIculture 行。代码似乎没有(正确地)尝试父母文化,因为如果我将其设置为通用文化(即“de”而不是“de-DE”),它会完美运行。

    Thread.CurrentThread.CurrentUICulture = new CultureInfo(CultureInfo.InstalledUICulture.TwoLetterISOLanguageName);
    

    我发现了这一点,因为这是 InitializeComponent() 和 ChangeLanguage() 的 ApplyResources 调用之间唯一明显的区别。

    现在,我不知道为什么会这样,而且肯定有更好的解决方案,但这是我迄今为止发现的唯一解决方案。

    字符串部分仍然不起作用:/

    【讨论】:

    • 我在从 .NET 2.0 更改为 .NET 4.0 时遇到了同样的问题(它与 SingleAssemblyComponentResourceManager 和 .NET 2.0 一起发挥了魅力)调用 InitializeComponent(); 之前的代码行;神奇地修复了它。尽管如此,弦乐部分仍然对我不起作用! :/ 对此有什么新的解决方案吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-27
    • 1970-01-01
    相关资源
    最近更新 更多