morphit/apps/web/scripts/i18n-translation-completeness-smoke.ts

1312 lines
120 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env tsx
/**
* i18n translation completeness smoke.
*
* Locale-parity (sister smoke i18n-locale-parity-smoke) checks
* STRUCTURAL parity: every key in en.json exists in every other
* locale. But it does NOT check that the values are actually
* translated — a locale can pass parity by simply copying the
* English value. That's what missed our 9 Part-104 fixes.
*
* This smoke catches the specific high-signal drift class:
* **a key translated by 7+ non-EN locales is still
* byte-identical to English in 1-2 locales.** When most of the
* world translated something but a couple didn't, those couple
* are almost certainly genuine misses, not legitimate loanwords.
*
* (Lower-coverage cases — 3+ locales not translating — are
* usually legitimate loanwords adopted into multiple locales'
* tech-speak, e.g. "Live", "Filter", "Region", "Privacy" in
* German/Italian. Those go into the explicit allow-list.)
*
* The allow-list is the project's translation policy: each
* entry says "this English-spelled value is the correct
* rendering in locale X because the locale's word happens to
* be identical (e.g. Region in German, Transaction in French)
* OR because the term is a universally-adopted loanword
* (e.g. permlink, custom_json)."
*/
// Import SUPPORTED_LOCALES so the "expected count" assertion below
// auto-tracks the registry instead of pinning a literal "10". When a
// PLANNED locale graduates to SUPPORTED, this assertion updates with
// no code change.
import { SUPPORTED_LOCALES } from '../src/lib/i18n/locales';
import { readFileSync, readdirSync } from 'node:fs';
import { join } from 'node:path';
const REPO = join(import.meta.dirname, '..');
const LOC_DIR = join(REPO, 'src/lib/i18n/locales');
type JsonObj = { [k: string]: unknown };
function flattenStrings(d: unknown, prefix = ''): Map<string, string> {
const out = new Map<string, string>();
if (typeof d === 'string') {
out.set(prefix, d);
return out;
}
if (typeof d !== 'object' || d === null) return out;
for (const [k, v] of Object.entries(d as JsonObj)) {
const path = prefix ? `${prefix}.${k}` : k;
for (const [sk, sv] of flattenStrings(v, path)) out.set(sk, sv);
}
return out;
}
const locales = readdirSync(LOC_DIR)
.filter((f) => f.endsWith('.json'))
.map((f) => f.replace(/\.json$/, ''))
.sort();
const data = new Map<string, Map<string, string>>();
for (const loc of locales) {
const obj = JSON.parse(readFileSync(join(LOC_DIR, `${loc}.json`), 'utf-8')) as JsonObj;
data.set(loc, flattenStrings(obj));
}
const en = data.get('en')!;
const nonEn = locales.filter((l) => l !== 'en');
// ─── Allow-list ────────────────────────────────────────────
//
// Each entry: a (key, locale) pair where the locale's value
// being byte-identical to English is the CORRECT rendering.
// Three reasons admitted:
// (a) "same-word": the locale's word for this concept is
// spelled identically to English (e.g. "Region" in
// German is also "Region", "Transaction" in French is
// also "Transaction").
// (b) "loanword": the locale has adopted the English term
// as the standard usage in this domain, even though a
// native term exists (e.g. "Live" in German tech UIs,
// "Privacy" in Italian privacy-policy contexts).
// (c) "invariant": the value is a brand name, technical
// identifier, code-string, or universal acronym.
//
// New entries MUST cite which (a/b/c) applies.
interface AllowEntry { key: string; locale: string; reason: string }
const ALLOW_LIST: AllowEntry[] = [
// ─── v1.9.15 (t.txt, Ken) footer column header "SUPPORT" → German "Support"
// is the standard loanword for a help/support section in tech UIs (native
// "Unterstützung"/"Hilfe" read oddly as a footer nav label), so it is
// byte-identical to EN.
{ key: 'footer.col_support', locale: 'de', reason: '(b) "Support" is the standard German loanword for a help/support nav section; byte-identical to EN' },
// ─── v1.9.5 (Ken) blog "## Details:" heading — German uses "Details" (the
// standard loanword; native "Einzelheiten" is rarer in tech UIs), so it is
// byte-identical to EN. It only tripped the heuristic after the heading was
// changed from all-caps bold "DETAILS" to title-case "Details:".
{ key: 'syndicate.order_post.details', locale: 'de', reason: '(b) "Details" is the standard German loanword; byte-identical to EN only after the all-caps→title-case change' },
// ─── post-order amount hint: the value "{amount} {fiat} (≈ {usd})" is
// ENTIRELY interpolation placeholders + a math symbol (≈) + ASCII
// parens — there is no translatable word, so byte-identity with EN
// is correct for the native-translation locales (de/es/fr). zh-CN/HK
// legitimately differ (full-width parens ); it/pl/ru/fa are
// policy-fallback (skipped above). The smoke's "pure format" skip
// (no [a-zA-Z]) misses this because the placeholder NAMES contain
// letters. (b) invariant.
{ key: 'post_order.form.amount_entered_usd_hint', locale: 'de', reason: '(b) pure interpolation placeholders + math symbol (≈) — no translatable text' },
{ key: 'post_order.form.amount_entered_usd_hint', locale: 'es', reason: '(b) pure interpolation placeholders + math symbol (≈) — no translatable text' },
{ key: 'post_order.form.amount_entered_usd_hint', locale: 'fr', reason: '(b) pure interpolation placeholders + math symbol (≈) — no translatable text' },
// ─── cp321 explorer-account Public Keys card: the four Blurt key-role
// names (Owner / Active / Posting / Memo) are technical identifiers
// kept in English in EVERY locale by project convention — exactly as
// backup_keys_panel.role.* does ("Owner-Schlüssel" / "Clave Owner" /
// etc. keep the role word English and translate only "key"). Here the
// label IS just the bare role word (under a translated "Public Keys"
// heading), so it is byte-identical to English by design, not a miss.
{ key: 'explorer.account.key_owner', locale: 'de', reason: '(c) Blurt key-role identifier kept in English by project convention (mirrors backup_keys_panel.role.*)' },
{ key: 'explorer.account.key_owner', locale: 'es', reason: '(c) Blurt key-role identifier kept in English by project convention (mirrors backup_keys_panel.role.*)' },
{ key: 'explorer.account.key_owner', locale: 'fr', reason: '(c) Blurt key-role identifier kept in English by project convention (mirrors backup_keys_panel.role.*)' },
{ key: 'explorer.account.key_active', locale: 'de', reason: '(c) Blurt key-role identifier kept in English by project convention (mirrors backup_keys_panel.role.*)' },
{ key: 'explorer.account.key_active', locale: 'es', reason: '(c) Blurt key-role identifier kept in English by project convention (mirrors backup_keys_panel.role.*)' },
{ key: 'explorer.account.key_active', locale: 'fr', reason: '(c) Blurt key-role identifier kept in English by project convention (mirrors backup_keys_panel.role.*)' },
{ key: 'explorer.account.key_posting', locale: 'de', reason: '(c) Blurt key-role identifier kept in English by project convention (mirrors backup_keys_panel.role.*)' },
{ key: 'explorer.account.key_posting', locale: 'es', reason: '(c) Blurt key-role identifier kept in English by project convention (mirrors backup_keys_panel.role.*)' },
{ key: 'explorer.account.key_posting', locale: 'fr', reason: '(c) Blurt key-role identifier kept in English by project convention (mirrors backup_keys_panel.role.*)' },
{ key: 'explorer.account.key_memo', locale: 'de', reason: '(c) Blurt key-role identifier kept in English by project convention (mirrors backup_keys_panel.role.*)' },
{ key: 'explorer.account.key_memo', locale: 'es', reason: '(c) Blurt key-role identifier kept in English by project convention (mirrors backup_keys_panel.role.*)' },
{ key: 'explorer.account.key_memo', locale: 'fr', reason: '(c) Blurt key-role identifier kept in English by project convention (mirrors backup_keys_panel.role.*)' },
// cp305 — the sign-out-before-switch modal's confirm button is "OK"
// per Ken's explicit two-button [Cancel / OK] spec for this dialog.
// "OK" is an internationally-recognized affirmation rendered
// identically in these locales (it/pl already pass the heuristic);
// it is the intended text, not an untranslated miss.
{ key: 'login.signout_before_switch_modal.confirm', locale: 'de', reason: '(b) "OK" is a universal affirmation loanword; intentional per the modal\'s Cancel/OK spec' },
{ key: 'login.signout_before_switch_modal.confirm', locale: 'fr', reason: '(b) "OK" is a universal affirmation loanword; intentional per the modal\'s Cancel/OK spec' },
// ─── cp229 RSS feed-format names: "RSS 2.0", "Atom", "JSON" are
// proper-noun / technical format identifiers, byte-identical in
// every locale by design (the 3-format RSS feature). The
// surrounding copied-to-clipboard sentences ARE translated;
// only the bare format names are invariant. ──────────────────
{ key: 'rss.format_rss2', locale: 'de', reason: '(c) "RSS 2.0" is a feed-format name (proper noun); identical in every locale' },
{ key: 'rss.format_rss2', locale: 'es', reason: '(c) "RSS 2.0" is a feed-format name (proper noun); identical in every locale' },
{ key: 'rss.format_rss2', locale: 'fr', reason: '(c) "RSS 2.0" is a feed-format name (proper noun); identical in every locale' },
{ key: 'rss.format_atom', locale: 'de', reason: '(c) "Atom" is a feed-format name (proper noun); identical in every locale' },
{ key: 'rss.format_atom', locale: 'es', reason: '(c) "Atom" is a feed-format name (proper noun); identical in every locale' },
{ key: 'rss.format_atom', locale: 'fr', reason: '(c) "Atom" is a feed-format name (proper noun); identical in every locale' },
{ key: 'rss.format_json', locale: 'de', reason: '(c) "JSON" is a feed-format name (technical identifier); identical in every locale' },
{ key: 'rss.format_json', locale: 'es', reason: '(c) "JSON" is a feed-format name (technical identifier); identical in every locale' },
{ key: 'rss.format_json', locale: 'fr', reason: '(c) "JSON" is a feed-format name (technical identifier); identical in every locale' },
// cp295 — the footer link was shortened from "PGP keys" to the bare
// acronym "PGP" (Ken's batch item D). "PGP" is a universal
// cryptography acronym, written the same in every locale, so being
// byte-identical to English here is the CORRECT rendering, not a miss.
{ key: 'footer.pgp_keys', locale: 'de', reason: '(c) "PGP" is a universal cryptography acronym; identical in every locale' },
{ key: 'footer.pgp_keys', locale: 'es', reason: '(c) "PGP" is a universal cryptography acronym; identical in every locale' },
{ key: 'footer.pgp_keys', locale: 'fr', reason: '(c) "PGP" is a universal cryptography acronym; identical in every locale' },
// post-beta.28 — the footer "API" link (developer-API FAQ deep-link).
// "API" is a universal programming acronym, written the same in every
// locale, so being byte-identical to English is the CORRECT rendering.
// (Tooltip footer.api_title IS translated; only the bare label is invariant.)
{ key: 'footer.api', locale: 'de', reason: '(c) "API" is a universal programming acronym; identical in every locale' },
{ key: 'footer.api', locale: 'es', reason: '(c) "API" is a universal programming acronym; identical in every locale' },
{ key: 'footer.api', locale: 'fr', reason: '(c) "API" is a universal programming acronym; identical in every locale' },
{ key: 'footer.contact', locale: 'fr', reason: '(a) "Contact" is also French (same spelling, same meaning)' },
// cp423 — the chat-inbox "RE:" prefix on the "RE: <order title>" subline.
// "RE:" (from Latin "in re" = "regarding") is an internationally-recognized
// convention rendered identically in email clients across languages; it is
// Ken's literal wording and the intended text, not an untranslated miss.
// (The order title that follows IS fully translated via order_title.*.)
{ key: 'chat.inbox.re_prefix', locale: 'de', reason: '(b) "RE:" is a universal "regarding" convention (Latin in re); identical in every locale' },
{ key: 'chat.inbox.re_prefix', locale: 'es', reason: '(b) "RE:" is a universal "regarding" convention (Latin in re); identical in every locale' },
{ key: 'chat.inbox.re_prefix', locale: 'fr', reason: '(b) "RE:" is a universal "regarding" convention (Latin in re); identical in every locale' },
// post-beta.28 — the RPC endpoint-health error label "Error: {code}".
// "Error" is spelled identically in Spanish (cognate); only the
// interpolated HTTP status code follows, so es is legitimately
// byte-identical to EN here. (fr/de/it/pl/ru/fa/zh all differ.)
{ key: 'settings.endpoints.http_error', locale: 'es', reason: '(b) "Error" is identical in Spanish (cognate); the rest is the interpolated HTTP {code}' },
// ─── cp115 network product names: Latin-script brand names that
// legitimately do NOT translate. Arbitrum, Base, Polygon are
// Layer-2 network product names (registered marks). BEP-20
// and TRC-20 are technical token-standard identifiers (binance
// / tron equivalents of ERC-20). All five render identical
// across all 10 locales by design; the screen-reader form
// ("Arbitrum network" / "Red de Arbitrum" / etc.) carries
// the translation. ─────────────────────────────────────────
{ key: 'home.coin_carousel.networks.arbitrum', locale: 'de', reason: '(c) Arbitrum is a registered Layer-2 product name; does not translate' },
{ key: 'home.coin_carousel.networks.arbitrum', locale: 'es', reason: '(c) Arbitrum is a registered Layer-2 product name; does not translate' },
{ key: 'home.coin_carousel.networks.arbitrum', locale: 'fr', reason: '(c) Arbitrum is a registered Layer-2 product name; does not translate' },
{ key: 'home.coin_carousel.networks.base', locale: 'de', reason: '(c) Base is the Coinbase L2 product name; does not translate' },
{ key: 'home.coin_carousel.networks.base', locale: 'es', reason: '(c) Base is the Coinbase L2 product name; does not translate' },
{ key: 'home.coin_carousel.networks.base', locale: 'fr', reason: '(c) Base is the Coinbase L2 product name; does not translate' },
{ key: 'home.coin_carousel.networks.bep20', locale: 'de', reason: '(c) BEP-20 is a technical token-standard identifier; does not translate' },
{ key: 'home.coin_carousel.networks.bep20', locale: 'es', reason: '(c) BEP-20 is a technical token-standard identifier; does not translate' },
{ key: 'home.coin_carousel.networks.bep20', locale: 'fr', reason: '(c) BEP-20 is a technical token-standard identifier; does not translate' },
{ key: 'home.coin_carousel.networks.polygon', locale: 'de', reason: '(c) Polygon is a registered L2 network product name; does not translate' },
{ key: 'home.coin_carousel.networks.polygon', locale: 'es', reason: '(c) Polygon is a registered L2 network product name; does not translate' },
{ key: 'home.coin_carousel.networks.polygon', locale: 'fr', reason: '(c) Polygon is a registered L2 network product name; does not translate' },
{ key: 'home.coin_carousel.networks.trc20', locale: 'de', reason: '(c) TRC-20 is a technical token-standard identifier; does not translate' },
{ key: 'home.coin_carousel.networks.trc20', locale: 'es', reason: '(c) TRC-20 is a technical token-standard identifier; does not translate' },
{ key: 'home.coin_carousel.networks.trc20', locale: 'fr', reason: '(c) TRC-20 is a technical token-standard identifier; does not translate' },
// ─── (a) same-word: spelling matches in target locale ───
{ key: 'feature_bid.history_state_visible', locale: 'es', reason: '(a) "Visible" is also Spanish (same spelling, same meaning)' },
{ key: 'feature_bid.history_state_visible', locale: 'fr', reason: '(a) "Visible" is also French (same spelling, same meaning)' },
{ key: 'profile.reputation_heading', locale: 'de', reason: '(a) "Reputation" is also German' },
{ key: 'post_order.form.region_label', locale: 'de', reason: '(a) "Region (optional)" is German verbatim' },
{ key: 'chat.funds_sent.pill_txid_label', locale: 'fr', reason: '(a) "Transaction" is also French' },
{ key: 'explorer.block.page_title', locale: 'de', reason: '(a) "Block" is also German' },
{ key: 'explorer.block.heading', locale: 'de', reason: '(a) "Block" is also German' },
{ key: 'explorer.block.tx_count_label', locale: 'fr', reason: '(a) "Transactions" is also French' },
{ key: 'explorer.block.tx_index', locale: 'fr', reason: '(a) "Transaction" is also French' },
{ key: 'explorer.tx.page_title', locale: 'fr', reason: '(a) "Transaction" is also French' },
{ key: 'explorer.tx.heading', locale: 'fr', reason: '(a) "Transaction" is also French' },
{ key: 'explorer.tx.signatures_label', locale: 'fr', reason: '(a) "Signatures" is also French' },
{ key: 'explorer.tx.block_label', locale: 'de', reason: '(a) "Block" is also German' },
{ key: 'explorer.activity.col_asset', locale: 'de', reason: '(a/b) "Asset" adopted as German tech loanword' },
{ key: 'explorer.activity.col_asset', locale: 'it', reason: '(a/b) "Asset" adopted as Italian tech loanword' },
{ key: 'explorer.activity.col_trades', locale: 'de', reason: '(a/b) "Trades" adopted as German tech loanword' },
{ key: 'explorer.nav.home_title', locale: 'it', reason: '(b) "Home" is universal Italian tech loanword' },
{ key: 'explorer.op.label.transfer', locale: 'pl', reason: '(a) "Transfer" is also Polish' },
{ key: 'explorer.op.label.vote', locale: 'fr', reason: '(a) "Vote" is also French' },
{ key: 'explorer.op.label.comment', locale: 'it', reason: '(b) "Post" adopted as Italian tech loanword' },
{ key: 'explorer.op.label.comment', locale: 'pl', reason: '(b) "Post" adopted as Polish tech loanword' },
{ key: 'explorer.op.label.morphit_feedback', locale: 'de', reason: '(b) "Feedback" adopted as German tech loanword' },
{ key: 'explorer.block.timestamp_label', locale: 'it', reason: '(b) "Timestamp" adopted as Italian tech loanword' },
{ key: 'glossary.delegation.title', locale: 'de', reason: '(a) "Delegation" is also German' },
{ key: 'glossary.feedback.title', locale: 'de', reason: '(b) "Feedback" adopted as German loanword' },
{ key: 'glossary.feedback.title', locale: 'it', reason: '(b) "Feedback" adopted as Italian loanword' },
{ key: 'glossary.indexer.title', locale: 'de', reason: '(b) "Indexer" adopted as German tech loanword' },
{ key: 'glossary.indexer.title', locale: 'it', reason: '(b) "Indexer" adopted as Italian tech loanword' },
{ key: 'glossary.indexer.title', locale: 'pl', reason: '(b) "Indexer" adopted as Polish tech loanword' },
{ key: 'glossary.instance.title', locale: 'fr', reason: '(a) "Instance" is also French' },
{ key: 'glossary.operator.title', locale: 'pl', reason: '(a) "Operator" is also Polish' },
{ key: 'glossary.password.title', locale: 'it', reason: '(b) "Password" adopted as Italian tech loanword' },
{ key: 'glossary.relay.title', locale: 'de', reason: '(b) "Relay" adopted as German tech loanword' },
{ key: 'glossary.relay.title', locale: 'it', reason: '(b) "Relay" adopted as Italian tech loanword' },
{ key: 'glossary.release_op.title', locale: 'ru', reason: '(c) "Release op" is technical Blurt op-name' },
{ key: 'glossary.seed_phrase.title', locale: 'it', reason: '(b) "Seed phrase" adopted as Italian crypto loanword' },
{ key: 'onboarding.import.keyfile_tab_label', locale: 'fa', reason: '(b) "Keyfile" + ".json" are both tech loanwords / file extension literal in Persian' },
{ key: 'onboarding.import.keyfile_tab_label', locale: 'it', reason: '(b) "Keyfile" + ".json" — keyfile is widely-adopted Italian crypto loanword; .json is a literal file extension' },
{ key: 'onboarding.import.keyfile_tab_label', locale: 'ru', reason: '(b) "Keyfile" + ".json" — keyfile is widely-adopted Russian tech loanword; .json is a literal file extension' },
{ key: 'cheat_sheet.section_identity.password', locale: 'it', reason: '(b) "Password" adopted as Italian loanword' },
{ key: 'login.welcome_back.password_label', locale: 'it', reason: '(b) "Password" adopted as Italian loanword' },
{ key: 'onboarding.backup.print_card.account_label', locale: 'it', reason: '(b) "Account" adopted as Italian tech loanword' },
{ key: 'avatar_menu.category.order', locale: 'de', reason: '(b) "Orders" adopted as German tech loanword (matches "Meine Orders" pattern)' },
{ key: 'order_detail.details_heading', locale: 'de', reason: '(a) "Details" is also German' },
{ key: 'instances.live', locale: 'de', reason: '(b) "Live" adopted as German tech loanword' },
{ key: 'instances.live', locale: 'it', reason: '(b) "Live" adopted as Italian tech loanword' },
{ key: 'instances.operator_label', locale: 'pl', reason: '(a) "Operator" is also Polish' },
{ key: 'orderbook.live', locale: 'de', reason: '(b) "Live" adopted as German tech loanword' },
{ key: 'orderbook.live', locale: 'it', reason: '(b) "Live" adopted as Italian tech loanword' },
{ key: 'orderbook.filters.heading', locale: 'de', reason: '(a) "Filter" is also German' },
{ key: 'orderbook.filters.asset_label', locale: 'de', reason: '(b) "Asset" loanword' },
{ key: 'orderbook.filters.asset_label', locale: 'it', reason: '(b) "Asset" loanword' },
{ key: 'orderbook.filters.region_label', locale: 'de', reason: '(a) "Region" is also German' },
{ key: 'orderbook.filters.region_label', locale: 'pl', reason: '(a) "Region" is also Polish' },
{ key: 'orderbook.order.region_label', locale: 'de', reason: '(a) "Region" is also German' },
{ key: 'orderbook.order.region_label', locale: 'pl', reason: '(a) "Region" is also Polish' },
{ key: 'settings.preferences.region_label', locale: 'de', reason: '(a) "Region" is also German' },
{ key: 'settings.preferences.region_label', locale: 'pl', reason: '(a) "Region" is also Polish' },
{ key: 'settings.privacy.heading', locale: 'it', reason: '(b) "Privacy" adopted as Italian loanword' },
{ key: 'privacy_terms.privacy_heading', locale: 'it', reason: '(b) "Privacy" adopted as Italian loanword' },
{ key: 'settings.session.heading', locale: 'fr', reason: '(a) "Session" is also French' },
{ key: 'settings.session.autolock_15min', locale: 'fr', reason: '(a) "15 minutes" is also French' },
{ key: 'settings.session.autolock_30min', locale: 'fr', reason: '(a) "30 minutes" is also French' },
{ key: 'settings.notifications.heading', locale: 'fr', reason: '(a) "Notifications" is also French' },
{ key: 'settings.notifications.category_feedback_label', locale: 'es', reason: '(b) "Feedback" loanword' },
{ key: 'settings.notifications.category_feedback_label', locale: 'de', reason: '(b) "Feedback" loanword' },
{ key: 'settings.notifications.category_feedback_label', locale: 'it', reason: '(b) "Feedback" loanword' },
{ key: 'settings.syndication.heading', locale: 'fr', reason: '(a) "Syndication" is also French' },
{ key: 'settings.avatar.heading', locale: 'es', reason: '(b) "Avatar" universal loanword' },
{ key: 'settings.avatar.heading', locale: 'fr', reason: '(b) "Avatar" universal loanword' },
{ key: 'settings.avatar.heading', locale: 'de', reason: '(b) "Avatar" universal loanword' },
{ key: 'settings.avatar.heading', locale: 'it', reason: '(b) "Avatar" universal loanword' },
{ key: 'settings.hardware_key.slot_1', locale: 'de', reason: '(b) "Slot 1" universal tech loanword' },
{ key: 'settings.hardware_key.slot_1', locale: 'it', reason: '(b) "Slot 1" universal tech loanword' },
{ key: 'settings.hardware_key.slot_1', locale: 'pl', reason: '(b) "Slot 1" universal tech loanword' },
{ key: 'settings.hardware_key.slot_label', locale: 'de', reason: '(b) "Slot" universal tech loanword' },
{ key: 'settings.hardware_key.slot_label', locale: 'it', reason: '(b) "Slot" universal tech loanword' },
{ key: 'settings.hardware_key.slot_label', locale: 'pl', reason: '(b) "Slot" universal tech loanword' },
{ key: 'scan_login.confirm_website_label', locale: 'de', reason: '(b) "Website" adopted as German loanword' },
{ key: 'avatar_menu.notifications', locale: 'fr', reason: '(a) "Notifications" is also French' },
{ key: 'avatar_menu.notifications_heading', locale: 'fr', reason: '(a) "Notifications" is also French' },
{ key: 'avatar_menu.category.chat', locale: 'es', reason: '(b) "Chat" universal loanword' },
{ key: 'avatar_menu.category.chat', locale: 'fr', reason: '(b) "Chat" universal loanword' },
{ key: 'avatar_menu.category.chat', locale: 'de', reason: '(b) "Chat" universal loanword' },
{ key: 'avatar_menu.category.chat', locale: 'it', reason: '(b) "Chat" universal loanword' },
{ key: 'avatar_menu.category.feedback', locale: 'es', reason: '(b) "Feedback" loanword' },
{ key: 'avatar_menu.category.feedback', locale: 'de', reason: '(b) "Feedback" loanword' },
{ key: 'avatar_menu.category.feedback', locale: 'it', reason: '(b) "Feedback" loanword' },
{ key: 'chat.composer.acct_reminder.heading', locale: 'fr', reason: '(a) "Permanent." is also French' },
{ key: 'chat.live', locale: 'de', reason: '(b) "Live" adopted as German tech loanword' },
{ key: 'chat.message_button_label', locale: 'fr', reason: '(a) "Message" is also French' },
{ key: 'chat.inbox.tab_messages', locale: 'fr', reason: '(a) "Messages" is also French' },
{ key: 'chat.pay_blurt.memo_label', locale: 'es', reason: '(b) "Memo" universal loanword' },
{ key: 'chat.pay_blurt.memo_label', locale: 'de', reason: '(b) "Memo" universal loanword' },
{ key: 'chat.pay_blurt.memo_label', locale: 'it', reason: '(b) "Memo" universal loanword' },
{ key: 'chat.pay_blurt.memo_label', locale: 'ru', reason: '(b) "Memo" universal loanword (Latin script intentional)' },
{ key: 'profile.pnl.csv_header.memo', locale: 'es', reason: '(b) "Memo" + CSV-cross-tool convention' },
{ key: 'profile.pnl.csv_header.memo', locale: 'fr', reason: '(b) "Memo" + CSV-cross-tool convention' },
{ key: 'profile.pnl.csv_header.memo', locale: 'de', reason: '(b) "Memo" + CSV-cross-tool convention' },
{ key: 'profile.pnl.csv_header.memo', locale: 'it', reason: '(b) "Memo" + CSV-cross-tool convention' },
{ key: 'profile.pnl.csv_header.memo', locale: 'pl', reason: '(b) "Memo" + CSV-cross-tool convention' },
{ key: 'profile.pnl.csv_header.memo', locale: 'ru', reason: '(b) "Memo" + CSV-cross-tool convention' },
{ key: 'profile.pnl.csv_header.block', locale: 'de', reason: '(a) "Block" is also German' },
{ key: 'nav.messages', locale: 'fr', reason: '(a) "Messages" is also French' },
{ key: 'operators.contact', locale: 'fr', reason: '(a) "Contact" is also French' },
{ key: 'footer.source', locale: 'fr', reason: '(a) "Source" is also French' },
{ key: 'footer.plan', locale: 'es', reason: '(a) "Plan" is also Spanish' },
{ key: 'footer.plan', locale: 'fr', reason: '(a) "Plan" is also French' },
{ key: 'footer.plan', locale: 'de', reason: '(a) "Plan" is also German' },
{ key: 'footer.plan', locale: 'pl', reason: '(a) "Plan" is also Polish' },
{ key: 'footer.rss', locale: 'es', reason: '(c) "RSS" is universal acronym' },
{ key: 'footer.rss', locale: 'fr', reason: '(c) "RSS" is universal acronym' },
{ key: 'footer.rss', locale: 'de', reason: '(c) "RSS" is universal acronym' },
{ key: 'footer.rss', locale: 'it', reason: '(c) "RSS" is universal acronym' },
{ key: 'footer.rss', locale: 'pl', reason: '(c) "RSS" is universal acronym' },
{ key: 'footer.rss', locale: 'ru', reason: '(c) "RSS" is universal acronym' },
{ key: 'footer.rss', locale: 'fa', reason: '(c) "RSS" is universal acronym' },
{ key: 'footer.rss', locale: 'zh-CN', reason: '(c) "RSS" is universal acronym' },
{ key: 'footer.rss', locale: 'zh-HK', reason: '(c) "RSS" is universal acronym' },
{ key: 'footer.i2p_b32', locale: 'es', reason: '(c) "B32 I2P" technical protocol' },
{ key: 'footer.i2p_b32', locale: 'fr', reason: '(c) technical protocol' },
{ key: 'footer.i2p_b32', locale: 'de', reason: '(c) technical protocol' },
{ key: 'footer.i2p_b32', locale: 'it', reason: '(c) technical protocol' },
{ key: 'footer.i2p_b32', locale: 'pl', reason: '(c) technical protocol' },
{ key: 'footer.i2p_b32', locale: 'ru', reason: '(c) technical protocol' },
{ key: 'footer.i2p_b32', locale: 'fa', reason: '(c) technical protocol' },
{ key: 'footer.i2p_b32', locale: 'zh-CN', reason: '(c) technical protocol' },
{ key: 'footer.i2p_b32', locale: 'zh-HK', reason: '(c) technical protocol' },
{ key: 'glossary.permlink.title', locale: 'es', reason: '(c) Blurt-chain technical term, universal' },
{ key: 'glossary.permlink.title', locale: 'fr', reason: '(c) Blurt-chain technical term, universal' },
{ key: 'glossary.permlink.title', locale: 'de', reason: '(c) Blurt-chain technical term, universal' },
{ key: 'glossary.permlink.title', locale: 'it', reason: '(c) Blurt-chain technical term, universal' },
{ key: 'glossary.permlink.title', locale: 'pl', reason: '(c) Blurt-chain technical term, universal' },
{ key: 'glossary.permlink.title', locale: 'ru', reason: '(c) Blurt-chain technical term, universal' },
{ key: 'glossary.permlink.title', locale: 'fa', reason: '(c) Blurt-chain technical term, universal' },
{ key: 'glossary.custom_json.title', locale: 'es', reason: '(c) JSON op-type literal identifier' },
{ key: 'glossary.custom_json.title', locale: 'fr', reason: '(c) JSON op-type literal identifier' },
{ key: 'glossary.custom_json.title', locale: 'de', reason: '(c) JSON op-type literal identifier' },
{ key: 'glossary.custom_json.title', locale: 'it', reason: '(c) JSON op-type literal identifier' },
{ key: 'glossary.custom_json.title', locale: 'pl', reason: '(c) JSON op-type literal identifier' },
{ key: 'glossary.custom_json.title', locale: 'ru', reason: '(c) JSON op-type literal identifier' },
{ key: 'glossary.custom_json.title', locale: 'fa', reason: '(c) JSON op-type literal identifier' },
{ key: 'glossary.custom_json.title', locale: 'zh-CN', reason: '(c) JSON op-type literal identifier' },
{ key: 'glossary.custom_json.title', locale: 'zh-HK', reason: '(c) JSON op-type literal identifier' },
{ key: 'glossary.fiat.title', locale: 'es', reason: '(b) "Fiat" universal crypto loanword' },
{ key: 'glossary.fiat.title', locale: 'fr', reason: '(b) "Fiat" universal crypto loanword' },
{ key: 'glossary.fiat.title', locale: 'de', reason: '(b) "Fiat" universal crypto loanword' },
{ key: 'glossary.fiat.title', locale: 'it', reason: '(b) "Fiat" universal crypto loanword' },
{ key: 'glossary.fiat.title', locale: 'pl', reason: '(b) "Fiat" universal crypto loanword' },
{ key: 'glossary.blurt_power.title', locale: 'es', reason: '(c) Blurt-chain proper-name term' },
{ key: 'glossary.blurt_power.title', locale: 'fr', reason: '(c) Blurt-chain proper-name term' },
{ key: 'glossary.blurt_power.title', locale: 'de', reason: '(c) Blurt-chain proper-name term' },
{ key: 'glossary.blurt_power.title', locale: 'it', reason: '(c) Blurt-chain proper-name term' },
{ key: 'glossary.blurt_power.title', locale: 'pl', reason: '(c) Blurt-chain proper-name term' },
{ key: 'glossary.blurt_power.title', locale: 'ru', reason: '(c) Blurt-chain proper-name term' },
{ key: 'glossary.blurt_power.title', locale: 'fa', reason: '(c) Blurt-chain proper-name term' },
{ key: 'glossary.blurt_power.title', locale: 'zh-CN', reason: '(c) Blurt-chain proper-name term' },
{ key: 'glossary.blurt_power.title', locale: 'zh-HK', reason: '(c) Blurt-chain proper-name term' },
{ key: 'cheat_sheet.section_assets.heading', locale: 'es', reason: '(c) all 3 are brand names; "vs" is loanword' },
{ key: 'cheat_sheet.section_assets.heading', locale: 'fr', reason: '(c) all 3 are brand names; "vs" is loanword' },
{ key: 'cheat_sheet.section_assets.heading', locale: 'de', reason: '(c) all 3 are brand names; "vs" is loanword' },
{ key: 'cheat_sheet.section_assets.heading', locale: 'it', reason: '(c) all 3 are brand names; "vs" is loanword' },
{ key: 'cheat_sheet.section_assets.heading', locale: 'pl', reason: '(c) all 3 are brand names; "vs" is loanword' },
{ key: 'cheat_sheet.section_assets.heading', locale: 'ru', reason: '(c) all 3 are brand names; "vs" is loanword' },
{ key: 'cheat_sheet.section_assets.heading', locale: 'zh-CN', reason: '(c) all 3 are brand names; "vs" is loanword' },
{ key: 'cheat_sheet.section_assets.heading', locale: 'zh-HK', reason: '(c) all 3 are brand names; "vs" is loanword' },
{ key: 'explorer.block.witness_label', locale: 'de', reason: '(c) Blurt-chain technical term universal' },
{ key: 'explorer.block.witness_label', locale: 'it', reason: '(c) Blurt-chain technical term universal' },
{ key: 'explorer.block.witness_label', locale: 'pl', reason: '(c) Blurt-chain technical term universal' },
{ key: 'explorer.block.witness_label', locale: 'ru', reason: '(c) Blurt-chain technical term universal' },
{ key: 'explorer.block.witness_label', locale: 'fa', reason: '(c) Blurt-chain technical term universal' },
{ key: 'explorer.nav.fallback_title', locale: 'es', reason: '(c) literal domain name' },
{ key: 'explorer.nav.fallback_title', locale: 'fr', reason: '(c) literal domain name' },
{ key: 'explorer.nav.fallback_title', locale: 'de', reason: '(c) literal domain name' },
{ key: 'explorer.nav.fallback_title', locale: 'it', reason: '(c) literal domain name' },
{ key: 'explorer.nav.fallback_title', locale: 'pl', reason: '(c) literal domain name' },
{ key: 'explorer.nav.fallback_title', locale: 'ru', reason: '(c) literal domain name' },
{ key: 'explorer.nav.fallback_title', locale: 'fa', reason: '(c) literal domain name' },
{ key: 'explorer.nav.fallback_title', locale: 'zh-CN', reason: '(c) literal domain name' },
{ key: 'explorer.nav.fallback_title', locale: 'zh-HK', reason: '(c) literal domain name' },
{ key: 'my_orders.order.range_both', locale: 'es', reason: '(c) pure format string' },
{ key: 'my_orders.order.range_both', locale: 'fr', reason: '(c) pure format string' },
{ key: 'my_orders.order.range_both', locale: 'de', reason: '(c) pure format string' },
{ key: 'my_orders.order.range_both', locale: 'it', reason: '(c) pure format string' },
{ key: 'my_orders.order.range_both', locale: 'pl', reason: '(c) pure format string' },
{ key: 'my_orders.order.range_both', locale: 'ru', reason: '(c) pure format string' },
{ key: 'my_orders.order.range_both', locale: 'fa', reason: '(c) pure format string' },
{ key: 'my_orders.order.range_both', locale: 'zh-CN', reason: '(c) pure format string' },
{ key: 'my_orders.order.range_both', locale: 'zh-HK', reason: '(c) pure format string' },
{ key: 'orderbook.order.range_both', locale: 'es', reason: '(c) pure format string' },
{ key: 'orderbook.order.range_both', locale: 'fr', reason: '(c) pure format string' },
{ key: 'orderbook.order.range_both', locale: 'de', reason: '(c) pure format string' },
{ key: 'orderbook.order.range_both', locale: 'it', reason: '(c) pure format string' },
{ key: 'orderbook.order.range_both', locale: 'pl', reason: '(c) pure format string' },
{ key: 'orderbook.order.range_both', locale: 'ru', reason: '(c) pure format string' },
{ key: 'orderbook.order.range_both', locale: 'fa', reason: '(c) pure format string' },
{ key: 'orderbook.order.range_both', locale: 'zh-CN', reason: '(c) pure format string' },
{ key: 'orderbook.order.range_both', locale: 'zh-HK', reason: '(c) pure format string' },
// Placeholder examples (latin-script: keep — example formats matter)
{ key: 'onboarding.import.posting_only.account_placeholder', locale: 'es', reason: '(c) example placeholder name' },
{ key: 'onboarding.import.posting_only.account_placeholder', locale: 'fr', reason: '(c) example placeholder name' },
{ key: 'onboarding.import.posting_only.account_placeholder', locale: 'de', reason: '(c) example placeholder name' },
{ key: 'onboarding.import.posting_only.account_placeholder', locale: 'it', reason: '(c) example placeholder name' },
{ key: 'onboarding.import.posting_only.account_placeholder', locale: 'pl', reason: '(c) example placeholder name' },
{ key: 'onboarding.import.posting_only.account_placeholder', locale: 'ru', reason: '(c) example placeholder name' },
{ key: 'onboarding.import.posting_only.account_placeholder', locale: 'fa', reason: '(c) example placeholder name' },
{ key: 'onboarding.import.posting_only.account_placeholder', locale: 'zh-CN', reason: '(c) example placeholder name' },
{ key: 'onboarding.import.posting_only.account_placeholder', locale: 'zh-HK', reason: '(c) example placeholder name' },
{ key: 'settings.account_name.input_placeholder', locale: 'es', reason: '(c) example placeholder name' },
{ key: 'settings.account_name.input_placeholder', locale: 'fr', reason: '(c) example placeholder name' },
{ key: 'settings.account_name.input_placeholder', locale: 'de', reason: '(c) example placeholder name' },
{ key: 'settings.account_name.input_placeholder', locale: 'it', reason: '(c) example placeholder name' },
{ key: 'settings.account_name.input_placeholder', locale: 'pl', reason: '(c) example placeholder name' },
{ key: 'settings.account_name.input_placeholder', locale: 'ru', reason: '(c) example placeholder name' },
{ key: 'settings.account_name.input_placeholder', locale: 'fa', reason: '(c) example placeholder name' },
{ key: 'settings.account_name.input_placeholder', locale: 'zh-CN', reason: '(c) example placeholder name' },
{ key: 'settings.account_name.input_placeholder', locale: 'zh-HK', reason: '(c) example placeholder name' },
// Latin-script locales legitimately keep "your-new-name" placeholder
{ key: 'onboarding.register_name.field_placeholder', locale: 'es', reason: '(c) tu-nuevo-nombre is the localized form (already done) — wait check' },
// footer.instances — French "Instances" is byte-identical to English (coincidence, not a fallback).
{ key: 'footer.instances', locale: 'fr', reason: '(b) French "Instances" equals English "Instances" — coincidental same-spelling, not an EN fallback' },
// post_order placeholder
{ key: 'post_order.form.price_model_fiat_placeholder', locale: 'es', reason: '(b) "fiat" loanword' },
{ key: 'post_order.form.price_model_fiat_placeholder', locale: 'fr', reason: '(b) "fiat" loanword' },
{ key: 'post_order.form.price_model_fiat_placeholder', locale: 'it', reason: '(b) "fiat" loanword' },
{ key: 'post_order.form.price_model_fiat_placeholder', locale: 'pl', reason: '(b) "fiat" loanword' },
// run_a_node terms
{ key: 'run_a_node.key_terms.term_indexer', locale: 'it', reason: '(b) "indexer" Italian tech loanword' },
{ key: 'run_a_node.key_terms.term_indexer', locale: 'pl', reason: '(b) "indexer" Polish tech loanword' },
{ key: 'run_a_node.key_terms.term_relay', locale: 'es', reason: '(b) "relay" Spanish tech loanword' },
{ key: 'run_a_node.key_terms.term_relay', locale: 'it', reason: '(b) "relay" Italian tech loanword' },
{ key: 'run_a_node.key_terms.term_relay', locale: 'pl', reason: '(b) "relay" Polish tech loanword' },
{ key: 'run_a_node.key_terms.term_relay', locale: 'ru', reason: '(b) Russian uses "relay" loanword for chain context' },
// Hardware loanword
{ key: 'run_a_node.req_hw_label', locale: 'es', reason: '(b) "Hardware" universal loanword' },
{ key: 'run_a_node.req_hw_label', locale: 'de', reason: '(b) "Hardware" universal loanword' },
{ key: 'run_a_node.req_hw_label', locale: 'it', reason: '(b) "Hardware" universal loanword' },
// Online category
{ key: 'payment_method.category.online', locale: 'de', reason: '(b) "Online" loanword' },
{ key: 'payment_method.category.online', locale: 'it', reason: '(b) "Online" loanword' },
{ key: 'payment_method.category.online', locale: 'pl', reason: '(b) "Online" loanword' },
{ key: 'payment_method.category.crypto', locale: 'fr', reason: '(a) "Crypto" is also French' },
// SEO chat-related — Chat is universal loanword
{ key: 'seo.chat_inbox.title', locale: 'es', reason: '(b) "Chat" universal loanword' },
{ key: 'seo.chat_inbox.title', locale: 'fr', reason: '(b) "Chat" universal loanword' },
{ key: 'seo.chat_inbox.title', locale: 'de', reason: '(b) "Chat" universal loanword' },
{ key: 'seo.chat_inbox.title', locale: 'it', reason: '(b) "Chat" universal loanword' },
{ key: 'seo.chat_conversation.title', locale: 'fr', reason: '(a) "Conversation" is also French' },
{ key: 'seo.order_detail.title', locale: 'de', reason: '(b) "Order" adopted as German tech loanword' },
{ key: 'download.iphone_heading', locale: 'es', reason: '(c) brand names' },
// iPad downloads — Spanish "iPhone y iPad" is the established translation, German uses "und"
// ─── (c) brand/protocol invariants for footer + chain assets ───
{ key: 'footer.i2p', locale: 'es', reason: '(c) protocol name' },
{ key: 'footer.i2p', locale: 'fr', reason: '(c) protocol name' },
{ key: 'footer.i2p', locale: 'de', reason: '(c) protocol name' },
{ key: 'footer.i2p', locale: 'it', reason: '(c) protocol name' },
{ key: 'footer.i2p', locale: 'pl', reason: '(c) protocol name' },
{ key: 'footer.i2p', locale: 'ru', reason: '(c) protocol name' },
{ key: 'footer.i2p', locale: 'fa', reason: '(c) protocol name' },
{ key: 'footer.i2p', locale: 'zh-CN', reason: '(c) protocol name' },
{ key: 'footer.i2p', locale: 'zh-HK', reason: '(c) protocol name' },
{ key: 'footer.i2p_name', locale: 'es', reason: '(c) protocol name' },
{ key: 'footer.i2p_name', locale: 'fr', reason: '(c) protocol name' },
{ key: 'footer.i2p_name', locale: 'de', reason: '(c) protocol name' },
{ key: 'footer.i2p_name', locale: 'it', reason: '(c) protocol name' },
{ key: 'footer.i2p_name', locale: 'pl', reason: '(c) protocol name' },
{ key: 'footer.i2p_name', locale: 'ru', reason: '(c) protocol name' },
{ key: 'footer.i2p_name', locale: 'fa', reason: '(c) protocol name' },
{ key: 'footer.i2p_name', locale: 'zh-CN', reason: '(c) protocol name' },
{ key: 'footer.i2p_name', locale: 'zh-HK', reason: '(c) protocol name' },
{ key: 'footer.ens', locale: 'es', reason: '(c) protocol name' },
{ key: 'footer.ens', locale: 'fr', reason: '(c) protocol name' },
{ key: 'footer.ens', locale: 'de', reason: '(c) protocol name' },
{ key: 'footer.ens', locale: 'it', reason: '(c) protocol name' },
{ key: 'footer.ens', locale: 'pl', reason: '(c) protocol name' },
{ key: 'footer.ens', locale: 'ru', reason: '(c) protocol name' },
{ key: 'footer.ens', locale: 'fa', reason: '(c) protocol name' },
{ key: 'footer.ens', locale: 'zh-CN', reason: '(c) protocol name' },
{ key: 'footer.ens', locale: 'zh-HK', reason: '(c) protocol name' },
{ key: 'footer.lokinet', locale: 'es', reason: '(c) brand/protocol name' },
{ key: 'footer.lokinet', locale: 'fr', reason: '(c) brand/protocol name' },
{ key: 'footer.lokinet', locale: 'de', reason: '(c) brand/protocol name' },
{ key: 'footer.lokinet', locale: 'it', reason: '(c) brand/protocol name' },
{ key: 'footer.lokinet', locale: 'pl', reason: '(c) brand/protocol name' },
{ key: 'footer.lokinet', locale: 'ru', reason: '(c) brand/protocol name' },
{ key: 'footer.lokinet', locale: 'fa', reason: '(c) brand/protocol name' },
{ key: 'footer.lokinet', locale: 'zh-CN', reason: '(c) brand/protocol name' },
{ key: 'footer.lokinet', locale: 'zh-HK', reason: '(c) brand/protocol name' },
{ key: 'footer.nostr', locale: 'es', reason: '(c) protocol name' },
{ key: 'footer.nostr', locale: 'fr', reason: '(c) protocol name' },
{ key: 'footer.nostr', locale: 'de', reason: '(c) protocol name' },
{ key: 'footer.nostr', locale: 'it', reason: '(c) protocol name' },
{ key: 'footer.nostr', locale: 'pl', reason: '(c) protocol name' },
{ key: 'footer.nostr', locale: 'ru', reason: '(c) protocol name' },
{ key: 'footer.nostr', locale: 'fa', reason: '(c) protocol name' },
{ key: 'footer.nostr', locale: 'zh-CN', reason: '(c) protocol name' },
{ key: 'footer.nostr', locale: 'zh-HK', reason: '(c) protocol name' },
{ key: 'footer.contact_operator_matrix_label', locale: 'es', reason: '(c) brand/protocol name' },
{ key: 'footer.contact_operator_matrix_label', locale: 'fr', reason: '(c) brand/protocol name' },
{ key: 'footer.contact_operator_matrix_label', locale: 'de', reason: '(c) brand/protocol name' },
{ key: 'footer.contact_operator_matrix_label', locale: 'it', reason: '(c) brand/protocol name' },
{ key: 'footer.contact_operator_matrix_label', locale: 'pl', reason: '(c) brand/protocol name' },
{ key: 'footer.contact_operator_matrix_label', locale: 'ru', reason: '(c) brand/protocol name' },
{ key: 'footer.contact_operator_matrix_label', locale: 'zh-CN', reason: '(c) brand/protocol name' },
{ key: 'footer.contact_operator_matrix_label', locale: 'zh-HK', reason: '(c) brand/protocol name' },
{ key: 'footer.tor', locale: 'es', reason: '(c) protocol name' },
{ key: 'footer.tor', locale: 'fr', reason: '(c) protocol name' },
{ key: 'footer.tor', locale: 'de', reason: '(c) protocol name' },
{ key: 'footer.tor', locale: 'it', reason: '(c) protocol name' },
{ key: 'footer.tor', locale: 'pl', reason: '(c) protocol name' },
{ key: 'footer.tor', locale: 'ru', reason: '(c) protocol name' },
{ key: 'footer.tor', locale: 'fa', reason: '(c) protocol name' },
{ key: 'footer.tor', locale: 'zh-CN', reason: '(c) protocol name' },
{ key: 'footer.tor', locale: 'zh-HK', reason: '(c) protocol name' },
{ key: 'glossary.blurt.title', locale: 'es', reason: '(c) chain brand name' },
{ key: 'glossary.blurt.title', locale: 'fr', reason: '(c) chain brand name' },
{ key: 'glossary.blurt.title', locale: 'de', reason: '(c) chain brand name' },
{ key: 'glossary.blurt.title', locale: 'it', reason: '(c) chain brand name' },
{ key: 'glossary.blurt.title', locale: 'pl', reason: '(c) chain brand name' },
{ key: 'glossary.blurt.title', locale: 'ru', reason: '(c) chain brand name' },
{ key: 'glossary.blurt.title', locale: 'fa', reason: '(c) chain brand name' },
{ key: 'glossary.blurt.title', locale: 'zh-CN', reason: '(c) chain brand name' },
{ key: 'glossary.blurt.title', locale: 'zh-HK', reason: '(c) chain brand name' },
{ key: 'profile.my_balance.blurt_label', locale: 'es', reason: '(c) chain asset symbol' },
{ key: 'profile.my_balance.blurt_label', locale: 'fr', reason: '(c) chain asset symbol' },
{ key: 'profile.my_balance.blurt_label', locale: 'de', reason: '(c) chain asset symbol' },
{ key: 'profile.my_balance.blurt_label', locale: 'it', reason: '(c) chain asset symbol' },
{ key: 'profile.my_balance.blurt_label', locale: 'pl', reason: '(c) chain asset symbol' },
{ key: 'profile.my_balance.blurt_label', locale: 'ru', reason: '(c) chain asset symbol' },
{ key: 'profile.my_balance.blurt_label', locale: 'fa', reason: '(c) chain asset symbol' },
{ key: 'profile.my_balance.blurt_label', locale: 'zh-CN', reason: '(c) chain asset symbol' },
{ key: 'profile.my_balance.blurt_label', locale: 'zh-HK', reason: '(c) chain asset symbol' },
// ─── (c) Cryptocurrency brand names in chat-address method labels ───
// "Blurt" is the chain brand name in all locales. "Bitcoin" and "Monero" are kept
// as universal English in Latin-script locales; fa/zh-CN/zh-HK have script versions.
{ key: 'chat.address.method_blurt', locale: 'es', reason: '(c) Blurt chain brand name' },
{ key: 'chat.address.method_blurt', locale: 'fr', reason: '(c) Blurt chain brand name' },
{ key: 'chat.address.method_blurt', locale: 'de', reason: '(c) Blurt chain brand name' },
{ key: 'chat.address.method_blurt', locale: 'it', reason: '(c) Blurt chain brand name' },
{ key: 'chat.address.method_blurt', locale: 'pl', reason: '(c) Blurt chain brand name' },
{ key: 'chat.address.method_blurt', locale: 'ru', reason: '(c) Blurt chain brand name' },
{ key: 'chat.address.method_blurt', locale: 'fa', reason: '(c) Blurt chain brand name' },
{ key: 'chat.address.method_blurt', locale: 'zh-CN', reason: '(c) Blurt chain brand name' },
{ key: 'chat.address.method_blurt', locale: 'zh-HK', reason: '(c) Blurt chain brand name' },
{ key: 'chat.address.method_btc', locale: 'es', reason: '(c) Bitcoin universal brand' },
{ key: 'chat.address.method_btc', locale: 'fr', reason: '(c) Bitcoin universal brand' },
{ key: 'chat.address.method_btc', locale: 'de', reason: '(c) Bitcoin universal brand' },
{ key: 'chat.address.method_btc', locale: 'it', reason: '(c) Bitcoin universal brand' },
{ key: 'chat.address.method_btc', locale: 'pl', reason: '(c) Bitcoin universal brand' },
{ key: 'chat.address.method_btc', locale: 'ru', reason: '(c) Bitcoin universal brand (Latin-script intentional)' },
{ key: 'chat.address.method_xmr', locale: 'es', reason: '(c) Monero universal brand' },
{ key: 'chat.address.method_xmr', locale: 'fr', reason: '(c) Monero universal brand' },
{ key: 'chat.address.method_xmr', locale: 'de', reason: '(c) Monero universal brand' },
{ key: 'chat.address.method_xmr', locale: 'it', reason: '(c) Monero universal brand' },
{ key: 'chat.address.method_xmr', locale: 'pl', reason: '(c) Monero universal brand' },
{ key: 'chat.address.method_xmr', locale: 'ru', reason: '(c) Monero universal brand (Latin-script intentional)' },
{ key: 'seo.site_name', locale: 'es', reason: '(c) Morphit brand name' },
{ key: 'seo.site_name', locale: 'fr', reason: '(c) Morphit brand name' },
{ key: 'seo.site_name', locale: 'de', reason: '(c) Morphit brand name' },
{ key: 'seo.site_name', locale: 'it', reason: '(c) Morphit brand name' },
{ key: 'seo.site_name', locale: 'pl', reason: '(c) Morphit brand name' },
{ key: 'seo.site_name', locale: 'ru', reason: '(c) Morphit brand name' },
{ key: 'seo.site_name', locale: 'fa', reason: '(c) Morphit brand name' },
{ key: 'seo.site_name', locale: 'zh-CN', reason: '(c) Morphit brand name' },
{ key: 'seo.site_name', locale: 'zh-HK', reason: '(c) Morphit brand name' },
// ─── (c) URL/example placeholders that should NOT be localized ───
{ key: 'compare.input.placeholder', locale: 'es', reason: '(c) URL example placeholder' },
{ key: 'compare.input.placeholder', locale: 'fr', reason: '(c) URL example placeholder' },
{ key: 'compare.input.placeholder', locale: 'de', reason: '(c) URL example placeholder' },
{ key: 'compare.input.placeholder', locale: 'it', reason: '(c) URL example placeholder' },
{ key: 'compare.input.placeholder', locale: 'pl', reason: '(c) URL example placeholder' },
{ key: 'compare.input.placeholder', locale: 'ru', reason: '(c) URL example placeholder' },
{ key: 'compare.input.placeholder', locale: 'fa', reason: '(c) URL example placeholder' },
{ key: 'compare.input.placeholder', locale: 'zh-CN', reason: '(c) URL example placeholder' },
{ key: 'compare.input.placeholder', locale: 'zh-HK', reason: '(c) URL example placeholder' },
{ key: 'explorer.block.previous_link', locale: 'es', reason: '(c) pure format/anchor' },
{ key: 'explorer.block.previous_link', locale: 'fr', reason: '(c) pure format/anchor' },
{ key: 'explorer.block.previous_link', locale: 'de', reason: '(c) pure format/anchor' },
{ key: 'explorer.block.previous_link', locale: 'it', reason: '(c) pure format/anchor' },
{ key: 'explorer.block.previous_link', locale: 'pl', reason: '(c) pure format/anchor' },
{ key: 'explorer.block.previous_link', locale: 'ru', reason: '(c) pure format/anchor' },
{ key: 'explorer.block.previous_link', locale: 'fa', reason: '(c) pure format/anchor' },
{ key: 'explorer.block.previous_link', locale: 'zh-CN', reason: '(c) pure format/anchor' },
{ key: 'explorer.block.previous_link', locale: 'zh-HK', reason: '(c) pure format/anchor' },
{ key: 'explorer.search.placeholder', locale: 'es', reason: '(c) example identifier formats' },
{ key: 'explorer.search.placeholder', locale: 'fr', reason: '(c) example identifier formats' },
{ key: 'explorer.search.placeholder', locale: 'de', reason: '(c) example identifier formats' },
{ key: 'explorer.search.placeholder', locale: 'it', reason: '(c) example identifier formats' },
{ key: 'explorer.search.placeholder', locale: 'pl', reason: '(c) example identifier formats' },
{ key: 'explorer.search.placeholder', locale: 'ru', reason: '(c) example identifier formats' },
{ key: 'explorer.search.placeholder', locale: 'fa', reason: '(c) example identifier formats' },
{ key: 'explorer.search.placeholder', locale: 'zh-CN', reason: '(c) example identifier formats' },
{ key: 'explorer.search.placeholder', locale: 'zh-HK', reason: '(c) example identifier formats' },
{ key: 'settings.endpoints.add_placeholder', locale: 'fa', reason: '(c) URL example placeholder' },
{ key: 'settings.endpoints.add_placeholder', locale: 'ru', reason: '(c) URL example placeholder' },
{ key: 'settings.endpoints.add_placeholder', locale: 'zh-CN', reason: '(c) URL example placeholder' },
{ key: 'settings.endpoints.add_placeholder', locale: 'zh-HK', reason: '(c) URL example placeholder' },
// ─── Witness in zh-CN/zh-HK (already allow-listed for the others) ───
{ key: 'explorer.block.witness_label', locale: 'zh-CN', reason: '(c) Blurt-chain technical term universal' },
{ key: 'explorer.block.witness_label', locale: 'zh-HK', reason: '(c) Blurt-chain technical term universal' },
// ─── Latin-script duration abbreviations: m/h/d/mo widely shared ───
{ key: 'feature_bid.hours_option', locale: 'es', reason: '(b) "h" universal Latin-script duration shorthand' },
{ key: 'feature_bid.hours_option', locale: 'fr', reason: '(b) "h" universal Latin-script duration shorthand' },
{ key: 'feature_bid.hours_option', locale: 'de', reason: '(b) "h" universal Latin-script duration shorthand' },
{ key: 'feature_bid.hours_option', locale: 'it', reason: '(b) "h" universal Latin-script duration shorthand' },
{ key: 'feature_bid.hours_option', locale: 'pl', reason: '(b) "h" universal Latin-script duration shorthand' },
{ key: 'relative_time.terse.days', locale: 'es', reason: '(b) "d" = "días" abbreviation' },
{ key: 'relative_time.terse.days', locale: 'pl', reason: '(b) "d" = "dni" abbreviation' },
{ key: 'relative_time.terse.hours', locale: 'es', reason: '(b) "h" = "horas" abbreviation' },
{ key: 'relative_time.terse.hours', locale: 'fr', reason: '(b) "h" = "heures" abbreviation' },
{ key: 'relative_time.terse.hours', locale: 'de', reason: '(b) "h" = "Stunden" abbreviation' },
{ key: 'relative_time.terse.hours', locale: 'it', reason: '(b) "h" = "ore" abbreviation' },
{ key: 'relative_time.terse.hours', locale: 'pl', reason: '(b) "h" = "godziny" abbreviation' },
{ key: 'relative_time.terse.lt1m', locale: 'es', reason: '(b) "<1m" universal Latin-script duration shorthand' },
{ key: 'relative_time.terse.lt1m', locale: 'fr', reason: '(b) "<1m" universal Latin-script duration shorthand' },
{ key: 'relative_time.terse.lt1m', locale: 'de', reason: '(b) "<1m" universal Latin-script duration shorthand' },
{ key: 'relative_time.terse.lt1m', locale: 'it', reason: '(b) "<1m" universal Latin-script duration shorthand' },
{ key: 'relative_time.terse.lt1m', locale: 'pl', reason: '(b) "<1m" universal Latin-script duration shorthand' },
{ key: 'relative_time.terse.lt1m', locale: 'ru', reason: '(b) "<1m" used as Latin-script time shorthand even in Cyrillic UI' },
{ key: 'relative_time.terse.minutes', locale: 'es', reason: '(b) "m" = "minutos" abbreviation' },
{ key: 'relative_time.terse.minutes', locale: 'fr', reason: '(b) "m" = "minutes" abbreviation' },
{ key: 'relative_time.terse.minutes', locale: 'de', reason: '(b) "m" = "Minuten" abbreviation' },
{ key: 'relative_time.terse.minutes', locale: 'it', reason: '(b) "m" = "minuti" abbreviation' },
{ key: 'relative_time.terse.minutes', locale: 'pl', reason: '(b) "m" = "minuty" abbreviation' },
{ key: 'relative_time.terse.months', locale: 'fr', reason: '(b) "mo" = "mois" — unusual but used' },
{ key: 'clearing_price.window_label', locale: 'es', reason: '(b) "{days}d" duration shorthand' },
{ key: 'clearing_price.window_label', locale: 'pl', reason: '(b) "{days}d" duration shorthand' },
// Part 108++ — wallet brand/product names: invariant across all locales
{ key: 'post_order.fee_method.tx_proof_how_to_cli_heading', locale: 'es', reason: '(c) "Monero CLI" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_cli_heading', locale: 'fr', reason: '(c) "Monero CLI" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_cli_heading', locale: 'de', reason: '(c) "Monero CLI" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_cli_heading', locale: 'it', reason: '(c) "Monero CLI" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_cli_heading', locale: 'pl', reason: '(c) "Monero CLI" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_cli_heading', locale: 'ru', reason: '(c) "Monero CLI" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_cli_heading', locale: 'fa', reason: '(c) "Monero CLI" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_cli_heading', locale: 'zh-CN', reason: '(c) "Monero CLI" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_cli_heading', locale: 'zh-HK', reason: '(c) "Monero CLI" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_gui_heading', locale: 'es', reason: '(c) "Monero GUI" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_gui_heading', locale: 'fr', reason: '(c) "Monero GUI" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_gui_heading', locale: 'de', reason: '(c) "Monero GUI" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_gui_heading', locale: 'it', reason: '(c) "Monero GUI" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_gui_heading', locale: 'pl', reason: '(c) "Monero GUI" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_gui_heading', locale: 'ru', reason: '(c) "Monero GUI" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_gui_heading', locale: 'fa', reason: '(c) "Monero GUI" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_gui_heading', locale: 'zh-CN', reason: '(c) "Monero GUI" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_gui_heading', locale: 'zh-HK', reason: '(c) "Monero GUI" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_cake_heading', locale: 'es', reason: '(c) "Cake Wallet" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_cake_heading', locale: 'fr', reason: '(c) "Cake Wallet" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_cake_heading', locale: 'de', reason: '(c) "Cake Wallet" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_cake_heading', locale: 'it', reason: '(c) "Cake Wallet" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_cake_heading', locale: 'pl', reason: '(c) "Cake Wallet" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_cake_heading', locale: 'ru', reason: '(c) "Cake Wallet" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_cake_heading', locale: 'fa', reason: '(c) "Cake Wallet" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_cake_heading', locale: 'zh-CN', reason: '(c) "Cake Wallet" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_cake_heading', locale: 'zh-HK', reason: '(c) "Cake Wallet" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_feather_heading', locale: 'es', reason: '(c) "Feather Wallet" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_feather_heading', locale: 'fr', reason: '(c) "Feather Wallet" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_feather_heading', locale: 'de', reason: '(c) "Feather Wallet" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_feather_heading', locale: 'it', reason: '(c) "Feather Wallet" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_feather_heading', locale: 'pl', reason: '(c) "Feather Wallet" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_feather_heading', locale: 'ru', reason: '(c) "Feather Wallet" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_feather_heading', locale: 'fa', reason: '(c) "Feather Wallet" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_feather_heading', locale: 'zh-CN', reason: '(c) "Feather Wallet" is a brand/product name' },
{ key: 'post_order.fee_method.tx_proof_how_to_feather_heading', locale: 'zh-HK', reason: '(c) "Feather Wallet" is a brand/product name' },
// ─── Part 121 — USDT proper nouns ───
// "Tether" is a brand name; same spelling in all Latin-script
// locales. fa/zh-CN/zh-HK get native transliterations (تتر,
// 泰达币, 泰達幣) so they're not in the allow-list.
{ key: 'assets.usdt.displayName', locale: 'de', reason: '(c) "Tether" is a brand name' },
{ key: 'assets.usdt.displayName', locale: 'es', reason: '(c) "Tether" is a brand name' },
{ key: 'assets.usdt.displayName', locale: 'fr', reason: '(c) "Tether" is a brand name' },
{ key: 'assets.usdt.displayName', locale: 'it', reason: '(c) "Tether" is a brand name' },
{ key: 'assets.usdt.displayName', locale: 'pl', reason: '(c) "Tether" is a brand name' },
{ key: 'assets.usdt.displayName', locale: 'ru', reason: '(c) "Tether" is a brand name' },
// Network display names: chain-name + ERC/TRC/SPL/BEP standard
// suffix are technical identifiers that don't translate. fa
// transliterates the chain name to Persian script for most;
// for BNB Smart Chain even fa keeps it untranslated because
// BNB is an acronym + "Smart Chain" is a brand-product name.
{ key: 'assets.usdt.network.erc20.displayName', locale: 'de', reason: '(c) "Ethereum (ERC-20)" — brand + ERC-20 standard suffix' },
{ key: 'assets.usdt.network.erc20.displayName', locale: 'es', reason: '(c) "Ethereum (ERC-20)" — brand + ERC-20 standard suffix' },
{ key: 'assets.usdt.network.erc20.displayName', locale: 'fr', reason: '(c) "Ethereum (ERC-20)" — brand + ERC-20 standard suffix' },
{ key: 'assets.usdt.network.erc20.displayName', locale: 'it', reason: '(c) "Ethereum (ERC-20)" — brand + ERC-20 standard suffix' },
{ key: 'assets.usdt.network.erc20.displayName', locale: 'pl', reason: '(c) "Ethereum (ERC-20)" — brand + ERC-20 standard suffix' },
{ key: 'assets.usdt.network.erc20.displayName', locale: 'ru', reason: '(c) "Ethereum (ERC-20)" — brand + ERC-20 standard suffix' },
{ key: 'assets.usdt.network.trc20.displayName', locale: 'de', reason: '(c) "Tron (TRC-20)" — brand + TRC-20 standard suffix' },
{ key: 'assets.usdt.network.trc20.displayName', locale: 'es', reason: '(c) "Tron (TRC-20)" — brand + TRC-20 standard suffix' },
{ key: 'assets.usdt.network.trc20.displayName', locale: 'fr', reason: '(c) "Tron (TRC-20)" — brand + TRC-20 standard suffix' },
{ key: 'assets.usdt.network.trc20.displayName', locale: 'it', reason: '(c) "Tron (TRC-20)" — brand + TRC-20 standard suffix' },
{ key: 'assets.usdt.network.trc20.displayName', locale: 'pl', reason: '(c) "Tron (TRC-20)" — brand + TRC-20 standard suffix' },
{ key: 'assets.usdt.network.trc20.displayName', locale: 'ru', reason: '(c) "Tron (TRC-20)" — brand + TRC-20 standard suffix' },
{ key: 'assets.usdt.network.spl.displayName', locale: 'de', reason: '(c) "Solana (SPL)" — brand + SPL standard suffix' },
{ key: 'assets.usdt.network.spl.displayName', locale: 'es', reason: '(c) "Solana (SPL)" — brand + SPL standard suffix' },
{ key: 'assets.usdt.network.spl.displayName', locale: 'fr', reason: '(c) "Solana (SPL)" — brand + SPL standard suffix' },
{ key: 'assets.usdt.network.spl.displayName', locale: 'it', reason: '(c) "Solana (SPL)" — brand + SPL standard suffix' },
{ key: 'assets.usdt.network.spl.displayName', locale: 'pl', reason: '(c) "Solana (SPL)" — brand + SPL standard suffix' },
{ key: 'assets.usdt.network.spl.displayName', locale: 'ru', reason: '(c) "Solana (SPL)" — brand + SPL standard suffix' },
{ key: 'assets.usdt.network.bep20.displayName', locale: 'de', reason: '(c) "BNB Smart Chain (BEP-20)" — BNB acronym + Smart Chain brand + BEP-20 standard suffix' },
{ key: 'assets.usdt.network.bep20.displayName', locale: 'es', reason: '(c) "BNB Smart Chain (BEP-20)" — BNB acronym + Smart Chain brand + BEP-20 standard suffix' },
{ key: 'assets.usdt.network.bep20.displayName', locale: 'fa', reason: '(c) "BNB Smart Chain (BEP-20)" — BNB acronym + Smart Chain brand + BEP-20 standard suffix' },
{ key: 'assets.usdt.network.bep20.displayName', locale: 'fr', reason: '(c) "BNB Smart Chain (BEP-20)" — BNB acronym + Smart Chain brand + BEP-20 standard suffix' },
{ key: 'assets.usdt.network.bep20.displayName', locale: 'it', reason: '(c) "BNB Smart Chain (BEP-20)" — BNB acronym + Smart Chain brand + BEP-20 standard suffix' },
{ key: 'assets.usdt.network.bep20.displayName', locale: 'pl', reason: '(c) "BNB Smart Chain (BEP-20)" — BNB acronym + Smart Chain brand + BEP-20 standard suffix' },
{ key: 'assets.usdt.network.bep20.displayName', locale: 'ru', reason: '(c) "BNB Smart Chain (BEP-20)" — BNB acronym + Smart Chain brand + BEP-20 standard suffix' },
// "USDT" is a universal acronym; same spelling everywhere.
{ key: 'chat.address.method_usdt', locale: 'de', reason: '(c) "USDT" is a universal acronym' },
{ key: 'chat.address.method_usdt', locale: 'es', reason: '(c) "USDT" is a universal acronym' },
{ key: 'chat.address.method_usdt', locale: 'fa', reason: '(c) "USDT" is a universal acronym' },
{ key: 'chat.address.method_usdt', locale: 'fr', reason: '(c) "USDT" is a universal acronym' },
{ key: 'chat.address.method_usdt', locale: 'it', reason: '(c) "USDT" is a universal acronym' },
{ key: 'chat.address.method_usdt', locale: 'pl', reason: '(c) "USDT" is a universal acronym' },
{ key: 'chat.address.method_usdt', locale: 'ru', reason: '(c) "USDT" is a universal acronym' },
{ key: 'chat.address.method_usdt', locale: 'zh-CN', reason: '(c) "USDT" is a universal acronym' },
{ key: 'chat.address.method_usdt', locale: 'zh-HK', reason: '(c) "USDT" is a universal acronym' },
// ─── (c) cp64: per-asset invariants (proper nouns / acronyms / protocol identifiers) — Memory #29 native-locale policy ───
{ key: 'chat.address.method_arrr', locale: 'es', reason: `(c) "ARRR" is the universal ticker symbol; no translation` },
{ key: 'chat.address.method_arrr', locale: 'fr', reason: `(c) "ARRR" is the universal ticker symbol; no translation` },
{ key: 'chat.address.method_arrr', locale: 'de', reason: `(c) "ARRR" is the universal ticker symbol; no translation` },
{ key: 'chat.address.method_bch', locale: 'es', reason: `(c) "Bitcoin Cash" is the proper brand name; no translation` },
{ key: 'chat.address.method_bch', locale: 'fr', reason: `(c) "Bitcoin Cash" is the proper brand name; no translation` },
{ key: 'chat.address.method_bch', locale: 'de', reason: `(c) "Bitcoin Cash" is the proper brand name; no translation` },
{ key: 'chat.address.method_dai', locale: 'es', reason: `(c) "DAI" is the universal ticker symbol; no translation` },
{ key: 'chat.address.method_dai', locale: 'fr', reason: `(c) "DAI" is the universal ticker symbol; no translation` },
{ key: 'chat.address.method_dai', locale: 'de', reason: `(c) "DAI" is the universal ticker symbol; no translation` },
{ key: 'chat.address.method_dash', locale: 'es', reason: `(c) "Dash" is the proper brand name; no translation` },
{ key: 'chat.address.method_dash', locale: 'fr', reason: `(c) "Dash" is the proper brand name; no translation` },
{ key: 'chat.address.method_dash', locale: 'de', reason: `(c) "Dash" is the proper brand name; no translation` },
{ key: 'chat.address.method_dcr', locale: 'es', reason: `(c) "DCR" is the universal ticker symbol; no translation` },
{ key: 'chat.address.method_dcr', locale: 'fr', reason: `(c) "DCR" is the universal ticker symbol; no translation` },
{ key: 'chat.address.method_dcr', locale: 'de', reason: `(c) "DCR" is the universal ticker symbol; no translation` },
{ key: 'chat.address.method_doge', locale: 'es', reason: `(c) "Dogecoin" is the proper brand name; no translation` },
{ key: 'chat.address.method_doge', locale: 'fr', reason: `(c) "Dogecoin" is the proper brand name; no translation` },
{ key: 'chat.address.method_doge', locale: 'de', reason: `(c) "Dogecoin" is the proper brand name; no translation` },
{ key: 'chat.address.method_eth', locale: 'es', reason: `(c) "ETH" is the universal ticker symbol; no translation` },
{ key: 'chat.address.method_eth', locale: 'fr', reason: `(c) "ETH" is the universal ticker symbol; no translation` },
{ key: 'chat.address.method_eth', locale: 'de', reason: `(c) "ETH" is the universal ticker symbol; no translation` },
{ key: 'chat.address.method_ltc', locale: 'es', reason: `(c) "Litecoin" is the proper brand name; no translation` },
{ key: 'chat.address.method_ltc', locale: 'fr', reason: `(c) "Litecoin" is the proper brand name; no translation` },
{ key: 'chat.address.method_ltc', locale: 'de', reason: `(c) "Litecoin" is the proper brand name; no translation` },
{ key: 'chat.address.method_sol', locale: 'es', reason: `(c) "SOL" is the universal ticker symbol; no translation` },
{ key: 'chat.address.method_sol', locale: 'fr', reason: `(c) "SOL" is the universal ticker symbol; no translation` },
{ key: 'chat.address.method_sol', locale: 'de', reason: `(c) "SOL" is the universal ticker symbol; no translation` },
{ key: 'chat.address.method_usdc', locale: 'es', reason: `(c) "USDC" is the universal ticker symbol; no translation` },
{ key: 'chat.address.method_usdc', locale: 'fr', reason: `(c) "USDC" is the universal ticker symbol; no translation` },
{ key: 'chat.address.method_usdc', locale: 'de', reason: `(c) "USDC" is the universal ticker symbol; no translation` },
{ key: 'chat.address.method_xrp', locale: 'es', reason: `(c) "XRP" is the universal ticker symbol; no translation` },
{ key: 'chat.address.method_xrp', locale: 'fr', reason: `(c) "XRP" is the universal ticker symbol; no translation` },
{ key: 'chat.address.method_xrp', locale: 'de', reason: `(c) "XRP" is the universal ticker symbol; no translation` },
{ key: 'chat.address.method_zec', locale: 'es', reason: `(c) "Zcash" is the proper brand name; no translation` },
{ key: 'chat.address.method_zec', locale: 'fr', reason: `(c) "Zcash" is the proper brand name; no translation` },
{ key: 'chat.address.method_zec', locale: 'de', reason: `(c) "Zcash" is the proper brand name; no translation` },
{ key: 'chat.address.pill_method_arrr', locale: 'es', reason: `(c) "Pirate Chain (ARRR)" is the proper brand name; no translation` },
{ key: 'chat.address.pill_method_arrr', locale: 'fr', reason: `(c) "Pirate Chain (ARRR)" is the proper brand name; no translation` },
{ key: 'chat.address.pill_method_arrr', locale: 'de', reason: `(c) "Pirate Chain (ARRR)" is the proper brand name; no translation` },
{ key: 'chat.address.pill_method_dai', locale: 'es', reason: `(c) "DAI {network}" — DAI is the brand; {network} is a placeholder` },
{ key: 'chat.address.pill_method_dai', locale: 'fr', reason: `(c) "DAI {network}" — DAI is the brand; {network} is a placeholder` },
{ key: 'chat.address.pill_method_dai', locale: 'de', reason: `(c) "DAI {network}" — DAI is the brand; {network} is a placeholder` },
{ key: 'chat.address.pill_method_dcr', locale: 'es', reason: `(c) "Decred (DCR)" is the proper brand name; no translation` },
{ key: 'chat.address.pill_method_dcr', locale: 'fr', reason: `(c) "Decred (DCR)" is the proper brand name; no translation` },
{ key: 'chat.address.pill_method_dcr', locale: 'de', reason: `(c) "Decred (DCR)" is the proper brand name; no translation` },
{ key: 'chat.address.pill_method_eth', locale: 'es', reason: `(c) "Ethereum (ETH)" is the proper brand name; no translation` },
{ key: 'chat.address.pill_method_eth', locale: 'fr', reason: `(c) "Ethereum (ETH)" is the proper brand name; no translation` },
{ key: 'chat.address.pill_method_eth', locale: 'de', reason: `(c) "Ethereum (ETH)" is the proper brand name; no translation` },
{ key: 'chat.address.pill_method_sol', locale: 'es', reason: `(c) "Solana (SOL)" is the proper brand name; no translation` },
{ key: 'chat.address.pill_method_sol', locale: 'fr', reason: `(c) "Solana (SOL)" is the proper brand name; no translation` },
{ key: 'chat.address.pill_method_sol', locale: 'de', reason: `(c) "Solana (SOL)" is the proper brand name; no translation` },
{ key: 'chat.address.pill_method_xrp', locale: 'es', reason: `(c) "Ripple (XRP)" is the proper brand name; no translation` },
{ key: 'chat.address.pill_method_xrp', locale: 'fr', reason: `(c) "Ripple (XRP)" is the proper brand name; no translation` },
{ key: 'chat.address.pill_method_xrp', locale: 'de', reason: `(c) "Ripple (XRP)" is the proper brand name; no translation` },
{ key: 'assets.dai.network.arbitrum.displayName', locale: 'es', reason: `(c) "Arbitrum One" is the proper network/brand name` },
{ key: 'assets.dai.network.arbitrum.displayName', locale: 'fr', reason: `(c) "Arbitrum One" is the proper network/brand name` },
{ key: 'assets.dai.network.arbitrum.displayName', locale: 'de', reason: `(c) "Arbitrum One" is the proper network/brand name` },
{ key: 'assets.dai.network.base.displayName', locale: 'es', reason: `(c) "Base" is the proper network/brand name (Coinbase L2)` },
{ key: 'assets.dai.network.base.displayName', locale: 'fr', reason: `(c) "Base" is the proper network/brand name (Coinbase L2)` },
{ key: 'assets.dai.network.base.displayName', locale: 'de', reason: `(c) "Base" is the proper network/brand name (Coinbase L2)` },
{ key: 'assets.dai.network.erc20.displayName', locale: 'es', reason: `(c) "Ethereum (ERC-20)" is the protocol identifier` },
{ key: 'assets.dai.network.erc20.displayName', locale: 'fr', reason: `(c) "Ethereum (ERC-20)" is the protocol identifier` },
{ key: 'assets.dai.network.erc20.displayName', locale: 'de', reason: `(c) "Ethereum (ERC-20)" is the protocol identifier` },
{ key: 'assets.dai.network.polygon.displayName', locale: 'es', reason: `(c) "Polygon (PoS)" is the proper network name + protocol designation` },
{ key: 'assets.dai.network.polygon.displayName', locale: 'fr', reason: `(c) "Polygon (PoS)" is the proper network name + protocol designation` },
{ key: 'assets.dai.network.polygon.displayName', locale: 'de', reason: `(c) "Polygon (PoS)" is the proper network name + protocol designation` },
{ key: 'assets.usdc.network.base.displayName', locale: 'es', reason: `(c) "Base" is the proper network/brand name (Coinbase L2)` },
{ key: 'assets.usdc.network.base.displayName', locale: 'fr', reason: `(c) "Base" is the proper network/brand name (Coinbase L2)` },
{ key: 'assets.usdc.network.base.displayName', locale: 'de', reason: `(c) "Base" is the proper network/brand name (Coinbase L2)` },
{ key: 'assets.usdc.network.erc20.displayName', locale: 'es', reason: `(c) "Ethereum (ERC-20)" is the protocol identifier` },
{ key: 'assets.usdc.network.erc20.displayName', locale: 'fr', reason: `(c) "Ethereum (ERC-20)" is the protocol identifier` },
{ key: 'assets.usdc.network.erc20.displayName', locale: 'de', reason: `(c) "Ethereum (ERC-20)" is the protocol identifier` },
{ key: 'assets.usdc.network.polygon.displayName', locale: 'es', reason: `(c) "Polygon" is the proper network/brand name` },
{ key: 'assets.usdc.network.polygon.displayName', locale: 'fr', reason: `(c) "Polygon" is the proper network/brand name` },
{ key: 'assets.usdc.network.polygon.displayName', locale: 'de', reason: `(c) "Polygon" is the proper network/brand name` },
{ key: 'assets.usdc.network.spl.displayName', locale: 'es', reason: `(c) "Solana (SPL)" is the protocol identifier` },
{ key: 'assets.usdc.network.spl.displayName', locale: 'fr', reason: `(c) "Solana (SPL)" is the protocol identifier` },
{ key: 'assets.usdc.network.spl.displayName', locale: 'de', reason: `(c) "Solana (SPL)" is the protocol identifier` },
{ key: 'privacy.opt_in_tech.cashfusion.name', locale: 'es', reason: `(c) "CashFusion" is the proper protocol name; no translation` },
{ key: 'privacy.opt_in_tech.cashfusion.name', locale: 'fr', reason: `(c) "CashFusion" is the proper protocol name; no translation` },
{ key: 'privacy.opt_in_tech.cashfusion.name', locale: 'de', reason: `(c) "CashFusion" is the proper protocol name; no translation` },
{ key: 'privacy.opt_in_tech.coinjoin.name', locale: 'es', reason: `(c) "CoinJoin" is the proper protocol name; no translation` },
{ key: 'privacy.opt_in_tech.coinjoin.name', locale: 'fr', reason: `(c) "CoinJoin" is the proper protocol name; no translation` },
{ key: 'privacy.opt_in_tech.coinjoin.name', locale: 'de', reason: `(c) "CoinJoin" is the proper protocol name; no translation` },
{ key: 'privacy.opt_in_tech.mweb.name', locale: 'es', reason: `(c) "MWEB (MimbleWimble Extension Blocks)" is the proper protocol name` },
{ key: 'privacy.opt_in_tech.mweb.name', locale: 'fr', reason: `(c) "MWEB (MimbleWimble Extension Blocks)" is the proper protocol name` },
{ key: 'privacy.opt_in_tech.mweb.name', locale: 'de', reason: `(c) "MWEB (MimbleWimble Extension Blocks)" is the proper protocol name` },
{ key: 'privacy.opt_in_tech.payjoin.name', locale: 'es', reason: `(c) "PayJoin (BIP-78)" is the proper protocol name + BIP designation` },
{ key: 'privacy.opt_in_tech.payjoin.name', locale: 'fr', reason: `(c) "PayJoin (BIP-78)" is the proper protocol name + BIP designation` },
{ key: 'privacy.opt_in_tech.payjoin.name', locale: 'de', reason: `(c) "PayJoin (BIP-78)" is the proper protocol name + BIP designation` },
{ key: 'privacy.opt_in_tech.privatesend.name', locale: 'es', reason: `(c) "PrivateSend" is the proper protocol name (Dash); no translation` },
{ key: 'privacy.opt_in_tech.privatesend.name', locale: 'fr', reason: `(c) "PrivateSend" is the proper protocol name (Dash); no translation` },
{ key: 'privacy.opt_in_tech.privatesend.name', locale: 'de', reason: `(c) "PrivateSend" is the proper protocol name (Dash); no translation` },
{ key: 'assets.dai.price_subline.live', locale: 'es', reason: `(c) "1 DAI = \${price}" — DAI brand + placeholder, no prose` },
{ key: 'assets.dai.price_subline.live', locale: 'fr', reason: `(c) "1 DAI = \${price}" — DAI brand + placeholder, no prose` },
{ key: 'assets.dai.price_subline.live', locale: 'de', reason: `(c) "1 DAI = \${price}" — DAI brand + placeholder, no prose` },
{ key: 'assets.dai.network.picker.label', locale: 'es', reason: `(c) "DAI network" — DAI brand; "network" treated as invariant in tight UI label` },
{ key: 'assets.dai.network.picker.label', locale: 'fr', reason: `(c) "DAI network" — DAI brand; "network" treated as invariant in tight UI label` },
{ key: 'assets.dai.network.picker.label', locale: 'de', reason: `(c) "DAI network" — DAI brand; "network" treated as invariant in tight UI label` },
{ key: 'assets.dai.network.arbitrum.displayName', locale: 'it', reason: `(c) "Arbitrum One" — brand name, no translation` },
{ key: 'assets.dai.network.arbitrum.displayName', locale: 'pl', reason: `(c) "Arbitrum One" — brand name, no translation` },
{ key: 'assets.dai.network.arbitrum.displayName', locale: 'ru', reason: `(c) "Arbitrum One" — brand name, no translation` },
{ key: 'assets.dai.network.arbitrum.displayName', locale: 'fa', reason: `(c) "Arbitrum One" — brand name, no translation` },
{ key: 'assets.dai.network.arbitrum.displayName', locale: 'zh-CN', reason: `(c) "Arbitrum One" — brand name, no translation` },
{ key: 'assets.dai.network.arbitrum.displayName', locale: 'zh-HK', reason: `(c) "Arbitrum One" — brand name, no translation` },
{ key: 'assets.dai.network.base.displayName', locale: 'it', reason: `(c) "Base" — brand name, no translation` },
{ key: 'assets.dai.network.base.displayName', locale: 'pl', reason: `(c) "Base" — brand name, no translation` },
{ key: 'assets.dai.network.base.displayName', locale: 'ru', reason: `(c) "Base" — brand name, no translation` },
{ key: 'assets.dai.network.base.displayName', locale: 'fa', reason: `(c) "Base" — brand name, no translation` },
{ key: 'assets.dai.network.base.displayName', locale: 'zh-CN', reason: `(c) "Base" — brand name, no translation` },
{ key: 'assets.dai.network.base.displayName', locale: 'zh-HK', reason: `(c) "Base" — brand name, no translation` },
{ key: 'assets.dai.network.erc20.displayName', locale: 'it', reason: `(c) "Ethereum (ERC-20)" — brand + protocol name` },
{ key: 'assets.dai.network.erc20.displayName', locale: 'pl', reason: `(c) "Ethereum (ERC-20)" — brand + protocol name` },
{ key: 'assets.dai.network.erc20.displayName', locale: 'ru', reason: `(c) "Ethereum (ERC-20)" — brand + protocol name` },
{ key: 'assets.dai.network.erc20.displayName', locale: 'fa', reason: `(c) "Ethereum (ERC-20)" — brand + protocol name` },
{ key: 'assets.dai.network.erc20.displayName', locale: 'zh-CN', reason: `(c) "Ethereum (ERC-20)" — brand + protocol name` },
{ key: 'assets.dai.network.erc20.displayName', locale: 'zh-HK', reason: `(c) "Ethereum (ERC-20)" — brand + protocol name` },
{ key: 'assets.dai.network.polygon.displayName', locale: 'it', reason: `(c) "Polygon (PoS)" — brand + consensus name` },
{ key: 'assets.dai.network.polygon.displayName', locale: 'pl', reason: `(c) "Polygon (PoS)" — brand + consensus name` },
{ key: 'assets.dai.network.polygon.displayName', locale: 'ru', reason: `(c) "Polygon (PoS)" — brand + consensus name` },
{ key: 'assets.dai.network.polygon.displayName', locale: 'fa', reason: `(c) "Polygon (PoS)" — brand + consensus name` },
{ key: 'assets.dai.network.polygon.displayName', locale: 'zh-CN', reason: `(c) "Polygon (PoS)" — brand + consensus name` },
{ key: 'assets.dai.network.polygon.displayName', locale: 'zh-HK', reason: `(c) "Polygon (PoS)" — brand + consensus name` },
{ key: 'assets.usdc.network.base.displayName', locale: 'it', reason: `(c) "Base" — brand name, no translation` },
{ key: 'assets.usdc.network.base.displayName', locale: 'pl', reason: `(c) "Base" — brand name, no translation` },
{ key: 'assets.usdc.network.base.displayName', locale: 'ru', reason: `(c) "Base" — brand name, no translation` },
{ key: 'assets.usdc.network.base.displayName', locale: 'fa', reason: `(c) "Base" — brand name, no translation` },
{ key: 'assets.usdc.network.base.displayName', locale: 'zh-CN', reason: `(c) "Base" — brand name, no translation` },
{ key: 'assets.usdc.network.base.displayName', locale: 'zh-HK', reason: `(c) "Base" — brand name, no translation` },
{ key: 'assets.usdc.network.erc20.displayName', locale: 'it', reason: `(c) "Ethereum (ERC-20)" — brand + protocol name` },
{ key: 'assets.usdc.network.erc20.displayName', locale: 'pl', reason: `(c) "Ethereum (ERC-20)" — brand + protocol name` },
{ key: 'assets.usdc.network.erc20.displayName', locale: 'ru', reason: `(c) "Ethereum (ERC-20)" — brand + protocol name` },
{ key: 'assets.usdc.network.erc20.displayName', locale: 'fa', reason: `(c) "Ethereum (ERC-20)" — brand + protocol name` },
{ key: 'assets.usdc.network.erc20.displayName', locale: 'zh-CN', reason: `(c) "Ethereum (ERC-20)" — brand + protocol name` },
{ key: 'assets.usdc.network.erc20.displayName', locale: 'zh-HK', reason: `(c) "Ethereum (ERC-20)" — brand + protocol name` },
{ key: 'assets.usdc.network.polygon.displayName', locale: 'it', reason: `(c) "Polygon" — brand name` },
{ key: 'assets.usdc.network.polygon.displayName', locale: 'pl', reason: `(c) "Polygon" — brand name` },
{ key: 'assets.usdc.network.polygon.displayName', locale: 'ru', reason: `(c) "Polygon" — brand name` },
{ key: 'assets.usdc.network.polygon.displayName', locale: 'fa', reason: `(c) "Polygon" — brand name` },
{ key: 'assets.usdc.network.polygon.displayName', locale: 'zh-CN', reason: `(c) "Polygon" — brand name` },
{ key: 'assets.usdc.network.polygon.displayName', locale: 'zh-HK', reason: `(c) "Polygon" — brand name` },
{ key: 'assets.usdc.network.spl.displayName', locale: 'it', reason: `(c) "Solana (SPL)" — brand + token-program name` },
{ key: 'assets.usdc.network.spl.displayName', locale: 'pl', reason: `(c) "Solana (SPL)" — brand + token-program name` },
{ key: 'assets.usdc.network.spl.displayName', locale: 'ru', reason: `(c) "Solana (SPL)" — brand + token-program name` },
{ key: 'assets.usdc.network.spl.displayName', locale: 'fa', reason: `(c) "Solana (SPL)" — brand + token-program name` },
{ key: 'assets.usdc.network.spl.displayName', locale: 'zh-CN', reason: `(c) "Solana (SPL)" — brand + token-program name` },
{ key: 'assets.usdc.network.spl.displayName', locale: 'zh-HK', reason: `(c) "Solana (SPL)" — brand + token-program name` },
{ key: 'chat.address.method_arrr', locale: 'it', reason: `(c) "ARRR" — ticker, invariant` },
{ key: 'chat.address.method_arrr', locale: 'pl', reason: `(c) "ARRR" — ticker, invariant` },
{ key: 'chat.address.method_arrr', locale: 'ru', reason: `(c) "ARRR" — ticker, invariant` },
{ key: 'chat.address.method_arrr', locale: 'fa', reason: `(c) "ARRR" — ticker, invariant` },
{ key: 'chat.address.method_arrr', locale: 'zh-CN', reason: `(c) "ARRR" — ticker, invariant` },
{ key: 'chat.address.method_arrr', locale: 'zh-HK', reason: `(c) "ARRR" — ticker, invariant` },
{ key: 'chat.address.method_dai', locale: 'it', reason: `(c) "DAI" — ticker, invariant` },
{ key: 'chat.address.method_dai', locale: 'pl', reason: `(c) "DAI" — ticker, invariant` },
{ key: 'chat.address.method_dai', locale: 'ru', reason: `(c) "DAI" — ticker, invariant` },
{ key: 'chat.address.method_dai', locale: 'fa', reason: `(c) "DAI" — ticker, invariant` },
{ key: 'chat.address.method_dai', locale: 'zh-CN', reason: `(c) "DAI" — ticker, invariant` },
{ key: 'chat.address.method_dai', locale: 'zh-HK', reason: `(c) "DAI" — ticker, invariant` },
{ key: 'chat.address.method_dcr', locale: 'it', reason: `(c) "DCR" — ticker, invariant` },
{ key: 'chat.address.method_dcr', locale: 'pl', reason: `(c) "DCR" — ticker, invariant` },
{ key: 'chat.address.method_dcr', locale: 'ru', reason: `(c) "DCR" — ticker, invariant` },
{ key: 'chat.address.method_dcr', locale: 'fa', reason: `(c) "DCR" — ticker, invariant` },
{ key: 'chat.address.method_dcr', locale: 'zh-CN', reason: `(c) "DCR" — ticker, invariant` },
{ key: 'chat.address.method_dcr', locale: 'zh-HK', reason: `(c) "DCR" — ticker, invariant` },
{ key: 'chat.address.method_eth', locale: 'it', reason: `(c) "ETH" — ticker, invariant` },
{ key: 'chat.address.method_eth', locale: 'pl', reason: `(c) "ETH" — ticker, invariant` },
{ key: 'chat.address.method_eth', locale: 'ru', reason: `(c) "ETH" — ticker, invariant` },
{ key: 'chat.address.method_eth', locale: 'fa', reason: `(c) "ETH" — ticker, invariant` },
{ key: 'chat.address.method_eth', locale: 'zh-CN', reason: `(c) "ETH" — ticker, invariant` },
{ key: 'chat.address.method_eth', locale: 'zh-HK', reason: `(c) "ETH" — ticker, invariant` },
{ key: 'chat.address.method_sol', locale: 'it', reason: `(c) "SOL" — ticker, invariant` },
{ key: 'chat.address.method_sol', locale: 'pl', reason: `(c) "SOL" — ticker, invariant` },
{ key: 'chat.address.method_sol', locale: 'ru', reason: `(c) "SOL" — ticker, invariant` },
{ key: 'chat.address.method_sol', locale: 'fa', reason: `(c) "SOL" — ticker, invariant` },
{ key: 'chat.address.method_sol', locale: 'zh-CN', reason: `(c) "SOL" — ticker, invariant` },
{ key: 'chat.address.method_sol', locale: 'zh-HK', reason: `(c) "SOL" — ticker, invariant` },
{ key: 'chat.address.method_usdc', locale: 'it', reason: `(c) "USDC" — ticker, invariant` },
{ key: 'chat.address.method_usdc', locale: 'pl', reason: `(c) "USDC" — ticker, invariant` },
{ key: 'chat.address.method_usdc', locale: 'ru', reason: `(c) "USDC" — ticker, invariant` },
{ key: 'chat.address.method_usdc', locale: 'fa', reason: `(c) "USDC" — ticker, invariant` },
{ key: 'chat.address.method_usdc', locale: 'zh-CN', reason: `(c) "USDC" — ticker, invariant` },
{ key: 'chat.address.method_usdc', locale: 'zh-HK', reason: `(c) "USDC" — ticker, invariant` },
{ key: 'chat.address.method_xrp', locale: 'it', reason: `(c) "XRP" — ticker, invariant` },
{ key: 'chat.address.method_xrp', locale: 'pl', reason: `(c) "XRP" — ticker, invariant` },
{ key: 'chat.address.method_xrp', locale: 'ru', reason: `(c) "XRP" — ticker, invariant` },
{ key: 'chat.address.method_xrp', locale: 'fa', reason: `(c) "XRP" — ticker, invariant` },
{ key: 'chat.address.method_xrp', locale: 'zh-CN', reason: `(c) "XRP" — ticker, invariant` },
{ key: 'chat.address.method_xrp', locale: 'zh-HK', reason: `(c) "XRP" — ticker, invariant` },
{ key: 'chat.address.pill_method_arrr', locale: 'it', reason: `(c) "Pirate Chain (ARRR)" — brand name` },
{ key: 'chat.address.pill_method_arrr', locale: 'pl', reason: `(c) "Pirate Chain (ARRR)" — brand name` },
{ key: 'chat.address.pill_method_arrr', locale: 'ru', reason: `(c) "Pirate Chain (ARRR)" — brand name` },
{ key: 'chat.address.pill_method_arrr', locale: 'fa', reason: `(c) "Pirate Chain (ARRR)" — brand name` },
{ key: 'chat.address.pill_method_arrr', locale: 'zh-CN', reason: `(c) "Pirate Chain (ARRR)" — brand name` },
{ key: 'chat.address.pill_method_arrr', locale: 'zh-HK', reason: `(c) "Pirate Chain (ARRR)" — brand name` },
{ key: 'chat.address.pill_method_dai', locale: 'it', reason: `(c) "DAI {network}" — brand + placeholder` },
{ key: 'chat.address.pill_method_dai', locale: 'pl', reason: `(c) "DAI {network}" — brand + placeholder` },
{ key: 'chat.address.pill_method_dai', locale: 'ru', reason: `(c) "DAI {network}" — brand + placeholder` },
{ key: 'chat.address.pill_method_dai', locale: 'fa', reason: `(c) "DAI {network}" — brand + placeholder` },
{ key: 'chat.address.pill_method_dai', locale: 'zh-CN', reason: `(c) "DAI {network}" — brand + placeholder` },
{ key: 'chat.address.pill_method_dai', locale: 'zh-HK', reason: `(c) "DAI {network}" — brand + placeholder` },
{ key: 'chat.address.pill_method_dcr', locale: 'it', reason: `(c) "Decred (DCR)" — brand name` },
{ key: 'chat.address.pill_method_dcr', locale: 'pl', reason: `(c) "Decred (DCR)" — brand name` },
{ key: 'chat.address.pill_method_dcr', locale: 'ru', reason: `(c) "Decred (DCR)" — brand name` },
{ key: 'chat.address.pill_method_dcr', locale: 'fa', reason: `(c) "Decred (DCR)" — brand name` },
{ key: 'chat.address.pill_method_dcr', locale: 'zh-CN', reason: `(c) "Decred (DCR)" — brand name` },
{ key: 'chat.address.pill_method_dcr', locale: 'zh-HK', reason: `(c) "Decred (DCR)" — brand name` },
{ key: 'chat.address.pill_method_eth', locale: 'it', reason: `(c) "Ethereum (ETH)" — brand name` },
{ key: 'chat.address.pill_method_eth', locale: 'pl', reason: `(c) "Ethereum (ETH)" — brand name` },
{ key: 'chat.address.pill_method_eth', locale: 'ru', reason: `(c) "Ethereum (ETH)" — brand name` },
{ key: 'chat.address.pill_method_eth', locale: 'fa', reason: `(c) "Ethereum (ETH)" — brand name` },
{ key: 'chat.address.pill_method_eth', locale: 'zh-CN', reason: `(c) "Ethereum (ETH)" — brand name` },
{ key: 'chat.address.pill_method_eth', locale: 'zh-HK', reason: `(c) "Ethereum (ETH)" — brand name` },
{ key: 'chat.address.pill_method_sol', locale: 'it', reason: `(c) "Solana (SOL)" — brand name` },
{ key: 'chat.address.pill_method_sol', locale: 'pl', reason: `(c) "Solana (SOL)" — brand name` },
{ key: 'chat.address.pill_method_sol', locale: 'ru', reason: `(c) "Solana (SOL)" — brand name` },
{ key: 'chat.address.pill_method_sol', locale: 'fa', reason: `(c) "Solana (SOL)" — brand name` },
{ key: 'chat.address.pill_method_sol', locale: 'zh-CN', reason: `(c) "Solana (SOL)" — brand name` },
{ key: 'chat.address.pill_method_sol', locale: 'zh-HK', reason: `(c) "Solana (SOL)" — brand name` },
{ key: 'chat.address.pill_method_xrp', locale: 'it', reason: `(c) "Ripple (XRP)" — brand name` },
{ key: 'chat.address.pill_method_xrp', locale: 'pl', reason: `(c) "Ripple (XRP)" — brand name` },
{ key: 'chat.address.pill_method_xrp', locale: 'ru', reason: `(c) "Ripple (XRP)" — brand name` },
{ key: 'chat.address.pill_method_xrp', locale: 'fa', reason: `(c) "Ripple (XRP)" — brand name` },
{ key: 'chat.address.pill_method_xrp', locale: 'zh-CN', reason: `(c) "Ripple (XRP)" — brand name` },
{ key: 'chat.address.pill_method_xrp', locale: 'zh-HK', reason: `(c) "Ripple (XRP)" — brand name` },
{ key: 'assets.dai.price_subline.live', locale: 'it', reason: `(c) "1 DAI = \${price}" — DAI brand + placeholder` },
{ key: 'assets.dai.price_subline.live', locale: 'pl', reason: `(c) "1 DAI = \${price}" — DAI brand + placeholder` },
{ key: 'assets.dai.price_subline.live', locale: 'ru', reason: `(c) "1 DAI = \${price}" — DAI brand + placeholder` },
{ key: 'assets.dai.price_subline.live', locale: 'fa', reason: `(c) "1 DAI = \${price}" — DAI brand + placeholder` },
{ key: 'assets.dai.price_subline.live', locale: 'zh-CN', reason: `(c) "1 DAI = \${price}" — DAI brand + placeholder` },
{ key: 'assets.dai.price_subline.live', locale: 'zh-HK', reason: `(c) "1 DAI = \${price}" — DAI brand + placeholder` },
{ key: 'privacy.opt_in_tech.cashfusion.name', locale: 'it', reason: `(c) "CashFusion" — protocol name (BCH)` },
{ key: 'privacy.opt_in_tech.cashfusion.name', locale: 'pl', reason: `(c) "CashFusion" — protocol name (BCH)` },
{ key: 'privacy.opt_in_tech.cashfusion.name', locale: 'ru', reason: `(c) "CashFusion" — protocol name (BCH)` },
{ key: 'privacy.opt_in_tech.cashfusion.name', locale: 'fa', reason: `(c) "CashFusion" — protocol name (BCH)` },
{ key: 'privacy.opt_in_tech.cashfusion.name', locale: 'zh-CN', reason: `(c) "CashFusion" — protocol name (BCH)` },
{ key: 'privacy.opt_in_tech.cashfusion.name', locale: 'zh-HK', reason: `(c) "CashFusion" — protocol name (BCH)` },
{ key: 'privacy.opt_in_tech.coinjoin.name', locale: 'it', reason: `(c) "CoinJoin" — protocol name (BTC)` },
{ key: 'privacy.opt_in_tech.coinjoin.name', locale: 'pl', reason: `(c) "CoinJoin" — protocol name (BTC)` },
{ key: 'privacy.opt_in_tech.coinjoin.name', locale: 'ru', reason: `(c) "CoinJoin" — protocol name (BTC)` },
{ key: 'privacy.opt_in_tech.coinjoin.name', locale: 'fa', reason: `(c) "CoinJoin" — protocol name (BTC)` },
{ key: 'privacy.opt_in_tech.coinjoin.name', locale: 'zh-CN', reason: `(c) "CoinJoin" — protocol name (BTC)` },
{ key: 'privacy.opt_in_tech.coinjoin.name', locale: 'zh-HK', reason: `(c) "CoinJoin" — protocol name (BTC)` },
{ key: 'privacy.opt_in_tech.mweb.name', locale: 'it', reason: `(c) "MWEB (MimbleWimble Extension Blocks)" — protocol acronym` },
{ key: 'privacy.opt_in_tech.mweb.name', locale: 'pl', reason: `(c) "MWEB (MimbleWimble Extension Blocks)" — protocol acronym` },
{ key: 'privacy.opt_in_tech.mweb.name', locale: 'ru', reason: `(c) "MWEB (MimbleWimble Extension Blocks)" — protocol acronym` },
{ key: 'privacy.opt_in_tech.mweb.name', locale: 'fa', reason: `(c) "MWEB (MimbleWimble Extension Blocks)" — protocol acronym` },
{ key: 'privacy.opt_in_tech.mweb.name', locale: 'zh-CN', reason: `(c) "MWEB (MimbleWimble Extension Blocks)" — protocol acronym` },
{ key: 'privacy.opt_in_tech.mweb.name', locale: 'zh-HK', reason: `(c) "MWEB (MimbleWimble Extension Blocks)" — protocol acronym` },
{ key: 'privacy.opt_in_tech.payjoin.name', locale: 'it', reason: `(c) "PayJoin (BIP-78)" — protocol name + BIP` },
{ key: 'privacy.opt_in_tech.payjoin.name', locale: 'pl', reason: `(c) "PayJoin (BIP-78)" — protocol name + BIP` },
{ key: 'privacy.opt_in_tech.payjoin.name', locale: 'ru', reason: `(c) "PayJoin (BIP-78)" — protocol name + BIP` },
{ key: 'privacy.opt_in_tech.payjoin.name', locale: 'fa', reason: `(c) "PayJoin (BIP-78)" — protocol name + BIP` },
{ key: 'privacy.opt_in_tech.payjoin.name', locale: 'zh-CN', reason: `(c) "PayJoin (BIP-78)" — protocol name + BIP` },
{ key: 'privacy.opt_in_tech.payjoin.name', locale: 'zh-HK', reason: `(c) "PayJoin (BIP-78)" — protocol name + BIP` },
{ key: 'privacy.opt_in_tech.privatesend.name', locale: 'it', reason: `(c) "PrivateSend" — protocol name (Dash)` },
{ key: 'privacy.opt_in_tech.privatesend.name', locale: 'pl', reason: `(c) "PrivateSend" — protocol name (Dash)` },
{ key: 'privacy.opt_in_tech.privatesend.name', locale: 'ru', reason: `(c) "PrivateSend" — protocol name (Dash)` },
{ key: 'privacy.opt_in_tech.privatesend.name', locale: 'fa', reason: `(c) "PrivateSend" — protocol name (Dash)` },
{ key: 'privacy.opt_in_tech.privatesend.name', locale: 'zh-CN', reason: `(c) "PrivateSend" — protocol name (Dash)` },
{ key: 'privacy.opt_in_tech.privatesend.name', locale: 'zh-HK', reason: `(c) "PrivateSend" — protocol name (Dash)` },
{ key: 'chat.address.method_bch', locale: 'it', reason: `(c) "Bitcoin Cash" — brand name` },
{ key: 'chat.address.method_bch', locale: 'pl', reason: `(c) "Bitcoin Cash" — brand name` },
{ key: 'chat.address.method_bch', locale: 'ru', reason: `(c) "Bitcoin Cash" — brand name` },
{ key: 'chat.address.method_bch', locale: 'fa', reason: `(c) "Bitcoin Cash" — brand name` },
{ key: 'chat.address.method_bch', locale: 'zh-CN', reason: `(c) "Bitcoin Cash" — brand name` },
{ key: 'chat.address.method_bch', locale: 'zh-HK', reason: `(c) "Bitcoin Cash" — brand name` },
{ key: 'chat.address.method_dash', locale: 'it', reason: `(c) "Dash" — brand name` },
{ key: 'chat.address.method_dash', locale: 'pl', reason: `(c) "Dash" — brand name` },
{ key: 'chat.address.method_dash', locale: 'ru', reason: `(c) "Dash" — brand name` },
{ key: 'chat.address.method_dash', locale: 'fa', reason: `(c) "Dash" — brand name` },
{ key: 'chat.address.method_dash', locale: 'zh-CN', reason: `(c) "Dash" — brand name` },
{ key: 'chat.address.method_dash', locale: 'zh-HK', reason: `(c) "Dash" — brand name` },
{ key: 'chat.address.method_doge', locale: 'it', reason: `(c) "Dogecoin" — brand name` },
{ key: 'chat.address.method_doge', locale: 'pl', reason: `(c) "Dogecoin" — brand name` },
{ key: 'chat.address.method_doge', locale: 'ru', reason: `(c) "Dogecoin" — brand name` },
{ key: 'chat.address.method_doge', locale: 'fa', reason: `(c) "Dogecoin" — brand name` },
{ key: 'chat.address.method_doge', locale: 'zh-CN', reason: `(c) "Dogecoin" — brand name` },
{ key: 'chat.address.method_doge', locale: 'zh-HK', reason: `(c) "Dogecoin" — brand name` },
{ key: 'chat.address.method_ltc', locale: 'it', reason: `(c) "Litecoin" — brand name` },
{ key: 'chat.address.method_ltc', locale: 'pl', reason: `(c) "Litecoin" — brand name` },
{ key: 'chat.address.method_ltc', locale: 'ru', reason: `(c) "Litecoin" — brand name` },
{ key: 'chat.address.method_ltc', locale: 'fa', reason: `(c) "Litecoin" — brand name` },
{ key: 'chat.address.method_ltc', locale: 'zh-CN', reason: `(c) "Litecoin" — brand name` },
{ key: 'chat.address.method_ltc', locale: 'zh-HK', reason: `(c) "Litecoin" — brand name` },
{ key: 'chat.address.method_zec', locale: 'it', reason: `(c) "Zcash" — brand name` },
{ key: 'chat.address.method_zec', locale: 'pl', reason: `(c) "Zcash" — brand name` },
{ key: 'chat.address.method_zec', locale: 'ru', reason: `(c) "Zcash" — brand name` },
{ key: 'chat.address.method_zec', locale: 'fa', reason: `(c) "Zcash" — brand name` },
{ key: 'chat.address.method_zec', locale: 'zh-CN', reason: `(c) "Zcash" — brand name` },
{ key: 'chat.address.method_zec', locale: 'zh-HK', reason: `(c) "Zcash" — brand name` },
{ key: 'assets.usdc.price_subline.live', locale: 'it', reason: `(c) "1 USDC = \${price} live" — brand + placeholder; "live" stays English in most locales as a UI status indicator` },
{ key: 'assets.usdc.price_subline.live', locale: 'pl', reason: `(c) "1 USDC = \${price} live" — brand + placeholder; "live" stays English in most locales as a UI status indicator` },
{ key: 'assets.usdc.price_subline.live', locale: 'ru', reason: `(c) "1 USDC = \${price} live" — brand + placeholder; "live" stays English in most locales as a UI status indicator` },
{ key: 'assets.usdc.price_subline.live', locale: 'fa', reason: `(c) "1 USDC = \${price} live" — brand + placeholder; "live" stays English in most locales as a UI status indicator` },
{ key: 'assets.usdc.price_subline.live', locale: 'zh-CN', reason: `(c) "1 USDC = \${price} live" — brand + placeholder; "live" stays English in most locales as a UI status indicator` },
{ key: 'assets.usdc.price_subline.live', locale: 'zh-HK', reason: `(c) "1 USDC = \${price} live" — brand + placeholder; "live" stays English in most locales as a UI status indicator` },
// ─── cp116 setup-wizard same-spelling cases: short labels that
// legitimately match English in some locales. ──────────────
{ key: 'admin.setup_wizard.payment.category_online', locale: 'de', reason: `(b) "Online" is the same word in German UI conventions; identical to EN by accepted usage` },
{ key: 'admin.setup_wizard.payment.category_crypto', locale: 'fr', reason: `(b) "Crypto" is the same word in French UI conventions; identical to EN by accepted usage` },
{ key: 'admin.setup_wizard.payment.description_label', locale: 'fr', reason: `(b) "Description" is the same word in French; identical to EN by spelling identity` },
// ─── ADR-0043 / cp132 2FA: closed-source-authenticator brand
// names that do NOT translate. Google Authenticator,
// Microsoft Authenticator, and Authy are product names
// trademarked by their respective vendors; their .name
// fields render identically in every locale by design.
// The .reason field beside each name IS translated. ──
{ key: 'settings.totp.not_recommended_apps.google_authenticator.name', locale: 'de', reason: '(c) "Google Authenticator" is a registered product name; does not translate' },
{ key: 'settings.totp.not_recommended_apps.google_authenticator.name', locale: 'es', reason: '(c) "Google Authenticator" is a registered product name; does not translate' },
{ key: 'settings.totp.not_recommended_apps.google_authenticator.name', locale: 'fr', reason: '(c) "Google Authenticator" is a registered product name; does not translate' },
{ key: 'settings.totp.not_recommended_apps.microsoft_authenticator.name', locale: 'de', reason: '(c) "Microsoft Authenticator" is a registered product name; does not translate' },
{ key: 'settings.totp.not_recommended_apps.microsoft_authenticator.name', locale: 'es', reason: '(c) "Microsoft Authenticator" is a registered product name; does not translate' },
{ key: 'settings.totp.not_recommended_apps.microsoft_authenticator.name', locale: 'fr', reason: '(c) "Microsoft Authenticator" is a registered product name; does not translate' },
{ key: 'settings.totp.not_recommended_apps.authy.name', locale: 'de', reason: '(c) "Authy" is a registered product name; does not translate' },
{ key: 'settings.totp.not_recommended_apps.authy.name', locale: 'es', reason: '(c) "Authy" is a registered product name; does not translate' },
{ key: 'settings.totp.not_recommended_apps.authy.name', locale: 'fr', reason: '(c) "Authy" is a registered product name; does not translate' },
// cp396 — "Blockchain" is a universally-adopted loanword; the body text in
// each of these locales uses it verbatim, so the glossary TITLE matches it
// by design. (it/pl already use "blockchain" elsewhere and pass the
// heuristic; ru/fa/zh translate it: Блокчейн / بلاکچین / 区块链 / 區塊鏈.)
{ key: 'glossary.blockchain.title', locale: 'de', reason: '(b) "Blockchain" is a universal tech loanword (Duden-listed); body uses it verbatim' },
{ key: 'glossary.blockchain.title', locale: 'es', reason: '(b) "Blockchain" is a universal tech loanword; body uses it verbatim' },
{ key: 'glossary.blockchain.title', locale: 'fr', reason: '(b) "Blockchain" is a universal tech loanword; body uses it verbatim' },
{ key: 'orderbook.card.message_word', locale: 'fr', reason: '(a) "Message" is the same word in French; translating it would be wrong (cp404)' },
{ key: 'chat.export.parties_heading', locale: 'fr', reason: '(a) "Parties" is the same word in French — the parties to an agreement (cp404)' },
// cp424 — "Power up" / "Power down" are Blurt operation terms of art,
// kept verbatim like BLURT / BP. blurtwallet.com and Morphit's own FAQ
// (all 10 locales) use them untranslated; the wallet modal's subtitles
// + schedule notice ARE fully translated around them.
{ key: 'profile.wallet.power_up_action', locale: 'de', reason: '(b) "Power up" is a Blurt term of art (loanword); FAQ + blurtwallet.com keep it verbatim' },
{ key: 'profile.wallet.power_up_action', locale: 'es', reason: '(b) "Power up" is a Blurt term of art (loanword); FAQ + blurtwallet.com keep it verbatim' },
{ key: 'profile.wallet.power_up_action', locale: 'fr', reason: '(b) "Power up" is a Blurt term of art (loanword); FAQ + blurtwallet.com keep it verbatim' },
{ key: 'profile.wallet.power_down_action', locale: 'de', reason: '(b) "Power down" is a Blurt term of art (loanword); FAQ + blurtwallet.com keep it verbatim' },
{ key: 'profile.wallet.power_down_action', locale: 'es', reason: '(b) "Power down" is a Blurt term of art (loanword); FAQ + blurtwallet.com keep it verbatim' },
{ key: 'profile.wallet.power_down_action', locale: 'fr', reason: '(b) "Power down" is a Blurt term of art (loanword); FAQ + blurtwallet.com keep it verbatim' },
{ key: 'profile.wallet.power_up_title', locale: 'de', reason: '(c) "Power up BLURT" is all Blurt terms (Power up + BLURT); invariant across locales' },
{ key: 'profile.wallet.power_up_title', locale: 'es', reason: '(c) "Power up BLURT" is all Blurt terms (Power up + BLURT); invariant across locales' },
{ key: 'profile.wallet.power_up_title', locale: 'fr', reason: '(c) "Power up BLURT" is all Blurt terms (Power up + BLURT); invariant across locales' },
{ key: 'profile.wallet.power_down_title', locale: 'de', reason: '(c) "Power down BP" is all Blurt terms (Power down + BP); invariant across locales' },
{ key: 'profile.wallet.power_down_title', locale: 'es', reason: '(c) "Power down BP" is all Blurt terms (Power down + BP); invariant across locales' },
{ key: 'profile.wallet.power_down_title', locale: 'fr', reason: '(c) "Power down BP" is all Blurt terms (Power down + BP); invariant across locales' },
// cp466 — the #2 Terms markdown-guide modal (post_order.terms_md_guide.*).
// German translates most element names (Heading→Überschrift, Bold→Fett,
// Link's row label stays a table cell) but two are byte-identical to English
// by correct German usage, not a miss: "Element" is a German cognate, and
// "Link" is the standard German loanword for a hyperlink (der Link).
{ key: 'post_order.terms_md_guide.col_element', locale: 'de', reason: '(a) "Element" is a German cognate — spelled identically to English' },
{ key: 'post_order.terms_md_guide.el_link', locale: 'de', reason: '(b) "Link" is the standard German loanword for a hyperlink (der Link)' },
// ─── FAQ glossary acronyms (2026-07-19, Ken): the 12 technical
// acronyms added as glossary terms have TITLES equal to the
// acronym itself (ECIES / X25519 / TLS / …). Acronyms are not
// translated, so the title is byte-identical to English in every
// locale by design — exactly like the Blurt key-role identifiers
// above. The BODIES are fully translated. (c) invariant.
{ key: 'glossary.aead.title', locale: 'de', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.aead.title', locale: 'es', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.aead.title', locale: 'fr', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.dns.title', locale: 'de', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.dns.title', locale: 'es', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.dns.title', locale: 'fr', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.ecdh.title', locale: 'de', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.ecdh.title', locale: 'es', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.ecdh.title', locale: 'fr', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.ecies.title', locale: 'de', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.ecies.title', locale: 'es', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.ecies.title', locale: 'fr', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.ens.title', locale: 'de', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.ens.title', locale: 'es', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.ens.title', locale: 'fr', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.ipfs.title', locale: 'de', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.ipfs.title', locale: 'es', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.ipfs.title', locale: 'fr', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.mcp.title', locale: 'de', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.mcp.title', locale: 'es', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.mcp.title', locale: 'fr', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.p2p.title', locale: 'de', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.p2p.title', locale: 'es', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.p2p.title', locale: 'fr', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.pwa.title', locale: 'de', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.pwa.title', locale: 'es', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.pwa.title', locale: 'fr', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.rss.title', locale: 'de', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.rss.title', locale: 'es', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.rss.title', locale: 'fr', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.tls.title', locale: 'de', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.tls.title', locale: 'es', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.tls.title', locale: 'fr', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.x25519.title', locale: 'de', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.x25519.title', locale: 'es', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
{ key: 'glossary.x25519.title', locale: 'fr', reason: '(c) universal acronym / technical identifier — not translated in any locale' },
// Website / Streaming profile cards (cp506)
{ key: 'footer.globe', locale: 'de', reason: '(b) "Website" is a German loanword, spelled identically to English' },
{ key: 'identity.website_link_tooltip', locale: 'de', reason: '(b) "Website" is a German loanword, spelled identically to English' },
{ key: 'footer.play', locale: 'de', reason: '(b) "Streaming" is a loanword, spelled identically to English' },
{ key: 'footer.play', locale: 'es', reason: '(b) "Streaming" is a loanword, spelled identically to English' },
{ key: 'footer.play', locale: 'fr', reason: '(b) "Streaming" is a loanword, spelled identically to English' },
{ key: 'settings.website_url.placeholder', locale: 'de', reason: '(c) "https://..." URL placeholder template — invariant across locales' },
{ key: 'settings.website_url.placeholder', locale: 'es', reason: '(c) "https://..." URL placeholder template — invariant across locales' },
{ key: 'settings.website_url.placeholder', locale: 'fr', reason: '(c) "https://..." URL placeholder template — invariant across locales' },
// v1.8.11 — the visibility badge. "Public" is genuinely the French word for
// public; there is no distinct native alternative to reach for, unlike the
// v1.8.9 case where FR "Syndication" was replaced with the natural
// "Diffusion" rather than allow-listed. The sibling strings (private,
// device, and all three detail sentences) ARE translated, so this is a
// single-word coincidence and not an untranslated section.
{ key: 'settings.visibility.public', locale: 'fr', reason: '(b) coincidental same spelling — "Public" is the correct French word' },
// t.txt #3 — the operators-subtitle linked word. "instances" is the same word
// in French and English (coincidental same spelling / loanword); the sibling
// subtitle text is fully translated, so this is a single-word coincidence, not
// an untranslated miss.
{ key: 'operators.subtitle_instances_link', locale: 'fr', reason: '(b) "instances" is the same word in French and English — coincidental same spelling; the linked word in the operators subtitle' }
];
const allowSet = new Set(ALLOW_LIST.map((e) => `${e.key}::${e.locale}`));
// ─── Find genuine misses ───────────────────────────────────
//
// Definition: a key whose value in some locale L is byte-identical
// to its English value, AND that pairing is NOT in the allow-list.
// We don't filter by translation-coverage threshold — every miss
// must be allow-listed or fixed.
interface Finding { key: string; locale: string; value: string }
const findings: Finding[] = [];
// Memory #29 policy on locale-translation requirements:
// - en/es/fr/de: MUST be natively translated for new keys
// (the "native-translation locales").
// - fa/it/pl/ru/zh-CN/zh-HK: EN-fallback acceptable as
// community-translation backlog (the "policy-fallback
// locales"). Each EN-identical string in these locales is
// the documented Memory #29 backlog state, NOT a translation
// miss. This smoke skips the byte-identical check for them.
//
// The native-translations-floor-smoke (LL #47) covers the
// orthogonal regression case — "going down" from a previously-
// native string back to EN-fallback — for ALL 9 non-EN locales.
// This smoke handles the "must be native per policy" forward
// gate for es/fr/de only.
const POLICY_FALLBACK_LOCALES = new Set(['fa', 'it', 'pl', 'ru', 'zh-CN', 'zh-HK']);
for (const [k, enV] of en) {
if (!enV || enV.trim() === '') continue;
// Skip strings that are pure format/identifiers (no alpha chars).
if (![...enV].some((c) => /[a-zA-Z]/.test(c))) continue;
for (const l of nonEn) {
if (POLICY_FALLBACK_LOCALES.has(l)) continue; // Memory #29 backlog (reduced to ~49 long-form keys at cp68)
const lV = data.get(l)!.get(k);
if (lV === undefined) continue; // structural drift caught by parity smoke
if (lV !== enV) continue; // translated, fine
if (allowSet.has(`${k}::${l}`)) continue;
findings.push({ key: k, locale: l, value: enV });
}
}
// ─── Reporting ─────────────────────────────────────────────
console.log('');
console.log('── i18n translation completeness smoke ─────────────────');
console.log('');
// ─── v1.7.7: WRONG-SCRIPT LEAK ──────────────────────────────────────
// A single Chinese character sat in the middle of a Russian sentence
// ("но他 делает") and 3,368 i18n checks passed. Key coverage was fine, parity
// was fine, dead keys were fine — every existing guard asks "is the key there?"
// and none asks "is the text in the right alphabet?".
//
// This is a translation-time hazard, not a typo: when ten locales are written in
// one pass, characters bleed between them. It is also nearly invisible on
// review, because catching it means reading a language you may not speak and
// noticing one glyph. A machine notices instantly.
//
// Deliberately narrow — it only flags a locale carrying a script that has no
// business in it at all. It says nothing about Latin text inside a non-Latin
// locale, because brand names, protocol terms and placeholders legitimately stay
// Latin everywhere (there is already a reasoned allow-list above for exactly
// that). Han characters in Cyrillic prose, or Cyrillic in Persian, are never
// deliberate.
const HAN = /[\u4e00-\u9fff\u3400-\u4dbf]/;
const CYRILLIC = /[\u0400-\u04ff]/;
const ARABIC = /[\u0600-\u06ff]/;
const HANGUL = /[\uac00-\ud7af]/;
const KANA = /[\u3040-\u30ff]/;
/** Scripts that must NEVER appear in a given locale's strings. */
const FORBIDDEN_SCRIPTS: Record<string, Array<{ name: string; re: RegExp }>> = {
en: [{ name: 'Han', re: HAN }, { name: 'Cyrillic', re: CYRILLIC }, { name: 'Arabic', re: ARABIC }, { name: 'Hangul', re: HANGUL }, { name: 'Kana', re: KANA }],
es: [{ name: 'Han', re: HAN }, { name: 'Cyrillic', re: CYRILLIC }, { name: 'Arabic', re: ARABIC }, { name: 'Hangul', re: HANGUL }, { name: 'Kana', re: KANA }],
fr: [{ name: 'Han', re: HAN }, { name: 'Cyrillic', re: CYRILLIC }, { name: 'Arabic', re: ARABIC }, { name: 'Hangul', re: HANGUL }, { name: 'Kana', re: KANA }],
de: [{ name: 'Han', re: HAN }, { name: 'Cyrillic', re: CYRILLIC }, { name: 'Arabic', re: ARABIC }, { name: 'Hangul', re: HANGUL }, { name: 'Kana', re: KANA }],
it: [{ name: 'Han', re: HAN }, { name: 'Cyrillic', re: CYRILLIC }, { name: 'Arabic', re: ARABIC }, { name: 'Hangul', re: HANGUL }, { name: 'Kana', re: KANA }],
pl: [{ name: 'Han', re: HAN }, { name: 'Cyrillic', re: CYRILLIC }, { name: 'Arabic', re: ARABIC }, { name: 'Hangul', re: HANGUL }, { name: 'Kana', re: KANA }],
// Russian legitimately carries Latin brand names; Han/Arabic/Hangul/Kana never.
ru: [{ name: 'Han', re: HAN }, { name: 'Arabic', re: ARABIC }, { name: 'Hangul', re: HANGUL }, { name: 'Kana', re: KANA }],
// Persian legitimately carries Latin brand names and Arabic script IS its script.
fa: [{ name: 'Han', re: HAN }, { name: 'Cyrillic', re: CYRILLIC }, { name: 'Hangul', re: HANGUL }, { name: 'Kana', re: KANA }],
// Chinese legitimately carries Latin brand names; Cyrillic/Arabic/Hangul never.
// Kana is excluded: it is NOT Chinese, and a stray one means text bled in.
'zh-CN': [{ name: 'Cyrillic', re: CYRILLIC }, { name: 'Arabic', re: ARABIC }, { name: 'Hangul', re: HANGUL }, { name: 'Kana', re: KANA }],
'zh-HK': [{ name: 'Cyrillic', re: CYRILLIC }, { name: 'Arabic', re: ARABIC }, { name: 'Hangul', re: HANGUL }, { name: 'Kana', re: KANA }]
};
const scriptLeaks: string[] = [];
for (const loc of locales) {
const forbidden = FORBIDDEN_SCRIPTS[loc];
if (forbidden === undefined) continue;
const strings = data.get(loc);
if (strings === undefined) continue;
for (const [key, value] of strings) {
for (const { name, re } of forbidden) {
const m = re.exec(value);
if (m !== null) {
scriptLeaks.push(`${loc}: ${name} character ${JSON.stringify(m[0])} in ${key}`);
}
}
}
}
const scenarios = [
{
name: `no wrong-script leaks across all ${SUPPORTED_LOCALES.length} locales`,
ok: scriptLeaks.length === 0,
detail: scriptLeaks.slice(0, 5).join('; ')
},
{
name: `all ${SUPPORTED_LOCALES.length} locale files were loaded successfully`,
ok: locales.length === SUPPORTED_LOCALES.length
},
{
name: 'EN source-of-truth has at least 2,000 string keys',
ok: en.size >= 2000
},
{
name: 'allow-list has documented justifications for every entry',
ok: ALLOW_LIST.every((e) => e.reason && e.reason.trim().length > 5)
},
{
name: 'no string is byte-identical to English in a locale outside the allow-list',
ok: findings.length === 0
}
];
if (findings.length > 0) {
console.log(` ${findings.length} unexpected EN-byte-identical entries:`);
const byKey = new Map<string, string[]>();
for (const f of findings) {
if (!byKey.has(f.key)) byKey.set(f.key, []);
byKey.get(f.key)!.push(f.locale);
}
for (const [k, ls] of [...byKey.entries()].sort()) {
const enV = en.get(k)!;
const preview = enV.length > 50 ? enV.slice(0, 47) + '…' : enV;
console.log(` ${k}: ${JSON.stringify(preview)} [${ls.sort().join(', ')}]`);
}
console.log('');
console.log(' Each finding is either (a) a real translation miss — fix the locale,');
console.log(' or (b) a legitimate same-spelling/loanword/invariant — add to the');
console.log(' ALLOW_LIST in this smoke with a documented (a/b/c) reason.');
console.log('');
}
let passed = 0;
let failed = 0;
const failures: string[] = [];
for (const s of scenarios) {
if (s.ok) passed++;
else {
failed++;
failures.push(`${s.name}`);
}
}
if (failures.length > 0) {
console.log(failures.join('\n'));
console.log('');
}
console.log('────────────────────────────────────────────────────────');
if (failed === 0) {
console.log(`✓ all ${passed} scenarios passed`);
process.exit(0);
} else {
console.log(`${failed} of ${passed + failed} scenarios failed`);
process.exit(1);
}