Android Localization Tips
I've been interested in localization on Android recently. There's a few neat things I've been experimenting with I thought I'd share.
xliff:g
One common problem when sending strings for translation is that some parts of a string should not be localized. For example, suppose I've got this string:
<string name="hello">Hello, %s!</string>
I don't want %s
to be touched by any translator - it might break my code! You can use xliff:g to indicate to translators not to translate a string:
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="hello">Hello, <xliff:g id="name">%s</xliff:g>!</string>
</resources
As an added bonus, you can specify an "example" parameter.
<string name="hello">Hello, <xliff:g id="name" example="Dan Lew">%s</xliff:g>!</string>
If you do that, your code in Android Studio will automatically fold:
R.string.hello --> "Hello, (Dan Lew)!"
Phrase
Phrase is a small library from Square that makes localization clearer. One problem with localization is that the formatting strings (%1$s
, %2$d
, etc.) are difficult to interpret (as both a developer and a translator). Wouldn't it be easier to use plain English?
With Phrase, you can turn my previous example into something more readable:
<string name="hello">Hello, {name}!</string>
Then in code you format the string by keyword instead of by position:
Phrase.from(context, R.string.hello)
.put("name", "Dan Lew")
.format();
If you've ever dealt with strings with more than one positional parameter you'll quickly realize why this is helpful.
Another reason I like Phrase is because it handles HTML in strings well. Without it you have to escape your HTML and then later call Html.fromHtml()
, which is ugly. With Phrase you can skip all of that, just using plain HTML in your strings:
<string name="hello">Hello, <b>{name}</b>!</string>
pseudolocalization
Edit April 6, 2015: The pseudolocalization information below is out-of-date. Please refer to this article for the latest information.
In Android 4.3, they added a new locale, "Accented English" (identifier zz_ZZ). The advantange of enabling this locale is finding potential problems with your app - either its inability to handle weird characters or simply finding unlocalized strings.
aapt supports generating a pseudolocalized version of your strings automatically. From the command-line, you can call aapt -c zz_ZZ
and it'll generate accented English automatically. For gradle builds, you use resConfig
:
defaultConfig {
resConfig "zz_ZZ"
}
If you're like me, you'll only want test translations generated on debug builds:
android.applicationVariants.all { variant ->
if (variant.buildType.isDebuggable()) {
variant.mergedFlavor.addResourceConfiguration("zz_ZZ")
}
}
Watch out - the pseudolocalizer doesn't know which parts of the string to localize and which not. Good thing we just learned about xliff:g! Just make sure to wrap your format parameters (or anything else you don't want changed, like URLs) with xliff:g tags and they won't be touched by the pseudolocalization tool.
Here's my final string, ready for translation, Phrase and pseudolocalization:
<string name="hello">Hello, <xliff:g id="name" example="Dan Lew">{name}</xliff:g>!</string>
It may seem like a lot, but trust me - when it comes to localization, you want to help your translators as much as possible so you can get a high-quality, accurate depiction of your app in other locales.