用例:记录显示给用户的错误消息。
但是,您不希望日志中的消息依赖于用户设备的区域设置。 另一方面,您不希望仅为您的(技术)日志记录更改用户设备的区域设置。 这可以实现吗? 我在stackoverflow上找到了几个可能的解决方案:
但是,它们都会导致更改设备的区域设置(直到下一次配置更改)。
无论如何,我目前的解决方法是这样的:
public String getStringInDefaultLocale(int resId) {
Resources currentResources = getResources();
AssetManager assets = currentResources.getAssets();
DisplayMetrics metrics = currentResources.getDisplayMetrics();
Configuration config = new Configuration(
currentResources.getConfiguration());
config.locale = DEFAULT_LOCALE;
/*
* Note: This (temporiarily) changes the devices locale! TODO find a
* better way to get the string in the specific locale
*/
Resources defaultLocaleResources = new Resources(assets, metrics,
config);
String string = defaultLocaleResources.getString(resId);
// Restore device-specific locale
new Resources(assets, metrics, currentResources.getConfiguration());
return string;
}
说实话,我根本不喜欢这种做法。它并不高效 - 考虑并发性和所有这些 - 它可能导致“错误”区域设置中的某些视图。
所以 - 任何想法?也许这可以使用ResourceBundle来实现,就像在标准Java中一样?
答案 0 :(得分:22)
您可以将其用于API +17
@NonNull
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public static String getStringByLocal(Activity context, int id, String locale) {
Configuration configuration = new Configuration(context.getResources().getConfiguration());
configuration.setLocale(new Locale(locale));
return context.createConfigurationContext(configuration).getResources().getString(id);
}
更新(1):如何支持旧版本。
@NonNull
public static String getStringByLocal(Activity context, int resId, String locale) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1)
return getStringByLocalPlus17(context, resId, locale);
else
return getStringByLocalBefore17(context, resId, locale);
}
@NonNull
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private static String getStringByLocalPlus17(Activity context, int resId, String locale) {
Configuration configuration = new Configuration(context.getResources().getConfiguration());
configuration.setLocale(new Locale(locale));
return context.createConfigurationContext(configuration).getResources().getString(resId);
}
private static String getStringByLocalBefore17(Context context,int resId, String language) {
Resources currentResources = context.getResources();
AssetManager assets = currentResources.getAssets();
DisplayMetrics metrics = currentResources.getDisplayMetrics();
Configuration config = new Configuration(currentResources.getConfiguration());
Locale locale = new Locale(language);
Locale.setDefault(locale);
config.locale = locale;
/*
* Note: This (temporarily) changes the devices locale! TODO find a
* better way to get the string in the specific locale
*/
Resources defaultLocaleResources = new Resources(assets, metrics, config);
String string = defaultLocaleResources.getString(resId);
// Restore device-specific locale
new Resources(assets, metrics, currentResources.getConfiguration());
return string;
}
更新(2): Check this article
答案 1 :(得分:3)
您可以将Map
内的默认语言环境的所有字符串保存在全局类中,例如启动应用时执行的Application
:
public class DualLocaleApplication extends Application {
private static Map<Integer, String> defaultLocaleString;
public void onCreate() {
super.onCreate();
Resources currentResources = getResources();
AssetManager assets = currentResources.getAssets();
DisplayMetrics metrics = currentResources.getDisplayMetrics();
Configuration config = new Configuration(
currentResources.getConfiguration());
config.locale = Locale.ENGLISH;
new Resources(assets, metrics, config);
defaultLocaleString = new HashMap<Integer, String>();
Class<?> stringResources = R.string.class;
for (Field field : stringResources.getFields()) {
String packageName = getPackageName();
int resId = getResources().getIdentifier(field.getName(), "string", packageName);
defaultLocaleString.put(resId, getString(resId));
}
// Restore device-specific locale
new Resources(assets, metrics, currentResources.getConfiguration());
}
public static String getStringInDefaultLocale(int resId) {
return defaultLocaleString.get(resId);
}
}
此解决方案不是最佳解决方案,但您不会遇到并发问题。
答案 2 :(得分:1)
感谢@Khaled Lela的回答,我进行了Kotlin扩展:
fun Context.getStringByLocale(@StringRes stringRes: Int, locale: Locale, vararg formatArgs: Any): String {
val configuration = Configuration(resources.configuration)
configuration.setLocale(locale)
return createConfigurationContext(configuration).resources.getString(stringRes, *formatArgs)
}
我直接在Activity
,Fragment
或Context
相关类中使用,只需调用:
getStringByLocale(R.string.my_text, Locale.UK)
或带有参数:
getStringByLocale(R.string.my_other_text, Locale.RU, arg1, arg2, arg3)
答案 3 :(得分:0)
对于api +17,我们可以使用:
public static String getDefaultString(Context context, @StringRes int stringId){
Resources resources = context.getResources();
Configuration configuration = new Configuration(resources.getConfiguration());
Locale defaultLocale = new Locale("en");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
LocaleList localeList = new LocaleList(defaultLocale);
configuration.setLocales(localeList);
return context.createConfigurationContext(configuration).getString(stringId);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){
configuration.setLocale(defaultLocale);
return context.createConfigurationContext(configuration).getString(stringId);
}
return context.getString(stringId);
}
答案 4 :(得分:-2)
试试这个:
Configuration conf = getResources().getConfiguration();
conf.locale = new Locale("ar"); // locale I used here is Arabic
Resources resources = new Resources(getAssets(), getResources().getDisplayMetrics(), conf);
/* get localized string */
String appName = resources.getString(R.string.app_name);