I have a classic multi-language setup in my app with two 'values' folders: values for default danish language and values-se for swedish. My device is set to locale sw-SE, but my app still shows string resources in danish (default).
If I move the danish resources to a folder values-da (for danish) and create an empty folder values, Then I get the error that the resource is not found. I this case if finds nither danish nor swedish strings.
Here is a typical call to a resource:
m_ButtonOk.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
String email = m_EditEmail.getText().toString();
String pass = m_EditPassword.getText().toString();
if (email.equals("") == false && pass.equals("") == false) {
//Save user info to Crashlytics
Crashlytics.setUserEmail(email);
showProgressDialog(getResources().getString(R.string.wait), getResources().getString(R.string.logging_on));
Intent logOnIntent = new Intent(v.getContext(), dk.le34.taskassistant.activity.TaskAssistantService.class);
logOnIntent.addCategory("dk.le34.taskassistant.LOG_ON");
logOnIntent.putExtra("EMAIL", email);
logOnIntent.putExtra("PASSWORD", pass);
logOnIntent.putExtra("REMEMBER", m_CheckBoxRemember.isChecked());
startService(logOnIntent);
} else {
Toast.makeText(v.getContext(), getResources().getString(R.string.user_details), Toast.LENGTH_LONG).show();
}
}
});
My setup is by the book, so why do I get these errors?
The locale for Swedish is "sv_SE". Your Swedish resources need to go into values-sv, not values-se.
"sv" is the language (in this case Swedish)
"SE" is the country (in this case Sweden)
Related
My Android application supports two languages: Arabic and English. Arabic is the default language.
Now, to make Arabic as default language, i am changing my app locale to Arabic in Splash Screen. And i have maintained both English and Arabic string files for the locale change. But, when i click on some other random fragments (eg. Navigation menu item), my app static strings changes back to English locale.
I assume this is because my app default locale might have been changed to English. This issue is generated randomly, no specific scenarios are noted.
Can you suggest any solution?
Edit: I am using Shared preferences to save the language.
First step you wand to save the language in your sqlite (ex: language saved in table settings at sqlite):
mDatabase = new SqliteItemDatabase(getApplicationContext());
final List<Setting> allsettings = mDatabase.listSettings();
String the_lang = "";
if(position == 0)
{
the_lang = "en";
}
else if(position == 1)
{
the_lang = "ar";
}
LocaleHelper.setLocale(LAngSelect.this, the_lang);// =>set language
mDatabase.updateSettings(new Setting(allsettings.get(0).getId(),the_lang));
mDatabase.close();
Second step: to set activity right-to-left you want to add in every activity:
mDatabase = new SqliteItemDatabase(this);
final List<Setting> allsettings = mDatabase.listSettings();
String langs = allsettings.get(0).getLang() ;
if(langs.equals("ar")) {
//HERE CHECK CONDITION FOR YOUR LANGUAGE if it is AR then
//change if it is english then don't
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
getWindow().getDecorView().setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
//Resources res = getResources(); //resource handle
}
}
I have an android method that outputs all the language codes for the speech recognition that are available in the device. The problem is it returns the codes like "en-US", "es-ES", "es-MX"... I would like to know if there is a way to transform these codes into the language's display name (English (USA), Spanish (Spain)...). Thank you for your help.
#Override
public void onReceive(Context context, Intent intent)
{
Bundle results = getResultExtras(true);
if (results.containsKey(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE))
{
languagePreference =
results.getString(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE);
}
if (results.containsKey(RecognizerIntent.EXTRA_SUPPORTED_LANGUAGES))
{
supportedLanguages =
results.getStringArrayList(
RecognizerIntent.EXTRA_SUPPORTED_LANGUAGES);
}
for(int i=0;i<supportedLanguages.size();i++){
System.out.println("The language supported is: "+supportedLanguages.get(i));
}
}
Yes you can use Locale.forLanguageTag:
Locale locale = Locale.forLanguageTag("en-US");
System.out.println(locale.getDisplayName());
// "English (United States)"
Build a dictionary from a data source of ISO Language codes:
https://www.andiamo.co.uk/resources/iso-language-codes
I need to check my fragment when I change the app language.
Here is my Android Espresso test:
#Test
public void changeLanguages() {
Resources resources = context.getResources();
String[] appLanguages = resources.getStringArray(R.array.app_lang_codes);
for (int index = 0; index < appLanguages.length; index++) {
String currentLang = appLanguages[index];
Locale currentLocale = new Locale(currentLang);
if (currentLocale.equals(AppLanguageService.getLocaleRO(context))) {
// click Romanian
onView(withId(R.id.containerLanguageRO)).perform(click());
onView(withId(R.id.textViewSelectLanguage)).check(matches(withText("Selecți limba")));
} else if (currentLocale.equals(AppLanguageService.getLocaleEN(context))) {
// click English
onView(withId(R.id.containerLanguageEN)).perform(click());
onView(withId(R.id.textViewSelectLanguage)).check(matches(withText("Select language")));
}
}
}
Ant it's working fine. OK!
But as you can see I need to hard code the string for a specific language for the test.
"Selecți limba" and "Select language". And I think it's not good.
Is it possible to not use hard code strings to check that text is shown in a specific language?
You can use
mActivityRule.getActivity()
to get the activity you are testing. With this you could fetch a string from your resources like this:
mActivityRule.getActivity().getResources().getString(R.string.your_string)
You could rewrite your check like this:
onView(withId(R.id.textViewSelectLanguage)).check(matches(withText(mActivityRule.getActivity().getResources().getString(R.string.your_string))));
where your_string is the name of your string resource in your strings.xml files.
The Serbian language has Latin and Cyrillic alphabets. In Android's Date and Time Picker widgets, the displayed alphabet for Serbian locales seems to be Cyrillic, as seen here.
I wanted to change the locale so that the android widgets are using the Latin Serbian alphabet.
The current language/country code (yielding Cyrillic) are sr and RS respectively. Therefore, my setLocale function is called as
setLocale("sr", "RS");
This is the part im not sure about - according to localeplanet.com, the local code for latin serbian is sr_Latn_RS. However, I tried both
setLocale("sr_Latn", "RS");
//and
setLocale("sr_Latn_RS", "RS");
neither of which work (no change occurs, default to english). According to the Android documentation, it looks like setLocale expects two letter codes.
The language codes are two-letter lowercase ISO language codes (such
as "en") as defined by ISO 639-1. The country codes are two-letter
uppercase ISO country codes (such as "US") as defined by ISO 3166-1.
The variant codes are unspecified.
So how do I specify a Latin serbian locale code? Or does it not exist?
The previous answer works well if you only support Lollipop or above. However, if you're coding in Serbian a lot of your user base probably won't have it. Here's a solution that works for old and new versions.
private static Locale serbianLatinLocale(){
Locale locale = null;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
for (Locale checkLocale : Locale.getAvailableLocales()) {
if (checkLocale.getISO3Language().equals("srp") && checkLocale.getCountry().equals("LATN") && checkLocale.getVariant().equals("")) {
locale = checkLocale;
}
}
} else {
locale = new Locale.Builder().setLanguage("sr").setRegion("RS").setScript("Latn").build();
}
return locale;
}
For getting latin locale I first used code below.
new Locale.Builder().setLanguage("sr").setRegion("RS").setScript("Latn").build();
But this solution didn't work on my Android 5.1.1 device (it was still in cyrillic). So I removed setting of region like this:
new Locale.Builder().setLanguage("sr").setScript("Latn").build();
And you have to put your string for serbian resources in b+sr+Latn folder.
Please search for your query before posting a question. It may be answered in some other related form.
Locale newLocale = new Locale("sr","RS");
Configuration config = new Configuration();
config.setLocale(newLocale);
// using this to reference my Activity
this.getBaseContext().getResources().updateConfiguration(config, this.getBaseContext().getResources().getDisplayMetrics());
i found these two answers suitable to your query
android custom date-picker SO and locale from english to french.
EDIT
Locale[] locales = Locale.getAvailableLocales();
for(Locale locale : locales){
if(locale.getCountry().equalsIgnoreCase("RS")
&& locale.getScript().equalsIgnoreCase("Latn"))
{
Configuration config = new Configuration();
config.setLocale(locale);
// using this to reference my Activity
this.getBaseContext().getResources().updateConfiguration(config, this.getBaseContext().getResources().getDisplayMetrics());
break;
}
}
I know there will be an efficient way to do it, however you may get the direction that you need to get the list of available locales and get the locale you desire. Hope it helps
EDIT-2 (Final)
you can construct the locale using:
Locale locale = new Locale.Builder().setLanguage("sr").setRegion("RS").setScript("Latn").build();
setLocale(locale);
Can you please use below one ?
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
Resources res = this.getResources();
Configuration conf = res.getConfiguration();
boolean isLatinAlphabet = PreferenceManager.getDefaultSharedPreferences(this);
if(conf.locale.getLanguage().equals("sr") && isLatinAlphabet) {
conf.locale = new Locale("sr", "YourContryCode");
res.updateConfiguration(conf, res.getDisplayMetrics());
}
}
}
Note: Replace your YourContryCode in conf.locale = new Locale("sr", "YourContryCode"); line.
Manifest.xml:
<application
android:name=".MyApplication"
android:icon="#drawable/ic_launcher"
android:label="#string/application_name"
android:theme="#style/AppTheme">
...
</application>
Hope this will help you.
How can I get simplified chinese description (简体)? From the available locale Locale.SIMPLIFIED_CHINESE, no method seems to return this description:
getDisplayLanguage() returns the correct language name, but without the variant.
getDisplayName() returns the correct language name and country, but also without the variant.
getDisplayVariant() returns an empty string.
I've also tried to build a new Locale using the different constructors, also to no avail.
new Locale("zh", "CN");
new Locale("zh", "CN", "Hans");
I've checked the Android source code for LocalePicker and I've concluded that it is loaded from the resources (special_locale_codes and special_locale_names).
Any solutions besides having to hardcode/include this string in my resources?
Let me explain my process on how I tackled this. First, I found this block of code in LocalePicker.java
private static String getDisplayName(Locale l, String[] specialLocaleCodes, String[] specialLocaleNames) {
String code = l.toString();
for (int i = 0; i < specialLocaleCodes.length; i++) {
if (specialLocaleCodes[i].equals(code)) {
return specialLocaleNames[i];
}
}
return l.getDisplayName(l);
}
which takes in a Locale as you already know. Then it tries to find the locale code in the specialLocaleCodes string array. The specialLocaleNames you are seeking are obtained from arrays.xml as you've helpfully stated:
<string-array translatable="false" name="special_locale_codes">
<item>ar_EG</item>
<item>zh_CN</item>
<item>zh_TW</item>
</string-array>
and the corresponding languages
<string-array translatable="false" name="special_locale_names">
<item>العربية</item>
<item>中文 (简体)</item>
<item>中文 (繁體)</item>
</string-array>
Notice the code with the simplified Chinese is zh_CN and the last two characters are capitalized.
However,
Locale locale = new Locale("zh_CN");
System.out.println("Locale: " + locale);
prints
Locale: zh_cn
Notice the lower case. So there is no way specialLocaleCodes[i].equals(code) will return true. So then I poked around Locale.java and, long story short, we can bypass that case-changing jumble by doing this (and you MUST keep the 3rd parameter as an empty string for this to work):
Locale locale = new Locale("zh", "CN", "");
System.out.println("Locale: " + locale);
Prints
Locale: zh_CN
With this you should be able to do this:
Locale locale = new Locale("zh", "CN", "");
System.out.println("Name:" + locale.getDisplayName(locale));
Upon further inspection on Kitkat using this (thank you Andrew!)
int specialLocaleNamesId = Resources.getSystem().getIdentifier("special_locale_names", "array", "android");
String[] specialLocaleNames = Resources.getSystem().getStringArray(specialLocaleNamesId);
it was possible to print out
العربية,中文 (简体),中文 (繁體)
as expected. However, something in Kitkat is still preventing the correct string to display. Frustrating.
However, in Lollipop 5.0+ and Java 1.7 this works using forLanguageTag() in Locale.
Locale locale = Locale.forLanguageTag("zh-Hans");
System.out.println("getDisplayName:" + locale.getDisplayName(locale));
System.out.println("getDisplayLanguage:" + locale.getDisplayLanguage(locale));
which prints
getDisplayName:中文 (简体中文)
getDisplayLanguage:中文
You could probably access the android internal resource: com.android.internal.R.array.special_locale_names the same way it's done in LocalePicker:
final Resources resources = context.getResources();
final String[] specialLocaleNames = resources.getStringArray(com.android.internal.R.array.special_locale_names);
But it's probably safer to use your own resource here (avoiding
the use of internals)