ЛокализацияLocalization

Скачать пример Скачать примерDownload Sample Download the sample

Приложения Xamarin.Forms можно локализовать с помощью файлов ресурсов .NET.Xamarin.Forms apps can be localized using .NET resources files.

ОбзорOverview

Встроенный механизм для локализации приложений использует RESX-файлы и классы в пространствах имен System.Resources и System.Globalization.The built-in mechanism for localizing .NET applications uses RESX files and the classes in the System.Resources and System.Globalization namespaces. RESX-файлы, содержащие переведенные строки, внедряются в сборку Xamarin.Forms вместе с создаваемым компилятором классом, который обеспечивает строго типизированный доступ к переводам.The RESX files containing translated strings are embedded in the Xamarin.Forms assembly, along with a compiler-generated class that provides strongly-typed access to the translations. Затем переведенный текст можно извлечь в коде.The translated text can then be retrieved in code.

Пример кодаSample Code

Существует два примера, связанных с этим документом.There are two samples associated with this document:

  • UsingResxLocalization — это очень простая демонстрация описанных понятий.UsingResxLocalization is a very simple demonstration of the concepts explained. Все приведенные ниже фрагменты кода входят в этот пример.The code snippets shown below are all from this sample.
  • TodoLocalized — это базовое работающее приложение, которое использует эти методы локализации.TodoLocalized is a basic working app that uses these localization techniques.

Пример TodoLocalized включает демонстрацию общих проектов, но из-за ограничений системы сборка файлы ресурсов не получают созданный файл .designer.cs, что препятствует доступу к переведенным строкам со строгой типизацией в коде.The TodoLocalized sample includes a Shared Project demo however due to limitations of the build system the resource files do not get a .designer.cs file generated which breaks the ability to access translated strings strongly-typed in code.

Далее в этом документе описываются проекты, использующие шаблон библиотеки .NET Standard в Xamarin.Forms.The remainder of this document relates to projects using the Xamarin.Forms .NET Standard library template.

Глобализация кода Xamarin.FormsGlobalizing Xamarin.Forms Code

Глобализация приложения — это процесс подготовки приложения для доступа по всему миру.Globalizing an application is the process of making it "world ready." Это означает написание кода, который может отображать разные языки.This means writing code that is capable of displaying different languages.

Один из ключевых элементов глобализации приложения — создание пользовательского интерфейса таким образом, чтобы исключить жестко заданный текст.One of the key parts of globalizing an application is building the user-interface so that there is no hard-coded text. Вместо этого все отображаемое для пользователя должно извлекаться из набора строк, которые переведены на выбранный язык.Instead, anything displayed to the user should be retrieved from a set of strings that have been translated into their chosen language.

В этом документе мы рассмотрим, как использовать файлы RESX для хранения этих строк и извлекать их для отображения в зависимости от предпочтений пользователя.In this document we'll examine how to use RESX files to store those strings and retrieve them for display depending on the user's preference.

В примере рассматриваются английский, французский, испанский, немецкий, китайский, японский, русский и португальский (Бразилия).The samples target English, French, Spanish, German, Chinese, Japanese, Russian, and Brazilian Portuguese languages. Приложения могут быть переведены на любое количество языков.Applications can be translated into as few or as many languages as required.

Примечание

На универсальной платформе Windows для локализации push-уведомлений следует использовать RESW-файлы вместо RESX-файлов.On the Universal Windows Platform, RESW files should be used for push notification localization, rather than RESX files. Подробнее об этом см. в разделе Локализация на универсальной платформе Windows.For more information, see UWP Localization.

Добавление ресурсовAdding Resources

Первый шаг глобализации приложения библиотеки .NET Standard в Xamarin.Forms — добавление файлов ресурсов RESX, которые будут использоваться для хранения всего текста, используемого в приложении.The first step in globalizing a Xamarin.Forms .NET Standard library application is adding the RESX resource files that will be used to store all the text used in the app. Нам нужно добавить RESX-файлы, содержащие текст по умолчанию, а затем добавить дополнительные RESX-файлы для каждого языка, который требуется поддерживать.We need to add a RESX file that contains the default text, and then add additional RESX files for each language we wish to support.

Базовый ресурс языкаBase Language Resource

Файл базовых ресурсов (RESX) будет содержать строки языка по умолчанию (в примерах это английский).The base resources (RESX) file will contain the default language strings (the samples assume English is the default language). Добавьте файл в обычный проект кода Xamarin.Forms, щелкнув правой кнопкой мыши на проекте и выбрав Добавить > Новый файл... .Add the file to the Xamarin.Forms common code project by right-clicking on the project and choosing Add > New File....

Выберите понятное имя, например AppResources, и нажмите ОК.Choose a meaningful name such as AppResources and press OK.

Добавить файл ресурсовAdd Resource File

В проект будут добавлены два файла:Two files will be added to the project:

  • файл AppResources.resx, где переводимые строки хранятся в формате XML;AppResources.resx file where translatable strings are stored in an XML format.
  • файл AppResources.designer.cs, который объявляет разделяемый класс для хранения ссылок на все элементы, созданные в XML RESX-файле.AppResources.designer.cs file that declares a partial class to contain references to all the elements created in the RESX XML file.

Дерево решений будет показывать файлы как связанные.The solution tree will show the files as related. RESX-файл следует отредактировать, чтобы добавить новые переводимые строки; файл . designer.cs не нужно редактировать.The RESX file should be edited to add new translatable strings; the .designer.cs file should not be edited.

Видимость строкString Visibility

По умолчанию при создании строго типизированных ссылок на строки они будут internal для сборки.By default when strongly-typed references to strings are generated, they will be internal to the assembly. Это связано с тем, что средство сборки по умолчанию для RESX-файлов создает файл . designer.cs со свойствами internal.This is because the default build tool for RESX files generates the .designer.cs file with internal properties.

Выберите файл AppResources.resx и откройте панель свойств, чтобы увидеть, где настраивается это средство сборки.Select the AppResources.resx file and show the Properties pad to see where this build tool is configure. На снимке экрана ниже показана конфигурация Custom Tool (Пользовательское средство): ResXFileCodeGenerator.The screenshot below shows the Custom Tool: ResXFileCodeGenerator.

Чтобы получить строго типизированные свойства строки public, необходимо вручную изменить конфигурацию на Custom Tool: (Пользовательское средство): PublicResXFileCodeGenerator, как показано на следующем снимке экрана.To make the strongly-typed string properties public, you must manually change the configuration to Custom Tool: PublicResXFileCodeGenerator, as shown in the screenshot below:

Это изменение является необязательным и требуется только в том случае, если вы хотите ссылаться на локализованные строки в разных сборках (например, если вы помещаете RESX-файлы в другую сборку в коде).This change is optional, and is only required if you wish to reference localized strings across different assemblies (for example, if you put the RESX files in a different assembly to your code). В примере для этого раздела строки остаются internal, так как они определены в той же сборке библиотеки .NET Standard Xamarin.Forms, где они используются.The sample for this topic leaves the strings internal because they are defined in the same Xamarin.Forms .NET Standard library assembly where they are used.

Необходимо задать пользовательское средство только в базовом RESX-файле, как показано выше. Не нужно задавать никакие средства сборки в языковых RESX-файлах, рассмотренных в следующих разделах.You only need to set the custom tool on the base RESX file as shown above; you do not need to set any build tool on the language-specific RESX files discussed in the following sections.

Редактирование RESX-файлаEditing the RESX file

К сожалению, в Visual Studio для Mac нет встроенного редактора RESX.Unfortunately there is no built-in RESX editor in Visual Studio for Mac. Добавление новых переводимых строк требует добавления нового элемента XML data для каждой строки.Adding new translatable strings requires the addition of a new XML data element for each string. Каждый элемент data может содержать следующее.Each data element can contain the following:

  • Атрибут name (обязательно) необходим для этой переводимой строки.name attribute (required) is the key for this translatable string. Это должно быть допустимое имя свойства C#, поэтому пробелы или специальные символы не допускаются.It must be a valid C# property name - so no spaces or special characters are allowed.
  • Элемент value (обязательно) — это фактическая строка, которая отображается в приложении.value element (required), which is the actual string that is displayed in the application.
  • Элемент comment (необязательно) может содержать инструкции для переводчика, которые объясняют, как используется эта строка.comment element (optional) can contain instructions for the translator that explains how this string is used.
  • Атрибут xml:space (необязательно) управляет сохранением интервалов в строке.xml:space attribute (optional) to control how spacing in the string is preserved.

Некоторые примеры элементов data:Some example data elements are shown here:

<data name="NotesLabel" xml:space="preserve">
    <value>Notes:</value>
    <comment>label for input field</comment>
</data>
<data name="NotesPlaceholder" xml:space="preserve">
    <value>eg. buy milk</value>
    <comment>example input for notes field</comment>
</data>
<data name="AddButton" xml:space="preserve">
    <value>Add new item</value>
</data>

По мере написания приложения каждый фрагмент текста, отображаемый пользователю, необходимо добавлять в базовый файл ресурсов RESX в новый элемент data.As the application is written, every piece of text displayed to the user should be added to the base RESX resources file in a new data element. Рекомендуется включать как можно больше comment, чтобы качество перевода было высоким.It is recommended that you include comments as much as possible to ensure a high-quality translation.

Примечание

Visual Studio (включая бесплатный выпуск Community) содержит базовый редактор RESX.Visual Studio (including the free Community edition) contains a basic RESX editor. Если у вас есть доступ к компьютеру Windows, это удобный способ добавлять и изменять строки в RESX-файлах.If you have access to a Windows computer, that can be a convenient way to add and edit strings in RESX files.

Языковые ресурсыLanguage-Specific Resources

Как правило, фактический перевод строк текста по умолчанию выполняется только после написания больших блоков приложения (в этом случае RESX-файл по умолчанию будет содержать множество строк).Typically, the actual translation of the default text strings won't happen until large chunks of the application have been written (in which case the default RESX file will contain lots of strings). По-прежнему рекомендуется добавлять языковые ресурсы на ранних этапах цикла разработки, при необходимости добавляя машинный перевод для тестирования кода локализации.It is still a good idea to add the language-specific resources early in the development cycle, optionally populating with machine-translated text to help test the localization code.

Один дополнительный RESX-файл добавляется для каждого языка, который будет поддерживаться.One additional RESX file is added for each language we wish to support. Файлы языковых ресурсов должны соответствовать соглашению об именовании: используйте одно имя файла как базовый файл ресурса (например,Language-specific resource files must follow a specific naming convention: use the same filename as the base resources file (eg. AppResources), затем точка (.) и код языка.AppResources) followed by a period (.) and then the language code. Примеры:Simple examples include:

  • AppResources.fr.resx — французский.AppResources.fr.resx - French language translations.
  • AppResources.es.resx — испанский.AppResources.es.resx - Spanish language translations.
  • AppResources.de.resx — немецкий.AppResources.de.resx - German language translations.
  • AppResources.ja.resx — японский.AppResources.ja.resx - Japanese language translations.
  • AppResources.zh-Hans.resx — китайский (упрощенное письмо).AppResources.zh-Hans.resx - Chinese (Simplified) language translations.
  • AppResources.zh-Hant.resx — китайский (традиционное письмо).AppResources.zh-Hant.resx - Chinese (Traditional) language translations.
  • AppResources.pt.resx — португальский.AppResources.pt.resx - Portuguese language translations.
  • AppResources.pt-BR.resx — португальский (Бразилия).AppResources.pt-BR.resx - Brazilian Portuguese language translations.

Общий шаблон — использовать двухбуквенные коды языков, но есть несколько примеров (например, китайский), в которых используется другой формат, и другие примеры (например, португальский (Бразилия)), где требуется четырехзначный код языка.The general pattern is to use two-letter language codes, but there are some examples (such as Chinese) where a different format is used, and other examples (such as Brazilian Portuguese) where a four character locale identifier is required.

Эти файлы языковых ресурсов не требуют разделяемый класс . designer.cs, поэтому их можно добавлять как обычные XML-файлы с конфигурацией Build Action (Действие при сборке): EmbeddedResource.These language-specific resources files do not require a .designer.cs partial class so they can be added as regular XML files, with the Build Action: EmbeddedResource set. На этом снимке экрана показано решение с файлами языковых ресурсов.This screenshot shows a solution containing language-specific resource files:

После разработки приложения и добавления текста в базовый RESX-файл вы должны отправить его переводчикам, которые переведут каждый элемент data и вернут файл языкового ресурса (используя соглашение об именовании), который вы включите в приложение.As an application is developed and the base RESX file has text added, you should send it out to translators who will translate each data element and return a language-specific resource file (using the naming convention shown) to be included in the app. Ниже приведены некоторые примеры с машинным переводом.Some 'machine translated' examples are shown below:

AppResources.es.resx (испанский)AppResources.es.resx (Spanish)

<data name="AddButton" xml:space="preserve">
    <value>Escribir un artículo</value>
    <comment>this string appears on a button to add a new item to the list</comment>
</data>

AppResources.ja.resx (японский)AppResources.ja.resx (Japanese)

<data name="AddButton" xml:space="preserve">
    <value>新しい項目を追加</value>
    <comment>this string appears on a button to add a new item to the list</comment>
</data>

AppResources.pt-BR.resx (португальский (Бразилия))AppResources.pt-BR.resx (Brazilian Portuguese)

<data name="AddButton" xml:space="preserve">
    <value>adicionar novo item</value>
    <comment>this string appears on a button to add a new item to the list</comment>
</data>

Переводчик изменяет только элемент value — comment не предназначен для перевода.Only the value element needs to be updated by the translator - the comment is not intended to be translated. Помните, что при редактировании XML-файлов нужно экранировать зарезервированные знаки, такие как <, >, & с &lt;, &gt; и &amp;, если они находятся в value или comment.Remember: when editing XML files to escape reserved characters like <, >, & with &lt;, &gt;, and &amp; if they appear in the value or comment.

Использование ресурсов в кодеUsing Resources in Code

Строки в файлах ресурсов RESX будут доступны для использования в коде пользовательского интерфейса с помощью класса AppResources.Strings in the RESX resource files will be available to use in your user interface code using the AppResources class. name, назначенное каждой строке в RESX-файле, становится свойством для этого класса, на который можно ссылаться в коде Xamarin.Forms, как показано ниже.The name assigned to each string in the RESX file becomes a property on that class which can be referenced in Xamarin.Forms code as shown below:

var myLabel = new Label ();
var myEntry = new Entry ();
var myButton = new Button ();
// populate UI with translated text values from resources
myLabel.Text = AppResources.NotesLabel;
myEntry.Placeholder = AppResources.NotesPlaceholder;
myButton.Text = AppResources.AddButton;

Пользовательский интерфейс в iOS, Android и на универсальной платформе Windows (UWP) преобразуется для просмотра так, как ожидалось, только теперь можно перевести приложение на несколько языков, так как текст загружается из ресурса, а не закодирован жестко.The user interface on iOS, Android, and the Universal Windows Platform (UWP) renders as you'd expect, except now it's possible to translate the app into multiple languages because the text is being loaded from a resource rather than being hard-coded. Ниже приведен снимок экрана пользовательского интерфейса на каждой платформе до перевода.Here is a screenshot showing the UI on each platform prior to translation:

Устранение неполадокTroubleshooting

Тестирование конкретного языкаTesting a Specific Language

Бывает сложно переключить симулятор или устройство на разные языки, особенно во время разработки, когда необходимо быстро протестировать разные языки и региональные параметры.It can be tricky to switch the simulator or a device to different languages, particularly during development when you want to test different cultures quickly.

Вы можете принудительно загрузить конкретный язык, задав Culture, как показано в этом фрагменте кода.You can force a specific language to be loaded by setting the Culture as shown in this code snippet:

// force a specific culture, useful for quick testing
AppResources.Culture =  new CultureInfo("fr-FR");

Такой подход — задать язык и региональные параметры непосредственно в классе AppResources — также можно использовать для реализации селектора языка внутри приложения (а не с помощью языкового стандарта устройства).This approach – setting the culture directly on the AppResources class – can also be used to implement a language-selector inside your app (rather than using the device's locale).

Загрузка внедренных ресурсовLoading Embedded Resources

Следующий фрагмент кода полезен при отладке проблем с внедренными ресурсами (такими как RESX-файлы).The following code snippet is useful when trying to debug issues with embedded resources (such as RESX files). Добавьте этот код в приложение (на раннем этапе жизненного цикла), и он перечислит все ресурсы, внедренные в сборку, показав полный идентификатор ресурсов:Add this code to your app (early in the app lifecycle) and it will list all the resources embedded in the assembly, showing the full resource identifier:

using System.Reflection;
// ...
// NOTE: use for debugging, not in released app code!
var assembly = typeof(EmbeddedImages).GetTypeInfo().Assembly; // "EmbeddedImages" should be a class in your app
foreach (var res in assembly.GetManifestResourceNames())
{
    System.Diagnostics.Debug.WriteLine("found resource: " + res);
}

В файле AppResources.Designer.cs (около строки 33) указано полное имя диспетчера ресурсов (например,In the AppResources.Designer.cs file (around line 33), the full resource manager name is specified (eg. "UsingResxLocalization.Resx.AppResources"), как в приведенном ниже коде."UsingResxLocalization.Resx.AppResources") similar to the code below:

System.Resources.ResourceManager temp =
        new System.Resources.ResourceManager(
                "UsingResxLocalization.Resx.AppResources",
                typeof(AppResources).GetTypeInfo().Assembly);

Просмотрите выходные данные приложения, чтобы узнать результаты отладки кода и проверить, что указаны правильные ресурсы (т. е. "UsingResxLocalization.Resx.AppResources").Check the Application Output for the results of the debug code shown above, to confirm the correct resources are listed (ie. "UsingResxLocalization.Resx.AppResources").

Если нет, класс AppResources не сможет загрузить свои ресурсы.If not, the AppResources class will be unable to load its resources. Проверьте следующее, чтобы устранить проблемы, когда не удается найти ресурсы.Check the following to resolve issues where the resources cannot be found:

  • Пространство имен по умолчанию для проекта совпадает с корневым пространством имен в файле AppResources.Designer.cs.The default namespace for the project matches the root namespace in the AppResources.Designer.cs file.
  • Если файл AppResources.resx находится в подкаталоге, имя подкаталога должно быть частью пространства имен и частью идентификатора ресурса.If the AppResources.resx file is located in a subdirectory, the subdirectory name should be part of the namespace and part of the resource identifier.
  • Для файла AppResources.resx указана конфигурация Build Action (Действие при сборке): EmbeddedResource.The AppResources.resx file has Build Action: EmbeddedResource.
  • Установлен флажок Параметры проекта > Исходный код > Политики именования .NET > Использовать имена ресурсов в стиле Visual Studio.The Project Options > Source Code > .NET Naming Policies > Use Visual Studio-style resources names is ticked. Вы можете убрать этот флажок при желании, но пространства имен, используемые при ссылке на ресурсы RESX, потребуется обновить в приложении.You can untick this if you prefer, however the namespaces used when referencing your RESX resources will need to updated throughout the app.

Не работает в режиме отладки (только Android)Doesn't work in DEBUG mode (Android only)

Если переведенные строки работают в сборках выпуска Android, но не во время отладки, щелкните правой кнопкой мыши Проект Android, выберите Параметры > Сборка > Сборка Android и убедитесь, что флажок Быстрое развертывание сборок не установлен.If the translated strings are working in your RELEASE Android builds but not while debugging, right-click on the Android Project and select Options > Build > Android Build and ensure that the Fast assembly deployment is NOT ticked. Этот параметр вызывает проблемы с загрузкой ресурсов, и его не следует использовать при тестировании локализованных приложений.This option causes problems with loading resources and should not be used if you are testing localized apps.

Отображение нужного языкаDisplaying the Correct Language

Пока что мы изучали, как написать код таким образом, чтобы включить возможность переводов, но еще не обсуждали, как сделать так, чтобы они действительно отображались.So far we've examined how to write code so that translations can be provided, but not how to actually make them appear. Код Xamarin.Forms может использовать ресурсы .NET для загрузки переводов на правильный язык, но нам нужно запросить операционную систему на каждой платформе, чтобы определить, какой язык выбрал пользователь.Xamarin.Forms code can take advantage of .NET's resources to load the correct language translations, but we need to query the operating system on each platform to determine which language the user has selected.

Поскольку нам нужен зависящий от платформы код, чтобы узнать языковые настройки пользователя, используйте службу зависимостей, чтобы предоставить эту информацию в приложении Xamarin.Forms и реализовать ее для каждой платформы.Because some platform-specific code is required to obtain the user's language preference, use a dependency service to expose that information in the Xamarin.Forms app and implement it for each platform.

Во-первых, определите интерфейс для получения выбранного языка и региональных параметров пользователя, как в приведенном ниже коде.First, define an interface to expose the user's preferred culture, similar to the code below:

public interface ILocalize
{
    CultureInfo GetCurrentCultureInfo ();
    void SetLocale (CultureInfo ci);
}

Во-вторых, используйте DependencyService в классе Xamarin.Forms App для вызова интерфейса и установки для языка и региональных параметров ресурса RESX правильного значения.Second, use the DependencyService in the Xamarin.Forms App class to call the interface and set our RESX resources culture to the correct value. Нам не нужно вручную задавать это значение для универсальной платформы Windows, так как платформа ресурсов автоматически распознает выбранный язык на этих платформах.Notice that we don't need to manually set this value for the Universal Windows Platform, since the resources framework automatically recognizes the selected language on those platforms.

if (Device.RuntimePlatform == Device.iOS || Device.RuntimePlatform == Device.Android)
{
    var ci = DependencyService.Get<ILocalize>().GetCurrentCultureInfo();
    Resx.AppResources.Culture = ci; // set the RESX for resource localization
    DependencyService.Get<ILocalize>().SetLocale(ci); // set the Thread for locale-aware methods
}

Ресурс Culture необходимо задать при первой загрузке приложения, чтобы использовать строку на правильном языке.The resource Culture needs to be set when the application first loads so that the correct language strings are used. При необходимости вы можете изменить это значение в соответствии с событиями конкретных платформ, которые могут возникать в iOS или Android, если пользователь меняет языковые настройки во время работы приложения.You may optionally update this value according to platform-specific events that may be raised on iOS or Android if the user updates their language preferences while the app is running.

Реализации для интерфейса ILocalize показаны в разделе Код для конкретных платформ ниже.The implementations for the ILocalize interface are shown in the Platform-specific Code section below. Эти реализации используют этот вспомогательный класс PlatformCulture:These implementations take advantage of this PlatformCulture helper class:

public class PlatformCulture
{
    public PlatformCulture (string platformCultureString)
    {
        if (String.IsNullOrEmpty(platformCultureString))
        {
            throw new ArgumentException("Expected culture identifier", "platformCultureString"); // in C# 6 use nameof(platformCultureString)
        }
        PlatformString = platformCultureString.Replace("_", "-"); // .NET expects dash, not underscore
        var dashIndex = PlatformString.IndexOf("-", StringComparison.Ordinal);
        if (dashIndex > 0)
        {
            var parts = PlatformString.Split('-');
            LanguageCode = parts[0];
            LocaleCode = parts[1];
        }
        else
        {
            LanguageCode = PlatformString;
            LocaleCode = "";
        }
    }
    public string PlatformString { get; private set; }
    public string LanguageCode { get; private set; }
    public string LocaleCode { get; private set; }
    public override string ToString()
    {
        return PlatformString;
    }
}

Код для конкретных платформPlatform-Specific Code

Код для определения того, какой язык будет отображаться, должен зависеть от платформы, так как iOS, Android и универсальная платформа Windows по-разному предоставляют эту информацию.The code to detect which language to display must be platform-specific because iOS, Android, and UWP all expose this information in slightly different ways. Ниже предоставляется код для службы зависимостей ILocalize для каждой платформы, а также дополнительные требования платформ для корректного отображения локализованного текста.The code for the ILocalize dependency service is provided below for each platform, along with additional platform-specific requirements to ensure localized text is rendered correctly.

Код для платформы также должен обрабатывать случаи, когда операционная система позволяет пользователю настроить идентификатор языкового стандарта, который не поддерживается классом CultureInfo .NET.The platform-specific code must also handle cases where the operating system allows the user to configure a locale identifier that is not supported by .NET's CultureInfo class. В таких случаях нужно написать пользовательский код для определения неподдерживаемых языковых стандартов и замены наиболее подходящего языкового стандарта, совместимого с .NET.In these cases custom code must be written to detect unsupported locales and substitute the best .NET-compatible locale.

Проект приложения iOSiOS Application Project

Пользователи iOS выбирают язык отдельно от региональных параметров, определяющих дату и время.iOS users select their preferred language separately from date and time formatting culture. Чтобы загрузить правильные ресурсы для локализации приложения Xamarin.Forms, нам просто нужно запросить массив NSLocale.PreferredLanguages для первого элемента.To load the correct resources to localize a Xamarin.Forms app we just need to query the NSLocale.PreferredLanguages array for the first element.

Следующую реализацию службы зависимостей ILocalize необходимо поместить в проект приложения iOS.The following implementation of the ILocalize dependency service should be placed in the iOS application project. Поскольку iOS использует символы подчеркивания, а не тире (это стандартное представление .NET), код заменяет символ подчеркивания перед созданием экземпляра класса CultureInfo:Because iOS uses underscores instead of dashes (which is the .NET standard representation) the code replaces the underscore before instantiating the CultureInfo class:

[assembly:Dependency(typeof(UsingResxLocalization.iOS.Localize))]

namespace UsingResxLocalization.iOS
{
    public class Localize : UsingResxLocalization.ILocalize
    {
        public void SetLocale (CultureInfo ci)
        {
            Thread.CurrentThread.CurrentCulture = ci;
            Thread.CurrentThread.CurrentUICulture = ci;
        }

        public CultureInfo GetCurrentCultureInfo ()
        {
            var netLanguage = "en";
            if (NSLocale.PreferredLanguages.Length > 0)
            {
                var pref = NSLocale.PreferredLanguages [0];
                netLanguage = iOSToDotnetLanguage(pref);
            }
            // this gets called a lot - try/catch can be expensive so consider caching or something
            System.Globalization.CultureInfo ci = null;
            try
            {
                ci = new System.Globalization.CultureInfo(netLanguage);
            }
            catch (CultureNotFoundException e1)
            {
                // iOS locale not valid .NET culture (eg. "en-ES" : English in Spain)
                // fallback to first characters, in this case "en"
                try
                {
                    var fallback = ToDotnetFallbackLanguage(new PlatformCulture(netLanguage));
                    ci = new System.Globalization.CultureInfo(fallback);
                }
                catch (CultureNotFoundException e2)
                {
                    // iOS language not valid .NET culture, falling back to English
                    ci = new System.Globalization.CultureInfo("en");
                }
            }
            return ci;
        }

        string iOSToDotnetLanguage(string iOSLanguage)
        {
            // .NET cultures don't support underscores
            string netLanguage = iOSLanguage.Replace("_", "-");

            //certain languages need to be converted to CultureInfo equivalent
            switch (iOSLanguage)
            {
                case "ms-MY":   // "Malaysian (Malaysia)" not supported .NET culture
                case "ms-SG":    // "Malaysian (Singapore)" not supported .NET culture
                    netLanguage = "ms"; // closest supported
                    break;
                case "gsw-CH":  // "Schwiizertüütsch (Swiss German)" not supported .NET culture
                    netLanguage = "de-CH"; // closest supported
                    break;
                // add more application-specific cases here (if required)
                // ONLY use cultures that have been tested and known to work
            }
            return netLanguage;
        }

        string ToDotnetFallbackLanguage (PlatformCulture platCulture)
        {
            var netLanguage = platCulture.LanguageCode; // use the first part of the identifier (two chars, usually);
            switch (platCulture.LanguageCode)
            {
                case "pt":
                    netLanguage = "pt-PT"; // fallback to Portuguese (Portugal)
                    break;
                case "gsw":
                    netLanguage = "de-CH"; // equivalent to German (Switzerland) for this app
                    break;
                // add more application-specific cases here (if required)
                // ONLY use cultures that have been tested and known to work
            }
            return netLanguage;
        }
    }
}

Примечание

Блоки try/catch в методе GetCurrentCultureInfo имитируют резервное поведение, которое обычно используется с описателями языкового стандарта — если точное соответствие не найдено, выполняется поиск близкого соответствия на основе только языка (первый блок символов в языковом стандарте).The try/catch blocks in the GetCurrentCultureInfo method mimic the fallback behavior typically used with locale specifiers – if the exact match is not found, look for a close match based just on the language (first block of characters in the locale).

В случае Xamarin.Forms некоторые языковые стандарты являются допустимыми в iOS, но не соответствуют допустимому CultureInfo в .NET, и приведенный выше код пытается решить проблему.In the case of Xamarin.Forms, some locales are valid in iOS but do not correspond to a valid CultureInfo in .NET, and the code above attempts to handle this.

Например, на экране iOS Параметры > Общий язык & Регион можно выбрать Язык телефона Английский, а Регион — Испания, поэтому строка языкового стандарта будет выглядеть как "en-ES".For example, the iOS Settings > General Language & Region screen allows you to set your phone Language to English but the Region to Spain, which results in a locale string of "en-ES". Если создание CultureInfo завершается с ошибкой, код использует только первые две буквы для выбора отображаемого языка.When the CultureInfo creation fails, the code falls back to using just the first two letters to select the display language.

Разработчики должны изменить методы iOSToDotnetLanguage и ToDotnetFallbackLanguage для обработки конкретных случаев для поддерживаемых языков.Developers should modify the iOSToDotnetLanguage and ToDotnetFallbackLanguage methods to handle specific cases required for their supported languages.

Некоторые определяемые системой элементы пользовательского интерфейса автоматически переводятся в iOS, например кнопка Готово в элементе управления Picker.There are some system-defined user-interface elements that are automatically translated by iOS, such as the Done button on the Picker control. Чтобы заставить iOS перевести эти элементы, нужно указать поддерживаемые языки в файле Info.plist.To force iOS to translate these elements we need to indicate which languages we support in the Info.plist file. Вы можете добавить эти значения с помощью Info.plist > Источник следующим образом.You can add these values via Info.plist > Source as shown here:

Ключи локализации в Info.plistLocalization keys in Info.plist

Или вы можете открыть файл Info.plist в редакторе XML и изменить значения напрямую:Alternatively, open the Info.plist file in an XML editor and edit the values directly:

<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>

Когда вы реализуете службу зависимостей и обновите файл Info.plist, приложение для iOS сможет отображать локализованный текст.Once you've implemented the dependency service and updated Info.plist, the iOS app will be able to display localized text.

Примечание

Apple обрабатывает португальский не совсем так, как можно ожидать.Note that Apple treats Portuguese slightly differently than you'd expect. Из их документации: "используйте pt как идентификатор языка для португальского языка в Бразилии и pt-PT как идентификатор языка для португальского языка в Португалии" .From their docs: "use pt as the language ID for Portuguese as it is used in Brazil and pt-PT as the language ID for Portuguese as it is used in Portugal". Это означает, что, если португальский язык выбран в нестандартном языковом стандарте, резервным языком в iOS будет португальский (Бразилия), если только код не изменяет это поведение (например, как ToDotnetFallbackLanguage выше).This means when Portuguese language is chosen in a non-standard locale, the fallback language will be Brazilian Portuguese on iOS, unless code is written to change this behavior (such as the ToDotnetFallbackLanguage above).

Дополнительные сведения о локализации в iOS см. в разделе Локализация в iOS.For more information about iOS Localization, see iOS Localization.

Проект приложения AndroidAndroid Application Project

Android предоставляет текущий выбранный языковой стандарт через Java.Util.Locale.Default и тоже использует разделитель в виде символа подчеркивания вместо тире (который заменяется следующим кодом).Android exposes the currently selected locale via Java.Util.Locale.Default, and also uses an underscore separator instead of a dash (which is replaced by the following code). Добавьте в проект приложения Android эту реализацию службы зависимостей:Add this dependency service implementation to the Android application project:

[assembly:Dependency(typeof(UsingResxLocalization.Android.Localize))]

namespace UsingResxLocalization.Android
{
    public class Localize : UsingResxLocalization.ILocalize
    {
        public void SetLocale(CultureInfo ci)
        {
            Thread.CurrentThread.CurrentCulture = ci;
            Thread.CurrentThread.CurrentUICulture = ci;
        }
        public CultureInfo GetCurrentCultureInfo()
        {
            var netLanguage = "en";
            var androidLocale = Java.Util.Locale.Default;
            netLanguage = AndroidToDotnetLanguage(androidLocale.ToString().Replace("_", "-"));
            // this gets called a lot - try/catch can be expensive so consider caching or something
            System.Globalization.CultureInfo ci = null;
            try
            {
                ci = new System.Globalization.CultureInfo(netLanguage);
            }
            catch (CultureNotFoundException e1)
            {
                // iOS locale not valid .NET culture (eg. "en-ES" : English in Spain)
                // fallback to first characters, in this case "en"
                try
                {
                    var fallback = ToDotnetFallbackLanguage(new PlatformCulture(netLanguage));
                    ci = new System.Globalization.CultureInfo(fallback);
                }
                catch (CultureNotFoundException e2)
                {
                    // iOS language not valid .NET culture, falling back to English
                    ci = new System.Globalization.CultureInfo("en");
                }
            }
            return ci;
        }
        string AndroidToDotnetLanguage(string androidLanguage)
        {
            var netLanguage = androidLanguage;
            //certain languages need to be converted to CultureInfo equivalent
            switch (androidLanguage)
            {
                case "ms-BN":   // "Malaysian (Brunei)" not supported .NET culture
                case "ms-MY":   // "Malaysian (Malaysia)" not supported .NET culture
                case "ms-SG":   // "Malaysian (Singapore)" not supported .NET culture
                    netLanguage = "ms"; // closest supported
                    break;
                case "in-ID":  // "Indonesian (Indonesia)" has different code in  .NET
                    netLanguage = "id-ID"; // correct code for .NET
                    break;
                case "gsw-CH":  // "Schwiizertüütsch (Swiss German)" not supported .NET culture
                    netLanguage = "de-CH"; // closest supported
                    break;
                    // add more application-specific cases here (if required)
                    // ONLY use cultures that have been tested and known to work
            }
            return netLanguage;
        }
        string ToDotnetFallbackLanguage(PlatformCulture platCulture)
        {
            var netLanguage = platCulture.LanguageCode; // use the first part of the identifier (two chars, usually);
            switch (platCulture.LanguageCode)
            {
                case "gsw":
                    netLanguage = "de-CH"; // equivalent to German (Switzerland) for this app
                    break;
                    // add more application-specific cases here (if required)
                    // ONLY use cultures that have been tested and known to work
            }
            return netLanguage;
        }
    }
}

Примечание

Блоки try/catch в методе GetCurrentCultureInfo имитируют резервное поведение, которое обычно используется с описателями языкового стандарта — если точное соответствие не найдено, выполняется поиск близкого соответствия на основе только языка (первый блок символов в языковом стандарте).The try/catch blocks in the GetCurrentCultureInfo method mimic the fallback behavior typically used with locale specifiers – if the exact match is not found, look for a close match based just on the language (first block of characters in the locale).

В случае Xamarin.Forms некоторые языковые стандарты являются допустимыми в Android, но не соответствуют допустимому CultureInfo в .NET, и приведенный выше код пытается решить проблему.In the case of Xamarin.Forms, some locales are valid in Android but do not correspond to a valid CultureInfo in .NET, and the code above attempts to handle this.

Разработчики должны изменить методы iOSToDotnetLanguage и ToDotnetFallbackLanguage для обработки конкретных случаев для поддерживаемых языков.Developers should modify the iOSToDotnetLanguage and ToDotnetFallbackLanguage methods to handle specific cases required for their supported languages.

Когда этот код будет добавлен в проект приложения Android, он сможет автоматически отображать переведенные строки.Once this code has been added to the Android application project, it will be able to automatically display translated strings.

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

Если переведенные строки работают в сборках выпуска Android, но не во время отладки, щелкните правой кнопкой мыши Проект Android, выберите Параметры > Сборка > Сборка Android и убедитесь, что флажок Быстрое развертывание сборок не установлен.If the translated strings are working in your RELEASE Android builds but not while debugging, right-click on the Android Project and select Options > Build > Android Build and ensure that the Fast assembly deployment is NOT ticked. Этот параметр вызывает проблемы с загрузкой ресурсов, и его не следует использовать при тестировании локализованных приложений.This option causes problems with loading resources and should not be used if you are testing localized apps.

Дополнительные сведения о локализации в Android см. в разделе Локализация в Android.For more information about Android localization, see Android Localization.

Универсальная платформа WindowsUniversal Windows Platform

Проекты универсальной платформы Windows (UWP) не требуют службы зависимостей.Universal Windows Platform (UWP) projects do not require the dependency service. Вместо этого эта платформа автоматически правильно задает язык и региональные параметры ресурса.Instead, this platform automatically sets the resource's culture correctly.

AssemblyInfo.csAssemblyInfo.cs

Разверните узел свойств в проекте библиотеки .NET Standard и дважды щелкните файл AssemblyInfo.cs.Expand the Properties node in the .NET Standard library project and double-click on the AssemblyInfo.cs file. Добавьте следующую строку в файл, чтобы установить английский в качестве нейтрального языка сборки ресурсов:Add the following line to the file to set the neutral resources assembly language to English:

[assembly: NeutralResourcesLanguage("en")]

Это значение сообщает диспетчеру ресурсов язык и региональные параметры приложения по умолчанию, поэтому строки, определенные в RESX-файле, не учитывающем язык (AppResources.resx), будут отображаться, когда приложение выполняется в одном из языковых стандартов на английском языке.This informs the resource manager of the app's default culture, therefore ensuring that the strings defined in the language neutral RESX file (AppResources.resx) will be displayed when the app is running in one the English locales.

ПримерExample

После обновления проектов для конкретной платформы, как показано выше, и перекомпиляции приложения с переведенными RESX-файлами обновленные переводы будут доступны в каждом приложении.After updating the platform-specific projects as shown above and recompiling the app with translated RESX files, updated translations will be available in each app. Ниже приведен снимок экрана из примера кода, переведенный на упрощенный китайский язык.Here is a screenshot from the sample code translated into Simplified Chinese:

Дополнительные сведения о локализации на универсальной платформе Windows см. в разделе Локализация на универсальной платформе Windows.For more information about UWP localization, see UWP Localization.

Локализация XAMLLocalizing XAML

При сборке пользовательского интерфейса Xamarin.Forms в XAML разметка будет выглядеть примерно следующим образом и строки будут внедрены напрямую в XML:When building a Xamarin.Forms user interface in XAML the markup would look similar to this, with strings embedded directly in the XML:

<Label Text="Notes:" />
<Entry Placeholder="eg. buy milk" />
<Button Text="Add to list" />

В идеале мы могли бы перевести элементы пользовательского интерфейса напрямую в XAML с помощью создания расширения разметки.Ideally, we could translate user interface controls directly in the XAML, which we can do by creating a markup extension. Ниже приведен код для расширения разметки, предоставляющего ресурсы RESX для XAML.The code for a markup extension that exposes the RESX resources to XAML is shown below. Этот класс следует добавить в общий код Xamarin.Forms (вместе со страницами XAML):This class should be added to the Xamarin.Forms common code (along with the XAML pages):

using System;
using System.Globalization;
using System.Reflection;
using System.Resources;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace UsingResxLocalization
{
    // You exclude the 'Extension' suffix when using in XAML
    [ContentProperty("Text")]
    public class TranslateExtension : IMarkupExtension
    {
        readonly CultureInfo ci = null;
        const string ResourceId = "UsingResxLocalization.Resx.AppResources";

        static readonly Lazy<ResourceManager> ResMgr = new Lazy<ResourceManager>(
            () => new ResourceManager(ResourceId, IntrospectionExtensions.GetTypeInfo(typeof(TranslateExtension)).Assembly));

        public string Text { get; set; }

        public TranslateExtension()
        {
            if (Device.RuntimePlatform == Device.iOS || Device.RuntimePlatform == Device.Android)
            {
                ci = DependencyService.Get<ILocalize>().GetCurrentCultureInfo();
            }
        }

        public object ProvideValue(IServiceProvider serviceProvider)
        {
            if (Text == null)
                return string.Empty;

            var translation = ResMgr.Value.GetString(Text, ci);
            if (translation == null)
            {
#if DEBUG
                throw new ArgumentException(
                    string.Format("Key '{0}' was not found in resources '{1}' for culture '{2}'.", Text, ResourceId, ci.Name),
                    "Text");
#else
                translation = Text; // HACK: returns the key, which GETS DISPLAYED TO THE USER
#endif
            }
            return translation;
        }
    }
}

Ниже объясняются важные элементы в приведенном выше коде.The following bullets explain the important elements in the code above:

  • Класс назван TranslateExtension, но по соглашению мы можем называть его Translate в нашей разметке.The class is named TranslateExtension, but by convention we can refer to is as Translate in our markup.
  • Этот класс реализует IMarkupExtension, которое необходимо для работы Xamarin.Forms.The class implements IMarkupExtension, which is required by Xamarin.Forms for it to work.
  • "UsingResxLocalization.Resx.AppResources" — это идентификатор ресурса для ресурсов RESX."UsingResxLocalization.Resx.AppResources" is the resource identifier for our RESX resources. Он состоит из нашего пространства имен по умолчанию, папки, где находятся файлы ресурсов, и имени файла RESX по умолчанию.It is comprised of our default namespace, the folder where the resource files are located and the default RESX filename.
  • Класс ResourceManager создается с помощью IntrospectionExtensions.GetTypeInfo(typeof(TranslateExtension)).Assembly) для определения текущей сборки для загрузки ресурсов и кэшируется в статическом поле ResMgr.The ResourceManager class is created using IntrospectionExtensions.GetTypeInfo(typeof(TranslateExtension)).Assembly) to determine the current assembly to load resources from, and cached in the static ResMgr field. Он создается как тип Lazy, чтобы его создание откладывалось до первого использования в методе ProvideValue.It's created as a Lazy type so that its creation is deferred until it's first used in the ProvideValue method.
  • ci использует службу зависимостей для получения выбранного языка пользователя из собственной операционной системы.ci uses the dependency service to get the user's chosen language from the native operating system.
  • GetString — это метод, который извлекает фактическую переведенную строку из файлов ресурсов.GetString is the method that retrieves the actual translated string from the resources files. На универсальной платформе Windows ci будет иметь значение NULL, так как интерфейс ILocalize не реализован на этих платформах.On the Universal Windows Platform, ci will be null because the ILocalize interface isn't implemented on those platforms. Это эквивалентно вызову метода GetString только с первым параметром.This is equivalent to calling the GetString method with only the first parameter. Вместо этого платформа ресурсов автоматически распознает языковой стандарт и извлекает переведенную строку из соответствующего RESX-файла.Instead, the resources framework will automatically recognize the locale and will retrieve the translated string from the appropriate RESX file.
  • Включена обработка ошибок для отладки отсутствующих ресурсов путем создания исключения (только в режиме DEBUG).Error handling has been included to help debug missing resources by throwing an exception (in DEBUG mode only).

В следующем фрагменте XAML показано, как использовать расширение разметки.The following XAML snippet shows how to use the markup extension. Для этого используется два шага:There are two steps to make it work:

  1. Объявите пользовательское пространство имен xmlns:i18n в корневом узле.Declare the custom xmlns:i18n namespace in the root node. namespace и assembly должны в точности соответствовать параметрам проекта — в этом примере они идентичны, но могут отличаться в вашем проекте.The namespace and assembly must match the project settings exactly - in this example they are identical but could be different in your project.
  2. Используйте синтаксис {Binding} для атрибутов, которые обычно содержат текст для вызова расширения разметки Translate.Use {Binding} syntax on attributes that would normally contain text to call the Translate markup extension. Ключ ресурса является единственным обязательным параметром.The resource key is the only required parameter.
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        x:Class="UsingResxLocalization.FirstPageXaml"
        xmlns:i18n="clr-namespace:UsingResxLocalization;assembly=UsingResxLocalization">
    <StackLayout Padding="0, 20, 0, 0">
        <Label Text="{i18n:Translate NotesLabel}" />
        <Entry Placeholder="{i18n:Translate NotesPlaceholder}" />
        <Button Text="{i18n:Translate AddButton}" />
    </StackLayout>
</ContentPage>

Следующий более подробный синтаксис также является допустимым для расширения разметки:The following more verbose syntax is also valid for the markup extension:

<Button Text="{i18n:TranslateExtension Text=AddButton}" />

Локализация элементов, зависящих от платформыLocalizing Platform-Specific Elements

Хотя мы можем обработать перевод пользовательского интерфейса в коде Xamarin.Forms, некоторые элементы необходимо выполнить в проекте для конкретной платформы.Although we can handle the translation of the user interface in Xamarin.Forms code, there are some elements that must be done in each platform-specific project. В этом разделе мы рассмотрим, как локализовать:This section will cover how to localize:

  • Application NameApplication Name
  • ОбразыImages

Пример проекта содержит локализованное изображение flag.png, на которое ссылается код C# следующим образом:The sample project includes a localized image called flag.png, which is referenced in C# as follows:

var flag = new Image();
switch (Device.RuntimePlatform)
{
    case Device.iOS:
    case Device.Android:
        flag.Source = ImageSource.FromFile("flag.png");
        break;
    case Device.UWP:
        flag.Source = ImageSource.FromFile("Assets/Images/flag.png");
        break;
}

На изображение флага также есть ссылки в XAML:The flag image is also referenced in the XAML like this:

<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>

Все платформы автоматически разрешают подобные ссылки на изображение до локализованных версий изображений, если реализуются структуры проекта, описанные ниже.All platforms will automatically resolve image references like these to localized versions of the images, as long as the project structures explained below are implemented.

Проект приложения iOSiOS Application Project

iOS использует стандарт именования "Проекты локализации" или каталоги .lproj для хранения ресурсов изображений и строк.iOS uses a naming standard called Localization Projects or .lproj directories to contain image and string resources. Эти каталоги могут содержать локализованные версии изображений, используемых в приложении, а также файл InfoPlist.strings, который можно использовать для локализации имени приложения.These directories can contain localized versions of images used in the app, and also the InfoPlist.strings file that can be used to localize the app name. Дополнительные сведения о локализации в iOS см. в разделе Локализация в iOS.For more information about iOS Localization, see iOS Localization.

ОбразыImages

На этом снимке экрана показан пример приложения iOS с языковыми каталогами .lproj.This screenshot shows the iOS sample app with language-specific .lproj directories. Испанский каталог es.lproj содержит локализованные версии изображения по умолчанию, а также flag.png.The Spanish directory called es.lproj, contains localized versions of the default image, as well as flag.png:

Каждый каталог языка содержит копию файла flag.png, локализованного для этого языка.Each language directory contains a copy of flag.png, localized for that language. Если изображение не предоставляется, операционная система по умолчанию выберет изображение в каталоге языка по умолчанию.If no image is supplied, the operating system will default to the image in the default language directory. Для полной поддержки Retina необходимо предоставить копии @2x и @3x каждого изображения.For full Retina support, you should supply @2x and @3x copies of each image.

Имя приложенияApp Name

Содержание InfoPlist.strings — всего одна пара "ключ — значение" для настройки имени приложения:The contents of the InfoPlist.strings is just a single key-value to configure the app name:

"CFBundleDisplayName" = "ResxEspañol";

При запуске приложения имя приложения и изображение локализуются:When the application is run, the app name and the image are both localized:

Проект приложения AndroidAndroid Application Project

В Android используется другая схема хранения локализованных изображений с помощью разных каталогов прорисовываемых ресурсов и строк с суффиксом кода языка.Android follows a different scheme for storing localized images using different drawable and strings directories with a language code suffix. Когда нужен четырехбуквенный код языкового стандарта (например, zh-TW или pt-BR), Android требует дополнительную r после тире/перед кодом языкового стандарта (например,When a four-letter locale code is required (such as zh-TW or pt-BR), note that Android requires an additional r following the dash/preceding the locale code (eg. zh-rTW или pt-rBR).zh-rTW or pt-rBR). Дополнительные сведения о локализации в Android см. в разделе Локализация в Android.For more information about Android localization, see Android Localization.

ОбразыImages

На этом снимке экрана показан пример Android с локализованными строками и прорисовываемыми ресурсами.This screenshot shows the Android sample with a some localized drawables and strings:

Android не использует коды zh-Hans и zh-Hant для упрощенного и традиционного китайского, а поддерживает только коды страны zh-CN и zh-TW.Note that Android does not use zh-Hans and zh-Hant codes for Simplified and Traditional Chinese; instead, it only supports country-specific codes zh-CN and zh-TW.

Для поддержки изображений в другом разрешении для экранов с высокой плотностью создайте дополнительные языковые папки с суффиксами -*dpi, например drawables-es-mdpi, drawables-es-xdpi, drawables-es-xxdpi и т. д. Дополнительные сведения см. в разделе Предоставление альтернативных ресурсов Android.To support different resolution images for high-density screens, create additional language folders with -*dpi suffixes, such as drawables-es-mdpi, drawables-es-xdpi, drawables-es-xxdpi, etc. See Providing Alternative Android Resources for more information.

Имя приложенияApp Name

Содержание strings.xml — всего одна пара "ключ — значение" для настройки имени приложения:The contents of the strings.xml is just a single key-value to configure the app name:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">ResxEspañol</string>
</resources>

Обновите MainActivity.cs в проекте приложения Android, чтобы Label ссылался на строки XML.Update the MainActivity.cs in the Android app project so that the Label references the strings XML.

[Activity (Label = "@string/app_name", MainLauncher = true,
        ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]

Приложение теперь локализует имя приложения и изображение.The app now localizes the app name and image. Ниже приведен снимок экрана результата (на испанском языке).Here's a screenshot of the result (in Spanish):

Проекты приложений универсальной платформы WindowsUniversal Windows Platform Application Projects

Универсальная платформа Windows обладает инфраструктурой ресурсов, которая упрощает локализацию изображений и имени приложения.The Universal Windows Platform possesses a resource infrastructure that simplifies the localization of images and the app name. Дополнительные сведения о локализации на универсальной платформе Windows см. в разделе Локализация на универсальной платформе Windows.For more information about UWP localization, see UWP Localization.

ОбразыImages

Чтобы локализовать изображения, можно поместить их в папку для ресурса, как показано на следующем снимке экрана.Images can be localized by placing them in a resource-specific folder, as demonstrated in the following screenshot:

Во время выполнения инфраструктура ресурсов Windows выберет подходящее изображение на основе языкового стандарта пользователя.At runtime the Windows resource infrastructure will select the appropriate image based on the user's locale.

СводкаSummary

Приложения Xamarin.Forms можно локализовать с помощью RESX-файлов и классов глобализации .NET.Xamarin.Forms applications can be localized using RESX files and .NET globalization classes. Помимо небольшого объема кода для конкретных платформ для обнаружения языковых настроек пользователя, большая часть усилий по локализации направлена на общий код.Apart from a small amount of platform-specific code to detect what language the user prefers, most of the localization effort is centralized in the common code.

Изображения обычно обрабатываются платформой, чтобы использовать преимущества различных решений, предоставляемых в iOS и Android.Images are generally handled in a platform-specific way to take advantage of the multi-resolution support provided in both iOS and Android.