Android strings xml format specification in Respresso

One of the localization formats that Respresso supports is the commonly used xml used on Android. You can read the Android developers docs page about string resources to learn more about the format.

Currently, Respresso supports only the single string value with proper handling of special characters and full support of variables. Arrays and plurals are not yet supported, but they are hopefully coming soon.

As Respresso is a platform-independent resource management solution, we have no plans to support Android only features like spannables or annotations.

About the format

Android uses multiple resource files in different values folders that can specify a variety of qualifiers that define when should the app use the resources found in that folder. Although it is a bad practice, the format allows you to mix all kind of resources (like localizations, colors, dimensions etc.) in a single file.

There is an example how a single strings xml should look like:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="localization_key">localization value</string>
    <!--Other string resources-->
</resources>

Requirements of a strings xml:

  • Starts with a proper XML declaration. (Like <?xml version="1.0" encoding="utf-8"?>.)
  • The root node must be resources. (Make sure that it is opened and also closed.)
  • Contains some string elements in the root resources node.
  • Optionally, it can contain other resource elements and comments, but they might be ignored by Respresso.

Requirements of the string element:

  • Has a name attribute.
  • Contains some text or CDATA.
  • Optionally, the translatable attribute is also parsed.

How Respresso imports it?

Currently, Respresso can import a single xml file at a time. This is why you have to import it to a preselected language.

When you import an Android resource xml that contains string resources, the following parts will be imported:

  • The name attribute will be used as a localization key. (It is treated as an id, so it is used to track updates. See import merging strategy.)
  • The content will be unescaped/decoded and imported as the localization value for the selected language.
  • If you selected to import variables, Respresso will parse any printf based variables from the imported localization value and register them with a generated name, similar to var_1.
  • If the translatable attribute is present and set to false, then the resource is ignored.
  • If there is a comment before a string resource element, then it will be imported as a comment. (Except if it contains xml code.)

How Respresso generates it?

Respresso will generate a single xml file for each localization language you add. Optionally, it can output one more for the default language.

Let's assume that you have 3 languages registered in Respresso:

By default, Respresso will generate the following files:

  • res/values/respresso.strings.xml (Containing the en localizations)
  • res/values-fr/respresso.strings.xml (Containing the fr localizations)
  • res/values-en-rGB/respresso.strings.xml (Containing the en-gb localizations)
  • Optionally, you can configure it to get an xml file at res/values-en/respresso.strings.xml. (Containing the en localizations)

The last one can be configured in the Flow. See the exportDefaultAsIndividualLanguage option in Flow docs.

The generated files will contain the following:

  • A single string element for each localization key.
  • The name attribute will contain the transformed localization key. (This ensures key validity.)
  • Properly escaped localization value in the element's content.
  • The localization value will contain transformed localization variable placeholder for each registered variable it contains. (In case it contains multiple variables without attribute indexes the computed argument indexes are automatically included.)
  • If there are registered variables a comment will be placed before the string element containing the original name and formatting of the variables.

Let's assume you have a single localization with two registered variables in Respresso:
mainScreen.accountBalance: Current balance: {{ balance }} ({{ currency }})

It will output a file like this one:

<?xml version='1.0' encoding='UTF-8'?>
<resources>
  <!--VARIABLES: balance | %'3.2f; currency | %s-->
  <string name="main_screen_account_balance">Current balance: %1$,3.2f (%2$s)</string>
</resources>

Notice:

  • The key is transformed to avoid build time errors: camelCase is converted to snake_case, while the . is transformed to _
  • The original %'3.2f variable format is transformed to the Android specific variant with forced argument indexing: %1$,3.2f