Android has built in functionality to switch between resources based on a users device language (http://developer.android.com/training/basics/supporting-devices/languages.html), but is it possible to switch the resources manually?
For example if I have:
yProject/
res/
values/
strings.xml
values-es/
strings.xml
values-fr/
strings.xml
Can I change which string file is used based on the users preference rather than their device language? So someone using a french language device can choose to use the English text if they want?
I know I can do it with string variables in my code rather than using the xml, but I feel the xml would be neater.
Yes you can. This is a copy/paste from a project doing so, based on user preference, to be put in onCreate():
Resources res = getResources();
Configuration conf = res.getConfiguration();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
String def = Locale.getDefault().getDisplayLanguage();
String lang = prefs.getString("LANGUAGE", def);
conf.locale = new Locale(lang);
Log.v("myapp", lang+" = "+conf.locale+" = "+conf.locale.getDisplayName());
res.updateConfiguration(conf, res.getDisplayMetrics());
By setting a user preference named LANGUAGE to the two-letter code of the desired language, and then restarting the Activity, you manually override set the language. By removing the preference you get the system default.
Related
I read this google doc.
It says we must use this format:
<resource type>-b+<language code>[+<country code>]
for example: value-b+es/string.xml
But somewhere it use value-es/string.xml
Is it true?
also how system can understand which language must choose?
for example I call string by this:
String hello = getResources().getString(R.string.hello_world);
Do I have to use a condition? (if yes how?) ...I couldn't undesrtand the doc well.
Yes. Android OS can choose the best language for user from your app by searching res folder.
For example,you can define the Spanish string values in the res/values-es/strings.xml.
So, if user set up their primary language as a Spanish in the phone, Android OS will read strings from your res/values-es/strings.xml folder first instead of res/values/strings.xml.
If some strings missing in the res/values-es/strings.xml then it will be referenced from res/values/strings.xml
Android loads text and media resources from the project’s ‘res’ directory. based on the current device configuration and locale.
For example, if the code loads a string called ‘R.string.title’, Android will choose the correct value for that string at runtime by loading the appropriate strings.xml file from a matching ‘res/values’ directory.
AndroidAppProject/
res/
values/
strings.xml
values-es/
strings.xml
values-fr/
strings.xml
At runtime, the Android system uses the appropriate set of string resources based on the locale currently set for the user's device.
Now u can load specific locale strings from res folder using:
getResources().getString(R.string.hello_world);
For ex:
Configuration conf = getResources().getConfiguration();
conf.locale = new Locale("fr"); //french language locale
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_world);
this will load R.string.hello_world from values-fr/ directory.
See the Doc
In my android application, I've to provide two language versions (GERMAN,ENGLISH) of the application.In the German Version ,Some extra categories(extra screens) are available compared to English Version.What are the best practices,I should follow?
You have to make two folder in the res directory.
values (This is the by default, put English Language here.)
values-in(This is for Indonesia language), similarlyyou can find for other languages too.
In both the folder, you will having one file named strings.xml.
Now put all your strings in this two files, with the same refrence name.
Like below.
in values-in/strings.xml
<string name="date">Tanggal</string>
in values/strings.xml
<string name="date">Date</string>
and use this method in your MainActivity Class.
public void changeLanguage(String lang) {
Locale myLocale;
if (lang.equalsIgnoreCase(""))
return;
myLocale = new Locale(lang);
Locale.setDefault(myLocale);
android.content.res.Configuration config = new android.content.res.Configuration();
config.locale = myLocale;
getBaseContext().getResources().updateConfiguration(config,
getBaseContext().getResources().getDisplayMetrics());
}
You can get the user language using -
Locale.getDefault().getDisplayLanguage();
and then maybe using if else and a boolean data type you may program your system accordingly.
Or you may want the user to select his or her language themselves using RadioButtons.
Use #strings for the Text Content as then you can translate them easily using coding
You need to create string.xml file for both GERMAN,ENGLISH language with same key with different language text.
You will have to create two folder's in your resource directory named as 'values' and 'values-de' for English and German Language respectively. Also, you can design layouts based on device language. for ex. layout folder for English and layout-de folder for the German Language. Same way to set the font sizes of TextViews you can create a file named as dimen.xml in values folder for respective languages.
// I added this code in every activity and it worked and ofcoarse u need to add a translation string first
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_log_in)
changeLang = findViewById(R.id.changeLang)
changeLang.setOnClickListener {
baseContext.setAppLocale("am")
recreate() }
}
private fun Context.setAppLocale(language: String): Context {
val locale = Locale(language)
Locale.setDefault(locale)
val config = resources.configuration
config.setLocale(locale)
config.setLayoutDirection(locale)
return createConfigurationContext(config)
}
I'm looking for a way to "swap" the default language with the secondary language that are already defined by the string.xml files in the main project. This should only affect a specific flavor.
Example situation: An app's flavor is targeted to a different region than all other flavors, where the default language does not make sense for users anymore.
Note: Copy-Pasting the string files from the main project is not a solution.
maybe you can try
public void setLocale(String lang) {
myLocale = new Locale(lang);
Resources res = getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
conf.locale = myLocale;
res.updateConfiguration(conf, dm);
reloadUI(); // you may not need this, in my activity ui must be refreshed immediately so it has a function like this.
}
take from here
The solution I went for, based on MTZ4's solution, was calling this on onCreate() in my application's singleton:
/**
* Sets the locale to {#link Locale#ENGLISH}
* if the device locale is not {#link Locale#GERMAN}.
*/
public void setLocale() {
if(BuildConfig.FLAVOR.equals("flavorWithSwapedLocale")) {
Resources res = getResources();
Configuration conf = res.getConfiguration();
if (!conf.locale.equals(Locale.GERMAN)) {
conf.locale = Locale.ENGLISH;
res.updateConfiguration(conf, res.getDisplayMetrics());
}
}
}
Note that the default language in the main project is German, this swap makes the default flavor language English, unless the device is in German.
With this approach, an app restart might be needed for the changes to show after changing the device's language.
This is how I did it, say you have:
main/
res/
values/
strings.xml
values-es/
strings.xml
where under main/values you have your default language (let's assume English), and under_main/values-es_ the Spanish translation of it. Now you want one of your flavor to default to Spanish instead of English, even when the user select US or UK locales:
main/
res/
values/
strings.xml
values-es/
strings.xml
a_flavor/
res/
values/
strings.xml // <-- this is a symbolic link
so I introduced in the flavor a symbolic link strings.xml to point to the Spanish translation, overwriting the default file under values.
Symlink was created with a command like:
$ cd app/src/a_flavor/res/values
$ ln -s ../../../main/res/values-es/strings.xml strings.xml
Use symlinks to different languages in flavour folders
i am trying to post my question understable.
I have 2 strings.xml one is for english and another is for Indian Local Language, let it be Tamil.
I have kept the meanings of all the attributes of strings.xml(english) in my tamil strings.xml
Initially my application will load english strings.xml (as normal)
I have button somewhere which should be used to change the language (tamil in this case)
Upon clicking that - my whole app should be reading my tamil strings.xml ..
I know below code only works for default LOCALE
Resources res = getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
conf.locale = Locale.GERMANY;
res.updateConfiguration(conf, dm);
Can this be tweaked to read the my customized strings.xml on the fly?
Any ideas are greatly appreciated.
That is not possible. It's only possible to change the language of your phone and than you will change the language for your app.
why don't you make a settings activity and in there you put an option to change the language that will transfer you user to a locale and text in the settings page on phone?
Tell me if you need a code or something like that.
Do you mean you want to change your language on demand from English to Tamil within your app?
I call this method in my activity onCreate:
public void setupLocale(Activity c, String NewLocale) {
Resources res = c.getBaseContext().getResources();
Configuration newConfig = new Configuration(res.getConfiguration());
newConfig.locale = new Locale(NewLocale);
res.updateConfiguration(newConfig, null);
}
Where c is my activity and NewLocale is the locale string I want to use. e.g "fr" for french, "da" for Danish. Don't know what Tamil is but you probably do.
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?
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"...
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);
}
This one has no side effects: API17 and higher
Configuration config = new Configuration(context.getResources().getConfiguration());
config.setLocale(locale);
return context.createConfigurationContext(config).getResources();
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.
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.
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!
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.
I combined the two approaches necessary to work on all Android versions. See my answer here.