Internationalization and localization (I18N and L10N)

To test a device for localization, the device or the emulator can be rebooted in a particular locale by using adb as follows :

  1. Run adb using the command : adb shell
  2. Run the following command at the adb command prompt : setprop persist.sys.locale [BCP-47 language tag];stop;sleep 5;start where [BCP-47 language tag] is the language specific code as described here : BCP47 codes

e.g. to check Japanese localization in the app, use the command : setprop persist.sys.locale ja-JP;stop;sleep 5;start

Internationalization (i18n) and Localization (L10n) are used to adapt software according to differences in languages, regional differences and target audience.

Internationalization : the process of planning for future localization i.e. making the software design flexible to an extent that it can adjust and adapt to future localization efforts.

Localization : the process of adapting the software to a particular region/country/market (locale).

Planning for localization : enable RTL support in Manifest

RTL (Right-to-left) support is an essential part in planning for i18n and L10n. Unlike English language which is written from left to right, many languages like Arabic, Japanese, Hebrew, etc. are written from right to left. To appeal to a more global audience, it is a good idea to plan your layouts to support these language from the very beginning of the project, so that adding localization is easier later on.

RTL support can be enabled in an Android app by adding the supportsRtl tag in the AndroidManifest, like so :

<application
    ...
    android:supportsRtl="true"
    ...>
...
</application>

Planning for localization : Add RTL support in Layouts

Starting SDK 17 (Android 4.2), RTL support was added in Android layouts and is an essential part of localization. Going forward, the left/right notation in layouts should be replaced by start/end notation. If, however, your project has a minSdk value less than 17, then both left/right and start/end notation should be used in layouts.

For relative layouts, alignParentStart and alignParentEnd should be used, like so:

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"/>
</RelativeLayout>

For specifying gravity and layout gravity, similar notation should be used, like so :

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="left|start"
        android:gravity="left|start"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="right|end"
        android:gravity="right|end"/>

Paddings and margins should also be specified accordingly, like so :

<include layout="@layout/notification"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_marginLeft="12dp"
    android:layout_marginStart="12dp"
    android:paddingLeft="128dp"
    android:paddingStart="128dp"
    android:layout_toLeftOf="@id/cancel_action"
    android:layout_toStartOf="@id/cancel_action"/>
<include layout="@layout/notification2"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_marginRight="12dp"
    android:layout_marginEnd="12dp"
    android:paddingRight="128dp"
    android:paddingEnd="128dp"
    android:layout_toRightOf="@id/cancel_action"
    android:layout_toEndOf="@id/cancel_action"/>

Planning for localization : Test layouts for RTL

To test if the layouts that have been created are RTL compatible, do the following :

Go to Settings -> Developer options -> Drawing -> Force RTL layout direction

Enabling this option would force the device to use RTL locales and you can easily verify all parts of the app for RTL support. Note that you don't need to actually add any new locales/ language support up till this point.

Coding for Localization : Creating default strings and resources

The first step for coding for localization is to create default resources. This step is so implicit that many developers do not even think about it. However, creating default resources is important because if the device runs on an unsupported locale, it would load all of its resources from the default folders. If even one of the resources is missing from the default folders, the app would simply crash.

The default set of strings should be put in the following folder at the specified location:

res/values/strings.xml 

This file should contain the strings in the language that majority users of the app are expected to speak.

Also, default resources for the app should be placed at the following folders and locations :

res/drawable/
res/layout/

If your app requires folders like anim, or xml, the default resources should be added to the following folders and locations:

res/anim/
res/xml/
res/raw/

Coding for localization : Providing alternative strings

To provide translations in other languages (locales), we need to create a strings.xml in a separate folder by the following convention :

res/values-<locale>/strings.xml

An example for the same is given below:

In this example, we have default English strings in the file res/values/strings.xml, French translations are provided in the folder res/values-fr/strings.xml and Japanese translations are provided in the folder res/values-ja/strings.xml

Other translations for other locales can similarly be added to the app.

A complete list of locale codes can be found here : ISO 639 codes

Non-translatable Strings:

Your project may have certain strings that are not to be translated. Strings which are used as keys for SharedPreferences or strings which are used as symbols, fall in this category. These strings should be stored only in the default strings.xml and should be marked with a translatable="false" attribute. e.g.

<string name="pref_widget_display_label_hot">Hot News</string>
<string name="pref_widget_display_key" translatable="false">widget_display</string>
<string name="pref_widget_display_hot" translatable="false">0</string>

This attribute is important because translations are often carried out by professionals who are bilingual. This would allow these persons involved in translations to identify strings which are not to be translated, thus saving time and money.

Coding for localization : Providing alternate layouts

Creating language specific layouts is often unnecessary if you have specified the correct start/end notation, as described in the earlier example. However, there may be situations where the defaults layouts may not work correctly for certain languages. Sometimes, left-to-right layouts may not translate for RTL languages. It is necessary to provide the correct layouts in such cases.

To provide complete optimization for RTL layouts, we can use entirely separate layout files using the ldrtl resource qualifier (ldrtl stands for layout-direction-right-to-left}). For example, we can save your default layout files in res/layout/ and our RTL optimized layouts in res/layout-ldrtl/.

The ldrtl qualifier is great for drawable resources, so that you can provide graphics that are oriented in the direction corresponding to the reading direction.

Here is a great post which describes the precedence of the ldrtl layouts : Language specific layouts