Interpolation
Placeholders are values you splice into a translation string at runtime.
Default pattern: :name
extend("en", { greet: "Hello :name", create: "Create New :item",});
trans("greet", { name: "Ada" }); // "Hello Ada"trans("create", { item: "Category" }); // "Create New Category"A placeholder name must match [a-zA-Z0-9_-]+ and is prefixed by :. If a placeholder name has no matching key in the passed object, it’s left in the output as-is:
trans("greet", {}); // "Hello :name"trans("greet", { name: "Ada", extra: 1 }); // "Hello Ada" (extras ignored)Numbers are stringified via .toString().
Switching the pattern
setLocalizationConfigurations({ placeholderPattern: "doubleCurly", // "colon" | "doubleCurly" | RegExp});
extend("en", { greet: "Hi {{name}}" });trans("greet", { name: "Ada" }); // "Hi Ada"For something custom, pass a RegExp with one capture group (the placeholder name):
setLocalizationConfigurations({ placeholderPattern: /\$\{([a-zA-Z]+)\}/g,});
extend("en", { greet: "Hi ${name}" });trans("greet", { name: "Ada" }); // "Hi Ada"The pattern is global module state. Once changed, every subsequent translation uses it. There’s no per-call override for the pattern.
The default converter
function plainConverter( translation: string, placeholders: { [key: string]: string | number | undefined } = {}, placeholderPattern: RegExp = /:([a-zA-Z0-9_-]+)/g,): string;plainConverter is String.prototype.replace over the placeholder pattern. Imported directly for testing or manual conversion:
import { plainConverter } from "@mongez/localization";
plainConverter("Hello :name", { name: "Ada" }); // "Hello Ada"Custom converters
A converter is (translation, placeholders, placeholderPattern) => any. The return type is not constrained — jsxConverter returns an array of React fragments rather than a string.
import { setLocalizationConfigurations } from "@mongez/localization";
setLocalizationConfigurations({ converter: (text, placeholders, pattern) => { return text.replace(pattern, (_, key) => `[${placeholders[key]}]`); },});
trans("greet", { name: "Ada" }); // "Hello [Ada]"Or via setConverter directly:
import { setConverter, plainConverter } from "@mongez/localization";
setConverter(myConverter);// ... later, restore the default:setConverter(plainConverter);When the converter runs
A converter is only invoked when trans / transFrom is called with a placeholders argument. A bare trans("home") returns the raw translation string with no converter call. This matters when you switch to jsxConverter globally — keywords without placeholders still return plain strings, not JSX nodes.
import { jsxConverter } from "@mongez/react-localization";setConverter(jsxConverter);
trans("home"); // "Home" (plain string — no placeholders)trans("greet", { name: "Ada" }); // [<>Hello </>, <>Ada</>]React: JSX placeholders
The React adapter (@mongez/react-localization) ships jsxConverter and a convenience transX. jsxConverter splits the translation on the placeholder pattern and wraps each segment in a React.Fragment so JSX values (a <strong>, a <Link>, …) interleave correctly:
import { setConverter } from "@mongez/localization";import { jsxConverter } from "@mongez/react-localization";
setConverter(jsxConverter);
trans("welcome", { name: <strong>Ada</strong>,});// → [<>Hello </>, <strong>Ada</strong>, <></>]For a single-shot JSX call without flipping the global converter, use transX:
import { transX } from "@mongez/react-localization";
transX("welcome", { name: <strong>Ada</strong> });Escaping / XSS notes
plainConverter uses String.prototype.replace — there is no HTML escaping. If your placeholders carry user-controlled data and you render the result via dangerouslySetInnerHTML or a v-html equivalent, you’re responsible for escaping. The safe path is jsxConverter (React text nodes auto-escape) or a custom converter that escapes before substituting.