Translate YAML locale files, Rails style
A Rails-style YAML file starts with the language code and nests everything under it, and its strings hold %{name} variables. KAERIS translates the values, rewrites the root key for the target language and checks that every variable came through.
How a YAML locale file is built
The first line is the locale (en:); every key lives under it. Plural forms are plain keys such as one and other. Lists are supported. A file that is one flat mapping without a root locale is also read, and its dotted keys stay as written.
en: greeting: "Welcome back, %{name}!" inbox: one: "%{count} new message" other: "%{count} new messages" errors: blank: "can't be blank" too_short: "is too short (minimum is %{count} characters)" checkout: total: "Total: <strong>%{amount}</strong>"
What to watch for in YAML translations
The root key follows the file
en:has to becomede:in the German file or Rails never finds it. KAERIS writes the target language as the root.%{variables} and HTML
Rails interpolation is
%{name}; some projects use{{name}}. Both are compared with the source. Inline tags like<strong>are checked the same way.Quoting
A translated value that starts with
[,*or&, or contains:, is not valid YAML unless quoted. The writer decides on quotes itself: in the example output a value starting with%{count}comes back quoted.Comments do not travel
YAML comments in the source are not carried into the translated file. Keep notes for translators in service keys (a key starting with
_is left untranslated) or in your repository.
A real run: translated to German and checked
A real run, 27 October 2026, nothing edited by hand: kaeris translate en.yml --langs de with kaeris 0.2.35, 3 seconds, model google/gemini-2.5-flash-lite, the free-tier default. Below, the German file it wrote and what kaeris check says about it.
de: greeting: Willkommen zurück, %{name}! inbox: one: '%{count} neue Nachricht' other: '%{count} neue Nachrichten' errors: blank: darf nicht leer sein too_short: ist zu kurz (mindestens %{count} Zeichen) checkout: total: 'Gesamt: <strong>%{amount}</strong>'
$ kaeris check --source en.yml --langs de ✓ de: complete & placeholder-safe ✓ all locales complete & placeholder-safe
What KAERIS does with it
Structure kept
Nesting, key order and lists come back the same; the root locale key is rewritten for each language.
Variables and tags checked
A lost
%{name}or<strong>is found by counting, with no model involved.Free check for this format
The free check on /check reads this format and runs without a key or an account. The terminal command
kaeris checkreads it too: it takes all 13 formats since kaeris 0.2.35, with the same rules and nothing sent anywhere.
Run it in three steps
Install the CLI
Run
pip install kaeris.Translate the file
Run
kaeris translate config/locales/en.yml --langs de,ja. Output files are named by language.Check the result
Upload the source and the translated file on the free check page; it lists lost variables, tags and missing keys.
pip install kaeris kaeris translate config/locales/en.yml --langs de,ja --verify
Questions
Does it work for Rails en.yml?
Yes. The root en: key, nested keys and %{name} variables are handled. See also the Rails page.
What about comments in my YAML?
They stay in your source file. The translated file is written without them.
Is it free?
Yes, without an account: 10,000 characters per file and up to 8 languages per run. A free API key raises the file limit to 50,000 characters. Lifetime is $79 once, on your own OpenRouter key; monthly plans start at $19. Pricing
Can I run it from the terminal or in CI?
Yes. pip install kaeris, then kaeris translate config/locales/en.yml --langs de,ja. The GitHub Action runs the same translation in a pull request. CLI docs · GitHub Action
Keep going
CLI reference · Check reference · Translate in the browser · Free check · Convert formats · Pseudo-localization
Other formats: JSON · .po · ARB · XLIFF · .strings · .xcstrings · .properties · .resx · CSV · Markdown · Fluent · Android XML