Нелегкая судьба андроид-программиста заставила меня принять участие в
Контесте андроид-разработчиков, проводимом HTC.
По условиям конкурса приложения должны либо быть на украинском языке, либо поддерживать несколько языков, включая русский и украинский. Поскольку я собирался публиковать приложение на маркете, и предполагал, что пользоваться программой будут не только пользователи из Украины, то вариант только с локализацией на украинский мне не подходил.
До сих пор, я в своих приложениях ограничивался только двумя языками - английским, который устанавливал, как язык по умолчанию, и русским. Андроид до сих пор не поддерживает украинскую локаль, что, безусловно, является полным аллес капутом.
А еще хотелось, чтобы пользователь мог переключать язык из настроек приложения.
Cyanogenmod поддерживает возможность установки украинской локали. Однако, по понятным причинам, не стоит ожидать, что жюри в конкурсе HTC будет использовать устройства с цианогеном.
Я остался перед выбором:
- в качестве языка по умолчанию использовать украинский. После окончания конкурса заменить его на английский, а русский и украинский оставить тем, у кого включена соответствующая локаль.
- забыть про системные средства локализации, сделать свой менеджер локализации.
Надо ли говорить, что второй вариант мне не нравился совсем, особенно учитывая, что андроид позволяет хранить в ресурсах массивы строк, которые очень легко локализуются стандартными средствами, но для реализации их собственноручно, пришлось бы усложнять свой паровоз.
Поэтому я остановился на 1-м варианте. Но не сразу. Я таки сделал маленький mock-менеджер локализации и попробовал как он работает. Получилось отвратительно. Но! Благодаря этому я получил в настройках приложения опцию
Language
, которую мне не хотелось выбрасывать.
И я стал думать дальше. В процессе размышлений я дошел до класса Locale и его метода
setDefault()
. Сам по себе он не помог, поскольку менеджер ресурсов андроида использует локаль из своих настроек. Но и эти настройки можно изменить.
Итак, что я сделал.
В ресурсы я добавил два массива для окна настроек:
<string-array name="languages">
<item>English</item>
<item>Українська</item>
<item>Русский</item>
</string-array>
<string-array name="language_values">
<item>en</item>
<item>uk</item>
<item>ru</item>
</string-array>
GUI для выбора языка я поместил в стандартное
PreferenceActivity
.
Моя
PreferenceActivity
реализует интерфейс
OnSharedPreferenceChangeListener
. В метод
onSharedPreferenceChanged
помещаем следующий код:
String lang = prefs.getString(key, Consts.DEFAULT_LOCALE);
Utils.setLocale(this, lang);
Const.DEFAULT_LOCALE
- это просто строка "en".
И вот в методе
Utils.setLocale()
и происходит волшебство, размером всего в 5 строчек кода.
public static void setLocale(Activity a, String lang) {
Locale locale2 = new Locale(lang);
Locale.setDefault(locale2);
Configuration c = new Configuration(a.getBaseContext().getResources().getConfiguration());
c.locale = locale2;
a.getBaseContext().getResources().updateConfiguration(c, a.getBaseContext().getResources().getDisplayMetrics());
}
locale2
- это наша новая локаль, создаваемая с переданным кодом языка. Код берется из массива
language_values
. Сперва мы устанавливаем ее как локаль по умолчанию для Java, а затем изменяем конфигурацию менеджера ресурсов андроида. Благодаря этому при загрузке ресурсов будут использоваться ресурсы, соответствующие новой локали. Все активити, созданные после этого будут использовать ресурсы в только-что установленной локали. Правда, все активити, которые уже созданы не поменяются.
На данный момент, я просто предлагаю пользователю перезагрузить приложение, если он изменил язык. Если он не желает этого делать, то по мере того, как система будет убивать и создавать активити, они будут переключаться на новый язык.
Ах, да. Самое главное. В основной активити, которая запускается первой (ну и вообще в любой активити, которая может быть запущена интентом) я вызываю следующий метод в
onCreate()
, сразу после
super()
:
Utils.setLocale(this);
. Это перегруженный метод setLocale, который берет текущий язык приложения из
SharePreferences
. Выглядит он так:
public static void setLocale(Activity a) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(a);
setLocale(a, prefs.getString(Consts.PREF_LOCALE, Consts.DEFAULT_LOCALE));
}
Теперь мое приложение поддерживает локализацию на три языка - английский, украинский и русский, использует только стандартные средства системы андроид и позволяет пользователю менять язык приложения на лету через окно настроек. PROFIT!!!