ITADN

Feature request: named object substitutions in i18n.t()

#2332Openoyzamil 创建于 2026-05-03
contribution welcomegood first issue
O
oyzamilcommented
### Feature Request Add support for passing a plain object as the substitution argument to `i18n.t()`, allowing named `{placeholder}` syntax in message strings as an alternative to the positional `$1–$9` approach. ## 🔥 Motivation The current positional substitution system works well for simple cases, but becomes fragile and hard to read when a message has 2 or more dynamic values: ```yaml # en.yml msg: My name is $1, and I create extensions using $2. ``` ```ts i18n.t('msg', ['Muzamil', 'WXT']) ``` **Problems with positional substitutions at scale:** - **Order-dependent** — reordering args silently breaks translations - **No translator context** — `$1` and `$2` give translators no hint of what the values represent - **Hard to maintain** — readability degrades quickly with 3+ substitutions - **Word order inflexibility** — some languages require a different word order than English, which positional args can't support ## ✅ Proposed API ```yaml # en.yml msg: My name is {name}, and I create extensions using {tool}. ``` ```ts i18n.t('msg', { name: 'Muzamil', tool: 'WXT', }) // => "My name is Muzamil, and I create extensions using WXT." ``` ## ✅ Expected behaviour - Object keys map to `{key}` tokens in the message string - Unmatched placeholders are left as-is — no silent empty strings - Fully backward-compatible — existing `$1–$9` array substitutions are unchanged - Works alongside plural forms — count as second arg, object as third - Type-safe: TypeScript can infer required keys from the message template ## ✅ Reference implementation The core logic is a single regex replace — minimal surface area, no new dependencies: ```ts // In packages/i18n/src/index.ts // Detect object arg alongside existing number/array detection } else if (typeof arg === 'object' && !Array.isArray(arg)) { objectSub = arg; } // Apply after browser.i18n.getMessage resolves the message if (objectSub) { message = message.replace(/\{(\w+)\}/g, (match, key) => Object.prototype.hasOwnProperty.call(objectSub, key) ? String(objectSub[key]) : match ); } ``` ## ✅ Notes Happy to open a PR with a full implementation including type definitions and tests if this direction is approved.
6 条评论