Android get device locale
Asked Answered
T

7

56

Upon installation of my Android program I check for device locale:

String deviceLocale=Locale.getDefault().getLanguage();

If deviceLocale is inside my supported languages (english, french, german) I don't change locale.

But for instance say that if I don't support device's language: for example spanish.
I set current locale to English, because most of the people can understand English partly.

Locale locale = new Locale("en");
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
pContext.getResources().updateConfiguration(config, null);

But after that, in other methods, when I check device's locale like this:

String deviceLocale=Locale.getDefault().getLanguage();

I get result as "English". But device's locale is Spanish.

Does getLanguage() gives current app's locale ?
How can I get device's locale ?

Edit: In app's first run, it is an option to save device locale. But if user changes device locale after I save, I can't know new locale of the device. I can only know the locale that I saved in app install.

Telethon answered 28/4, 2014 at 18:49 Comment(5)
If you get the default locale AFTER you set it... you get what you set. It could be an option to save the locale BEFORE changing it (say, to a SharedPreference), to be recovered later - if you need to go back.Communal
But when I go back and load locale value that I saved, I get latest known device locale. But after save, if user changes device locale, I can't know device's current locale ?Telethon
That's a good point. Mine was kind of a hack. I still believe you don't have much fun in changing your device locale more than once in a phone-life... or to be more "funny", more than once a day. Anyway, you're right - my hack doesn't really solve the issue.Communal
In general its best to modify existing objects than creating your own, and just modify the fields in the existing object instead. Right now when you create your new Configuration object the constructor internally calls setToDefaults(). This may override some changes that you made to your configuration elsewhere if you aren't careful. This is unrelated to your question, but just a good rule of thumb. So instead of making a new object, call getResources().getConfiguration().Succotash
You can detect the locale change listening for the LOCALE_CHANGED broadcast. But the intent doesn't seem to include the new Locale, so you will have to rely on @shoe answer to get the new Locale.War
L
95

There's a much simpler and cleaner way to do this than using reflection or parsing some system property.

As you noticed once you set the default Locale in your app you don't have access to the system default Locale any more. The default Locale you set in your app is valid only during the life cycle of your app. Whatever you set in your Locale.setDefault(Locale) is gone once the process is terminated . When the app is restarted you will again be able to read the system default Locale.

So all you need to do is retrieve the system default Locale when the app starts, remember it as long as the app runs and update it should the user decide to change the language in the Android settings. Because we need that piece of information only as long as the app runs, we can simply store it in a static variable, which is accessible from anywhere in your app.

And here's how we do it:

public class MyApplication extends Application {
    
    public static String sDefSystemLanguage;
    
    @Override
    public void onCreate() {
        super.onCreate();

        sDefSystemLanguage = Locale.getDefault().getLanguage();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);

        sDefSystemLanguage = newConfig.locale.getLanguage();
    }

}

Using an Application (don't forget to define it in your manifest) we get the default locale when the app starts (onCreate()) and we update it when the user changes the language in the Android settings (onConfigurationChanged(Configuration)). That's all there is. Whenever you need to know what the system default language was before you used your setDefault call, sDefSystemLanguage will give you the answer.

There's one issue I spotted in your code. When you set the new Locale you do:

Configuration config = new Configuration();
config.locale = locale;
pContext.getResources().updateConfiguration(config, null);

When you do that, you overwrite all Configuration information that you might want to keep. E.g. Configuration.fontScale reflects the Accessibility settings Large Text. By settings the language and losing all other Configuration your app would not reflect the Large Text settings any more, meaning text is smaller than it should be (if the user has enabled the large text setting). The correct way to do it is:

Resources res = pContext.getResources();
Configuration config = res.getConfiguration();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
    configuration.setLocale(locale);
}
else {
    configuration.locale = locale;
}
res.updateConfiguration(config, null);

So instead of creating a new Configuration object we just update the current one.

Lunalunacy answered 9/5, 2014 at 4:10 Comment(2)
Thank you for information and additional info about new Configuration() issue.Telethon
This was really in detail. Loved the details, samples were everywhere!Androgynous
J
58

Update: As pointed out in comments 'locale' field is deprecated and you need to use getLocales() instead.

defaultLocale = Resources.getSystem().getConfiguration().getLocales().get(0);

You can access global locale by -

defaultLocale = Resources.getSystem().getConfiguration().locale;

Take a look at http://developer.android.com/reference/android/content/res/Resources.html#getSystem() -

Returns a global shared Resources object that provides access to only system resources (no application resources)

Jarret answered 8/5, 2014 at 9:59 Comment(2)
this is the right solution! Locale.getDefault().getLanguage() will give the one set by your app and not the phone's languageDialectologist
Took me way to long to find this comment! This is what I was looking for, how to get the devices default languages and then change the app's language depending on this. Thank you!Flin
C
8

The best way to design the app is to use a default lang, English in your case, under values/ and you can add addition langs under values-XX/. In this way when a language is not supported Android fallback to your default, so English. Let the OS does the work for you :) However, yes if you change the locale you'll get your last settings, so you have to save that information somewhere.

Columbous answered 28/4, 2014 at 18:53 Comment(0)
S
3

As you are changing the Application language programatically like

Locale locale = new Locale("en");
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
pContext.getResources().updateConfiguration(config, null);

And

But after that, in other methods, when I check device's locale like this:

String deviceLocale=Locale.getDefault().getLanguage();
I get result as "English". But device's locale is Spanish.

So instead of that use this below code to get the device's Local

try {
    Process exec = Runtime.getRuntime().exec(new String[]{"getprop", "persist.sys.language"});
    String locale = new BufferedReader(new InputStreamReader(exec.getInputStream())).readLine();
    exec.destroy();
    Log.e("", "Device locale: "+locale);
} catch (IOException e) {
    e.printStackTrace();
}

OUTPUT: Spanish Check this

Hope this exactly you are looking for.

Semang answered 8/5, 2014 at 2:24 Comment(0)
M
2

you should use String deviceLocale= Locale.getDefault().getDisplayLanguage(); to display the language instead of

String deviceLocale=Locale.getDefault().getLanguage();

check out this answer it may help you if above does not. Clickable

Mcclimans answered 1/5, 2014 at 19:52 Comment(0)
H
1

Although, the answer by @user2944616 is politically correct, that does not give an answer to the actual question posed.

So, if I really had to know the user set system locale, I'd use reflection (do not know any better option ATM):

private String getSystemPropertyValue(String name) {
    try {
        Class<?> systemProperties = Class.forName("android.os.SystemProperties");
        try {
            Method get = systemProperties.getMethod("get", String.class, String.class);
            if (get == null) {
                return "Failure!?";
            }
            try {
                return (String)get.invoke(systemProperties, name, "");
            } catch (IllegalAccessException e) {
                return "IllegalAccessException";
            } catch (IllegalArgumentException e) {
                return "IllegalArgumentException";
            } catch (InvocationTargetException e) {
                return "InvocationTargetException";
            }
        } catch (NoSuchMethodException e) {
            return "SystemProperties.get(String key, String def) method is not found";
        }
    } catch (ClassNotFoundException e) {
        return "SystemProperties class is not found";
    }
}

With that given and device locale set to Spanish (United States) / Español (Estados Unidos) following string

<string name="system_locale">System locale: <xliff:g id="profile_name">%1$s</xliff:g>&#95;<xliff:g id="device_name">%2$s</xliff:g></string>

and this code

private static final String SYS_COUNTRY = "persist.sys.country";
private static final String SYS_LANG = "persist.sys.language";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    TextView tv = (TextView)findViewById(R.id.locale);
    tv.setText(getString(R.string.system_locale, getSystemPropertyValue(SYS_LANG),
            getSystemPropertyValue(SYS_COUNTRY)));
}

yields following screen:

System locale screenshot

If desired, one could also easily construct Locale instance using the above:

Locale locale = new Locale(getSystemPropertyValue(SYS_LANG),
        getSystemPropertyValue(SYS_COUNTRY));
Log.d(TAG, "Language: " + locale.getLanguage());
Log.d(TAG, "Country: " + locale.getCountry());

Log output:

D/GetSystemLocale(5697): Language: es
D/GetSystemLocale(5697): Country: US

Hope this helps.

Hohenlohe answered 6/5, 2014 at 15:5 Comment(2)
To me it seems the best way to do it. A way to avoid reflection would be to just execute the getprop command and parse the output. You also can you can get the Country and Language of the TTS system.War
TTS engine's default language may easily differ from the system locale.Hohenlohe
B
-1

To get the device locale use this

Locale current = context.getResources().getConfiguration().locale;

and current.toString() will return you "en" "ar" etc

Boulware answered 5/5, 2014 at 12:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.