Android: How to get string in specific locale WITHOUT changing the current locale

前端 未结 5 2001

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 t

相关标签:
5条回答
  • 2020-12-05 06:52

    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);
    
    0 讨论(0)
  • 2020-12-05 06:57

    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:

    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.

    0 讨论(0)
  • 2020-12-05 07:04

    You can use this for 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.

    @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

    0 讨论(0)
  • 2020-12-05 07:07

    For api +17 we could use this:

    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);
    }
    
    0 讨论(0)
  • 2020-12-05 07:08

    Thanks to @Khaled Lela answer, I've made a Kotlin extension:

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

    And I'm using directly within an Activity, Fragment or Context related classes, just simply calling:

    getStringByLocale(R.string.my_text, Locale.UK) or with arguments:

    getStringByLocale(R.string.my_other_text, Locale.RU, arg1, arg2, arg3)

    0 讨论(0)
提交回复
热议问题