Build Tolgee Cloud
KINDAreplaces $56.52/mosaves $678.24/yrback to the verdict
A localisation workspace whose two real problems are that plural and gender rules differ enormously between languages, and that a source string edited in English silently leaves twenty translations describing something else until someone notices in production.
Before step 1
Everything below is assumed from the first step. Tick each one when you actually have it, not when you plan to.
- installfree
Why Runs the server and the bundle publisher.
Get it nodejs.org, or nvm install 22. open ↗
Verify
node --version prints v22 or higher - installfree locally
Why Keys, versions and staleness relationships.
Get it Docker or your package manager. open ↗
Verify
psql connects and creates a table - have readyfree
Why Designing around English gives two forms, and several languages need four to six, which cannot be retrofitted without revisiting every plural string.
Get it Take the plural rules from the standard locale data for every language you intend to support, including at least one with more than two categories.
Verify
Category lists exist per locale and at least one locale has four or more - have readyfree
Why Placeholder reordering, plural complexity and length constraints all only appear when the targets are genuinely different from the source.
Get it Choose targets that differ structurally, including one with more plural categories and one substantially longer than English.
Verify
Four locales are configured, one with four or more plural forms - have readyfree
Why Context problems, length constraints and unused keys only become visible against a real codebase with a few hundred keys and some accumulated cruft.
Get it Export the strings from an application you actually work on, including the keys nobody is sure are still used.
Verify
At least three hundred keys are imported with their code locations
Data model
Create these before the first phase that stores anything. Changing a table later is the expensive kind of change.
- keys(id, namespace, name, description, screenshot_path, max_length, created_at, deprecated_at) - source_strings(key_id, text, plural_forms_json, version, updated_at) · the source of truth - translations(id, key_id, locale, text, plural_forms_json, source_version, state, translated_by, at) - state · current, stale, missing or needs_review. Stale means the source moved after this was written - locales(code, plural_categories_json, direction, fallback_locale) - bundles(id, locale, version, content_hash, published_at) · immutable, so a client fetches a consistent set - usages(key_id, file, line, last_seen_at) · so an unused key can be found and removed - A translation records the source version it was made from, which is the whole mechanism for detecting staleness.
Environment variables
These go in a .env file the app reads at startup. The pack's .env.example is this table as a file · copy it, never commit the filled-in version.
| Variable | Needed | Example | Where the value comes from |
|---|---|---|---|
DATABASE_URLsecret | required | postgres://localhost:5432/i18n | Keys, translations and version history. |
SOURCE_LOCALE | required | en | The source of truth. Edits to it mark other locales stale. |
FALLBACK_CHAIN | required | regional,base,source | Documented, and never resulting in an empty string. |
SERVE_STALE_TRANSLATIONS | required | always | A stale translation beats an English string in a French interface. |
BUNDLE_CDN_URL | required | https://i18n.example.com/bundles | Where immutable bundles are served from. |
REQUIRE_KEY_CONTEXT | required | warn | Whether a context-free key blocks or warns. A bare word is ambiguous. |
The build, in order
Messages that survive being translated
A string can be translated into a language that orders words differently.
Positional ones swap values in languages that reorder.
Files
src/messages.tsA pure function, unit tested with a dropped and an invented placeholder.
Files
src/validate.tssrc/validate.test.tsA missing placeholder is a runtime error in someone's language.
Files
src/translations.ts
done when · tick each as it passeswatch out- Positional placeholders assume the target language keeps the same word order, which many do not, so a sentence with two substitutions comes out with the values swapped and nobody testing in English ever sees it. Use named placeholders and validate the set matches between source and translation.
Plurals in languages that are not English
Every locale gets exactly the plural forms its language requires.
From the standard data, not from an assumption about English.
Files
src/locales.tsTwo forms is an English answer to a general question.
Files
src/plurals.tssrc/plurals.test.tsTested across a range of numbers per locale, against expected output.
Files
src/select.ts
done when · tick each as it passeswatch out- Designing the plural model around English gives you two forms, and then Arabic needs six and Russian and Polish need four, so the translations for those languages are either wrong or impossible to express. Model the categories per locale from the outset, since retrofitting means revisiting every plural string in every language.
A changed source invalidates its translations
Editing English marks the other twenty languages as stale.
The mechanism the whole phase rests on.
Files
src/versions.tsInvalidating on every edit gets the feature turned off.
Files
src/edits.tsA stale translation beats an English string in a French interface.
Files
src/serve.ts
done when · tick each as it passeswatch out- Treating every source edit as invalidating everything means fixing a typo sends twenty languages back for retranslation, and the team turns the feature off within a month. Let the editor mark a change as not affecting meaning, record who said so, and keep the invalidation for changes that actually alter what the string says.
Context, because a word is not a sentence
A translator can see where a string appears and how much room it has.
A bare word is ambiguous in ways English speakers do not notice.
Files
src/keys.tsSo unused keys can be removed and context can be found.
Files
src/usage.tsGerman is longer. The button is not.
Files
src/constraints.ts
done when · tick each as it passeswatch out- A translator handed a bare word with no context cannot tell whether it is a noun or a verb, and English is full of words that are both, which produces translations that are grammatically correct and completely wrong. Attach context to the key, and treat a key without any as an incomplete key rather than a normal one.
Shipping translations without shipping codeproduct builder
A locale updates atomically and a client never sees a half-updated bundle.
So a client is never half updated.
Files
src/bundles.tsRegional to base to source. Never an empty string.
Files
src/fallback.tsA bad translation shipped is fixed by pointing at the previous version.
Files
src/publish.ts
done when · tick each as it passeswatch out- Serving translations key by key from a live database means a client can fetch half its strings before a publish and half after, producing an interface in two states, and the bug is unreproducible. Publish immutable bundles and let clients move between whole versions.
That is the whole plan for Tolgee Cloud. What it deliberately does not cover is below · check the gaps before you call it a replacement.
- Machine translation quality.
- Translator marketplace and vendor management.
- Right-to-left layout handling.
- Professional translation memory and terminology.
- managed hosting, backups, collaboration, machine translation, and support
- professional translator marketplace
- advanced translation memory
- website proxy network
- enterprise workflows and integrations
- In-context editing on a running application, which is the fastest way to catch bad context
- Machine translation as a first pass for post-editing, which is where it genuinely helps
- Length warnings driven by rendered width rather than character count
Need the files? The project pack on the verdict page hands your agent the whole brief · more localization.