Introduction
Localization is the process of providing the appropriate resources for your app based on the device’s language settings.
If your app targets a specific locale, then localizing it might not be necessary. If it targets different regions speaking different languages, it might increase its reach and make it more usable to people speaking other languages.
Your application should provide text, audio files, numbers, currency, and graphics that are appropriate in the locales used.
In the Android hierarchy, resource files are placed in subdirectories of the res
folder. To qualify a resource to be used in a particular locale, you create additional directories inside res/
that include a hyphen and the ISO 639–1 language codes at the end of the directory name, optionally followed by a two letter ISO 3166–1-alpha–2 region code (preceded by lowercase ‘r’).
Including the region qualifier targets resources even more specifically. For example, instead of using ‘-es’ which is the language qualifier for Spanish, you might want to provide different resources for España (-es-rES) and Estados Unidos (-es-rUS), representing Spanish spoken in Spain and Latin America respectively.
When a user runs your application and the device’s language is set to a language you specified, the Android system will load that language’s resources.
An example of an application that supports english (as the default language) and french can be seen in the file hierarchy below.
MyApp/
src/
MainActivity.java
res/
drawable/
background.png
drawable-fr/
background.png
layout/
activity_main.xml
values/
strings.xml
values-fr/
strings.xml
You can provide language specific directories for any directory that is allowed in the res/
folder. Subdirectory names are tied to the Android build system, you cannot specify your own. Well, you can, and the application will run without errors, but any resources you include in that subdirectory will be ignored.
Resources must also be saved in a subdirectory of res
. If you save in the root directory, there will be build errors. For a list of supported res
subdirectories check the documentation.
The above example shows an application that has different strings
and background image files for French and English locales but shares the same layout file.
Since English is the default language the app supports, there is no need for including resources with the -en
extension.
Default Resources
You must provide default resources in your projects. These are the resources found under the unqualified resource directories e.g. drawable/
and values/
. It is important to provide default resources. If your app doesn’t find a resource that matches the devices’s configuration and there is no default resource to fall back on, it will crash.
In the above example hierarchy, you might be tempted to qualify all your resources and thus add the english qualifier to files meant for the English locales as shown below.
MyApp/
src/
MainActivity.java
res/
drawable-en/
background.png
drawable-fr/
background.png
layout/
activity_main.xml
values-en/
strings.xml
values-fr/
strings.xml
This isn’t a good idea. When the app is run on a device with a locale setting not supported, the app will crash.
Make sure that a default resource is defined for all resources. Your default string files should be complete. The localized files can be a subset of the default’s strings but the default must contain all of them.
This type of omission can go undetected especially since the IDE won’t highlight it and you will not see the problem if testing with a device or emulator that has the supported locales.
Testing for Default Resources
You should test your default resources to make sure that they are all made available in the default files.
To do this, simply change the locale of your device or emulator to a locale not supported by your app. If you run the app and get an error message and a Force Close button, then it might be looking for a resource that isn’t available in the default subdirectories.
Qualifier Priority
Since Android allows you to specify different resources to target different scenarios of device use, sometimes the configuration you use might match more than one alternative resource.
Qualifiers have different priorities which are used to determine the resource loaded. The priority is based on the order shown below.
- MCC (mobile country code) and MNC (mobile network code)
- Language and region
- Layout Direction
- Smallest Width
- Available width
- Available height
- Screen size
- Screen aspect
- Screen orientation
- UI mode
- Night mode
- Screen pixel density (dpi)
- Touchscreen type
- Keyboard availability
- Primary text input method
- Navigation key availability
- Primary non-touch navigation method
- Platform Version (API level)
As an example, consider the hierarchy of the application below
MyApp/
src/
MainActivity.java
res/
values/
strings.xml
values-fr/
strings.xml
values-land
strings.xml
The application has alternative resources for French locale and for landscape mode. If the user has France as their locale and switches their phone to landscape mode, since language has precedence over screen orientation, the res/values-fr/strings.xml
file is loaded and not the landscape specific file in res/values-land/strings.xml
.
Understanding the precedence rules can save you time debugging, wondering why a resource isn’t loaded when you think it should.
For more on how Android finds the best matching resource, look at the documentation.
Using Multiple Qualifiers
You can specify more than one qualifier for a resource directory. This can come in handy in cases such as the above example where you might want to use resources that fit more than one scenario.
In the above example, the default version of the app has a different resource file for landscape mode. But when landscape mode is entered in the french locale, there is no french-and-landscape resource.
The language qualifier takes precedence over the screen orientation qualifier and therefore the system will not take into consideration the string values in values-land
.
You can add french-and-landscape resource with values-fr-land
. When using multiple qualifiers on directories, you must put them in the order of their precedence otherwise the resources will be ignored. values-land-fr
is not a valid directory name.
Things to Note
-
Keep in mind that different languages have different length words and sentences, some languages read top to bottom, others back to front. Translating string literals alone might not be enough to localize an app. You should consider these language differences when working on your layouts. You could create different layouts for each language that requires a different display. However, this makes your application harder to maintain. Whenever possible, it is better to use fragments to create dynamic and flexible user interfaces.
-
If your app uses custom fonts, you should have a fallback plan for foreign characters that the font family doesn’t support.
-
Don’t hard code resources. Don’t use string literals in your code, instead use
R.string
to access the strings in yourstrings.xml
file. Don’t use image paths in your code, instead useR.drawable
. Not only does this make maintenance easier, it also makes localizing your app easier and less prone to bugs. -
You cannot create additional subdirectories in
res
. This restriction can make sorting through resource files difficult, especially for large projects where it might have been better to organize the numerous files into subdirectories. What you can do is decide on a file naming convention that suits you and your organisation so that sorting through and finding particular files is easier. -
Avoid creating more resource files than you need to. If there are some common resources, then they should be shared between locales. For example in
strings.xml
, you might have some common strings that you don’t want translated like the app title. For these types of shared resources, leave them in your default directory and don’t copy them in your specific directories. -
Localization is pretty much handled by the Android system but you might want to change something in code according to the user locale. To get the locale, use the
Context
object.String locale = context.getResources().getConfiguration().locale.getDisplayName();
Conclusion
Localizing your app might greatly expand your app’s market. It is particularly important in countries where there could be a large opportunity and English (or your app’s default language) isn’t widely used. You should undertake research of your target market, identify the languages you want to include and build for them.
If you are going to build an app that will support different locales and languages, it is worth a check through the Android Localization Checklist before releasing it to make sure that everything is in order.
I am a web developer who dabbles in mobile development from time to time. You can find me on Twitter @joyceechessa to see what I’m up to.