Android:如何在特定区域设置中获取字符串而不更改当前区域设置

时间:2023-01-29 09:15:08

Use Case: Logging error messages as displayed to the user.

使用案例:记录显示给用户的错误消息。

However you don't want to have messages in your log that depend on the locale of the user's device. On the other hand you don't want to change the locale of the user's device just for your (technical) logging. Can this be achieved? I found a couple of potential solutions here on *:

但是,您不希望日志中的消息依赖于用户设备的区域设置。另一方面,您不希望仅为您的(技术)日志记录更改用户设备的区域设置。这可以实现吗?我在*上找到了几个可能的解决方案:

However, they all result in changing the locale of my device (until the next configuration change).

但是,它们都会导致更改设备的区域设置(直到下一次配置更改)。

Anyway, my current workaround is like so:

无论如何,我目前的解决方法是这样的:

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;
}

To be honest, I don't like this approach at all. It's not efficient and - thinking about concurrency and all that - it might result in some view in the "wrong" locale.

说实话,我根本不喜欢这种方法。它并不高效 - 考虑并发性和所有这些 - 它可能会导致“错误”区域设置中的某些视图。

So - Any ideas? Maybe this could be achieved using ResourceBundles, just like in standard Java?

所以 - 任何想法?也许这可以使用ResourceBundles实现,就像在标准Java中一样?

4 个解决方案

#1


15  

You can use this for API +17

您可以将此用于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);
}

Update (1) : How to support old versions.

更新(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;
}

Update (2): Check this article

更新(2):检查这篇文章

#2


3  

You can save all the strings of the default locale in a Map inside a global class, like Application that is executed when launching the app:

您可以将默认语言环境的所有字符串保存在全局类中的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);
    }

}

This solution is not optimal, but you won't have concurrency problems.

此解决方案不是最佳解决方案,但您不会遇到并发问题。

#3


0  

For api +17 we could use this:

对于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  

Try this:

  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);

#1


15  

You can use this for API +17

您可以将此用于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);
}

Update (1) : How to support old versions.

更新(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;
}

Update (2): Check this article

更新(2):检查这篇文章

#2


3  

You can save all the strings of the default locale in a Map inside a global class, like Application that is executed when launching the app:

您可以将默认语言环境的所有字符串保存在全局类中的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);
    }

}

This solution is not optimal, but you won't have concurrency problems.

此解决方案不是最佳解决方案,但您不会遇到并发问题。

#3


0  

For api +17 we could use this:

对于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  

Try this:

  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);