@fluojs/i18n
Advanced tools
| import type { I18nMessageTree } from './types.js'; | ||
| /** | ||
| * Checks whether a value is a plain object suitable for i18n option or catalog validation. | ||
| * | ||
| * @param value Candidate value to inspect. | ||
| * @returns `true` when the value is a plain object or null-prototype object. | ||
| */ | ||
| export declare function isPlainObject(value: unknown): value is Record<string, unknown>; | ||
| /** | ||
| * Creates a detached immutable message tree from untrusted catalog-like input. | ||
| * | ||
| * @param value Catalog-like value to validate and snapshot. | ||
| * @param path Diagnostic path used in validation errors. | ||
| * @returns A frozen message tree detached from caller-owned data. | ||
| */ | ||
| export declare function snapshotMessageTree(value: unknown, path: string): I18nMessageTree; | ||
| /** | ||
| * Resolves a direct or dot-path message from an immutable i18n message tree. | ||
| * | ||
| * @param tree Locale-scoped catalog tree to inspect. | ||
| * @param key Direct key or dot-path key to resolve. | ||
| * @returns The resolved message string, or `undefined` when the key is absent or not a string leaf. | ||
| */ | ||
| export declare function resolveCatalogMessage(tree: I18nMessageTree | undefined, key: string): string | undefined; | ||
| //# sourceMappingURL=catalog.d.ts.map |
| {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAO9E;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,eAAe,CA0BjF;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,eAAe,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAqBxG"} |
| import { I18nError } from './errors.js'; | ||
| /** | ||
| * Checks whether a value is a plain object suitable for i18n option or catalog validation. | ||
| * | ||
| * @param value Candidate value to inspect. | ||
| * @returns `true` when the value is a plain object or null-prototype object. | ||
| */ | ||
| export function isPlainObject(value) { | ||
| if (typeof value !== 'object' || value === null) { | ||
| return false; | ||
| } | ||
| const prototype = Object.getPrototypeOf(value); | ||
| return prototype === Object.prototype || prototype === null; | ||
| } | ||
| /** | ||
| * Creates a detached immutable message tree from untrusted catalog-like input. | ||
| * | ||
| * @param value Catalog-like value to validate and snapshot. | ||
| * @param path Diagnostic path used in validation errors. | ||
| * @returns A frozen message tree detached from caller-owned data. | ||
| */ | ||
| export function snapshotMessageTree(value, path) { | ||
| if (!isPlainObject(value)) { | ||
| throw new I18nError(`${path} must be a plain object message tree.`, 'I18N_INVALID_CATALOG'); | ||
| } | ||
| const snapshot = {}; | ||
| for (const [key, entry] of Object.entries(value)) { | ||
| if (key.trim() === '') { | ||
| throw new I18nError(`${path} contains an empty message key segment.`, 'I18N_INVALID_CATALOG'); | ||
| } | ||
| if (typeof entry === 'string') { | ||
| snapshot[key] = entry; | ||
| continue; | ||
| } | ||
| if (isPlainObject(entry)) { | ||
| snapshot[key] = snapshotMessageTree(entry, `${path}.${key}`); | ||
| continue; | ||
| } | ||
| throw new I18nError(`${path}.${key} must be a string or nested message tree.`, 'I18N_INVALID_CATALOG'); | ||
| } | ||
| return Object.freeze(snapshot); | ||
| } | ||
| /** | ||
| * Resolves a direct or dot-path message from an immutable i18n message tree. | ||
| * | ||
| * @param tree Locale-scoped catalog tree to inspect. | ||
| * @param key Direct key or dot-path key to resolve. | ||
| * @returns The resolved message string, or `undefined` when the key is absent or not a string leaf. | ||
| */ | ||
| export function resolveCatalogMessage(tree, key) { | ||
| if (tree === undefined) { | ||
| return undefined; | ||
| } | ||
| if (Object.hasOwn(tree, key)) { | ||
| const direct = tree[key]; | ||
| return typeof direct === 'string' ? direct : undefined; | ||
| } | ||
| let current = tree; | ||
| for (const part of key.split('.')) { | ||
| if (!isPlainObject(current) || !Object.hasOwn(current, part)) { | ||
| return undefined; | ||
| } | ||
| current = current[part]; | ||
| } | ||
| return typeof current === 'string' ? current : undefined; | ||
| } |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"icu.d.ts","sourceRoot":"","sources":["../src/icu.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAGlD,OAAO,EAAE,WAAW,EAAc,MAAM,cAAc,CAAC;AACvD,OAAO,KAAK,EAAwD,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEhI;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,CAAC;AAExF;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;AAEnE;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,IAAI,CAAC,oBAAoB,EAAE,QAAQ,CAAC;IACnF,kGAAkG;IAClG,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAChC,mEAAmE;IACnE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;CACrC;AAgFD;;;;;;GAMG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IAEtC;;;;OAIG;gBACS,OAAO,GAAE,iBAAiB,GAAG,WAAgB;IAIzD;;;;OAIG;IACH,cAAc,IAAI,WAAW;IAI7B;;;;;;;OAOG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,uBAAuB,GAAG,MAAM;CAsBjE;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,GAAE,iBAAiB,GAAG,WAAgB,GAAG,cAAc,CAE3F"} | ||
| {"version":3,"file":"icu.d.ts","sourceRoot":"","sources":["../src/icu.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAIlD,OAAO,EAAE,WAAW,EAAc,MAAM,cAAc,CAAC;AACvD,OAAO,KAAK,EAAuC,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAE/G;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,CAAC;AAExF;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;AAEnE;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,IAAI,CAAC,oBAAoB,EAAE,QAAQ,CAAC;IACnF,kGAAkG;IAClG,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAChC,mEAAmE;IACnE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;CACrC;AAqDD;;;;;;GAMG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IAEtC;;;;OAIG;gBACS,OAAO,GAAE,iBAAiB,GAAG,WAAgB;IAIzD;;;;OAIG;IACH,cAAc,IAAI,WAAW;IAI7B;;;;;;;OAOG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,uBAAuB,GAAG,MAAM;CAsBjE;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,GAAE,iBAAiB,GAAG,WAAgB,GAAG,cAAc,CAE3F"} |
+2
-21
| import { FormatError, IntlMessageFormat } from 'intl-messageformat'; | ||
| import { resolveCatalogMessage } from './catalog.js'; | ||
| import { I18nError } from './errors.js'; | ||
@@ -40,22 +41,2 @@ import { I18nService, createI18n } from './service.js'; | ||
| } | ||
| function hasOwn(value, key) { | ||
| return typeof value === 'object' && value !== null && Object.hasOwn(value, key); | ||
| } | ||
| function resolveMessage(tree, key) { | ||
| if (tree === undefined) { | ||
| return undefined; | ||
| } | ||
| if (hasOwn(tree, key)) { | ||
| const direct = tree[key]; | ||
| return typeof direct === 'string' ? direct : undefined; | ||
| } | ||
| let current = tree; | ||
| for (const part of key.split('.')) { | ||
| if (!hasOwn(current, part)) { | ||
| return undefined; | ||
| } | ||
| current = current[part]; | ||
| } | ||
| return typeof current === 'string' ? current : undefined; | ||
| } | ||
| function resolveMessageLocale(service, key, options) { | ||
@@ -65,3 +46,3 @@ const resolvedKey = options.namespace === undefined ? key : `${options.namespace}.${key}`; | ||
| for (const locale of service.resolveLocales(options.locale)) { | ||
| if (resolveMessage(snapshot.catalogs?.[locale], resolvedKey) !== undefined) { | ||
| if (resolveCatalogMessage(snapshot.catalogs?.[locale], resolvedKey) !== undefined) { | ||
| return locale; | ||
@@ -68,0 +49,0 @@ } |
@@ -23,10 +23,4 @@ import type { I18nLocale, I18nMessageTree, I18nTranslationKey } from '../types.js'; | ||
| } | ||
| export { isPlainObject } from '../catalog.js'; | ||
| /** | ||
| * Checks whether a value is a plain object suitable for loader option or catalog validation. | ||
| * | ||
| * @param value Candidate value to inspect. | ||
| * @returns `true` when the value is a plain object or null-prototype object. | ||
| */ | ||
| export declare function isPlainObject(value: unknown): value is Record<string, unknown>; | ||
| /** | ||
| * Validates a loader locale before a backend is called. | ||
@@ -33,0 +27,0 @@ * |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/loaders/shared.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAKnF;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;;;;;;OAOG;IACH,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CACpH;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAO9E;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,UAAU,CAIjG;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,IAAI,kBAAkB,CAelH;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,eAAe,CA0BvF"} | ||
| {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/loaders/shared.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAKnF;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;;;;;;OAOG;IACH,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,kBAAkB,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CACpH;AAED,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,UAAU,CAIjG;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,IAAI,kBAAkB,CAelH;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,eAAe,CAEvF"} |
| import { I18nError } from '../errors.js'; | ||
| import { snapshotMessageTree } from '../catalog.js'; | ||
| const SAFE_LOCALE_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9_-]*[A-Za-z0-9])?(?:-[A-Za-z0-9](?:[A-Za-z0-9_-]*[A-Za-z0-9])?)*$/; | ||
@@ -13,15 +14,3 @@ const SAFE_NAMESPACE_SEGMENT_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9_-]*[A-Za-z0-9])?$/; | ||
| /** | ||
| * Checks whether a value is a plain object suitable for loader option or catalog validation. | ||
| * | ||
| * @param value Candidate value to inspect. | ||
| * @returns `true` when the value is a plain object or null-prototype object. | ||
| */ | ||
| export function isPlainObject(value) { | ||
| if (typeof value !== 'object' || value === null) { | ||
| return false; | ||
| } | ||
| const prototype = Object.getPrototypeOf(value); | ||
| return prototype === Object.prototype || prototype === null; | ||
| } | ||
| export { isPlainObject } from '../catalog.js'; | ||
@@ -71,21 +60,3 @@ /** | ||
| export function snapshotLoaderMessageTree(value, path) { | ||
| if (!isPlainObject(value)) { | ||
| throw new I18nError(`${path} must be a plain object message tree.`, 'I18N_INVALID_CATALOG'); | ||
| } | ||
| const snapshot = {}; | ||
| for (const [key, entry] of Object.entries(value)) { | ||
| if (key.trim() === '') { | ||
| throw new I18nError(`${path} contains an empty message key segment.`, 'I18N_INVALID_CATALOG'); | ||
| } | ||
| if (typeof entry === 'string') { | ||
| snapshot[key] = entry; | ||
| continue; | ||
| } | ||
| if (isPlainObject(entry)) { | ||
| snapshot[key] = snapshotLoaderMessageTree(entry, `${path}.${key}`); | ||
| continue; | ||
| } | ||
| throw new I18nError(`${path}.${key} must be a string or nested message tree.`, 'I18N_INVALID_CATALOG'); | ||
| } | ||
| return Object.freeze(snapshot); | ||
| return snapshotMessageTree(value, path); | ||
| } |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAgF,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAwMlI;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,GAAE,iBAAsB,GAAG,iBAAiB,CAU5F"} | ||
| {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../src/options.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAgF,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAmKlI;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,GAAE,iBAAsB,GAAG,iBAAiB,CAU5F"} |
+1
-28
| import { I18nError } from './errors.js'; | ||
| function isPlainObject(value) { | ||
| if (typeof value !== 'object' || value === null) { | ||
| return false; | ||
| } | ||
| const prototype = Object.getPrototypeOf(value); | ||
| return prototype === Object.prototype || prototype === null; | ||
| } | ||
| import { isPlainObject, snapshotMessageTree } from './catalog.js'; | ||
| function assertLocale(value, label) { | ||
@@ -65,23 +59,2 @@ if (typeof value !== 'string' || value.trim() === '') { | ||
| } | ||
| function snapshotMessageTree(value, path) { | ||
| if (!isPlainObject(value)) { | ||
| throw new I18nError(`${path} must be a plain object message tree.`, 'I18N_INVALID_CATALOG'); | ||
| } | ||
| const snapshot = {}; | ||
| for (const [key, entry] of Object.entries(value)) { | ||
| if (key.trim() === '') { | ||
| throw new I18nError(`${path} contains an empty message key segment.`, 'I18N_INVALID_CATALOG'); | ||
| } | ||
| if (typeof entry === 'string') { | ||
| snapshot[key] = entry; | ||
| continue; | ||
| } | ||
| if (isPlainObject(entry)) { | ||
| snapshot[key] = snapshotMessageTree(entry, `${path}.${key}`); | ||
| continue; | ||
| } | ||
| throw new I18nError(`${path}.${key} must be a string or nested message tree.`, 'I18N_INVALID_CATALOG'); | ||
| } | ||
| return Object.freeze(snapshot); | ||
| } | ||
| function snapshotCatalogs(catalogs, supportedLocales) { | ||
@@ -88,0 +61,0 @@ if (catalogs === undefined) { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,yBAAyB,EACzB,yBAAyB,EAEzB,qBAAqB,EACrB,UAAU,EAEV,iBAAiB,EACjB,uBAAuB,EACvB,6BAA6B,EAC7B,oBAAoB,EACrB,MAAM,YAAY,CAAC;AA+IpB;;;;;;GAMG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAE5C;;;;OAIG;gBACS,OAAO,GAAE,iBAAsB;IAI3C;;;;OAIG;IACH,eAAe,IAAI,iBAAiB;IAIpC;;;;;;OAMG;IACH,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,SAAS,UAAU,EAAE;IA2BzD,OAAO,CAAC,mBAAmB;IAkB3B;;;;;;;OAOG;IACH,cAAc,CAAC,KAAK,EAAE,IAAI,GAAG,MAAM,EAAE,OAAO,EAAE,yBAAyB,GAAG,MAAM;IAWhF;;;;;;;OAOG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,uBAAuB,GAAG,MAAM;IAWrE;;;;;;;OAOG;IACH,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,yBAAyB,GAAG,MAAM;IAiBzE;;;;;;;OAOG;IACH,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,uBAAuB,GAAG,MAAM;IAWtE;;;;;;;OAOG;IACH,UAAU,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,qBAAqB,GAAG,MAAM;IAY7E;;;;;;;;OAQG;IACH,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,sBAAsB,EAAE,OAAO,EAAE,6BAA6B,GAAG,MAAM;IAWpH;;;;;;;OAOG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,GAAG,MAAM;CAoC9D;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,WAAW,CAEvE"} | ||
| {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,yBAAyB,EACzB,yBAAyB,EAEzB,qBAAqB,EACrB,UAAU,EACV,iBAAiB,EACjB,uBAAuB,EACvB,6BAA6B,EAC7B,oBAAoB,EACrB,MAAM,YAAY,CAAC;AA2GpB;;;;;;GAMG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoB;IAE5C;;;;OAIG;gBACS,OAAO,GAAE,iBAAsB;IAI3C;;;;OAIG;IACH,eAAe,IAAI,iBAAiB;IAIpC;;;;;;OAMG;IACH,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,SAAS,UAAU,EAAE;IA2BzD,OAAO,CAAC,mBAAmB;IAkB3B;;;;;;;OAOG;IACH,cAAc,CAAC,KAAK,EAAE,IAAI,GAAG,MAAM,EAAE,OAAO,EAAE,yBAAyB,GAAG,MAAM;IAWhF;;;;;;;OAOG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,uBAAuB,GAAG,MAAM;IAWrE;;;;;;;OAOG;IACH,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,yBAAyB,GAAG,MAAM;IAiBzE;;;;;;;OAOG;IACH,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,uBAAuB,GAAG,MAAM;IAWtE;;;;;;;OAOG;IACH,UAAU,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,EAAE,qBAAqB,GAAG,MAAM;IAY7E;;;;;;;;OAQG;IACH,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,sBAAsB,EAAE,OAAO,EAAE,6BAA6B,GAAG,MAAM;IAWpH;;;;;;;OAOG;IACH,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,GAAG,MAAM;CAoC9D;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,WAAW,CAEvE"} |
+2
-28
@@ -0,13 +1,4 @@ | ||
| import { isPlainObject, resolveCatalogMessage } from './catalog.js'; | ||
| import { snapshotI18nModuleOptions } from './options.js'; | ||
| import { I18nError } from './errors.js'; | ||
| function hasOwn(value, key) { | ||
| return typeof value === 'object' && value !== null && Object.hasOwn(value, key); | ||
| } | ||
| function isPlainObject(value) { | ||
| if (typeof value !== 'object' || value === null) { | ||
| return false; | ||
| } | ||
| const prototype = Object.getPrototypeOf(value); | ||
| return prototype === Object.prototype || prototype === null; | ||
| } | ||
| function normalizeTranslationKey(key, namespace) { | ||
@@ -89,19 +80,2 @@ if (typeof key !== 'string') { | ||
| } | ||
| function resolveMessage(tree, key) { | ||
| if (tree === undefined) { | ||
| return undefined; | ||
| } | ||
| if (hasOwn(tree, key)) { | ||
| const direct = tree[key]; | ||
| return typeof direct === 'string' ? direct : undefined; | ||
| } | ||
| let current = tree; | ||
| for (const part of key.split('.')) { | ||
| if (!hasOwn(current, part)) { | ||
| return undefined; | ||
| } | ||
| current = current[part]; | ||
| } | ||
| return typeof current === 'string' ? current : undefined; | ||
| } | ||
| function pushUnique(locales, locale) { | ||
@@ -320,3 +294,3 @@ if (locale !== undefined && !locales.includes(locale)) { | ||
| for (const locale of locales) { | ||
| const message = resolveMessage(this.options.catalogs?.[locale], resolvedKey); | ||
| const message = resolveCatalogMessage(this.options.catalogs?.[locale], resolvedKey); | ||
| if (message !== undefined) { | ||
@@ -323,0 +297,0 @@ return interpolate(message, options.values); |
+7
-9
@@ -11,3 +11,3 @@ { | ||
| ], | ||
| "version": "1.0.3", | ||
| "version": "2.0.0", | ||
| "private": false, | ||
@@ -20,5 +20,2 @@ "license": "MIT", | ||
| }, | ||
| "engines": { | ||
| "node": ">=20.0.0" | ||
| }, | ||
| "publishConfig": { | ||
@@ -68,8 +65,8 @@ "access": "public" | ||
| "dependencies": { | ||
| "@fluojs/core": "^1.0.3" | ||
| "@fluojs/core": "^1.1.0" | ||
| }, | ||
| "peerDependencies": { | ||
| "intl-messageformat": "^11.2.4", | ||
| "@fluojs/http": "^1.1.0", | ||
| "@fluojs/validation": "^1.0.4" | ||
| "@fluojs/http": "^2.0.1", | ||
| "@fluojs/validation": "^1.0.6" | ||
| }, | ||
@@ -90,4 +87,5 @@ "peerDependenciesMeta": { | ||
| "vitest": "^3.2.4", | ||
| "@fluojs/http": "^1.1.0", | ||
| "@fluojs/validation": "^1.0.4" | ||
| "@fluojs/testing": "^2.0.0", | ||
| "@fluojs/http": "^2.0.1", | ||
| "@fluojs/validation": "^1.0.6" | ||
| }, | ||
@@ -94,0 +92,0 @@ "scripts": { |
+5
-3
@@ -33,3 +33,3 @@ # @fluojs/i18n | ||
| Root entry point는 `@fluojs/core`에만 의존합니다. Optional subpath는 integration dependency를 optional peer로 유지합니다. `@fluojs/i18n/icu`를 opt-in하면 `intl-messageformat`, `@fluojs/i18n/http`를 opt-in하면 `@fluojs/http`, `@fluojs/i18n/validation`을 opt-in하면 `@fluojs/validation`을 함께 설치하세요. 기존 subpath 사용자는 이 dependency boundary 변경이 포함된 릴리스로 업그레이드하기 전에 해당 peer dependency를 application 또는 package manifest에 추가해야 합니다. | ||
| Root entry point는 `@fluojs/core`에만 의존하고 Node.js engine floor를 선언하지 않으며 framework-agnostic bundle에서 안전하게 import할 수 있습니다. Optional subpath는 integration dependency를 optional peer로 유지합니다. `@fluojs/i18n/icu`를 opt-in하면 `intl-messageformat`, `@fluojs/i18n/http`를 opt-in하면 `@fluojs/http`, `@fluojs/i18n/validation`을 opt-in하면 `@fluojs/validation`을 함께 설치하세요. 기존 subpath 사용자는 이 dependency boundary 변경이 포함된 릴리스로 업그레이드하기 전에 해당 peer dependency를 application 또는 package manifest에 추가해야 합니다. | ||
@@ -72,2 +72,4 @@ ## 사용 시점 | ||
| `I18nModule.forRoot(...)`는 기본적으로 `I18nService`를 global provider로 export하므로 root package를 한 번 import한 뒤 sibling module에서도 shared service를 inject할 수 있습니다. Service를 i18n module을 import한 module 안에만 보이게 하려면 `global: false`를 전달하세요. | ||
| ## 코어 번역 | ||
@@ -424,6 +426,6 @@ | ||
| |---|---| | ||
| | `I18nModule` | DI 등록을 위한 모듈입니다. | | ||
| | `I18nModule` | Core i18n service surface를 등록하는 모듈 facade입니다. Provider는 기본적으로 global이며 `global: false`로 module-local로 유지할 수 있습니다. | | ||
| | `I18nService` | Detached option/catalog snapshot을 소유하고 translation을 resolve하며 explicit-locale `Intl` formatting helper(`formatDateTime`, `formatNumber`, `formatCurrency`, `formatPercent`, `formatList`, `formatRelativeTime`)를 제공하는 core service입니다. | | ||
| | `createI18n` | 독립형 서비스를 생성하기 위한 헬퍼입니다. | | ||
| | `I18nError` | 패키지 전용 에러 클래스입니다. | | ||
| | `I18nError` | 안정적인 에러 코드를 포함하는 기본 i18n 패키지 에러입니다. | | ||
@@ -430,0 +432,0 @@ **타입:** `I18nModuleOptions`, `I18nMessageCatalogs`, `I18nMessageTree`, `I18nTranslateOptions`, `I18nInterpolationValues`, `I18nMissingMessageHandler`, `I18nMissingMessageContext`, `I18nLocale`, `I18nTranslationKey`, `I18nErrorCode`, `I18nFallbackLocales`, `I18nFormatOptions`, `I18nFormatterOptions`, `I18nDateTimeFormatOptions`, `I18nNumberFormatOptions`, `I18nCurrencyFormatOptions`, `I18nListFormatOptions`, `I18nRelativeTimeFormatOptions`, `I18nNamedDateTimeFormats`, `I18nNamedNumberFormats`, `I18nNamedListFormats`, `I18nNamedRelativeTimeFormats`. |
+4
-2
@@ -33,3 +33,3 @@ # @fluojs/i18n | ||
| The root entry point depends only on `@fluojs/core`. Optional subpaths keep their integration dependencies as optional peers: install `intl-messageformat` for `@fluojs/i18n/icu`, `@fluojs/http` for `@fluojs/i18n/http`, and `@fluojs/validation` for `@fluojs/i18n/validation` when you opt into those surfaces. Existing subpath users should add those peer dependencies to their application or package manifest before upgrading to the release that includes this dependency boundary change. | ||
| The root entry point depends only on `@fluojs/core`, does not declare a Node.js engine floor, and is safe to import in framework-agnostic bundles. Optional subpaths keep their integration dependencies as optional peers: install `intl-messageformat` for `@fluojs/i18n/icu`, `@fluojs/http` for `@fluojs/i18n/http`, and `@fluojs/validation` for `@fluojs/i18n/validation` when you opt into those surfaces. Existing subpath users should add those peer dependencies to their application or package manifest before upgrading to the release that includes this dependency boundary change. | ||
@@ -72,2 +72,4 @@ ## When to Use | ||
| `I18nModule.forRoot(...)` exports `I18nService` as a global provider by default so sibling modules can inject the shared service after the root package is imported once. Pass `global: false` when the service should stay visible only to the module that imports the i18n module. | ||
| ## Core Translation | ||
@@ -424,3 +426,3 @@ | ||
| |---|---| | ||
| | `I18nModule` | Module facade for registering the core i18n service surface. | | ||
| | `I18nModule` | Module facade for registering the core i18n service surface; providers are global by default and can be kept module-local with `global: false`. | | ||
| | `I18nService` | Core service that owns detached options/catalog snapshots, resolves translations, and exposes explicit-locale `Intl` formatting helpers (`formatDateTime`, `formatNumber`, `formatCurrency`, `formatPercent`, `formatList`, `formatRelativeTime`). | | ||
@@ -427,0 +429,0 @@ | `createI18n(options)` | Creates a standalone `I18nService` without module registration. | |
222181
0.71%52
6.12%540
0.37%5
25%3173
-0.56%+ Added
+ Added
- Removed
- Removed
Updated