This article shows a few tricks which can help you when developing string resources for Android applications.
How can percents make code sick?
By default, string resources are so-called formatted. This means that they can be potentially used for formatting. Here is a simple example:
Lint performs checks on formatted strings and will complain if it encounters a string like this:
%d of %d left. The error message in such case is Multiple substitutions specified in non-positional format; did you mean to add the formatted=”false” attribute?.
One may think that adding the
formatted="false" attribute is the proper solution (in fact, there is no other direct suggestions on how to repair this issue). If you add the suggested attribute, the lint error will disappear. However, the correct fix in such cases is to make the format positional. In this example, it would be
%1$d of %2$d left.
On the other hand,
formatted="false" is intended for strings where percent signs are not parts of any format specifiers, e.g.
The secret ingredient
Assume that you are developing an app for local market only and there is no need for English texts. The default translation (located in
values directory) will be in the most common language in the given area e.g. Polish in Poland or German in Switzerland. Since there is no locale qualifier in a directory name, English is assumed. This leads to several problems. Firstly, Android Studio spellchecker will complain about most of the words.
Moreover, lint may detect some words as common misspellings and produce warnings as a result. For example, word adres is correct in Polish but is a common misspelling for English address. Here are the quick fixes suggested by Android Studio:
Unfortunately, the best one is not on the list. Note that adding
tools:ignore="Typos" attribute to each tag works but it is quite cumbersome and, thus, not the best solution.
tools:locale attribute is what can really help. It tells the tools what language is used inside a file. You can add it to the
resources tag like this:
Keep in mind that this is used only by Android Studio spellchecker and lint. It won’t affect any behaviour at runtime! This is especially true in some areas – it won’t change plural rules, for instance. What does this mean in practice?
Let’s consider the same plural resource with the number of songs from the linked official documentation, but with Polish used as a default translation (located in
values directory) and without English at all. Note that the current version of lint will complain about missing
many quantity, but we’ll come back to this in the next chapter. Here is the snippet:
For example, if the language of the device is set to Polish and the actual number of songs is 5, the resulting text is
Znaleziono 5 piosenek. because 5 in Polish belongs to the
many quantity. However, in other languages, the same number may be mapped to different quantities. Take a look at the table below:
CLDR cardinal integer chart fragment. Full version can be found on unicode.org
For example, if the language is set to Lithuanian, we’ll get
Znaleziono 5 piosenki., which is incorrect in Polish. However, if a device is running Android 7 or newer (API 24+) and you specify
resConfigs 'pl' (see DSL documentation for more information). Then the
other quantity will be used in case of locales unsupported by the app. Here is a modified sample plural including this quantity:
Why are inserts sexy?
Let’s say that you have to repeat some text in a few places, e.g. some screen name is used as a label on a list and as a title on that screen itself. Of course, you can just copy and paste them but this is quite inconvenient. In the case of text changes, you have to remember to update it in several places. However, there is a better solution. You can just reference already existing strings, like this:
Entities to the rescue
What about cases where only part of the text is repeated? For example, the application name is used inside several texts. Well, we can create a custom internal XML entity for that. Then, it can used just like standard character entities (
& etc.). Look at the following example:
To translate or not to translate?
Some texts are not meant to be translated. For example, the author’s or application name and other proper names. If you only provide default translations for some strings, omitting them in language-specific files, lint will complain about missing translations. Of course, you can suppress this error but, fortunately, there is a cleaner solution.
translatable="false" attribute marks the given string as untranslatable. Such resources not only don’t require translations, but must not even have any. Translations of untranslatable text will cause the appropriate lint error. This feature is also supported by Android Studio’s Translation Editor. Here is an example of an untranslatable string:
The translatable attribute only works on a single string level. If you have a lot of them, you can group them into one file called
donottranslate.xml. Lint will treat all of them as untranslatable.
Also published on Medium.