Getting started

Overview

locallingo extends i18n-tasks with AI translation, source-hash drift detection, and quality linting — driven entirely by a single config file, with a subcommand CLI and shipped RuboCop cops.

One toolchain, every app#

The whole point.

Most Rails apps grow the same bin/translate script: a wrapper around i18n-tasks that calls an LLM to fill in missing translations, tracks what changed, and lints the results. Copied between apps, it forks — bug fixes and features drift instead of compounding.

locallingo is that script, extracted into a gem. Everything app-specific — target locales, provider and model, prompt context and glossary, per-language style guides, which validators and quality rules run, and post-translate hooks — lives in a .locallingo.yml file, with a default block plus optional per-package overrides. The behaviour is the same in every app; only the config differs.

locallingo sits on top of i18n-tasks, which it shells out to for normalization. It reads and writes the same flat config/locales/<namespace>.<locale>.yml files your app already uses.

What you get#

  • AI translation — translate missing and changed keys through RubyLLM: OpenAI, Anthropic, Google, and more, chosen by config. Only the keys that actually changed.
  • Drift detection — a per-key source hash records the English value a translation was made from, so a later edit to the source marks every locale's copy outdated instead of letting it silently go stale.
  • CI validationlingo validate --strict fails on missing and outdated keys; --strict-all adds duplicate-value and (optional) manual-edit checks.
  • Quality linting — regex rules, configurable terminology lists, optional British-spelling drift, and an optional AI review — with auto-fix for the fixable ones.
  • Multi-package — one default config plus per-package overrides, so an engine or gem can translate to its own locales with its own prompt.
  • RuboCop copsLocallingo/RelativeI18nKey (with autocorrect) and Locallingo/StrftimeInView, enforcing fully-qualified keys and locale-aware date formatting.

How it fits together#

You author English in config/locales/*.en.yml. locallingo hashes each source value into .i18n-state/, translates the missing/changed keys to your target locales through your configured provider, and merges the results back into the matching locale files. validate compares the current state against those hashes to report what's missing or outdated; quality lints the text; the RuboCop cops keep your t() calls fully-qualified.

The lingo CLI is the entry point; everything it does is also available programmatically through Locallingo::Manager and Locallingo::QualityChecker.

Where next#