Смена языка приложения в настройках

    В системе Android очень удобная для использования система локализации, достаточно создать папку и в ней файл со строками. Но в приложение сложно встроить все возможные языки, и не плохо бы предоставить пользователю выбор языка, отличного от стандартного.
    Приведу пример такой ситуации:
    В приложении есть 2 языка стандартный английский и русский. Это приложение решил установить украинец, у которого аппарат на украинском языке, но так же он хорошо знает русский, а английский не очень. Но вот Андроид, обнаружив, что в приложении нет украинского языка, запустит приложение со стандартным языком, который в нашей ситуации — английский, а для того, что бы приложение запустить на русском, необходимо менять язык системы, что не очень хорошо.
    Вот для этой и многих подобных ситуаций есть решение, в настройки вывести пункт выбора языка, который включает автоматический выбор языка, английский, русский, etc. (смотря какие требуются).


    Приступим к написанию.
    1. Необходимо создать класс Application и определить его в манифесте в соответственном разделе application в параметре android:name="".
    например:
    <application android:icon="@drawable/icon" android:label="@string/app_name" android:name="MyApplication" android:enabled="true">
    </application>
    

    (хотя у некоторых этот класс уже может быть)
    2. Создать настройку с выбором языка, для этого в файле настроек добавим:
    <ListPreference
       android:key="lang"
       android:title="@string/LangTitle"
       android:summary="@string/LangSummary"
       android:entries="@array/entries_lang"
       android:entryValues="@array/entryvalues_lang"
       android:dialogTitle="@string/LangDialogTitle" />
    


    3. В файл со строками добавим нужные строки:
    <string name="LangTitle">Язык</string>
    <string name="LangDialogTitle">Выберите язык:</string>
    <string name="LangSummary">Язык приложения.\nНеобходимо перезапустить приложение для принятия изменений.</string>
    

    4. А в файл с массивами 2 текстовых массива:
    <string-array name="entries_lang">
      <item>Язык аппарата</item>
      <item>Английский</item>
      <item>Русский</item> 
    </string-array> 
    <string-array name="entryvalues_lang">
      <item>default</item> 
      <item>en</item>
      <item>ru</item> 
    </string-array>
    

    5. В созданном классе в методе onCreate объявим строковую переменную «lang», чтение переменной из настроек, изменение конфигурации приложение, и метод, который вызывается при изменении конфигурации, в котором еще раз её меняем (без повторной смены язык не хотел меняться во всем приложении). В итоге получим следующий класс:
    public class MyApplication extends Application {
    	private SharedPreferences preferences;
    	private Locale locale;
    	private String lang;
    	
    	@Override
    	public void onCreate() {
    		preferences = PreferenceManager.getDefaultSharedPreferences(this);
    		lang = preferences.getString("lang", "default");	
    			if (lang.equals("default")) {lang=getResources().getConfiguration().locale.getCountry();}
    			locale = new Locale(lang);
    			Locale.setDefault(locale);
    			Configuration config = new Configuration();
    			config.locale = locale;
    			getBaseContext().getResources().updateConfiguration(config, null);
    	}
    	
    	@Override
        public void onConfigurationChanged(Configuration newConfig)
        {
            super.onConfigurationChanged(newConfig);
            locale = new Locale(lang);
    		Locale.setDefault(locale);
    		Configuration config = new Configuration();
    		config.locale = locale;
    		getBaseContext().getResources().updateConfiguration(config, null);     
        }	
    }
    

    6. После для того, что бы язык применился, необходимо полностью перезапустить приложение (finish(); тут не поможет, так как перезапускает только активити), для этого использую команду System.exit();
    (В примере сделал пункт перезапуска по будильнику).
    7. Для того, что бы в не возникло проблем в сети советуют в манифесте к каждому активити, в котором используется локализация:
     android:configChanges="locale"
    

    А так же, что бы приложение отображалось правильно определить поддерживаемые размеры экранов:
    <supports-screens android:anyDensity="true" android:smallScreens="true" android:normalScreens="true" android:largeScreens="true" />
    


    Вот таким нехитрым образом можно упростить пользователю жизнь.



    Плюсы этого подхода:
    -Пользователю дается выбор языка.
    Минусы:
    -Необходимость указывать в массивах добавляемые языки.

    Как обычно пример приложения с исходным кодом:
    1. Исходный код примера;
    2. Пример приложения (apk).

    P.S. Каким еще способом можно закрыть приложение полностью (включая Application), кроме System.exit()?
    Share post

    Comments 42

      +2
      > Каким еще способом можно закрыть приложение полностью (включая Application), кроме System.exit()?

      Можно просто завершить все активити и сервисы, но тогда процесс всё равно останется висеть. Когда-то гуглил на эту тему, ничего кроме «в андроиде нельзя закрывать приложения, а если и можно, то не нужно» не нашел.
      Ещё можно попробовать вот так:
      android.os.Process.killProcess(android.os.Process.myPid());

      Сам не пробовал, может работает.
        0
        Ну да, так и советуют делать выход-завершать активити и сервисы, но приложение остается в памяти до тех пор, пока не выгрузит его система, но в данном случае необходим полный перезапуск приложения.
        Данный код вроде тоже работает, какой из них лучше использовать-не знаю…
          +1
          Своего рода перезагрузка приложения:
          Intent i = getBaseContext().getPackageManager().getLaunchIntentForPackage( getBaseContext().getPackageName() );
          i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
          startActivity(i);
            0
            Это перезапуск активити или всего приложения?
            Для данного решения необходима полная перезагрузку с полной выгрузкой из памяти.
              +1
              Всего приложения, недавно была похожая задача, работает.
                0
                Надо попробовать. спасибо.
                  0
                  пожалуйста
          +4
          Жалко, что в самой ОС нельзя для избранных приложений менять язык. Инерфейсы, переведенные на русский с помощью google translate, увы, не редкость.
            0
            Насчет перевода через Google Translate верно, уж лучше использовать на английском языке приложение, чем на таком «русском».
            А насчет выбора в самой ОС — честно ни в одной системе такого функционала не встречал, хотя за то, что бы был такой функционал.
              +1
              Про мобильные не в курсе, а в «большом» линуксе это не проблема:

              $ LANG=«en» ran_bedli_locilaizet_app
                0
                Касательно перевода: большинство разработчиков, я думаю, примут ваши исправления в переводе и всячески будут сотрудничать для создания более качественного продукта.
                  +1
                  Ну если им прислать перевод, то да, хотя я перевел одну игру на Андроид, подобие SimCity, но видать этот проект мертв, что ответов никаких нету на перевод…
                  А так верно, надо помогать переводить. «Кто, если не ты!»
                    0
                    Вслепую переводить — тоже обидно, если нет реакции. Я, например, участвую в переводе Plume с помощью сервиса crowdin.net (выбран разработчиками). Кажется вполне удобным, но минус в том, что не видно, где именно используется переводимая фраза — надо переключать телефон на английский и искать название стринги по оригинальному значению локали.
                    Кто ещё какие сервисы и способы локализации может посоветовать, кроме банального обмена файлами strings.xml?
                      0
                      Ну вообще стандартная система локализации через xml файлы, а как уж их переводить-много способов…
                0
                А нельзя разве сделать приложение которое запускает другое приложение?
                Там, конечно, отдельная виртуалка под каждое приложение, и отдельный линукс процесс…
                Но неужто совсем нельзя сделать такой финт, откуда-нибудь из-под рута?
                  0
                  Даже без рута можно запускать другие приложения через Intent, а так же брать ресурсы из других приложений.
                    0
                    В intent можно явно указать какое именно приолжение запустить?

                    Так ведь можно сделать «универсальный запускатель», который бы, например, менял системную локаль в дефолт, запускал приложение, и потом менял обратно.
                    Или тут есть какие-то тонкости?
                      0
                      Ну да, через имя пакета, например как в примере «com.example.boom.lang». насчет смены системного языка-не знаю, но это не удобно, так как Андроид-многозадачная система, а язык поменяется во всех запущенных приложениях и во всем меню, а не только в данном. Лучше все-таки в отдельно взятом приложении делать выбор языка, хотя может и есть какой хак, который позволит изменить конфигурацию приложения.
                        0
                        Весьма сложно будет поменять язык в самом приложении, если это, например, АндроидМаркет.

                        Закинул вопрос в андро-девелоперскую гугло-группу.
                          0
                          Ну в таких приложениях-да, только полностью сменой локали аппарата.
                0
                Вы описали работу с preferences screen по сути, добавив сохранение/чтение локали из своего объекта Application. Подобные вещи делаются быстро и без сложностей, а тут целая статья на эту тему. Хм.

                Сохраняется настройка в xml, которая живет в папке /data/data/app_name/prefs_name.xml и редактируется по мере необходимости. На отдельную статью не тянет, ИМХО.

                Если бы добавить материал какой-нибудь по теме, то да. Было бы приятно почитать, ибо по стилю написано неплохо, ну а так получилось, что получилось.

                Давайте писать интересные статьи(сам грешен, но исправлюсь)

                p.s. критику нужно воспринимать правильно:)
                  0
                  Действительно получилось, что больше описано создание настроек, чем смысла темы, в следующих статьях исправлюсь.
                  п.с. и не буду писать по ночам..)
                    +1
                    Тут затрагивается работа с локалями и конфигурациями, которая мне показалась интересной, а это в мануалах читать обычно нужды нет, а вот так вот не встретишь в рунете.
                  +2
                  Было бы хорошо, если бы в Андроиде можно было выставлять приоритет языков, по типу ua->ru->en, в соответствии с которым загружались бы локализации.
                    0
                    Мне кажется такое не надо, если приложение направлено на весь мир-никогда не предскажешь на каком языке будет запущено приложение, поэтому система и выбирает стандартный язык, если нет текущего, хотя стандартным в праве сделать любой язык, хотя все-таки лучше Английский.
                    А вот если приложение направлено например на СНГ, тогда бы неплохо выставлять приоритет русскому языку, хотя опять же его можно сделать стандартным.
                      +2
                      Но, с другой стороны, я смогу выставить приоритет для языков, которые я знаю лучше. Например, я свободно владею украинским и русским, не очень — английским. Приложения предпочитаю видеть на украинском, при его отсутствии — на русском, в крайнем случае — на английском. В настройках KDE у меня на десктопе именно такой порядок языков и стоит. Если бы можно было так же сделать в Андроиде, я был бы за. И, думаю. не только я. Т.к. есть люди которые владеют 4-5+ языками.
                        0
                        В маке тоже такая возможность есть, весьма удобно (хотя у меня там всё равно англ+рус, но возможность имеется).
                        0
                        Возможно меня неправильно поняли, я имею ввиду системную настройку, а не настройку в отдельно взятом приложении.
                          0
                          Ну да, подумал про приложение, а системная настройка не помешала бы такая, но к сожалению нету.
                          А вот в приложении выбор языка как раз и нужен для вашего случая, не во многих приложениях есть украинский язык, но есть русский, а по умолчанию выставляется английский.
                        0
                        Тут думаю сделали получше. Есть файл с дефолтовым переводом и есть файл с русскими переводом. Если система на русском берется соответственно файл с русским переводом, иначе дефолтовый. Языков может быть много
                          0
                          Ну так то верно, но в начале поста указал пример, для чего полезна смена, а так же <~VaMpir> доказал на собственном примере, что такой подход нужен.
                      • UFO just landed and posted this here
                          0
                          Не проверял, но кажется, что для данного подхода необходимо переделывать систему локализации и хранения строк, а не использовать стандартную Андроидовскую.
                          0
                          А какие официальные приложения используют самостоятельную смену языка? Если у вас аудитория — страны СНГ, имеет смысл сделать по умолчанию русский, отдельно английский и все остальные.
                            0
                            BP приложений на Андроид вспомню пока только приложения от Go team, например Go SMS, там есть выбор языки и они устанавливаются отдельными пакетами, а так мало приложений используют функцию смены языка, полагаясь на систему.
                              0
                              Пользователи даже некоторых качественных приложений (соответственно, с качественными переводами) хотят иметь возможность настройки языка, как, например, выбор языка в PowerAmp.
                              Но это стоит делать лишь для действительно более-менее серьёзных программ, имеющих сотни строк переводов, иначе настройка лишь будет грузить пользователя своим наличием, который наверняка ничего не выиграет от смены надписей нескольких полей и двух кнопок.
                                0
                                Если так же как и в вышеприведенном приложении — скачивать пакеты с языками, то действительно такой подход полезен для серьезных приложений, ежели небольшое, то от настройки языка, как в примере будет только плюс, даже если одна кнопка и строка, приятнее народном языке пользоваться.
                            +1
                            Честно говоря, не понимаю зачем нужно делать ручной выбор языка и ручной перезапуск. Да, конечно для некоторый приложений это может и выход, но в основной своей части можно все автоматизировать, закрепив за странами, в которых русский язык один из основных, по умолчанию русский. А остальным в свою очередь оставить английский язык. И уже в настройках программы сделать пункт «Язык», причем приложение чтобы само перезапускалось. Мы в своем приложении делали именно так.
                              0
                              В принципе интересный вариант, и даже лучше наверно такой, но в статье рассмотрен простейший пример, да и нагляднее так. А способ с автоматическим выбором языка уже более продвинутый, но все равно тот же метод используется.
                              На счет автоматического перезапуска приложения-не всегда хорошо это, например если сетевое приложение, и, допустим, идет отправка или загрузка каких-либо данных, она прервется.
                              п.с. А каким способом у Вас реализован полный выход из приложения? System.exit()? По идее должен быть более элегантный способ завершить полностью приложение, что бы и onTerminate() в application классе вызывался, чего не происходит при System.exit().
                                0
                                ответил ниже
                              +1
                              С перезапуском — согласен с Вами, все зависит от самого приложения. Мы использовали System.exit() и как-то не задавались этим вопросом.
                                0
                                В принципе можно выполнять автоперезапуск, если ни каких действий не выполняется, только спрашивать пользователя об этом.
                                Значит тоже буду его использовать.

                              Only users with full accounts can post comments. Log in, please.