Програмно змінюйте мову програми в Android


448

Чи можливо змінити мову програми програмно, використовуючи ресурси Android?

Якщо ні, чи можна запитувати ресурс певною мовою?

Я хотів би дозволити користувачеві змінювати мову програми з програми.


4
Ви можете використовувати таку бібліотеку, яка містить список мов, уподобання екрана налаштувань та замінює мову у вашій програмі: github.com/delight-im/Android-Languages
caw

@MarcoW. Чи знаєте ви, чи працює Android-Languages ​​з Android 5.0 Lollipop?
neu242

1
@ neu242 Так, він працює на Android 5.0 без проблем.
каре

1
Ви можете використовувати таку бібліотеку: github.com/zeugma-solutions/locale-helper-android
josue.0

1
@ josue.0 що бібліотека насправді є найчистішим рішенням для цього
amitavk

Відповіді:


376

Це можливо. Ви можете встановити локаль. Однак я б не рекомендував цього. Ми спробували це на ранніх стадіях, це в основному боротьба з системою.

У нас є однакові вимоги щодо зміни мови, але ми вирішили примиритися до того, що інтерфейс повинен бути таким же, як і інтерфейс телефону. Він працював за допомогою локального налаштування, але був занадто глючним. І ви повинні встановити це щоразу, коли ви входите в діяльність (кожну діяльність) з мого досвіду. ось код, якщо він вам все ще потрібен (знову ж, я не рекомендую цього)

Resources res = context.getResources();
// Change locale settings in the app.
DisplayMetrics dm = res.getDisplayMetrics();
android.content.res.Configuration conf = res.getConfiguration();
conf.setLocale(new Locale(language_code.toLowerCase())); // API 17+ only.
// Use conf.locale = new Locale(...) if targeting lower versions
res.updateConfiguration(conf, dm);

Якщо у вас є вміст, специфічний для мови - ви можете змінити цю базу в налаштуваннях.


оновлення 26 березня 2020 року

public static void setLocale(Activitycontext) {
        Locale locale;
        Sessions session = new Sessions(context);
        //Log.e("Lan",session.getLanguage());
            locale = new Locale(langCode);
        Configuration config = new Configuration(context.getResources().getConfiguration());
        Locale.setDefault(locale);
        config.setLocale(locale);

       context.getBaseContext().getResources().updateConfiguration(config,
              context.getBaseContext().getResources().getDisplayMetrics());
    }

329
Не можу повірити, що Android робить це так важко. Я не дуже розумію, чому між локальним телефоном та програмою має існувати СТРИКТНА асоціація. Я завжди маю свій телефон, використовуючи англійську мову, хоча я не є носієм англійської мови. Причина в тому, що перекладені напівтехнічні слова стають занадто дивними моєю мовою, тому англійська мова є набагато легшою. Також мені полегшується дотримуватися порад з Мережі. Але це не означає, що я хочу, щоб КОЖНА програма на своєму телефоні використовувала англійську мову (хоча це абсолютно нормально, що за замовчуванням). Я хочу вміти вибирати !!!
peterh

9
О, схоже, введено API рівня 17 Context.createConfigurationContext(), який можна використовувати для обгортання контексту за замовчуванням з конфігурацією, що залежить від локальності, а потім викликати getResourcesце без необхідності оновлення конфігурації на самих об'єктах ресурсів.
JAB

8
Потрібно поставити це в onCreate () кожної діяльності. Інакше система може перекрити систему - наприклад, коли ви перетворите ваш пристрій на пейзаж, і ваша активність буде відтворена за допомогою нової (наданої системи) конфігурації.
Zsolt Safrany

14
Якщо ви встановите локальний файл RTL типу "ar" і хочете, щоб також працювали ваші папки ресурсів -ldrtl, тоді також зателефонуйте conf.setLayoutDirection (locale);
Zsolt Safrany

3
@ZsoltSafrany - Замість того , щоб додати виклик conf.setLayoutDirection(locale), ви можете замінити conf.locale = new Locale(...))з conf.setLocale(new Locale(...)). Він внутрішньо зателефонує setLayoutDirection.
Тед Хопп

180

Цей код справді працює:

fa = перська, en = англійська

Введіть свій код мови languageToLoadзмінною:

import android.app.Activity;
import android.content.res.Configuration;
import android.os.Bundle;

public class Main extends Activity {
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    String languageToLoad  = "fa"; // your language
    Locale locale = new Locale(languageToLoad); 
    Locale.setDefault(locale);
    Configuration config = new Configuration();
    config.locale = locale;
    getBaseContext().getResources().updateConfiguration(config, 
      getBaseContext().getResources().getDisplayMetrics());
    this.setContentView(R.layout.main);
  }
}

2
Я хочу змінити локаль під час виконання, у своєму коді ви поставите свій код перед методом setContentView (). Тож ваш код не корисний для мене, так як змінити мову під час виконання, у моїй програмі є дві перемикачі для англійської та іншої для арабської,
Dwivedi Ji

2
@Buffalo, це лише другий аргумент Resources.updateConfigurationметоду. Я відрізав код, щоб зробити його більш зрозумілим.
Czechnology

5
Це добре працює для всіх заходів при встановленні в процесі запуску. Але заголовок рядка дій здається невпливним і продовжує відображати мову за замовчуванням. Будь-яка ідея, що я могла пропустити?
AndroidMechanic - Viral Patel

8
Config.locale застаріло
Zoe

2
замість "config.locale = locale;" використовувати "if (Build.VERSION.SDK_INT> = 17) {config.setLocale (locale);} else {config.locale = locale;}
roghayeh hosseini

36

Я шукав спосіб змінити системну мову програмно. Хоча я повністю розумію, що звичайна програма ніколи не повинна цього робити, а натомість:

  • користувач повинен бути вказаний (через наміри) до системних налаштувань, щоб змінити його вручну
  • додаток повинен самостійно обробляти свою локалізацію, як описано у відповіді Алекса

виникла потреба реально змінити мову системи програмно.

Це незадокументований API, і тому його не слід використовувати для додатків для ринку / кінцевих користувачів!

У будь-якому випадку є знайдене нами рішення:

  Locale locale = new Locale(targetLocaleAsString);

  Class amnClass = Class.forName("android.app.ActivityManagerNative");
  Object amn = null;
  Configuration config = null;

  // amn = ActivityManagerNative.getDefault();
  Method methodGetDefault = amnClass.getMethod("getDefault");
  methodGetDefault.setAccessible(true);
  amn = methodGetDefault.invoke(amnClass);

  // config = amn.getConfiguration();
  Method methodGetConfiguration = amnClass.getMethod("getConfiguration");
  methodGetConfiguration.setAccessible(true);
  config = (Configuration) methodGetConfiguration.invoke(amn);

  // config.userSetLocale = true;
  Class configClass = config.getClass();
  Field f = configClass.getField("userSetLocale");
  f.setBoolean(config, true);

  // set the locale to the new value
  config.locale = locale;

  // amn.updateConfiguration(config);
  Method methodUpdateConfiguration = amnClass.getMethod("updateConfiguration", Configuration.class);
  methodUpdateConfiguration.setAccessible(true);
  methodUpdateConfiguration.invoke(amn, config);

2
надати виняток invocationtarget виключення
Раві

1
Добре залежить, куди кинеться invocationTargetException. Тоді ви повинні знати клас, який був змінений.
icyerasor

1
@ Rat-a-tat-a-tat Ratatouille, починаючи з Android 4.2, android.permission.CHANGE_CONFIGURATIONнадається лише програма, підписана ключем виконувати.
Єун

3
Я розміщую свою програму в / system / priv-app, щоб вирішити проблему Android 6.0. Деталі тут .
weiyin

1
@Ravi Мені довелося перенести свій додаток з / system / app в / system / priv-app, щоб він працював
alexislg

31

Якщо ви хочете, щоб мова, змінена у всіх ваших програмах, вам потрібно зробити дві речі.

По-перше, створіть базову діяльність та зробіть усі ваші дії продовженими від цього:

public class BaseActivity extends AppCompatActivity {

    private Locale mCurrentLocale;

    @Override
    protected void onStart() {
        super.onStart();

        mCurrentLocale = getResources().getConfiguration().locale;
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        Locale locale = getLocale(this);

        if (!locale.equals(mCurrentLocale)) {

            mCurrentLocale = locale;
            recreate();
        }
    }

    public static Locale getLocale(Context context){
        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);

        String lang = sharedPreferences.getString("language", "en");
        switch (lang) {
            case "English":
                lang = "en";
                break;
            case "Spanish":
                lang = "es";
                break;
        }
        return new Locale(lang);
    }
}

Зауважте, що я зберігаю нову мову в спільнійПреференції.

По-друге, створіть розширення програми так:

    public class App extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        setLocale();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        setLocale();
    }

    private void setLocale() {

        final Resources resources = getResources();
        final Configuration configuration = resources.getConfiguration();
        final Locale locale = getLocale(this);
        if (!configuration.locale.equals(locale)) {
            configuration.setLocale(locale);
            resources.updateConfiguration(configuration, null);
        }
    }
}

Зауважте, що getLocale () це те саме, що вище.

Це все! Я сподіваюся, що це може комусь допомогти.


Діяльність у додатку - це основна діяльність, як MainActivity? наприклад, я можу вирішити це в setLocale () у своєму методі onCreate ()?
Морозов

Додаток - це розширення програми, це не діяльність. Я не розумію, що вам потрібно, вибачте. Можливо, ви можете спробувати пояснити мені ще раз :)
Даніель С.

1
для тих Android Noobs, як я, завітайте сюди, щоб дізнатися, що Applicationтаке і як ними користуватися. mobomo.com/2011/05/how-to-use-application-object-of-android
Siwei Shen 申思维

2
configuration.locateзастаріло, setLocale вимагає API 17+ та оновленняConfiguration застаріле
Zoe

19

Відповідно до цієї статті . Вам потрібно буде завантажити LocaleHelper.javaпосилання в цій статті.

  1. Створіть MyApplicationклас, який буде розширюватисяApplication
  2. Замініть attachBaseContext()мову, щоб оновити мову.
  3. Зареєструйте цей клас у маніфесті.

    public class MyApplication extends Application {
       @Override
       protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocaleHelper.onAttach(base, "en"));
       }
    }
    
    <application
         android:name="com.package.MyApplication"
         .../>
  4. Створіть BaseActivity та замініть onAttach()для оновлення мови. Потрібно для Android 6+

    public class BaseActivity extends Activity {
      @Override
      protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocaleHelper.onAttach(base));
      }
    }
  5. Зробіть все дії на ваше додаток поширюється від BaseActivity.

    public class LocaleHelper {
    
    private static final String SELECTED_LANGUAGE = "Locale.Helper.Selected.Language";
    
    public static Context onAttach(Context context) {
        String lang = getPersistedData(context, Locale.getDefault().getLanguage());
        return setLocale(context, lang);
    }
    
    public static Context onAttach(Context context, String defaultLanguage) {
        String lang = getPersistedData(context, defaultLanguage);
        return setLocale(context, lang);
    }
    
    public static String getLanguage(Context context) {
        return getPersistedData(context, Locale.getDefault().getLanguage());
    }
    
    public static Context setLocale(Context context, String language) {
        persist(context, language);
    
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return updateResources(context, language);
        }
    
        return updateResourcesLegacy(context, language);
    }
    
    private static String getPersistedData(Context context, String defaultLanguage) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        return preferences.getString(SELECTED_LANGUAGE, defaultLanguage);
    }
    
    private static void persist(Context context, String language) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        SharedPreferences.Editor editor = preferences.edit();
    
        editor.putString(SELECTED_LANGUAGE, language);
        editor.apply();
    }
    
    @TargetApi(Build.VERSION_CODES.N)
    private static Context updateResources(Context context, String language) {
        Locale locale = new Locale(language);
        Locale.setDefault(locale);
    
        Configuration configuration = context.getResources().getConfiguration();
        configuration.setLocale(locale);
        configuration.setLayoutDirection(locale);
    
        return context.createConfigurationContext(configuration);
    }
    
    @SuppressWarnings("deprecation")
    private static Context updateResourcesLegacy(Context context, String language) {
        Locale locale = new Locale(language);
        Locale.setDefault(locale);
    
        Resources resources = context.getResources();
    
        Configuration configuration = resources.getConfiguration();
        configuration.locale = locale;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            configuration.setLayoutDirection(locale);
        }
    
        resources.updateConfiguration(configuration, resources.getDisplayMetrics());
    
        return context;
    }
    }

не може використовувати super.attachBaseContext (LocaleHelper.onAttach (newBase)) , тому що я вже з допомогою super.attachBaseContext (CalligraphyContextWrapper.wrap (newBase))
Rasel

1
можна обмотати одне іншим. super.attachBaseContext (CalligraphyContextWrapper.wrap (LocaleHelper.onAttach (newBase)))
Yeahia2508

15

Просто додаю зайвий шматок, який мене збудив.

У той час як інші відповіді працюють нормально, наприклад, "де"

String lang = "de";
Locale locale = new Locale(lang); 
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config, 
    getBaseContext().getResources().getDisplayMetrics());

Вищенаведене не працює, наприклад, з "fr_BE"locale, тому воно використовує values-fr-rBEпапку чи подібні.

Для роботи потрібна наступна незначна зміна "fr_BE"

String lang = "fr";

//create a string for country
String country = "BE";
//use constructor with country
Locale locale = new Locale(lang, country);

Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config, 
    getBaseContext().getResources().getDisplayMetrics());

1
якщо ви хочете застосувати зміну місцевості до поточного відкритого виклику активностіactivity.recreate()
до

Я знаю, що я спізнююсь на вечірку, але новий Локал (lang, country) був усім, що мені потрібно!
Джейкоб Холлоуей

activity.recreate () як це працює або якщо ми це називаємо, то String lang = "fr"; String country = "BE"; ніколи не
переможе,

Що з використанням android.content.res.Configuration conf = res.getConfiguration();замість створення нового Configurationекземпляра? Чи є якась користь від використання свіжої?
Bianca Daniciuc

14

Я змінений на німецьку мову для самого запуску програми.

Ось мій правильний код. Хто хоче скористатися цим самим для мене .. (Як змінити мову в андроїд програмно)

мій код:

Configuration config ; // variable declaration in globally

// this part is given inside onCreate Method starting and before setContentView()

public void onCreate(Bundle icic) 
{
    super.onCreate(icic);
    config = new Configuration(getResources().getConfiguration());
    config.locale = Locale.GERMAN ;
    getResources().updateConfiguration(config,getResources().getDisplayMetrics());

    setContentView(R.layout.newdesign);
}

1
@harikrishnan Це не працює для мене, і клавіатура не змінюється на вказаній мові .. Як ви оголосили активність у маніфесті?
Авадхані Y

13

Я знаю, що пізно відповісти, але я знайшов цю статтю тут . Це дуже добре пояснює весь процес і надає вам добре структурований код.

Місцевий помічник класу:

import android.annotation.TargetApi;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Build;
import android.preference.PreferenceManager;

import java.util.Locale;

/**
 * This class is used to change your application locale and persist this change for the next time
 * that your app is going to be used.
 * <p/>
 * You can also change the locale of your application on the fly by using the setLocale method.
 * <p/>
 * Created by gunhansancar on 07/10/15.
 */
public class LocaleHelper {

    private static final String SELECTED_LANGUAGE = "Locale.Helper.Selected.Language";

    public static Context onAttach(Context context) {
        String lang = getPersistedData(context, Locale.getDefault().getLanguage());
        return setLocale(context, lang);
    }

    public static Context onAttach(Context context, String defaultLanguage) {
        String lang = getPersistedData(context, defaultLanguage);
        return setLocale(context, lang);
    }

    public static String getLanguage(Context context) {
        return getPersistedData(context, Locale.getDefault().getLanguage());
    }

    public static Context setLocale(Context context, String language) {
        persist(context, language);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return updateResources(context, language);
        }

        return updateResourcesLegacy(context, language);
    }

    private static String getPersistedData(Context context, String defaultLanguage) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        return preferences.getString(SELECTED_LANGUAGE, defaultLanguage);
    }

    private static void persist(Context context, String language) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        SharedPreferences.Editor editor = preferences.edit();

        editor.putString(SELECTED_LANGUAGE, language);
        editor.apply();
    }

    @TargetApi(Build.VERSION_CODES.N)
    private static Context updateResources(Context context, String language) {
        Locale locale = new Locale(language);
        Locale.setDefault(locale);

        Configuration configuration = context.getResources().getConfiguration();
        configuration.setLocale(locale);
        configuration.setLayoutDirection(locale);

        return context.createConfigurationContext(configuration);
    }

    @SuppressWarnings("deprecation")
    private static Context updateResourcesLegacy(Context context, String language) {
        Locale locale = new Locale(language);
        Locale.setDefault(locale);

        Resources resources = context.getResources();

        Configuration configuration = resources.getConfiguration();
        configuration.locale = locale;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            configuration.setLayoutDirection(locale);
        }

        resources.updateConfiguration(configuration, resources.getDisplayMetrics());

        return context;
    }
}

Потрібно переосмислити attachBaseContext і зателефонувати LocaleHelper.onAttach (), щоб ініціалізувати параметри локалі у вашій програмі.

import android.app.Application;
import android.content.Context;

import com.gunhansancar.changelanguageexample.helper.LocaleHelper;

public class MainApplication extends Application {
    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocaleHelper.onAttach(base, "en"));
    }
}

Все, що вам потрібно зробити - це додати

LocaleHelper.onCreate(this, "en");

де ви хочете змінити локаль.


LocaleHelper - клас зі статті. Будь-які посилання мають загрозу зняття. Будь ласка, додайте код у свою відповідь.
Зої

Я не хочу перезавантажувати додаток, оскільки програма виконує якусь задачу, наприклад, екран запису. тож без перезапуску програми є рішення для Android 7.0
PriyankaChauhan

1
@PriyankaChauhan Я вважаю, що стаття охоплює цей випадок: у вас є два варіанти оновлення видимого макета: По-перше , ви можете просто оновлювати текст або будь-які інші ресурси, залежні від мови один за одним.
Максим Тураєв

дякую, що додали нове createConfigurationContext, що було корисно
jacoballenwood

1
onCreate або onAttach для дзвінка?
vanste25

12

Створення класу Extends Applicationта створення статичного методу. Тоді ви можете викликати цей метод у всіх видах діяльності раніше setContentView().

public class MyApp extends Application {

@Override
public void onCreate() {
    super.onCreate();
}

public static void setLocaleFa (Context context){
    Locale locale = new Locale("fa"); 
    Locale.setDefault(locale);
    Configuration config = new Configuration();
    config.locale = locale;
    context.getApplicationContext().getResources().updateConfiguration(config, null);
}

public static void setLocaleEn (Context context){
    Locale locale = new Locale("en_US"); 
    Locale.setDefault(locale);
    Configuration config = new Configuration();
    config.locale = locale;
    context.getApplicationContext().getResources().updateConfiguration(config, null);
}

}

Використання в діяльності:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    MyApp.setLocaleFa(MainActivity.this);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    setContentView(R.layout.activity_main);
}

10

Для Android 7.0 Nougat (і нижче) дотримуйтесь цієї статті:

Змініть мову програматично в Android

Стара відповідь
Сюди входить підтримка RTL / LTR:

public static void changeLocale(Context context, Locale locale) {
    Configuration conf = context.getResources().getConfiguration();
    conf.locale = locale;
    Locale.setDefault(locale);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
       conf.setLayoutDirection(conf.locale);
    }

    context.getResources().updateConfiguration(conf, context.getResources().getDisplayMetrics());
}

1
updateConfiguration застаріло. Посилання корисне, будь ласка, додайте його у свою відповідь. (Відповіді лише на посилання є недобрими, оскільки посилання може бути знято. Якщо це трапиться, ця відповідь марна)
Zoe

8

Єдине рішення, яке повністю працює для мене, - це поєднання коду Алекса Волового з механізмом перезавантаження програми:

void restartApplication() {
    Intent i = new Intent(MainTabActivity.context, MagicAppRestart.class);
    i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    MainTabActivity.context.startActivity(i);
}


/** This activity shows nothing; instead, it restarts the android process */
public class MagicAppRestart extends Activity {
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        finish();
    }

    protected void onResume() {
        super.onResume();
        startActivityForResult(new Intent(this, MainTabActivity.class), 0);         
    }
}

2
після зміни мови ви також можете зателефонуватиactivity.recreate()
До

1
Я не хочу перезавантажувати додаток, оскільки програма виконує якусь задачу, наприклад, екран запису. тож без перезапуску програми є рішення для Android 7.0
PriyankaChauhan

7

Я стикався з тим же питанням. На GitHub я знайшов бібліотеку Android-LocalizationActivity .

Ця бібліотека дозволяє дуже просто змінювати мову вашого додатка під час виконання, як ви бачите в прикладі коду нижче. Зразок проекту, що включає зразок коду нижче та додаткову інформацію, можна знайти на сторінці github.

LocalizationActivity розширює AppCompatActivity, тому ви також можете використовувати його під час використання фрагментів.

public class MainActivity extends LocalizationActivity implements View.OnClickListener {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_simple);

        findViewById(R.id.btn_th).setOnClickListener(this);
        findViewById(R.id.btn_en).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        int id = v.getId();
        if (id == R.id.btn_en) {
            setLanguage("en");
        } else if (id == R.id.btn_th) {
            setLanguage("th");
        }
    }
}

7

Час для належного оновлення.

По-перше, застарілий список з API, в якому він був застарілим:

  • configuration.locale (API 17)
  • updateConfiguration(configuration, displaymetrics) (API 17)

Те, на що нещодавно не отримали жодного питання, - це використання нового методу .

createConfigurationContext - це новий метод updateConfiguration.

Деякі використовували його окремо так:

Configuration overrideConfiguration = ctx.getResources().getConfiguration();
Locale locale = new Locale("en_US");
overrideConfiguration.setLocale(locale);
createConfigurationContext(overrideConfiguration);

... але це не працює. Чому? Метод повертає контекст, який потім використовується для обробки перекладів Strings.xml та інших локалізованих ресурсів (зображень, макетів і т. Д.).

Правильне використання виглядає так:

Configuration overrideConfiguration = ctx.getResources().getConfiguration();
Locale locale = new Locale("en_US");
overrideConfiguration.setLocale(locale);
//the configuration can be used for other stuff as well
Context context  = createConfigurationContext(overrideConfiguration);
Resources resources = context.getResources();

Якщо ви просто скопіювали це в свій IDE, ви побачите попередження, що API вимагає націлювання на API 17 або вище. Це можна вирішити, ввівши його в метод і додавши анотацію@TargetApi(17)

Але чекай. А як щодо старих API?

Потрібно створити інший метод, використовуючи updateConfiguration без анотації TargetApi.

Resources res = YourApplication.getInstance().getResources();
// Change locale settings in the app.
DisplayMetrics dm = res.getDisplayMetrics();
android.content.res.Configuration conf = res.getConfiguration();
conf.locale = new Locale("th");
res.updateConfiguration(conf, dm);

Тут не потрібно повертати контекст.

Тепер, управління ними може бути важким. В API 17+ вам потрібен створений контекст (або ресурси з створеного контексту), щоб отримати відповідні ресурси на основі локалізації. Як ви справляєтеся з цим?

Ну ось так я це роблю:

/**
 * Full locale list: /programming/7973023/what-is-the-list-of-supported-languages-locales-on-android
 * @param lang language code (e.g. en_US)
 * @return the context
 * PLEASE READ: This method can be changed for usage outside an Activity. Simply add a COntext to the arguments
 */
public Context setLanguage(String lang/*, Context c*/){
    Context c = AndroidLauncher.this;//remove if the context argument is passed. This is a utility line, can be removed totally by replacing calls to c with the activity (if argument Context isn't passed)
    int API = Build.VERSION.SDK_INT;
    if(API >= 17){
        return setLanguage17(lang, c);
    }else{
        return setLanguageLegacy(lang, c);
    }
}

/**
 * Set language for API 17
 * @param lang
 * @param c
 * @return
 */
@TargetApi(17)
public Context setLanguage17(String lang, Context c){
    Configuration overrideConfiguration = c.getResources().getConfiguration();
    Locale locale = new Locale(lang);
    Locale.setDefault(locale);
    overrideConfiguration.setLocale(locale);
    //the configuration can be used for other stuff as well
    Context context  = createConfigurationContext(overrideConfiguration);//"local variable is redundant" if the below line is uncommented, it is needed
    //Resources resources = context.getResources();//If you want to pass the resources instead of a Context, uncomment this line and put it somewhere useful
    return context;
}

public Context setLanguageLegacy(String lang, Context c){
    Resources res = c.getResources();
    // Change locale settings in the app.
    DisplayMetrics dm = res.getDisplayMetrics();//Utility line
    android.content.res.Configuration conf = res.getConfiguration();

    conf.locale = new Locale(lang);//setLocale requires API 17+ - just like createConfigurationContext
    Locale.setDefault(conf.locale);
    res.updateConfiguration(conf, dm);

    //Using this method you don't need to modify the Context itself. Setting it at the start of the app is enough. As you
    //target both API's though, you want to return the context as you have no clue what is called. Now you can use the Context
    //supplied for both things
    return c;
}

Цей код працює за допомогою одного методу, який здійснює виклики до відповідного методу на основі API. Це те, що я робив із багатьма застарілими дзвінками (включаючи Html.fromHtml). У вас є один метод, який бере необхідні аргументи, який потім розбиває його на один з двох (або трьох або більше) методів і повертає відповідний результат на основі рівня API. Це гнучко, оскільки вам не доведеться перевіряти кілька разів, метод "введення" робить це за вас. Метод введення тут єsetLanguage

ПРОСЯТЬСЯ ПРОЧИТАЙТЕ ЦЕ, перш ніж використовувати його

Вам потрібно використовувати контекст, який повертається, коли ви отримуєте ресурси. Чому? Тут я бачив інші відповіді, які використовують createConfigurationContext і не використовують контекст, який він повертає. Щоб він працював так, потрібно викликати updateConfiguration. Що застаріло. Використовуйте контекст, повернений методом, щоб отримати ресурси.

Приклад використання :

Конструктор або десь подібне:

ctx = getLanguage(lang);//lang is loaded or generated. How you get the String lang is not something this answer handles (nor will handle in the future)

І тоді, де б ви хотіли отримати ресурси, якими ви користуєтеся:

String fromResources = ctx.getString(R.string.helloworld);

Використання будь-якого іншого контексту це (теоретично) це порушить.

AFAIK, ви все ще повинні використовувати контекст діяльності для показу діалогів або тостів. для цього ви можете використовувати примірник дії (якщо ви знаходитесь поза)


І, нарешті, скористайтеся recreate()діяльністю, щоб оновити вміст. Ярлик не потрібно створювати наміру оновити.


1
Деякі можуть задатися питанням, чи буде коштувати створений контекст вашої пам'яті. Однак згідно з офіційною документацією Android: "Кожен виклик цього методу повертає новий екземпляр об'єкта контексту; об'єкти контексту не поділяються, однак загальний стан (ClassLoader, інші ресурси для тієї ж конфігурації) може бути таким, що сам контекст може бути справедливим легкий ». Тому я думаю, що Android очікує, що ви використовуєте окремий контекстний об’єкт для локальних речей.
Сіра Лам

7

Якщо ти пишеш

android:configChanges="locale"

У кожній діяльності (у файлі маніфесту) тоді не потрібно встановлювати її щоразу, коли ви вводите Activity.


11
Якщо це в маніфесті, то як це може змінити час виконання, яке, як видається, було те, чого хотіла ОП?
користувач316117

1
@ user316117 Він вказує на Android, що програма буде вирішувати всі питання щодо конфігурації локалі внутрішньо, а не те, що мова є статичною. Я не впевнений, чи це не дозволить Android встановити локаль при зміні між видами діяльності, однак, як я бачив, що configChangesвикористовувався лише для злому, щоб зберегти стан активності при обертаннях / тощо.
JAB

як встановити мову лише для англійської мови?
Kaveesh Kanwal

1
... поки Android не вбиває вашу активність, оскільки їй потрібно більше оперативної пам’яті
Louis CAD

@Brijesh Якщо у нас є зміна мови додатка, тоді, якщо у програмі є якийсь варіант пошуку, і якщо ми будемо шукати в цьому випадку, як додаток відображатиме дані, чи слід нам розробити якусь іншу базу даних для кожної мови чи налаштування коду Android, це так що додаток може показувати дані відповідно до пошуку?
Vishwa Pratap

5
Locale locale = new Locale("en");
Locale.setDefault(locale);

Configuration config = context.getResources().getConfiguration();
config.setLocale(locale);
context.createConfigurationContext(config);

Важливе оновлення:

context.getResources().updateConfiguration(config, context.getResources().getDisplayMetrics());

Зауважте, що на SDK> = 21 вам потрібно зателефонувати "Resources.updateConfiguration ()" , інакше ресурси не оновлюються.


updateConfiguration застаріло. AFAIK ви використовуєте createConfigurationContext і застосовуєте до нього контекст ( Context ctx = createConfigurationContext(args);і отримуєте з цього ресурси
Zoe

Я знаю, що це застаріло. Але все одно я не знаю жодного рішення, яке може працювати на android 5 і вище.
Максим Петлюк

Тоді ви явно не перевірили javadoc. Ви викликаєте контекст, створений з createConfigurationContext
Zoe

Гаразд, але все одно ми повинні викликати updateConfiguration (), правда?
Максим Петлюк

1
Не використовуйте застарілий виклик. Означає відсутність оновлення викликуConfiguration
Zoe

4
/*change language at Run-time*/
//use method like that:
//setLocale("en");
 public void setLocale(String lang) { 
  myLocale = new Locale(lang);         
  Resources res = getResources();         
  DisplayMetrics dm = res.getDisplayMetrics();         
  Configuration conf = res.getConfiguration();         
  conf.locale = myLocale;         
  res.updateConfiguration(conf, dm);         
  Intent refresh = new Intent(this, AndroidLocalize.class);         
  startActivity(refresh); 
 }

5
не потрібно починати нову діяльність, просто оновіть фактичнуactivity.recreate()
До

4

Locale configurationactivityперед налаштуванням вмісту слід встановити в кожному -this.setContentView(R.layout.main);


Але що робити, якщо ви хочете перемикати його на льоту, після виклику setContentView ()?
ІгорГанапольський

2
після зміни мови ви також можете зателефонуватиactivity.recreate()
До

4

Спочатку створіть multi string.xml для різних мов; потім використовуйте цей блок коду в onCreate()методі:

super.onCreate(savedInstanceState);
String languageToLoad  = "fr"; // change your language here
Locale locale = new Locale(languageToLoad); 
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config, 
  getBaseContext().getResources().getDisplayMetrics());
this.setContentView(R.layout.main);

Дякую, цей код чудово працює, я протестував на Android 5.x та 6.x без проблем
inovaciones

4

Ось код, який працює для мене:

public class  MainActivity extends AppCompatActivity {
    public static String storeLang;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        SharedPreferences shp = PreferenceManager.getDefaultSharedPreferences(this);
        storeLang = shp.getString(getString(R.string.key_lang), "");

        // Create a new Locale object
        Locale locale = new Locale(storeLang);

        // Create a new configuration object
        Configuration config = new Configuration();
        // Set the locale of the new configuration
        config.locale = locale;
        // Update the configuration of the Accplication context
        getResources().updateConfiguration(
                config,
                getResources().getDisplayMetrics()
        );

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

Джерело: тут


3

Жодне з перерахованих тут рішень мені не допомогло.

Мова не вмикається на android> = 7.0, якщо AppCompatDelegate.setDefaultNightMode (AppCompatDelegate.MODE_NIGHT_YES)

Цей LocaleUtils працює чудово: https://gist.github.com/GigigoGreenLabs/7d555c762ba2d3a810fe

LocaleUtils

public class LocaleUtils {

public static final String LAN_SPANISH      = "es";
public static final String LAN_PORTUGUESE   = "pt";
public static final String LAN_ENGLISH      = "en";

private static Locale sLocale;

public static void setLocale(Locale locale) {
    sLocale = locale;
    if(sLocale != null) {
        Locale.setDefault(sLocale);
    }
}

public static void updateConfig(ContextThemeWrapper wrapper) {
    if(sLocale != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        Configuration configuration = new Configuration();
        configuration.setLocale(sLocale);
        wrapper.applyOverrideConfiguration(configuration);
    }
}

public static void updateConfig(Application app, Configuration configuration) {
    if(sLocale != null && Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
        //Wrapping the configuration to avoid Activity endless loop
        Configuration config = new Configuration(configuration);
        config.locale = sLocale;
        Resources res = app.getBaseContext().getResources();
        res.updateConfiguration(config, res.getDisplayMetrics());
    }
}
}

Додано цей код до програми

public class App extends Application {
public void onCreate(){
    super.onCreate();

    LocaleUtils.setLocale(new Locale("iw"));
    LocaleUtils.updateConfig(this, getBaseContext().getResources().getConfiguration());
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    LocaleUtils.updateConfig(this, newConfig);
}
}

Код у діяльності

public class BaseActivity extends AppCompatActivity {
    public BaseActivity() {
        LocaleUtils.updateConfig(this);
    }
}

2

Відповідь Олексія Волового працює для мене лише в тому випадку, якщо вона використовується в методі onCreate в процесі діяльності.

Відповідь, яка працює у всіх методах, знаходиться в іншій темі

Програмно змінюйте мову в Android

Ось адаптація коду



    Resources standardResources = getBaseContext().getResources();

    AssetManager assets = standardResources.getAssets();

    DisplayMetrics metrics = standardResources.getDisplayMetrics();

    Configuration config = new Configuration(standardResources.getConfiguration());

    config.locale = new Locale(languageToLoad);

    Resources defaultResources = new Resources(assets, metrics, config);

Сподіваюся, що це допомагає.


19
Ви сказали, що "Відповідь, яка працює у всіх методах, є в іншій темі", але ваше посилання вказує на ЦЕ нитку! "
користувач316117

1
застаріле налаштування config.locale
Zoe

2
рекурсивна відповідь, можлива StackOverflow
тамтом

2

Зауважте, що це рішення з використанням updateConfiguration більше не працюватиме з випуском Android M через кілька тижнів. Новий спосіб зробити це зараз за допомогою applyOverrideConfigurationметоду ContextThemeWrapper див. API API

Ви можете знайти моє повне рішення тут, оскільки я зіткнувся з проблемою сам: https://stackoverflow.com/a/31787201/2776572


Я спробую код updateConfiguration на Android 6.0.1, і він працює нормально, не знаю, чи Google це виправив, але я можу це використовувати без проблем
inovaciones

1
Застарілі методи @innovaciones існують деякий час. Врешті-решт її видалять. Це займає багато часу, але найкраще якнайшвидше перейти до нового API, щоб запобігти проблемам вниз
Zoe

1

Є кілька кроків, які слід здійснити

Спочатку потрібно змінити локальну конфігурацію

Resources resources = context.getResources();

Configuration configuration = resources.getConfiguration();
configuration.locale = new Locale(language);

resources.updateConfiguration(configuration, resources.getDisplayMetrics());

По-друге, якщо ви хочете, щоб ваші зміни застосовувалися безпосередньо до видимого макета, ви можете або оновити представлення даних безпосередньо, або ви можете просто зателефонувати за Activity.recreate (), щоб відновити поточну активність.

А також вам доведеться зберегти свої зміни, оскільки після закриття програми користувач втратить мову.

Я пояснив більш детальне рішення у своєму дописі в блозі Програма зміни програмно в Android

В основному, ви просто викликаєте LocaleHelper.onCreate () у вашому класі додатків, і якщо ви хочете змінити локаль на ходу, ви можете зателефонувати LocaleHelper.setLocale ()


@LunarWatcher Так, якщо ви дійсно перевіряєте код на github чи gist, він уже обробляється.
Гунхань

1

Це працює, коли я натискаю кнопку, щоб змінити мову тексту мого TextView. (Strings.xml у папці значень-de)

String languageToLoad = "de"; // your language
Configuration config = getBaseContext().getResources().getConfiguration();
Locale locale = new Locale(languageToLoad);
Locale.setDefault(locale);
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
recreate();

1

Додати клас LocaleHelper

public class LocaleHelper{ 
private static final String SELECTED_LANGUAGE = "Locale.Helper.Selected.Language";
public static Context onAttach(Context context) {
    String lang = getPersistedData(context, Locale.getDefault().getLanguage());
    return setLocale(context, lang);
}

public static Context onAttach(Context context, String defaultLanguage) {
    String lang = getPersistedData(context, defaultLanguage);
    return setLocale(context, lang);
}

public static String getLanguage(Context context) {
    return getPersistedData(context, Locale.getDefault().getLanguage());
}
public static Context setLocale(Context context, String language) {
    persist(context, language);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        return updateResources(context, language);
    }

    return updateResourcesLegacy(context, language);
}

private static String getPersistedData(Context context, String defaultLanguage) {
    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
    return preferences.getString(SELECTED_LANGUAGE, defaultLanguage);
}

private static void persist(Context context, String language) {
    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
    SharedPreferences.Editor editor = preferences.edit();

    editor.putString(SELECTED_LANGUAGE, language);
    editor.apply();
}

@TargetApi(Build.VERSION_CODES.N)
private static Context updateResources(Context context, String language) {
    Locale locale = new Locale(language);
    Locale.setDefault(locale);

    Configuration configuration = context.getResources().getConfiguration();
    configuration.setLocale(locale);
    configuration.setLayoutDirection(locale);

    return context.createConfigurationContext(configuration);
}

@SuppressWarnings("deprecation")
private static Context updateResourcesLegacy(Context context, String language) {
    Locale locale = new Locale(language);
    Locale.setDefault(locale);

    Resources resources = context.getResources();

    Configuration configuration = resources.getConfiguration();
    configuration.locale = locale;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        configuration.setLayoutDirection(locale);
    }

    resources.updateConfiguration(configuration, resources.getDisplayMetrics());

    return context;
}
}

У діяльності або фрагменті

Context context = LocaleHelper.setLocale(this, App.getSharedPre().getLanguage());
Resource resources = context.getResources();

Тепер SetText для кожного тексту

TextView tv = findViewById(R.id.tv);
tv.setText(resources.getString(R.string.tv));

0

подібний до прийнятої відповіді, але версія 2017 та доданий перезапуск (без перезавантаження, іноді наступна активність все ще надає англійську мову):

// Inside some activity...
private void changeDisplayLanguage(String langCode) {
// Step 1. Change the locale in the app's configuration
    Resources res = getResources();
    android.content.res.Configuration conf = res.getConfiguration();
    conf.setLocale(currentLocale);
    createConfigurationContext(conf);
// Step 2. IMPORTANT! you must restart the app to make sure it works 100%
    restart();
}
private void restart() {
    PackageManager packageManager = getPackageManager();
    Intent intent = packageManager.getLaunchIntentForPackage(getPackageName());
    ComponentName componentName = intent.getComponent();
    Intent mainIntent = IntentCompat.makeRestartActivityTask(componentName);
    mainIntent.putExtra("app_restarting", true);
    PrefUtils.putBoolean("app_restarting", true);
    startActivity(mainIntent);
    System.exit(0);
}

1) використовуйте Fin ((замість 2), щоб перезапустити додаток, яким ви можете скористатися. activity.recreate()3) повернутий контекст. Я думаю, що він повинен бути використаний для отримання ресурсів
Zoe

Я не хочу перезавантажувати додаток, оскільки програма виконує якусь задачу, наприклад, екран запису. тож без перезапуску програми є рішення для Android 7.0
PriyankaChauhan

0

Спочатку ви створюєте значення імені каталогів - "ім'я мови", як хінді, ніж пишете "привіт", і копіювати те саме ім'я файлу рядка в цей каталог і змінювати значення не змінювати параметр після встановленого нижче коду у вашій дії, як кнопка тощо ....

Locale myLocale = new Locale("hi");
Resources res = getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
conf.locale = myLocale;
res.updateConfiguration(conf, dm);
Intent refresh = new Intent(Home.this, Home.class);
startActivity(refresh);
finish(); 

1
conf.localeзастаріло
Zoe

0
private void setLanguage(String language) {
    Locale locale = new Locale(language);
    Locale.setDefault(locale);
    Configuration config = new Configuration();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        config.setLocale(locale);
    } else {
        config.locale = locale;
    }
    getResources().updateConfiguration(config,
            getResources().getDisplayMetrics());

}

1
Я не хочу перезавантажувати додаток, оскільки програма виконує якусь задачу, наприклад, екран запису. тож без перезапуску програми є рішення для Android 7.0
PriyankaChauhan

так на 6.0, це працює добре для мене, без перезавантаження програми, мову змінили, але я не тестувався 7.0
Adeeb karim

0

У прикладі ми встановлюємо англійську мову:

 Configuration config = GetBaseContext().getResources().getConfiguration();
 Locale locale = new Locale("en");
 Locale.setDefault(locale);
 config.locale = locale;
 GetBaseContext().getResources().updateConfiguration(config, 
            GetBaseContext().getResources().getDisplayMetrics());

Пам'ятайте, що це працює лише в тому випадку, якщо мова знайдена і в системі пристроїв, а не лише в додатку


0

Для підтримки арабською / RTL

  1. Ви повинні оновити мовні налаштування через - attachBaseContext ()
  2. Для версії N і вище для Android ви повинні використовувати createConfigurationContext () та updateConfiguration () - інакше RTL-макет не працює належним чином

 @Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(updateBaseContextLocale(newBase));
    }

    public Context updateBaseContextLocale(Context context) {
        String language = SharedPreference.getInstance().getValue(context, "lan");//it return "en", "ar" like this
        if (language == null || language.isEmpty()) {
            //when first time enter into app (get the device language and set it
            language = Locale.getDefault().getLanguage();
            if (language.equals("ar")) {
                SharedPreference.getInstance().save(mContext, "lan", "ar");
            }
        }
        Locale locale = new Locale(language);
        Locale.setDefault(locale);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            updateResourcesLocale(context, locale);
            return  updateResourcesLocaleLegacy(context, locale);
        }

        return updateResourcesLocaleLegacy(context, locale);
    }

    @TargetApi(Build.VERSION_CODES.N)
    private Context updateResourcesLocale(Context context, Locale locale) {
        Configuration configuration = context.getResources().getConfiguration();
        configuration.setLocale(locale);
        return context.createConfigurationContext(configuration);
    }

    @SuppressWarnings("deprecation")
    private Context updateResourcesLocaleLegacy(Context context, Locale locale) {
        Resources resources = context.getResources();
        Configuration configuration = resources.getConfiguration();
        configuration.locale = locale;
        resources.updateConfiguration(configuration, resources.getDisplayMetrics());
        return context;
    }

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.