Localization is an important topic to me; there's no faster way to expand your audience than include the entire rest of the world!

A few months ago I wrote about how to setup your strings. That's only half the battle - it can be surprisingly difficult to remember to cover all the cases where you should be using localized strings! The lint checks do not (and in some cases, cannot) cover every case.

Lint

Here's a couple obvious ones in XML that will be caught by Android lint's "hardcoded text" test:

android:text

android:hint

android:contentDescription

Just make sure to link a string definition for each and you'll be fine.

Not found by lint

There's also a couple less obvious places that lint currently does not check:

android:label - Applies to both your application name and Activity labels in AndroidManifest.xml.

<string-array> - String arrays should be composed of strings references so that the array is just an arrangement of the data: <string-array name="underwear"> <item>@string/boxers</item> <item>@string/briefs</item> <item>@string/commando</item> </string-array> This way you can change the ordering of the strings without having to go into each translation file and re-order them there as well.

<plurals> - Each quantity in your quantity strings should be localized. In addition, you should make sure to define the proper quantities for each translation: <plurals name="cats"> <item quantity="one">One Cat</item> <item quantity="other">%d Cats</item> </plurals>

android:imeActionLabel - Customized IME actions are rare, but need to be localized as well.

Setting text in code

By far the most difficult cases to diagnose will be whenever you're setting text in code. There's no possible automated check; here's what you should investigate:

TextView.setText()

TextView.setHint()

TextView.setImeActionLabel()

View.setContentDescription()

AlertDialog.Builder.setTitle()

AlertDialog.Builder.setMessage()

This list should look familiar - most are dynamic versions of the XML definitions above. Whenever possible you should use a resId (e.g. R.string.help ). Otherwise make sure that the source CharSequence will function in all languages.

One common mistake people make is to compose strings together and set them at runtime:

textView.setText(name1 + " and " + name2 + " are going shopping!");

Not every language has the same grammatical structure! As a simple example, check out these date formats, which vary dramatically between different locales. Simply concatenating the month, day, then year won't cut it!

If you are concatenating strings before putting them into a TextView, I would evaluate whether this is the proper strategy. A better tactic is to use formatted strings, which allows translators to move around arguments as they make sense in their own language.

Placeholder Strings

One other thing - if you want to put a placeholder string into your XML during development, use designtime layout attributes! If you add xmlns:tools="http://schemas.android.com/tools" to your layout, you can then take any attribute that would normally start with "android" and replace it with "tools" and it'll only show up in the design tools:

<TextView android:id="@+id/date_time" android:layout_width="wrap_content" android:layout_height="wrap_content" tools:text="June 25, 5:00 PM" />