Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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 stackoverflow:

  • how to get string from different locales in Android?
  • Can I access to resources from different locale android?
  • android - Get string from default locale using string in specific locale
  • maybe even android - Changing Locale within the app itself

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?

like image 785
schnatterer Avatar asked Jul 21 '13 10:07

schnatterer


People also ask

How do I localize a string in Android?

Localizing Strings In order to localize the strings used in your application , make a new folder under res with name of values-local where local would be the replaced with the region. Once that folder is made, copy the strings. xmlfrom default folder to the folder you have created. And change its contents.

What is i18n in Android?

Internationalization (i18n) is the engineering effort to make a product — an app in our case — ready for localization, i.e. adaptation to different regions. It includes important simplifications in the source code needed to avoid individual changes when entering foreign markets.

How do I change localization in Android?

You'll find this screen either in the System Settings app: Languages, or System Settings: System: Languages and input. The Language preference screen should contain one entry called “English (Europe)”. Click Add language and add a fallback language.

How can I add locale language in Android?

Go to app > res > values > right-click > New > Value Resource File and name it as strings. Now, we have to choose qualifiers as Locale from the available list and select the language as Hindi from the drop-down list.


2 Answers

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

like image 155
Khaled Lela Avatar answered Sep 22 '22 11:09

Khaled Lela


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.

like image 43
Juan Sánchez Avatar answered Sep 21 '22 11:09

Juan Sánchez