Локализация строк и изображений в Xamarin.Forms

Download Sample Скачайте пример

Локализация — это процедура адаптации приложения к конкретному языку и культурным особенностям определенного рынка. Для локализации может потребоваться перевести текст и изображения в приложении на несколько языков. Локализованное приложение автоматически отображает переведенный текст в соответствии с языком и региональными параметрами, выбранными на мобильном устройстве.

Screenshots of the localization application on iOS and Android

Платформа .NET Framework включает встроенный механизм для локализации приложений с помощью файлов ресурсов RESX. В файле ресурсов текст и другое содержимое хранится в виде пар "имя-значение", что позволяет приложению извлекать содержимое по указанному ключу. Файлы ресурсов позволяют отделить локализованное содержимое от кода приложения.

Для локализации приложений Xamarin.Forms с помощью файлов ресурсов необходимо выполнить следующие действия:

  1. создать файлы RESX, содержащие переведенный текст;
  2. указать язык и региональные параметры по умолчанию в общем проекте;
  3. локализовать текст в Xamarin.Forms;
  4. локализовать изображения в соответствии с языком и региональными параметрами для каждой платформы;
  5. локализовать имя приложения на каждой платформе;
  6. протестировать локализацию на каждой платформе.

Создание RESX-файлов

Файлы ресурсов — это XML-файлы с расширением RESX, которые компилируются в двоичные файлы ресурсов (RESOURCES) в процессе сборки. Visual Studio 2019 создает класс, который предоставляет интерфейс API для извлечения ресурсов. Локализованное приложение обычно содержит файл ресурсов по умолчанию со всеми строками, используемыми в приложении, а также файлы ресурсов для каждого поддерживаемого языка. В примере приложения в общем проекте имеется папка RESX, которая содержит файлы ресурсов. Файл ресурсов по умолчанию называется AppResources.resx.

Файлы ресурсов содержат следующие сведения для каждого элемента:

  • Name (Имя) — ключ, используемый для доступа к тексту в коде;
  • Value (Значение) — переведенный текст;
  • Comment (Примечание) — необязательное поле, содержащее дополнительные сведения.

Файл ресурсов добавляется в диалоговом окне Добавление нового элемента в Visual Studio 2019.

Add a new Resource in Visual Studio 2019

После добавления файла можно добавить строки для каждого текстового ресурса.

Specify default text resources in a .resx file

Значение, выбранное в раскрывающемся списке Модификатор доступа, определяет то, как Visual Studio создает класс, используемый для доступа к ресурсам. Если выбрать общедоступный или внутренний модификатор доступа, будет создан класс с соответствующим уровнем доступности. Если выбрать модификатор доступа Без создания кода, файл класса не создается. Для создания файла класса необходимо настроить файл ресурсов по умолчанию. В результате в проект будет добавлен файл с расширением .designer.cs.

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

Во время выполнения приложение пытается разрешить запрос ресурса в порядке от более конкретного к более общему. Например, если на устройстве выбраны язык и региональные параметры ru-RU, приложение ищет файлы ресурсов в следующем порядке:

  1. AppResources.ru-RU.resx
  2. AppResources.ru.resx
  3. AppResources.resx (по умолчанию)

На следующем снимке экрана показан файл с переводом на испанский язык, который называется AppResources.es.resx:

Specify default Spanish text resources in a .resx file

В файле с переводом поля Name содержат те же значения, что и в файле по умолчанию, но в столбце Value содержатся строки, переведенные на испанский язык. Кроме того, выбран модификатор доступаБез создания кода.

В Visual Studio 2019 для Mac файл ресурсов добавляется в диалоговом окне Добавление нового файла.

Add a new Resource in Visual Studio 2019 for Mac

После создания файла ресурсов по умолчанию можно добавить текст, создав элементы data в элементе root в файле ресурсов:

<?xml version="1.0" encoding="utf-8"?>
<root>
    ...
    <data name="AddButton" xml:space="preserve">
        <value>Add Note</value>
    </data>
    <data name="NotesLabel" xml:space="preserve">
        <value>Notes:</value>
    </data>
    <data name="NotesPlaceholder" xml:space="preserve">
        <value>e.g. Get Milk</value>
    </data>
</root>

Файл класса .designer.cs можно создать, задав свойство Специальный инструмент в параметрах файла ресурсов:

Custom Tool specified in a resource file's properties

Если в качестве специального инструмента выбрать PublicResXFileCodeGenerator, будет создан класс с уровнем доступа public. Если в качестве специального инструмента выбрать InternalResXFileCodeGenerator, будет создан класс с уровнем доступа internal. Если оставить значение Специальный инструмент пустым, класс создан не будет. Имя созданного класса будет совпадать с именем файла ресурсов. Например, если файл ресурсов называется AppResources.resx, класс AppResources будет создан в файле с именем AppResources.designer.cs.

Для каждого поддерживаемого языка и региональных параметров можно создать дополнительные файлы ресурсов. В имени файла для каждого языка должен быть указан целевой язык и региональные параметры. Так, файл для es-MX должен называться AppResources.es-MX.resx.

Во время выполнения приложение пытается разрешить запрос ресурса в порядке от более конкретного к более общему. Например, если на устройстве выбраны язык и региональные параметры ru-RU, приложение ищет файлы ресурсов в следующем порядке:

  1. AppResources.ru-RU.resx
  2. AppResources.ru.resx
  3. AppResources.resx (по умолчанию)

В файлах с переводом поля Name должны содержаться те же значения, что и в файле по умолчанию. Ниже представлен код XML в файле AppResources.es.resx с переводом на испанский язык.

<?xml version="1.0" encoding="utf-8"?>
<root>
    ...
    <data name="NotesLabel" xml:space="preserve">
        <value>Notas:</value>
    </data>
    <data name="NotesPlaceholder" xml:space="preserve">
        <value>por ejemplo . comprar leche</value>
    </data>
    <data name="AddButton" xml:space="preserve">
        <value>Agregar nuevo elemento</value>
    </data>
</root>

Указание языка и региональных параметров по умолчанию

Для правильной работы файлов ресурсов в приложении необходимо указать атрибут NeutralResourcesLanguage. В проекте, содержащем файлы ресурсов, в файле AssemblyInfo.cs нужно указать язык и региональные параметры по умолчанию. В следующем примере кода показано, как присвоить NeutralResourcesLanguage значение en-US в файле AssemblyInfo.cs:

using System.Resources;

// The resources from the neutral language .resx file are stored directly
// within the library assembly. For that reason, changing en-US to a different
// language in this line will not by itself change the language shown in the
// app. See the discussion of UltimateResourceFallbackLocation in the
// documentation for additional information:
// https://learn.microsoft.com/dotnet/api/system.resources.neutralresourceslanguageattribute
[assembly: NeutralResourcesLanguage("en-US")]

Предупреждение

Если атрибут NeutralResourcesLanguage не указан, класс ResourceManager возвращает значения null для всех языков и региональных параметров, для которых файлы ресурсов отсутствуют. Если язык и региональные параметры по умолчанию указаны, ResourceManager возвращает результаты из файла RESX по умолчанию для неподдерживаемых языков и региональных параметров. Поэтому рекомендуется всегда указывать NeutralResourcesLanguage, чтобы для неподдерживаемых языков и региональных параметров текст отображался.

После создания файла ресурсов по умолчанию и указания языка и региональных параметров по умолчанию в файле AssemblyInfo.cs приложение может извлекать локализованные строки во время выполнения.

Дополнительные сведения о файлах ресурсов см. в статье Создание файлов ресурсов для приложений .NET.

Указание поддерживаемых языков в iOS

В iOS необходимо объявить все поддерживаемые языки в файле Info.plist для своего проекта. В файле Info.plist используйте представление Source (Источник), чтобы задать массив для ключа CFBundleLocalizations, и укажите значения, соответствующие RESX-файлам. Кроме того, убедитесь, что вы установили ожидаемый язык с помощью ключа CFBundleDevelopmentRegion.

Screenshot of the Info.plist editor showing the Localizations section

Либо можно открыть файл Info.plist в редакторе XML и добавить следующее содержимое.

<key>CFBundleLocalizations</key>
<array>
    <string>de</string>
    <string>es</string>
    <string>fr</string>
    <string>ja</string>
    <string>pt</string> <!-- Brazil -->
    <string>pt-PT</string> <!-- Portugal -->
    <string>ru</string>
    <string>zh-Hans</string>
    <string>zh-Hant</string>
</array>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>

Примечание.

Apple обрабатывает португальский язык не совсем так, как можно ожидать. Дополнительные сведения см. в разделе Adding Languages (Добавление языков) на сайте developer.apple.com.

Дополнительные сведения см. в разделе Указание поддерживаемых языков по умолчанию в файле Info.plist.

Указание поддерживаемых языков в UWP

Это необходимо, только если вы создаете пакет приложений при упаковке приложения для загрузки неопубликованных приложений или хранения. Когда вы создаете пакет приложений UWP, при установке пакета будут загружены только ресурсы, связанные с языковыми параметрами устройства установки. Таким образом, если на устройстве доступен только английский язык, с приложением будут установлены только английские ресурсы. Дополнительные сведения см. в статье Приложения Магазина Windows 8.1. Принудительная установка ресурсов на устройстве независимо от потребности устройства в этих ресурсах.

Локализация текста в Xamarin.Forms

Текст в Xamarin.Forms локализуется с помощью создаваемого класса AppResources. Его имя совпадает с именем файла ресурсов по умолчанию. Так как пример файла ресурсов проекта называется AppResources.resx, Visual Studio создает соответствующий класс AppResources. Для каждой строки в файле ресурсов в классе AppResources создаются статические свойства. В классе AppResources для примера приложения создаются следующие статические свойства:

  • AddButton
  • NotesLabel
  • NotesPlaceholder

Доступ к этим значениям как к свойствам x:Static позволяет отображать локализованный текст в XAML:

<ContentPage ...
             xmlns:resources="clr-namespace:LocalizationDemo.Resx">
    <Label Text="{x:Static resources:AppResources.NotesLabel}" />
    <Entry Placeholder="{x:Static resources:AppResources.NotesPlaceholder}" />
    <Button Text="{x:Static resources:AppResources.AddButton}" />
</ContentPage>

Локализованный текст также можно извлекать в коде:

public LocalizedCodePage()
{
    Label notesLabel = new Label
    {
        Text = AppResources.NotesLabel,
        // ...
    };

    Entry notesEntry = new Entry
    {
        Placeholder = AppResources.NotesPlaceholder,
        //...
    };

    Button addButton = new Button
    {
        Text = AppResources.AddButton,
        // ...
    };

    Content = new StackLayout
    {
        Children = {
            notesLabel,
            notesEntry,
            addButton
        }
    };
}

Чтобы определить, из какого файла ресурсов следует извлечь значения, свойства класса AppResources используют текущее значение System.Globalization.CultureInfo.CurrentUICulture.

Локализация изображений

Помимо текста, в файлах RESX можно хранить изображения и двоичные данные. Однако мобильные устройства имеют экраны разного размера и плотности, а каждая мобильная платформа имеет функции для показа изображений с учетом плотности. Поэтому вместо хранения изображений в файлах ресурсов следует использовать функции локализации изображений, предоставляемые платформой.

Локализация изображений на Android

На Android локализованные прорисовываемые ресурсы (изображения) хранятся в соответствии с соглашением об именовании папок в каталоге Resources. Имена папок состоят из слова drawable и целевого языка в виде суффикса. Например, папка для испанского языка называется drawable-es.

Когда нужен четырехбуквенный код языкового стандарта, Android требует дополнительную букву r после дефиса. Например, папка для мексиканского языкового стандарта (es-MX) должна называться drawable-es-rMX. Имена файлов изображений в папке каждого языкового стандарта должны быть одинаковыми:

Localized images in the Android project

Дополнительные сведения см. в статье Локализация в Android.

Локализация изображений в iOS

В iOS локализованные изображения хранятся в соответствии с соглашением об именовании папок в каталоге Resources. Папка по умолчанию имеет имя Base.lproj. Имена папок для конкретных языков состоят из названия языка или языкового стандарта, за которым следует .lproj. Например, папка для испанского языка называется es.lproj.

Коды языковых стандартов из четырех символов используются так же, как и двухбуквенные коды языков. Например, папка для мексиканского языкового стандарта (es-MX) должна называться es-MX.lproj. Имена файлов изображений в папке каждого языкового стандарта должны быть одинаковыми:

Localized images in the iOS project

Примечание.

iOS поддерживает создание локализованного каталога ресурсов вместо использования структуры папок .lproj. Однако их следует создавать и управлять ими в Xcode.

Дополнительные сведения см. в статье Локализация в iOS.

Локализация изображений в UWP

В UWP локализованные изображения хранятся в соответствии с соглашением об именовании папок в каталоге Assets/Images. Имена папок совпадают с названиями языков или языковых стандартов. Например, папка для испанского языка называется es, а для мексиканского языкового стандарта — es-MX. Имена файлов изображений в папке каждого языкового стандарта должны быть одинаковыми:

Localized images in the UWP project

Подробнее об этом см. в разделе Локализация на универсальной платформе Windows.

Использование локализованных изображений

Так как на каждой платформе для хранения изображений используется уникальная структура файлов, XAML использует класс OnPlatform для задания свойства ImageSource в зависимости от текущей платформы:

<Image>
    <Image.Source>
        <OnPlatform x:TypeArguments="ImageSource">
            <On Platform="iOS, Android" Value="flag.png" />
            <On Platform="UWP" Value="Assets/Images/flag.png" />
        </OnPlatform>
    </Image.Source>
</Image>

Примечание.

Расширение разметки OnPlatform позволяет более лаконично указывать значения для конкретных платформ. Дополнительные сведения см. в разделе Расширение разметки OnPlatform.

Источник изображения можно указать в коде на основе свойства Device.RuntimePlatform:

string imgSrc = Device.RuntimePlatform == Device.UWP ? "Assets/Images/flag.png" : "flag.png";
Image flag = new Image
{
    Source = ImageSource.FromFile(imgSrc),
    WidthRequest = 100
};

Локализация имени приложения

Имя приложения указывается для каждой платформы без использования файлов ресурсов RESX. Сведения о локализации имени приложения на Android см. в статье Локализация имени приложения на Android. Сведения о локализации имени приложения в iOS см. в статье Локализация имени приложения в iOS. Сведения о локализации имени приложения в UWP см. в статье Локализация строк в манифесте пакета UWP.

Тестирование локализации

Чтобы протестировать локализацию, лучше всего сменить язык на устройстве. Можно также задать значение System.Globalization.CultureInfo.CurrentUICulture в коде, но результат будет разным на разных платформах, поэтому в целях тестирования делать это не рекомендуется.

В iOS в приложении "Параметры" можно задать язык для каждого отдельного приложения, не изменяя язык устройства.

На Android настройки языка определяются и кэшируются при запуске приложения. Чтобы после смены языка изменения вступили в силу, может потребоваться перезапустить приложение.