Documentation

Translations ($t)

Strings live once, in i18n/<locale>.toml. Everything Android wants — strings.xml per locale, plurals, escaping — is derived from them.

A string

// i18n/en.toml
[home]
title = "Trending"
greeting = "Hello, %s"
<Text>{$t("home.title")}</Text>
<Text>{$t("home.greeting", user.name)}</Text>

Arguments fill the % placeholders, in order. A % in a string with no arguments is literal.

Plurals

A table whose keys are CLDR quantities (zero, one, two, few, many, other) is a plural, and other is required:

[cart]
items = { one = "%d item", other = "%d items" }
<Text>{$t("cart.items", count = n)}</Text>

Call a plural with count =; call anything else without it. Getting that wrong is a build error, not a runtime surprise. count is not one of the positional arguments — it supplies the %d itself.

Checked at build time

Every key is checked when the app builds:

  • An unknown key is an error, with the nearest key suggested.
  • A key missing from one locale's file is a warning naming it.
  • A key nothing calls is a warning.

Debug builds also get Android's en-XA pseudo-locale: every character is accented (so a literal string that skipped $t stands out in plain English), the string is padded by the roughly 35% a real translation tends to grow, and the ends are bracketed so truncation shows. Turning it on:

# whitehall.toml
[i18n]
default = "en"
pseudo = true
$t works from a store or a worker as well as a screen, because it is backed by the application context rather than by a composition.

See Also

  • Text — the component these usually land in
  • Configuration — [i18n] in whitehall.toml