Add UI copy and German translation style guides - #34852
Conversation
Add two new documentation guides: - docs/ui-copy.md: language-independent guidelines for writing Element's interface copy and how translations should relate to the English source - docs/translations/de.md: English -> German translation style guide; docs/translations/ is the home for future per-language guides Cross-reference them from README.md, docs/translating.md, docs/translating-dev.md and the VitePress sidebar. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The custom link resolver rewrote every relative .md link to a GitHub blob URL missing the docs/ prefix, so in-content links between docs pages (e.g. ./jitsi.md in jitsi-dev.md) rendered as 404s. Let links whose target exists within docs/ pass through to VitePress native resolution; links to repo-root files keep the GitHub fallback. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
|
||
| Language-independent rules for Element's interface copy: how to write the English source, and how any translation should relate to it. | ||
|
|
||
| Applies to Element Web, Element Desktop, shared-components, Element X, Element Call, Element Admin and MAS. Per-language conventions live in the language guides in `docs/translations/` (e.g. the [German translation guidelines](./translations/de.md)). |
There was a problem hiding this comment.
It only applies to EW/ED et shared components. This repo doesn't rule the other product guidelines
There was a problem hiding this comment.
We should nevertheless make clear that language applies cross-product. You cannot change something in Element Web, like renaming a cryptographic concept, without adjusting this in the other places as well.
There was a problem hiding this comment.
Should it live in https://github.com/element-hq/element-meta instead? And we keep the exception or EW specialties here?
There was a problem hiding this comment.
imo all of this should be in localazy
There was a problem hiding this comment.
Can you point me to the place where this would live?
|
|
||
| These guidelines keep Element's German UI consistent and familiar—aligned with muscle memory from WhatsApp, Signal, Teams, and Slack. | ||
|
|
||
| Applies to Element Web, Element Desktop, shared-components, Element X, Element Call, Element Admin and MAS. Where a rule differs by product, it is called out explicitly. |
|
|
||
| - _Admin_ means a **room** admin. "Contact your admin" reads as "ask a moderator here", whatever you intended. | ||
| - _Session_ means a Megolm session in crypto contexts, and locally stored login state in others. | ||
| - _Client_ means an OAuth client in MAS and admin surfaces. |
There was a problem hiding this comment.
Client also means other matrix clients in our translations
There was a problem hiding this comment.
Can you point me to an example?
There was a problem hiding this comment.
I looked at the strings.
- There are 13 strings with the word client in EW and they all refer to the app.
- In EX there are zero strings with the word client. This is all app.
- MAS has 5 strings and I need to figure out which one of these are actually apps
- Admin has 5 strings and makes the important distinction in one of the strings:
Applications are OAuth 2.0 clients that users sign in to.
Proposal: I'll tidy up this string in a better way, so that
- App or Application is the consistent word for the software a user runs to chat
- Client is only used in the technical context of OAuth
Does that make sense to you?
There was a problem hiding this comment.
App or Application is the consistent word for the software a user runs to chat
I wouldn't consider a website an "app" - in the context of Element Web
There was a problem hiding this comment.
The browser itself calls something like Element an app
Yes, it is an app if you install the PWA "Progressive Web App" - hence it says "App available"
There was a problem hiding this comment.
So we're all aligned now?
|
|
||
| - **Name variables for the translator, not for the programmer.** `recipient` tells a translator nothing — is it a person, an email address, a user ID? `recipientEmailAddress` does. The variable name is often the only context a translator gets. | ||
|
|
||
| - **Before adding a string, check whether it already exists** in a related project. Reusing a shared string is better than a near-duplicate — but if the existing one is _wrong_, fix it rather than working around it, or the divergence spreads. |
There was a problem hiding this comment.
Same words have different meaning in different use case. Also the key is also kind of a path of where the translation is used and also a sense.
I agree to use common string for actions which are vastly used and without ambiguity.
There was a problem hiding this comment.
Sorry, i don't understand, what todo?
|
|
||
| | Change | Rename the key? | | ||
| | ----------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | | ||
| | **The meaning changes** — the string now says something different | **Yes.** Renaming forces every language to retranslate, which is what should happen | |
There was a problem hiding this comment.
I don't agree:
- You can force the re-translation in localazy without changing the key
- We have a lot of key like:
example_of_a_dialog|description. Even if the meaning change, the key is still valid. Forcing the re-translation in localazy is enough
There was a problem hiding this comment.
Right, you can force from localazy. Changing the key is not necessary. I'll remove this
|
|
||
| - **When referencing another system's UI** — iOS Settings, Android, another Element app — match that system's wording exactly, in every language. Some names (Apple's alert-tone names) are untranslated in every locale. | ||
|
|
||
| - **Name variables for the translator, not for the programmer.** `recipient` tells a translator nothing — is it a person, an email address, a user ID? `recipientEmailAddress` does. The variable name is often the only context a translator gets. |
There was a problem hiding this comment.
This is for the dev, should be in translating-dev.md
There was a problem hiding this comment.
What rule would you propose to distinguish what goes into what file? My impression was that the dev file is less about content but more about the dev mechanics, the project, the process. In that case, above language advise would sit here and not there.
There was a problem hiding this comment.
This guide is for developers or translators?
It seems to combine technical guidelines (how our internalization framework works) and wording guidelines(which are provided by the design team in Figma)
There was a problem hiding this comment.
It should be for whoever writes initial language strings. That can be a designer, a product manager, a contributors, a developer, etc... It should not contain technicalities, like how placeholders work or what the process is overall, but guide on UI copy content.
|
|
||
| - **Prefer full repeated sentences over shared fragments.** Several near-identical strings that differ by a word or two look like waste, but they translate faster and more accurately than fewer strings assembled from pieces. This is the opposite of the instinct that serves you well in code. | ||
|
|
||
| - **Use the framework's plural mechanism, never an `if`.** Choosing between a singular and a plural string in code assumes two forms; some languages have up to six. Pass the count and let the translation declare its own forms. |
There was a problem hiding this comment.
This is for the dev, should be in translating-dev.md
|
|
||
| ## 10. Working practice | ||
|
|
||
| - **Run the machine checks whenever the files change.** Key coverage, placeholder and markup parity, plural completeness, whitespace, and translation-identical-to-source are all mechanical, cost seconds, and catch regressions that reading does not. |
There was a problem hiding this comment.
Is it running the tests? I don't think we have anything to catch plural completeness?
There was a problem hiding this comment.
Fair point. I've run my own tooling when I worked through the clean-up which did all of the above and discovered loads of problems. But we don't have that in CI. I'll reword.


Adds two new documentation guides for translations and UI copy:
docs/ui-copy.md— language-independent guidelines for writing Element's interface copy and for how any translation should relate to the English source (voice, grammatical form by position, punctuation, terminology, placeholders/plurals, key renaming).docs/translations/de.md— an English → German translation style guide. The newdocs/translations/directory is intended as the home for future per-language guides.README.md,docs/translating.md,docs/translating-dev.mdand the VitePress sidebar.Also fixes a pre-existing docs-site bug surfaced while verifying this: the custom link resolver rewrote every relative in-content
.mdlink to a GitHub blob URL missing thedocs/prefix, so cross-doc links (e.g../jitsi.mdinjitsi-dev.md) rendered as 404s. Links whose target exists withindocs/now pass through to VitePress native resolution; links to repo-root files keep the GitHub fallback. (Separate commit, happy to split it out into its own PR if preferred.)Verified locally:
oxfmt --checkpasses andvitepress build docssucceeds with the dead-link check enabled.Checklist
public/exportedsymbols have accurate TSDoc documentation. — N/A