1

Я разрабатываю простое приложение C# .NET 4.0 и хочу, чтобы оно было локализовано на нескольких языках. Однако созданные для локализации спутниковые сборки (т. Е. De/MyApp.resources.dll) избавят его от простоты, перетащив эти DLL и их папки.C# Single-Assembly Multilanguage App - Ресурсы не загружаются должным образом

Вот почему я искал способ включить эти DLL в основную (и только) сборку, поэтому только конечный пользователь должен был отправить исполняемый файл. Я наткнулся на this very promising question и набросился на него.

После принятия класса в предлагаемом решении, я заменил все вхождения я мог бы найти в ResourceManager с SingleAssemblyResourceManager в файлах .Designer.cs с использованием FART в команде до сборки:

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

И это делает изменить язык формы. Таким образом, dlls фактически включены в exe. Почему же, InitializeComponent не загружает соответствующие ресурсы? Я проверил код конструктора, и ResourceManager был заменен на SingleAssemblyResourceManager.

Также, кроме текстов кнопок формы, у меня есть файл strings.resx для каждого языка, для MessageBoxes и еще много чего, и это, похоже, не работает в любом случае. Но это может быть еще один вопрос.

Я знаю, что оригинальное решение было разработано для среды NET 2.0, и что ResourceSets устарели, но я понимаю, что он должен работать, даже если его не рекомендуется.

Любые указания относительно того, где я должен был бы выглядеть, были бы замечательными.

ответ

1

Как оказалось, я в конечном итоге смог заставить его работать, слегка изменив линию CurrentUIculture. Казалось бы, код не пробует родительские культуры (правильно), потому что, если я установлю его на общую культуру (то есть, «de» вместо «de-DE»), он отлично работает.

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

Я обнаружил это, так как это было единственное явное различие между ApplyResources требует от InitializeComponent() и ChangeLanguage().

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

Строки часть по-прежнему не работает, хотя:/

+0

Я столкнулся с той же проблемой при переходе с .NET 2.0 для .NET 4.0 (он работал как шарм с SingleAssemblyComponentResourceManager и .NET 2.0) Ваша строка кода перед вызовом InitializeComponent(); зафиксировал его магически. Тем не менее, часть строк все еще не работает, хотя для меня тоже! :/Есть ли какие-нибудь новые решения? – Gerrit