5.2: Locales
Contents:
- Formatting the date and time
- Formatting numbers
- Formatting currencies
- Retrieving and using the locale
- Adding resources for different locales
- Related practical
- Learn more
Users run Android devices in many different parts of the world. To provide the best experience for users in different regions, your app should handle not only text but also numbers, dates, times, and currencies in ways appropriate to those regions.
When users choose a language, they also choose a locale for that language, such as English (United States) or English (United Kingdom). Your app should change to show the formats for that locale: for dates, times, numbers, currencies, and similar information. Dates can appear in different formats (such as dd / mm / yyyy or yyyy - mm - dd ), depending on the locale. Numbers appear with different punctuation, and currencies sometimes vary by locale.
Hardcoding your formats based on assumptions about the user's locale can result in problems when the user changes to another locale. For example, if your app guarantees shipping by 5/4/2017, that means May 4, 2017, in the U.S., but it means April 5, 2017, in the U.K.
Android provides classes and methods you can use to apply the format of the user-chosen locale, or to use a format from another locale. Store all data for the app in a default format, and use these classes to localize the data for display.
For some aspects of localization you might need to add non-default resources, as described in Adding resources for different locales.
Formatting the date and time
As a rule, store all data for the app in the format that's appropriate for the default language and locale, and then use a user-chosen format as needed.
Android provides the DateFormat
class and methods to apply the date format of the user-chosen locale. DateFormat
is an abstract class that can format a Date
object to a string, and parse a date string, in a language-independent manner. For example, you can use the DateFormat.getDateInstance()
method to get the format for the user's selected language and locale, and the DateFormat.format()
method to prepare a formatted string for display:
final Date myDate = new Date();
// Format the date for the locale.
String myFormattedDate = DateFormat.getDateInstance().format(myDate);
// Display the formatted date.
TextView dateView = (TextView) findViewById(R.id.date);
dateView.setText(myFormattedDate);
When you use DateFormat
, your code is independent of the locale conventions for formatting months, days of the week, or even the calendar format (lunar or solar). Use the following DateFormat
factory methods:
- To get the date format for the user-chosen locale, use
getDateInstance()
. When used withDateFormat.format
, the result is a string such as "Dec 31, 2016" (for the U.S. locale). - To get the date format for any given
Locale
object (which can be different from user-chosen locale), usegetDateInstance(
int style
, Locale aLocale)
. Thestyle
is a formatting style such asSHORT
for "M/d/yy" in the U.S. locale. - To get the time format for a specific country, use
getTimeInstance()
. The result is a time format such as "4:00:00 PM" (for the U.S. locale). - To get a combined date and time format, use
getDateTimeInstance()
. The result is a date/time format such as "Dec 31, 2016 4:00:00 PM" (for the U.S. locale).
To help you control how much space the localized date or time takes up, pass options (such as style
with getDateInstance()
) to these factory methods to control the length of the result. The exact result depends on the locale, but generally:
SHORT
is a numeric format, such as 12.13.52 or 3:30pm.MEDIUM
abbreviates the month, such as Jan 12, 1952.LONG
is the long version, such as January 12, 1952, or 3:30:32pmFULL
is completely specified, such as Tuesday, April 12, 1952 AD, or 3:30:42pm PST.
Tips:
- To create strings for things like elapsed time and date ranges, days of the week, months, and AM/PM for time, use the
DateUtils
class. - To write code that works with dates and a hybrid calendar that supports both the Julian and Gregorian calendar systems, use the
GregorianCalendar
class.
Formatting numbers
Numbers appear with different punctuation in different locales. In U.S. English, the thousands separator is a comma; in France, the thousands separator is a space; and in Spain, the thousands separator is a period. The decimal separator also varies from period to comma.
NumberFormat
is the abstract base class for all number formats. Your code can be completely independent of the locale conventions for decimal points and thousands separators.
For example, use the NumberFormat.getInstance()
method to return a number format for the user-selected language and locale, and the NumberFormat.format()
method to convert the formatted number to a string:
// Default quantity is 1.
int myQuantity = 1;
// Get the number format for this locale.
NumberFormat numberFormat = NumberFormat.getInstance();
// Format the number.
String myFormattedQuantity = numberFormat.format(myQuantity);
// Display the formatted number.
TextView quantityView = (TextView) findViewById(R.id.quantity);
quantityView.setText(myFormattedQuantity);
Tip: If you are formatting multiple numbers, it is more efficient to get the format and use it multiple times (such as numberFormat
), so that Android does not need to fetch the user-chosen language and locale multiple times.
To format a number for a locale other than the device's current locale, specify the locale in the NumberFormat.getInstance()
method. Android provides Locale
constants for many countries:
NumberFormat numberFormat = NumberFormat.getInstance(Locale.FRANCE);
The numberFormat
returned is for the specified locale, so that you can format the number without changing the user's chosen locale.
The NumberFormat.getInstance()
method returns a general-purpose number format for the user-chosen locale. This is the same as getNumberInstance()
. Use the following for more specific number formats:
getIntegerInstance()
: Returns an integer number format for the locale.getPercentInstance()
: Returns a percentage format for the locale.getCurrencyInstance()
: Returns a currency format for the locale. Currency formats are described in the next section.
Use NumberFormat.parse()
to parse a given string, such as EditText
field input, and use intValue()
to return an integer:
// Parse contents of string in EditText view and return a number.
try {
// Use numberFormat for the current locale.
myQuantity =
numberFormat.parse(qtyInput.getText().toString()).intValue();
} catch (ParseException e) {
e.printStackTrace();
}
Formatting currencies
Currencies sometimes vary by locale. Use the NumberFormat
class to format currency numbers. The getCurrencyInstance()
method returns the currency format for the user-selected language and locale, and the format()
method applies the format to create a string, as shown in the following code:
// Fixed price in U.S. dollars and cents: ten cents.
double myPrice = 0.10;
// Get locale's currency.
NumberFormat currencyFormat = NumberFormat.getCurrencyInstance();
// Use the currency format for the locale.
String myFormattedPrice = currencyFormat.format(myPrice);
// Show the string.
TextView localePrice = (TextView) findViewById(R.id.price);
localePrice.setText(myFormattedPrice);
In the above code, the NumberFormat
format()
method applies the currency format of the locale to the double
myPrice
to create the myFormattedPrice
string.
Currency exchange rates are in constant fluctuation. To offer multiple currencies in an app that calculates amounts, you may need to write code to retrieve the latest exchange rates every day from a web service.
Tip: You can quickly grab the latest exchange rate for a given currency by using the Google Finance Converter.
Retrieving and using the locale
A Locale
object represents a specific geographical, political, or cultural region. You can retrieve the country code of the user-chosen locale, compare the result to the locales supported by the app, then take actions depending on the locale.
Using the country/region code
For example, you may want to support three currencies in your app for three locales (U.S. dollars for the U.S., euros for France, and new shekels for Israel), and default to U.S. dollars for all other locales. To get the country/region code for the user-chosen locale, use Locale.getDefault().getCountry()
:
- Use the
Locale.getDefault()
method to get the value of the user-chosen locale. - Use the
Locale.getCountry()
method to get the country/region code for the user-chosen locale.
In the following snippet, the country/region code FR
is for France, and IL
is for Israel. If the country/region code matches a country whose currency your app supports (FR
or IL
), then use the currency format for that country; otherwise, use the default currency format:
String myFormattedPrice;
// Check if locale is supported for currency.
String deviceLocale = Locale.getDefault().getCountry();
if (deviceLocale.equals("FR") || deviceLocale.equals("IL")) {
// Use the currency format for France or Israel.
myFormattedPrice = currencyFormat.format(myPrice);
} else {
// Use the currency format for U.S.
currencyFormat = NumberFormat.getCurrencyInstance(Locale.US);
myFormattedPrice = currencyFormat.format(myPrice);
}
The code tests only for the FR
or IL
locales, because all other locales use the default currency format (U.S. dollars).
Using a locale constant
The Locale
class provides a number of convenient constants that you can use to create Locale
objects for commonly used locales. For example, Locale.US
creates a Locale
object for the U.S. The following line in the above snippet uses Locale.US
to apply the U.S. currency if the locale is not FR
or IL
:
currencyFormat = NumberFormat.getCurrencyInstance(Locale.US);
If a constant doesn't exist for a locale that you want to use, construct a Locale
object using Locale.Builder
(introduced in API Level 21). Once you've created a Locale
, you can query it for information about itself:
- Use
getCountry()
to get the country (or region) code of theLocale
object. - Use
getLanguage()
to get the language code. - Use
getDisplayCountry()
to get the name of the country suitable for displaying to the user. - Use
getDisplayLanguage()
to get the name of the language suitable for displaying to the user.
Tip: Create a Locale
object if you want to change the app's language dynamically from within the app at runtime.
Adding resources for different locales
In addition to formatting information for specific locales, you can add language dialects for a locale, and change images, colors, dimensions, and styles for different locales.
An app can include multiple resource directories, each customized for a different language and locale. When a user runs the app, Android automatically selects and loads the resource directories that best match the user's chosen language and locale.
For example, the strings in the strings.xml file in the values-fr
directory are in French. If the user chooses French as the language for the device, the French strings.xml
file is used rather than the strings.xml
file in the default values
directory.
The same is true for other values
files, such as colors.xml
and dimens.xml
. If the user chooses French as the language for the device, and if French colors.xml
and dimens.xml
files exist in values-fr
, then these French resources are used rather than the resources in the default values
directory.
The previous chapter described how to add languages with the Translations Editor. You can also use Android Studio to create resource directories for strings, dimensions, colors, drawable images, and other resources, as described in this section.
Adding a resource directory
Use Android Studio to add resource directories for a specific language and locale.
For example, you may want to substitute a specific image for "flag.png" in an app if the user chooses French as the language and France as the locale. To add a drawable
folder with a replacement image, follow these steps:
- Right-click the res directory and choosing New > Android Resource Directory to add a new resource directory.
- Choose drawable from the Resource type dropdown menu. The Directory name changes to
drawable
. Note that you can add any type of resource directory, includingvalues
orlayout
directories. - Choose Locale in the left column and click to select a language and locale. Choose fr: French as the language, and FR: France as the locale. The Directory name changes to
drawable-fr-rFR
. Click OK.
The Directory name now includes a localization qualifier that specifies a language and, optionally, a region. The localization qualifier is a two-letter ISO 639-1 language code such as fr
for French, optionally followed by a two letter ISO 3166-1-alpha-2 region code preceded by lowercase r
, such as rFR
for France.
The following is the general format for resource directory names that include localization qualifiers: resource type -
language code [-r
country code ]
- resource type : The resource subdirectory, such as
values
ordrawable
. - language code : The language code, such as
en
for English orfr
for French. - country code : Optional: The country code, such as
US
for the U.S. orFR
for France.
After creating the drawable-fr-rFR
directory, copy the replacement image, which should also be named "flag.png", into the directory. You must use the same filename, because that filename is defined for the ImageView
in the layout, as shown below—Android simply swaps in the different image.
<ImageView
android:id="@+id/flag"
app:srcCompat="@drawable/flag"
In Project: Android view, the image files appear in the drawable
directories with their identifiers in parentheses. The figure below shows the flag.png
drawable
in Project: Android view. The flag.png (fr-rFR)
drawable
is actually the flag.png
file inside the values-fr-rFR
directory for French in France. The flag.png (iw-rIL)
drawable
is the flag.png
file inside the values-iw-rIL
directory for Hebrew in Israel.
Changing colors and styles for different locales
You may not want to use the same design elements for each locale. For example, the color red in western countries indicates high energy or love, but in some eastern cultures, red is associated with prosperity, and in South Africa, mourning. Depending on your app, a design that incorporates a lot of red may work well in Peoria but not in Pretoria. You may also want to change the text size, font, and other style attributes for different languages.
To add color and style resources for different locales:
- Add a resource directory for a language and locale.
- Copy the files you need from the default resource directory, such as the
values
directory. - Paste the files into the new resource directory, such as
values-iw-rIL
(for Hebrew in Israel). - Edit the files that are associated with the language and locale identifiers—such as
styles.xml (iw-rIL)
orcolors.xml (iw-rIL)
.
For example, in some apps the text size is controlled by a style in styles.xml
in the values
directory. Copy that styles.xml
file into the newly created values-iw-rIL
directory, then open the styles.xml (iw-rIL)
file to modify it for the Hebrew language in Israel.
In some apps, color for a button's background may be set in an XML file in the drawable
directory. Copy the drawable
directory to create a different language version, then change the color in the copied XML file.
Why default resources are important
Do not assume that the device running your app is using one of the languages your app supports. The device might be set to a language or locale that you did not plan for, or that you didn't test. Design your app so that it will function no matter what language or locale the user chooses.
Android chooses the default resources if the language and locale is not specifically supported. That means if the user chooses Español (España) and your app does not provide the Spanish language (Español) for the Spain (España) locale, the app shows the language used in the default values
resource directory.
The default directories in the res
directory, created automatically by Android Studio, must contain all resources for the app. The following default directories are the ones most often used for translation and customization for languages and locales:
drawable
: Drawables and ".png" files for images and logos in the app.layout
: Layouts for the default language and locale.values
: The resources for the default language and locale (such as English in the U.S.). Thevalues
directory contains the following resource files:colors.xml
: Resources for color choices.dimens.xml
: Resources for dimensions in the layout.strings.xml
: Resources for all strings in the app.styles.xml
: Resources for styles used in the layout.
The following default directories are rarely customized for localization:
menu
: Options and popup menu choices. Your app can offer different menus for different languages, but to reduce the overhead of managing them, translate only the strings for the menu choices that are defined in thestrings.xml
file (in thevalues
directory).xml
: Preferences and other XML collections of resources. To reduce the overhead of managing separate XML resources, translate only the strings for the preferences that are defined in thestrings.xml
file (in thevalues
directory).mipmap
: Pre-calculated, optimized collections of app icons used by the Launcher. You can offer different icons for different languages and locales, but it is not necessary if your icon images are acceptable to the cultures in other countries.
Tip: To test whether an app includes every string resource that it needs, set the emulator or device to a language that your app does not support. For step-by-step instructions, see Testing for Default Resources.
Related practical
The related practical documentation is Using the locale to format information.
Learn more
Android developer documentation:
- Supporting Different Languages and Cultures
- Localizing with Resources
- Localization checklist
- Language and Locale
- Testing for Default Resources
Android Developers Blog:
Android Play Console: Translate & localize your app
Video: Welcome to the World of Localization
Other: