@opentf/web-i18n 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. package/T.jsx +14 -0
  2. package/format.js +47 -0
  3. package/i18n.js +0 -0
  4. package/index.js +15 -0
  5. package/package.json +42 -0
package/T.jsx ADDED
@@ -0,0 +1,14 @@
1
+ // <T id values /> — inline translation component (docs/I18N.md §5).
2
+ //
3
+ // Sugar over `t(id, values)`: renders the translated string into a <span>, wired
4
+ // reactively to the active locale like any text binding. For messages that
5
+ // interpolate a *signal* (e.g. a live `{count}`), prefer the bare `{t("key", { count })}`
6
+ // form in markup so the compiler tracks the signal directly.
7
+ //
8
+ // Shipped as JSX source and compiled by the consuming app's pipeline (like <Link>).
9
+
10
+ import { t } from "./i18n.js";
11
+
12
+ export default function T({ id, values }) {
13
+ return <span>{t(id, values)}</span>;
14
+ }
package/format.js ADDED
@@ -0,0 +1,47 @@
1
+ //! Locale-aware formatters over the browser-native `Intl` APIs (docs/I18N.md §5).
2
+ //
3
+ // Each formatter reads the active locale from `getLocale()` (which tracks the
4
+ // reactive `router.locale`), so `fmt.currency(...)` inside a binding re-renders on
5
+ // a locale-changing navigation. `Intl.*` instances are memoized per
6
+ // (kind, locale, options) — constructing them is comparatively expensive.
7
+
8
+ import { getLocale } from "./i18n.js";
9
+
10
+ const cache = new Map();
11
+
12
+ function intl(kind, Ctor, options) {
13
+ const locale = getLocale();
14
+ const key = `${kind} ${locale} ${options ? JSON.stringify(options) : ""}`;
15
+ let inst = cache.get(key);
16
+ if (!inst) {
17
+ inst = new Ctor(locale, options);
18
+ cache.set(key, inst);
19
+ }
20
+ return inst;
21
+ }
22
+
23
+ export const fmt = {
24
+ /** Locale-grouped number: `fmt.number(1234.5)`. */
25
+ number: (value, options) => intl("n", Intl.NumberFormat, options).format(value),
26
+
27
+ /** Currency: `fmt.currency(189, "USD")` → "$189.00" / "189,00 $US". */
28
+ currency: (value, currency, options) =>
29
+ intl("c", Intl.NumberFormat, { style: "currency", currency, ...options }).format(value),
30
+
31
+ /** Percent: `fmt.percent(0.42)` → "42%". */
32
+ percent: (value, options) =>
33
+ intl("pc", Intl.NumberFormat, { style: "percent", ...options }).format(value),
34
+
35
+ /** Date/time: `fmt.date(new Date(), { dateStyle: "long" })`. */
36
+ date: (value, options) => intl("d", Intl.DateTimeFormat, options).format(value),
37
+
38
+ /** Relative time: `fmt.relativeTime(-3, "day")` → "3 days ago". */
39
+ relativeTime: (value, unit, options) =>
40
+ intl("r", Intl.RelativeTimeFormat, options).format(value, unit),
41
+
42
+ /** Plural category for the active locale: `fmt.plural(2)` → "other". */
43
+ plural: (value, options) => intl("p", Intl.PluralRules, options).select(value),
44
+
45
+ /** List: `fmt.list(["a","b","c"])` → "a, b, and c". */
46
+ list: (values, options) => intl("l", Intl.ListFormat, options).format(values),
47
+ };
package/i18n.js ADDED
Binary file
package/index.js ADDED
@@ -0,0 +1,15 @@
1
+ // Public entry for @opentf/web-i18n — ICU messages + Intl formatters that pair
2
+ // with the core router's URL-prefix locale routing (docs/I18N.md).
3
+ //
4
+ // import { createI18n, t, fmt } from "@opentf/web-i18n";
5
+ // createI18n({ locales: ["en", "fr"], defaultLocale: "en", messages: { … } });
6
+ // t("greeting", { name }); // reactive on router.locale
7
+ // fmt.currency(189, "USD");
8
+
9
+ export { createI18n, getLocale, loadLocale, locales, setCatalog, t } from "./i18n.js";
10
+ export { fmt } from "./format.js";
11
+
12
+ // `<T>` is a pure JSX component (compiled by the app's pipeline). The bare import
13
+ // retains its Custom Element registration side effect; the re-export exposes it.
14
+ import "./T.jsx";
15
+ export { default as T } from "./T.jsx";
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@opentf/web-i18n",
3
+ "version": "1.1.0",
4
+ "description": "Internationalization for OTF Web — ICU messages, Intl formatters, and a reactive t() that pairs with the core's URL-prefix locale routing.",
5
+ "main": "index.js",
6
+ "module": "index.js",
7
+ "type": "module",
8
+ "exports": {
9
+ ".": "./index.js"
10
+ },
11
+ "files": [
12
+ "index.js",
13
+ "i18n.js",
14
+ "format.js",
15
+ "T.jsx",
16
+ "!**/*.test.js"
17
+ ],
18
+ "keywords": [
19
+ "opentf",
20
+ "i18n",
21
+ "internationalization",
22
+ "icu",
23
+ "intl",
24
+ "localization"
25
+ ],
26
+ "dependencies": {
27
+ "intl-messageformat": "^10.7.0"
28
+ },
29
+ "peerDependencies": {
30
+ "@opentf/web": "*"
31
+ },
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "scripts": {
36
+ "test": "bun test --env=happy-dom"
37
+ },
38
+ "devDependencies": {
39
+ "@opentf/web": "0.6.0",
40
+ "@opentf/web-test": "1.1.0"
41
+ }
42
+ }