Как использовать локализацию в С#

Я просто не могу заставить локализацию работать.

У меня есть библиотека классов. Теперь я хочу создать там файлы resx и вернуть некоторые значения на основе культуры потоков.

Как я могу это сделать?

Ответ 1

  • Добавьте в проект файл ресурсов (вы можете называть его "strings.resx" ), выполнив следующие действия:
    Щелкните правой кнопкой мыши Свойства в проекте, выберите Добавить → Новый элемент... в контекстном меню, затем в списке Элементы Visual С# выберите " Файл ресурсов" и назовите его strings.resx.
  • Добавьте строку resouce в файл resx и дайте ему хорошее имя (пример: назовите его "Hello" with и дайте ему значение "Hello" )
  • Сохраните файл ресурса ( note:, это будет файл ресурсов по умолчанию, так как он не имеет двухбуквенного кода языка)
  • Добавьте ссылки на свою программу: System.Threading и System.Globalization

Запустите этот код:

Console.WriteLine(Properties.strings.Hello);

Он должен напечатать "Hello" .

Теперь добавьте новый файл ресурсов с именем "strings.fr.resx" (обратите внимание на часть "fr", на которой будут представлены ресурсы на французском языке). Добавьте строковый ресурс с тем же именем, что и в strings.resx, но со значением на французском языке (Name= "Hello" , Value = "Salut" ). Теперь, если вы запустите следующий код, он должен распечатать Salut:

Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("fr-FR");
Console.WriteLine(Properties.strings.Hello);

Что произойдет, так это то, что система будет искать ресурс для "fr-FR". Он не найдет его (так как мы указали "fr" в вашем файле "). Затем он вернется к проверке" fr ", которую он находит (и использует).

Следующий код напечатает "Hello" :

Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-US");
Console.WriteLine(Properties.strings.Hello);

Это потому, что он не находит никакого ресурса "en-US", а также нет ресурса "en", поэтому он вернется к умолчанию, который был добавлен с самого начала.

При необходимости вы можете создавать файлы с более конкретными ресурсами (например, strings.fr-FR.resx и strings.fr-CA.resx для французского во Франции и Канаде соответственно). В каждом таком файле вам нужно будет добавить ресурсы для тех строк, которые отличаются от ресурсов, на которые он будет возвращаться. Так что, если текст во Франции и Канаде одинаковый, вы можете поместить его в strings.fr.resx, в то время как строки, которые отличаются на канадском французском, могут переходить в strings.fr-CA.resx.

Ответ 2

Это довольно просто, на самом деле. Создайте новый файл ресурсов, например Strings.resx. Установите Access Modifier в Public. Используйте шаблон apprioriate, поэтому Visual Studio автоматически создаст класс доступа (в этом случае имя будет Strings). Это ваш язык по умолчанию.

Теперь, когда вы хотите добавить, скажем, немецкую локализацию, добавить локализованный файл resx. В этом случае это будет обычно Strings.de.resx. Если вы хотите добавить дополнительную локализацию, скажем, в Австрию, вы также создадите Strings.de-AT.resx.

Теперь перейдите к созданию строки - скажем, строку с именем HelloWorld. В Strings.resx добавьте эту строку со значением "Hello, world!". В Strings.de.resx добавьте "Hallo, Welt!". И в Strings.de-AT.resx добавьте "Servus, Welt!". Это пока.

Теперь у вас есть сгенерированный класс Strings, и он имеет свойство с getter HelloWorld. Приобретение этого свойства будет загружать "Servus, Welt!" когда ваш язык де-AT, "Hallo, Welt!, когда ваш язык - это любой другой язык (включая de-DE и de-CH) и" Hello, World! ", когда ваш язык - это что-то еще. Если строка отсутствует в локализованной версии, диспетчер ресурсов будет автоматически перемещаться по цепочке от наиболее специализированного к инвариантному ресурсу.

Вы можете использовать класс ResourceManager для большего контроля над тем, как именно вы загружаете вещи. Созданный класс Strings также использует его.

Ответ 3

Кроме @Fredrik Mörk отличный ответ на строки, чтобы добавить локализацию в форму, сделайте следующее:

  • Установите для свойства формы "Localizable" значение true
  • Измените свойство Language формы на нужный вам язык (из приятного выпадающего списка)
  • Переведите элементы управления в эту форму и переместите их в случае необходимости (вставьте эти действительно длинные полные французские предложения!)

Изменение: Эта статья MSDN по локализации Windows Forms не является той, которую я связал, но может пролить больше света, если это необходимо. (старый был забран)

Ответ 4

Отличный ответ Ф.Мёрка. Но если вы хотите обновить перевод или добавить новые языки после того, как приложение будет выпущено, вы застряли, потому что вам всегда приходится перекомпилировать его для генерации файла resources.dll.

Вот решение для ручной компиляции dll ресурса. Он использует инструменты resgen.exe и al.exe(устанавливается с помощью sdk).

Скажем, у вас есть файл ресурсов Strings.fr.resx, вы можете скомпилировать dll ресурсов со следующей командой:

resgen.exe /compile Strings.fr.resx,WpfRibbonApplication1.Strings.fr.resources 
Al.exe /t:lib /embed:WpfRibbonApplication1.Strings.fr.resources /culture:"fr" /out:"WpfRibbonApplication1.resources.dll"
del WpfRibbonApplication1.Strings.fr.resources
pause

Обязательно сохраните исходное пространство имен в именах файлов (здесь "WpfRibbonApplication1" )

Ответ 5

Исправление и проработка ответа @Fredrik Mörk.

  • Добавьте файл ресурсов strings.resx в ваш проект (или другое имя файла)
  • Установите для Access Modifier значение Public (на открытой вкладке файла strings.resx)
  • Добавьте строку resouce в файл resx: (пример: имя Hello, значение Hello)
  • Сохраните файл ресурса

Visual Studio автоматически создает соответствующий класс strings, который фактически помещается в strings.Designer.cs. Класс находится в том же пространстве имен, в котором вы ожидаете разместить вновь созданный файл .cs.

Этот код всегда печатает Hello, потому что это ресурс по умолчанию, а ресурсы для конкретного языка недоступны:

Console.WriteLine(strings.Hello);

Теперь добавьте новый языковой ресурс:

  • Добавить strings.fr.resx (для французского)
  • Добавьте строку с тем же именем, что и ранее, но с другим значением: (имя Hello, значение Salut)

Следующий код печатает Salut:

Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("fr-FR");
Console.WriteLine(strings.Hello);

Какой ресурс используется, зависит от Thread.CurrentThread.CurrentUICulture. Он устанавливается в зависимости от языковой настройки Windows UI или может быть установлен вручную, как в этом примере. Узнайте больше об этом здесь.

Вы можете добавить специфичные для страны ресурсы, такие как strings.fr-FR.resx или strings.fr-CA.resx.

Используемая строка определяется в следующем порядке приоритета:

  • Из странового ресурса, такого как strings.fr-CA.resx
  • Из языкового ресурса, такого как strings.fr.resx
  • По умолчанию strings.resx

Обратите внимание, что языковые ресурсы генерируют спутниковые сборки.

Также узнайте, чем CurrentCulture отличается от CurrentUICulture здесь.

Ответ 6

В дополнение к ответу @Eric Bole-Feysot:

Благодаря сборкам спутников локализация может быть создана на основе файлов .dll/.exe. Таким образом:

  • исходный код (проект VS) можно отделить от языкового проекта,
  • Добавление нового языка не требует перекомпиляции проекта,
  • перевод может быть выполнен даже конечным пользователем.

Существует мало известный инструмент LSACreator (бесплатный для некоммерческого использования или вариант покупки), который позволяет создавать локализацию на основе на .dll/.exe. Фактически, внутренне (в каталоге проекта языка) он создает/управляет локализованными версиями файлов resx и компилирует сборку аналогично описанному @Eric Bole-Feysot.

Ответ 7

В моем случае

[assembly: System.Resources.NeutralResourcesLanguage("ru-RU")]

в AssemblyInfo.cs помешало всем работать как обычно.

Ответ 8

ResourceManager и .resx немного грязные.

Вы можете использовать Lexical.Localization ¹, который позволяет встраивать значения по умолчанию и значения, специфичные для культуры, в код и расширяться во внешних файлах локализации для других культур (например,.json или .resx).

public class MyClass
{
    /// <summary>
    /// Localization root for this class.
    /// </summary>
    static ILine localization = LineRoot.Global.Type<MyClass>();

    /// <summary>
    /// Localization key "Ok" with a default string, and couple of inlined strings for two cultures.
    /// </summary>
    static ILine ok = localization.Key("Success")
            .Text("Success")
            .fi("Onnistui")
            .sv("Det funkar");

    /// <summary>
    /// Localization key "Error" with a default string, and couple of inlined ones for two cultures.
    /// </summary>
    static ILine error = localization.Key("Error")
            .Format("Error (Code=0x{0:X8})")
            .fi("Virhe (Koodi=0x{0:X8})")
            .sv("Sönder (Kod=0x{0:X8})");

    public void DoOk()
    {
        Console.WriteLine( ok );
    }

    public void DoError()
    {
        Console.WriteLine( error.Value(0x100) );
    }
}

¹ (я хранитель этой библиотеки)