The Ultimate Guide to Organizing Translation Keys in Tolgee
·
...

Jan Cizmar
Founder & CEO

Translation keys are the foundation of any localization project. How you structure them with projects, namespaces, tags, and naming conventions determines whether your workflow scales smoothly or becomes painful to maintain. This guide covers every layer of key organization in Tolgee, with practical advice on when to use each tool and the mistakes that most commonly cause problems down the road.
When your localization project has 50 keys, the way you organize them doesn't matter much. When it has 5,000, it's the difference between a smooth workflow and a mess where nobody can find anything.
After years of building Tolgee and working with hundreds of teams, from startups with a single app to enterprises managing millions of translated strings, we've seen every possible approach to organizing translation keys. Some work well. Some create problems that only surface months later when they're painful to fix.
This guide covers everything. Projects, namespaces, tags, key naming, descriptions, and the common mistakes that trip up even experienced teams.
Projects. The top-level container
Every key in Tolgee lives in a project. You can't create a key outside of a project. This is the top-level container where all your settings, permissions, and configuration live.
For most teams, one project equals one app or one piece of software. If you have a product that runs on web, mobile, and desktop, it's natural to keep everything in a single project and reuse the keys across platforms. This is one of the core advantages of Tolgee being a key-based platform rather than a file-based one. You store a key once and export it in whatever format each platform needs.
When should I use multiple projects?
Sometimes different teams manage different platforms independently. In that case, separate projects can make sense. But you lose the ability to reuse keys across platforms, so think carefully before splitting.
The general rule: if the platforms share the same user-facing content, keep them in one project. If they're genuinely different products with different content, use separate projects.
Namespaces. Splitting your export into multiple files
Namespaces have one specific job: they split your exported translations into separate files. If you need your translations in common.json, settings.json, and dashboard.json instead of one big file, namespaces are how you do that. If you don't need multiple export files, you probably don't need namespaces at all.
This distinction matters because namespaces are easy to misread as a general organization tool, like folders. They're not. The platform has better tools for that. Namespaces are about the shape of your exported files.
What does a namespace look like in practice?
In the Tolgee platform, keys are displayed as namespace:key-name. A key called button.save in the common namespace appears as common:button.save. In your codebase, you reference both the namespace and the key name when fetching translations. This is also what you'll see in import/export file paths.
Namespaces are flat. There's one level only. You can't nest namespaces inside each other. If you're migrating from a file-based platform where you had nested folder structures like en/admin/settings.json, you'll need to flatten that into a single namespace name like admin-settings.
When should I start using namespaces?
The main trigger is performance in JavaScript web apps. When your application loads translations on the client side, you don't want to send all strings at once, especially if the user will only see a fraction of them. Namespaces let you split translations so the client fetches only what it needs for the current module.
For smaller apps, a single namespace is fine. But if your app is large and modularized, you can split strings into a common namespace for shared UI elements and one namespace per major module.
Organize namespaces by larger modules, not by individual components or features. Think about the natural loading boundaries of your application. If you have a settings module that loads separately from the dashboard, those could be different namespaces.
For large apps with heavy content like SEO strings or CMS-managed pages, keeping everything in a single namespace can slow down page loads. Moving content-heavy keys into a dedicated namespace that loads separately keeps the initial bundle small.
Exporting the same keys to different platform formats
If you use Tolgee Universal ICU Placeholders, you can export the same keys to different formats and the placeholders will be converted automatically. Pluralization, variables, number formatting: all handled across iOS, Android, web, Flutter, and more.
If you don't use ICU placeholders, you'll need to handle format differences yourself, which often means separate projects per platform anyway.
Tags. Flexible internal organization
If namespaces define the shape of your exported files, tags handle everything else. Tags are for internal organization and they're much more flexible.
The key difference: a key can have multiple tags, but it can only be in one namespace. If a key is used on both mobile and web, you can tag it with both. With namespaces, you'd have to pick one.
Common ways to use tags
Platform filtering. Tag keys with mobile, web, or desktop based on where they're used. When exporting via the CLI or the API, you can filter by tags using --filter-tags and --exclude-tags options.
Lifecycle management. Use tags like draft, production, and deprecated to track where keys are in their lifecycle. New keys start as drafts, get promoted to production when they ship, and get marked as deprecated when they're removed from the code.
Feature branches. Tag keys created for a specific feature with the feature name. If the feature gets cancelled, you know exactly which keys to clean up. Tolgee also supports branching for managing keys across lifecycle stages.
Ownership and modularization. Tags work well for marking key ownership by team or internal module. You can tag keys for any internal purpose that makes sense for your workflow.
How do I find and remove unused keys?
The answer is the Tolgee CLI combined with tags. The CLI can extract keys from your codebase and compare them with what's in the platform. You can tag keys that are currently in your production code with a production tag. When a key disappears from the code, you can mark it as deprecated and remove the production tag:
npx tolgee tag --filter-not-extracted --filter-tag production --tag deprecated --untag production
This gives you a clear view: keys tagged production are in use, keys tagged deprecated are candidates for deletion. We recommend reviewing in batches before deleting. Mark them first, then clean up when you're confident. See our article Organize Your Translation Keys Automatically with Tags for a full walkthrough.
Key naming. Be semantic, not literal
How you name your keys matters more than most developers think. A good naming convention makes keys findable, understandable, and resistant to content changes. We wrote a detailed guide on naming translation keys, but here’s the short version.
How should I name translation keys?
Name your keys based on where and how they're used, not what they say.
Good:
settings.notifications.email-toggle-labelGood:
checkout.payment.submit-buttonAvoid:
save,click-here,Save your changes
The key name should tell you, and the translator, where this string appears and what role it plays in the UI.
Why shouldn't I use the source string as the key name?
This is one of the most common mistakes and it creates real problems down the road.
Take the word "Save." In English, it's the same word whether you're saving a document, saving money, or saving animals. In German, these are completely different words: "Speichern," "Sparen," "Retten." If your key name is just save, a translator picks one meaning and every other context is wrong.
There's another practical problem. At some point a content team or product manager will start editing translations directly in the platform. They'll change "Save" to "Save changes," but the code still searches for "Save." With a semantic key name like document.save-button, there's no confusion. The key is a label for the purpose, not the content.
Should I use dots in key names?
Dots in key names are a common convention and Tolgee supports them. When you export to structured JSON, dots create nested objects.
Key name in Tolgee:
Exported as structured JSON:
If you already have a large codebase organized with dots, you don't need to change anything. Your existing conventions work fine. The one thing to watch out for is collisions: if you have both feature as a standalone key and feature.component.element as a nested key, the export structure breaks because feature can't be both a string and an object.
If you're starting a new project and don't need nested JSON output, keeping keys flat is slightly simpler to manage. You can also disable JSON structuring in export settings, which gives you a flat output regardless of dots in key names. The platform itself doesn't need nested structure for search or filtering. It has its own tools for that.
Bottom line: dots work, use them if your team already does. Just avoid the collision pattern and decide once whether you want structured or flat JSON output.
What about auto-generated key names?
Generating key names automatically, for example from the component path or a hash, avoids the contextual collision problem and ensures uniqueness. If your framework or tooling supports it, this is a valid approach. In the Figma plugin, you can generate keys from variables like node name, frame name, group name, and the node text value. This gives designers a starting point without typing every key name manually.
Why you shouldn't deduplicate translation keys
Earlier we mentioned that keeping web, mobile, and desktop in one project lets you reuse keys across platforms. That's still true. But reusing keys across UI contexts, the same button label in ten different places, is a different thing and it causes translation problems.
The distinction is important: reusing a key across platforms means the same button in your web and mobile app shares one translation. That's fine. Reusing a key across different UI contexts means a single common.save key gets used for saving a document, saving money, and saving a draft. That's where things go wrong.
The context problem
The English word "Post" can be a noun (blog post) or a verb (to post something). In German, these are completely different: "Beitrag" vs. "Veröffentlichen." If you use a single common.post key everywhere, the translator picks one and the other context is wrong.
Even something as seemingly universal as "Loading..." can differ. Loading data from a server and loading cargo onto a truck are different words in many languages. The tricky part is that you can't always predict this in English, since the words look the same. But in target languages, they might be completely different.
There's also a practical editing problem. If a translator changes the translation to fit one context, it might now be wrong in all the other places. Or worse, they see the key is shared and don't dare touch it because they're afraid of breaking something else.
What to do instead
Use unique keys for each usage and deduplicate at the component level. If you have a dialog component with a Close button, that dialog has its own dialog.close-button key. You reuse the dialog component, not the translation key.
Translation memory handles the efficiency concern. When a translator translates "Close" in one place, Tolgee's translation memory suggests the same translation for other occurrences. The translator can accept or override per context. This gives you consistency where it makes sense and flexibility where it doesn't.
Key descriptions. Context for translators and AI
Every key in Tolgee can have a description. This is free-text metadata that explains where the key is used, what it means, or what constraints apply such as character limits.
Descriptions directly impact translation quality, especially with AI translation. Without a description, a key called save-button with value "Save" could be translated as save money, save a life, or save data. The AI has to guess. With a description like "Button to save user profile changes in the settings page," the AI knows the exact context and produces the correct translation.
Traditional machine translators like Google Translate or DeepL don't use this context. But Tolgee's AI translator and human translators both benefit from good descriptions.
What should I include in a key description?
Keep it practical. Mention where the key appears in the UI, what action it triggers, and any constraints like maximum length for a button label. Even a short phrase like "Settings page, email notification toggle" is better than nothing.
Screenshots work as additional context too. You can upload them from the Figma plugin or capture them automatically through the in-context editing view in Tolgee's JS SDK. The SDK also automatically gathers the set of keys visible on the same screen at the same time, which gives the AI translator rich context for better translation decisions.
Why Tolgee doesn't support key nesting
A feature request we get regularly is the ability to reference other keys inside translation values. The idea: define a common word once, reference it everywhere, and it stays in sync automatically.
We don't implement this, and here's why. It adds enormous complexity to the platform. Every operation, such as search, export, and translation preview, would need to resolve references recursively. When you search for a string, should it search inside referenced keys too? When you export, do you expand the references or keep them as-is? What about circular references?
Some localization libraries like i18next or easy-localization for Flutter support this at the library level. That works because the library is just resolving strings at runtime. But for a platform that needs to display, search, filter, validate, and export translations, nested references make everything harder.
If you need to keep translations in sync, use translation memory. If you need common text fragments, handle them at the component level in your code.
Organizing keys with the Figma plugin
The Tolgee Figma plugin lets designers create and manage translation keys directly in Figma. The key principle: designers should follow the same naming conventions as developers.
The reason is that designers typically prepare keys for developers. A designer creates a screen, assigns key names to each text element, and pushes them to Tolgee. The developer then uses those exact keys in the code. If the naming conventions differ, someone has to rename everything, which defeats the purpose.
The plugin can auto-generate key name suggestions based on the Figma element names and frame structure. Use these as a starting point, not a final answer. When pushing content from Figma, the plugin also creates screenshots automatically, giving translators visual context for every key.
Migrating from a file-based platform
If you're coming from Phrase, Crowdin, Lokalise, or another file-based platform, the migration is straightforward. Your existing file paths typically become namespaces in Tolgee.
For example, if you had en/settings.json and en/dashboard.json, these become the settings and dashboard namespaces. The Tolgee CLI supports templates for mapping file paths to namespaces, so you can configure exactly how the conversion works.
Remember that Tolgee namespaces are flat, one level only. If your old file structure had nested folders like en/admin/settings.json, you'll need to flatten that. Common approaches are joining the path as admin-settings or restructuring your organization to use tags for the extra level.
After migration, consider whether you actually need all those namespaces. Many teams that migrated from file-based platforms realize they were using files for organization purposes that tags handle better. If you don't need separate export files, simplify to fewer namespaces or none, and use tags instead.
Quick reference. When to use what
Projects. One per product or application. Split into multiple projects only when different teams manage completely separate content.
Namespaces. Only when you need translations exported into separate files. Typically for performance reasons in client-side apps or for large modular applications. Organize by major modules, not by features or components.
Tags. For everything else. Platform identification, lifecycle tracking, feature flagging, automated cleanup. Tags are flexible, stackable, and don't affect your export structure unless you want them to.
Key names. Semantic and contextual. Describe where and why, not what. Avoid source strings as key names.
Descriptions. Add them for the best possible translation quality. Even a short phrase helps translators and AI produce better results.
Key deduplication. Don't deduplicate across UI contexts. Reuse components, not keys.
The bottom line
Good key organization is invisible when it works and painful when it doesn't. The time you invest upfront in setting clear conventions for naming, namespacing, and tagging pays back every time a translator opens your project, every time a developer searches for a key, and every time AI translates a string correctly because it had enough context.
Start simple. Use tags before namespaces. Write descriptions. Name keys semantically. And resist the urge to deduplicate.


