People searching localization keys, translation keys, stable string IDs, localization key naming, rename translation keys, string key best practices, descriptive localization keys, or how to change source text without losing translations are trying to solve a source-engineering problem that becomes a translation-cost problem. In software localization, a key is often the persistent identifier that connects source text, target translations, screenshots, comments, context, code, and release history. If the key itself changes every time the source wording changes, the system can treat a familiar string as brand-new work.
Current localization-platform documentation uses search language such as key name, unique key, descriptive keys, source strings as keys, key editor, and key naming. Phrase Strings explicitly distinguishes descriptive key names from using the source text itself as the key, warning that source-string keys become problematic when the original text changes because the relationship with translations breaks. Lokalise similarly treats keys as managed project objects with names, descriptions, plural forms, filenames, and other attributes. The practical reader job is clear: keep identity stable while copy evolves.
This article has one dominant job: design and maintain stable localization keys so ordinary source-copy changes update the right translation record instead of creating avoidable missing keys, stale keys, duplicate keys, and lost context. It does not replace the existing missing-key, duplicate-key, or stale-key QA articles. Those articles detect damage after resource files diverge. Stable-key design is preventive architecture: create persistent identifiers before translation begins, rename them only when identity truly changes, and migrate them deliberately when a rename is unavoidable.
Quick answer
A reliable stable-key workflow is:
- use descriptive, function-based identifiers instead of full source sentences as keys;
- keep a key stable when wording changes but the underlying UI/content function remains the same;
- change the key when the concept, screen role, data type, or ownership genuinely changes;
- store source text as content, not identity;
- attach context, screenshot references, notes, limits, and product metadata to the stable key;
- define naming conventions by product area and function;
- prevent duplicate key names within the relevant project scope;
- treat key renames as migrations, not casual edits;
- map old key to new key and preserve translations when semantic identity survives;
- run missing, duplicate, and stale-key QA after migrations.
The central rule is:
change the words freely when the message changes; change the key only when the identity changes.
What a localization key is
A localization key is an identifier used by software or a localization platform to refer to a translatable value.
Example:
checkout.pay_now
Source value:
Pay now
German target:
Jetzt bezahlen
French target:
Payer maintenant
Japanese target:
今すぐ支払う
The product code requests:
checkout.pay_now
The localization layer selects the correct target.
The key is the stable anchor.
The source text is the editable message.
Why source text makes a poor key
A simple resource system might use:
"Pay now": "Jetzt bezahlen"
This feels convenient because developers can recognize the English.
Then the source writer changes:
Pay now
to:
Pay securely
If the source string itself is the key, the system now sees a different identifier.
Consequences can include:
- old translations no longer linked;
- new missing-key work created;
- screenshots/context detached;
- review state reset;
- old key becomes stale.
The wording changed.
The product function did not.
A stable descriptive key avoids the churn.
Worked example 1: source copy change with stable key
Key:
checkout.pay_now
Old source:
Pay now
New source:
Pay securely
The key remains.
The localization platform can mark existing targets as:
- changed;
- unverified;
- needs review.
Translators see a source delta.
They repair only what changed.
This is efficient incremental localization.
Worked example 2: source-string key
Old key:
Pay now
New key:
Pay securely
The system may produce:
- one new untranslated key;
- one old stale key.
The translator has to rediscover that they are related.
That is avoidable.
Stable keys preserve history
A good key lets the project retain:
- translation memory linkage;
- comments;
- screenshots;
- approvals;
- version history;
- issue history;
- ownership;
- analytics.
The key becomes a durable content address.
This is why key naming is not just a developer preference.
It affects translation continuity.
Step 1: name by function, not wording
Good:
checkout.payment.submit
Better than:
pay_now
Why?
Because the product function can survive wording changes.
Possible source revisions:
- Pay now
- Pay securely
- Complete payment
- Confirm purchase
If the control is still the same checkout submit action, the key identity can remain stable.
Step 2: include useful product scope
A key should help distinguish where it belongs.
Examples:
account.security.password_resetbilling.invoice.downloadonboarding.profile.nextsettings.notifications.email_toggle
The structure gives humans context.
It also reduces collisions.
Avoid meaningless numeric IDs when humans need context
Key:
string_48291
can be technically stable.
It gives translators and developers no clue what it means.
Numeric IDs may be fine when:
- strong context metadata exists;
- tooling always shows screenshots;
- humans rarely inspect keys.
Otherwise descriptive names improve debugging.
Stability and readability are separate goals
A key can be:
- stable but unreadable;
- readable but unstable.
The best key is both:
- persistent;
- functionally descriptive.
Do not sacrifice identity merely to make the key mirror today’s English wording.
Step 3: define a naming convention
A simple convention might be:
area.component.function.variant
Examples:
checkout.button.pay checkout.error.carddeclined account.dialog.deleteconfirm profile.label.display_name
The exact syntax is less important than consistency.
Possible separators:
- dot;
- underscore;
- slash.
Choose one.
Key names should not contain every contextual detail
Bad:
checkoutblueprimarybuttonpaynowmobile
This is brittle.
What happens when:
- button becomes green;
- design changes;
- mobile and desktop merge?
The key should represent durable meaning.
Do not encode temporary visual implementation.
Step 4: use metadata for changing context
Instead of stuffing everything into key name, attach:
- description;
- screenshot;
- character limit;
- developer note;
- file/module;
- platform.
Key: checkout.button.pay
Description: “Primary button that submits the final payment.”
This separates identity from context detail.
Step 5: decide when wording change should keep the key
Keep the key when:
- same control;
- same concept;
- same user action;
- same runtime variable contract;
- wording refined;
- tone changes;
- punctuation changes.
Example:
Delete account
becomes:
Permanently delete account
Same destructive action.
Same key may be appropriate.
Targets need review.
Identity remains.
Step 6: decide when identity really changed
Change the key when the product concept changes.
Old:
account.button.delete
Action: permanently deletes account.
New product replaces it with:
action: deactivates account for 30 days.
Even if the visible source still says:
Delete account
the underlying function changed.
A new key can be appropriate because old translations and approvals describe a different action.
Key identity is semantic and functional
The key should answer:
Is this still the same user-facing thing?
Not merely:
Are the words similar?
This is the central judgment.
Step 7: treat key renames as migrations
Sometimes a key name is poor:
button_7
You want:
checkout.button.pay
If the underlying function is unchanged, the rename should preserve:
- targets;
- context;
- history;
- screenshots;
- state.
Use platform rename/migration features where possible.
Do not delete old key and create new key manually unless you intend to reset identity.
Worked example 3: safe rename
Old key:
btn_pay
New key:
checkout.button.pay
Migration maps one to one.
Source remains:
Pay now
Targets move with the key.
After migration:
- old key absent;
- new key contains all translations;
- code updated;
- no false untranslated work.
That is a real rename.
Unsafe rename pattern
- developer adds new key;
- translator sees it as untranslated;
- old key remains;
- both ship for one release;
- later old key deleted.
This creates:
- duplicate work;
- duplicate translation;
- stale-key cleanup.
A planned rename avoids it.
Step 8: coordinate code and localization changes
A key rename touches:
- source repository;
- localization platform;
- export files;
- tests;
- possibly analytics.
Coordinate the transition.
Useful sequence:
- create rename map;
- migrate localization key;
- update code reference;
- export;
- run missing/stale-key QA;
- test screen.
Do not change only one side.
Step 9: use a rename map
For bulk migrations:
| Old key | New key | Identity same? |
|---|---|---|
| btn_pay | checkout.button.pay | yes |
| profile_name | profile.label.display_name | yes |
| account_delete | account.deactivate | no |
The last row should not preserve old translations automatically because the function changed.
The map forces semantic thinking.
Step 10: keep aliases temporary
Some systems support aliases or linked keys.
They can help during migration.
But permanent aliases create complexity.
Define an expiry:
- one release;
- one sprint.
Then remove the old path after code is migrated.
Step 11: avoid duplicate identity under different keys
Two keys:
checkout.pay_button
payment.submit
both render the same control.
This can create:
- duplicate translations;
- divergence;
- review waste.
If they truly represent one string, use one key.
If they represent two contexts that happen to have same English source, keep separate keys.
Identity comes from function.
Same source text can need different keys
Source:
Open
Key A:
file.button.open
Key B:
ticket.status.open
Key C:
store.hours.open
Same characters.
Different concepts.
Do not deduplicate by source text alone.
Step 12: use context keys for TM where supported
Some TMS systems can use segment key or ID as TM context.
Stable keys improve context matching.
A repeated source string such as:
Save
can retrieve the right historical target when the segment key also matches.
Key stability therefore improves more than resource-file mapping.
It can improve TM precision.
Step 13: key churn can destroy context matches
If the key changes every release:
savebuttonv1 savebuttonv2 savebuttonv3
context-based TM sees three different contexts.
Even if source text stays identical.
Avoid version numbers in key names unless the function truly changes.
Version belongs in release metadata, not string identity.
Step 14: do not encode source language in the key
Bad:
buttonsaveenglish
The key identifies the concept across languages.
Language belongs in translation data.
Source language can change in some multilingual authoring systems.
Keep identity language-neutral.
Step 15: do not encode target locale in the key
Bad:
checkout.pay.fr
The locale is a dimension of the translation.
It is not the message identity.
A key should map across locales.
Step 16: do not encode current character count
Bad:
title_20chars
Length limits may change.
Store max length as metadata.
The key should survive redesign.
Step 17: avoid timestamps and random suffixes unless necessary
Keys such as:
message20260919482
are stable only because they never repeat.
They are poor for human debugging.
If auto-generated IDs are required, pair them with strong descriptions and searchable metadata.
Step 18: stable keys and screenshots
Screenshot systems often map visual strings to keys.
If key changes unnecessarily:
- screenshot link can break;
- old visual context becomes detached.
Stable keys preserve in-context translation.
Step 19: stable keys and comments
A translator may have asked:
Does “Home” mean navigation or product tier?
The answer is attached to the key.
If key is recreated, the decision history may disappear.
Stable identity preserves institutional memory.
Step 20: stable keys and terminology
A key can carry domain or feature metadata.
Term suggestions can be scoped.
Example:
billing.*
uses billing termbase.
Key naming can support resource routing.
Do not overfit naming merely for this purpose, but take advantage of stable hierarchy.
Step 21: stable keys and analytics
Product analytics may log:
- screen;
- action;
- content key.
If localization and analytics share stable identifiers, teams can connect:
- user exposure;
- fallback hits;
- translation debt.
Renaming keys casually can break historical analytics.
Coordinate.
Step 22: stable keys and A/B tests
A/B copy tests change wording frequently.
Do not create a brand-new permanent key for every tiny wording variant unless the platform needs separate variants.
Possible model:
checkout.pay.varianta checkout.pay.variantb
Then retire the losing variant intentionally.
Keep experimental scope clear.
Step 23: stable keys and feature flags
A feature flag can temporarily render two versions of UI.
Keys may need:
- old feature;
- new feature.
Do not reuse one key for two simultaneous meanings merely to reduce translation work.
If functions differ at the same time, they need distinct identities.
Step 24: stable keys and branching
Software branches can introduce keys independently.
When branches merge, key collisions can happen.
Use naming scope and duplicate-key QA.
Stable does not mean “globally unique forever” unless the platform requires that.
Define the project scope.
Step 25: key names and plural forms
Plural messages may use:
- one key with plural variants;
- separate keys per form.
Follow the localization platform’s model.
Do not create arbitrary keys such as:
itemone itemmany
if the system expects one plural-aware message.
The key should identify the message family.
Step 26: key names and gender/select variants
Same principle.
Dynamic variants may belong under one logical key with structured forms.
Do not fragment identity unnecessarily.
Step 27: stable keys and source rewrites
Source team may rewrite an entire sentence for clarity.
Question:
Same user-facing function?
If yes: keep key, mark target for review.
Translation history remains useful.
A translator can compare old and new source.
Step 28: major semantic rewrite
Old source:
We store your data for 30 days.
New:
We store your data until you delete your account.
Same paragraph location.
Different policy.
The key may still represent the same disclosure component.
Should it stay?
This requires judgment.
Stable keys preserve history, but a major semantic reset may justify:
- new key;
- new legal approval;
- clean review state.
Key policy should define high-risk changes.
Step 29: legal and regulated strings
For legally approved text, identity may include:
- jurisdiction;
- version;
- approval date.
A new legal version may need a new key even if it occupies the same UI slot.
Do not force ordinary UI key policy onto regulated content.
Step 30: translations should not determine key identity
A translator may suggest changing the key because the target uses a different noun.
Do not.
Key identity belongs to product/source semantics.
Target languages may structure meaning differently.
The key remains language-neutral.
Step 31: use a linter for key naming
For large codebases, automate checks:
- allowed characters;
- separator style;
- no spaces;
- no duplicate keys;
- required scope prefix;
- forbidden source-text keys.
A naming linter prevents drift.
Step 32: detect source-string keys
If the codebase contains keys such as:
"Delete account"
flag them.
Not every system can migrate immediately.
But new keys should follow the stable convention.
Reduce future debt.
Step 33: migration from source-string keys
A safe migration can proceed:
- inventory source-string keys;
- generate descriptive IDs;
- map old to new;
- preserve targets;
- update code;
- run missing/stale/duplicate QA;
- remove aliases after release.
Do it in batches.
Do not rename 20,000 keys without rollback.
Step 34: migrate highest-churn strings first
Source-string keys hurt most where copy changes often:
- marketing;
- onboarding;
- UI labels.
Stable legal boilerplate may change rarely.
Prioritize by source churn and translation volume.
Step 35: key descriptions matter after names become abstract
A descriptive key cannot encode every nuance.
Add a description.
Good description:
Primary destructive button in Account > Security. Permanently deletes the user account after confirmation.
This gives translators strong context.
Step 36: name keys for future maintainers
A developer two years later should be able to answer:
- where is this used?
- what function?
- what concept?
Avoid team-specific slang.
A stable key should outlive the person who created it.
Failure mode 1: source text used as key
Result:
every copy edit looks like new translation.
Repair:
descriptive stable ID.
Failure mode 2: key includes visual styling
Result:
redesign forces rename.
Repair:
name by function.
Failure mode 3: key renamed casually
Result:
translations/context lost.
Repair:
migration map.
Failure mode 4: key never changes even when function changes
Result:
old translations reused for new concept.
Repair:
new identity when semantics change.
Failure mode 5: duplicate function under two keys
Result:
translation divergence.
Repair:
consolidate or document distinct contexts.
Failure mode 6: same source deduplicated across different contexts
Result:
wrong target form.
Repair:
separate functional keys.
Failure mode 7: version numbers in keys
Result:
context churn.
Repair:
release metadata.
Failure mode 8: locale encoded in key
Result:
duplicate message identities.
Repair:
locale as data dimension.
Failure mode 9: rename leaves old key in code
Result:
stale-key debt.
Repair:
search references and test.
Failure mode 10: migration preserves translation despite semantic change
Result:
stale approved meaning.
Repair:
identity review.
A key-naming decision table
| Situation | Keep key? |
|---|---|
| punctuation edit | usually yes |
| tone refinement | yes |
| synonym rewrite | yes if function same |
| button moved to another screen | often yes if action same |
| action changes from delete to deactivate | no/new identity likely |
| legal version changes materially | project-specific, often new |
| key name itself is ugly | rename with migration |
| same English word used for another function | separate key |
The table is a starting point.
A stable-key checklist
Before creating a key:
- does it identify function?
- will it survive copy edits?
- is it unique?
- is it language-neutral?
- does it avoid visual styling?
- does it avoid version numbers?
- is context stored separately?
- can another developer understand it?
Before renaming:
