inlang
A

Android Resources

Plugin

Reads and writes Android strings.xml files through Inlang's v2 message model.

Supported: exact message keys, XML escaping, positional string variables, and CLDR plural quantities (zero, one, two, few, many, other). Unsupported selector shapes and annotated expressions fail explicitly instead of being dropped.

Non-translatable resources (translatable="false", e.g. the app name, URLs or API keys) are not imported as messages, so they are never written to the files of other locales. A message of another locale with the name of a non-translatable resource of the base locale file (e.g. created in an editor) is not written either, unless the file of that locale has it already. Attributes such as tools:ignore, tools:locale or formatted="false" are accepted. formatted="false" strings and plurals are read as plain text, so a raw % (Save 50% on %s) works; their %s and %d are text, not placeholders, so editors and machine translation don't protect them. Non-translatable product variants (product="…" with translatable="false") are kept as they are. Resource names are unique per type, so a <string> and a <plurals> may share a name if at most one of them is translatable. Inline markup inside a string (e.g. <xliff:g> or <b>) and translatable product-specific strings (product="…") are not supported and fail explicitly. Removing a message whose name also has non-translatable product variants (e.g. product="tablet") leaves only those variants, which AAPT2 may reject without a default.

Plurals: Android formats every item of a plural with the arguments, so in a plural with placeholders (and without formatted="false") every item is a format string: %% is read as %, and a % in text is written %%. A % that isn't a placeholder (50% off) is read as text; a Java specifier the plugin doesn't support (%.1f, %02d, %x) fails explicitly. Plurals without placeholders are read as text as before.

Hosts that pass the existing files to the export (inlang SDK 4) keep everything the plugin doesn't import byte for byte (non-translatable resources, <string-array>s, comments, …), keep the attributes of edited elements, and write each file to its Android path (res/values/, res/values-de/). Hosts without the existing files (inlang SDK 3) get the whole-file export as before, which contains only the messages. If the plugin can't keep an existing file (e.g. it can't read it anymore) and writing the whole-file export would delete elements it doesn't import, the export fails with an error instead.

{
  "modules": [
    "https://cdn.jsdelivr.net/npm/@inlang/plugin-android@latest/dist/index.js"
  ],
  "plugin.inlang.android": {
    "pathPattern": "./res/values{locale}/strings.xml"
  }
}

{locale} expands to an Android resource qualifier: the base locale uses no suffix, de uses -de, pt-BR uses -pt-rBR (as Android Studio writes it), and locales with a script or a numeric region use BCP 47, e.g. zh-Hans uses -b+zh+Hans and es-419 uses -b+es+419. An existing values-b+pt+BR/ is read and written too, as are the legacy codes iw, in and ji of Hebrew, Indonesian and Yiddish (values-iw/); if both values-he/ and values-iw/ exist, values-he/ is read and written. The language is written lowercase. A locale with files in two spellings is rejected, because inlang writes all messages of a locale to one file.

Translation descriptions

On SDK hosts supporting bundle descriptions, a comment directly above a source-locale <string> or <plurals> maps to bundle.description when it belongs to that entry alone. Blank lines separate document headings; a comment above adjacent entries is treated as a group heading. Target-locale comments remain file metadata.

The shared editor writes descriptions as native XML comments in the source file, preserving document metadata when the existing files are available. Removing the attached source comment clears the description. Descriptions containing -- cannot be represented as XML comments and are rejected.

Change the base locale through a loaded project’s settings and save the project before reopening it. If editing baseLocale directly in settings.json, move shared guidance into the new source entries or project.inlang/descriptions.json in the same change. A fresh directory load cannot identify the former source locale and never promotes target-only notes automatically.