Issue when changing Locale to ARABIC in Android application - android

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

Related

Set Android DatePicker title language

I have an app that is available in 4 languages, which can be chosen within the app. On Android, the DatePicker has a title. This title, even after setting the locale, always seems to favor the devices set locale. Only the title does this, as the functional part of the DatePicker is in the app-chosen language.
Here is what it looks like when the app is set to Korean.
How do I go about Changing that Thu, Aug 24 to Korean? I've set both Xamarin and Android locale to Korean. Is there an attribute in the Date Picker renderer I can set?
Thanks.
If you are doing something like this to apply a new locale context base configuration:
protected override void AttachBaseContext(Android.Content.Context #base)
{
Locale locale = Locale.Korean;
Locale.SetDefault(Locale.Category.Format, locale);
#base.Resources.Configuration.SetLocale(locale);
var newContext = #base.CreateConfigurationContext(#base.Resources.Configuration);
base.AttachBaseContext(newContext);
}
The Material-design CalendarView does not honor the context's locale correctly from the one that is passed to its .ctor and you end up with the wrong Title localization as shown in your question ;-(
One option is to subclass DatePicker and re-implement DatePickerCalendarDelegate and apply that to a sub-classed AlertDialog, but that is a bit crazy amount of coding to correctly address the issue.
So this is a fix (hack) that I have been using (simplified for SO, so you will need to API the various API level checks, etc..):
Material Design Fix (including Oreo beta):
// globals/cached
bool headerChangeFlag = true;
TextView headerTextView;
string headerDatePatternLocale;
SimpleDateFormat monthDayFormatLocale;
void SetHeaderMonthDay(DatePickerDialog dialog, Locale locale)
{
if (headerTextView == null)
{
// Material Design formatted CalendarView being used, need to do API level check and skip on older APIs
var id = base.Resources.GetIdentifier("date_picker_header_date", "id", "android");
headerTextView = dialog.DatePicker.FindViewById<TextView>(id);
headerDatePatternLocale = Android.Text.Format.DateFormat.GetBestDateTimePattern(locale, "EMMMd");
monthDayFormatLocale = new SimpleDateFormat(headerDatePatternLocale, locale);
headerTextView.SetTextColor(Android.Graphics.Color.Red);
headerTextView.TextChanged += (sender, e) =>
{
headerChangeFlag = !headerChangeFlag;
if (!headerChangeFlag)
return;
SetHeaderMonthDay(dialog, locale);
};
}
var selectedDateLocale = monthDayFormatLocale.Format(new Date((long)dialog.DatePicker.DateTime.ToUniversalTime().Subtract(
new System.DateTime(1970, 1, 1, 0, 0, 0, System.DateTimeKind.Utc)).TotalMilliseconds));
headerTextView.Text = selectedDateLocale;
}
Usage:
var dialog = new DatePickerDialog(this);
dialog.Show();
SetHeaderMonthDay(dialog, Locale.Korean); // Call once, the text change event will update it when user changes date...
Results:

Android. Espresso. How to check that text is shown in a specific language without hard code strings?

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.

Prevent change numbers localization when change android language localization

I want to change android application localization Arabic - English.
but when I change language to Arabic it's changed all numbers to Arabic so the app crashed I want to change language to Arabic and prevent change numbers language from English.
Locale locale = new Locale(AppConfig.Language);
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = "ar";
getBaseContext().getResources().updateConfiguration(config,
getBaseContext().getResources().getDisplayMetrics());
setContentView(R.layout.activity_main);
when I want to use gps get location it's return numbers in arabic
how I can prevent it to change numbers language ??
I know this answer is too late but it can help someone in the future.
I was struggling with it for some days but I found an easy solution.
just set the country as the second parameter.because some countries use Arabic numeral and others use the so-called Hindu Numerals
Locale locale = new Locale(LanguageToLoad,"MA");//For Morocco to use 0123...
or
Locale locale = new Locale(LanguageToLoad,"SA");//For Saudi Arabia to use ٠١٢٣...
Founded Here
there is a complement so you don't have to change the whole code.
There's such issue in Google's bugtracker: Arabic numerals in arabic language intead of Hindu-Arabic numeral system
If particularly Egypt locale doesn't work due to some customer's issue(I can understand it), then you can format your string to any other western locales. For example:
NumberFormat nf = NumberFormat.getInstance(new Locale("en","US")); //or "nb","No" - for Norway
String sDistance = nf.format(distance);
distanceTextView.setText(String.format(getString(R.string.distance), sDistance));
If solution with new Locale doesn't work at all, there's an ugly workaround:
public String replaceArabicNumbers(String original) {
return original.replaceAll("١","1")
.replaceAll("٢","2")
.replaceAll("٣","3")
.....;
}
(and variations around it with Unicodes matching (U+0661,U+0662,...). See more similar ideas here)
Upd1:
To avoid calling formatting strings one by one everywhere, I'd suggest to create a tiny Tool method:
public final class Tools {
static NumberFormat numberFormat = NumberFormat.getInstance(new Locale("en","US"));
public static String getString(Resources resources, int stringId, Object... formatArgs) {
if (formatArgs == null || formatArgs.length == 0) {
return resources.getString(stringId, formatArgs);
}
Object[] formattedArgs = new Object[formatArgs.length];
for (int i = 0; i < formatArgs.length; i++) {
formattedArgs[i] = (formatArgs[i] instanceof Number) ?
numberFormat.format(formatArgs[i]) :
formatArgs[i];
}
return resources.getString(stringId, formattedArgs);
}
}
....
distanceText.setText(Tools.getString(getResources(), R.string.distance, 24));
Or to override the default TextView and handle it in setText(CharSequence text, BufferType type)
public class TextViewWithArabicDigits extends TextView {
public TextViewWithArabicDigits(Context context) {
super(context);
}
public TextViewWithArabicDigits(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public void setText(CharSequence text, BufferType type) {
super.setText(replaceArabicNumbers(text), type);
}
private String replaceArabicNumbers(CharSequence original) {
if (original != null) {
return original.toString().replaceAll("١","1")
.replaceAll("٢","2")
.replaceAll("٣","3")
....;
}
return null;
}
}
I hope, it helps
It is possible to set the locale for the individual TextView or elements that extend it in your app. see http://developer.android.com/reference/android/widget/TextView.html#setTextLocale(java.util.Locale) for more information
UPDATE
You can use the following method to parse the number to the locale you want
public static String nFormate(double d) {
NumberFormat nf = NumberFormat.getInstance(Locale.ENGLISH);
nf.setMaximumFractionDigits(10);
String st= nf.format(d);
return st;
}
Then you can parse number to double again
The best and easy way to do is keep the number in all string file as it is , in all the localization strings. Or you need to translate each number string into numbers
I have had the same problem, the solution was to concatenate the number variable with an empty string.
For example like this :
public void displayPoints(int:points){
TextView scoreA = findViewById(R.id.score_id);
scoreA.setText(""+points);
}
I used this
scoreA.setText(""+points);
instead of this
scoreA.setText(String.format("%d",points));
this will even give you a warning that hardcoded text can not be properly translated to other languages, which exactly what we want here :) .

How to change locale to use Latin Serbian (instead of Cyrillic Serbian)

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.

Android Studio: Error getting string from resource in multi-language app

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)

Categories

Resources