Skip to content

refactor(i18n): adopt named interpolation and react-i18next's useTranslation - #41667

Merged
tassoevan merged 24 commits into
developfrom
refactor/i18n
Aug 10, 2026
Merged

refactor(i18n): adopt named interpolation and react-i18next's useTranslation#41667
tassoevan merged 24 commits into
developfrom
refactor/i18n

Conversation

@tassoevan

@tassoevan tassoevan commented Aug 3, 2026

Copy link
Copy Markdown
Member

Proposed changes (including videos or screenshots)

Groundwork for the i18next upgrade, in two related parts.

1. Adopt useTranslation from react-i18next in ui-client, web-ui-registration and fuselage-ui-kit, replacing the deprecated re-export from @rocket.chat/ui-contexts.

2. Migrate 19 translation keys from sprintf %s to i18next named interpolation ({{name}}), across every locale that defines them, along with all their call sites.

The second part is a prerequisite for finishing the first. The hook exported by ui-contexts returns a translate function wrapped by addSprinfToI18n, so t('Max_length_is', 120) works today. react-i18next's t has no such wrapper — those call sites keep type-checking in some positions but stop substituting, silently rendering a literal %s. Converting the keys first makes the remaining hook migration purely mechanical.

There is a second benefit. packages/i18n's missing-placeholders check validates every locale's {{…}} placeholders against the base language, but cannot see anything about %s. Each key converted here moves from unverifiable to CI-enforced — which is how most of the bugs below were found.

Rendering bugs fixed along the way

All of these predate this PR and were invisible precisely because %s is unvalidated. 23 placeholders repaired:

Locale Wrote Rendered
zh-HK (18 keys) %s — fullwidth percent (U+FF05) literal %s
sr (2 keys) % с — Cyrillic es, split by a space literal % с
hi-IN %एस — Devanagari transliteration literal %एस
ta-IN % கள் — Tamil transliteration literal % கள்
be-BY % з — Cyrillic ze, split by a space literal % з

Plus one semantic fix: es had The_user_will_be_removed_from_s as "El usuario %s se eliminará de %s", a copy-paste of the line directly above it (The_user_s_will_be_removed_from_role_s, which legitimately takes two placeholders). With only one argument supplied, Spanish users saw the room name in the wrong slot followed by a literal undefined.

Translations dropped — these need re-translation

Eight entries could not render their message regardless of placeholder syntax, so they were removed and now fall back to en. All were already broken; missing-placeholders reports them once the keys are named, and repairing them would have meant authoring grammar in languages I cannot verify.

Locale Key Why
th-TH The_setting_s_is_configured_to_s_and_you_are_accessing_from_s sentence truncated mid-clause, 1 of 3 slots
ta-IN The_setting_s_is_configured_to_s_and_you_are_accessing_from_s markup shredded, % and s orphaned across nested <strong>
he The_setting_s_is_configured_to_s_and_you_are_accessing_from_s RTL mangling split %s into %S, 2 of 3 slots
ta-IN Prune_Warning_after 4 slots against 3; surplus rendered undefined
ku Prune_Warning_before 4 slots against 3; surplus rendered undefined
ja, ka-GE, mn Prune_Warning_between omit the room name and reorder, so dates landed where the room name belongs

Keys migrated

Max_length_is · Min_length_is · The_user_wont_be_able_to_type_in_s · The_user_will_be_removed_from_s · User_has_been_removed_from_s · Channel_already_exist · Custom_oauth_helper · The_setting_s_is_configured_to_s_and_you_are_accessing_from_s · Do_you_want_to_change_to_s_question · Showing_results_of · if_they_are_from · Prune_Warning_all · Prune_Warning_after · Prune_Warning_before · Prune_Warning_between · The_user_s_will_be_removed_from_role_s · Users_Table_Generic_No_users · Mail_Messages_Subject · Mail_Message_Invalid_emails

One commit per key, so any single migration can be reviewed or reverted on its own.

Issue(s)

Steps to test or reproduce

Each migrated key is behaviour-preserving in en, so the useful check is that placeholders still substitute and that the repaired locales now render a value instead of a literal %s. Switching to 中文 (香港) exercises 18 of the 23 repairs.

  • Admin → Users → Edit — set a status message or bio over the limit; the validation message should read a number, not %s
  • Admin → Users — filter to Pending/Deactivated with no results; the empty state names the tab
  • Admin → Permissions → a role → remove a user — the modal names the user and the role
  • Admin → Settings → OAuth → a custom provider — the callback-URL helper shows the URL
  • Kebab → Prune Messages — set a date range, plus "Only prune content from these users"; the warning names the room, the dates and the users
  • Kebab → Export Messages → Send email — the subject names the room; enter an invalid address to see the error list them
  • User card → Mute / Remove from room — the confirmation names the room
  • Create a channel with an existing name — the validator names the channel; /create <existing> covers the server path
  • Access the workspace on a URL other than Site_Url — the warning names the setting and both URLs
  • Admin → Import, and any admin table pagination — "Showing results 1 - 25 of 100"

Further comments

Placeholder naming follows what each key's neighbours already use — {{roomName}} (56 prior uses), {{username}} (41), {{url}} (5). Two were deliberate:

  • Showing_results_of uses {{total}}, not {{count}}. count is i18next's pluralization trigger; it happens to work here only because no plural-suffixed variants of the key exist. The sibling Showing_current_of_total already uses {{total}}.
  • Channel_already_exist uses {{channelName}} rather than the more common {{roomName}}, matching the two existing #{{channelName}} templates since this one hardcodes the #.

Escaping is unchanged on the client: TranslationProvider sets interpolation.escapeValue: false, so the three keys feeding DOMPurify.sanitize receive byte-identical input. The one exception is Channel_already_exist's server call site in /create, where the server i18next instance does escape — a no-op for channel names under the default UTF8_Channel_Names_Validation regex ([0-9a-zA-Z-_.]+), and consistent with existing server-side named interpolation such as exportRoomMessagesToFile.

Positional mapping is safe. No locale anywhere uses %1$s, so sprintf already substituted strictly left to right; replacing the Nth %s with the Nth name is exactly behaviour-preserving.

replace-sprintf has a gap. yarn workspace @rocket.chat/i18n replace-sprintf <key> does this same migration interactively, but matches only ASCII %s — it would have skipped all 23 manglings above without reporting them. Worth teaching it the fullwidth and transliterated variants, and making it fail loudly on a locale it cannot convert, before the remaining keys are done.

Still on sprintf, deliberately out of scope. Three client call sites translate a key supplied at runtime rather than written literally: ActionInputBase and useUserBanners translate a key plus a positional argument array received from the server, and TranslationContextMock implements the post-processor so Storybook mirrors the real provider. type: 'action' settings return { message: TranslationKey; params?: string[] } from a Meteor method or REST endpoint, so converting those means changing that contract on both sides at once — a coordinated change rather than a call-site edit. Every client call site passing a literal key is now on named interpolation. 56 keys still contain %s in en; the remainder are server-only or unreferenced.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Improved dynamic value interpolation in warnings, confirmations, validation messages, pagination labels, imports, exports, and moderation dialogs.
    • Ensured channel names, URLs, limits, usernames, dates, and other values display consistently in translated content.
    • Improved translated labels and actions across setup, registration, account, and conferencing screens.
  • Localization
    • Updated supported translations to use named placeholders for more reliable formatting.
    • Removed obsolete translation entries where applicable.

Task: ARCH-2329

@tassoevan
tassoevan requested review from a team as code owners August 3, 2026 17:02
@tassoevan tassoevan added this to the 8.8.0 milestone Aug 3, 2026
@dionisio-bot

dionisio-bot Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Looks like this PR is ready to merge! 🎉
If you have any trouble, please check the PR guidelines

@changeset-bot

changeset-bot Bot commented Aug 3, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 7cdece0

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@tassoevan

Copy link
Copy Markdown
Member Author

/jira ARCH

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

The change replaces positional sprintf translation formatting with named interpolation values. It updates application calls, locale placeholders, and selected useTranslation imports across client, server, and shared packages.

Changes

Named interpolation migration

Layer / File(s) Summary
Application translation calls
apps/meteor/..., packages/ui-client/src/components/...
Translation calls now pass named values such as channelName, roomName, limit, from, to, and total.
Translation hook usage
packages/fuselage-ui-kit/..., packages/ui-client/..., packages/web-ui-registration/...
Selected components now import useTranslation from react-i18next and destructure t.
Locale placeholder conversion
packages/i18n/src/locales/*.i18n.json
Locale strings now use named {{...}} placeholders instead of positional %s tokens. Some obsolete entries were removed.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested labels: type: chore

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the migration to named i18n interpolation and react-i18next's useTranslation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • ARCH-2329: Request failed with status code 401

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@tassoevan

Copy link
Copy Markdown
Member Author

QA test plan

Full coverage for this PR. Nothing here should change behaviour in English — the point of the change is that placeholders keep substituting after moving off sprintf. The visible wins are in the non-English locales in Parts C–E.

The single most valuable thing to check: every step in Part B, run once in 中文 (香港). That locale alone accounts for 16 of the 23 repaired placeholders, and before this PR each of them rendered a literal %s to users.


0. Setup

Switch UI language My Account → Preferences → Localization → Language
Switch workspace language Admin → Settings → General → Language — needed for server-rendered strings (slash commands), which use the workspace default, not your user language
Custom fields (for Min_length_is / Max_length_is) Admin → Settings → Accounts → Registration → Custom Fields, e.g. {"twitter":{"type":"text","required":false,"minLength":5,"maxLength":10}}
Premium Engagement Dashboard step only
Video conf provider VideoConferenceBlock step only
Fresh workspace Setup Wizard step only

Universal fail condition for every step below: a literal %s, %s, {{something}}, the word undefined, or an empty gap where a value belongs.


Part A — useTranslation regression (no visible change expected)

Three packages moved off the deprecated useTranslation re-export. These components have no key changes, so the check is simply that they still render translated text and don't crash.

  1. Terms / Privacy / Legal pages — populate Admin → Settings → Layout → Terms of Service, then log out and open /terms-of-service, /privacy-policy, /legal-notice. Content renders, back button works.
  2. Reset password — Forgot password → open the emailed link (/reset-password/<token>) → set a new password. Also covers the forced "change password" variant.
  3. "Don't ask me again" modals — kebab on a room in the sidebar → Hide. Tick Don't ask me again, confirm. Hide a second room: no modal. Then My Account → Preferences → check the entry can be undone. Same component backs Marketplace → an app → Enable (exempt modal) and E2EE → Reset keys.
  4. Setup Wizard — fresh workspace: all steps render, admin creation and organization info submit correctly.
  5. Video conference message block — start a call in a channel; the call block in the message list renders (title, participant names, "Join"/"Call again" states, ended/expired states).

Part B — the 19 migrated keys

Grouped by screen. Run the whole part in English first (must be unchanged), then repeat in 中文 (香港).

B1. My Account → Profile

  • Set a status message longer than the limit → error names the number. → Max_length_is
  • Set a bio longer than the limit → error names the number. → Max_length_is
  • With custom fields configured, enter a value too short and too long → both errors name their numbers. → Min_length_is, Max_length_is

B2. Custom status modal

  • Avatar (top-right) → Custom Status → type past the limit → error names the number. → Max_length_is

B3. Admin → Users

  • Edit a user → over-long status message and bio → both errors name their numbers. → Max_length_is
  • Empty states: filter to Pending, Active, Deactivated with no matches → heading names the tab (e.g. "No pending users"). Also check the All tab, where the name is intentionally blank. → Users_Table_Generic_No_users
  • Pagination on a populated table → footer reads "Showing results 1 - 25 of N". → Showing_results_of

B4. Admin → Permissions

  • Open a role → Users in role → (pick a room for scoped roles) → remove a user → modal names both the user and the role. → The_user_s_will_be_removed_from_role_s

B5. Admin → Settings → OAuth

  • Add a custom OAuth provider → the helper text under it shows the callback URL inside a code block. → Custom_oauth_helper

B6. Site URL mismatch banner (admin only)

  • Set Admin → Settings → General → Site URL to a value different from the address you're browsing, then reload.
  • Modal names the setting, the configured URL and the URL you're on, and asks whether to change to the current one. → The_setting_s_is_configured_to_s_and_you_are_accessing_from_s, Do_you_want_to_change_to_s_question
  • Confirm → the setting updates.

B7. Room → Prune Messages

Kebab → Prune Messages. Check the warning text in all four combinations — each must name the room and the content type ("messages"/"files"):

  • No dates → Prune_Warning_all
  • Newer than only → also names that date → Prune_Warning_after
  • Older than only → also names that date → Prune_Warning_before
  • Both dates → names both → Prune_Warning_between
  • With any of the above, add users under Only prune content from these users → the sentence gains "(if they are from …)" listing them, comma-separated. → if_they_are_from
  • Tick Only remove attached files → wording switches from messages to files.

B8. Room → Export Messages

Kebab → Export Messages → method Send email:

  • The subject field is prefilled naming the room. → Mail_Messages_Subject
  • Enter an invalid address in To additional emails → error lists the offending address(es). → Mail_Message_Invalid_emails

B9. User card actions

Click a user in a room → user card → kebab:

  • Mute → modal says the user won't be able to type in that room. → The_user_wont_be_able_to_type_in_s
  • Remove from room → modal names the room; confirm → success toast names the room. → The_user_will_be_removed_from_s, User_has_been_removed_from_s

B10. Channel creation — client and server

  • Client: Create new → Channel → enter the name of an existing channel → inline validation names the channel. → Channel_already_exist
  • Server: in any room run /create <existing-channel-name> → the ephemeral reply names the channel. → same key, server path

⚠️ The server path renders in the workspace language (Admin → Settings → General → Language), not your personal one. To test it in 中文 (香港) you must switch the workspace setting.

B11. Admin → Import

  • Start an import (any provider) → on the Prepare step, the Users and Channels lists show "Showing results 1 - 25 of N". → Showing_results_of

B12. Engagement Dashboard (Premium)

  • Admin → Reports → Engagement → Channels tab → pagination footer. → Showing_results_of

Part C — repaired locales

These placeholders were broken before this PR and rendered literally. Confirm each now shows a real value.

Locale Keys Was rendering
中文 (香港) zh-HK 16 keys — everything in Part B except Showing_results_of, Users_Table_Generic_No_users, The_user_s_will_be_removed_from_role_s literal %s
中文 zh Min_length_is (B1), Prune_Warning_all (B7) literal %s
Српски sr Mail_Messages_Subject, Mail_Message_Invalid_emails (B8) literal % с
हिन्दी (भारत) hi-IN Custom_oauth_helper (B5) literal %एस
தமிழ் (இந்தியா) ta-IN Custom_oauth_helper (B5) literal % கள்
Беларуская be-BY Prune_Warning_between (B7) literal % з

For sr, also confirm spacing reads naturally — the mangling had swallowed a space, so it should be део {{roomName}} порука style, not run together.


Part D — dropped translations must fall back to English

Eight entries were removed because their text could not render the message at all. They must now show English, cleanly — not a blank, not a partial sentence, not a crash.

Locale Where to look
עברית he B6 — Site URL modal, first paragraph
தமிழ் (இந்தியா) ta-IN B6 — Site URL modal, first paragraph and B7 — "Newer than" only
ไทย th-TH B6 — Site URL modal, first paragraph
Kurdî ku B7 — "Older than" only
日本語 ja B7 — both dates
ქართული ka-GE B7 — both dates
Монгол mn B7 — both dates

These are flagged for re-translation; English here is the intended outcome of this PR, not a defect.


Part E — Spanish fix

In Español es, B9 → Remove from room.

  • Before: "El usuario general se eliminará de undefined" — room name in the wrong slot, literal undefined.
  • After: "El usuario se eliminará de general".

Part F — sanity sweep

  • Switch through several unaffected languages (de, fr, pt-BR, ru, ar) and spot-check Part B screens — no regressions, no untranslated keys leaking through.
  • RTL check: in Arabic or Hebrew, confirm B6/B7/B9 sentences still read correctly with values injected.
  • Confirm no console errors mentioning i18next, interpolation, or missing keys during the run.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

🟡 Minor comments (32)
packages/i18n/src/locales/af.i18n.json-1356-1361 (1)

1356-1361: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Restore separators around named interpolation values.

Several converted locale strings place {{...}} directly next to punctuation, words, or closing markup. The rendered text can concatenate the interpolated value with surrounding text.

  • packages/i18n/src/locales/af.i18n.json#L1356-L1361: Add separators after the colon and before {{roomName}}; apply the same fix to Max_length_is, Min_length_is, and the room-removal strings at Lines 1389, 1473, 2076-2077, and 2217.
  • packages/i18n/src/locales/az.i18n.json#L1356-L1361: Add separators around {{emails}} and {{limit}}; apply the same fix to Lines 799, 1389, 1473, 2077-2079, and 2218.
  • packages/i18n/src/locales/be-BY.i18n.json#L1376-L1381: Add separators after the colon, after the closing <strong> tags, and before {{roomName}} in Lines 2098-2100 and 2240.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/af.i18n.json` around lines 1356 - 1361, Restore
separators around named interpolation values in the locale strings. In
packages/i18n/src/locales/af.i18n.json lines 1356-1361, also update
Max_length_is, Min_length_is, and the room-removal strings at lines 1389, 1473,
2076-2077, and 2217; in packages/i18n/src/locales/az.i18n.json lines 1356-1361,
also update lines 799, 1389, 1473, 2077-2079, and 2218; and in
packages/i18n/src/locales/be-BY.i18n.json lines 1376-1381, also update lines
2098-2100 and 2240. Add spacing after colons, around {{emails}} and {{limit}},
after closing <strong> tags, and before {{roomName}} wherever needed so
interpolated values do not concatenate with adjacent text or markup.
packages/i18n/src/locales/bg.i18n.json-1353-1353 (1)

1353-1353: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve spaces around interpolated content.

{{emails}} renders directly after the colon. The setting message renders </strong>е and </strong>и. Add spaces so the Bulgarian text does not concatenate.

Also applies to: 2072-2072

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/bg.i18n.json` at line 1353, Update the Bulgarian
Mail_Message_Invalid_emails translation to include a space between the colon and
the {{emails}} interpolation, and apply the same spacing correction to the
additional affected translation entry so interpolated content does not
concatenate with surrounding text.
packages/i18n/src/locales/bs.i18n.json-398-398 (1)

398-398: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fix the mismatched quotation marks.

Channel_already_exist opens a double quote before #{{channelName}} and closes with a single quote. Use matching quotation marks.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/bs.i18n.json` at line 398, Update the
Channel_already_exist translation to use matching quotation marks around
#{{channelName}}, replacing the mismatched closing single quote while preserving
the rest of the message.
packages/i18n/src/locales/mn.i18n.json-1471-1471 (1)

1471-1471: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Correct the minimum-length label.

"Min урт бол{{limit}}" mixes Latin text into the Mongolian translation and joins the value to the preceding text. Use the locale's Mongolian label and add a space before {{limit}}.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/mn.i18n.json` at line 1471, Update the
“Min_length_is” translation in the Mongolian locale to use the correct Mongolian
label instead of “Min” and insert a space before the {{limit}} placeholder.
packages/i18n/src/locales/ca.i18n.json-3542-3542 (1)

3542-3542: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use the Catalan contraction del.

Replace de el rol with del rol in the role-removal message.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/ca.i18n.json` at line 3542, Update the Catalan
translation value for “The_user_s_will_be_removed_from_role_s” to use “del rol”
instead of “de el rol”, preserving the username and role placeholders.
packages/i18n/src/locales/mn.i18n.json-732-732 (1)

732-732: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve whitespace around interpolated values and markup.

These strings concatenate text with {{url}}, {{currentUrl}}, {{emails}}, {{settingName}}, or {{roomName}}. Add spaces after the colon and closing tags, and between Хэрэглэгч and {{roomName}}.

Also applies to: 798-798, 1354-1354, 2072-2074, 2212-2212

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/mn.i18n.json` at line 732, Update the affected
Mongolian locale strings, including Custom_oauth_helper and the additional
referenced entries, to preserve readable whitespace around interpolated values
and markup: add spaces after colons and closing tags, and between Хэрэглэгч and
{{roomName}}. Keep the existing translations and interpolation tokens unchanged.
packages/i18n/src/locales/bs.i18n.json-2071-2071 (1)

2071-2071: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add a separator before currentUrl.

The text contains pristupate se<strong>{{currentUrl}}</strong>, which renders the URL directly after se. Add a space before the opening tag.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/bs.i18n.json` at line 2071, Update the Bosnian
translation value for
The_setting_s_is_configured_to_s_and_you_are_accessing_from_s to insert a space
between “se” and the opening strong tag around currentUrl, preserving the rest
of the message unchanged.
packages/i18n/src/locales/ms-MY.i18n.json-1390-1390 (1)

1390-1390: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add spaces before the interpolated limits.

Both strings render ialah{{limit}}. Add a space before {{limit}}.

Also applies to: 1475-1475

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/ms-MY.i18n.json` at line 1390, Update the locale
entries “Max_length_is” and the corresponding string at the referenced second
occurrence so the Malay text includes a space between “ialah” and the
“{{limit}}” interpolation. Preserve the existing translation and placeholder
unchanged.
packages/i18n/src/locales/cs.i18n.json-2992-2992 (1)

2992-2992: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Repair the malformed <strong> markup.

The string opens <strong> several times without closing the earlier tags. Use balanced markup around settingName, configuredUrl, and currentUrl.

Proposed fix
-  "The_setting_s_is_configured_to_s_and_you_are_accessing_from_s": "<strong>Hodnota nastavení<strong>{{settingName}}<strong> je <strong>{{configuredUrl}}</strong>. Přistupujete z <strong>{{currentUrl}}</strong>!",
+  "The_setting_s_is_configured_to_s_and_you_are_accessing_from_s": "<strong>Hodnota nastavení {{settingName}}</strong> je <strong>{{configuredUrl}}</strong>. Přistupujete z <strong>{{currentUrl}}</strong>!",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/cs.i18n.json` at line 2992, Update the localized
string value for The_setting_s_is_configured_to_s_and_you_are_accessing_from_s
to use balanced strong tags around settingName, configuredUrl, and currentUrl,
removing the unmatched opening tags while preserving the Czech text and
interpolation placeholders.
packages/i18n/src/locales/nn.i18n.json-3042-3042 (1)

3042-3042: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve spaces around migrated placeholders.

These entries render without required spaces. Examples include e-poster:<value>, Maks lengde er<limit>, and fra<roomName>. Add the literal spaces that separate each placeholder from the surrounding text.

Proposed fix
-  "Mail_Message_Invalid_emails": "Du har oppgitt en eller flere ugyldige e-poster:{{emails}}",
+  "Mail_Message_Invalid_emails": "Du har oppgitt en eller flere ugyldige e-poster: {{emails}}",
-  "Mail_Messages_Subject": "Her er en valgt del av{{roomName}} meldinger",
+  "Mail_Messages_Subject": "Her er en valgt del av {{roomName}} meldinger",
-  "Max_length_is": "Maks lengde er{{limit}}",
+  "Max_length_is": "Maks lengde er {{limit}}",
-  "Min_length_is": "Min lengde er{{limit}}",
+  "Min_length_is": "Min lengde er {{limit}}",
-  "The_user_will_be_removed_from_s": "Brukeren blir fjernet fra{{roomName}}",
+  "The_user_will_be_removed_from_s": "Brukeren blir fjernet fra {{roomName}}",
-  "The_user_wont_be_able_to_type_in_s": "Brukeren kan ikke skrive inn{{roomName}}",
+  "The_user_wont_be_able_to_type_in_s": "Brukeren kan ikke skrive inn {{roomName}}",
-  "User_has_been_removed_from_s": "Brukeren er fjernet fra{{roomName}}",
+  "User_has_been_removed_from_s": "Brukeren er fjernet fra {{roomName}}",

Also applies to: 3048-3048, 3107-3107, 3291-3291, 4690-4691, 4977-4977

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/nn.i18n.json` at line 3042, Update the affected
Norwegian locale entries, including Mail_Message_Invalid_emails and the
additional listed keys, to add literal spaces between surrounding text and
migrated placeholders. Preserve the placeholder names and all other translations
unchanged.
packages/i18n/src/locales/cy.i18n.json-2213-2213 (1)

2213-2213: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Correct the removal wording.

Defnyddiwyd means “was used”. The rendered message does not say that the user was removed. Use the same removal terminology as the related entry at Line 2073.

Proposed fix
-  "User_has_been_removed_from_s": "Defnyddiwyd y defnyddiwr o {{roomName}}",
+  "User_has_been_removed_from_s": "Mae'r defnyddiwr wedi cael ei ddileu o {{roomName}}",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/cy.i18n.json` at line 2213, Update the Welsh
translation value for User_has_been_removed_from_s to use the removal
terminology from the related entry at line 2073, replacing the incorrect
“Defnyddiwyd” wording while preserving the {{roomName}} placeholder.
packages/i18n/src/locales/cy.i18n.json-1353-1353 (1)

1353-1353: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use the Welsh term for email addresses.

negeseuon e-bost means email messages. This key reports invalid email addresses. Replace it with cyfeiriadau e-bost.

Proposed fix
-  "Mail_Message_Invalid_emails": "Rydych wedi darparu un neu fwy o negeseuon e-bost annilys: {{emails}}",
+  "Mail_Message_Invalid_emails": "Rydych wedi darparu un neu fwy o gyfeiriadau e-bost annilys: {{emails}}",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/cy.i18n.json` at line 1353, Update the Welsh
translation for Mail_Message_Invalid_emails to use “cyfeiriadau e-bost” instead
of “negeseuon e-bost,” while preserving the existing {{emails}} placeholder and
message meaning.
packages/i18n/src/locales/cy.i18n.json-2074-2074 (1)

2074-2074: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve the “in” relation in the translation.

The key says “type in {{roomName}}”. The current text says “type {{roomName}}”. Add the Welsh preposition before the placeholder.

Proposed fix
-  "The_user_wont_be_able_to_type_in_s": "Ni fydd y defnyddiwr yn gallu deipio {{roomName}}",
+  "The_user_wont_be_able_to_type_in_s": "Ni fydd y defnyddiwr yn gallu deipio yn {{roomName}}",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/cy.i18n.json` at line 2074, Update the Welsh
translation for The_user_wont_be_able_to_type_in_s to include the appropriate
preposition meaning “in” immediately before the {{roomName}} placeholder,
preserving the existing sentence structure.
packages/i18n/src/locales/cy.i18n.json-2072-2072 (1)

2072-2072: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use the Welsh term for a configuration setting.

lleoliad means “location”. The key describes a setting, so use a setting term such as gosodiad in the message.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/cy.i18n.json` at line 2072, Update the Welsh
translation value for
“The_setting_s_is_configured_to_s_and_you_are_accessing_from_s” to use
“gosodiad” instead of “lleoliad”, preserving the existing interpolation
placeholders and HTML markup.
packages/i18n/src/locales/da.i18n.json-2034-2034 (1)

2034-2034: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve spacing around interpolated values.

These translations place the named values directly after punctuation or words. The rendered text can become e-mails:address, er10, or fraGeneral. Add literal separators before the placeholders.

Proposed fix
-  "Mail_Message_Invalid_emails": "Du har angivet en eller flere ugyldige e-mails:{{emails}}",
+  "Mail_Message_Invalid_emails": "Du har angivet en eller flere ugyldige e-mails: {{emails}}",

-  "Min_length_is": "Min længde er{{limit}}",
+  "Min_length_is": "Min længde er {{limit}}",

-  "The_user_will_be_removed_from_s": "Brugeren vil blive fjernet fra{{roomName}}",
+  "The_user_will_be_removed_from_s": "Brugeren vil blive fjernet fra {{roomName}}",

-  "User_has_been_removed_from_s": "Bruger er blevet fjernet fra{{roomName}}",
+  "User_has_been_removed_from_s": "Bruger er blevet fjernet fra {{roomName}}",

Also applies to: 2192-2192, 3087-3087, 3303-3303

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/da.i18n.json` at line 2034, Update the affected
Danish translation entries, including Mail_Message_Invalid_emails and the
entries at the referenced locations, to add literal spaces before each
interpolated placeholder where punctuation or text currently runs directly into
the value. Preserve the existing wording and placeholder names while ensuring
rendered output separates labels and values.
packages/i18n/src/locales/de-AT.i18n.json-1390-1390 (1)

1390-1390: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve the separator before {{limit}} in all length messages.

The interpolation migration removed the space between the label and the value.

  • packages/i18n/src/locales/de-AT.i18n.json#L1390-L1390: change to Maximale Länge ist {{limit}}.
  • packages/i18n/src/locales/de-AT.i18n.json#L1474-L1474: change to Min. Länge ist {{limit}}.
  • packages/i18n/src/locales/pt.i18n.json#L1733-L1733: change to O comprimento mínimo é {{limit}}.
  • packages/i18n/src/locales/ro.i18n.json#L1388-L1388: change to Lungimea maximă este {{limit}}.
  • packages/i18n/src/locales/ro.i18n.json#L1473-L1473: change to Lungimea minimă este {{limit}}.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/de-AT.i18n.json` at line 1390, Restore the missing
space before {{limit}} in all length messages: update
packages/i18n/src/locales/de-AT.i18n.json lines 1390-1390 and 1474-1474,
packages/i18n/src/locales/pt.i18n.json lines 1733-1733, and
packages/i18n/src/locales/ro.i18n.json lines 1388-1388 and 1473-1473, preserving
the specified translated wording and separator.
packages/i18n/src/locales/sk-SK.i18n.json-1361-1361 (1)

1361-1361: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add separators around the interpolated values.

These entries place named values directly after punctuation or words. The rendered text can become :address, správRoom, je10, or zGeneral. Add the required spaces in the Slovak strings.

Proposed fix
-  "Mail_Message_Invalid_emails": "Poslali ste jeden alebo viac neplatných e-mailov:{{emails}}",
+  "Mail_Message_Invalid_emails": "Poslali ste jeden alebo viac neplatných e-mailov: {{emails}}",
-  "Mail_Messages_Subject": "Tu je vybratá časť správ{{roomName}}",
+  "Mail_Messages_Subject": "Tu je vybratá časť správ {{roomName}}",
-  "Max_length_is": "Maximálna dĺžka je{{limit}}",
+  "Max_length_is": "Maximálna dĺžka je {{limit}}",
-  "Min_length_is": "Minimálna dĺžka je{{limit}}",
+  "Min_length_is": "Minimálna dĺžka je {{limit}}",
-  "The_user_will_be_removed_from_s": "Používateľ bude odstránený z{{roomName}}",
+  "The_user_will_be_removed_from_s": "Používateľ bude odstránený z {{roomName}}",
-  "The_user_wont_be_able_to_type_in_s": "Používateľ nebude môcť zadať{{roomName}}",
+  "The_user_wont_be_able_to_type_in_s": "Používateľ nebude môcť zadať {{roomName}}",
-  "User_has_been_removed_from_s": "Používateľ bol odstránený z{{roomName}}",
+  "User_has_been_removed_from_s": "Používateľ bol odstránený z {{roomName}}",

This finding is based on the supplied final locale strings and line-range change details.

Also applies to: 1366-1366, 1394-1394, 1478-1478, 2080-2081, 2220-2220

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/sk-SK.i18n.json` at line 1361, Update the affected
Slovak locale entries, including Mail_Message_Invalid_emails and the additional
referenced entries, to add spaces around each interpolated named value where
needed. Ensure rendered text separates punctuation or surrounding words from
placeholders, producing forms like “: address”, “správ Room”, “je 10”, and “z
General” without changing the translations or placeholder names.
packages/i18n/src/locales/sl-SI.i18n.json-1356-1356 (1)

1356-1356: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Remove the duplicate space after {{roomName}}.

The subject contains two spaces before sporočil. This produces extra whitespace in the rendered text.

Proposed fix
-  "Mail_Messages_Subject": "Tukaj je izbran delež {{roomName}}  sporočil",
+  "Mail_Messages_Subject": "Tukaj je izbran delež {{roomName}} sporočil",

This finding is based on the supplied final locale string.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/sl-SI.i18n.json` at line 1356, Remove the extra
space after the {{roomName}} interpolation in the Mail_Messages_Subject locale
string, leaving exactly one space before “sporočil”.
packages/i18n/src/locales/sr.i18n.json-312-312 (1)

312-312: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Remove the space before the closing apostrophe.

The current message renders as Канал '#name ' већ постоји.. Keep the apostrophes directly around channelName.

Proposed fix
-  "Channel_already_exist": "Канал '#{{channelName}} ' већ постоји.",
+  "Channel_already_exist": "Канал '#{{channelName}}' већ постоји.",

This finding is based on the supplied final locale string.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/sr.i18n.json` at line 312, Update the
Channel_already_exist locale string so the channelName interpolation has no
trailing space before the closing apostrophe, while preserving the surrounding
Serbian text and apostrophes.
packages/i18n/src/locales/sq.i18n.json-398-398 (1)

398-398: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use matching quotation marks around channelName.

The current message renders as Kanali "#name 'ekziston.. The opening double quote and closing apostrophe do not match.

Proposed fix
-  "Channel_already_exist": "Kanali \"#{{channelName}} 'ekziston.",
+  "Channel_already_exist": "Kanali \"#{{channelName}}\" ekziston.",

This finding is based on the supplied final locale string.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/sq.i18n.json` at line 398, Update the
Channel_already_exist translation so the channelName placeholder is enclosed by
matching quotation marks, replacing the mismatched closing apostrophe while
preserving the rest of the Albanian message.
packages/i18n/src/locales/el.i18n.json-1393-1393 (1)

1393-1393: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add a space before {{limit}}.

The current strings render as Το μέγιστο μήκος είναι10 and Το ελάχιστο μήκος είναι3. Add a space before the placeholder in both messages.

Proposed fix
-  "Max_length_is": "Το μέγιστο μήκος είναι{{limit}}",
+  "Max_length_is": "Το μέγιστο μήκος είναι {{limit}}",
-  "Min_length_is": "Το ελάχιστο μήκος είναι{{limit}}",
+  "Min_length_is": "Το ελάχιστο μήκος είναι {{limit}}",

Also applies to: 1478-1478

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/el.i18n.json` at line 1393, Update the Greek locale
messages Max_length_is and Min_length_is to include a space between the
translated text and the {{limit}} placeholder, so rendered values do not
concatenate with the number.
packages/i18n/src/locales/eo.i18n.json-1471-1471 (1)

1471-1471: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Correct the Esperanto minimum-length translation.

Mia longeco means “my length,” not “minimum length.” Use the repository-approved Esperanto wording, for example Minimuma longo estas {{limit}}, with a space before the placeholder.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/eo.i18n.json` at line 1471, Update the
"Min_length_is" entry in eo.i18n.json to use the repository-approved Esperanto
minimum-length wording, such as “Minimuma longo estas {{limit}}”, including the
required space before the placeholder.
packages/i18n/src/locales/eo.i18n.json-1354-1354 (1)

1354-1354: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add spaces before named interpolation values in the affected eo translations.

packages/i18n/src/locales/eo.i18n.json currently renders these values without separators, producing output such as :alice, de#room, estas5, and tajpi@room. Add the required spaces for {{emails}}, {{roomName}}, and {{limit}} in these entries, and ensure callers pass raw values for the interpolation.

Also applies to lines 1359, 1387, 2074-2075, and 2214.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/eo.i18n.json` at line 1354, Add spaces before the
named interpolation placeholders in the affected Esperanto translations:
Mail_Message_Invalid_emails ({{emails}}), the entries using {{roomName}} at the
referenced locations, and the entry using {{limit}}. Update the corresponding
callers to pass raw interpolation values so the translation-provided spacing
produces outputs such as “: alice”, “de `#room`”, “estas 5”, and “tajpi `@room`”.
packages/i18n/src/locales/es.i18n.json-2361-2361 (1)

2361-2361: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Correct the Spanish placeholder placement.

With roomName = "general", this renders as de general mensajes, which is not valid Spanish. Move the placeholder after mensajes.

Proposed fix
-  "Mail_Messages_Subject": "Aquí hay una parte seleccionada de {{roomName}} mensajes",
+  "Mail_Messages_Subject": "Aquí tienes una selección de mensajes de {{roomName}}",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/es.i18n.json` at line 2361, Update the
Mail_Messages_Subject translation so the {{roomName}} placeholder appears after
“mensajes,” producing the Spanish word order “... mensajes de {{roomName}}”
while preserving the existing placeholder name.
packages/i18n/src/locales/fa.i18n.json-1633-1633 (1)

1633-1633: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add whitespace around interpolated values.

At Line 1633 and Line 1720, {{limit}} is joined to the preceding word. Lines 1954-1957 join multiple placeholders to surrounding words. Line 2842 joins {{users}} to از. The rendered text will contain values such as طول10 and ازAlice.

Add spaces around each placeholder.

Proposed fix
-  "Max_length_is": "حداکثر طول{{limit}} است",
+  "Max_length_is": "حداکثر طول {{limit}} است",
-  "Min_length_is": "طول حداقل{{limit}} است",
+  "Min_length_is": "طول حداقل {{limit}} است",
-  "Prune_Warning_after": "این همه{{items}} در{{roomName}} پس از{{fromDate}} حذف خواهد شد.",
+  "Prune_Warning_after": "این همه {{items}} در {{roomName}} پس از {{fromDate}} حذف خواهد شد.",
-  "Prune_Warning_all": "این همه{{items}} را در{{roomName}} حذف می کند!",
+  "Prune_Warning_all": "این همه {{items}} را در {{roomName}} حذف می کند!",
-  "Prune_Warning_before": "این همه{{items}} را در{{roomName}} قبل از{{toDate}} حذف می کند.",
+  "Prune_Warning_before": "این همه {{items}} را در {{roomName}} قبل از {{toDate}} حذف می کند.",
-  "Prune_Warning_between": "این همه{{items}} در{{roomName}} بین{{fromDate}} و{{toDate}} حذف خواهد شد.",
+  "Prune_Warning_between": "این همه {{items}} در {{roomName}} بین {{fromDate}} و {{toDate}} حذف خواهد شد.",
-  "if_they_are_from": "(اگر از{{users}} هستند)",
+  "if_they_are_from": "(اگر از {{users}} هستند)",

Also applies to: 1720-1720, 1954-1957, 2842-2842

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/fa.i18n.json` at line 1633, Update the affected
Persian locale entries at the keys corresponding to lines 1633, 1720, 1954-1957,
and 2842 so every interpolated placeholder has surrounding whitespace, including
placeholders adjacent to words or other placeholders. Preserve the existing
translation text and placeholder names while ensuring rendered values are
separated clearly.
packages/i18n/src/locales/ta-IN.i18n.json-1388-1388 (1)

1388-1388: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Separate {{limit}} from the preceding text in all affected locale entries.

  • packages/i18n/src/locales/ta-IN.i18n.json#L1388-L1388: add a separator before {{limit}} in Max_length_is.
  • packages/i18n/src/locales/ta-IN.i18n.json#L1473-L1473: add a separator before {{limit}} in Min_length_is.
  • packages/i18n/src/locales/tr.i18n.json#L1667-L1667: add a separator before {{limit}} in Max_length_is.
  • packages/i18n/src/locales/tr.i18n.json#L1758-L1758: add a separator before {{limit}} in Min_length_is.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/ta-IN.i18n.json` at line 1388, Separate the
{{limit}} placeholder from the preceding text in the Max_length_is and
Min_length_is locale entries: update packages/i18n/src/locales/ta-IN.i18n.json
lines 1388 and 1473, and packages/i18n/src/locales/tr.i18n.json lines 1667 and
1758, by adding the appropriate separator before the placeholder.
packages/i18n/src/locales/ta-IN.i18n.json-1684-1686 (1)

1684-1686: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Correct the placeholder roles in the pruning warnings.

The current text uses {{items}} as the location and places date values where the deleted items should appear. Keep {{roomName}} as the location, {{items}} as the deleted content, and {{fromDate}}/{{toDate}} as date bounds.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/ta-IN.i18n.json` around lines 1684 - 1686, The
Prune_Warning_all, Prune_Warning_before, and Prune_Warning_between translations
use the placeholders in the wrong roles. Keep roomName as the location, items as
the deleted content, and use fromDate/toDate only for their respective date
bounds while preserving the Tamil wording.
packages/i18n/src/locales/th-TH.i18n.json-1355-1355 (1)

1355-1355: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Translate the remaining English word in Mail_Messages_Subject.

This Thai message uses messages, while the adjacent locale entry uses ข้อความ. Replace the English word to avoid mixed-language output.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/th-TH.i18n.json` at line 1355, Update the
Mail_Messages_Subject translation to replace the remaining English “messages”
word with the established Thai equivalent “ข้อความ”, preserving the existing
interpolation and sentence structure.
packages/i18n/src/locales/hr.i18n.json-456-456 (1)

456-456: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fix the mismatched closing quote.

The string opens with " before {{channelName}} but closes with '. Users will see mismatched quotation marks.

Proposed fix
-  "Channel_already_exist": "Soba \"#{{channelName}}' već postoji.",
+  "Channel_already_exist": "Soba \"#{{channelName}}\" već postoji.",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/hr.i18n.json` at line 456, Update the
Channel_already_exist translation value so the interpolated channel name uses
matching quotation marks, replacing the mismatched closing apostrophe with the
intended double quote while preserving the surrounding Croatian text and
placeholder.
packages/i18n/src/locales/id.i18n.json-798-798 (1)

798-798: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add spaces around the interpolated values.

Several placeholders are adjacent to surrounding words. The rendered text will contain values such as kehttps://..., adalah5, or dariroom.

Add a space before each affected placeholder. Keep the placeholder names unchanged.

Proposed fix
-  "Do_you_want_to_change_to_s_question": "Apakah Anda ingin mengubah <strong>ke{{currentUrl}}?</strong>",
+  "Do_you_want_to_change_to_s_question": "Apakah Anda ingin mengubah <strong>ke {{currentUrl}}?</strong>",

-  "Mail_Message_Invalid_emails": "Anda telah disediakan email satu atau lebih valid:{{emails}}",
+  "Mail_Message_Invalid_emails": "Anda telah disediakan email satu atau lebih valid: {{emails}}",

-  "Mail_Messages_Subject": "Berikut adalah bagian yang terpilih dari pesan{{roomName}}",
+  "Mail_Messages_Subject": "Berikut adalah bagian yang terpilih dari pesan {{roomName}}",

-  "Max_length_is": "Panjang maks adalah{{limit}}",
+  "Max_length_is": "Panjang maks adalah {{limit}}",

-  "Min_length_is": "Panjang min adalah{{limit}}",
+  "Min_length_is": "Panjang min adalah {{limit}}",

-  "The_setting_s_is_configured_to_s_and_you_are_accessing_from_s": "<strong>Pengaturan{{settingName}}</strong> dikonfigurasi <strong>untuk{{configuredUrl}}</strong> dan Anda mengakses <strong>dari{{currentUrl}}!</strong>",
-  "The_user_will_be_removed_from_s": "pengguna akan dihapus dari{{roomName}}",
-  "The_user_wont_be_able_to_type_in_s": "Pengguna tidak akan dapat mengetikkan{{roomName}}",
+  "The_setting_s_is_configured_to_s_and_you_are_accessing_from_s": "<strong>Pengaturan {{settingName}}</strong> dikonfigurasi <strong>untuk {{configuredUrl}}</strong> dan Anda mengakses <strong>dari {{currentUrl}}!</strong>",
+  "The_user_will_be_removed_from_s": "pengguna akan dihapus dari {{roomName}}",
+  "The_user_wont_be_able_to_type_in_s": "Pengguna tidak akan dapat mengetikkan {{roomName}}",

-  "User_has_been_removed_from_s": "Pengguna telah dihapus dari{{roomName}}",
+  "User_has_been_removed_from_s": "Pengguna telah dihapus dari {{roomName}}",

Also applies to: 1354-1354, 1359-1359, 1387-1387, 1471-1471, 2070-2072, 2212-2212

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/id.i18n.json` at line 798, Update the affected
Indonesian translation entries, including Do_you_want_to_change_to_s_question
and the entries at the referenced locations, by adding spaces around each
interpolated placeholder that is adjacent to surrounding words. Preserve every
placeholder name and the existing translation meaning.
packages/i18n/src/locales/it.i18n.json-2565-2565 (1)

2565-2565: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve spaces around the HTML tags.

The rendered text concatenates impostazione with settingName and da with currentUrl. HTML tags do not add whitespace.

Proposed fix
-  "The_setting_s_is_configured_to_s_and_you_are_accessing_from_s": "L'impostazione<strong>{{settingName}}</strong> è configurata su <strong>{{configuredUrl}}</strong> e stai accedendo da<strong>{{currentUrl}}</strong>!",
+  "The_setting_s_is_configured_to_s_and_you_are_accessing_from_s": "L'impostazione <strong>{{settingName}}</strong> è configurata su <strong>{{configuredUrl}}</strong> e stai accedendo da <strong>{{currentUrl}}</strong>!",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/it.i18n.json` at line 2565, Update the Italian
translation value for
“The_setting_s_is_configured_to_s_and_you_are_accessing_from_s” to include
explicit spaces before and after the <strong> tags where needed, ensuring the
rendered text separates “impostazione” from settingName and “da” from
currentUrl.
packages/i18n/src/locales/it.i18n.json-2107-2107 (1)

2107-2107: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add the missing space between the date placeholders.

Line 2107 renders {{fromDate}}e without a space. This produces malformed Italian text.

Proposed fix
-  "Prune_Warning_between": "Questo cancellerà tutto {{items}} in {{roomName}} tra {{fromDate}}e {{toDate}}.",
+  "Prune_Warning_between": "Questo cancellerà tutto {{items}} in {{roomName}} tra {{fromDate}} e {{toDate}}.",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/i18n/src/locales/it.i18n.json` at line 2107, Update the
Prune_Warning_between translation so the {{fromDate}} and {{toDate}}
placeholders are separated by a space, preserving the rest of the Italian text
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/i18n/src/locales/ja.i18n.json`:
- Around line 2883-2885: Update the Japanese Prune_Warning_after,
Prune_Warning_all, and Prune_Warning_before translations so {{roomName}}
precedes {{items}} and the date placeholder clearly identifies the deletion
boundary rather than appearing as the deleted value. Preserve all existing
placeholders and warning meanings while matching the intended relationship and
ordering.

---

Minor comments:
In `@packages/i18n/src/locales/af.i18n.json`:
- Around line 1356-1361: Restore separators around named interpolation values in
the locale strings. In packages/i18n/src/locales/af.i18n.json lines 1356-1361,
also update Max_length_is, Min_length_is, and the room-removal strings at lines
1389, 1473, 2076-2077, and 2217; in packages/i18n/src/locales/az.i18n.json lines
1356-1361, also update lines 799, 1389, 1473, 2077-2079, and 2218; and in
packages/i18n/src/locales/be-BY.i18n.json lines 1376-1381, also update lines
2098-2100 and 2240. Add spacing after colons, around {{emails}} and {{limit}},
after closing <strong> tags, and before {{roomName}} wherever needed so
interpolated values do not concatenate with adjacent text or markup.

In `@packages/i18n/src/locales/bg.i18n.json`:
- Line 1353: Update the Bulgarian Mail_Message_Invalid_emails translation to
include a space between the colon and the {{emails}} interpolation, and apply
the same spacing correction to the additional affected translation entry so
interpolated content does not concatenate with surrounding text.

In `@packages/i18n/src/locales/bs.i18n.json`:
- Line 398: Update the Channel_already_exist translation to use matching
quotation marks around #{{channelName}}, replacing the mismatched closing single
quote while preserving the rest of the message.
- Line 2071: Update the Bosnian translation value for
The_setting_s_is_configured_to_s_and_you_are_accessing_from_s to insert a space
between “se” and the opening strong tag around currentUrl, preserving the rest
of the message unchanged.

In `@packages/i18n/src/locales/ca.i18n.json`:
- Line 3542: Update the Catalan translation value for
“The_user_s_will_be_removed_from_role_s” to use “del rol” instead of “de el
rol”, preserving the username and role placeholders.

In `@packages/i18n/src/locales/cs.i18n.json`:
- Line 2992: Update the localized string value for
The_setting_s_is_configured_to_s_and_you_are_accessing_from_s to use balanced
strong tags around settingName, configuredUrl, and currentUrl, removing the
unmatched opening tags while preserving the Czech text and interpolation
placeholders.

In `@packages/i18n/src/locales/cy.i18n.json`:
- Line 2213: Update the Welsh translation value for User_has_been_removed_from_s
to use the removal terminology from the related entry at line 2073, replacing
the incorrect “Defnyddiwyd” wording while preserving the {{roomName}}
placeholder.
- Line 1353: Update the Welsh translation for Mail_Message_Invalid_emails to use
“cyfeiriadau e-bost” instead of “negeseuon e-bost,” while preserving the
existing {{emails}} placeholder and message meaning.
- Line 2074: Update the Welsh translation for The_user_wont_be_able_to_type_in_s
to include the appropriate preposition meaning “in” immediately before the
{{roomName}} placeholder, preserving the existing sentence structure.
- Line 2072: Update the Welsh translation value for
“The_setting_s_is_configured_to_s_and_you_are_accessing_from_s” to use
“gosodiad” instead of “lleoliad”, preserving the existing interpolation
placeholders and HTML markup.

In `@packages/i18n/src/locales/da.i18n.json`:
- Line 2034: Update the affected Danish translation entries, including
Mail_Message_Invalid_emails and the entries at the referenced locations, to add
literal spaces before each interpolated placeholder where punctuation or text
currently runs directly into the value. Preserve the existing wording and
placeholder names while ensuring rendered output separates labels and values.

In `@packages/i18n/src/locales/de-AT.i18n.json`:
- Line 1390: Restore the missing space before {{limit}} in all length messages:
update packages/i18n/src/locales/de-AT.i18n.json lines 1390-1390 and 1474-1474,
packages/i18n/src/locales/pt.i18n.json lines 1733-1733, and
packages/i18n/src/locales/ro.i18n.json lines 1388-1388 and 1473-1473, preserving
the specified translated wording and separator.

In `@packages/i18n/src/locales/el.i18n.json`:
- Line 1393: Update the Greek locale messages Max_length_is and Min_length_is to
include a space between the translated text and the {{limit}} placeholder, so
rendered values do not concatenate with the number.

In `@packages/i18n/src/locales/eo.i18n.json`:
- Line 1471: Update the "Min_length_is" entry in eo.i18n.json to use the
repository-approved Esperanto minimum-length wording, such as “Minimuma longo
estas {{limit}}”, including the required space before the placeholder.
- Line 1354: Add spaces before the named interpolation placeholders in the
affected Esperanto translations: Mail_Message_Invalid_emails ({{emails}}), the
entries using {{roomName}} at the referenced locations, and the entry using
{{limit}}. Update the corresponding callers to pass raw interpolation values so
the translation-provided spacing produces outputs such as “: alice”, “de `#room`”,
“estas 5”, and “tajpi `@room`”.

In `@packages/i18n/src/locales/es.i18n.json`:
- Line 2361: Update the Mail_Messages_Subject translation so the {{roomName}}
placeholder appears after “mensajes,” producing the Spanish word order “...
mensajes de {{roomName}}” while preserving the existing placeholder name.

In `@packages/i18n/src/locales/fa.i18n.json`:
- Line 1633: Update the affected Persian locale entries at the keys
corresponding to lines 1633, 1720, 1954-1957, and 2842 so every interpolated
placeholder has surrounding whitespace, including placeholders adjacent to words
or other placeholders. Preserve the existing translation text and placeholder
names while ensuring rendered values are separated clearly.

In `@packages/i18n/src/locales/hr.i18n.json`:
- Line 456: Update the Channel_already_exist translation value so the
interpolated channel name uses matching quotation marks, replacing the
mismatched closing apostrophe with the intended double quote while preserving
the surrounding Croatian text and placeholder.

In `@packages/i18n/src/locales/id.i18n.json`:
- Line 798: Update the affected Indonesian translation entries, including
Do_you_want_to_change_to_s_question and the entries at the referenced locations,
by adding spaces around each interpolated placeholder that is adjacent to
surrounding words. Preserve every placeholder name and the existing translation
meaning.

In `@packages/i18n/src/locales/it.i18n.json`:
- Line 2565: Update the Italian translation value for
“The_setting_s_is_configured_to_s_and_you_are_accessing_from_s” to include
explicit spaces before and after the <strong> tags where needed, ensuring the
rendered text separates “impostazione” from settingName and “da” from
currentUrl.
- Line 2107: Update the Prune_Warning_between translation so the {{fromDate}}
and {{toDate}} placeholders are separated by a space, preserving the rest of the
Italian text unchanged.

In `@packages/i18n/src/locales/mn.i18n.json`:
- Line 1471: Update the “Min_length_is” translation in the Mongolian locale to
use the correct Mongolian label instead of “Min” and insert a space before the
{{limit}} placeholder.
- Line 732: Update the affected Mongolian locale strings, including
Custom_oauth_helper and the additional referenced entries, to preserve readable
whitespace around interpolated values and markup: add spaces after colons and
closing tags, and between Хэрэглэгч and {{roomName}}. Keep the existing
translations and interpolation tokens unchanged.

In `@packages/i18n/src/locales/ms-MY.i18n.json`:
- Line 1390: Update the locale entries “Max_length_is” and the corresponding
string at the referenced second occurrence so the Malay text includes a space
between “ialah” and the “{{limit}}” interpolation. Preserve the existing
translation and placeholder unchanged.

In `@packages/i18n/src/locales/nn.i18n.json`:
- Line 3042: Update the affected Norwegian locale entries, including
Mail_Message_Invalid_emails and the additional listed keys, to add literal
spaces between surrounding text and migrated placeholders. Preserve the
placeholder names and all other translations unchanged.

In `@packages/i18n/src/locales/sk-SK.i18n.json`:
- Line 1361: Update the affected Slovak locale entries, including
Mail_Message_Invalid_emails and the additional referenced entries, to add spaces
around each interpolated named value where needed. Ensure rendered text
separates punctuation or surrounding words from placeholders, producing forms
like “: address”, “správ Room”, “je 10”, and “z General” without changing the
translations or placeholder names.

In `@packages/i18n/src/locales/sl-SI.i18n.json`:
- Line 1356: Remove the extra space after the {{roomName}} interpolation in the
Mail_Messages_Subject locale string, leaving exactly one space before
“sporočil”.

In `@packages/i18n/src/locales/sq.i18n.json`:
- Line 398: Update the Channel_already_exist translation so the channelName
placeholder is enclosed by matching quotation marks, replacing the mismatched
closing apostrophe while preserving the rest of the Albanian message.

In `@packages/i18n/src/locales/sr.i18n.json`:
- Line 312: Update the Channel_already_exist locale string so the channelName
interpolation has no trailing space before the closing apostrophe, while
preserving the surrounding Serbian text and apostrophes.

In `@packages/i18n/src/locales/ta-IN.i18n.json`:
- Line 1388: Separate the {{limit}} placeholder from the preceding text in the
Max_length_is and Min_length_is locale entries: update
packages/i18n/src/locales/ta-IN.i18n.json lines 1388 and 1473, and
packages/i18n/src/locales/tr.i18n.json lines 1667 and 1758, by adding the
appropriate separator before the placeholder.
- Around line 1684-1686: The Prune_Warning_all, Prune_Warning_before, and
Prune_Warning_between translations use the placeholders in the wrong roles. Keep
roomName as the location, items as the deleted content, and use fromDate/toDate
only for their respective date bounds while preserving the Tamil wording.

In `@packages/i18n/src/locales/th-TH.i18n.json`:
- Line 1355: Update the Mail_Messages_Subject translation to replace the
remaining English “messages” word with the established Thai equivalent
“ข้อความ”, preserving the existing interpolation and sentence structure.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e1322b67-7114-4334-bb84-3f385d2669a7

📥 Commits

Reviewing files that changed from the base of the PR and between 0c5bcc9 and ca06a94.

📒 Files selected for processing (82)
  • apps/meteor/client/components/UrlChangeModal.tsx
  • apps/meteor/client/navbar/NavBarPagesGroup/actions/CreateChannelModal.tsx
  • apps/meteor/client/navbar/NavBarSettingsToolbar/UserMenu/EditStatusModal.tsx
  • apps/meteor/client/views/account/profile/AccountProfileForm.tsx
  • apps/meteor/client/views/admin/engagementDashboard/channels/ChannelsOverview.tsx
  • apps/meteor/client/views/admin/import/PrepareChannels.tsx
  • apps/meteor/client/views/admin/import/PrepareUsers.tsx
  • apps/meteor/client/views/admin/permissions/UsersInRole/hooks/useRemoveUserFromRole.tsx
  • apps/meteor/client/views/admin/settings/groups/OAuthGroupPage/OAuthGroupPage.tsx
  • apps/meteor/client/views/admin/users/AdminUserForm.tsx
  • apps/meteor/client/views/admin/users/UsersTable/UsersTable.tsx
  • apps/meteor/client/views/room/contextualBar/ExportMessages/ExportMessages.tsx
  • apps/meteor/client/views/room/contextualBar/PruneMessages/PruneMessagesWithData.tsx
  • apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useMuteUserAction.tsx
  • apps/meteor/client/views/room/hooks/useUserInfoActions/actions/useRemoveUserAction.tsx
  • apps/meteor/server/slashcommands/create/server.ts
  • packages/fuselage-ui-kit/src/blocks/VideoConferenceBlock/VideoConferenceBlock.tsx
  • packages/i18n/src/locales/af.i18n.json
  • packages/i18n/src/locales/ar.i18n.json
  • packages/i18n/src/locales/az.i18n.json
  • packages/i18n/src/locales/be-BY.i18n.json
  • packages/i18n/src/locales/bg.i18n.json
  • packages/i18n/src/locales/bs.i18n.json
  • packages/i18n/src/locales/ca.i18n.json
  • packages/i18n/src/locales/cs.i18n.json
  • packages/i18n/src/locales/cy.i18n.json
  • packages/i18n/src/locales/da.i18n.json
  • packages/i18n/src/locales/de-AT.i18n.json
  • packages/i18n/src/locales/de-IN.i18n.json
  • packages/i18n/src/locales/de.i18n.json
  • packages/i18n/src/locales/el.i18n.json
  • packages/i18n/src/locales/en.i18n.json
  • packages/i18n/src/locales/eo.i18n.json
  • packages/i18n/src/locales/es.i18n.json
  • packages/i18n/src/locales/fa.i18n.json
  • packages/i18n/src/locales/fi.i18n.json
  • packages/i18n/src/locales/fr.i18n.json
  • packages/i18n/src/locales/gl.i18n.json
  • packages/i18n/src/locales/he.i18n.json
  • packages/i18n/src/locales/hi-IN.i18n.json
  • packages/i18n/src/locales/hr.i18n.json
  • packages/i18n/src/locales/hu.i18n.json
  • packages/i18n/src/locales/id.i18n.json
  • packages/i18n/src/locales/it.i18n.json
  • packages/i18n/src/locales/ja.i18n.json
  • packages/i18n/src/locales/ka-GE.i18n.json
  • packages/i18n/src/locales/km.i18n.json
  • packages/i18n/src/locales/ko.i18n.json
  • packages/i18n/src/locales/ku.i18n.json
  • packages/i18n/src/locales/lo.i18n.json
  • packages/i18n/src/locales/lt.i18n.json
  • packages/i18n/src/locales/lv.i18n.json
  • packages/i18n/src/locales/mn.i18n.json
  • packages/i18n/src/locales/ms-MY.i18n.json
  • packages/i18n/src/locales/nb.i18n.json
  • packages/i18n/src/locales/nl.i18n.json
  • packages/i18n/src/locales/nn.i18n.json
  • packages/i18n/src/locales/pl.i18n.json
  • packages/i18n/src/locales/pt-BR.i18n.json
  • packages/i18n/src/locales/pt.i18n.json
  • packages/i18n/src/locales/ro.i18n.json
  • packages/i18n/src/locales/ru.i18n.json
  • packages/i18n/src/locales/sk-SK.i18n.json
  • packages/i18n/src/locales/sl-SI.i18n.json
  • packages/i18n/src/locales/sq.i18n.json
  • packages/i18n/src/locales/sr.i18n.json
  • packages/i18n/src/locales/sv.i18n.json
  • packages/i18n/src/locales/ta-IN.i18n.json
  • packages/i18n/src/locales/th-TH.i18n.json
  • packages/i18n/src/locales/tr.i18n.json
  • packages/i18n/src/locales/ug.i18n.json
  • packages/i18n/src/locales/uk.i18n.json
  • packages/i18n/src/locales/vi-VN.i18n.json
  • packages/i18n/src/locales/zh-HK.i18n.json
  • packages/i18n/src/locales/zh-TW.i18n.json
  • packages/i18n/src/locales/zh.i18n.json
  • packages/ui-client/src/components/CustomFieldsForm.tsx
  • packages/ui-client/src/components/GenericTable/hooks/useShowingResultsLabel.ts
  • packages/ui-client/src/components/Modal/GenericModal/withDoNotAskAgain.tsx
  • packages/ui-client/src/views/setupWizard/providers/SetupWizardProvider.tsx
  • packages/web-ui-registration/src/CMSPage.tsx
  • packages/web-ui-registration/src/ResetPassword/ResetPasswordPage.tsx

Comment thread packages/i18n/src/locales/ja.i18n.json Outdated
@codecov

codecov Bot commented Aug 3, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 44.44444% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.65%. Comparing base (4c37fbf) to head (7cdece0).
⚠️ Report is 18 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #41667      +/-   ##
===========================================
+ Coverage    68.62%   68.65%   +0.03%     
===========================================
  Files         4162     4162              
  Lines       158824   158822       -2     
  Branches     28151    28131      -20     
===========================================
+ Hits        108986   109041      +55     
+ Misses       44665    44606      -59     
- Partials      5173     5175       +2     
Flag Coverage Δ
e2e 58.95% <33.33%> (+0.05%) ⬆️
e2e-api 45.74% <ø> (ø)
unit 70.56% <54.54%> (+0.05%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

37 issues found across 82 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/i18n/src/locales/it.i18n.json">

<violation number="1" location="packages/i18n/src/locales/it.i18n.json:2107">
P3: The Italian Prune_Warning_between renders the two dates glued to the word "e" (e.g. "tra 03/05/2024e 04/05/2024") because there's no space between {{fromDate}} and "e". Since the migration now fixes the previously-broken placeholder substitution, this spacing glitch becomes user-visible in the prune confirmation. Consider adding a space: "tra {{fromDate}} e {{toDate}}."</violation>
</file>

<file name="packages/i18n/src/locales/tr.i18n.json">

<violation number="1" location="packages/i18n/src/locales/tr.i18n.json:1667">
P3: The Turkish max-length validation message renders the numeric limit directly adjacent to `uzunluk` (for example, `Maksimum uzunluk100`). Adding a space before `{{limit}}` keeps the dynamic value readable.</violation>

<violation number="2" location="packages/i18n/src/locales/tr.i18n.json:1758">
P3: The Turkish min-length validation message renders the numeric limit directly adjacent to `uzunluk` (for example, `Minimum uzunluk5`). Adding a space before `{{limit}}` keeps the dynamic value readable.</violation>
</file>

<file name="packages/i18n/src/locales/fr.i18n.json">

<violation number="1" location="packages/i18n/src/locales/fr.i18n.json:2323">
P3: French export subjects render with incorrect word order around the interpolated room name. Using `des messages de {{roomName}}` keeps the subject natural while preserving the new named placeholder.</violation>
</file>

<file name="packages/i18n/src/locales/ta-IN.i18n.json">

<violation number="1" location="packages/i18n/src/locales/ta-IN.i18n.json:1684">
P2: Tamil prune confirmations display the wrong entities and dates—for example, the `all` message says it deletes all `roomName` in `items`, while the date variants treat the item label as a date. Reordering the named placeholders preserves the call site's `{ items, roomName, fromDate, toDate }` semantics.</violation>
</file>

<file name="packages/i18n/src/locales/zh-HK.i18n.json">

<violation number="1" location="packages/i18n/src/locales/zh-HK.i18n.json:1708">
P2: The zh-HK prune confirmation renders the dynamic values in the wrong semantic slots: for example, `Prune_Warning_all` says it will delete all `{{roomName}}` in `{{items}}`, and the date variants treat dates as the deleted items. Reordering the placeholders to match the sentence meaning keeps the room, item type, and date information understandable.</violation>

<violation number="2" location="packages/i18n/src/locales/zh-HK.i18n.json:2102">
P3: The zh-HK mute warning says the user cannot type `{{roomName}}`, rather than cannot type in that room, so the rendered warning describes the wrong restriction. A wording such as `用户将无法在{{roomName}}中输入文字` preserves the source message’s meaning.</violation>
</file>

<file name="packages/i18n/src/locales/zh.i18n.json">

<violation number="1" location="packages/i18n/src/locales/zh.i18n.json:4204">
P2: Prune confirmation text reverses the values: it says the app will delete all room names in the file/message type instead of deleting files/messages in the room. Matching the English locale, place `{{roomName}}` before `{{items}}` in all four messages.</violation>

<violation number="2" location="packages/i18n/src/locales/zh.i18n.json:5577">
P3: The removal-success toast renders as `已从移除 <room> 中用户`, which is grammatically malformed and does not clearly state that the user was removed from the room. Since this entry is being migrated here, reordering it to `用户已从 {{roomName}} 中移除` would make the Chinese toast usable.</violation>
</file>

<file name="packages/i18n/src/locales/pt.i18n.json">

<violation number="1" location="packages/i18n/src/locales/pt.i18n.json:1733">
P3: Portuguese minimum-length validation renders the number directly against `é` (`é5`) because the migrated template omits the space before `{{limit}}`. Adding the space keeps the message readable and matches the English/base translation.</violation>
</file>

<file name="packages/i18n/src/locales/fa.i18n.json">

<violation number="1" location="packages/i18n/src/locales/fa.i18n.json:1633">
P3: The Persian validation message renders the numeric limit concatenated with the preceding word (`طول10`). Adding a space around the named interpolation would keep the user-facing message readable.</violation>

<violation number="2" location="packages/i18n/src/locales/fa.i18n.json:1954">
P3: The prune confirmation renders dynamic values glued to surrounding Persian words, such as `همهپیامها دراتاق`. Spaces around these interpolations would make the confirmation readable in Persian.</violation>

<violation number="3" location="packages/i18n/src/locales/fa.i18n.json:2842">
P3: The conditional prune suffix renders as `اگر ازAlice` instead of separating the user list from `از`. A space before `{{users}}` would preserve readable Persian output.</violation>
</file>

<file name="packages/i18n/src/locales/eo.i18n.json">

<violation number="1" location="packages/i18n/src/locales/eo.i18n.json:1354">
P3: The invalid-email validation message concatenates the colon and interpolated email list. Adding the missing space keeps the rendered Esperanto message readable.</violation>

<violation number="2" location="packages/i18n/src/locales/eo.i18n.json:1359">
P3: The exported-mail subject concatenates `de` with the room name. Including a space before `{{roomName}}` makes the generated subject readable.</violation>

<violation number="3" location="packages/i18n/src/locales/eo.i18n.json:1387">
P3: The maximum-length validation text runs the limit directly into `estas`. A space before `{{limit}}` is needed for readable validation feedback.</violation>

<violation number="4" location="packages/i18n/src/locales/eo.i18n.json:1471">
P3: The minimum-length validation text runs the limit directly into `estas`. Adding a space before `{{limit}}` keeps the rendered message readable.</violation>

<violation number="5" location="packages/i18n/src/locales/eo.i18n.json:2074">
P3: The removal confirmation concatenates `de` and the room name. Adding the missing space makes the room-specific message readable.</violation>

<violation number="6" location="packages/i18n/src/locales/eo.i18n.json:2075">
P3: The read-only-room warning concatenates `tajpi` and the room name. Adding a space before `{{roomName}}` avoids rendering text such as `tajpi#room`.</violation>

<violation number="7" location="packages/i18n/src/locales/eo.i18n.json:2214">
P3: The removal success toast concatenates `de` and the room name. Adding the missing space keeps the room-specific notification readable.</violation>
</file>

<file name="packages/i18n/src/locales/vi-VN.i18n.json">

<violation number="1" location="packages/i18n/src/locales/vi-VN.i18n.json:1446">
P3: Vietnamese users see the invalid-email value attached directly to the colon (`không hợp lệ:foo@example.com`), making the validation message poorly formatted. A space before `{{emails}}` would keep the interpolated value readable.</violation>

<violation number="2" location="packages/i18n/src/locales/vi-VN.i18n.json:1451">
P3: Exported-mail subjects in Vietnamese render the room name joined to the preceding word (`củaGeneral`), because `{{roomName}}` has no preceding space. Adding that space would preserve word boundaries around the dynamic room name.</violation>

<violation number="3" location="packages/i18n/src/locales/vi-VN.i18n.json:1479">
P3: Length validation messages render the numeric limit joined to `là` (`là10`), so the Vietnamese text has no word/value boundary. A space before `{{limit}}` would produce readable validation feedback.</violation>

<violation number="4" location="packages/i18n/src/locales/vi-VN.i18n.json:1563">
P3: Minimum-length validation renders the numeric limit joined to `là` (`là3`), which breaks Vietnamese word/value spacing. A space before `{{limit}}` would keep the dynamic value readable.</violation>

<violation number="5" location="packages/i18n/src/locales/vi-VN.i18n.json:2166">
P3: The remove-user modal renders the room name joined to `khỏi` (`khỏiGeneral`), producing malformed Vietnamese text. A space before `{{roomName}}` would preserve the expected word boundary.</violation>

<violation number="6" location="packages/i18n/src/locales/vi-VN.i18n.json:2167">
P3: The mute-user modal renders the room name joined to `gõ` (`gõGeneral`), which breaks Vietnamese word spacing. A space before `{{roomName}}` would make the dynamic room name readable.</violation>

<violation number="7" location="packages/i18n/src/locales/vi-VN.i18n.json:2309">
P3: The remove-user success toast renders the room name joined to `khỏi` (`khỏiGeneral`), producing malformed Vietnamese text. A space before `{{roomName}}` would preserve the expected word boundary.</violation>
</file>

<file name="packages/i18n/src/locales/lt.i18n.json">

<violation number="1" location="packages/i18n/src/locales/lt.i18n.json:1404">
P3: The invalid-email message renders the interpolated email list without a space after the colon, so validation errors are typographically joined to the dynamic value. Keeping a space before `{{emails}}` would make the Lithuanian message readable.</violation>

<violation number="2" location="packages/i18n/src/locales/lt.i18n.json:1409">
P3: The mail subject joins the room name to the preceding word (`pasirinkta#room`), making the generated subject difficult to read. A space before `{{roomName}}` would preserve the intended word boundary.</violation>

<violation number="3" location="packages/i18n/src/locales/lt.i18n.json:1437">
P3: The maximum-length validation message concatenates the number with the preceding word. Adding a space before `{{limit}}` would render the value as a separate, readable token.</violation>

<violation number="4" location="packages/i18n/src/locales/lt.i18n.json:1521">
P3: The minimum-length validation message concatenates the numeric limit with `yra`, so the dynamic value is not separated in the UI. A space before `{{limit}}` would fix the rendered text.</violation>

<violation number="5" location="packages/i18n/src/locales/lt.i18n.json:2124">
P3: The removal warning joins `{{roomName}}` to the preceding Lithuanian word, producing `iš#room` instead of a readable room reference. Adding a space before the interpolation would restore the word boundary.</violation>

<violation number="6" location="packages/i18n/src/locales/lt.i18n.json:2125">
P3: The mute warning joins `{{roomName}}` to the preceding word, so the rendered room reference is difficult to read. A space before the interpolation would preserve the intended word boundary.</violation>

<violation number="7" location="packages/i18n/src/locales/lt.i18n.json:2266">
P3: The success toast joins `{{roomName}}` to the preceding word, producing an unreadable room reference such as `iš#room`. Adding a space before the interpolation would make the toast readable.</violation>
</file>

<file name="packages/i18n/src/locales/hi-IN.i18n.json">

<violation number="1" location="packages/i18n/src/locales/hi-IN.i18n.json:3537">
P2: Hindi prune confirmations now substitute the `items`, room, and date values into the wrong positions because these translations changed placeholder names without preserving each locale's original positional order. The confirmation can say that a date is being deleted or that messages occur after a room name; preserving the old Hindi order while naming the placeholders keeps the rendered warning correct.</violation>
</file>

<file name="packages/i18n/src/locales/zh-TW.i18n.json">

<violation number="1" location="packages/i18n/src/locales/zh-TW.i18n.json:2824">
P2: The Traditional Chinese prune confirmation displays the wrong entity in each part of the warning: `items` is used as the date/position, `roomName` as the collection, and the date as the collection. Users can therefore see a misleading destructive-action confirmation. Reordering the named placeholders so the room is the container, the date is the boundary, and `items` is the deleted content would preserve the intended warning.</violation>
</file>

<file name="packages/i18n/src/locales/ja.i18n.json">

<violation number="1" location="packages/i18n/src/locales/ja.i18n.json:2883">
P2: The Japanese prune warning placeholders are in an order that changes the sentence meaning, so the destructive warning can read as if the date is being deleted instead of messages/files in a room. Reordering placeholders to `roomName -> date -> items` keeps it aligned with the interpolation data and the intent used in other locales.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/i18n/src/locales/ta-IN.i18n.json Outdated
Comment thread packages/i18n/src/locales/zh-HK.i18n.json Outdated
Comment thread packages/i18n/src/locales/zh.i18n.json Outdated
Comment thread packages/i18n/src/locales/hi-IN.i18n.json Outdated
Comment thread packages/i18n/src/locales/zh-TW.i18n.json Outdated
Comment thread packages/i18n/src/locales/lt.i18n.json Outdated
Comment thread packages/i18n/src/locales/lt.i18n.json Outdated
Comment thread packages/i18n/src/locales/lt.i18n.json Outdated
Comment thread packages/i18n/src/locales/lt.i18n.json Outdated
Comment thread packages/i18n/src/locales/lt.i18n.json Outdated
@tassoevan

Copy link
Copy Markdown
Member Author

Pushed 7d9ac1eb63 addressing the review comments — 35 locale files, no source changes. Two distinct classes, and they differ in an important way.

1. Placeholder slots — genuinely surfaced by this PR

ja, zh, zh-HK, zh-TW, hi-IN, ta-IN write the prune warnings in their own word order, but sprintf substitutes strictly by position. So the values were already landing in the wrong slots on develop. The positional migration preserved that faithfully — naming the placeholders is what made it legible:

ja  before:  {{items}}の{{roomName}}以降の{{fromDate}}が削除されます。
             → "The 2024/01/01 after general of messages will be deleted"
    after:   {{roomName}}の{{fromDate}}以降の{{items}}が削除されます。
             → "Messages in general from 2024/01/01 onward will be deleted"

Also fixed: the zh-HK mute warning read "cannot type <room>" rather than "cannot type in <room>", and the zh removal toast (已从移除 X 中用户) was malformed word order.

For zh-HK this was more than cosmetic. Repairing its fullwidth %s earlier in the PR turned a visibly-broken placeholder into a plausible-looking wrong value — worse than before, on a destructive-action confirmation. Worth a careful look from a reviewer who reads Chinese.

2. Spacing — pre-existing, not caused by this PR

Several comments attributed the missing spaces to the migration. That attribution is incorrect. Verified against develop:

develop:  "Max longo estas%s"
now:       "Max longo estas{{limit}}"

Byte-identical spacing. %s substituted fine before, so estas5 was already what users saw. The migration swapped the token in place and changed nothing about surrounding whitespace.

The bugs are real, though, and they live in strings this PR already owns — so rather than field them one at a time, I scanned every character adjacent to a placeholder across all 19 migrated keys × 68 locales and fixed all 111 in one pass. That covers locales nobody had reported yet: af, ar, bg, ca, da, de-AT, el, he, id, km, ku, mn, ms-MY, nn, ro, sk-SK, th-TH.

Deliberately left alone

  • az{{limit}}dir and {{roomName}}dən are legitimate copula and ablative suffixes, not missing spaces
  • ug — one scrambled string I can't verify; flagged for re-translation instead
  • <pre>{{url}} (219×), `#{{channelName}}` (57×), code fences, parens, and every script without inter-word spaces (CJK, Thai, Lao) — abutment is correct there and untouched

I also reverted four of my own over-corrections during this pass: sv and zh had symmetric %s-%s ranges I'd made asymmetric, th-TH's combining-mark case was inconsistent with its own untouched siblings, and ug is unverifiable.

Now guarded mechanically

Beyond missing-placeholders, two invariants hold across every locale and are cheap to re-run:

  1. In Prune_Warning_between, {{fromDate}} and {{toDate}} are adjacent — no other placeholder can sit between them
  2. The relative order of {{items}} and {{roomName}} is consistent across all four Prune_Warning_* keys within a locale

Both return 0 violations. Combined with missing-placeholders, the slot-mismapping class is now detectable without needing a native speaker per locale — which is the durable win here, given it went unnoticed for as long as these strings have existed.

Build 68/68 · lint 71/71 · typecheck 48/48 · tests 42/42.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 35 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/i18n/src/locales/ka-GE.i18n.json Outdated
Comment thread packages/i18n/src/locales/ug.i18n.json Outdated
Comment thread packages/i18n/src/locales/he.i18n.json Outdated
Comment thread packages/i18n/src/locales/zh.i18n.json Outdated
Comment thread packages/i18n/src/locales/he.i18n.json Outdated
@ggazzo

ggazzo commented Aug 4, 2026

Copy link
Copy Markdown
Member

/jira ARCH-2327

@ggazzo ggazzo added the stat: QA assured Means it has been tested and approved by a company insider label Aug 4, 2026
@dionisio-bot dionisio-bot Bot added the stat: ready to merge PR tested and approved waiting for merge label Aug 4, 2026
tassoevan and others added 10 commits August 4, 2026 21:17
Replace the deprecated `useTranslation` hook from `@rocket.chat/ui-contexts`
with the one from `react-i18next`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Replace the deprecated `useTranslation` hook from `@rocket.chat/ui-contexts`
with the one from `react-i18next`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Replace the deprecated `useTranslation` hook from `@rocket.chat/ui-contexts`
with the one from `react-i18next`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Replace the sprintf `%s` placeholder with i18next's `{{limit}}` named
interpolation across all 57 locales that define the key, and update the
six call sites accordingly.

Five of them were relying on the legacy positional-argument form provided
by `addSprinfToI18n`; the sixth already passed an explicit
`{ postProcess: 'sprintf', sprintf: [...] }` option, which is no longer
needed.

Also fixes zh-HK, which used a fullwidth `%s` (U+FF05) that sprintf never
matched, so the placeholder was rendered literally.

`{{limit}}` matches the existing convention for this shape, e.g.
`get-password-policy-maxLength-label` ("At most {{limit}} characters").

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Replace the sprintf `%s` placeholder with i18next's `{{limit}}` named
interpolation across all 57 locales that define the key, and drop the
`{ postProcess: 'sprintf', sprintf: [...] }` option from its single call
site.

Also fixes zh-HK and zh, which used a fullwidth `%s` (U+FF05) that
sprintf never matched, so the placeholder was rendered literally.

Mirrors the `Max_length_is` migration, keeping the sibling keys
consistent.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… interpolation

Replace the sprintf `%s` placeholder with i18next's `{{roomName}}` named
interpolation across all 58 locales that define the key, and update its
single call site to pass a named option instead of a positional argument.

`{{roomName}}` is the established name for this value and matches the
neighbouring `User__username__muted_in_room__roomName__` call in the same
hook.

Also fixes zh-HK, which used a fullwidth `%s` (U+FF05) that sprintf never
matched, so the placeholder was rendered literally.

Escaping is unaffected: the client i18next instance is configured with
`interpolation.escapeValue: false`, so the existing `escapeHTML` call
remains the sole escaping step.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…terpolation

Replace the sprintf `%s` placeholder with i18next's `{{roomName}}` named
interpolation across all 58 locales that define the key, and update its
single call site to pass a named option instead of a positional argument.

Also fixes two pre-existing translation bugs:

- es had `El usuario %s se eliminará de %s`, a copy-paste of the adjacent
  `The_user_s_will_be_removed_from_role_s`, which legitimately takes two
  placeholders. Since the call site supplies only the room name, Spanish
  users saw the room in the wrong slot followed by a literal `undefined`.
  Corrected to `El usuario se eliminará de {{roomName}}`, matching its
  sibling `User_has_been_removed_from_s`.
- zh-HK used a fullwidth `%s` (U+FF05) that sprintf never matched, so the
  placeholder was rendered literally.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…polation

Replace the sprintf `%s` placeholder with i18next's `{{roomName}}` named
interpolation across all 58 locales that define the key, and update its
single call site to pass a named option instead of a positional argument.

Also fixes zh-HK, which used a fullwidth `%s` (U+FF05) that sprintf never
matched, so the placeholder was rendered literally.

This clears the last sprintf usage from `useRemoveUserAction`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Replace the sprintf `%s` placeholder with i18next's `{{channelName}}` named
interpolation across all 59 locales that define the key, and update both
call sites — the client validator and the `/create` slash command — to pass
a named option. The server call keeps its `lng` option and simply drops
`postProcess`/`sprintf`.

`{{channelName}}` matches the two existing uses of that name, both of which
are `#`-prefixed exactly like this template.

Also fixes zh-HK, which used a fullwidth `%s` (U+FF05) that sprintf never
matched, so the placeholder was rendered literally.

Note the server i18next instance escapes interpolated values by default,
unlike sprintf. This is a no-op for channel names under the default
`UTF8_Channel_Names_Validation` regex (`[0-9a-zA-Z-_.]+`), and is
consistent with existing server-side named interpolation such as
`exportRoomMessagesToFile`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Replace the sprintf `%s` placeholder with i18next's `{{url}}` named
interpolation across all 57 locales that define the key, and update its
single call site to pass a named option instead of a positional argument.

`{{url}}` matches the existing convention for this value, e.g.
`Saved_new_url_site_is__url__` and `error-avatar-invalid-url`.

Also fixes three locales where the placeholder itself had been
transliterated and so was never matched by sprintf, leaving it rendered
literally:

- hi-IN used `%एस` (Devanagari)
- ta-IN used `% கள்` (Tamil)
- zh-HK used a fullwidth `%s` (U+FF05)

Escaping is unaffected: the client i18next instance is configured with
`interpolation.escapeValue: false`, so the result reaching
`DOMPurify.sanitize` is byte-identical to the sprintf output.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tassoevan and others added 14 commits August 4, 2026 21:17
…_accessing_from_s` to named interpolation

Replace the three sprintf `%s` placeholders with `{{settingName}}`,
`{{configuredUrl}}` and `{{currentUrl}}` across the 55 locales that carry a
well-formed translation, and update the call site to pass named options.

The mapping is positional, which is exactly behaviour-preserving: no locale
uses `%1$s`, so sprintf already substituted strictly left to right.

Drop the translation from three locales whose text cannot render the message
regardless of placeholder syntax, so they fall back to en. All three were
already broken before this change, and the `missing-placeholders` check now
reports them:

- th-TH was truncated mid-sentence, with only one of the three slots
- ta-IN had its markup shredded, leaving `%` and `s` orphaned across nested
  `<strong>` tags
- he had `%s` split into `%` … `S` by RTL mangling, leaving two slots

Escaping is unaffected: the client i18next instance sets
`interpolation.escapeValue: false`, so the string reaching
`DOMPurify.sanitize` is byte-identical to the sprintf output.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…d interpolation

Replace the sprintf `%s` placeholder with i18next's `{{currentUrl}}` named
interpolation across all 58 locales that define the key, and update its
single call site to pass a named option.

`{{currentUrl}}` is the same value the sibling
`The_setting_s_is_configured_to_s_and_you_are_accessing_from_s` already
interpolates in this component, so the two messages stay consistent. This
clears the last sprintf usage from `UrlChangeModal`.

Also fixes zh-HK, which used a fullwidth `%s` (U+FF05) that sprintf never
matched, so the placeholder was rendered literally.

Escaping is unaffected: the client i18next instance sets
`interpolation.escapeValue: false`, so the string reaching
`DOMPurify.sanitize` is byte-identical to the sprintf output.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Replace the three sprintf `%s` placeholders with `{{from}}`, `{{to}}` and
`{{total}}` across the 18 locales that define the key, and update all four
call sites to pass named options.

`{{total}}` rather than `{{count}}`: the sibling `Showing_current_of_total`
already uses `{{total}}` for this value, and `count` is i18next's
pluralization trigger, which this string does not want. It happens to work
today only because no plural-suffixed variants of the key exist.

The mapping is positional, which is exactly behaviour-preserving: no locale
uses `%1$s`, so sprintf already substituted strictly left to right. All 18
translations carry exactly three placeholders.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Replace the sprintf `%s` placeholder with i18next's `{{users}}` named
interpolation across all 57 locales that define the key, and update its
single call site to pass a named option.

Also fixes zh-HK, which used a fullwidth `%s` (U+FF05) that sprintf never
matched, so the placeholder was rendered literally.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Replace the two sprintf `%s` placeholders with `{{items}}` and
`{{roomName}}` across all 56 locales that define the key, and update its
single call site to pass named options.

All 56 translations carry exactly two placeholders, and the mapping is
positional, which is exactly behaviour-preserving: no locale uses `%1$s`,
so sprintf already substituted strictly left to right.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Replace the three sprintf `%s` placeholders with `{{items}}`, `{{roomName}}`
and `{{fromDate}}` across the 55 locales that carry a well-formed
translation, and update its single call site to pass named options.

Drop the ta-IN translation, which had four placeholders against the base
language's three. Because Tamil word order puts the object last, the values
already landed in the wrong slots and the surplus one rendered as
`undefined`; the text was broken before this change. It now falls back to
en, and the `missing-placeholders` check would otherwise report it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Replace the three sprintf `%s` placeholders with `{{items}}`, `{{roomName}}`
and `{{toDate}}` across the 55 locales that carry a well-formed translation,
and update its single call site to pass named options.

Drop the ku translation, which had four placeholders against the base
language's three, so the surplus one rendered as `undefined`. Its sibling
`Prune_Warning_after` is well formed, so this is an isolated error in one
string rather than a systematic problem with the locale. It now falls back
to en.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Replace the four sprintf `%s` placeholders with `{{items}}`, `{{roomName}}`,
`{{fromDate}}` and `{{toDate}}` across the 53 locales that carry a
well-formed translation, and update its single call site to pass named
options. This clears the last sprintf usage from `PruneMessagesWithData`.

Repair be-BY, whose third placeholder had been mangled into `% з` (a space
and a Cyrillic ze) inside the `паміж … і …` construction. Its slot order
matches the base language, so un-mangling it restores the intended text
rather than changing it.

Drop three translations that cannot render the message regardless of
placeholder syntax, so they fall back to en. All three were already broken:

- ja and ka-GE omit the room name entirely and reorder the remaining
  values, so dates were being rendered where the room name belongs
- mn likewise reorders, and its fourth placeholder is a bare `%`

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…amed interpolation

Replace the two sprintf `%s` placeholders with `{{username}}` and `{{role}}`
across all 25 locales that define the key, and update its single call site
to pass named options.

All 25 translations carry exactly two placeholders, and the mapping is
positional, which is exactly behaviour-preserving.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…polation

Replace the sprintf `%s` placeholder with i18next's `{{status}}` named
interpolation across all 6 locales that define the key, and update its
single call site to pass a named option.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Replace the sprintf `%s` placeholder with i18next's `{{roomName}}` named
interpolation across all 58 locales that define the key, and update its
single call site to pass a named option.

Also repairs two locales whose placeholder was never matched by sprintf and
so was rendered literally:

- sr had `% с`, with a Cyrillic es and a stray space, sitting exactly where
  the placeholder belongs; the space is restored ahead of it
- zh-HK used a fullwidth `%s` (U+FF05)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…olation

Replace the sprintf `%s` placeholder with i18next's `{{emails}}` named
interpolation across all 58 locales that define the key, and update its
single call site to pass a named option. This clears the last sprintf usage
from `ExportMessages`, and the last client call site that passes a literal
translation key.

Three sprintf usages remain in client code, none of which can be migrated
here because the key is supplied at runtime rather than written literally:
`ActionInputBase` and `useUserBanners` both translate a key and argument
array received from the server, and `TranslationContextMock` implements the
sprintf post-processor so Storybook mirrors the real provider.

Also repairs two locales whose placeholder was never matched by sprintf and
so was rendered literally:

- sr had `% с`, with a Cyrillic es and a stray space
- zh-HK used a fullwidth `%s` (U+FF05)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ions

Follow-up to the sprintf migration, addressing two classes of problem in the
translations it touched.

**Placeholder slots (ja, zh, zh-HK, zh-TW, hi-IN, ta-IN).** These locales
write the prune warnings in their own word order, but sprintf substitutes
strictly by position, so the values already landed in the wrong slots. The
positional migration preserved that faithfully; naming the placeholders is
what made it legible. The warnings variously announced that the date was
being deleted, or that all rooms in the message type were. Also corrects the
zh-HK mute warning, which read "cannot type <room>" rather than "cannot type
in <room>", and the zh removal toast, whose word order was malformed.

For zh-HK this was more than cosmetic: repairing its fullwidth `%s` turned a
visibly broken placeholder into a plausible-looking wrong value.

Two invariants now hold across every locale, checked mechanically: in
`Prune_Warning_between` the two dates are adjacent, and the relative order of
`items` and `roomName` is consistent across the whole family.

**Spacing (23 locales, 111 places).** A placeholder abutting the preceding
word or a colon, rendering `estas5` or `emails:foo@bar`. These are
pre-existing and unrelated to the migration — the spacing is byte-identical
to what `%s` had on develop — but they live in strings this change already
touches, so they are fixed here rather than left behind. Found by scanning
every character adjacent to a placeholder across all migrated keys and
locales, so the sweep covers cases not individually reported.

Left alone: `{{limit}}dir` and `{{roomName}}dən` in az, which are legitimate
copula and ablative suffixes, and one scrambled ug string. Abutment is also
expected and untouched for `<pre>{{url}}`, `` `#{{channelName}}` ``, and
scripts without inter-word spaces.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Corrects over-application of the previous spacing sweep, which assumed a
letter next to a placeholder always meant a missing space. Several scripts
attach grammatical affixes directly:

- he: `מ` is an inseparable "from" prefix, so `מ{{roomName}}` and
  `מ{{users}}` must stay closed up; a lone `מ` is not a word
- ar: the conjunction `و` is written attached, so `و{{toDate}}` is correct

Persian is unaffected and keeps its spaces: despite sharing the script, its
particles (`همه`, `در`, `از`, `بین`, and Persian `و`) are separate words.

Also fixes three issues the sweep did not reach:

- ug: the room name still ran into the following word; a space after it
  matches the neighbouring `The_user_will_be_removed_from_s`
- ka-GE: the ablative `-დან` was split as `- დან` in three strings, unlike
  the attached form already used by `Importer_From_Description`
- zh: the temporal clause trailed the deleted-content phrase (`… 于 X 后`),
  which reads awkwardly; it now precedes the container as it already does in
  zh-HK and zh-TW

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@tassoevan
tassoevan enabled auto-merge August 10, 2026 18:46
@tassoevan tassoevan added stat: QA assured Means it has been tested and approved by a company insider and removed stat: ready to merge PR tested and approved waiting for merge stat: QA assured Means it has been tested and approved by a company insider labels Aug 10, 2026
@dionisio-bot dionisio-bot Bot added the stat: ready to merge PR tested and approved waiting for merge label Aug 10, 2026
@tassoevan
tassoevan added this pull request to the merge queue Aug 10, 2026
Merged via the queue into develop with commit 93aa04b Aug 10, 2026
101 checks passed
@tassoevan
tassoevan deleted the refactor/i18n branch August 10, 2026 20:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stat: QA assured Means it has been tested and approved by a company insider stat: ready to merge PR tested and approved waiting for merge type: chore

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants