Приложения включают ресурсы, которые могут быть специфичными для определенной культуры. Например, приложение может включать строки, специфичные для языка и региональных параметров, которые переведены на язык текущей локали.
Хорошей практикой является отделение ресурсов, специфичных для конкретной культуры, от остальной части вашего приложения. Android определяет ресурсы, зависящие от языка и культуры, на основе настроек языкового стандарта системы. Вы можете обеспечить поддержку различных локалей, используя каталог ресурсов в своем проекте Android.
Вы можете указать ресурсы, адаптированные к культуре людей, использующих ваше приложение. Вы можете предоставить любой тип ресурса , соответствующий языку и культуре ваших пользователей. Например, на следующих снимках экрана показано приложение, отображающее строки и доступные для рисования ресурсы в языковом стандарте устройства по умолчанию en_US
и испанском языковом стандарте es_ES
.
Когда вы создаете проект с помощью инструментов Android SDK, эти инструменты создают каталог res/
на верхнем уровне проекта. В этом каталоге res/
находятся подкаталоги для различных типов ресурсов. Существует также несколько файлов по умолчанию, например файл res/values/strings.xml
, в котором хранятся строковые значения.
Поддержка разных языков выходит за рамки использования ресурсов, специфичных для локали. Некоторые пользователи выбирают язык, в котором используются сценарии с письмом справа налево (RTL), например арабский или иврит, в качестве языкового стандарта пользовательского интерфейса. Другие пользователи, которые установили в качестве языкового стандарта пользовательского интерфейса язык, использующий сценарии LTR, например английский, могут просматривать или создавать контент на языке, использующем сценарии RTL. Чтобы поддерживать оба типа пользователей, ваше приложение должно выполнять следующие действия:
- Используйте макет пользовательского интерфейса RTL для локалей RTL.
- Обнаруживайте и объявляйте направление текстовых данных, отображаемых внутри форматированных сообщений. Обычно вы можете вызвать метод , как описано в этом руководстве, который определяет за вас направление текстовых данных.
Создание каталогов локали и файлов ресурсов.
Чтобы добавить поддержку большего количества локалей, создайте дополнительные каталоги внутри 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
:
Значок испанского флага (локаль es_ES
) в /mipmap-b+es+ES/country_flag.png
:
Примечание. Вы можете использовать квалификаторы конфигурации, такие как квалификатор языкового стандарта, для любого типа ресурса. Например, вы можете захотеть предоставить локализованные версии ваших растровых изображений. Дополнительную информацию см. в разделе Локализация вашего приложения .
Используйте ресурсы вашего приложения
Ссылайтесь на ресурсы в исходном коде и других XML-файлах, используя атрибут name
каждого ресурса: R.<resource type>.<resource name>
. Существует множество методов, принимающих ресурс таким образом, как показано в следующих примерах:
Котлин
// 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) }
Ява
// 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
. Дополнительные сведения см. в разделе Указание языков, поддерживаемых вашим приложением .
Форматирование текста в сообщениях
Одной из наиболее распространенных задач в приложении является форматирование текста. Локализованные сообщения форматируются путем вставки текстовых и числовых данных в соответствующие позиции. К сожалению, при работе с пользовательским интерфейсом RTL или данными RTL простое форматирование может отображать неправильный или даже нечитаемый текстовый вывод.
На таких языках, как арабский, иврит, персидский и урду, используется письмо RTL. Однако некоторые элементы, такие как числа и встроенный текст LTR, записываются LTR внутри текста RTL. Языки, использующие сценарии LTR, включая английский, также являются двунаправленными, поскольку могут содержать встроенные сценарии RTL, которые необходимо отображать с письмом справа налево.
Приложения часто генерируют экземпляры такого рода встроенного текста в противоположном направлении, например, путем вставки текстовых данных произвольного языка и произвольного направления текста в локализованные сообщения. Такое смешение направлений часто не включает четкого указания того, где начинается и заканчивается текст в противоположном направлении, поэтому текст, генерируемый приложением, может ухудшить взаимодействие с пользователем.
Хотя система по умолчанию обрабатывает двунаправленный текст, как правило, отображает текст должным образом, текст может отображаться неправильно, когда ваше приложение вставляет его в локализованное сообщение. Ниже приведены примеры ситуаций, в которых текст может отображаться неправильно:
Текст, вставленный в начало сообщения:
PERSON_NAME звонит вам
Текст, начинающийся с цифры, например адреса или номера телефона:
987 654-3210
Текст, начинающийся со знаков препинания, например номер телефона:
+19876543210
Текст, заканчивающийся знаками препинания:
Вы уверены?
Текст, который уже содержит оба направления:
Слово בננה на иврите означает банан.
Пример
Предположим, приложению иногда необходимо отображать сообщение «Вы имели в виду %s?» с адресом, вставленным вместо %s во время выполнения. Приложение поддерживает разные локали пользовательского интерфейса, поэтому сообщение поступает из ресурса, специфичного для локали, и использует направление RTL, когда на устройстве установлен локаль RTL. Например, для пользовательского интерфейса на иврите сообщение выглядит следующим образом:
האם התכוונת ל %s ?
Однако предлагаемый адрес может быть взят из базы данных, которая не содержит текста на языке локали. Например, если адрес относится к месту в Калифорнии, он отображается в базе данных с текстом на английском языке. Если вы вставите адрес «15 Bay Street, Laurel, CA» в сообщение с письмом справа налево без каких-либо подсказок относительно направления текста, результат не будет ожидаемым или правильным:
Где находится: Бэй-стрит, 15, Лорел, Калифорния?
Номер дома отображается справа от адреса, а не слева, как предполагалось. Из-за этого номер дома больше похож на странный почтовый индекс. Та же проблема может возникнуть, если вы включите текст RTL в сообщение, использующее направление текста LTR.
Объяснение и решение
Проблема в этом примере возникает из-за того, что форматировщик текста не указывает, что «15» является частью адреса, поэтому система не может определить, является ли «15» частью текста RTL, который идет перед ним, или текста LTR. это происходит после этого.
Чтобы решить эту проблему, используйте метод unicodeWrap()
из класса BidiFormatter
. Этот метод определяет направление строки и оборачивает ее в символы форматирования Юникода, задающие это направление.
Следующий фрагмент кода демонстрирует, как использовать unicodeWrap()
:
Котлин
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))
Ява
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» теперь появляется внутри текста, объявленного как LTR, она отображается в правильном положении:
Адрес : 15 Bay Street, Лорел, Калифорния ?
Используйте метод unicodeWrap()
для каждого фрагмента текста, который вы вставляете в локализованное сообщение, за исключением случаев, когда применимо одно из следующих условий:
- Текст вставляется в машиночитаемую строку, например URI или SQL-запрос.
- Вы знаете, что фрагмент текста уже правильно упакован.
Примечание. Если ваше приложение предназначено для Android 4.3 (уровень API 18) или более поздней версии, используйте версию BidiFormatter
, найденную в Android Framework. В противном случае используйте версию BidiFormatter
, найденную в библиотеке поддержки.
Формат чисел
Используйте строки формата , а не вызовы методов, для преобразования чисел в строки в логике вашего приложения:
Котлин
var myIntAsString = "$myInt"
Ява
String myIntAsString = String.format("%d", myInt);
Это форматирует числа в соответствии с вашим языковым стандартом, что может включать использование другого набора цифр.
Когда вы используете String.format()
для создания SQL-запроса на устройстве, для которого установлен языковой стандарт, использующий собственный набор цифр, например персидский и большинство арабских языковых стандартов, возникают проблемы, если какой-либо из параметров запроса является числом. Это связано с тем, что число отформатировано цифрами языкового стандарта, и эти цифры недопустимы в SQL.
Чтобы сохранить числа в формате ASCII и обеспечить корректность SQL-запроса, вместо этого необходимо использовать перегруженную версию String.format()
, которая включает локаль в качестве первого параметра. Используйте аргумент локали Locale.US
.
Поддержка зеркального отображения макета
Люди, использующие сценарии RTL, предпочитают пользовательский интерфейс RTL, который включает меню, выровненный по правому краю, текст, выровненный по правому краю, и стрелки вперед, указывающие влево.
На рис. 4 показан контраст между версией экрана с буквенным и правым письмом в приложении «Настройки» и его аналогом с письмом с письмом справа налево:
Добавляя поддержку RTL в ваше приложение, имейте в виду следующие моменты:
- Зеркальное отображение текста RTL поддерживается только в приложениях при использовании на устройствах под управлением Android 4.2 (уровень API 17) или выше. Чтобы узнать, как поддерживать зеркальное отображение текста на старых устройствах, см. раздел Обеспечение поддержки устаревших приложений в этом руководстве.
- Чтобы проверить, поддерживает ли ваше приложение направление текста с письмом справа налево, протестируйте его, используя параметры разработчика , как описано в этом руководстве, и пригласите людей, использующих сценарии с письмом справа налево, использовать ваше приложение.
Примечание. Чтобы просмотреть дополнительные рекомендации по проектированию, связанные с зеркальным отображением макета, включая список элементов, которые можно и не следует зеркально отображать, см. Рекомендации по проектированию материалов двунаправленности .
Чтобы отразить макет пользовательского интерфейса в вашем приложении, чтобы он отображался с RTL в языковом стандарте RTL, выполните действия, описанные в следующих разделах.
Измените файлы сборки и манифеста.
Измените файл build.gradle
модуля приложения и файл манифеста приложения следующим образом:
build.gradle (Module: app)
классный
android { ... defaultConfig { targetSdkVersion 17 // Or higher ... } }
Котлин
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
атрибутов, которые появляются в файлах макета вашего приложения. В этом случае зеркальное отображение макета RTL в вашем приложении не происходит автоматически.
Обновить существующие ресурсы
Преобразуйте left
и right
в start
и end
соответственно в существующих файлах ресурсов макета. Это позволяет платформе согласовывать элементы пользовательского интерфейса вашего приложения с учетом языковых настроек пользователя.
Примечание. Прежде чем обновлять ресурсы, узнайте, как обеспечить поддержку устаревших приложений или приложений, предназначенных для Android 4.1.1 (уровень API 16) и более ранних версий.
Чтобы использовать возможности выравнивания RTL платформы, измените атрибуты в файлах макета, которые представлены в таблице 1.
В таблице 2 показано, как система обрабатывает атрибуты выравнивания пользовательского интерфейса в зависимости от целевой версии SDK, определены ли left
и right
атрибуты, а также определены ли start
и end
атрибуты.
| Левое и правое определены? | Начало и конец определены? | Результат |
---|---|---|---|
Да | Да | Да | используются 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 используют квалификаторы языка ресурса, чтобы определить правильное направление текста.
Предположим, вы хотите добавить определенный файл макета для поддержки сценариев RTL, таких как иврит, арабский и персидский языки. Для этого добавьте каталог 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), большинство элементов пользовательского интерфейса платформы автоматически поддерживают направление текста RTL. Однако некоторые элементы платформы, такие как ViewPager
, не поддерживают направление текста RTL.
Виджеты главного экрана поддерживают направление текста RTL, если соответствующие файлы манифеста содержат назначение атрибута android:supportsRtl="true"
.
Обеспечьте поддержку устаревших приложений
Если ваше приложение предназначено для Android 4.1.1 (уровень API 16) или более ранней версии, помимо start
и end
включите атрибуты left
и right
.
Чтобы проверить, нужно ли вашему макету использовать направление текста RTL, используйте следующую логику:
Котлин
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 } }
Ява
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) или выше вы можете включить принудительное направление макета RTL в настройках разработчика на устройстве . Этот параметр позволяет просматривать текст, использующий сценарии LTR, например текст на английском языке, в режиме RTL.
Обновить логику приложения
В этом разделе описаны конкретные аспекты логики вашего приложения, которые необходимо обновить при адаптации вашего приложения для обработки нескольких направлений текста.
Изменения свойств
Чтобы обработать изменение любого свойства, связанного с RTL, например направления макета, параметров макета, заполнения, направления текста, выравнивания текста или положения рисования, используйте обратный вызов onRtlPropertiesChanged()
. Этот обратный вызов позволяет вам получить текущее направление макета и соответствующим образом обновить объекты View
действия.
Просмотры
Если вы создаете виджет пользовательского интерфейса, который не является непосредственно частью иерархии представлений действия, например диалоговое окно или всплывающий элемент пользовательского интерфейса, установите правильное направление макета в зависимости от контекста. Следующий фрагмент кода демонстрирует, как завершить этот процесс:
Котлин
val config: Configuration = context.resources.configuration view.layoutDirection = config.layoutDirection
Ява
final Configuration config = getContext().getResources().getConfiguration(); view.setLayoutDirection(config.getLayoutDirection());
Некоторые методы класса View
требуют дополнительного рассмотрения:
-
onMeasure()
- Размеры просмотра могут различаться в зависимости от направления текста.
-
onLayout()
- Если вы создаете собственную реализацию макета, вам необходимо вызвать
super()
в вашей версииonLayout()
и адаптировать свою собственную логику для поддержки сценариев RTL. -
onDraw()
- Если вы реализуете настраиваемое представление или добавляете в чертеж расширенные функции, вам необходимо обновить код для поддержки сценариев RTL. Используйте следующий код, чтобы определить, находится ли ваш виджет в режиме RTL:
Котлин
// 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
Ява
// 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); }
Рисованные
Если у вас есть объект, который необходимо отразить для макета RTL, выполните один из этих шагов в зависимости от версии Android, работающей на устройстве:
- На устройствах под управлением Android 4.3 (уровень API 18) и более ранних версий добавьте и определите файлы ресурсов
-ldrtl
. В Android 4.4 (уровень API 19) и выше используйте
android:autoMirrored="true"
при определении объекта рисования, что позволяет системе обрабатывать зеркальное отображение макета RTL за вас.Примечание. Атрибут
android:autoMirrored
работает только для простых объектов рисования, двунаправленное зеркалирование которых представляет собой просто графическое отражение всего объекта рисования. Если ваш объект рисования содержит несколько элементов или если отражение вашего объекта рисования меняет его интерпретацию, вы можете выполнить зеркальное отображение самостоятельно. По возможности проконсультируйтесь с двунаправленным экспертом, чтобы определить, имеют ли ваши зеркальные изображения смысл для пользователей.
Гравитация
Если код макета вашего приложения использует Gravity.LEFT
или Gravity.RIGHT
, измените эти значения на Gravity.START
и Gravity.END
соответственно.
Если у вас есть код Kotlin или Java, который зависит от свойств Gravity.LEFT
или Gravity.RIGHT
, вы можете адаптировать его для работы с этим изменением, установив absoluteGravity
в соответствии с layoutDirection
.
Например, если вы используете следующий код:
Котлин
when (gravity and Gravity.HORIZONTAL_GRAVITY_MASK) { Gravity.LEFT -> { // Handle objects that are left-aligned. } Gravity.RIGHT -> { // Handle objects that are right-aligned. } }
Ява
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; }
Измените его на следующее:
Котлин
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. } }
Ява
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
.
Поля и отступы
Чтобы поддерживать сценарии RTL в вашем приложении, следуйте этим рекомендациям, связанным со значениями полей и заполнения:
- Используйте
getMarginStart()
иgetMarginEnd()
вместо эквивалентов атрибутов, специфичных для направления,leftMargin
иrightMargin
. - При использовании
setMargins()
поменяйте местами значенияleft
иright
аргументов, если ваше приложение обнаруживает сценарии RTL. - Если ваше приложение включает пользовательскую логику заполнения, переопределите
setPadding()
иsetPaddingRelative()
.
Поддержка языковых настроек для каждого приложения.
Во многих случаях многоязычные пользователи устанавливают в качестве языка своей системы один язык, например английский, но они хотят выбрать другие языки для конкретных приложений, например голландский, китайский или хинди. Чтобы приложения были более удобными для этих пользователей, в Android 13 представлены следующие функции для приложений, поддерживающих несколько языков:
Системные настройки : централизованное место, где пользователи могут выбрать предпочтительный язык для каждого приложения.
Ваше приложение должно объявить атрибут
android:localeConfig
в своем манифесте, чтобы сообщить системе, что оно поддерживает несколько языков. Дополнительные сведения см. в инструкциях по созданию файла ресурсов и его объявлению в файле манифеста вашего приложения .Дополнительные API : эти общедоступные API, такие как методы
setApplicationLocales()
иgetApplicationLocales()
вLocaleManager
, позволяют приложениям устанавливать язык, отличный от языка системы, во время выполнения.Приложения, которые используют собственные средства выбора языка в приложении, могут использовать эти API, чтобы предоставить пользователям единообразный пользовательский интерфейс независимо от того, где они выбирают свои языковые предпочтения. Публичные API также помогают сократить объем шаблонного кода и поддерживают разделенные APK. Они также поддерживают автоматическое резервное копирование приложений для хранения настроек языка пользователя на уровне приложения.
Для обратной совместимости с предыдущими версиями Android в AndroidX также доступны эквивалентные API. Мы рекомендуем использовать Appcompat 1.6.0-beta01 или выше.
Чтобы узнать больше, ознакомьтесь с инструкциями по внедрению новых API .
См. также
Дополнительные ресурсы
Чтобы узнать больше о поддержке старых устройств, просмотрите следующие ресурсы:
Сообщения в блоге
- Чтобы сделать приложения доступными, сделайте их совместимыми с различными устройствами
- Пишу для мировой аудитории