- Локализация. חתול מדען (хатуль мадан) — кот учёный
- Просмотр и создание локализованных строк в режиме дизайна
- Непереводимая игра слов с использованием местных идиоматических выражений
- Поддержка письма справа налево
- Несколько локалей
- The All-In-One Guide for Changing App Locale Dynamically in Android (Kotlin)
- 1. Setup SharedPreferences class
- 2. Setup Locale support class
- 3. Setup Application class
- 4. Setup BaseActivity class
- 5. Extending BaseActivity in each Activity
- 6. Adding localized strings.xml files
- Локализация Android-приложений: о чем умалчивает документация
- Введение
- Проблема № 1. Приложение отображается не на том языке
- «Один случай»
- Проблема № 2. Как узнать текущую локаль приложения?
- Проблема № 3. Как получить список предпочитаемых языков устройства?
- Заключение
- О переводчике
Локализация. חתול מדען (хатуль мадан) — кот учёный
В статье, посвященной ресурсам, мы уже затрагивали эту тему с теоретической точки зрения. Разберем теперь практическую часть. Мы уже умеем пользоваться строковыми ресурсами и меняли строчки, например, Hello, World на Здравствуй, Мир! Но на самом деле это не совсем правильный подход. Для профессионально написанного приложения лучше использовать другой подход. А именно, локализацию.
Что это значит? Мы не будем менять строчку Hello, World, которая будет считаться строкой по умолчанию, а создадим новый локализованный ресурс. Это даст нам дополнительное преимущество, если пользователь запустит приложение на телефоне с английской локалью, то он увидит текст на знакомом ему языке. Если приложение запустит русский пользователь, то он увидит текст на русском языке. Согласитесь — очень удобно.
Напишем приложение, которое будет поддерживать английскую и русскую локализации. По умолчанию будет использоваться английская локализация. В этом случае, если на телефоне не будет найден нужный локализованный ресурс, то будет применяться английский вариант.
Чтобы не усложнять материал, воспользуемся стандартным приложением, который мы изучали в самом начале. Создадим новый проект «LocaleApp», но на этот раз мы не будем трогать файл strings.xml в каталоге res/values.
Для русской локализации необходимо создать новый подкаталог values-ru в том же каталоге res. Если вы планируете создавать локализацию только для русского языка, то название каталога не трудно запомнить и вы можете создать папку вручную через res | New | Directory. Но вряд ли вы запомните названия других папок. Поэтому покажу способ создания с помощью мастера студии.
Щёлкаем правой кнопкой мыши на папке res и выбираем New | Android resource directory. В диалоговом окне в левой части Available qualifiers: выбираем пункт Locale и переносим его в правую часть Chosen qualifiers: с помощью кнопки с двумя стрелками вправо. В появившейся третьей колонке выбираем нужные языки, например, русский. Вы увидите, что в поле Directory name автоматически появится нужное название папки. Дополнительно вы можете указать и регион в колонке Specific Region Only
В режиме Android вы можете не увидеть созданную папку, поэтому временно переключитесь в режим Project. Скопируйте файл res/values/strings.xml и вставьте его в новую папку. Можете вернуться в прежний режим. Если папка не пуста, то она уже видна.
Изменим его содержание.
В английской версии им соответствуют ресурсы
Запустим приложение и увидим, что текст выводится на русском, если у вас на эмуляторе или реальном устройстве выбраны русские настройки.
Как перейти на американскую локаль? Идём в Настройки→Язык и клавиатура→Выбрать язык. Выбираем английский язык English (United States). Снова запускаем приложение в эмуляторе или на телефоне. Теперь наше приложение будет выглядеть так:
Ресурсы из каталога res/values считаются ресурсами по умолчанию. Они отображаются в том случае, когда система не найдёт ресурсы для текущей локали устройства. В нашем случае, при выборе любого языка, кроме русского будет использоваться res/values. Если мы захотим разделить англичан и американцев, тогда придётся создавать два каталога: res/values-en-rUK и res/values-en-rUS. Обратите внимание, что перед кодом второй части ставится буква ‘r’. Иными словами, мы определяем не только язык, но и регион.
Проведем несколько экспериментов. Удалим из файла res/values-ru/strings.xml строковый ресурс hello_world с текстом Здравствуй, Мир!. Сохраним изменения и запустим проект на устройстве с русским языком. Платформа заменила отсутствующий в локализации ресурс дефолтным английским.
Продолжим опыты и поступим наоборот — удалим теперь ресурс из файла res/values/strings.xml. На устройстве выберем какой-нибудь другой язык, например, итальянский. В этом случае вы увидите что-то непонятное, скорее всего вы получите сообщение об ошибке.
Отсюда можно сделать вывод, что вам необходимо следить за ресурсами по умолчанию. Старайтесь проконтролировать, чтобы ваше приложение всегда содержало все необходимые ресурсы по умолчанию, а уже потом можете начинать локализацию приложения. Для этого вам достаточно будет скопировать файл в новый подкаталог и отредактировать его.
На самом деле локализовать можно не только строковые ресурсы. В разных странах принято рисовать какой-нибудь объект в соответствии со своими традициями, например, изображение почтового ящика. В этом случае вы можете создать каталог /res/drawable-de, в котором будут находиться изображения, предназначенные для немцев.
В коде вы обращаетесь к нужным ресурсам следующим образом:
Система сама подставит нужную строку. Явно указать, что хочется использовать ресурс на конкретном языке, у вас не получится.
Спустя продолжительное время один из читателей подсказал, как всё-таки задействовать локальный ресурс. Объяснять код не буду, сами поймёте, когда наберётесь опыта.
Просмотр и создание локализованных строк в режиме дизайна
Чтобы увидеть, как меняется текст в различных локализованных версиях вашего приложения, необязательно запускать приложение в эмуляторе. Можно в студии на панели инструментов щёлкнуть на значке глобуса и выбрать из выпадающего списка нужный вам пункт (он появится после того, как вы создадите необходимые локализованные ресурсы), и все локализованные строчки сразу поменяются на экране активности.
Можно сразу создать локализованный файл через удобный мастер. Там же в меню есть пункт Edit Translations. , который выводит диалоговое окно со списком уже имеющихся строковых ресурсов из вашей программы (раньше). Вам нужно выбрать язык для перевода, а затем заполнить в таблице нужную колонку.
После того, как вы завершите перевод всех ресурсов, нажимаете на кнопку OK и у вас появится готовая папка с новым файлом strings.xml для выбранной локализации.
Сейчас в студии вместо диалогового окна выводится окно редактора, в котором можно редактировать текст.
Непереводимая игра слов с использованием местных идиоматических выражений
Если вы решили использовать локализацию на разных языках, то можете встретиться с одной проблемой. Предположим, вы перевели только несколько строковых ресурсов и в один прекрасный день решили выложить программу в магазин приложений. Android Studio при сборке подписанного приложения может заругаться, что вы перевели не все строки. Есть два способа обхода проблемы. Вы можете использовать атрибут translatable=»false», чтобы указать среде разработке, что данная строка не требует перевода:
В окне редактора это сделать проще через флажки в столбце Untranslatable.
Второй вариант — явно указать, что все строки в файле не нужно переводить с помощью tools:ignore=»MissingTranslation».
Есть ещё один вариант, когда непереводимые строки размещаются не в ресурсе strings.xml, а в другом файле под именем donottranslate.xml.
Когда вы исправите строковые ресурсы, то избавьтесь от ошибок через Project | Clean. и попытайтесь собрать приложение заново.
Поддержка письма справа налево
Арабы и некоторые другие народы используют непривычную для европейцев схему написания текстов справа налево. В Android 4.2 появилась поддержка данного режима. В блоге (англ.) Native RTL support in Android 4.2 рассказано о некоторых вещах по этой теме.
Теперь вы можете писать приложение для израильских военкоматов. Русские призывники в интервью офицерам душевного здоровья часто используют сочетание хатуль мадан (חתול מדען). Теперь вы знаете, как локализовать строки пушкинского стихотворения про кота учёного.
Несколько локалей
В Android 7.0 (API 24) пользователь может установить несколько локалей. В этом случае, если не будут найдены ресурсы для первой локали, то будут искаться ресурсы для второй локали. Таким образом, если француз знает два языка, например, французский и испанский, а в приложение не поддерживает французского, но поддерживает испанский, то пользователь увидит текст на испанском, а не на английском.
Источник
The All-In-One Guide for Changing App Locale Dynamically in Android (Kotlin)
Changing in-App locale is not straight forward in Android as there is no native library support for that. So, here is the one-by-one production level approach you can follow. We will copy the locale change mechanism like WhatsApp.
1. Setup SharedPreferences class
To save the current locale settings, we must need to save them in SharedPrefrenece. So, we will create a Storage class to save and to get the saved locale. As an example for English, we are saving “en” in the storage.
2. Setup Locale support class
We are now at the main stage, implementing the locale changes functionality independent of the system settings. This is a Util class, so we can call the methods without initializing the class.
Note: We are using “sys_def” for defining the option for following system language.
3. Setup Application class
As we wanted to change locale throughout the app we must need to modify the application class. So, we will get the localized string even with the applicationContext.
2. Mention the application class name in AndroidMenifest.xml
We will need to specify the application class name in AndroidMenifest. Just add android:name=”.MyApp” inside the application tag like below:
4. Setup BaseActivity class
We will need a top-level activity class which will handle the locale changes so that we won’t need to write code for every activity we have.
Note: We will need to restart every activity after changing the locale. So, we use recreate method in onResume.
5. Extending BaseActivity in each Activity
Now, we can simply extend the BaseActivity class in every activity to make it work. So, AppCompatActivity() will be replaced with BaseActivity() in all the activity classes like below:
If you have more Activities you should do the same.
6. Adding localized strings.xml files
Now, we will add our localized strings in res/values folder. If we go to app > res > values in the project view, we will see there is a file named strings.xml which should contain all the strings that will be used by our app. This file is the default file. So, if we want to use our localized strings we will need to add new strings.xml file specifying the locale. To do so, we will have to follow the steps: File > New > Android Resouce File.
File Name: strings
Resource type: Values
Directory name: values
Select locale in available qualifiers then press >>. Now you can select language and region. The final screen will be like below. I have chosen my locale Bengali.
Источник
Локализация Android-приложений: о чем умалчивает документация
Локализация Android-приложений — намного более сложная задача, чем должна была бы быть. Описание в документации недостаточное: чтобы разобраться в происходящем «под капотом», нужно искать информацию во внешних источниках (на StackOverflow и в блогах) и тренироваться на базовых приложениях типа «Hello World».
В этой статье я разберу некоторые трудности процесса локализации, с которыми я столкнулся в своих приложениях. Решения, которые я буду приводить, не описаны в документации, поэтому я постараюсь быть максимально точным. (Примечание: термины «локаль» и «язык» в статье используются как синонимы.)
Многобукаф? Нажмите Ctrl-F и введите «вывод №».
Введение
В статье говорится о некоторых трудностях локализации, которые не рассматриваются в официальных ресурсах, — то есть, это не руководство по локализации «для чайников».
Перед чтением полезно будет изучить основы локализации Android-приложений (если вы еще не знакомы с этой темой) — прочтите следующие документы:
Проблема № 1. Приложение отображается не на том языке
Разберемся, что происходит в этом случае «под капотом». Допустим, языковые настройки телефона следующие:
Если перевести этот список в псевдокод, получим:
(Примечание. Язык по умолчанию для приложения определяется самим приложением. В одном случае это может быть польский, в другом — немецкий, и так далее, — это язык, файл которого размещен по пути values/strings.xml . К сожалению, указать системе Android язык по умолчанию для конкретного приложения нельзя — и мы с этой особенностью еще столкнемся позже.)
В основе этого списка лежит вроде бы простая логика. Однако в некоторых случаях приложение использует не тот язык, который должно было бы, и переключается на свою локаль по умолчанию, когда вы этого не ожидаете.
Чтобы увидеть, как это происходит, установите языковые настройки так, как показано на скриншоте выше, а затем создайте в Android Studio новое приложение из шаблона «Empty Activity». Откройте res/values/strings.xml и для строки app_name (название приложения) задайте значение «App In Default Language» («Приложение на языке по умолчанию»).
Запустите приложение и проверьте, чтобы оно работало. Название приложения появится слева вверху экрана.
Теперь добавим еще два файла values.xml :
Приложение можно снова запускать, но перед этим подумайте: какое значение app_name будет отображаться?
Разумно предположить, что это будет название на французском: испанский — предпочитаемый язык пользователя, но для этой локали файла strings.xml нет, поэтому система выберет следующий предпочитаемый язык — то есть, французский, для которого файл strings.xml у нас есть. Верно же?
А теперь запустите приложение:
Какого… Как так? Почему не на французском? У нас проблемы с логикой?
Нет. С нашей логикой всё в порядке. Дело в другом.
При создании проекта в Android Studio с ним идут кое-какие библиотеки по умолчанию. Взгляните на файл app/build.gradle :
В этих библиотеках содержатся файлы ресурсов для многих локалей — в том числе в них могут быть файлы values-es/strings.xml . Поэтому в скомпилированном и упакованном приложении у вас наверняка найдутся файлы strings.xml на испанском.
В итоге Android будет считать, что в приложении есть испанская локаль, и попытается найти app_name на испанском. Но мы эту переменную не определили, поэтому приложение берет ее в strings.xml по умолчанию и, соответственно, отображает строку «App In Default Language».
Такая ситуация называется загрязнением ресурсов: Android наступает на свои же грабли. Подробнее — здесь и здесь.
Чтобы обойти эту проблему, нужно объявить поддерживаемые языки в файле app/build.gradle .
Таким образом мы удаляет все ресурсы, за исключением французской и английской локали: это позволяет не только избежать загрязнения ресурсов, но и снизить размер APK-файла.
Измените файл app/build.gradle так, как показано выше, и перезапустите приложение:
Отлично. А если удалить французский язык из списка поддерживаемых?
Работает как ожидалось… за исключением одного случая.
«Один случай»
Давайте кое-что немного поменяем. Приведем список предпочитаемых языков к такому виду:
Теперь удалим папку resources/values-en из проекта и добавим новый файл values-es/strings.xml :
Итак, теперь у нас есть файл по умолчанию strings.xml (по-прежнему со строкой «App In Default Language»), его французская и испанская версии.
Удалим английский из списка поддерживаемых языков и добавим испанский:
Прежде чем запускать приложение, подумайте: на каком языке оно будет отображаться?
Если следовать той же логике, что и раньше, это должен быть испанский.
А теперь запустите приложение:
Черт побери… опять?! Мы же только что всё исправили! Или нет?
Поэкспериментировав несколько часов с таким поведением, я пришел к следующему заключению: где-то в кодовой базе Android предполагается, что ресурсы по умолчанию — на английском языке.
Это, на мой взгляд, неверно, но что уж поделаешь.
Выше я говорил, что resConfig удаляет ресурсы всех локалей, кроме объявленных… но я соврал: ресурсы по умолчанию resConfig НЕ УДАЛЯЕТ.
Итак, что у нас есть? В настройках пользователя английский указан как предпочитаемый язык. В пакете нашего приложения есть кое-какие строковые файлы по умолчанию (ведь они не были удалены), Android считает, что они на английском, и поэтому решает использовать файлы ресурсов по умолчанию.
Вывод № 1. Обязательно объявляйте языки, поддерживаемые в приложении, — с помощью resConfigs .
Вывод № 2. Если нужно, чтобы приложение поддерживало английский язык, файлы ресурсов по умолчанию должны быть на английском: Android рассчитывает на такое положение дел, поэтому так у вас будет меньше головной боли.
(Если вам английский в приложении не нужен, пропустите второй вывод.)
Проблема № 2. Как узнать текущую локаль приложения?
Казалось бы, найти ответ на такой вопрос должно быть легко, но, к сожалению, это не так: погуглив, вы увидите, что на StackOverflow об этом спрашивали, и не раз.
Причем там есть несколько вводящих в заблуждение ответов, например:
О каждом из этих методов я расскажу подробнее. Но прежде проясним кое-что очевидное, что путают советчики на StackOverflow:
Язык устройства != язык приложения
Первое — это язык, выбранный пользователем в настройках устройства. Второе — это язык, который Android решил использовать для конкретного приложения.
Узнать значение для языка устройства легко:
Итак, с языком устройства мы разобрались — перейдем к языку приложения. К сожалению, официального способа узнать локаль приложения во время выполнения, гарантированно не наткнувшись на ошибку, не существует.
Еще раз: не существует официального способа надежным образом узнать язык приложения во время выполнения.
Почему? Рассмотрим два случая:
Случай 1. Android нашел соответствующий файл «strings.xml» и использует его.
Случай 2. Android не нашел соответствующий файл «strings.xml» и использует файл по умолчанию.
В первом случае следующий код всегда будет возвращать правильное значение:
[[[[ НАЧАЛО БОЛЬШОГО ПРИМЕЧАНИЯ. Ребята на StackOverflow предлагают использовать Locale.getDefault() . Чем это отличается от только что описанного способа?
Я рекомендую почитать документацию по классу Locale. Если вкратце, то Locale.getDefault() используется для целей самой JVM: некоторые операции зависят от локали (например, выбор формата дат), и если не указать для них язык, JVM будет использовать значение, получаемое методом Locale.getDefault() .
Но самое главное отличие в том, что Locale.getDefault() определяется во время запуска приложения, и единственный способ изменить это значение — вызвать Locale.setDefault(новаяЛокаль) самостоятельно. Другими словами, если пользователь изменит настройки языка по умолчанию во время работы приложения, то Locale.getDefault() всё равно будет возвращать значение, определенное во время запуска.
А вот метод getResources().getConfiguration().getLocales().get(0) всегда будет давать актуальное значение (если вы его не кешировали, конечно).
КОНЕЦ БОЛЬШОГО ПРИМЕЧАНИЯ ]]]]
Ладно. Это был первый случай. А что насчет второго?
К сожалению, для случая 2 получить текущую локаль приложения нельзя. Нет официального способа узнать, какой файл strings.xml используется системой Android: локализованный или по умолчанию. Если применить способ для случая 1, мы просто получим локаль устройства.
Еще раз: если у вас случай 2, то метод getResources().getConfiguration().getLocales.get(0) вернет вам локаль устройства, а не приложения.
Однако для решения этой задачи есть обходной путь: нужно добавить в каждый из файлов strings.xml специальную строку (допустим, это будет current_locale ). В испанской версии strings.xml будет current_locale = ‘es’ , в итальянской — current_locale = ‘it’ , в файле по умолчанию — current_locale = ‘en’ (смотрите второй вывод статьи). Теперь достаточно будет в коде приложения вызвать следующий метод: getString(R.strings.current_locale)
Вывод № 3. Получение текущей локали устройства: Resources.getSystem().getConfiguration().getLocales().get(0) . Если уровень API равен 23 или ниже: Resources.getSystem().getConfiguration().locale .
Вывод № 4. Не существует надежного официального способа получить текущую локаль стандартными методами. Но есть обходной путь — см. чуть выше.
Проблема № 3. Как получить список предпочитаемых языков устройства?
В руководствах по Android сказано, что для этого есть новый API — LocaleList (для Android API с уровня 24). Теоретически, при вызове LocaleList.getDefault() вы должны получить список предпочитаемых языков пользователя, заданный в настройках, и он не должен зависеть от приложения — по крайней мере, так говорится в руководствах…
Я поэкспериментировал с LocaleList.getDefault() и могу сказать, что этот метод не всегда возвращает список предпочитаемых языков точно как в настройках.
В каких случаях бывает несоответствие? Проиллюстрирую на примере: предположим, немецкий НЕ ВЫБРАН как предпочитаемый язык и ваше приложение его тоже не поддерживает. Сделаем так:
Каким-то образом в списке, возвращенном методом LocaleList.getDefault() , оказался немецкий… хотя ни телефон, ни приложение его не поддерживают. Смотрим документацию LocaleList.getDefault() :
«Результат обязательно включает в себя локаль по умолчанию, получаемую из Locale.getDefault(), но не обязательно в верхней части списка. Если локаль по умолчанию не вверху списка, это значит, что система установила в качестве ее одну из других предпочитаемых локалей пользователя, заключив, что основной вариант не поддерживается, но вторичный поддерживается.
Внимание: для API >= 24 список LocaleList по умолчанию изменится, если вызвать Locale.setDefault(). В этом методе это учитывается: проверяется вывод Locale.getDefault() и при необходимости пересчитывается список LocaleList по умолчанию.»
Чего-о-о? Я прочел это трижды и всё равно не понял.
Давайте лучше я сам расскажу, как получить список предпочитаемых локалей на устройстве — и это будет последний вывод статьи.
Вывод № 5. Получение списка предпочитаемых локалей устройства (заданных в настройках): Resources.getSystem().getConfiguration().getLocales() . Это применимо только в API уровня 24 и выше: раньше в качестве предпочитаемого пользователь мог выбрать только один язык.
Заключение
В документации (а также в кодовой базе) Android не учитываются многие варианты использования локализации, и это может быть неприятно, поскольку разработчикам приходится учитывать крайние случаи, и делается это не всегда удобным и логичным образом.
Надеюсь, в этой статье мне удалось объяснить, как Android работает с локализацией, и какой API лучше выбрать для конкретного случая.
О переводчике
Перевод статьи выполнен в Alconost.
Alconost занимается локализацией игр, приложений и сайтов на 70 языков. Переводчики-носители языка, лингвистическое тестирование, облачная платформа с API, непрерывная локализация, менеджеры проектов 24/7, любые форматы строковых ресурсов.
Мы также делаем рекламные и обучающие видеоролики — для сайтов, продающие, имиджевые, рекламные, обучающие, тизеры, эксплейнеры, трейлеры для Google Play и App Store.
Источник