Приложения содержат ресурсы, которые могут быть специфичны для определенной культуры. Например, в приложении могут быть строки, которые переводятся на язык текущего региона.
Рекомендуется хранить ресурсы, связанные с культурой, отдельно от остальных ресурсов приложения. Android выбирает ресурсы, связанные с языком и культурой, на основе системных настроек региональных стандартов. Вы можете обеспечить поддержку разных региональных настроек, используя каталог ресурсов в проекте для Android.
Вы можете указать ресурсы, адаптированные к культуре людей, использующих ваше приложение. Вы можете предоставить любой тип ресурса, соответствующий языку и культуре ваших пользователей. Например, на скриншотах ниже показано приложение, в котором отображаются строковые и прорисовываемые ресурсы для региональных настроек по умолчанию (en_US) и для испанского языка (es_ES).
Рисунок 1. Приложение, использующее разные ресурсы в зависимости от текущих региональных настроек.
При создании проекта с помощью Android SDK Tools в корневом каталоге проекта создается каталог res/. В каталоге res/ есть подкаталоги для разных типов ресурсов. Также есть несколько файлов по умолчанию, например res/values/strings.xml, в котором хранятся строковые значения.
Поддержка разных языков не ограничивается использованием ресурсов, зависящих от региона. Некоторые пользователи выбирают для интерфейса язык с направлением письма справа налево, например арабский или иврит. Другие пользователи, у которых в интерфейсе установлен язык с направлением письма слева направо, например английский, могут просматривать или создавать контент на языке с направлением письма справа налево. Чтобы поддерживать оба типа пользователей, ваше приложение должно делать следующее:
- Используйте макет пользовательского интерфейса с направлением письма справа налево для соответствующих регионов.
- Определяйте и указывайте направление текста, который показывается в форматированных сообщениях. Обычно вы можете вызвать метод, который определяет направление текста.
Создайте каталоги и файлы ресурсов для локалей
Чтобы добавить поддержку других языков, создайте дополнительные каталоги в res/. Название каждого каталога должно соответствовать следующему формату:
<resource type>-b+<language code>[+<country code>]
Например, values-b+es/ содержит строковые ресурсы для региональных настроек с кодом языка es. Аналогично, в папке mipmap-b+es+ES/ содержатся значки для регионов с кодом языка es и кодом страны ES.
Android загружает соответствующие ресурсы в соответствии с региональными настройками устройства во время выполнения. Подробнее об альтернативных ресурсах…
Определив, какие языки вы будете поддерживать, создайте подкаталоги и файлы ресурсов. Пример:
MyProject/
res/
values/
strings.xml
values-b+es/
strings.xml
mipmap/
country_flag.png
mipmap-b+es+ES/
country_flag.png
Заполните файлы ресурсов локализованными ресурсами. Ниже приведены примеры локализованных файлов строковых ресурсов и изображений.
Строки на английском языке (региональные настройки по умолчанию) в /values/strings.xml:
<resources> <string name="hello_world">Hello World!</string> </resources>
Строки на испанском языке (региональные настройки es) в /values-b+es/strings.xml:
<resources> <string name="hello_world">¡Hola Mundo!</string> </resources>
Значок флага США (региональные настройки по умолчанию) в /mipmap/country_flag.png:
Рисунок 2. Значок, используемый для региональных настроек по умолчанию (en_US).
Значок флага Испании (региональные настройки es_ES) в /mipmap-b+es+ES/country_flag.png:
Рисунок 3. Значок, используемый для региональных настроек es_ES.
Примечание. Квалификаторы конфигурации, например квалификатор региональных настроек, можно использовать с любым типом ресурсов. Например, вы можете предоставить локализованные версии графических объектов в виде битовых карт. Подробнее о том, как локализовать приложение…
Как использовать ресурсы в приложении
Чтобы сослаться на ресурсы в исходном коде и других XML-файлах, используйте атрибут name каждого ресурса: R.<resource type>.<resource name>. Ниже приведены примеры методов, которые принимают ресурс таким образом.
Kotlin
// Get a string resource val hello = resources.getString(R.string.hello_world) // Or supply a string resource to a method that requires a string TextView(this).apply { setText(R.string.hello_world) }
Java
// Get a string resource String hello = getResources().getString(R.string.hello_world); // Or supply a string resource to a method that requires a string TextView textView = new TextView(this); textView.setText(R.string.hello_world);
В XML-файлах вы можете ссылаться на ресурс с помощью синтаксиса @<resource type>/<resource name>, когда атрибут XML принимает совместимое значение, как показано в следующем примере:
<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@mipmap/country_flag" />
Примечание. Чтобы языковые настройки пользователя имели правильный приоритет, укажите языки, которые поддерживает ваше приложение, с помощью свойства resConfigs. Подробнее о том, как указать поддерживаемые языки…
Как форматировать текст в сообщениях
Одна из самых распространенных задач в приложении – форматирование текста. Локализованные сообщения форматируются путем вставки текста и числовых данных в соответствующие позиции. К сожалению, при работе с интерфейсом или данными с письмом справа налево простое форматирование может привести к неправильному или даже нечитаемому тексту.
Например, на арабском, иврите, персидском и урду. Однако некоторые элементы, например числа и встроенный текст с направлением слева направо, пишутся слева направо в тексте с направлением справа налево. Языки, в которых используется письмо слева направо, включая английский, также являются двунаправленными, поскольку могут содержать встроенные фрагменты с письмом справа налево, которые должны отображаться справа налево.
Приложения часто генерируют экземпляры такого встроенного текста противоположного направления, например, путем вставки текстовых данных произвольного языка и произвольного направления текста в локализованные сообщения. При этом часто не указывается, где начинается и заканчивается текст, написанный в противоположном направлении, что может вызвать неудобства у пользователей.
Хотя система по умолчанию обрабатывает двунаправленный текст корректно, он может отображаться неправильно, когда приложение вставляет его в локализованное сообщение. Ниже приведены примеры ситуаций, в которых текст, скорее всего, будет отображаться неправильно:
-
Текст, вставляемый в начало сообщения:
PERSON_NAME звонит вам
-
Текст, который начинается с цифры, например адрес или номер телефона:
987 654-3210
-
Текст, который начинается со знака препинания, например номер телефона:
+19876543210
-
Текст, который заканчивается знаком препинания:
Вы уверены?
-
Текст, который уже содержит оба направления:
Слово בננה означает "банан" на иврите.
Пример
Предположим, что в приложении иногда должно появляться сообщение "Вы имели в виду %s?", где вместо %s во время выполнения вставляется адрес. Приложение поддерживает разные языки интерфейса, поэтому сообщение поступает из ресурса, зависящего от региональных настроек, и использует направление справа налево, когда на устройстве заданы региональные настройки с направлением справа налево. Например, в интерфейсе на иврите сообщение выглядит следующим образом:
האם התכוונת ל %s?
Однако предложенный адрес может быть взят из базы данных, в которой нет текста на языке региона. Например, если адрес относится к месту в Калифорнии, он будет представлен в базе данных на английском языке. Если вы вставите адрес "15 Bay Street, Laurel, CA" в сообщение с направлением письма справа налево, не указав направление текста, результат будет некорректным:
האם התכוונת ל 15 Bay Street, Laurel, CA?
Номер дома указан справа от адреса, а не слева, как должно быть. Из-за этого номер дома больше похож на странный почтовый индекс. Такая же проблема может возникнуть, если вы включите текст с направлением справа налево в сообщение, в котором используется направление слева направо.
Объяснение и решение
Проблема в этом примере возникает из-за того, что в средстве форматирования текста не указано, что "15" – это часть адреса. Поэтому система не может определить, относится ли "15" к тексту с направлением справа налево, который идет перед ним, или к тексту с направлением слева направо, который идет после него.
Чтобы решить эту проблему, используйте метод unicodeWrap() из класса BidiFormatter. Этот метод определяет направление строки и заключает ее в символы форматирования Unicode, которые объявляют это направление.
В следующем фрагменте кода показано, как использовать unicodeWrap():
Kotlin
val mySuggestion = "15 Bay Street, Laurel, CA" val myBidiFormatter: BidiFormatter = BidiFormatter.getInstance() // The "did_you_mean" localized string resource includes // a "%s" placeholder for the suggestion. String.format(getString(R.string.did_you_mean), myBidiFormatter.unicodeWrap(mySuggestion))
Java
String mySuggestion = "15 Bay Street, Laurel, CA"; BidiFormatter myBidiFormatter = BidiFormatter.getInstance(); // The "did_you_mean" localized string resource includes // a "%s" placeholder for the suggestion. String.format(getString(R.string.did_you_mean), myBidiFormatter.unicodeWrap(mySuggestion));
Поскольку число 15 теперь находится внутри текста, для которого задано направление слева направо, оно отображается в правильной позиции:
האם התכוונת ל 15 Bay Street, Laurel, CA?
Используйте метод unicodeWrap() для каждого фрагмента текста, который вы вставляете в локализованное сообщение, за исключением следующих случаев:
- Текст вставляется в машиночитаемую строку, например URI или SQL-запрос.
- Вы знаете, что фрагмент текста уже правильно перенесен.
Примечание. Если ваше приложение предназначено для Android 4.3 (уровень API 18) или более поздней версии, используйте версию BidiFormatter, которая находится в Android Framework. В противном случае используйте версию BidiFormatter из библиотеки поддержки.
Форматирование чисел
Для преобразования чисел в строки в логике приложения используйте строки форматирования, а не вызовы методов.
Kotlin
var myIntAsString = "$myInt"
Java
String myIntAsString = String.format("%d", myInt);
Это позволяет форматировать числа в соответствии с вашими региональными настройками, которые могут включать использование другого набора цифр.
Если вы используете String.format() для создания SQL-запроса на устройстве, где выбран язык с собственным набором цифр (например, персидский или большинство арабских языков), то при наличии в запросе числовых параметров могут возникнуть проблемы. Это связано с тем, что число отформатировано в цифрах региональных настроек, а эти цифры недопустимы в SQL.
Чтобы сохранить числа в формате ASCII и не нарушить работу SQL-запроса, используйте перегруженную версию String.format(), в которой в качестве первого параметра указан региональный стандарт. Используйте аргумент locale.
Locale.US
Поддержка зеркального отображения макета
Пользователи, использующие скрипты с письмом справа налево, предпочитают пользовательский интерфейс с выравниванием по правому краю, в котором меню и текст выровнены по правому краю, а стрелки "вперед" указывают влево.
На рисунке 4 показана разница между версиями экрана в приложении "Настройки" для языков с направлением письма слева направо и справа налево.
При добавлении поддержки RTL в приложение учитывайте следующее:
- Отражение текста с направлением письма справа налево поддерживается только в приложениях, используемых на устройствах с Android 4.2 (уровень API 17) или более поздней версии. Чтобы узнать, как обеспечить поддержку зеркального отображения текста на старых устройствах, ознакомьтесь с разделом Поддержка устаревших приложений в этом руководстве.
- Чтобы проверить, поддерживает ли ваше приложение направление письма справа налево, используйте параметры для разработчиков, как описано в этом руководстве, и пригласите пользователей, которые пишут справа налево, протестировать ваше приложение.
Примечание. Дополнительные рекомендации по зеркальному отображению макета, в том числе список элементов, которые можно и нельзя отображать зеркально, приведены в руководстве по двунаправленности Material Design.
Чтобы отразить макет пользовательского интерфейса в приложении, чтобы он отображался справа налево в региональных настройках с письмом справа налево, выполните действия, описанные в следующих разделах.
Измените файлы сборки и манифеста
Измените файл build.gradle модуля приложения и файл манифеста приложения следующим образом:
build.gradle (Module: app)
Яркий
android { ... defaultConfig { targetSdkVersion 17 // Or higher ... } }
Kotlin
android { ... defaultConfig { targetSdkVersion(17) // Or higher ... } }
AndroidManifest.xml
<manifest ... > ... <application ... android:supportsRtl="true"> </application> </manifest>
Примечание. Если ваше приложение предназначено для Android 4.1.1 (уровень API 16) или более ранней версии, атрибут android:supportsRtl игнорируется вместе со значениями атрибутов start и end, которые указаны в файлах макета приложения. В этом случае зеркальное отображение макета справа налево не происходит в вашем приложении автоматически.
Обновление существующих ресурсов
Замените left и right на start и end соответственно в существующих файлах ресурсов макета.
Это позволяет фреймворку выравнивать элементы интерфейса приложения в соответствии с языковыми настройками пользователя.
Примечание. Прежде чем обновлять ресурсы, узнайте, как обеспечить поддержку устаревших приложений или приложений, предназначенных для Android 4.1.1 (уровень API 16) и более ранних версий.
Чтобы использовать возможности фреймворка по выравниванию справа налево, измените атрибуты в файлах макета, указанные в таблице 1.
Таблица 1. Атрибуты, которые нужно использовать, если ваше приложение поддерживает несколько направлений текста
В таблице 2 показано, как система обрабатывает атрибуты выравнивания пользовательского интерфейса в зависимости от целевой версии SDK, а также от того, определены ли атрибуты left и right и атрибуты start и end.
Таблица 2. Выравнивание элементов интерфейса в зависимости от целевой версии SDK и заданных атрибутов
|
|
Определены ли левая и правая стороны? | Определены ли начало и конец? | Результат |
|---|---|---|---|
| Да | Да | Да |
Используются start и end, переопределяя left и right.
|
| Да | Да | Нет | Используются left и right |
| Да | Нет | Да | Используются start и end |
| Нет | Да | Да |
Используются left и right (start и end игнорируются)
|
| Нет | Да | Нет | Используются left и right |
| Нет | Нет | Да |
start и end разрешаются в left и right.
|
Добавьте ресурсы для конкретных языков и направлений письма
Для этого нужно добавить специальные версии макета, графических объектов и файлов ресурсов со значениями, которые содержат настроенные значения для разных языков и направлений текста.
В Android 4.2 (уровень API 17) и более поздних версиях можно использовать квалификаторы ресурсов -ldrtl (направление макета справа налево) и -ldltr (направление макета слева направо). Чтобы обеспечить обратную совместимость с существующими ресурсами, в более ранних версиях Android для определения правильного направления текста используются квалификаторы языка ресурса.
Предположим, вы хотите добавить специальный файл макета для поддержки языков с направлением письма справа налево, таких как иврит, арабский и персидский. Для этого добавьте каталог layout-ldrtl/ в каталог res/, как показано в примере ниже.
res/
layout/
main.xml This layout file is loaded by default.
layout-ldrtl/
main.xml This layout file is loaded for languages using an
RTL text direction, including Arabic, Persian, and Hebrew.
Если вы хотите добавить специальную версию макета, предназначенную только для арабского текста, структура каталога будет выглядеть следующим образом:
res/
layout/
main.xml This layout file is loaded by default.
layout-ar/
main.xml This layout file is loaded for Arabic text.
layout-ldrtl/
main.xml This layout file is loaded only for non-Arabic
languages that use an RTL text direction.
Примечание. Ресурсы, зависящие от языка, имеют приоритет над ресурсами, зависящими от направления макета, которые, в свою очередь, имеют приоритет над ресурсами по умолчанию.
Используйте поддерживаемые виджеты
Начиная с Android 4.2 (уровень API 17), большинство элементов пользовательского интерфейса фреймворка автоматически поддерживают направление текста справа налево. Однако некоторые элементы фреймворка, например ViewPager, не поддерживают направление текста справа налево.
Виджеты на главном экране поддерживают направление текста справа налево, если в их файлах манифеста есть атрибут android:supportsRtl="true".
Поддержка устаревших приложений
Если ваше приложение предназначено для Android 4.1.1 (уровень API 16) или более ранней версии, добавьте атрибуты left и right в дополнение к start и end.
Чтобы проверить, нужно ли использовать в макете направление текста справа налево, используйте следующую логику:
Kotlin
private fun shouldUseLayoutRtl(): Boolean { return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) { View.LAYOUT_DIRECTION_RTL == layoutDirection } else { false } }
Java
private boolean shouldUseLayoutRtl() { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) { return View.LAYOUT_DIRECTION_RTL == getLayoutDirection(); } else { return false; } }
Примечание. Чтобы избежать проблем с совместимостью, используйте Android SDK Build Tools версии 23.0.1 или более поздней.
Тестирование с помощью настроек для разработчиков
На устройствах с Android 4.4 (уровень API 19) или более поздней версии можно включить параметр Отразить интерфейс в Для разработчиков. Этот параметр позволяет просматривать текст, написанный слева направо, например на английском языке, в режиме справа налево.
Обновить логику приложения
В этом разделе описываются конкретные аспекты логики вашего приложения, которые необходимо обновить при адаптации приложения для обработки нескольких направлений текста.
Изменения ресурсов
Чтобы обработать изменение любого свойства, связанного с направлением справа налево, например направления макета, параметров макета, отступов, направления текста, выравнивания текста или позиционирования графических объектов, используйте обратный вызов onRtlPropertiesChanged(). Этот обратный вызов позволяет получить текущее направление макета и соответствующим образом обновить объекты View действия.
Просмотры
Если вы создаете виджет пользовательского интерфейса, который не является частью иерархии View, например диалоговое окно или всплывающее уведомление, задайте правильное направление макета в зависимости от контекста. В следующем фрагменте кода показано, как это сделать:
Kotlin
val config: Configuration = context.resources.configuration view.layoutDirection = config.layoutDirection
Java
final Configuration config = getContext().getResources().getConfiguration(); view.setLayoutDirection(config.getLayoutDirection());
Некоторые методы класса View требуют дополнительного внимания:
onMeasure()- Размеры могут различаться в зависимости от направления текста.
onLayout()- Если вы создаете собственную реализацию макета, вам нужно вызвать
super()в вашей версииonLayout()и адаптировать вашу пользовательскую логику для поддержки скриптов с направлением письма справа налево. onDraw()- Если вы реализуете специальный вид или добавляете расширенные функции в рисунок, вам необходимо обновить код для поддержки скриптов с письмом справа налево. Чтобы определить, находится ли виджет в режиме RTL, используйте следующий код:
Kotlin
// On devices running Android 4.1.1 (API level 16) and lower, // you can call the isLayoutRtl() system method directly. fun isLayoutRtl(): Boolean = layoutDirection == LAYOUT_DIRECTION_RTL
Java
// On devices running Android 4.1.1 (API level 16) and lower, // you can call the isLayoutRtl() system method directly. public boolean isLayoutRtl() { return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); }
Объекты Drawable
Если у вас есть объект Drawable, который нужно зеркально отразить для макета с направлением письма справа налево, выполните одно из следующих действий в зависимости от версии Android на устройстве:
-
На устройствах с Android 4.3 (уровень API 18) и более ранними версиями добавьте и определите файлы ресурсов
-ldrtl. -
В Android 4.4 (уровня API 19) и более поздних версиях при определении графического объекта используйте
android:autoMirrored="true". Это позволит системе автоматически зеркально отражать макеты с направлением письма справа налево.Примечание. Атрибут
android:autoMirroredработает только для простых графических объектов, двунаправленное зеркальное отображение которых представляет собой простое графическое зеркальное отображение всего графического объекта. Если ваш графический объект содержит несколько элементов или если его отражение меняет его интерпретацию, вы можете выполнить зеркальное отображение самостоятельно. По возможности проконсультируйтесь со специалистом по двунаправленному письму, чтобы определить, понятны ли пользователям ваши зеркальные графические объекты.
Гравитация
Если в коде макета приложения используются значения Gravity.LEFT или Gravity.RIGHT, замените их на Gravity.START и Gravity.END соответственно.
Если у вас есть код Kotlin или Java, который зависит от свойств Gravity.LEFT или Gravity.RIGHT, вы можете адаптировать его к этому изменению, задав для absoluteGravity значение, соответствующее layoutDirection.
Например, если вы используете следующий код:
Kotlin
when (gravity and Gravity.HORIZONTAL_GRAVITY_MASK) { Gravity.LEFT -> { // Handle objects that are left-aligned. } Gravity.RIGHT -> { // Handle objects that are right-aligned. } }
Java
switch (gravity & Gravity.HORIZONTAL_GRAVITY_MASK) { case Gravity.LEFT: // Handle objects that are left-aligned. break; case Gravity.RIGHT: // Handle objects that are right-aligned. break; }
Замените его на следующий:
Kotlin
val absoluteGravity: Int = Gravity.getAbsoluteGravity(gravity, layoutDirection) when (absoluteGravity and Gravity.HORIZONTAL_GRAVITY_MASK) { Gravity.LEFT -> { // Handle objects that are left-aligned. } Gravity.RIGHT -> { // Handle objects that are right-aligned. } }
Java
final int layoutDirection = getLayoutDirection(); final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection); switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { case Gravity.LEFT: // Handle objects that are left-aligned. break; case Gravity.RIGHT: // Handle objects that are right-aligned. break; }
Это означает, что вы можете сохранить существующий код, который обрабатывает значения с выравниванием по левому и правому краю, даже если вы используете start и end для значений гравитации.
Примечание. Применяя настройки гравитации, используйте перегруженную версию Gravity.apply(), которая включает аргумент layoutDirection.
Поля и отступы
Чтобы обеспечить поддержку языков с письмом справа налево, следуйте рекомендациям по настройке полей и отступов:
-
Используйте
getMarginStart()иgetMarginEnd()вместо атрибутовleftMarginиrightMargin, которые зависят от направления. -
Если вы используете
setMargins(), поменяйте местами значения аргументовleftиright, если ваше приложение обнаруживает скрипты с направлением письма справа налево. -
Если в вашем приложении используется собственная логика отступов, переопределите
setPadding()иsetPaddingRelative().
Поддержка языковых настроек для отдельных приложений
Часто пользователи, говорящие на нескольких языках, устанавливают один из них, например английский, как системный, но в некоторых приложениях хотят выбрать другой язык (нидерландский, китайский, хинди и т. п.). Чтобы разработчикам было проще создавать приложения для таких пользователей, в Android 13 появились следующие функции:
-
Системные настройки. Централизованный раздел, в котором пользователи могут выбрать предпочитаемый язык для каждого приложения.
Чтобы сообщить системе, что приложение поддерживает несколько языков, в его манифесте необходимо объявить атрибут
android:localeConfig. Подробнее о том, как создать файл ресурсов и объявить его в файле манифеста приложения… -
Дополнительные API. Эти общедоступные API, например методы
setApplicationLocales()иgetApplicationLocales()вLocaleManager, позволяют приложениям устанавливать язык, отличный от системного, во время выполнения.Приложения, в которых используются специальные средства выбора языка, могут использовать эти API, чтобы обеспечить пользователям единообразный интерфейс независимо от того, где они выбирают языковые настройки. Общедоступные API также позволяют сократить объем шаблонного кода и поддерживают раздельные APK. Они также поддерживают автоматическое резервное копирование для приложений, чтобы сохранять языковые настройки на уровне приложения.
Для обратной совместимости с предыдущими версиями Android в AndroidX также доступны эквивалентные API. Рекомендуем использовать Appcompat 1.6.0-beta01 или более позднюю версию.
Подробнее о том, как реализовать новые API…
Дополнительная информация
Дополнительные ресурсы
Дополнительную информацию о поддержке старых устройств можно найти в следующих ресурсах:
Записи в блоге
- Чтобы сделать приложения доступными, обеспечьте их совместимость с разными устройствами
- Как писать для глобальной аудитории