私は第一言語が英語、第二言語がアラビア語の多言語アプリを持っています。
アプリ内のすべてのActivity
のsetLocale()
でonCreate()
を呼び出しています:
_public static void setLocale(Locale locale){
Locale.setDefault(locale);
Context context = MyApplication.getInstance();
final Resources resources = context.getResources();
final Configuration config = resources.getConfiguration();
config.setLocale(locale);
context.getResources().updateConfiguration(config,
resources.getDisplayMetrics());
}
_
ここで、locale
は次のいずれかです。
上記のメソッドが呼び出される前にbeforesuper.onCreate(savedInstanceState)
が呼び出されます。
documentation で説明されているように、
Android:supportsRtl="true"
_を追加しました。left
およびright
属性を持つすべてのxmlプロパティを、それぞれstart
およびend
に変更しました。res\values-ar\strings
_フォルダーに入れ、ドローアブルリソースを_res\drawable-ar
_フォルダーに入れました(他のリソースも同様です)。上記の設定は正しく動作します。 Locale
を_ar-AE
_に変更すると、アクティビティにアラビア語のテキストとリソースが正しく表示されます。
ただし、すべてのAndroidバージョン8.0を搭載したデバイス)以降では、リソースとレイアウト方向の両方に問題があります。
バージョンが8.0より前のデバイスでは、RTL画面が正しくは次のようになります。
また、8.0以降のすべてのデバイスで、同じ画面が次のように表示されます。
これはwrongです。
方向とリソースの両方が正しく表示されていないことがわかります。
ここには2つの問題があります。
Locale
は、アプリ構成全体で更新されていないようです。方向に関しては、以前気づかなかった setLayoutDirection()
と呼ばれる奇妙なメソッドが存在します。
この問題が何であるか、なぜそれがオレオで発生するのか、そしてその解決策は何ですか?これについて助け/コメントしてください。
[〜#〜]編集[〜#〜]:
API Differencesレポート によると、
updateConfiguration()
メソッドは実際にAndroid 7.1(API level 25) 。
また、これに関連するすべての投稿を見つけました。重要度の高い順に:
2。Android context.getResources.updateConfiguration()deprecated 。
3。変更方法Android O/Oreo/api 26アプリの言語 。
4。ロケールの変更によるAPI 24以降のAndroid RTLの問題
この問題の完全な解決策は、3つのステップで構成されています。
ステップ1:
BaseActivity
(またはすべてのActivity
s)のonCreate()
で、Locale
を次のように設定します。
_@Override
protected void onCreate(Bundle savedInstanceState) {
// set the Locale the very first thing
Utils.setLocale(Utils.getSavedLocale());
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
......
......
}
_
ここで、getSavedLocale()
は、現在のリージョンに対応するLocale
です(これはプロジェクトに固有です...)。
また、メソッドUtils.setLocale(...)
は次のように定義されています。
_public static void setLocale(Locale locale){
Context context = MyApplication.getInstance();
Resources resources = context.getResources();
Configuration configuration = resources.getConfiguration();
Locale.setDefault(locale);
configuration.setLocale(locale);
configuration.setLayoutDirection(locale);
// updateConfiguration(...) is deprecated in N
if (Build.VERSION.SDK_INT >= 25) {
context = context.getApplicationContext().createConfigurationContext(configuration);
context = context.createConfigurationContext(configuration);
}
context.getResources().updateConfiguration(configuration,
resources.getDisplayMetrics());
}
_
これにより、すべてのLocale
に正しいActivity
が設定されます。これは、APIレベル25をサポートするアプリには十分です。APIレベル26以上の場合は、STEP 2とSTEP 3も必要です。
ステップ2:
BaseActivity
で次のメソッドをオーバーライドします。
_@Override
protected void attachBaseContext(Context newBase) {
newBase = Utils.getLanguageAwareContext(newBase);
super.attachBaseContext(newBase);
}
_
ここで、関数getLanguageAwareContext(...)
は次のように定義されています。
_public static Context getLanguageAwareContext(Context context){
Configuration configuration = context.getResources().getConfiguration();
Locale locale = getIntendedLocale();
configuration.setLocale(locale);
configuration.setLayoutDirection(locale);
return context.createConfigurationContext(configuration);
}
_
これは、STEP 1とともに、APIレベル26以上のアプリのすべてのLocale
に正しいActivity
を設定します。
ただし、言語の方向を正しく設定するには、もう1つの手順が必要です...
ステップ:
BaseActivity
のonCreate()
に、次のコードを追加します。
_@Override
protected void onCreate(Bundle savedInstanceState) {
....
....
// yup, it's a legit bug ... :)
if (Build.VERSION.SDK_INT >= 26) {
getWindow().getDecorView().setLayoutDirection(Utils.isRTL()
? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
}
....
....
}
_
ここで、isRTL()
関数は次のように定義されています。
_public static boolean isRTL(){
return TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault()) == View.LAYOUT_DIRECTION_RTL;
}
_
上記の手順は、Androidの現存するすべてのバージョンでのすべての問題(少なくともLocale
とテキストの方向の設定に関して)に対処する必要があります。
updateConfiguration()
メソッドは 非推奨
createConfigurationContext()
を使用する必要があります
私はこのように管理しました
新しいクラスを作成する
ContextWrapper
import Android.content.Context;
import Android.content.res.Configuration;
import Android.content.res.Resources;
import Android.os.Build;
import Android.os.LocaleList;
import Java.util.Locale;
public class ContextWrapper extends Android.content.ContextWrapper {
public ContextWrapper(Context base) {
super(base);
}
public static ContextWrapper wrap(Context context, Locale newLocale) {
Resources res = context.getResources();
Configuration configuration = res.getConfiguration();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
configuration.setLocale(newLocale);
LocaleList localeList = new LocaleList(newLocale);
LocaleList.setDefault(localeList);
configuration.setLocales(localeList);
context = context.createConfigurationContext(configuration);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
configuration.setLocale(newLocale);
context = context.createConfigurationContext(configuration);
} else {
configuration.locale = newLocale;
res.updateConfiguration(configuration, res.getDisplayMetrics());
}
return new ContextWrapper(context);
}}
BaseActivity
の新しいクラスを作成する
import Android.content.Context;
import Android.support.v7.app.AppCompatActivity;
import Java.util.Locale;
/**
* Created by nilesh on 20/3/18.
*/
public class BaseActivity extends AppCompatActivity {
@Override
protected void attachBaseContext(Context newBase) {
Locale newLocale;
String lang = new PrefManager(newBase).getLanguage();
if (lang.equals("zh_CN")) {
newLocale = new Locale("zh");
} else {
newLocale = new Locale(lang);
}
Context context = ContextWrapper.wrap(newBase, newLocale);
super.attachBaseContext(context);
}
}
ロケールを格納する
PrefManager
クラスを作成します
import Android.content.Context;
import Android.content.SharedPreferences;
public class PrefManager {
private SharedPreferences.Editor editor;
private Context mContext;
private SharedPreferences prefs;
private final String LANGUAGE = "language";
private final String PREF = "user_data";
public PrefManager(Context mContext) {
this.mContext = mContext;
}
public String getLanguage() {
this.prefs = this.mContext.getSharedPreferences(PREF, 0);
return this.prefs.getString(LANGUAGE, "en_US");
}
public void setLanguage(String language) {
this.editor = this.mContext.getSharedPreferences(PREF, 0).edit();
this.editor.putString(LANGUAGE, language);
this.editor.apply();
}
}
次に、BaseActivityを次のようなすべてのアクティビティで拡張する必要があります。
public class OrdersActivity extends BaseActivity
Locale
を変更する必要がある場合は、PrefManager
の値を更新して、アクティビティを再開してください
PrefManager prefManager= new PrefManager(this);
prefManager.setLanguage("zh_CN");
// restart your activity
メソッド Resources#updateConfiguration (Configuration config, DisplayMetrics metrics)
はAPIレベル25で廃止されました。
ドキュメントは Context#createConfigurationContext (Configuration overrideConfiguration)
の使用を提案しています
以下に示すように、単純にすべてのアクティビティの共通の親である基本アクティビティを作成できます。
_public class BaseActivity
extends AppCompatActivity {
private static final String LANGUAGE_CODE_ENGLISH = "en";
private static final String LANGUAGE_CODE_ARABIC = "ar";
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(getLanguageAwareContext(newBase));
}
private static Context getLanguageAwareContext(Context context) {
Configuration configuration = context.getResources().getConfiguration();
configuration.setLocale(new Locale(getLanguageCode));
return context.createConfigurationContext(configuration);
}
// Rewrite this method according to your needs
private static String getLanguageCode() {
return LANGUAGE_CODE_ARABIC;
}
}
_
getLanguageCode()
は言語コードを返す必要があります。通常、言語コードまたはそれを表すその他のデータは、設定に保存されます。getActivity()
ではなく、アクティビティからthis
または_ActivityName.this
_を使用し、フラグメントからgetApplicationContext()
を使用します。アプリがバックグラウンドでキャッシュを作成しているため、アプリを完全に閉じました。
以下のコードを使用して、私の場合にどのようにそれを達成したかを確認してください。
Intent mStartActivity = new Intent(ctc, SplashActivity.class);
int mPendingIntentId = 123456;
PendingIntent mPendingIntent = PendingIntent.getActivity(ctc, mPendingIntentId, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager mgr = (AlarmManager)ctc.getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
System.exit(0);
_public void setLocale(final Context ctx, final String lang) {
AppSettings.getInstance(ctx).save(PrefKeys.language, lang);
final Locale loc = new Locale(lang);
Locale.setDefault(loc);
final Configuration cfg = new Configuration();
cfg.locale = loc;
ctx.getResources().updateConfiguration(cfg, null);
}
_
英語に変更:setLocale(getActivity(), "en";
アラビア語に変更:setLocale(getActivity(), "ar");
その後、アプリケーションを再起動して言語変更の効果を得る必要があります。
Resources.updateConfigurationは非推奨です。代わりにこれを使用してください:
fun setLocale(old: Context, locale: Locale): Context {
val oldConfig = old.resources.configuration
oldConfig.setLocale(locale)
return old.createConfigurationContext(oldConfig)
}
override fun attachBaseContext(newBase: Context?) {
super.attachBaseContext(newBase?.let { setLocale(it, Locale("ar")) })
}
Javaで
private Context setLocale(Context old, Locale locale) {
Configuration oldConfig = old.getResources().getConfiguration();
oldConfig.setLocale(locale);
return old.createConfigurationContext(oldConfig);
}
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(setLocale(newBase, new Locale("ar")));
}