snapshot of https://github.com/RocketChat/Rocket.Chat.git (develop, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s

This commit is contained in:
upstream-mirror
2026-09-16 01:21:02 +05:00
commit 30810eecd7
10161 changed files with 987110 additions and 0 deletions

94
docs/frontend/i18n.md Normal file
View File

@@ -0,0 +1,94 @@
# Translations (i18n) in the client
Client-side conventions only. How keys are stored, named, and written — naming, interpolation, plurals, formatters, what the linter enforces — is in [docs/i18n.md](../i18n.md), and applies here too.
## Reading translations
Use `useTranslation` from `react-i18next`:
```tsx
import { useTranslation } from 'react-i18next';
const DeleteRoomButton = () => {
const { t } = useTranslation();
return <Button danger>{t('Delete_room')}</Button>;
};
```
❌ Not `useTranslation` from `@rocket.chat/ui-contexts` — it is `@deprecated` and re-renders every consumer of the translation context on language change. ~125 client modules still import it against ~890 for the `react-i18next` one; don't add to the count.
[`TranslationProvider`](../../apps/meteor/client/providers/TranslationProvider.tsx) bundles `en` statically and sets it as `fallbackLng`, so English keys resolve immediately. Only a non-English active locale is fetched over HTTP (`partialBundledLanguages: true`); until it arrives, and for any key it omits, the English string is used. The server, by contrast, holds all 68 locales in memory.
## Never build keys at runtime
`t()` does not reject unknown keys (see [docs/i18n.md](../i18n.md#types-are-generated-from-en)), so a computed key has nothing checking it — and it makes the key invisible to anyone grepping for it.
❌ Incorrect:
```tsx
{t(`App_status_${instance.status}` as TranslationKey)}
```
✅ Correct — map the value to a literal key:
```tsx
const APP_STATUS_LABELS = {
installed: 'App_status_installed',
updating: 'App_status_updating',
} as const satisfies Record<AppStatus, RocketchatI18nKeys>;
{t(APP_STATUS_LABELS[instance.status])}
```
The map is the thing that tells you a key is missing when a new status is added, and `satisfies` is what makes the map itself checkable. `as TranslationKey` appears about 70 times in the client; treat every one as debt rather than precedent.
## Rich text: the `Trans` component
When a sentence contains a link, bold run, or nested element, don't split it into several keys. Use `Trans` and put the markup in the translation:
```json
{
"Unique_ID_change_detected_learn_more_link": "Read the <a>documentation</a> before proceeding."
}
```
```tsx
import { Trans } from 'react-i18next';
<Trans i18nKey='Unique_ID_change_detected_learn_more_link' components={{ a: <ExternalLink to={links.go.fingerPrintChangedFaq} /> }} />;
```
Name your tags. Indexed placeholders (`<1>`, `<3>`) appear in older keys and are effectively unreadable for a translator, who can't tell what index 3 wraps:
❌ Avoid:
```json
{ "Limits_reached": "Your workspace reached the <1>{{val}}</1> limit. <3>Manage subscription</3>." }
```
✅ Prefer:
```json
{ "Limits_reached": "Your workspace reached the <bold>{{val}}</bold> limit. <link>Manage subscription</link>." }
```
The base locale is currently split about evenly between the two (~50 values each), so this is a direction, not an established majority.
Pass interpolation values through `values` and `t` options through `tOptions`:
```tsx
<Trans i18nKey='Airgapped_workspace_warning' values={{ remainingDays }} />
```
## Interpolated values are not HTML-escaped
`escapeValue` is `false`. That is safe only because React escapes strings when it renders them as text nodes — it is not a property of the translation itself.
So if a translated string is injected as HTML, sanitize it, as the two existing call sites do:
```tsx
<FieldHint dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(t(provider.description)) }} />
```
Prefer `Trans` over injected HTML wherever possible — it needs no sanitizing because the components are real React elements, not parsed markup.