5.2: Locales

Contents:

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.  An app localized for the U.S. (left), France (center), and Israel (right)

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 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:32pm
  • FULL 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:

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():

  1. Use the Locale.getDefault() method to get the value of the user-chosen locale.
  2. 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:

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.

Important: Always provide default resources—don't rely on language- or locale-specific resources to cover all the use cases for your app. For details, see "Why default resources are important" in this section.

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:

  1. Right-click the res directory and choosing New > Android Resource Directory to add a new resource directory.
  2. Choose drawable from the Resource type dropdown menu. The Directory name changes to drawable. Note that you can add any type of resource directory, including values or layout directories.
  3. 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.  Choose a language and locale pair.

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 or drawable.
  • language code : The language code, such as en for English or fr for French.
  • country code : Optional: The country code, such as US for the U.S. or FR 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.  The flag drawable in three versions—default (U.S.), France, and 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:

  1. Add a resource directory for a language and locale.
  2. Copy the files you need from the default resource directory, such as the values directory.
  3. Paste the files into the new resource directory, such as values-iw-rIL (for Hebrew in Israel).
  4. Edit the files that are associated with the language and locale identifiers—such as styles.xml (iw-rIL) or colors.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.

Note: Make sure that your app includes a full set of default resources. If an app is missing a default resource (such as a string or a color setting), its behavior will be unpredictable.

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.). The values 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 the strings.xml file (in the values 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 the strings.xml file (in the values 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.

The related practical documentation is Using the locale to format information.

Learn more

Android developer documentation:

Android Developers Blog:

Android Play Console: Translate & localize your app

Video: Welcome to the World of Localization

Other:

results matching ""

    No results matching ""