Skip to main content

Translation tracking

A missing translation is easy to spot: nothing is there. An outdated one is not: the string is present, reads fine, and no longer says what the source says. Nothing in the files tells it apart from an up-to-date translation.

With a sourceLocale, Hermes records, for every translated key, a fingerprint of the source string it was translated from. When the source changes, every language that had translated it is flagged.

hermes.config.js
export default {
sourceLocale: 'fr',
completeLocales: ['en-US', 'de', 'es-ES'],
};

completeLocales lists the languages expected to hold every key (all of them by default). The others are treated as deliberately partial: they are never reported as missing a key. Tracking still applies to them: a partial language that translated a string is told when that string changes.

Commands​

hermes todo <locale> # what a language still needs, as JSON
hermes lock [locales...] # baseline a project or a new language (all by default)
hermes lock <locale> --keys a,b # accept a source edit on specific keys
hermes check # same checks as the build, with an exit code for CI

hermes build reports the same findings as warnings, outdated ones first: a missing translation visibly falls back to another language, while an outdated one is served as if it were current.

hermes todo gives, for each outdated entry, both the new source and the current translation, since a retouch is cheaper than a rewrite.

The lock file​

Fingerprints are stored in <localesDir>/.hermes-lock.json, which belongs in version control. Each entry holds two fingerprints, source:target: what the translation was made from, and the translation itself.

locales/.hermes-lock.json
{"de": {"settings:antiraid.closeDm": "a1b2c3d4e5f6:9876543210ab"}}

The second fingerprint lets the build tell a regression from a fix:

  • the source changed, the translation did not: nobody has answered yet, the key stays flagged;
  • both changed: someone answered, and hermes build refreshes the entry on its own.

So a translation pass needs no extra command. Commit the refreshed lock file along with the translations. hermes check reads it as committed and never writes: a forgotten lock fails CI instead of passing silently.

When to use hermes lock​

hermes lock serves two purposes:

  • baselining a project or a new language the first time. The build only refreshes languages the lock already covers: automatically locking an unlocked project would mark everything as current on the first build, stale translations included, and nothing would ever be flagged again;
  • accepting a source edit without retranslating. A cosmetic source fix (a typo, an accent) flags every language, which is usually right since they may need the same fix. When it is not, hermes lock <locale> --keys <keys> accepts the change on those keys only.