私のアプリは3(まもなく4)言語をサポートします。いくつかのロケールは非常に似ているので、アプリケーションでロケールを変更するオプションをユーザーに提供したいと思います。たとえば、イタリア人は英語よりもスペイン語を好むかもしれません。
ユーザーがアプリケーションで使用できるロケールの中から選択して、使用するロケールを変更する方法はありますか?基本クラスで実行するのは簡単なタスクなので、各アクティビティのロケールを設定することは問題とは見なしません。
私のアプリは3(まもなく4)言語をサポートします。いくつかのロケールは非常に似ているので、アプリケーションでロケールを変更するオプションをユーザーに提供したいと思います。たとえば、イタリア人は英語よりもスペイン語を好むかもしれません。
ユーザーがアプリケーションで使用できるロケールの中から選択して、使用するロケールを変更する方法はありますか?基本クラスで実行するのは簡単なタスクなので、各アクティビティのロケールを設定することは問題とは見なしません。
回答:
configuration.locale
API 24から廃止されたため、この回答をまだ探している人は、次のように使用できます。
configuration.setLocale(locale);
このメソッドのminSkdVersionがAPI 17であることを考慮してください。
完全なサンプルコード:
@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);
}
}
実行中のアクティビティでロケールを変更した場合は、変更を有効にするために再起動する必要があることを忘れないでください。
2018年5月11日の編集
@CookieMonsterの投稿にあるように、APIの上位バージョンでロケールの変更を維持できない場合があります。その場合は、次のコードをベースアクティビティに追加して、アクティビティを作成するたびにコンテキストロケールを更新します。
@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;
}
これを使用する場合は、ロケールを次のように設定するときに、言語をSharedPreferencesに保存することを忘れないでください。 setLocate(locale)
2020年4月7日の編集
Android 6および7で問題が発生している可能性があります。これは、夜間モードの処理中のandroidxライブラリの問題が原因で発生します。このためapplyOverrideConfiguration
、ベースアクティビティをオーバーライドし、新しいロケールが作成された場合に備えて構成のロケールを更新する必要もあります。
サンプルコード:
@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);
}
androidx.appcompat:appcompat:
のバージョンを1.0.2
する1.1.0
アンドロイド7上で動作していないが、アンドロイド9に取り組ん
1.1.0
androidx にとって同じ問題
appcompat:1.1.0
で修正できるappcompat:1.2.0-alpha02
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));
@TargetApi(Build.VERSION_CODES.N) updateResourcesLocale()
このヘルプが(onResumeで)願っています:
Locale locale = new Locale("ru");
Locale.setDefault(locale);
Configuration config = getBaseContext().getResources().getConfiguration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config,
getBaseContext().getResources().getDisplayMetrics());
Android OS N以上のデバイスでプログラムを使用してロケールを設定する際に問題が発生しました。私にとっての解決策は、私のベースアクティビティでこのコードを書くことでした:
(基本アクティビティがない場合は、すべてのアクティビティでこれらの変更を行う必要があります)
@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;
}
ここでは電話するだけでは不十分であることに注意してください
createConfigurationContext(configuration)
このメソッドが返すコンテキストを取得してから、このコンテキストをメソッドに設定する必要もありますattachBaseContext
。
updateBaseContextLocale
メソッドを呼び出しonCreate
ます。
この問題を解決する現在の方法に対する答えは完全ではないので、私は完全なソリューションの指示を与えるようにしています。不足しているものや改善できる点があればコメントしてください。
まず、問題を解決したいライブラリがいくつかありますが、それらはすべて古くなっているように見えるか、いくつかの機能がありません。
さらに、ライブラリを作成することは、この問題を解決するための良い/簡単な方法ではないかもしれないと思います。完全に切り離されたものを使用するのではなく、既存のコードを変更するだけです。そのため、以下の指示を完全なものにまとめました。
私のソリューションは、主にhttps://github.com/gunhansancar/ChangeLanguageExampleに基づいています(すでにlocalhostによってリンクされています)。これは、私が見極めるのに見つけた最高のコードです。いくつかの備考:
updateViews()
各アクティビティのメソッドを使用して、ロケールを変更した後(通常のを使用してgetString(id)
)手動ですべての文字列を更新します。これは、以下に示すアプローチでは必要ありません。私はそれを少し変更して、選択したロケールを永続化する部分を分離しました(以下で提案されているように、個別に実行したい場合があるため)。
ソリューションは、次の2つのステップで構成されています。
gunhansancarのLocaleHelperにLocaleHelper
基づくクラスを使用します。
ListPreference
でa PreferenceFragment
を追加します(後で言語を追加する必要がある場合は維持する必要があります)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;
}
}
SettingsFragment
次のようなを作成します。
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);
}
}
locales.xml
次の方法で、利用可能な翻訳を含むすべてのロケールをリストするリソースを作成します(ロケールコードのリスト)。
<!-- 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>
あなたにはPreferenceScreen
、あなたは、ユーザーが使用可能な言語を選択できるように、次のセクションを使用することができます。
<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>
次の文字列を使用します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>
次に、カスタムロケールセットを使用するように各アクティビティを設定します。これを実現する最も簡単な方法は、次のコード(すべての重要なコードがattachBaseContext(Context base)
と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();
}
}
}
それは何ですか
attachBaseContext(Context base)
以前に永続化されたロケールを使用するためのオーバーライドLocaleHelper
アクティビティを再作成しても、ActionBarのタイトルは更新されません(すでにここで確認されています:https : //github.com/gunhansancar/ChangeLanguageExample/issues/1)。
setTitle(R.string.mytitle)
を含めるだけで実現できますonCreate()
。これにより、ユーザーはシステムのデフォルトロケールとアプリのデフォルトロケール(この場合は「英語」)を選択できます。
fr-rCA
これまでサポートされているのは言語コードのみで、地域(国)とバリアントコード(など)はサポートされていません。完全なロケール仕様をサポートするには、Android-Languagesライブラリのパーサーと同様のパーサーを使用できます(これは、リージョンをサポートしますが、バリアントコードはサポートしません)。
attachBaseContext(Context base)
し、onResume()
別のクラスには)トリックを行うことができます。次に、アクティビティの基本クラスごとに1つのオブジェクトを宣言し、それら2つの呼び出しを委任するだけです。
@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);
}
}
このヘルパーメソッドを使用して、特定のロケールを強制するだけです。
UDPATE 2017年8月22日。このアプローチを使用することをお勧めします。
次のメソッドを使用してヘルパークラスを追加します。
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());
}
}
}
そして、あなたのスタートアップアクティビティでそれを呼び出しますMainActivity.java
:
public void onCreate(Bundle savedInstanceState) {
...
LanguageHelper.setAppLocale("fa", this);
...
}
シンプルで簡単
Locale locale = new Locale("en", "US");
Resources res = getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
conf.locale = locale;
res.updateConfiguration(conf, dm);
「en」は言語コード、「US」は国コードです。
conf.locale=locale;
非推奨ですupdateConfiguration
。
API16からAPI28まで有効このメソッドを次の場所に配置するだけです。
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;
}
次のコードを使用して、すべてのアクティビティにこのコードを挿入します:
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(localeUpdateResources(base, "<-- language code -->"));
}
または、新しいコンテキストが必要なフラグメント、アダプターなどでlocaleUpdateResourcesを呼び出します。
クレジット:Yaroslav Berezanskyi
とても簡単な方法があります。
BaseActivity、Activity、またはFragmentでattachBaseContextをオーバーライドします
override fun attachBaseContext(context: Context) {
super.attachBaseContext(context.changeLocale("tr"))
}
拡張
fun Context.changeLocale(language:String): Context {
val locale = Locale(language)
Locale.setDefault(locale)
val config = this.resources.configuration
config.setLocale(locale)
return createConfigurationContext(config)
}
私が見つかりましたandroidx.appcompat:appcompat:1.1.0
バグは、単に呼び出すことによって固定することが可能getResources()
でapplyOverrideConfiguration()
@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);
}
/**
* 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
}
}
すべてを試しましたが、うまくいかない人のために。で設定darkmode
しAppCompatDelegate.setDefaultNightMode
、システムが暗くConfiguration.setLocale
ない場合は、Andorid 7.0以降では動作しないことを確認してください。
この問題を解決するには、すべてのアクティビティにこのコードを追加します。
override fun applyOverrideConfiguration(overrideConfiguration: Configuration?) {
if (overrideConfiguration != null) {
val uiMode = overrideConfiguration.uiMode
overrideConfiguration.setTo(baseContext.resources.configuration)
overrideConfiguration.uiMode = uiMode
}
super.applyOverrideConfiguration(overrideConfiguration)
}
このコードをあなたの活動に入れてください
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();
}