18

Ok, I know title sound crazy :)

Here is what I want. My app is localized for device user but information I send back to server need to be all English. My default app locale English.

For example, I have array:

  • Apples
  • Oranges
  • Peaches

I have localized array:

  • Яблоки
  • Апельсины
  • Персики

When russian user sees list and selects couple items - I need to get corresponding english versions.

I guess my answer boils down to how to do getString() and pass locale? Or how do I get Array in specific locale?

katit
  • 17,375
  • 35
  • 128
  • 256

8 Answers8

26

The code below will retrieve localized string for polish language even if the default locale on the device is different:

Configuration conf = getResources().getConfiguration();
conf.locale = new Locale("pl");
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
Resources resources = new Resources(getAssets(), metrics, conf);
/* get localized string */
String str = resources.getString(R.string.hello);

I hope this also apply to other resource types like array, so it should suffice to replace "pl" with "en"...

wjeshak
  • 1,064
  • 9
  • 6
  • I really don't think it's good way to operate locality like that. If I understand correctly I need to make sure switch view back proper language before all other localized content didn't start to go wild.. – katit Jun 30 '11 at 00:11
  • @katit I didn't tested that, but if you will keep calling `getResources()` on your context object instead of using created resources for a given locale, it should always return properly localized resouces with respect to current device locale and you don't have to switch back, I hope I understood correctly your concerns – wjeshak Jun 30 '11 at 08:15
  • The display metrics needed to construct the new `Resources` can also be retrieved by `getResources().getDisplayMetrics()`. No need to involve the window manager. – Ted Hopp Apr 29 '12 at 17:28
  • 10
    also, to avoid modifying your current configuration, go like this: `Configuration conf = new Configuration(getResources().getConfiguration());` – Ivan Bartsov May 15 '12 at 07:26
  • 1
    this will alter your global settings since the new config will be injected in the AssetManager you fetch with getAssets(). You probably want to revert the settings after getting the string (when you do so it's probably easier to just alter the existing Configuration rather than creating a new Resource) – Calin Nov 26 '13 at 15:29
  • Is it not simpler to use: `Resources res = getResources(); new Resources(res.getAssets(), res.getDisplayMetrics(), conf);`? because this does not require access to an activity context. – Mark Sep 06 '14 at 10:16
  • 3
    Please consider starring https://code.google.com/p/android/issues/detail?id=67672 – Mark Sep 06 '14 at 14:14
5

If you use JB 2.2.x or above (basically API >= 17) you can use createConfigurationContext do:

public String translate(Locale locale, int resId) {  
    Configuration config = new Configuration(context.getResources().getConfiguration()); 
    config.setLocale(locale);   
    return context.createConfigurationContext(config).getText(resId);
}
Calin
  • 1,471
  • 1
  • 15
  • 22
3

This one has no side effects: API17 and higher

Configuration config = new Configuration(context.getResources().getConfiguration()); 
config.setLocale(locale);   
return context.createConfigurationContext(config).getResources();
Tunaki
  • 132,869
  • 46
  • 340
  • 423
2

This "force" localization won't work if your devices doesn't have locale you're forcing.

Cannot prove this "just like this", but just now i'm struggling with such issue, where i'm forcing resource to be in locale/language witch isn't installed on device (on android 2.3.3), and still getting strings from values-en (english) resources.

On other devices, with locale you're forcing (but not necessary set as current locale), you'll get correct resources.

Tomo
  • 6,847
  • 1
  • 22
  • 32
1

You have to identify the element by something else, like an id, or even the English Name.

It is not possible to get the original string for a given localized string. One of the reason is that localization of strings is not a transitive function, but there are many other reasons why this is not a good direction.

sorin
  • 161,544
  • 178
  • 535
  • 806
0

I believe, this is the safe way to go (without touching current configuration):

Configuration conf = new Configuration();
conf.setToDefaults();   // That will set conf.locale to null (current locale)
// We don't want current locale, so modify it
conf.locale = new Locale("");   // Or conf.locale = Locale.ROOT for API 9+
                                // or conf.setLocale(Locale.ROOT) for API 14+
// Since we need only strings, we can safely set metrics to null
Resources rsrcDflt = new Resources(getAssets(), null, conf);
String apples = srcDflt.getString(R.string.apples); // Got it at last!
cyanide
  • 3,885
  • 3
  • 25
  • 33
  • 2
    Actually the constructor new Resources(getAssets(), null, conf) overrides the system configuration for your APK. So after creating that object you will always get the default version of string. – ddmytrenko Oct 25 '13 at 13:27
0

I had the same issue with ListPreference that saved "state name" and "body figure" preferences. The ListPreference gets its values and entries from an array saved in the localized "values" folders. The list values were the same (english) but the entries were localized (english and hebrew).

I finally used the following code:

public void OnSharedPreferenceChanged (SharedPreferences sharedPreferences, String key)
{
    SharedPreferences.Editor editor = sharedPreferences.edit();
    Preference pref = settings.findPreference(key);
    pref.setSummary(sharedPreferences.getString(key, ""));

    if (key.equalsIgnoreCase(PREF_STATE) 
        || key.equalsIgnoreCase(PREF_BODY_FIGURE))
    {
        editor.putString(key, ((ListPreference) pref).getValue());
        editor.commit();
    }
}

That way the preference always showed the localized string to the user (as the summary) but saved the English string in the preference memory which was ultimately sent to the server.

Elyakim Levi
  • 360
  • 4
  • 16
0

I combined the two approaches necessary to work on all Android versions. See my answer here.

Johnson_145
  • 1,994
  • 1
  • 17
  • 26