Localization is more than just the translation of the strings in your application in other languages. It also involves displaying data, such as dates and times, in the right format for your users. Even if you only want an English version of your application it's good to know what localization involves. That way you'll be ready if you decide to add support for additional locales and you won't have to look for strings and values all over your application's code base.
With the Android SDK, the language of the localized strings and the format used to display values depends on the locale of the device. The locale is a combination of the language and the country. The language is defined by the ISO 639-1 standard while the country is defined by the ISO 3166-1 standard. This means that the Android locale is compatible with the culture or locale used by most other programming languages and frameworks.
The only locale guaranteed to be present on every Android device is English as spoken in the United States. It is represented by the en_US code, with en being the language code for English and US being the country code for the United States. You can also use the en language code only as the locale to represent all the English-speaking countries and regions.
To localize an application for a language or for a specific country and language, you need to include the resources for that locale in the /res folder of your application. This usually includes string resources in the /res/values folder, but it can also include other types of resources, such as images and layouts. The Android SDK identifies the various alternative resources with configuration qualifiers, which are then used to name the folder containing those resources. The configuration qualifier for the locale is the language code, optionally followed by the country code. So, the localized string resources for your application must be in the /res/values-<language code> or /res/values-<language code>-r<country code> folder.
1. Localizing Strings
Every Android application should have all its string resources in the /res/values/strings.xml file. This allows for string reuse in your application even if no localization is needed. Also, if no file is available for the device's current locale this file is used. If you don't have one and your application tries to access a string resource that is only available in a strings.xml file specific to a locale, your application will crash without warning since resources are loaded at runtime and not during compilation.
A strings.xml file specific to a locale doesn't need to have all the string resources from the /res/values/strings.xml file. This means that if a resource, like the name of your application, doesn't need to be localized, you don't need to include it in every strings file.
At runtime, the /res/values-<language code>-r<country code>/strings.xml file for the locale of the device is checked followed by the /res/values-<language code>/strings.xml file for the language only. If the specified string is not available in those files, then the application falls back to the /res/values/strings.xml.
For example, if you want to localize your application for all the French-speaking regions and countries without targeting a specific one, you put the strings for the application in the /res/values-fr/strings.xml file. However, if you want to localize some strings with spelling specific to French as written in France, you have to put them in the /res/values-fr-rFr/strings.xml file. Make sure to add the r before the country code in the name of the folder or it won't be found at runtime when the application is localized.
Here is an example of a /res/values/strings.xml file with a few string resources in English:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Android Localization Demo</string> <string name="hello_world">Hello world!</string> <string name="hello_world_name">Hello %s!</string> </resources>
And here is a /res/values-fr/strings.xml file with the same resources in French:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Démo de localisation Android</string> <string name="hello_world">Bonjour le monde!</string> <string name="hello_world_name">Bonjour %s!</string> </resources>
Localizing Strings in Layouts
The strings in your layouts should be string resources. In fact, a Lint warning is displayed if a string is hard-coded. You can use resources everywhere where you would set strings in layouts. String resources are identified by
@string/ followed by the name of the resource from the strings.xml file. The following displays the
hello_world string from the previous example in a
TextView according to the locale of the device:
<TextView android:id="@+id/hello_world_textview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_world" />
This shows "Bonjour le monde!" on an Android device set to a locale that includes the French language. For all the other locales, the "Hello world!" string is shown.
Localizing Strings in Code
You will also need to localize strings from your code if you create or modify controls outside your layouts. To localize those strings you must first get the
android.content.res.Resources object that contains all the resources
in the package of the application for the current context. You then call the
getString method on that object, passing in the identifier of the string to display. For example, the following code block shows you how to set the text of a
// Get the translated string from the string resource android.content.res.Resources res = context.getResources(); String helloWorld = res.getString(R.string.hello_world); // Set the string to the textview TextView helloTextView; helloTextView = (TextView)findViewById(R.id.hello_world_textview); helloTextView.setText(helloWorld);
More complex strings, with one or more variable components, you need to use format strings. Format strings let you to specify the values for parameters to display. The parameters in the format string are identified with format specifiers. The most commonly used format specifier is
%s, representing a string. In fact, all the format strings from the
java.util.Formatter class are available. Also, if multiple parameters are required, you must number your format specifiers. In the case of string format specifiers, the first should be
%1$s, the second
%2$s, and so on.
Once format strings are specified, you use the
String.format method to pass in the parameters to display to your string. Here is how to set the text to show in a
TextView with the
hello_world_name format string from the strings.xml file. This format string includes a format specifier for the name of the user:
// Get the format string android.content.res.Resources res = context.getResources(); String helloFormatString = res.getString(R.string.hello_world_name); String userName = "Bob"; // Insert the name in the format string String helloWorldName = String.format(helloFormatString, userName); // Set text of the textview TextView helloTextView; helloTextView = (TextView)findViewById(R.id.hello_world_textview); helloTextView.setText(helloWorldName);
This shows the "Bonjour Bob!" string for an Android device with a locale that includes the French language. For all the other locales the "Hello Bob!" string is shown.
2. Localizing Dates and Times
If the strings of your application are already localized, your application is already in pretty good shape. However, you may need to show dates and times to the user in many cases. Those dates and times should also be adapted to the current locale of the device. Fortunately, the Android SDK includes classes that format dates and times according to the locale.
In the Android SDK, dates and times are managed by the
java.util namespace. The current date and time of the device is returned by the
Dates can be formatted using an instance of the
DateFormat formatter from the
java.text namespace. You must use the
DateFormat class from the Android SDK in the
android.text.format namespace to get the right formatter for the locale of the device. The following code snippet shows how to get a string with the current date formatted for the device's locale:
// Gets the current date and time Date currentDate = Calendar.getInstance().getTime(); // Gets the standard date formatter for the current locale of // the device java.text.DateFormat dateFormat; dateFormat = android.text.format.DateFormat.getDateFormat(this); // Formats the current date according to the locale String formattedCurrentDate = dateFormat.format(currentDate);
If the current locale of the device is English as spoken in the United States, the string will contain the current date in a short date format, 11/30/2014. The
DateFormat class includes a few other date formats. For example, the
getLongDateFormat method returns a long date format, Sunday, November 30, 2014.
Since times are represented as
Date objects by the Android SDK, they must also be displayed using a formatter returned by the
DateFormat class from the
android.text.format namespace. The
getTimeFormat method returns a format that only displays the time of a
Date object. The following code snippet show how to get a string with the current time formatted for the device's locale:
// Gets the current date and time java.util.Date currentDate = Calendar.getInstance().getTime(); // Gets a date formatter for the current locale of the device // that shows times. java.text.DateFormat timeFormat; timeFormat = android.text.format.DateFormat.getTimeFormat(this); // Formats the current time according to the locale String formattedTime = timeFormat.format(currentDate);
If the current locale of the device is English as spoken in the United States, the string will contain the current time in the following format, 8:15 PM.
It's important to only localize the strings that are used in the application's user interface. For example, there's no need to localize debug messages that are only used during development or for diagnostic purposes. Also note that you shouldn't write localized dates and times to disk or to a database. Not only can the locale of a device change, working with localized dates and times makes development unnecessarily difficult and complex.