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.