我有一个多语言的应用程序,其主要语言为英语,第二语言为阿拉伯语。
我正在应用程序中每个setLocale()
的{{1}}中调用onCreate()
:
Activity
其中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
被调用之前被称为。
如documentation中所述,
super.onCreate(savedInstanceState)
。android:supportsRtl="true"
和left
属性的xml属性分别更改为right
和start
。end
文件夹中,并将可绘制资源放在res\values-ar\strings
文件夹中(其他资源也是如此)。以上设置正常运行。将res\drawable-ar
更改为Locale
后,阿拉伯文字和资源会正确显示在我的活动中。
但是,所有 8.0 及更高版本的Android设备的资源和布局方向都存在问题。
在版本低于8.0的设备上,RTL屏幕 正确 如下所示:
在所有8.0+的设备上,出现的同一个屏幕如下所示:
是 错误 。
事实证明,方向和资源都在增加 显示不正确。
这里有两个问题:
ar-AE
似乎并未在整个应用程序配置中更新。关于方向,存在一种我以前没有注意到的名为setLayoutDirection()
的奇怪方法。
我想知道这个问题是什么,为什么它在奥利奥(Oreo)中发生,并且有什么解决方案。请对此提供帮助/发表评论。
编辑:
根据API Differences report,
updateConfiguration()
该方法确实在Android 7.1(API级别25)中已弃用。
还找到了与此相关的所有帖子。按照重要性顺序:
1。 Android N change language programmatically。
2。 Android context.getResources.updateConfiguration() deprecated。
3。 How to change Android O / Oreo / api 26 app language。
4。 Android RTL issue in API 24 and higher on locale change
5。 Change language programmatically (Android N 7.0 - API 24)。
答案 0 :(得分:4)
不推荐使用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
答案 1 :(得分:1)
在API级别25中不推荐使用方法Resources#updateConfiguration (Configuration config, DisplayMetrics metrics)
。
医生建议使用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(CommonUtils.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()
应该返回语言代码。通常,语言代码或代表它的任何其他数据都存储在首选项中。this
或ActivityName.this
,从片段中使用getActivity()
,而不是getApplicationContext()
。答案 2 :(得分:1)
此问题的完整解决方案包括三个步骤:
步骤1 :
在onCreate()
(或所有BaseActivity
)的Activity
中,如下设置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
。
但是,还需要一步来正确设置语言方向...
第3步:
在您的onCreate()
的{{1}}中,添加以下代码:
BaseActivity
其中@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()
上述步骤应解决所有现有Android版本上的所有问题(至少与设置public static boolean isRTL(){
return TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault()) == View.LAYOUT_DIRECTION_RTL;
}
和文本方向有关)。
答案 3 :(得分: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");
此后,您需要重新启动应用程序以获取语言更改效果。
答案 4 :(得分:0)
不推荐使用Resource.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")));
}
答案 5 :(得分:0)
完全关闭了该应用程序,因为我认为它正在后台缓存。
使用下面的代码来说明我是如何实现的,您也可以尝试一下:
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);