Setel Lokal secara terprogram

139

Aplikasi saya mendukung 3 (segera 4) bahasa. Karena beberapa lokal sangat mirip, saya ingin memberi pengguna opsi untuk mengubah lokal di aplikasi saya, misalnya orang Italia mungkin lebih suka bahasa Spanyol daripada bahasa Inggris.

Apakah ada cara bagi pengguna untuk memilih di antara lokal yang tersedia untuk aplikasi dan kemudian mengubah lokal apa yang digunakan? Saya tidak melihatnya sebagai masalah untuk menetapkan lokal untuk setiap Kegiatan karena itu adalah tugas sederhana untuk dilakukan di kelas dasar.

Roland
sumber
Jika Anda memerlukan cara untuk mengembalikan lokal default nanti atau jika Anda memerlukan preferensi bahasa yang berisi daftar bahasa, dan jika Anda ingin mengubah lokal dengan lebih nyaman, ini mungkin membantu: github.com/delight-im/Android -Languages
gak

Jawaban:

114

Untuk orang yang masih mencari jawaban ini, karena configuration.localesudah tidak digunakan lagi di API 24, Anda sekarang dapat menggunakan:

configuration.setLocale(locale);

Mempertimbangkan bahwa minSkdVersion untuk metode ini adalah API 17.

Kode contoh lengkap:

@SuppressWarnings("deprecation")
private void setLocale(Locale locale){
    SharedPrefUtils.saveLocale(locale); // optional - Helper method to save the selected language to SharedPreferences in case you might need to attach to activity context (you will need to code this)
    Resources resources = getResources();
    Configuration configuration = resources.getConfiguration();
    DisplayMetrics displayMetrics = resources.getDisplayMetrics();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){
        configuration.setLocale(locale);
    } else{
        configuration.locale=locale;
    }
    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N){
        getApplicationContext().createConfigurationContext(configuration);
    } else {
        resources.updateConfiguration(configuration,displayMetrics);
    }
}

Jangan lupa bahwa, jika Anda mengubah lokal dengan Activity yang sedang berjalan, Anda harus memulai kembali agar perubahan tersebut berlaku.

EDIT 11 MEI 2018

Seperti dari pos @ CookieMonster, Anda mungkin memiliki masalah menjaga perubahan lokal di versi API yang lebih tinggi. Jika demikian, tambahkan kode berikut ke Aktivitas Dasar Anda sehingga Anda memperbarui lokal konteks pada setiap pembuatan Aktivitas:

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

private Context updateBaseContextLocale(Context context) {
    String language = SharedPrefUtils.getSavedLanguage(); // Helper method to get saved language from SharedPreferences
    Locale locale = new Locale(language);
    Locale.setDefault(locale);

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

    return updateResourcesLocaleLegacy(context, locale);
}

@TargetApi(Build.VERSION_CODES.N_MR1)
private Context updateResourcesLocale(Context context, Locale locale) {
    Configuration configuration = new 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;
}

Jika Anda menggunakan ini, jangan lupa untuk menyimpan bahasa ke SharedPreferences saat Anda mengatur lokal dengan setLocate(locale)

EDIT 7 APRIL 2020

Anda mungkin mengalami masalah di Android 6 dan 7, dan ini terjadi karena masalah di pustaka androidx saat menangani mode malam. Untuk ini, Anda juga perlu menggantiapplyOverrideConfiguration dalam aktivitas dasar Anda dan memperbarui lokal konfigurasi jika seandainya lokal baru yang baru dibuat.

Kode sampel:

@Override
public void applyOverrideConfiguration(Configuration overrideConfiguration) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1) {
        // update overrideConfiguration with your locale  
        setLocale(overrideConfiguration) // you will need to implement this
    }
    super.applyOverrideConfiguration(overrideConfiguration);
} 
Ricardo
sumber
2
Ini berfungsi untuk kegiatan, tetapi apakah ada cara untuk memperbarui konteks aplikasi?
alekop
2
Setelah mengubah androidx.appcompat:appcompat:versi dari 1.0.2ke 1.1.0tidak bekerja pada android 7, tetapi bekerja pada android 9.
Bek
4
Masalah yang sama bagi saya dan 1.1.0androidx
Alexander Dadukin
2
Masalah yang sama bagi saya. Setelah saya beralih ke androidx.appcompat: appcompat: 1.1.0 'lib
Rahul Jidge
4
Masalah dengan appcompat:1.1.0dapat diperbaiki dengan appcompat:1.2.0-alpha02dan kode Set<Locale> set = new LinkedHashSet<>(); // bring the target locale to the front of the list set.add(locale); LocaleList all = LocaleList.getDefault(); for (int i = 0; i < all.size(); i++) { // append other locales supported by the user set.add(all.get(i)); } Locale[] locales = set.toArray(new Locale[0]); configuration.setLocales(new LocaleList(locales));di dalam@TargetApi(Build.VERSION_CODES.N) updateResourcesLocale()
Vojtech Pohl
178

Semoga bantuan ini (di onResume):

Locale locale = new Locale("ru");
Locale.setDefault(locale);
Configuration config = getBaseContext().getResources().getConfiguration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config,
      getBaseContext().getResources().getDisplayMetrics());
Rubycon
sumber
2
Jadi ini harus ditetapkan untuk setiap kegiatan?
Tobias
6
1. apakah wajib menggunakan getBaseContext () atau lebih baik menggunakan contex aplikasi? 2. kode ini harus dipanggil di setiap kegiatan? Terima kasih.
Paul
10
Saya menempatkan kode ini di onCreate () dari aktivitas peluncur saya (dan tidak di tempat lain) dan sangat terkejut melihat bahwa lokal tersebut berlaku untuk seluruh aplikasi. Ini ada dalam aplikasi yang menargetkan 4.3 dengan minSDK 14 (ICS).
IAmKale
8
Tidak perlu membuat objek Konfigurasi baru. Anda dapat menggunakan konfigurasi saat ini dan memperbaruinya: getResources (). GetConfiguration ()
jmart
1
jangan gunakan Konfigurasi baru () ;, ia mengubah tampilan teks, fontSize
Jemshit Iskenderov
22

Saya punya masalah dengan pengaturan lokal secara pemrograman dengan perangkat yang memiliki Android OS N dan lebih tinggi . Bagi saya solusinya adalah menulis kode ini dalam aktivitas dasar saya:

(jika Anda tidak memiliki aktivitas dasar maka Anda harus membuat perubahan ini di semua aktivitas Anda)

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

private Context updateBaseContextLocale(Context context) {
    String language = SharedPref.getInstance().getSavedLanguage();
    Locale locale = new Locale(language);
    Locale.setDefault(locale);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        return updateResourcesLocale(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;
}

perhatikan bahwa ini tidak cukup untuk menelepon

createConfigurationContext(configuration)

Anda juga perlu mendapatkan konteks bahwa metode ini kembali dan kemudian mengatur konteks ini dalam attachBaseContextmetode ini.

Monster kue
sumber
Ini adalah solusi termudah dan berhasil! Ini harus menjadi jawaban yang diterima.
Prasad Pawar
3
Kode ini sangat berfungsi di Android di atas 7 tetapi dalam versi di bawah N tidak berfungsi. Apakah Anda punya solusi?
Matin Ashtiani
Tidak yakin karena ini bekerja untuk saya. Apakah Anda ingin mengirimi saya implementasi Anda agar saya bisa melihatnya?
CookieMonster
2
Tidak berfungsi dalam versi di bawah Android N karena resources.updateConfiguration harus dipanggil di onCreate () bukannya attachBaseContext ()
Chandler
@ Chandler benar. Untuk Android 6-, tentukan updateBaseContextLocalemetode pada onCreateaktivitas induk / basis Anda.
Azizjon Kholmatov
22

Karena tidak ada jawaban yang lengkap untuk cara saat ini untuk menyelesaikan masalah ini, saya mencoba memberikan instruksi untuk solusi yang lengkap. Berikan komentar jika ada yang hilang atau bisa dilakukan dengan lebih baik.

Informasi Umum

Pertama, ada beberapa perpustakaan yang ingin menyelesaikan masalah tetapi mereka semua tampaknya sudah ketinggalan zaman atau kehilangan beberapa fitur:

Lebih lanjut saya pikir menulis perpustakaan mungkin bukan cara yang baik / mudah untuk memecahkan masalah ini karena tidak banyak yang harus dilakukan, dan apa yang harus dilakukan adalah mengubah kode yang ada daripada menggunakan sesuatu yang sepenuhnya dipisahkan. Karena itu saya menyusun instruksi berikut yang harus lengkap.

Solusi saya terutama didasarkan pada https://github.com/gunhansancar/ChangeLanguageExample (sebagaimana telah ditautkan oleh localhost ). Ini adalah kode terbaik yang saya temukan untuk orientasi. Beberapa komentar:

  • Sebagaimana diperlukan, ia menyediakan implementasi yang berbeda untuk mengubah lokal untuk Android N (dan di atas) dan di bawah
  • Ini menggunakan metode updateViews()di setiap Aktivitas untuk memperbarui semua string secara manual setelah mengubah lokal (menggunakan yang biasagetString(id) ) yang tidak diperlukan dalam pendekatan yang ditunjukkan di bawah ini
  • Ini hanya mendukung bahasa dan tidak menyelesaikan lokal (yang juga mencakup wilayah (negara) dan kode varian)

Saya mengubahnya sedikit, memisahkan bagian yang tetap ada lokal yang dipilih (karena orang mungkin ingin melakukannya secara terpisah, seperti yang disarankan di bawah).

Larutan

Solusinya terdiri dari dua langkah berikut:

  • Ubah secara permanen lokal yang akan digunakan oleh aplikasi
  • Buat aplikasi menggunakan set lokal kustom, tanpa memulai ulang

Langkah 1: Ubah lokal

Gunakan kelas LocaleHelper, berdasarkan LocaleHelper gunhansancar :

  • Tambahkan ListPreferencedalam PreferenceFragmentdengan bahasa yang tersedia (harus dipertahankan ketika bahasa harus ditambahkan kemudian)
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;

import mypackage.SettingsFragment;

/**
 * Manages setting of the app's locale.
 */
public class LocaleHelper {

    public static Context onAttach(Context context) {
        String locale = getPersistedLocale(context);
        return setLocale(context, locale);
    }

    public static String getPersistedLocale(Context context) {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        return preferences.getString(SettingsFragment.KEY_PREF_LANGUAGE, "");
    }

    /**
     * Set the app's locale to the one specified by the given String.
     *
     * @param context
     * @param localeSpec a locale specification as used for Android resources (NOTE: does not
     *                   support country and variant codes so far); the special string "system" sets
     *                   the locale to the locale specified in system settings
     * @return
     */
    public static Context setLocale(Context context, String localeSpec) {
        Locale locale;
        if (localeSpec.equals("system")) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                locale = Resources.getSystem().getConfiguration().getLocales().get(0);
            } else {
                //noinspection deprecation
                locale = Resources.getSystem().getConfiguration().locale;
            }
        } else {
            locale = new Locale(localeSpec);
        }
        Locale.setDefault(locale);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            return updateResources(context, locale);
        } else {
            return updateResourcesLegacy(context, locale);
        }
    }

    @TargetApi(Build.VERSION_CODES.N)
    private static Context updateResources(Context context, Locale locale) {
        Configuration configuration = context.getResources().getConfiguration();
        configuration.setLocale(locale);
        configuration.setLayoutDirection(locale);

        return context.createConfigurationContext(configuration);
    }

    @SuppressWarnings("deprecation")
    private static Context updateResourcesLegacy(Context context, Locale 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;
    }
}

Buat SettingsFragmentseperti berikut:

import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import mypackage.LocaleHelper;
import mypackage.R;

/**
 * Fragment containing the app's main settings.
 */
public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
    public static final String KEY_PREF_LANGUAGE = "pref_key_language";

    public SettingsFragment() {
        // Required empty public constructor
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_settings, container, false);
        return view;
    }

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        switch (key) {
            case KEY_PREF_LANGUAGE:
                LocaleHelper.setLocale(getContext(), PreferenceManager.getDefaultSharedPreferences(getContext()).getString(key, ""));
                getActivity().recreate(); // necessary here because this Activity is currently running and thus a recreate() in onResume() would be too late
                break;
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        // documentation requires that a reference to the listener is kept as long as it may be called, which is the case as it can only be called from this Fragment
        getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
    }

    @Override
    public void onPause() {
        super.onPause();
        getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
    }
}

Buat sumber daya yang locales.xmlmencantumkan semua lokal dengan terjemahan yang tersedia dengan cara berikut ( daftar kode lokal ):

<!-- Lists available locales used for setting the locale manually.
     For now only language codes (locale codes without country and variant) are supported.
     Has to be in sync with "settings_language_values" in strings.xml (the entries must correspond).
  -->
<resources>
    <string name="system_locale" translatable="false">system</string>
    <string name="default_locale" translatable="false"></string>
    <string-array name="locales">
        <item>@string/system_locale</item> <!-- system setting -->
        <item>@string/default_locale</item> <!-- default locale -->
        <item>de</item>
    </string-array>
</resources>

Di Anda, PreferenceScreenAnda dapat menggunakan bagian berikut untuk membiarkan pengguna memilih bahasa yang tersedia:

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <PreferenceCategory
        android:title="@string/preferences_category_general">
        <ListPreference
            android:key="pref_key_language"
            android:title="@string/preferences_language"
            android:dialogTitle="@string/preferences_language"
            android:entries="@array/settings_language_values"
            android:entryValues="@array/locales"
            android:defaultValue="@string/system_locale"
            android:summary="%s">
        </ListPreference>
    </PreferenceCategory>
</PreferenceScreen>

yang menggunakan string berikut dari strings.xml:

<string name="preferences_category_general">General</string>
<string name="preferences_language">Language</string>
<!-- NOTE: Has to correspond to array "locales" in locales.xml (elements in same orderwith) -->
<string-array name="settings_language_values">
    <item>Default (System setting)</item>
    <item>English</item>
    <item>German</item>
</string-array>

Langkah 2: Buat aplikasi menggunakan lokal kustom

Sekarang atur setiap Aktivitas untuk menggunakan set lokal kustom. Cara termudah untuk mencapai ini adalah memiliki kelas dasar yang sama untuk semua kegiatan dengan kode berikut (di mana kode penting berada di attachBaseContext(Context base)dan onResume()):

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;

import mypackage.LocaleHelper;
import mypackage.R;

/**
 * {@link AppCompatActivity} with main menu in the action bar. Automatically recreates
 * the activity when the locale has changed.
 */
public class MenuAppCompatActivity extends AppCompatActivity {
    private String initialLocale;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initialLocale = LocaleHelper.getPersistedLocale(this);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_settings:
                Intent intent = new Intent(this, SettingsActivity.class);
                startActivity(intent);
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(LocaleHelper.onAttach(base));
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (initialLocale != null && !initialLocale.equals(LocaleHelper.getPersistedLocale(this))) {
            recreate();
        }
    }
}

Apa yang dilakukannya adalah

  • Override attachBaseContext(Context base)untuk menggunakan lokal yang sebelumnya bertahanLocaleHelper
  • Mendeteksi perubahan lokal dan menciptakan kembali Aktivitas untuk memperbarui string-nya

Catatan tentang solusi ini

  • Menciptakan sebuah Aktivitas tidak memperbarui judul ActionBar (seperti yang telah diamati di sini: https://github.com/gunhansancar/ChangeLanguageExample/issues/1 ).

    • Hal ini dapat dicapai dengan hanya memiliki setTitle(R.string.mytitle)dalam onCreate()metode masing-masing kegiatan.
  • Ini memungkinkan pengguna memilih lokal default sistem, serta lokal default aplikasi (yang dapat dinamai, dalam hal ini "Bahasa Inggris").

  • Hanya kode bahasa, tidak ada wilayah (negara) dan kode varian (seperti fr-rCA) yang didukung sejauh ini. Untuk mendukung spesifikasi lokal lengkap, parser yang mirip dengan yang ada di pustaka Android-Bahasa dapat digunakan (yang mendukung wilayah tetapi tidak ada kode varian).

    • Jika seseorang menemukan atau telah menulis parser yang bagus, tambahkan komentar sehingga saya dapat memasukkannya dalam solusi.
pengguna905686
sumber
1
Sangat baik tetapi raja mimpi buruk
Odys
1
Sial, aplikasi saya sudah terlalu kompleks, pendekatan ini akan menjadi mimpi buruk untuk dipertahankan di masa depan.
Josh
@Josh Bisakah Anda menjelaskan ini sedikit lebih jauh? Sebenarnya hanya beberapa baris yang harus ditambahkan ke setiap kelas basis aktivitas yang Anda gunakan. Saya melihat bahwa mungkin tidak mungkin menggunakan kelas dasar yang sama untuk semua kegiatan tetapi bahkan proyek yang lebih besar harus dapat bergaul dengan beberapa. Pemrograman berorientasi aspek dapat membantu di sini tetapi komposisi (memindahkan kode dari attachBaseContext(Context base)dan onResume()ke kelas yang terpisah) dapat melakukan trik. Maka yang harus Anda lakukan adalah mendeklarasikan satu objek di setiap kelas dasar aktivitas dan mendelegasikan dua panggilan itu.
user905686
Jika pengguna mengubah lokalnya, bisakah lokal semua halaman aktivitas sebelumnya diubah juga?
Raju yourPepe
Ini adalah jawaban terbaik untuk masalah ini. Terima kasih kawan, itu berhasil
Alok Gupta
16
@SuppressWarnings("deprecation")
public static void forceLocale(Context context, String localeCode) {
    String localeCodeLowerCase = localeCode.toLowerCase();

    Resources resources = context.getApplicationContext().getResources();
    Configuration overrideConfiguration = resources.getConfiguration();
    Locale overrideLocale = new Locale(localeCodeLowerCase);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
        overrideConfiguration.setLocale(overrideLocale);
    } else {
        overrideConfiguration.locale = overrideLocale;
    }

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        context.getApplicationContext().createConfigurationContext(overrideConfiguration);
    } else {
        resources.updateConfiguration(overrideConfiguration, null);
    }
}

Cukup gunakan metode pembantu ini untuk memaksa lokal tertentu.

UDPATE 22 Agustus 2017. Lebih baik gunakan pendekatan ini .

localhost
sumber
4

Tambahkan kelas pembantu dengan metode berikut:

public class LanguageHelper {
    public static final void setAppLocale(String language, Activity activity) {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
            Resources resources = activity.getResources();
            Configuration configuration = resources.getConfiguration();
            configuration.setLocale(new Locale(language));
            activity.getApplicationContext().createConfigurationContext(configuration);
        } else {
            Locale locale = new Locale(language);
            Locale.setDefault(locale);
            Configuration config = activity.getResources().getConfiguration();
            config.locale = locale;
            activity.getResources().updateConfiguration(config,
                    activity.getResources().getDisplayMetrics());
        }

    }
}

Dan menyebutnya dalam aktivitas startup Anda, seperti MainActivity.java:

public void onCreate(Bundle savedInstanceState) {
    ...
    LanguageHelper.setAppLocale("fa", this);
    ...
}
Grafis Hadid
sumber
3

sederhana dan mudah

Locale locale = new Locale("en", "US");
Resources res = getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
conf.locale = locale;
res.updateConfiguration(conf, dm);

di mana "en" adalah kode bahasa dan "AS" adalah kode negara.

Makvin
sumber
Sebagaimana dinyatakan dalam posting saya conf.locale=locale;sudah usang, dan juga updateConfiguration.
Ricardo
sangat sederhana dan tidak terlalu rumit :)
Ramkesh Yadav
2

Berlaku untuk API16 hingga API28 Tempatkan metode ini di mana saja:

    Context newContext = context;

        Locale locale = new Locale(languageCode);
        Locale.setDefault(locale);

        Resources resources = context.getResources();
        Configuration config = new Configuration(resources.getConfiguration());

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {

        config.setLocale(locale);
                newContext = context.createConfigurationContext(config);

        } else {

        config.locale = locale;
                resources.updateConfiguration(config, resources.getDisplayMetrics());
        }

    return newContext;
}

Masukkan kode ini di semua aktivitas Anda menggunakan:

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(localeUpdateResources(base, "<-- language code -->"));
    }

atau panggil localeUpdateResources pada fragmen, adaptor, dll. di mana Anda memerlukan konteks baru.

Penghargaan: Yaroslav Berezanskyi

nnyerges
sumber
2

Ada cara yang super sederhana.

di BaseActivity, Activity, atau Fragment override attachBaseContext

 override fun attachBaseContext(context: Context) {
    super.attachBaseContext(context.changeLocale("tr"))
}

perpanjangan

fun Context.changeLocale(language:String): Context {
    val locale = Locale(language)
    Locale.setDefault(locale)
    val config = this.resources.configuration
    config.setLocale(locale)
    return createConfigurationContext(config)
}
Burak Dizlek
sumber
2

Saya menemukan androidx.appcompat:appcompat:1.1.0bug juga bisa diperbaiki hanya dengan menelepon getResources()diapplyOverrideConfiguration()

@Override public void
applyOverrideConfiguration(Configuration cfgOverride)
{
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP &&
      Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
    // add this to fix androidx.appcompat:appcompat 1.1.0 bug
    // which happens on Android 6.x ~ 7.x
    getResources();
  }

  super.applyOverrideConfiguration(cfgOverride);
}
Sam Lu
sumber
1
 /**
 * Requests the system to update the list of system locales.
 * Note that the system looks halted for a while during the Locale migration,
 * so the caller need to take care of it.
 */
public static void updateLocales(LocaleList locales) {
    try {
        final IActivityManager am = ActivityManager.getService();
        final Configuration config = am.getConfiguration();

        config.setLocales(locales);
        config.userSetLocale = true;

        am.updatePersistentConfiguration(config);
    } catch (RemoteException e) {
        // Intentionally left blank
    }
}
Zbigniew Mazur
sumber
1

Bagi mereka yang mencoba segalanya tetapi tidak berhasil . Harap periksa bahwa jika Anda mengatur darkmodedengan AppCompatDelegate.setDefaultNightModedan sistem tidak gelap, maka Configuration.setLocaletidak akan berfungsi di atas Andorid 7.0 .

Tambahkan kode ini di setiap aktivitas Anda untuk menyelesaikan masalah ini:

override fun applyOverrideConfiguration(overrideConfiguration: Configuration?) {
  if (overrideConfiguration != null) {
    val uiMode = overrideConfiguration.uiMode
    overrideConfiguration.setTo(baseContext.resources.configuration)
    overrideConfiguration.uiMode = uiMode
  }
  super.applyOverrideConfiguration(overrideConfiguration)
}
Yeahia2508
sumber
-1

Masukkan kode ini ke dalam aktivitas Anda

 if (id==R.id.uz)
    {
        LocaleHelper.setLocale(MainActivity.this, mLanguageCode);

        //It is required to recreate the activity to reflect the change in UI.
        recreate();
        return true;
    }
    if (id == R.id.ru) {

        LocaleHelper.setLocale(MainActivity.this, mLanguageCode);

        //It is required to recreate the activity to reflect the change in UI.
        recreate();
    }
Xurshid Raxmatov
sumber