translate string by value in locale - android

Does android API support translating string resources by value?
I know that I can create multiple XML files for different locale. My problem is that I am getting the values from the server in a "default locale" so, I can't use getString(int).
I want something like getTranslation("myValueInDefaultLocale", "target locale")

There is no efficient way to do what you are asking, but to modify the server. If you can't change server, then you can do this:
Save current locale
Switch to default locale programmatically
Iterate through all string resources looking for specific string
Save ID of the string
Switch back to saved locale
Get translated value of string by ID in desired locale
But this will work really slow. Don't say I didn't warn you.
Here is the code sample:
String translateFrom = "server reply";
Resources res = getResources();
Configuration conf = res.getConfiguration();
Locale savedLocale = conf.locale;
conf.locale = defaultLocale; // set to default locale here
res.updateConfiguration(conf, null);
// iterate through all string resources in default locale
int idTranslateTo = 0;
Field fields[] = R.string.class.getFields();
for (Field field : fields) {
int id = getResources().getIdentifier(field.getName(), "string", this.getPackageName()));
if (translateFrom.equals(res.getString(id)) {
idTranslateTo = id;
break;
}
}
// restore original locale
conf.locale = savedLocale;
res.updateConfiguration(conf, null);
// retrieve translated string from saved locale
if (idTranslateTo != 0) {
String translateTo = res.getString(idTranslateTo);
}

Related

font styles are not Changing neither numbers in android

I'm getting stuck in this for two days i hope i find a solution..
I'm trying to localize my app (Arabic, and English)
the localization mechanism is working fine, the words, layout directions are working well,
However there are two things are not being localized the first one is numbers.
numbers are not being localized to arabic.
the second one is Font style font style are not being localized neither.
BUT it change the font style and number to arabic, only if i reinstalled the app using my USB and the configuration was in Arabic before the installing. here is my code
public static void changeLocale(Activity context, Bundle... bundles) {
MedfastSharedPreferencesHelper sharakehSharedPreference = new MedfastSharedPreferencesHelper(context);
String lang = sharakehSharedPreference.getKey("locale");
Locale locale = null;
if (null == lang) {
locale = new Locale(Resources.getSystem().getConfiguration().locale.getLanguage());
lang = locale.getDisplayLanguage();
if (locale.getDisplayLanguage().equalsIgnoreCase("English")) {
locale = new Locale("ar");
lang = "ar";
} else {
locale = new Locale("en");
lang = "en";
}
} else if (lang.equalsIgnoreCase("ar")) {
lang = "en";
locale = new Locale("en");
} else if (lang.equalsIgnoreCase("en")) {
lang = "ar";
locale = new Locale("ar");
}
sharakehSharedPreference.setKey("locale", lang);
Resources resources = context.getResources();
DisplayMetrics displayMetrics = resources.getDisplayMetrics();
Locale.setDefault(locale);
Configuration configuration = resources.getConfiguration();
configuration.setLocale(locale);
configuration.locale = locale;
resources.updateConfiguration(configuration, displayMetrics);
Intent intent = new Intent(context, ((Activity) context).getClass());
if (null != bundles && bundles.length > 0 && null != bundles[0])
intent.putExtras(bundles[0]);
context.startActivity(intent);
context.finish();
}
After researching, android does not support font as resource, so i had do create 6 classes in order to customize my fonts and check weather if the locale is Arabic or english, and depending on the locale i load the font, unlike drawable in android
Hey as Basil Battikhi said, the font does not apply to numbers, But there are some solutions:
1: Create your own custom textView to be able to change things you want.
2: Define this in strings.xml
<string name="number">%1d</string>
and set number to your textView like this:
textCoin.text = getString(R.string.number, it)
3: You can use this code for formating your textView for numbers:
public static String convertEngNumToFa(String number) {
if (AppConstants.FA_LOCALE == DataManager.Language.fa) {
StringBuilder res = new StringBuilder();
try {
for (char _ch : number.toCharArray()) {
if ((int) _ch > 47 && (int) _ch < 58) {
int x = (int) _ch + 1632 - 48;
char ch = (char) (x);
res.append(Character.toString(ch));
} else {
res.append(Character.toString(_ch));
}
}
} catch (Exception e) {
return res.toString();
}
return res.toString();
} else return number;
}

How to get the id of a string resource associated with a TextView?

I can access the TextView instance, get it's resource ID and get it's resource name via getResources().getResourceEntryName(), but I can't seem to find a way to get the id of the string associated with it.
How can I dynamically get the id of the string resource associated with a TextView ?
You can't. A TextView doesn't store the id of the String resources if you call setText(int resid). All this overloaded method does is get the String from the resources and call the setText(CharSequence text) method.
The only workaround I could was to match the +id of the TextView instances in the layout xml with the name of the string, then use Resources to get pair the two:
/**
* finds a string id matching a text view id name and returns the value
* #param textView - text view
* #param context - the context
* #param locale - the locale string
* #return String - resource string if found, empty string otherwise
*/
public static String getTextViewStringFromResources(TextView textView,Context context,String locale){
String result = "";
final int textViewID = textView.getId();
if(textViewID <= 0){
Log.e(TAG,"invalid id for textView " + textView + " text = " + textView.getText());
result = textView.getText().toString();
return result;
}
//get resources (re-usable)
final Resources resources = getLocalizedResources(context,locale);
// get textViews id
final String entryName = resources.getResourceEntryName(textView.getId());
// get the string id !! must match the textview id !!
final int stringID = resources.getIdentifier(entryName,"string",context.getPackageName());
//return string value for string id found by textview id
try{
result = resources.getString(stringID);
}catch (Resources.NotFoundException e){
Log.e(TAG,"couldn't find a string id for " + entryName);
Log.e(TAG,e.getMessage());
}
return result;
}
//!! requires minSDK 17
#NonNull
public static Resources getLocalizedResources(Context context, String locale) {
Locale desiredLocale = new Locale(locale);
Configuration conf = context.getResources().getConfiguration();
conf.setLocale(desiredLocale);
Context localizedContext = context.createConfigurationContext(conf);
return localizedContext.getResources();
}
The swapping is partially based on Gunhan Sancar's method of swapping text field.
This works but it pretty much a hack.
Eventually I needed to also change the Google Handwriting Input language programmatically and for that Juuso's ADB Change Language app came in super handy.
For reference, here's a function using Juuso's approach:
final String TAG = "ChangeLanguage"
//change language utils "kindly borrowed" from net.sanapeli.adbchangelanguage: brilliant little app!
/**
* updates a Configuration with a list of Locales
* #param configuration - a configuration to updated
* #param arrayList - an ArrayList of Locale instances
* #return the updated configuration
*/
#TargetApi(24)
public static Configuration addLocalesToConfiguration(Configuration configuration, ArrayList<Locale> arrayList) {
configuration.setLocales(new LocaleList((Locale[]) arrayList.toArray(new Locale[arrayList.size()])));
return configuration;
}
/**
* Change the system language
* #param lanaguageList - a list of Locale instances to change to
*/
public static void changeLanguages(ArrayList<Locale> lanaguageList){
try {
Class cls = Class.forName("android.app.ActivityManagerNative");
Method method = cls.getMethod("getDefault", new Class[0]);
method.setAccessible(true);
Object invoke = method.invoke(cls, new Object[0]);
method = cls.getMethod("getConfiguration", new Class[0]);
method.setAccessible(true);
Configuration configuration = (Configuration) method.invoke(invoke, new Object[0]);
configuration.getClass().getField("userSetLocale").setBoolean(configuration, true);
if (VERSION.SDK_INT >= 24) {
configuration = addLocalesToConfiguration(configuration, lanaguageList);
} else {
configuration.locale = (Locale) lanaguageList.get(0);
}
Method method2 = cls.getMethod("updateConfiguration", new Class[]{Configuration.class});
method2.setAccessible(true);
method2.invoke(invoke, new Object[]{configuration});
Log.d(TAG,"locale updated to" + lanaguageList.get(0).toString());
} catch (Exception e) {
Log.e(TAG,"error changing locale (double check you're granted permissions to the app first: pm grant your.app.package.here android.permission.CHANGE_CONFIGURATION )");
e.printStackTrace();
}
}
Remember to grant CHANGE_CONFIGURATION to your app.
This is tested with Android 7.1.1 but bare in mind that it will fail on Android 8.0 (and potentially upwards) as getConfiguration is not found (the API is different) under certain build conditions.
The method expects an ArrayList of Locale objects with the language you want to change to on top:
e.g.
ArrayList<Locale> fr = new ArrayList<Locale>();
fr.add(new Locale("fr"));
fr.add(new Locale("en"));
ArrayList<Locale> en = new ArrayList<Locale>();
en.add(new Locale("en"));
en.add(new Locale("fr"));
Make sure the Languages are installed on the devices as well.
If you have other improvement suggestions I'd be more than happy to update the answer

Not able to read strings from region specific folders in Android

I am trying to override locale configuration in my app. But, I am not able to differentiate between language and their regions.
I am trying following code to override the locale.
Getting locale to override.
Example : "de_DE", "de_AT"
public static Locale getLocaleFromString(#NonNull final String locale) {
String[] split = locale.split("_");
if (split != null || split.length > 1) {
String language = split[0];
String country = split[1];
return new Locale(language, language, country);
}
return Locale.getDefault();
}
The structure of my resource folders is:
values/strings.xml (default strings)
values-de-rDE/strings.xml
values-de-rAT/strings.xml
If, I define values-de/strings.xml, application start reading from this folder.
That means locale overriding works in app, but some how android system is not able to read string from region specific folders.
(My device language is english.)
Any help would be really appreciated.
The arguments passed to Location's constructor may be wrong:
The second should be country and the third should be variant.
So getLocaleFromString should like this:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Resources res = getResources();
DisplayMetrics dm = res.getDisplayMetrics();
Configuration conf = res.getConfiguration();
conf.locale = getLocaleFromString("de_DE");
res.updateConfiguration(conf, dm);
setContentView(R.layout.activity_main);
}
public static Locale getLocaleFromString(#NonNull final String locale) {
String[] split = locale.split("_");
if (split != null || split.length > 1) {
String language = split[0];
String country = split[1];
return new Locale(language, country);
}
return Locale.getDefault();
}
}

Android Localization from resources

I am currently trying to localize my android app and i have setup everything but it keeps of loading the same string resource whenever i try to change the language.
I have the below string resources
values
values-am
values-om
SharedPreferences sharedPreferences = getSharedPreferences("MY_SHARED_PREF", MODE_PRIVATE);
String languageLocale = sharedPreferences.getString("SAVED_LANGUAGE_LOCALE", "am");
Log.d(TAG,languageLocale);
String languageToLoad = languageLocale; // your language
Locale locale = new Locale(languageToLoad);
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config,
getBaseContext().getResources().getDisplayMetrics());
I am also using the code below for selecting the language in a different activity
RadioGroup.OnCheckedChangeListener radioGroupOnCheckedChangeListener =
new RadioGroup.OnCheckedChangeListener(){
#Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
RadioButton checkedRadioButton = (RadioButton)mRadioGroup.findViewById(checkedId);
int checkedIndex = mRadioGroup.indexOfChild(checkedRadioButton);
//AppController languageSetting = (AppController)getApplication();
SavePreferences(KEY_SAVED_RADIO_BUTTON_INDEX, checkedIndex);
mLanguageId = checkedIndex + 1;
languageSetting.setLanguageId(mLanguageId);
switch (mLanguageId){
case 1:
SavePreferencesLocale(KEY_SAVED_LANGUAGE_LOCALE,"en");
mTest = "en";
break;
case 2:
SavePreferencesLocale(KEY_SAVED_LANGUAGE_LOCALE,"am");
mTest = "am";
break;
case 3:
SavePreferencesLocale(KEY_SAVED_LANGUAGE_LOCALE,"om");
mTest = "om";
break;
}
}};
Now the problem is whenever the application started for the first time it loads the correct string resource but when I change the language it keeps the same string resource. that means eg. if the app starts with the values-am string resource when i change it to values-om i still see the values-am strings despite the locale is assigned with the correct value ("om")
Here is something:
String languageLocale = sharedPreferences.getString("SAVED_LANGUAGE_LOCALE", "am");
by **
sharedPreferences.getString(""SAVED_LANGUAGE_LOCALE", "am");
** you dont need string "am". This "am" you need only by .putString()!
Should look like
String languageLocale = sharedPreferences.getString("KEY_SAVED_LANGUAGE_LOCALE");
You need to call the below code on every language selection in onCheckedChanged().
Locale locale = new Locale("Selected language code comes here");
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
After setting the Locale, use recreate() to restart the activity.
Intent Refresh and call
Locale locale = new Locale("ar");
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale; getBaseContext().getResources().updateConfiguration(config, getBaseContext().getResources().getDisplayMetrics());
this.setContentView(R.layout.activity_main_category_page);

android: programmatically localize a dynamic string

I have a computed String stored in local variable.
There is no way I can know the string on before hand, however I know for sure in the end it will be one of the Strings whose translations to different languages are inside the string.xml files.
How can I translate such a dynamic string to the current locale?
Although this will take quite long, you could iterate through all the strings, check whether they match, and return the localized version if they do:
public String translatedString(String s)
//Set the locale to en-us
Resources standardResources = context.getResources();
AssetManager assets = standardResources.getAssets();
DisplayMetrics metrics = standardResources.getDisplayMetrics();
Configuration config = new Configuration(standardResources.getConfiguration());
config.locale = Locale.US;
Resources defaultResources = new Resources(assets, metrics, config);
//Iterate over string res
Field fields[] = R.string.class.getFields();
for (Field field : fields) {
String value = defaultResources.getString(defaultResources.getIdentifier(field.getName(), "string", this.getPackageName())));
if (value.equals(s)){
return getResources().getString(getResources().getIdentifier(field.getName(), "string", this.getPackageName())));
}
}
return null;
}

Categories

Resources