With the launch of the Amazon Mobile App Distribution Portal for international distribution, we'd like to talk about how to get your Android apps ready for an international audience.
Localization is the process of making your app display appropriate resources depending on the device's default locale and language. "Appropriate Resources" can include more than text. Depending on your app, you may also want to change:
- Number and date formatting
- Currency formatting
- Colors and layout styles
- Input methods
Localization is a big topic, so we'll focus on those resources that impact customers the most: text, images, and currency.
Each Android device has a default locale which consists of a region and language, which you can query programmatically. Fortunately, this is seldom necessary. Since Android is designed to be used on a variety of platforms, it looks for resources that are appropriate for the current execution environment. For example, you may already provide different bitmaps or backgrounds for your app based on the device's pixel density. As long as the resources are in the right directory (e.g., drawable-hdpi), Android will select the best resource for the job.
Localization works the same way – by putting your resources in the correct folder, Android will find the right one at runtime, without you having to write additional code. The simplest example is one you are probably familiar with: /res/values/strings.xml. The strings.xml file is designed to hold your user-viewable strings in such a way that they can be used by reference. Here is a sample definition in strings.xml:
<?xml version="1.0" encoding="utf-8"?>
The string resource named "hello" can be referenced in your source code by calling:
String helloText = getString(R.id.hello);
And in other XML files (such as layout or the manifest) by referencing:
<application android:label="@string/hello" >
Now suppose you want to provide a better user experience for new customers who speak French or German. Simply create a new version of strings.xml for each language, and put them in their own "values" directory. The format is: values-xx-rYY, where 'xx' is the ISO-639 language code, and 'YY' is the ISO-3166-1 region code.
/values (default directory, make sure all references are present)
/values-fr (contains French language strings, region not used)
/values-de (contains German language strings, region not used)
When Android looks for a string reference, it will try to match a resource that is specific to a region and language, then by language, then in the default directory (values). It is extremely important to make sure all of your string references are in the default directory.
If Android fails to find a reference after searching the default directory, your program will force close!
Once the references are defined in the defaults, your language-specific files can define the strings you want to localize in that language. For example, some language speakers are comfortable with a mix of English and their native tongue, while others speakers expect a full translation.
Not all UI presentation is done using strings, and many apps have menus, price lists, or instructions written as bitmaps or other graphical data. Fortunately, the same dynamic resource handling we just saw with strings applies to resources in the drawable folders as well.
/drawable-fr (contains German language strings, region not used)
/drawable-de (contains German language strings, region not used)
If you already have several drawable directories with resources based on pixel density, you can further extend the structure to accommodate language. The resource directory name modifiers (locale, pixel density, screen size, screen orientation, etc.) can be chained together:
If you find yourself reusing drawable assets (putting duplicate copies of bitmaps in several folders, for example), Android provides a way to "link" a reference to a binary using an XML file in the drawable directory.
Suppose you want the resource named "background" in the Great Britain locale to point to a resource in the default drawable directory. Save the following file as "/drawable-en-rGB/background.xml":
<?xml version="1.0" encoding="utf-8"?>
Any reference to "background" that resolved to that directory (drawable-en-GB) would automatically use the resource: /drawable/background_common.
Lastly, we'll look at an example where we display the price of our IAP items in local format. The most important elements are the currency symbol, and the decimal divider:
€19,95 // in some European locales
$19.95 // in North America
Let's say your app uses the IAP API to fetch a price for an item from the regional store. The API will give you a price that you can parse to a float. Wouldn't it be nice to have an object that takes care of the number formatting for you? As it turns out, Android provides a NumberFormat object for this purpose.
To get the formatted String, make the following calls:
NumberFormat nf = NumberFormat.getCurrencyInstance(Locale.getDefault());
String formattedPrice = nf.format(19.99f);
This is formatting only, and does not do currency value conversion. If you decide to use a locale other than the default, make sure you define it using both language and region (e.g., en_US, or fr_FR). Otherwise you won't get the correct formatting. For example, there are many countries using French as their primary language and have different currencies.
As mentioned before, localization is a deep topic – we've barely scratched the surface. Check back for additional tips to improve the customer experience as you distribute your apps around the world.