@nxgt/i18n 1.1.0 → 2.0.1

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.
package/README.md CHANGED
@@ -51,10 +51,31 @@ and `errors.service-unavailable`.
51
51
 
52
52
  `getLanguage()` asks, most specific first:
53
53
 
54
- 1. the Hono request context (`LANGUAGE_KEY`, `'language'`)
54
+ 1. every registered **language source**, in the order registered
55
55
  2. `localStorage.language`, when that object exists
56
56
  3. `FALLBACK_LANGUAGE` (`'en'`)
57
57
 
58
+ A source is a function answering the current request's language, or nothing.
59
+ This package knows no server; the server says where its request keeps the
60
+ language:
61
+
62
+ ```ts
63
+ import { registerLanguageSource } from '@nxgt/i18n';
64
+
65
+ const remove = registerLanguageSource(() => currentRequest()?.language);
66
+ ```
67
+
68
+ | server | its source |
69
+ | --- | --- |
70
+ | Hono | `@nxgt/shared-hono` registers `honoLanguageSource` when imported: the `language` variable `languageDetector()` sets, read through `contextStorage()` |
71
+ | GraphQL Yoga on Hono | `@nxgt/shared-graphql`'s `createYogaHono()` registers the same |
72
+ | alxia | `@alxia/i18n`'s `createI18n()` registers the request's language |
73
+
74
+ A source that answers nothing, a language no catalogue has, or throws is
75
+ skipped. Registering one twice keeps one. The registry is on `globalThis`, so
76
+ two copies of this package in one app — one a dependency of
77
+ `@nxgt/shared-hono`, one the app's own — share it.
78
+
58
79
  The two consuming monorepos had forked exactly this — one read the request, the
59
80
  other read `localStorage` — and neither could run where the other did. Asking
60
81
  both serves either without a caller changing anything. Pass a provider (a
@@ -63,19 +84,29 @@ and not the other.
63
84
 
64
85
  `SUPPORTED_LANGUAGES` is derived from the catalogue keys, not typed out.
65
86
 
87
+ ### Since 2.0
88
+
89
+ Until 2.0, `getLanguage()` read the Hono request context itself, through
90
+ `hono/context-storage`: every consumer depended on Hono, and a server on
91
+ anything else got the fallback. The Hono part lives in `@nxgt/shared-hono`
92
+ now, with the `ContextVariableMap` augmentation that types `c.get('language')`.
93
+ An app that imports `@nxgt/shared-hono` sees no difference; one that used
94
+ `@nxgt/i18n` beside Hono without it calls `useHonoLanguage()` from
95
+ `@nxgt/shared-hono` once, or registers its own source.
96
+
66
97
  ## In a browser bundle
67
98
 
68
99
  Nothing to change: `import { translate } from '@nxgt/i18n'` is the same import
69
100
  whether the code runs in Node, Bun, or a bundler that resolves the `browser`
70
- export condition (Vite, Nuxt's client build). Under `browser`, `getLanguage()`
71
- drops step 1 above — there is no Hono request to read from inside a browser —
72
- and answers from `localStorage`, then `FALLBACK_LANGUAGE`. Everything else,
73
- including `translate` and `createTranslator`, behaves the same. The point of
74
- the condition is what it leaves out of the bundle: no `hono/context-storage`,
75
- and nothing Node-only, ships to the client.
101
+ export condition (Vite, Nuxt's client build). Since 2.0 nothing in the package
102
+ is Node-only, and the `browser` entry is the same code; a client app registers
103
+ a source as a server does, or relies on `localStorage`.
76
104
 
77
105
  ## Things that bite
78
106
 
107
+ - **A server's language is a registered source.** Without one, every
108
+ request is translated in `localStorage`'s language — none, on a server — or
109
+ the fallback.
79
110
  - **Messages are keys.** Rendering at the throw site (or translating in a
80
111
  service) freezes the language of whoever threw, not of whoever reads.
81
112
  - **ICU formatting failures are swallowed** (`console.error`) and the
@@ -45,7 +45,8 @@ var errors_default = {
45
45
  "persisted-query-not-supported": "Persisted queries are not supported on this server.",
46
46
  "bad-user-input": "Invalid input provided. Please check your data and try again.",
47
47
  "operation-resolution-failure": "Failed to resolve the GraphQL operation.",
48
- "bad-request": "The request is invalid or malformed. Please verify the request format."
48
+ "bad-request": "The request is invalid or malformed. Please verify the request format.",
49
+ "list-patch-one-operation-per-path": "Only one of ''replace'', ''add'' and ''remove'' can change ''{path}'' in one update. Send them as separate updates."
49
50
  };
50
51
  // src/resources/en/validation.json
51
52
  var validation_default = {
@@ -269,7 +270,8 @@ var errors_default2 = {
269
270
  "persisted-query-not-supported": "Les requêtes persistantes ne sont pas prises en charge sur ce serveur.",
270
271
  "bad-user-input": "Données saisies invalides. Veuillez vérifier vos informations et réessayer.",
271
272
  "operation-resolution-failure": "Échec de la résolution de l'opération GraphQL.",
272
- "bad-request": "La requête est invalide ou mal formée. Veuillez vérifier le format de la requête."
273
+ "bad-request": "La requête est invalide ou mal formée. Veuillez vérifier le format de la requête.",
274
+ "list-patch-one-operation-per-path": "Une seule des opérations ''replace'', ''add'' et ''remove'' peut modifier ''{path}'' dans une même mise à jour. Envoyez-les dans des mises à jour distinctes."
273
275
  };
274
276
  // src/resources/fr/validation.json
275
277
  var validation_default2 = {
@@ -457,7 +459,68 @@ var resources2 = {
457
459
  var LANGUAGE_KEY2 = "language";
458
460
  var SUPPORTED_LANGUAGES2 = Object.keys(resources2);
459
461
  var FALLBACK_LANGUAGE2 = "en";
460
- export { resources2, LANGUAGE_KEY2, SUPPORTED_LANGUAGES2, FALLBACK_LANGUAGE2 };
461
462
 
462
- //# debugId=9B74B0DCF0FC1D0A64756E2164756E21
463
- //# sourceMappingURL=index-86mgj3nf.js.map
463
+ // src/sources.ts
464
+ var REGISTRY = Symbol.for("@nxgt/i18n/language-sources");
465
+ function registry() {
466
+ const global = globalThis;
467
+ global[REGISTRY] ??= [];
468
+ return global[REGISTRY];
469
+ }
470
+ function registerLanguageSource2(source) {
471
+ const sources = registry();
472
+ if (!sources.includes(source))
473
+ sources.push(source);
474
+ return () => {
475
+ const index = sources.indexOf(source);
476
+ if (index !== -1)
477
+ sources.splice(index, 1);
478
+ };
479
+ }
480
+ function languageFromSources2() {
481
+ for (const source of registry()) {
482
+ let answer;
483
+ try {
484
+ answer = source();
485
+ } catch {
486
+ continue;
487
+ }
488
+ if (SUPPORTED_LANGUAGES2.includes(answer)) {
489
+ return answer;
490
+ }
491
+ }
492
+ return;
493
+ }
494
+
495
+ // src/i18n.ts
496
+ import { IntlMessageFormat } from "intl-messageformat";
497
+ import _ from "lodash";
498
+ function getLanguage2() {
499
+ const fromSource = languageFromSources2();
500
+ if (fromSource !== undefined)
501
+ return fromSource;
502
+ if (typeof localStorage !== "undefined") {
503
+ const stored = localStorage.getItem(LANGUAGE_KEY2);
504
+ if (SUPPORTED_LANGUAGES2.includes(stored)) {
505
+ return stored;
506
+ }
507
+ }
508
+ return FALLBACK_LANGUAGE2;
509
+ }
510
+ function createTranslator2(resources = {}, localeProvider = getLanguage2) {
511
+ return (key, context = undefined, provideLanguage = localeProvider) => {
512
+ const language = typeof provideLanguage === "function" ? provideLanguage() : provideLanguage;
513
+ let message = _.get(resources[language], key) ?? key;
514
+ try {
515
+ message = new IntlMessageFormat(message, language).format(context);
516
+ } catch (e) {
517
+ console.error(e);
518
+ }
519
+ return message;
520
+ };
521
+ }
522
+ var translate2 = createTranslator2(resources2);
523
+ export { resources2, LANGUAGE_KEY2, SUPPORTED_LANGUAGES2, FALLBACK_LANGUAGE2, registerLanguageSource2, languageFromSources2, getLanguage2, createTranslator2, translate2 };
524
+
525
+ //# debugId=2FA53BAC7C0D362464756E2164756E21
526
+ //# sourceMappingURL=index-jscbtbek.js.map
@@ -0,0 +1,15 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/resources/en/index.ts", "../src/resources/fr/index.ts", "../src/resources/index.ts", "../src/consts.ts", "../src/sources.ts", "../src/i18n.ts"],
4
+ "sourcesContent": [
5
+ "import common from './common.json';\nimport errors from './errors.json';\nimport validation from './validation.json';\nimport zod from './zod.json';\n\nexport const en = {\n\t...common,\n\terrors,\n\tvalidation,\n\tzod,\n};\n",
6
+ "import common from './common.json';\nimport errors from './errors.json';\nimport validation from './validation.json';\nimport zod from './zod.json';\n\nexport const fr = {\n\t...common,\n\terrors,\n\tvalidation,\n\tzod,\n};\n",
7
+ "import { en } from './en';\nimport { fr } from './fr';\n\nexport const resources = {\n\ten,\n\tfr,\n};\n",
8
+ "import { resources } from './resources';\nimport type { Language } from './types';\n\nexport const LANGUAGE_KEY = 'language';\n\nexport const SUPPORTED_LANGUAGES = Object.keys(resources) as Language[];\n\nexport const FALLBACK_LANGUAGE: Language = 'en';\n",
9
+ "import { SUPPORTED_LANGUAGES } from './consts';\nimport type { Language } from './types';\n\n/**\n * Where a language may come from: a server's request context, a framework's\n * state. It answers the request's language, or nothing — `undefined`, `null`,\n * a language no catalogue has — and the next source is asked.\n */\nexport type LanguageSource = () => string | null | undefined;\n\n/**\n * One registry for the process, on `globalThis`: an app can hold two copies\n * of this package — one a dependency of `@nxgt/shared-hono`, one its own —\n * and a source registered through either must answer both.\n */\nconst REGISTRY = Symbol.for('@nxgt/i18n/language-sources');\n\nfunction registry(): LanguageSource[] {\n\tconst global = globalThis as { [REGISTRY]?: LanguageSource[] };\n\tglobal[REGISTRY] ??= [];\n\treturn global[REGISTRY];\n}\n\n/**\n * Adds a source `getLanguage()` asks, after those registered before it.\n * Registering one twice keeps one. Answers the function that removes it.\n *\n * This package knows no server: `@nxgt/shared-hono` registers the Hono\n * request context's `language`, `@alxia/i18n` the alxia request's.\n */\nexport function registerLanguageSource(source: LanguageSource): () => void {\n\tconst sources = registry();\n\tif (!sources.includes(source)) sources.push(source);\n\treturn () => {\n\t\tconst index = sources.indexOf(source);\n\t\tif (index !== -1) sources.splice(index, 1);\n\t};\n}\n\n/**\n * The first supported language a registered source answers. A source that\n * throws is skipped: a language is never worth a failed request.\n */\nexport function languageFromSources(): Language | undefined {\n\tfor (const source of registry()) {\n\t\tlet answer: string | null | undefined;\n\t\ttry {\n\t\t\tanswer = source();\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tif (SUPPORTED_LANGUAGES.includes(answer as Language)) {\n\t\t\treturn answer as Language;\n\t\t}\n\t}\n\treturn undefined;\n}\n",
10
+ "import { IntlMessageFormat } from 'intl-messageformat';\nimport _ from 'lodash';\nimport { FALLBACK_LANGUAGE, LANGUAGE_KEY, SUPPORTED_LANGUAGES } from './consts';\nimport { resources } from './resources';\nimport { languageFromSources } from './sources';\nimport type {\n\tLanguage,\n\tLanguageProvider,\n\tLocaleKey,\n\tTranslationContext,\n} from './types';\n\n/**\n * Where the language comes from when the caller does not say, most specific\n * first:\n *\n * 1. a registered source — `registerLanguageSource()`: a server's request\n * context, which `@nxgt/shared-hono` registers for Hono and\n * `@alxia/i18n` for alxia;\n * 2. `localStorage`, when that object exists;\n * 3. the fallback language.\n *\n * Until 2.0 this read Hono's request context itself, through\n * `hono/context-storage`, which tied every consumer — a browser bundle, an\n * alxia server — to Hono. The Hono part lives in `@nxgt/shared-hono` now.\n *\n * `createTranslator` still takes a provider, so a caller that wants one source\n * and not the others passes it.\n */\nexport function getLanguage(): Language {\n\tconst fromSource = languageFromSources();\n\tif (fromSource !== undefined) return fromSource;\n\tif (typeof localStorage !== 'undefined') {\n\t\tconst stored = localStorage.getItem(LANGUAGE_KEY);\n\t\tif (SUPPORTED_LANGUAGES.includes(stored as Language)) {\n\t\t\treturn stored as Language;\n\t\t}\n\t}\n\treturn FALLBACK_LANGUAGE;\n}\n\nexport function createTranslator<K extends string = LocaleKey>(\n\tresources: Record<string, any> = {},\n\tlocaleProvider: LanguageProvider = getLanguage,\n) {\n\treturn (\n\t\tkey: K,\n\t\tcontext: TranslationContext = undefined,\n\t\tprovideLanguage: LanguageProvider = localeProvider,\n\t): string => {\n\t\tconst language =\n\t\t\ttypeof provideLanguage === 'function'\n\t\t\t\t? provideLanguage()\n\t\t\t\t: provideLanguage;\n\t\tlet message: string = _.get(resources[language], key) ?? key;\n\t\ttry {\n\t\t\tmessage = new IntlMessageFormat(message, language).format(context);\n\t\t} catch (e) {\n\t\t\tconsole.error(e);\n\t\t}\n\n\t\treturn message;\n\t};\n}\n\nexport const translate = createTranslator(resources);\n"
11
+ ],
12
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKO,IAAM,KAAK;AAAA,KACd;AAAA,EACH;AAAA,EACA;AAAA,EACA;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACLO,IAAM,KAAK;AAAA,KACd;AAAA,EACH;AAAA,EACA;AAAA,EACA;AACD;;;ACPO,IAAM,aAAY;AAAA,EACxB;AAAA,EACA;AACD;;;ACHO,IAAM,gBAAe;AAErB,IAAM,uBAAsB,OAAO,KAAK,UAAS;AAEjD,IAAM,qBAA8B;;;ACQ3C,IAAM,WAAW,OAAO,IAAI,6BAA6B;AAEzD,SAAS,QAAQ,GAAqB;AAAA,EACrC,MAAM,SAAS;AAAA,EACf,OAAO,cAAc,CAAC;AAAA,EACtB,OAAO,OAAO;AAAA;AAUR,SAAS,uBAAsB,CAAC,QAAoC;AAAA,EAC1E,MAAM,UAAU,SAAS;AAAA,EACzB,IAAI,CAAC,QAAQ,SAAS,MAAM;AAAA,IAAG,QAAQ,KAAK,MAAM;AAAA,EAClD,OAAO,MAAM;AAAA,IACZ,MAAM,QAAQ,QAAQ,QAAQ,MAAM;AAAA,IACpC,IAAI,UAAU;AAAA,MAAI,QAAQ,OAAO,OAAO,CAAC;AAAA;AAAA;AAQpC,SAAS,oBAAmB,GAAyB;AAAA,EAC3D,WAAW,UAAU,SAAS,GAAG;AAAA,IAChC,IAAI;AAAA,IACJ,IAAI;AAAA,MACH,SAAS,OAAO;AAAA,MACf,MAAM;AAAA,MACP;AAAA;AAAA,IAED,IAAI,qBAAoB,SAAS,MAAkB,GAAG;AAAA,MACrD,OAAO;AAAA,IACR;AAAA,EACD;AAAA,EACA;AAAA;;;ACvDD;AACA;AA4BO,SAAS,YAAW,GAAa;AAAA,EACvC,MAAM,aAAa,qBAAoB;AAAA,EACvC,IAAI,eAAe;AAAA,IAAW,OAAO;AAAA,EACrC,IAAI,OAAO,iBAAiB,aAAa;AAAA,IACxC,MAAM,SAAS,aAAa,QAAQ,aAAY;AAAA,IAChD,IAAI,qBAAoB,SAAS,MAAkB,GAAG;AAAA,MACrD,OAAO;AAAA,IACR;AAAA,EACD;AAAA,EACA,OAAO;AAAA;AAGD,SAAS,iBAA8C,CAC7D,YAAiC,CAAC,GAClC,iBAAmC,cAClC;AAAA,EACD,OAAO,CACN,KACA,UAA8B,WAC9B,kBAAoC,mBACxB;AAAA,IACZ,MAAM,WACL,OAAO,oBAAoB,aACxB,gBAAgB,IAChB;AAAA,IACJ,IAAI,UAAkB,EAAE,IAAI,UAAU,WAAW,GAAG,KAAK;AAAA,IACzD,IAAI;AAAA,MACH,UAAU,IAAI,kBAAkB,SAAS,QAAQ,EAAE,OAAO,OAAO;AAAA,MAChE,OAAO,GAAG;AAAA,MACX,QAAQ,MAAM,CAAC;AAAA;AAAA,IAGhB,OAAO;AAAA;AAAA;AAIF,IAAM,aAAY,kBAAiB,UAAS;",
13
+ "debugId": "2FA53BAC7C0D362464756E2164756E21",
14
+ "names": []
15
+ }
@@ -1,15 +1,9 @@
1
- import type { Language, LanguageProvider, LocaleKey, TranslationContext } from './types';
2
1
  /**
3
- * The browser build of {@link getLanguage} from `./i18n`.
4
- *
5
- * A bundler that resolves the `browser` export condition (Vite, Nuxt's client
6
- * build) gets this file instead: it never imports `hono/context-storage`,
7
- * which pulls in `node:async_hooks` — absent in a browser and dead weight in
8
- * a client bundle that never runs inside a Hono request. There is no request
9
- * context to ask in a browser anyway, so the behaviour a consumer sees is the
10
- * same: `localStorage`, then the fallback language.
2
+ * The `browser` condition's build of `./i18n`. They were two files while
3
+ * `./i18n` imported `hono/context-storage`, which pulls in `node:async_hooks`;
4
+ * since 2.0 neither imports anything Node-only, and a browser registers its
5
+ * own language sources as a server does. The entry point stays, so a bundler
6
+ * that resolves the `browser` condition keeps resolving it.
11
7
  */
12
- export declare function getLanguage(): Language;
13
- export declare function createTranslator<K extends string = LocaleKey>(resources?: Record<string, any>, localeProvider?: LanguageProvider): (key: K, context?: TranslationContext, provideLanguage?: LanguageProvider) => string;
14
- export declare const translate: (key: "errors.not-found" | "errors.unauthenticated" | "errors.duplicate-key" | "errors.something-went-wrong" | "errors.insufficient-permissions" | "errors.cast-failed" | "errors.server-connection-failed" | "errors.forbidden" | "errors.optimistic-lock-failed" | "errors.internal-server-error" | "errors.validation-failed" | "errors.address-blocked" | "errors.could-not-use-first-and-last-together" | "errors.invalid-cursor" | "errors.invalid-status-transition" | "errors.service-unavailable" | "errors.graphql-parse-failed" | "errors.graphql-validation-failed" | "errors.persisted-query-not-found" | "errors.persisted-query-not-supported" | "errors.bad-user-input" | "errors.operation-resolution-failure" | "errors.bad-request" | "validation.errors.time" | "validation.errors.invalid-account-number" | "validation.errors.invalid-big-int" | "validation.errors.invalid-country-code" | "validation.errors.invalid-country-name" | "validation.errors.invalid-cuid" | "validation.errors.invalid-currency" | "validation.errors.invalid-date" | "validation.errors.invalid-date-time" | "validation.errors.invalid-duration" | "validation.errors.invalid-email-address" | "validation.errors.invalid-geo-json" | "validation.errors.invalid-guid" | "validation.errors.invalid-hex-color-code" | "validation.errors.invalid-hexadecimal" | "validation.errors.invalid-hsl" | "validation.errors.invalid-hsla" | "validation.errors.invalid-iban" | "validation.errors.invalid-ip" | "validation.errors.invalid-ipv4" | "validation.errors.invalid-ipv6" | "validation.errors.invalid-isbn" | "validation.errors.invalid-json" | "validation.errors.invalid-json-object" | "validation.errors.invalid-jwt" | "validation.errors.invalid-latitude" | "validation.errors.invalid-locale" | "validation.errors.invalid-longitude" | "validation.errors.invalid-long" | "validation.errors.invalid-mac" | "validation.errors.invalid-negative-float" | "validation.errors.invalid-negative-int" | "validation.errors.invalid-non-empty-string" | "validation.errors.invalid-non-negative-float" | "validation.errors.invalid-non-negative-int" | "validation.errors.invalid-non-positive-float" | "validation.errors.invalid-non-positive-int" | "validation.errors.invalid-object-id" | "validation.errors.invalid-phone-number" | "validation.errors.invalid-port" | "validation.errors.invalid-positive-float" | "validation.errors.invalid-positive-int" | "validation.errors.invalid-postal-code" | "validation.errors.invalid-rgb" | "validation.errors.invalid-rgba" | "validation.errors.invalid-sessn" | "validation.errors.invalid-time" | "validation.errors.invalid-timestamp" | "validation.errors.invalid-url" | "validation.errors.invalid-us-currency" | "validation.errors.invalid-utc-offset" | "validation.errors.invalid-uuid" | "validation.errors.invalid-void" | "validation.errors.min" | "validation.errors.max" | "validation.errors.min-length" | "validation.errors.max-length" | "validation.errors.range" | "validation.errors.size" | "validation.errors.past" | "validation.errors.future" | "validation.errors.email" | "validation.errors.ip" | "validation.errors.ipv4" | "validation.errors.ipv6" | "validation.errors.mac" | "validation.errors.url" | "validation.errors.uuid" | "validation.errors.guid" | "validation.errors.ssn" | "validation.errors.phone" | "validation.errors.street" | "validation.errors.zip-code" | "validation.errors.object-id" | "validation.errors.pattern" | "validation.errors.not-blank" | "validation.errors.not-empty" | "validation.errors.positive" | "validation.errors.negative" | "validation.errors.no-scalars" | "validation.errors.not-null" | "validation.errors.required" | "zod.required" | "zod.invalid_value_single" | "zod.invalid_value_multiple" | "zod.too_big_inclusive" | "zod.too_big_exclusive" | "zod.too_big_no_unit_inclusive" | "zod.too_big_no_unit_exclusive" | "zod.too_small_inclusive" | "zod.too_small_exclusive" | "zod.too_small_no_unit_inclusive" | "zod.too_small_no_unit_exclusive" | "zod.not_multiple_of" | "zod.unrecognized_keys_single" | "zod.unrecognized_keys_multiple" | "zod.invalid_key" | "zod.invalid_union" | "zod.invalid_element" | "zod.default" | "zod.invalid_type.string" | "zod.invalid_type.number" | "zod.invalid_type.bigint" | "zod.invalid_type.boolean" | "zod.invalid_type.symbol" | "zod.invalid_type.undefined" | "zod.invalid_type.object" | "zod.invalid_type.function" | "zod.invalid_type.date" | "zod.invalid_type.default" | "zod.invalid_type.array" | "zod.invalid_type.null" | "zod.invalid_type.enum" | "zod.invalid_format.includes" | "zod.invalid_format.default" | "zod.invalid_format.starts_with" | "zod.invalid_format.ends_with" | "zod.invalid_format.regex" | "zod.nouns.emoji" | "zod.nouns.nanoid" | "zod.nouns.cuid" | "zod.nouns.cuid2" | "zod.nouns.date" | "zod.nouns.time" | "zod.nouns.duration" | "zod.nouns.email" | "zod.nouns.ipv4" | "zod.nouns.ipv6" | "zod.nouns.mac" | "zod.nouns.url" | "zod.nouns.uuid" | "zod.nouns.guid" | "zod.nouns.regex" | "zod.nouns.uuidv4" | "zod.nouns.uuidv6" | "zod.nouns.ulid" | "zod.nouns.xid" | "zod.nouns.ksuid" | "zod.nouns.datetime" | "zod.nouns.cidrv4" | "zod.nouns.cidrv6" | "zod.nouns.base64" | "zod.nouns.base64url" | "zod.nouns.json_string" | "zod.nouns.e164" | "zod.nouns.jwt" | "zod.nouns.template_literal" | "zod.sizing.string.unit" | "zod.sizing.string.verb" | "zod.sizing.array.unit" | "zod.sizing.array.verb" | "zod.sizing.file.unit" | "zod.sizing.file.verb" | "zod.sizing.set.unit" | "zod.sizing.set.verb" | "mail.common.thanks" | "mail.common.greeting" | "mail.common.copyright" | "mail.templates.verification.message" | "mail.templates.verification.verify" | "mail.templates.verification.notes" | "opening-hours.errors.invalid-start-time-format" | "opening-hours.errors.invalid-end-time-format", context?: TranslationContext, provideLanguage?: LanguageProvider) => string;
8
+ export * from './i18n';
15
9
  //# sourceMappingURL=i18n.browser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.browser.d.ts","sourceRoot":"","sources":["../src/i18n.browser.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACX,QAAQ,EACR,gBAAgB,EAChB,SAAS,EACT,kBAAkB,EAClB,MAAM,SAAS,CAAC;AAEjB;;;;;;;;;GASG;AACH,wBAAgB,WAAW,IAAI,QAAQ,CAQtC;AAED,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,GAAG,SAAS,EAC5D,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,EACnC,cAAc,GAAE,gBAA8B,IAG7C,KAAK,CAAC,EACN,UAAS,kBAA8B,EACvC,kBAAiB,gBAAiC,KAChD,MAAM,CAcT;AAED,eAAO,MAAM,SAAS,koLAlBX,kBAAkB,oBACV,gBAAgB,KAC/B,MAgBgD,CAAC"}
1
+ {"version":3,"file":"i18n.browser.d.ts","sourceRoot":"","sources":["../src/i18n.browser.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,QAAQ,CAAC"}
package/dist/i18n.d.ts CHANGED
@@ -1,17 +1,22 @@
1
1
  import type { Language, LanguageProvider, LocaleKey, TranslationContext } from './types';
2
2
  /**
3
- * Where the language comes from when the caller does not say.
3
+ * Where the language comes from when the caller does not say, most specific
4
+ * first:
4
5
  *
5
- * The two repositories had forked exactly this: sellix-monorepo read
6
- * `localStorage`, nxgt-federation read the Hono request context, and neither
7
- * could run where the other did — federation's fell back to `'en'` outside a
8
- * request, sellix's knew nothing about one. Asking both, most specific first,
9
- * serves either without a caller changing anything.
6
+ * 1. a registered source — `registerLanguageSource()`: a server's request
7
+ * context, which `@nxgt/shared-hono` registers for Hono and
8
+ * `@alxia/i18n` for alxia;
9
+ * 2. `localStorage`, when that object exists;
10
+ * 3. the fallback language.
11
+ *
12
+ * Until 2.0 this read Hono's request context itself, through
13
+ * `hono/context-storage`, which tied every consumer — a browser bundle, an
14
+ * alxia server — to Hono. The Hono part lives in `@nxgt/shared-hono` now.
10
15
  *
11
16
  * `createTranslator` still takes a provider, so a caller that wants one source
12
- * and not the other passes it.
17
+ * and not the others passes it.
13
18
  */
14
19
  export declare function getLanguage(): Language;
15
20
  export declare function createTranslator<K extends string = LocaleKey>(resources?: Record<string, any>, localeProvider?: LanguageProvider): (key: K, context?: TranslationContext, provideLanguage?: LanguageProvider) => string;
16
- export declare const translate: (key: "errors.not-found" | "errors.unauthenticated" | "errors.duplicate-key" | "errors.something-went-wrong" | "errors.insufficient-permissions" | "errors.cast-failed" | "errors.server-connection-failed" | "errors.forbidden" | "errors.optimistic-lock-failed" | "errors.internal-server-error" | "errors.validation-failed" | "errors.address-blocked" | "errors.could-not-use-first-and-last-together" | "errors.invalid-cursor" | "errors.invalid-status-transition" | "errors.service-unavailable" | "errors.graphql-parse-failed" | "errors.graphql-validation-failed" | "errors.persisted-query-not-found" | "errors.persisted-query-not-supported" | "errors.bad-user-input" | "errors.operation-resolution-failure" | "errors.bad-request" | "validation.errors.time" | "validation.errors.invalid-account-number" | "validation.errors.invalid-big-int" | "validation.errors.invalid-country-code" | "validation.errors.invalid-country-name" | "validation.errors.invalid-cuid" | "validation.errors.invalid-currency" | "validation.errors.invalid-date" | "validation.errors.invalid-date-time" | "validation.errors.invalid-duration" | "validation.errors.invalid-email-address" | "validation.errors.invalid-geo-json" | "validation.errors.invalid-guid" | "validation.errors.invalid-hex-color-code" | "validation.errors.invalid-hexadecimal" | "validation.errors.invalid-hsl" | "validation.errors.invalid-hsla" | "validation.errors.invalid-iban" | "validation.errors.invalid-ip" | "validation.errors.invalid-ipv4" | "validation.errors.invalid-ipv6" | "validation.errors.invalid-isbn" | "validation.errors.invalid-json" | "validation.errors.invalid-json-object" | "validation.errors.invalid-jwt" | "validation.errors.invalid-latitude" | "validation.errors.invalid-locale" | "validation.errors.invalid-longitude" | "validation.errors.invalid-long" | "validation.errors.invalid-mac" | "validation.errors.invalid-negative-float" | "validation.errors.invalid-negative-int" | "validation.errors.invalid-non-empty-string" | "validation.errors.invalid-non-negative-float" | "validation.errors.invalid-non-negative-int" | "validation.errors.invalid-non-positive-float" | "validation.errors.invalid-non-positive-int" | "validation.errors.invalid-object-id" | "validation.errors.invalid-phone-number" | "validation.errors.invalid-port" | "validation.errors.invalid-positive-float" | "validation.errors.invalid-positive-int" | "validation.errors.invalid-postal-code" | "validation.errors.invalid-rgb" | "validation.errors.invalid-rgba" | "validation.errors.invalid-sessn" | "validation.errors.invalid-time" | "validation.errors.invalid-timestamp" | "validation.errors.invalid-url" | "validation.errors.invalid-us-currency" | "validation.errors.invalid-utc-offset" | "validation.errors.invalid-uuid" | "validation.errors.invalid-void" | "validation.errors.min" | "validation.errors.max" | "validation.errors.min-length" | "validation.errors.max-length" | "validation.errors.range" | "validation.errors.size" | "validation.errors.past" | "validation.errors.future" | "validation.errors.email" | "validation.errors.ip" | "validation.errors.ipv4" | "validation.errors.ipv6" | "validation.errors.mac" | "validation.errors.url" | "validation.errors.uuid" | "validation.errors.guid" | "validation.errors.ssn" | "validation.errors.phone" | "validation.errors.street" | "validation.errors.zip-code" | "validation.errors.object-id" | "validation.errors.pattern" | "validation.errors.not-blank" | "validation.errors.not-empty" | "validation.errors.positive" | "validation.errors.negative" | "validation.errors.no-scalars" | "validation.errors.not-null" | "validation.errors.required" | "zod.required" | "zod.invalid_value_single" | "zod.invalid_value_multiple" | "zod.too_big_inclusive" | "zod.too_big_exclusive" | "zod.too_big_no_unit_inclusive" | "zod.too_big_no_unit_exclusive" | "zod.too_small_inclusive" | "zod.too_small_exclusive" | "zod.too_small_no_unit_inclusive" | "zod.too_small_no_unit_exclusive" | "zod.not_multiple_of" | "zod.unrecognized_keys_single" | "zod.unrecognized_keys_multiple" | "zod.invalid_key" | "zod.invalid_union" | "zod.invalid_element" | "zod.default" | "zod.invalid_type.string" | "zod.invalid_type.number" | "zod.invalid_type.bigint" | "zod.invalid_type.boolean" | "zod.invalid_type.symbol" | "zod.invalid_type.undefined" | "zod.invalid_type.object" | "zod.invalid_type.function" | "zod.invalid_type.date" | "zod.invalid_type.default" | "zod.invalid_type.array" | "zod.invalid_type.null" | "zod.invalid_type.enum" | "zod.invalid_format.includes" | "zod.invalid_format.default" | "zod.invalid_format.starts_with" | "zod.invalid_format.ends_with" | "zod.invalid_format.regex" | "zod.nouns.emoji" | "zod.nouns.nanoid" | "zod.nouns.cuid" | "zod.nouns.cuid2" | "zod.nouns.date" | "zod.nouns.time" | "zod.nouns.duration" | "zod.nouns.email" | "zod.nouns.ipv4" | "zod.nouns.ipv6" | "zod.nouns.mac" | "zod.nouns.url" | "zod.nouns.uuid" | "zod.nouns.guid" | "zod.nouns.regex" | "zod.nouns.uuidv4" | "zod.nouns.uuidv6" | "zod.nouns.ulid" | "zod.nouns.xid" | "zod.nouns.ksuid" | "zod.nouns.datetime" | "zod.nouns.cidrv4" | "zod.nouns.cidrv6" | "zod.nouns.base64" | "zod.nouns.base64url" | "zod.nouns.json_string" | "zod.nouns.e164" | "zod.nouns.jwt" | "zod.nouns.template_literal" | "zod.sizing.string.unit" | "zod.sizing.string.verb" | "zod.sizing.array.unit" | "zod.sizing.array.verb" | "zod.sizing.file.unit" | "zod.sizing.file.verb" | "zod.sizing.set.unit" | "zod.sizing.set.verb" | "mail.common.thanks" | "mail.common.greeting" | "mail.common.copyright" | "mail.templates.verification.message" | "mail.templates.verification.verify" | "mail.templates.verification.notes" | "opening-hours.errors.invalid-start-time-format" | "opening-hours.errors.invalid-end-time-format", context?: TranslationContext, provideLanguage?: LanguageProvider) => string;
21
+ export declare const translate: (key: "errors.not-found" | "errors.unauthenticated" | "errors.duplicate-key" | "errors.something-went-wrong" | "errors.insufficient-permissions" | "errors.cast-failed" | "errors.server-connection-failed" | "errors.forbidden" | "errors.optimistic-lock-failed" | "errors.internal-server-error" | "errors.validation-failed" | "errors.address-blocked" | "errors.could-not-use-first-and-last-together" | "errors.invalid-cursor" | "errors.invalid-status-transition" | "errors.service-unavailable" | "errors.graphql-parse-failed" | "errors.graphql-validation-failed" | "errors.persisted-query-not-found" | "errors.persisted-query-not-supported" | "errors.bad-user-input" | "errors.operation-resolution-failure" | "errors.bad-request" | "errors.list-patch-one-operation-per-path" | "validation.errors.time" | "validation.errors.invalid-account-number" | "validation.errors.invalid-big-int" | "validation.errors.invalid-country-code" | "validation.errors.invalid-country-name" | "validation.errors.invalid-cuid" | "validation.errors.invalid-currency" | "validation.errors.invalid-date" | "validation.errors.invalid-date-time" | "validation.errors.invalid-duration" | "validation.errors.invalid-email-address" | "validation.errors.invalid-geo-json" | "validation.errors.invalid-guid" | "validation.errors.invalid-hex-color-code" | "validation.errors.invalid-hexadecimal" | "validation.errors.invalid-hsl" | "validation.errors.invalid-hsla" | "validation.errors.invalid-iban" | "validation.errors.invalid-ip" | "validation.errors.invalid-ipv4" | "validation.errors.invalid-ipv6" | "validation.errors.invalid-isbn" | "validation.errors.invalid-json" | "validation.errors.invalid-json-object" | "validation.errors.invalid-jwt" | "validation.errors.invalid-latitude" | "validation.errors.invalid-locale" | "validation.errors.invalid-longitude" | "validation.errors.invalid-long" | "validation.errors.invalid-mac" | "validation.errors.invalid-negative-float" | "validation.errors.invalid-negative-int" | "validation.errors.invalid-non-empty-string" | "validation.errors.invalid-non-negative-float" | "validation.errors.invalid-non-negative-int" | "validation.errors.invalid-non-positive-float" | "validation.errors.invalid-non-positive-int" | "validation.errors.invalid-object-id" | "validation.errors.invalid-phone-number" | "validation.errors.invalid-port" | "validation.errors.invalid-positive-float" | "validation.errors.invalid-positive-int" | "validation.errors.invalid-postal-code" | "validation.errors.invalid-rgb" | "validation.errors.invalid-rgba" | "validation.errors.invalid-sessn" | "validation.errors.invalid-time" | "validation.errors.invalid-timestamp" | "validation.errors.invalid-url" | "validation.errors.invalid-us-currency" | "validation.errors.invalid-utc-offset" | "validation.errors.invalid-uuid" | "validation.errors.invalid-void" | "validation.errors.min" | "validation.errors.max" | "validation.errors.min-length" | "validation.errors.max-length" | "validation.errors.range" | "validation.errors.size" | "validation.errors.past" | "validation.errors.future" | "validation.errors.email" | "validation.errors.ip" | "validation.errors.ipv4" | "validation.errors.ipv6" | "validation.errors.mac" | "validation.errors.url" | "validation.errors.uuid" | "validation.errors.guid" | "validation.errors.ssn" | "validation.errors.phone" | "validation.errors.street" | "validation.errors.zip-code" | "validation.errors.object-id" | "validation.errors.pattern" | "validation.errors.not-blank" | "validation.errors.not-empty" | "validation.errors.positive" | "validation.errors.negative" | "validation.errors.no-scalars" | "validation.errors.not-null" | "validation.errors.required" | "zod.required" | "zod.invalid_value_single" | "zod.invalid_value_multiple" | "zod.too_big_inclusive" | "zod.too_big_exclusive" | "zod.too_big_no_unit_inclusive" | "zod.too_big_no_unit_exclusive" | "zod.too_small_inclusive" | "zod.too_small_exclusive" | "zod.too_small_no_unit_inclusive" | "zod.too_small_no_unit_exclusive" | "zod.not_multiple_of" | "zod.unrecognized_keys_single" | "zod.unrecognized_keys_multiple" | "zod.invalid_key" | "zod.invalid_union" | "zod.invalid_element" | "zod.default" | "zod.invalid_type.string" | "zod.invalid_type.number" | "zod.invalid_type.bigint" | "zod.invalid_type.boolean" | "zod.invalid_type.symbol" | "zod.invalid_type.undefined" | "zod.invalid_type.object" | "zod.invalid_type.function" | "zod.invalid_type.date" | "zod.invalid_type.default" | "zod.invalid_type.array" | "zod.invalid_type.null" | "zod.invalid_type.enum" | "zod.invalid_format.includes" | "zod.invalid_format.default" | "zod.invalid_format.starts_with" | "zod.invalid_format.ends_with" | "zod.invalid_format.regex" | "zod.nouns.emoji" | "zod.nouns.nanoid" | "zod.nouns.cuid" | "zod.nouns.cuid2" | "zod.nouns.date" | "zod.nouns.time" | "zod.nouns.duration" | "zod.nouns.email" | "zod.nouns.ipv4" | "zod.nouns.ipv6" | "zod.nouns.mac" | "zod.nouns.url" | "zod.nouns.uuid" | "zod.nouns.guid" | "zod.nouns.regex" | "zod.nouns.uuidv4" | "zod.nouns.uuidv6" | "zod.nouns.ulid" | "zod.nouns.xid" | "zod.nouns.ksuid" | "zod.nouns.datetime" | "zod.nouns.cidrv4" | "zod.nouns.cidrv6" | "zod.nouns.base64" | "zod.nouns.base64url" | "zod.nouns.json_string" | "zod.nouns.e164" | "zod.nouns.jwt" | "zod.nouns.template_literal" | "zod.sizing.string.unit" | "zod.sizing.string.verb" | "zod.sizing.array.unit" | "zod.sizing.array.verb" | "zod.sizing.file.unit" | "zod.sizing.file.verb" | "zod.sizing.set.unit" | "zod.sizing.set.verb" | "mail.common.thanks" | "mail.common.greeting" | "mail.common.copyright" | "mail.templates.verification.message" | "mail.templates.verification.verify" | "mail.templates.verification.notes" | "opening-hours.errors.invalid-start-time-format" | "opening-hours.errors.invalid-end-time-format", context?: TranslationContext, provideLanguage?: LanguageProvider) => string;
17
22
  //# sourceMappingURL=i18n.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACX,QAAQ,EACR,gBAAgB,EAChB,SAAS,EACT,kBAAkB,EAClB,MAAM,SAAS,CAAC;AAEjB;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,IAAI,QAAQ,CAetC;AAED,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,GAAG,SAAS,EAC5D,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,EACnC,cAAc,GAAE,gBAA8B,IAG7C,KAAK,CAAC,EACN,UAAS,kBAA8B,EACvC,kBAAiB,gBAAiC,KAChD,MAAM,CAcT;AAED,eAAO,MAAM,SAAS,koLAlBX,kBAAkB,oBACV,gBAAgB,KAC/B,MAgBgD,CAAC"}
1
+ {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../src/i18n.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACX,QAAQ,EACR,gBAAgB,EAChB,SAAS,EACT,kBAAkB,EAClB,MAAM,SAAS,CAAC;AAEjB;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,IAAI,QAAQ,CAUtC;AAED,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,GAAG,SAAS,EAC5D,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,EACnC,cAAc,GAAE,gBAA8B,IAG7C,KAAK,CAAC,EACN,UAAS,kBAA8B,EACvC,kBAAiB,gBAAiC,KAChD,MAAM,CAcT;AAED,eAAO,MAAM,SAAS,+qLAlBX,kBAAkB,oBACV,gBAAgB,KAC/B,MAgBgD,CAAC"}
@@ -5,5 +5,6 @@
5
5
  export * from './consts';
6
6
  export * from './i18n.browser';
7
7
  export * from './resources';
8
+ export * from './sources';
8
9
  export * from './types';
9
10
  //# sourceMappingURL=index.browser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.browser.d.ts","sourceRoot":"","sources":["../src/index.browser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.browser.d.ts","sourceRoot":"","sources":["../src/index.browser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC"}
@@ -2,42 +2,24 @@ import {
2
2
  resources2,
3
3
  LANGUAGE_KEY2,
4
4
  SUPPORTED_LANGUAGES2,
5
- FALLBACK_LANGUAGE2
6
- } from "./chunks/index-86mgj3nf.js";
7
- // src/i18n.browser.ts
8
- import { IntlMessageFormat } from "intl-messageformat";
9
- import _ from "lodash";
10
- function getLanguage() {
11
- if (typeof localStorage !== "undefined") {
12
- const stored = localStorage.getItem(LANGUAGE_KEY2);
13
- if (SUPPORTED_LANGUAGES2.includes(stored)) {
14
- return stored;
15
- }
16
- }
17
- return FALLBACK_LANGUAGE2;
18
- }
19
- function createTranslator(resources = {}, localeProvider = getLanguage) {
20
- return (key, context = undefined, provideLanguage = localeProvider) => {
21
- const language = typeof provideLanguage === "function" ? provideLanguage() : provideLanguage;
22
- let message = _.get(resources[language], key) ?? key;
23
- try {
24
- message = new IntlMessageFormat(message, language).format(context);
25
- } catch (e) {
26
- console.error(e);
27
- }
28
- return message;
29
- };
30
- }
31
- var translate = createTranslator(resources2);
5
+ FALLBACK_LANGUAGE2,
6
+ registerLanguageSource2,
7
+ languageFromSources2,
8
+ getLanguage2,
9
+ createTranslator2,
10
+ translate2
11
+ } from "./chunks/index-jscbtbek.js";
32
12
  export {
33
13
  FALLBACK_LANGUAGE2 as FALLBACK_LANGUAGE,
34
14
  LANGUAGE_KEY2 as LANGUAGE_KEY,
35
15
  SUPPORTED_LANGUAGES2 as SUPPORTED_LANGUAGES,
36
- createTranslator,
37
- getLanguage,
16
+ createTranslator2 as createTranslator,
17
+ getLanguage2 as getLanguage,
18
+ languageFromSources2 as languageFromSources,
19
+ registerLanguageSource2 as registerLanguageSource,
38
20
  resources2 as resources,
39
- translate
21
+ translate2 as translate
40
22
  };
41
23
 
42
- //# debugId=E6A0C2B0582763A764756E2164756E21
24
+ //# debugId=56C1E29CC90F7A3164756E2164756E21
43
25
  //# sourceMappingURL=index.browser.js.map
@@ -1,10 +1,9 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/i18n.browser.ts"],
3
+ "sources": [],
4
4
  "sourcesContent": [
5
- "import { IntlMessageFormat } from 'intl-messageformat';\nimport _ from 'lodash';\nimport { FALLBACK_LANGUAGE, LANGUAGE_KEY, SUPPORTED_LANGUAGES } from './consts';\nimport { resources } from './resources';\nimport type {\n\tLanguage,\n\tLanguageProvider,\n\tLocaleKey,\n\tTranslationContext,\n} from './types';\n\n/**\n * The browser build of {@link getLanguage} from `./i18n`.\n *\n * A bundler that resolves the `browser` export condition (Vite, Nuxt's client\n * build) gets this file instead: it never imports `hono/context-storage`,\n * which pulls in `node:async_hooks` — absent in a browser and dead weight in\n * a client bundle that never runs inside a Hono request. There is no request\n * context to ask in a browser anyway, so the behaviour a consumer sees is the\n * same: `localStorage`, then the fallback language.\n */\nexport function getLanguage(): Language {\n\tif (typeof localStorage !== 'undefined') {\n\t\tconst stored = localStorage.getItem(LANGUAGE_KEY);\n\t\tif (SUPPORTED_LANGUAGES.includes(stored as Language)) {\n\t\t\treturn stored as Language;\n\t\t}\n\t}\n\treturn FALLBACK_LANGUAGE;\n}\n\nexport function createTranslator<K extends string = LocaleKey>(\n\tresources: Record<string, any> = {},\n\tlocaleProvider: LanguageProvider = getLanguage,\n) {\n\treturn (\n\t\tkey: K,\n\t\tcontext: TranslationContext = undefined,\n\t\tprovideLanguage: LanguageProvider = localeProvider,\n\t): string => {\n\t\tconst language =\n\t\t\ttypeof provideLanguage === 'function'\n\t\t\t\t? provideLanguage()\n\t\t\t\t: provideLanguage;\n\t\tlet message: string = _.get(resources[language], key) ?? key;\n\t\ttry {\n\t\t\tmessage = new IntlMessageFormat(message, language).format(context);\n\t\t} catch (e) {\n\t\t\tconsole.error(e);\n\t\t}\n\n\t\treturn message;\n\t};\n}\n\nexport const translate = createTranslator(resources);\n"
6
5
  ],
7
- "mappings": ";;;;;;;AAAA;AACA;AAoBO,SAAS,WAAW,GAAa;AAAA,EACvC,IAAI,OAAO,iBAAiB,aAAa;AAAA,IACxC,MAAM,SAAS,aAAa,QAAQ,aAAY;AAAA,IAChD,IAAI,qBAAoB,SAAS,MAAkB,GAAG;AAAA,MACrD,OAAO;AAAA,IACR;AAAA,EACD;AAAA,EACA,OAAO;AAAA;AAGD,SAAS,gBAA8C,CAC7D,YAAiC,CAAC,GAClC,iBAAmC,aAClC;AAAA,EACD,OAAO,CACN,KACA,UAA8B,WAC9B,kBAAoC,mBACxB;AAAA,IACZ,MAAM,WACL,OAAO,oBAAoB,aACxB,gBAAgB,IAChB;AAAA,IACJ,IAAI,UAAkB,EAAE,IAAI,UAAU,WAAW,GAAG,KAAK;AAAA,IACzD,IAAI;AAAA,MACH,UAAU,IAAI,kBAAkB,SAAS,QAAQ,EAAE,OAAO,OAAO;AAAA,MAChE,OAAO,GAAG;AAAA,MACX,QAAQ,MAAM,CAAC;AAAA;AAAA,IAGhB,OAAO;AAAA;AAAA;AAIF,IAAM,YAAY,iBAAiB,UAAS;",
8
- "debugId": "E6A0C2B0582763A764756E2164756E21",
6
+ "mappings": "",
7
+ "debugId": "56C1E29CC90F7A3164756E2164756E21",
9
8
  "names": []
10
9
  }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from './consts';
2
2
  export * from './i18n';
3
3
  export * from './resources';
4
+ export * from './sources';
4
5
  export * from './types';
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,QAAQ,CAAC;AACvB,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -2,47 +2,24 @@ import {
2
2
  resources2,
3
3
  LANGUAGE_KEY2,
4
4
  SUPPORTED_LANGUAGES2,
5
- FALLBACK_LANGUAGE2
6
- } from "./chunks/index-86mgj3nf.js";
7
- // src/i18n.ts
8
- import { tryGetContext } from "hono/context-storage";
9
- import { IntlMessageFormat } from "intl-messageformat";
10
- import _ from "lodash";
11
- function getLanguage() {
12
- const fromRequest = tryGetContext()?.get(LANGUAGE_KEY2);
13
- if (typeof fromRequest === "string" && SUPPORTED_LANGUAGES2.includes(fromRequest)) {
14
- return fromRequest;
15
- }
16
- if (typeof localStorage !== "undefined") {
17
- const stored = localStorage.getItem(LANGUAGE_KEY2);
18
- if (SUPPORTED_LANGUAGES2.includes(stored)) {
19
- return stored;
20
- }
21
- }
22
- return FALLBACK_LANGUAGE2;
23
- }
24
- function createTranslator(resources = {}, localeProvider = getLanguage) {
25
- return (key, context = undefined, provideLanguage = localeProvider) => {
26
- const language = typeof provideLanguage === "function" ? provideLanguage() : provideLanguage;
27
- let message = _.get(resources[language], key) ?? key;
28
- try {
29
- message = new IntlMessageFormat(message, language).format(context);
30
- } catch (e) {
31
- console.error(e);
32
- }
33
- return message;
34
- };
35
- }
36
- var translate = createTranslator(resources2);
5
+ FALLBACK_LANGUAGE2,
6
+ registerLanguageSource2,
7
+ languageFromSources2,
8
+ getLanguage2,
9
+ createTranslator2,
10
+ translate2
11
+ } from "./chunks/index-jscbtbek.js";
37
12
  export {
38
13
  FALLBACK_LANGUAGE2 as FALLBACK_LANGUAGE,
39
14
  LANGUAGE_KEY2 as LANGUAGE_KEY,
40
15
  SUPPORTED_LANGUAGES2 as SUPPORTED_LANGUAGES,
41
- createTranslator,
42
- getLanguage,
16
+ createTranslator2 as createTranslator,
17
+ getLanguage2 as getLanguage,
18
+ languageFromSources2 as languageFromSources,
19
+ registerLanguageSource2 as registerLanguageSource,
43
20
  resources2 as resources,
44
- translate
21
+ translate2 as translate
45
22
  };
46
23
 
47
- //# debugId=54477F22AC4CF7A564756E2164756E21
24
+ //# debugId=B6438B8D81267DD164756E2164756E21
48
25
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1,10 +1,9 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/i18n.ts"],
3
+ "sources": [],
4
4
  "sourcesContent": [
5
- "import { tryGetContext } from 'hono/context-storage';\nimport { IntlMessageFormat } from 'intl-messageformat';\nimport _ from 'lodash';\nimport { FALLBACK_LANGUAGE, LANGUAGE_KEY, SUPPORTED_LANGUAGES } from './consts';\nimport { resources } from './resources';\nimport type {\n\tLanguage,\n\tLanguageProvider,\n\tLocaleKey,\n\tTranslationContext,\n} from './types';\n\n/**\n * Where the language comes from when the caller does not say.\n *\n * The two repositories had forked exactly this: sellix-monorepo read\n * `localStorage`, nxgt-federation read the Hono request context, and neither\n * could run where the other did — federation's fell back to `'en'` outside a\n * request, sellix's knew nothing about one. Asking both, most specific first,\n * serves either without a caller changing anything.\n *\n * `createTranslator` still takes a provider, so a caller that wants one source\n * and not the other passes it.\n */\nexport function getLanguage(): Language {\n\tconst fromRequest: unknown = tryGetContext()?.get(LANGUAGE_KEY as never);\n\tif (\n\t\ttypeof fromRequest === 'string' &&\n\t\tSUPPORTED_LANGUAGES.includes(fromRequest as Language)\n\t) {\n\t\treturn fromRequest as Language;\n\t}\n\tif (typeof localStorage !== 'undefined') {\n\t\tconst stored = localStorage.getItem(LANGUAGE_KEY);\n\t\tif (SUPPORTED_LANGUAGES.includes(stored as Language)) {\n\t\t\treturn stored as Language;\n\t\t}\n\t}\n\treturn FALLBACK_LANGUAGE;\n}\n\nexport function createTranslator<K extends string = LocaleKey>(\n\tresources: Record<string, any> = {},\n\tlocaleProvider: LanguageProvider = getLanguage,\n) {\n\treturn (\n\t\tkey: K,\n\t\tcontext: TranslationContext = undefined,\n\t\tprovideLanguage: LanguageProvider = localeProvider,\n\t): string => {\n\t\tconst language =\n\t\t\ttypeof provideLanguage === 'function'\n\t\t\t\t? provideLanguage()\n\t\t\t\t: provideLanguage;\n\t\tlet message: string = _.get(resources[language], key) ?? key;\n\t\ttry {\n\t\t\tmessage = new IntlMessageFormat(message, language).format(context);\n\t\t} catch (e) {\n\t\t\tconsole.error(e);\n\t\t}\n\n\t\treturn message;\n\t};\n}\n\nexport const translate = createTranslator(resources);\n"
6
5
  ],
7
- "mappings": ";;;;;;;AAAA;AACA;AACA;AAsBO,SAAS,WAAW,GAAa;AAAA,EACvC,MAAM,cAAuB,cAAc,GAAG,IAAI,aAAqB;AAAA,EACvE,IACC,OAAO,gBAAgB,YACvB,qBAAoB,SAAS,WAAuB,GACnD;AAAA,IACD,OAAO;AAAA,EACR;AAAA,EACA,IAAI,OAAO,iBAAiB,aAAa;AAAA,IACxC,MAAM,SAAS,aAAa,QAAQ,aAAY;AAAA,IAChD,IAAI,qBAAoB,SAAS,MAAkB,GAAG;AAAA,MACrD,OAAO;AAAA,IACR;AAAA,EACD;AAAA,EACA,OAAO;AAAA;AAGD,SAAS,gBAA8C,CAC7D,YAAiC,CAAC,GAClC,iBAAmC,aAClC;AAAA,EACD,OAAO,CACN,KACA,UAA8B,WAC9B,kBAAoC,mBACxB;AAAA,IACZ,MAAM,WACL,OAAO,oBAAoB,aACxB,gBAAgB,IAChB;AAAA,IACJ,IAAI,UAAkB,EAAE,IAAI,UAAU,WAAW,GAAG,KAAK;AAAA,IACzD,IAAI;AAAA,MACH,UAAU,IAAI,kBAAkB,SAAS,QAAQ,EAAE,OAAO,OAAO;AAAA,MAChE,OAAO,GAAG;AAAA,MACX,QAAQ,MAAM,CAAC;AAAA;AAAA,IAGhB,OAAO;AAAA;AAAA;AAIF,IAAM,YAAY,iBAAiB,UAAS;",
8
- "debugId": "54477F22AC4CF7A564756E2164756E21",
6
+ "mappings": "",
7
+ "debugId": "B6438B8D81267DD164756E2164756E21",
9
8
  "names": []
10
9
  }
@@ -23,6 +23,7 @@ export declare const en: {
23
23
  "bad-user-input": string;
24
24
  "operation-resolution-failure": string;
25
25
  "bad-request": string;
26
+ "list-patch-one-operation-per-path": string;
26
27
  };
27
28
  validation: {
28
29
  errors: {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/resources/en/index.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAKd,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/resources/en/index.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAKd,CAAC"}
@@ -23,6 +23,7 @@ export declare const fr: {
23
23
  "bad-user-input": string;
24
24
  "operation-resolution-failure": string;
25
25
  "bad-request": string;
26
+ "list-patch-one-operation-per-path": string;
26
27
  };
27
28
  validation: {
28
29
  errors: {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/resources/fr/index.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAKd,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/resources/fr/index.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAKd,CAAC"}
@@ -24,6 +24,7 @@ export declare const resources: {
24
24
  "bad-user-input": string;
25
25
  "operation-resolution-failure": string;
26
26
  "bad-request": string;
27
+ "list-patch-one-operation-per-path": string;
27
28
  };
28
29
  validation: {
29
30
  errors: {
@@ -248,6 +249,7 @@ export declare const resources: {
248
249
  "bad-user-input": string;
249
250
  "operation-resolution-failure": string;
250
251
  "bad-request": string;
252
+ "list-patch-one-operation-per-path": string;
251
253
  };
252
254
  validation: {
253
255
  errors: {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAGrB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resources/index.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAGrB,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { Language } from './types';
2
+ /**
3
+ * Where a language may come from: a server's request context, a framework's
4
+ * state. It answers the request's language, or nothing — `undefined`, `null`,
5
+ * a language no catalogue has — and the next source is asked.
6
+ */
7
+ export type LanguageSource = () => string | null | undefined;
8
+ /**
9
+ * Adds a source `getLanguage()` asks, after those registered before it.
10
+ * Registering one twice keeps one. Answers the function that removes it.
11
+ *
12
+ * This package knows no server: `@nxgt/shared-hono` registers the Hono
13
+ * request context's `language`, `@alxia/i18n` the alxia request's.
14
+ */
15
+ export declare function registerLanguageSource(source: LanguageSource): () => void;
16
+ /**
17
+ * The first supported language a registered source answers. A source that
18
+ * throws is skipped: a language is never worth a failed request.
19
+ */
20
+ export declare function languageFromSources(): Language | undefined;
21
+ //# sourceMappingURL=sources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sources.d.ts","sourceRoot":"","sources":["../src/sources.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;AAe7D;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,IAAI,CAOzE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,QAAQ,GAAG,SAAS,CAa1D"}
@@ -1,4 +1,3 @@
1
- import './hono.d.ts';
2
1
  export * from './i18n';
3
2
  export * from './path';
4
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAC;AAErB,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxgt/i18n",
3
- "version": "1.1.0",
3
+ "version": "2.0.1",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -41,7 +41,6 @@
41
41
  ]
42
42
  },
43
43
  "dependencies": {
44
- "hono": "^4.13.4",
45
44
  "intl-messageformat": "^12.1.2",
46
45
  "lodash": "^4.18.1"
47
46
  },
@@ -1,13 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/resources/en/index.ts", "../src/resources/fr/index.ts", "../src/resources/index.ts", "../src/consts.ts"],
4
- "sourcesContent": [
5
- "import common from './common.json';\nimport errors from './errors.json';\nimport validation from './validation.json';\nimport zod from './zod.json';\n\nexport const en = {\n\t...common,\n\terrors,\n\tvalidation,\n\tzod,\n};\n",
6
- "import common from './common.json';\nimport errors from './errors.json';\nimport validation from './validation.json';\nimport zod from './zod.json';\n\nexport const fr = {\n\t...common,\n\terrors,\n\tvalidation,\n\tzod,\n};\n",
7
- "import { en } from './en';\nimport { fr } from './fr';\n\nexport const resources = {\n\ten,\n\tfr,\n};\n",
8
- "import { resources } from './resources';\nimport type { Language } from './types';\n\nexport const LANGUAGE_KEY = 'language';\n\nexport const SUPPORTED_LANGUAGES = Object.keys(resources) as Language[];\n\nexport const FALLBACK_LANGUAGE: Language = 'en';\n"
9
- ],
10
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKO,IAAM,KAAK;AAAA,KACd;AAAA,EACH;AAAA,EACA;AAAA,EACA;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACLO,IAAM,KAAK;AAAA,KACd;AAAA,EACH;AAAA,EACA;AAAA,EACA;AACD;;;ACPO,IAAM,aAAY;AAAA,EACxB;AAAA,EACA;AACD;;;ACHO,IAAM,gBAAe;AAErB,IAAM,uBAAsB,OAAO,KAAK,UAAS;AAEjD,IAAM,qBAA8B;",
11
- "debugId": "9B74B0DCF0FC1D0A64756E2164756E21",
12
- "names": []
13
- }
@@ -1,7 +0,0 @@
1
- export {};
2
-
3
- declare module 'hono' {
4
- interface ContextVariableMap {
5
- language?: 'en' | 'fr';
6
- }
7
- }