@fluojs/i18n 1.0.0-beta.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.
Files changed (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.ko.md +537 -0
  3. package/README.md +537 -0
  4. package/dist/adapters.d.ts +180 -0
  5. package/dist/adapters.d.ts.map +1 -0
  6. package/dist/adapters.js +266 -0
  7. package/dist/errors.d.ts +17 -0
  8. package/dist/errors.d.ts.map +1 -0
  9. package/dist/errors.js +19 -0
  10. package/dist/http.d.ts +120 -0
  11. package/dist/http.d.ts.map +1 -0
  12. package/dist/http.js +179 -0
  13. package/dist/icu.d.ts +59 -0
  14. package/dist/icu.d.ts.map +1 -0
  15. package/dist/icu.js +142 -0
  16. package/dist/index.d.ts +5 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +3 -0
  19. package/dist/loaders/fs.d.ts +43 -0
  20. package/dist/loaders/fs.d.ts.map +1 -0
  21. package/dist/loaders/fs.js +79 -0
  22. package/dist/loaders/remote.d.ts +146 -0
  23. package/dist/loaders/remote.d.ts.map +1 -0
  24. package/dist/loaders/remote.js +268 -0
  25. package/dist/loaders/shared.d.ts +54 -0
  26. package/dist/loaders/shared.d.ts.map +1 -0
  27. package/dist/loaders/shared.js +89 -0
  28. package/dist/locale-resolution.d.ts +86 -0
  29. package/dist/locale-resolution.d.ts.map +1 -0
  30. package/dist/locale-resolution.js +201 -0
  31. package/dist/module.d.ts +22 -0
  32. package/dist/module.d.ts.map +1 -0
  33. package/dist/module.js +60 -0
  34. package/dist/options.d.ts +9 -0
  35. package/dist/options.d.ts.map +1 -0
  36. package/dist/options.js +169 -0
  37. package/dist/service.d.ts +104 -0
  38. package/dist/service.d.ts.map +1 -0
  39. package/dist/service.js +348 -0
  40. package/dist/typegen.d.ts +60 -0
  41. package/dist/typegen.d.ts.map +1 -0
  42. package/dist/typegen.js +215 -0
  43. package/dist/types.d.ts +154 -0
  44. package/dist/types.d.ts.map +1 -0
  45. package/dist/types.js +1 -0
  46. package/dist/validation.d.ts +74 -0
  47. package/dist/validation.d.ts.map +1 -0
  48. package/dist/validation.js +123 -0
  49. package/package.json +97 -0
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Locale identifier accepted by the i18n package surface.
3
+ */
4
+ export type I18nLocale = string;
5
+ /**
6
+ * Dot-path translation key resolved from a locale-scoped message catalog.
7
+ */
8
+ export type I18nTranslationKey = string;
9
+ /**
10
+ * Stable i18n package error codes for caller-visible failures.
11
+ */
12
+ export type I18nErrorCode = 'I18N_ERROR' | 'I18N_INVALID_CATALOG' | 'I18N_INVALID_LOADER_OPTIONS' | 'I18N_INVALID_LOCALE_CONFIG' | 'I18N_INVALID_MESSAGE_FORMAT' | 'I18N_INVALID_OPTIONS' | 'I18N_LOADER_ABORTED' | 'I18N_LOADER_FAILED' | 'I18N_LOADER_TIMEOUT' | 'I18N_MISSING_CATALOG' | 'I18N_MISSING_MESSAGE';
13
+ /**
14
+ * Named `Intl.DateTimeFormat` option bags captured during i18n registration.
15
+ */
16
+ export type I18nNamedDateTimeFormats = Readonly<Record<string, Intl.DateTimeFormatOptions>>;
17
+ /**
18
+ * Named `Intl.NumberFormat` option bags captured during i18n registration.
19
+ */
20
+ export type I18nNamedNumberFormats = Readonly<Record<string, Intl.NumberFormatOptions>>;
21
+ /**
22
+ * Named `Intl.ListFormat` option bags captured during i18n registration.
23
+ */
24
+ export type I18nNamedListFormats = Readonly<Record<string, Intl.ListFormatOptions>>;
25
+ /**
26
+ * Named `Intl.RelativeTimeFormat` option bags captured during i18n registration.
27
+ */
28
+ export type I18nNamedRelativeTimeFormats = Readonly<Record<string, Intl.RelativeTimeFormatOptions>>;
29
+ /**
30
+ * Reusable named option groups for standard `Intl` formatters.
31
+ */
32
+ export interface I18nFormatOptions {
33
+ /** Named date/time format option bags. */
34
+ readonly dateTime?: I18nNamedDateTimeFormats;
35
+ /** Named number, currency, and percent format option bags. */
36
+ readonly number?: I18nNamedNumberFormats;
37
+ /** Named list format option bags. */
38
+ readonly list?: I18nNamedListFormats;
39
+ /** Named relative time format option bags. */
40
+ readonly relativeTime?: I18nNamedRelativeTimeFormats;
41
+ }
42
+ /**
43
+ * Common per-call options for helpers backed by standard `Intl` formatters.
44
+ */
45
+ export interface I18nFormatterOptions {
46
+ /** Locale passed directly to the underlying `Intl` formatter. */
47
+ readonly locale: I18nLocale;
48
+ /** Optional named format option bag registered in `I18nModuleOptions.formats`. */
49
+ readonly format?: string;
50
+ }
51
+ /**
52
+ * Per-call date/time formatting options.
53
+ */
54
+ export interface I18nDateTimeFormatOptions extends I18nFormatterOptions {
55
+ /** Inline `Intl.DateTimeFormat` options merged after the named option bag. */
56
+ readonly options?: Intl.DateTimeFormatOptions;
57
+ }
58
+ /**
59
+ * Per-call number, currency, and percent formatting options.
60
+ */
61
+ export interface I18nNumberFormatOptions extends I18nFormatterOptions {
62
+ /** Inline `Intl.NumberFormat` options merged after the named option bag. */
63
+ readonly options?: Intl.NumberFormatOptions;
64
+ }
65
+ /**
66
+ * Per-call currency formatting options.
67
+ */
68
+ export interface I18nCurrencyFormatOptions extends I18nNumberFormatOptions {
69
+ /** ISO 4217 currency code passed to `Intl.NumberFormat`. */
70
+ readonly currency: string;
71
+ }
72
+ /**
73
+ * Per-call list formatting options.
74
+ */
75
+ export interface I18nListFormatOptions extends I18nFormatterOptions {
76
+ /** Inline `Intl.ListFormat` options merged after the named option bag. */
77
+ readonly options?: Intl.ListFormatOptions;
78
+ }
79
+ /**
80
+ * Per-call relative time formatting options.
81
+ */
82
+ export interface I18nRelativeTimeFormatOptions extends I18nFormatterOptions {
83
+ /** Inline `Intl.RelativeTimeFormat` options merged after the named option bag. */
84
+ readonly options?: Intl.RelativeTimeFormatOptions;
85
+ }
86
+ /**
87
+ * Interpolation values available to simple `{{ name }}` placeholders.
88
+ */
89
+ export type I18nInterpolationValues = Readonly<Record<string, string | number | boolean | null | undefined>>;
90
+ /**
91
+ * Nested message tree for one locale.
92
+ */
93
+ export interface I18nMessageTree {
94
+ /** Message leaf or nested message tree keyed by path segment. */
95
+ readonly [key: string]: string | I18nMessageTree;
96
+ }
97
+ /**
98
+ * Canonical locale-scoped catalog map consumed by the core translation service.
99
+ */
100
+ export type I18nMessageCatalogs = Readonly<Record<I18nLocale, I18nMessageTree>>;
101
+ /**
102
+ * Fallback locale chain applied globally or per requested locale.
103
+ */
104
+ export type I18nFallbackLocales = readonly I18nLocale[] | Readonly<Record<I18nLocale, readonly I18nLocale[]>>;
105
+ /**
106
+ * Context passed to the missing-message hook after catalog/default fallback resolution fails.
107
+ */
108
+ export interface I18nMissingMessageContext {
109
+ /** Requested locale supplied explicitly by the translation caller. */
110
+ readonly locale: I18nLocale;
111
+ /** Translation key after optional namespace prefixing. */
112
+ readonly key: I18nTranslationKey;
113
+ /** Deterministic locale chain inspected before the hook was invoked. */
114
+ readonly attemptedLocales: readonly I18nLocale[];
115
+ /** Interpolation values supplied by the caller. */
116
+ readonly values?: I18nInterpolationValues;
117
+ }
118
+ /**
119
+ * Hook invoked when no message and no default value can satisfy a translation request.
120
+ */
121
+ export type I18nMissingMessageHandler = (context: I18nMissingMessageContext) => string | undefined;
122
+ /**
123
+ * Per-call translation options. Locale is always explicit in the framework-agnostic core.
124
+ */
125
+ export interface I18nTranslateOptions {
126
+ /** Locale to resolve first. */
127
+ readonly locale: I18nLocale;
128
+ /** Optional namespace prefix, resolved as `${namespace}.${key}`. */
129
+ readonly namespace?: I18nTranslationKey;
130
+ /** Values interpolated into `{{ name }}` placeholders. */
131
+ readonly values?: I18nInterpolationValues;
132
+ /** Caller-provided fallback returned before the missing-message hook is invoked. */
133
+ readonly defaultValue?: string;
134
+ }
135
+ /**
136
+ * Root i18n module options captured during package registration.
137
+ */
138
+ export interface I18nModuleOptions {
139
+ /** Default fallback locale used after the configured locale chain. */
140
+ defaultLocale?: I18nLocale;
141
+ /** Locale-scoped message catalogs. */
142
+ catalogs?: I18nMessageCatalogs;
143
+ /** Supported locale allow-list for configuration and per-call locale validation. */
144
+ supportedLocales?: readonly I18nLocale[];
145
+ /** Global or per-locale deterministic fallback chain inspected before the default locale. */
146
+ fallbackLocales?: I18nFallbackLocales;
147
+ /** Hook invoked when no catalog entry and no default value can satisfy a translation request. */
148
+ missingMessage?: I18nMissingMessageHandler;
149
+ /** Reusable named `Intl` formatter option bags captured as immutable service-owned snapshots. */
150
+ formats?: I18nFormatOptions;
151
+ /** Whether the module should expose `I18nService` globally. Defaults to `true`. */
152
+ global?: boolean;
153
+ }
154
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC;AAEhC;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAExC;;GAEG;AACH,MAAM,MAAM,aAAa,GACrB,YAAY,GACZ,sBAAsB,GACtB,6BAA6B,GAC7B,4BAA4B,GAC5B,6BAA6B,GAC7B,sBAAsB,GACtB,qBAAqB,GACrB,oBAAoB,GACpB,qBAAqB,GACrB,sBAAsB,GACtB,sBAAsB,CAAC;AAE3B;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC;AAE5F;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC;AAExF;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;AAEpF;;GAEG;AACH,MAAM,MAAM,4BAA4B,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,yBAAyB,CAAC,CAAC,CAAC;AAEpG;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,0CAA0C;IAC1C,QAAQ,CAAC,QAAQ,CAAC,EAAE,wBAAwB,CAAC;IAC7C,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,CAAC,EAAE,sBAAsB,CAAC;IACzC,qCAAqC;IACrC,QAAQ,CAAC,IAAI,CAAC,EAAE,oBAAoB,CAAC;IACrC,8CAA8C;IAC9C,QAAQ,CAAC,YAAY,CAAC,EAAE,4BAA4B,CAAC;CACtD;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,iEAAiE;IACjE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,kFAAkF;IAClF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,yBAA0B,SAAQ,oBAAoB;IACrE,8EAA8E;IAC9E,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,qBAAqB,CAAC;CAC/C;AAED;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,oBAAoB;IACnE,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,mBAAmB,CAAC;CAC7C;AAED;;GAEG;AACH,MAAM,WAAW,yBAA0B,SAAQ,uBAAuB;IACxE,4DAA4D;IAC5D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,qBAAsB,SAAQ,oBAAoB;IACjE,0EAA0E;IAC1E,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,iBAAiB,CAAC;CAC3C;AAED;;GAEG;AACH,MAAM,WAAW,6BAA8B,SAAQ,oBAAoB;IACzE,kFAAkF;IAClF,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,yBAAyB,CAAC;CACnD;AAED;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC;AAE7G;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,iEAAiE;IACjE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,eAAe,CAAC;CAClD;AAED;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC,CAAC;AAEhF;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,SAAS,UAAU,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,UAAU,EAAE,CAAC,CAAC,CAAC;AAE9G;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,sEAAsE;IACtE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,0DAA0D;IAC1D,QAAQ,CAAC,GAAG,EAAE,kBAAkB,CAAC;IACjC,wEAAwE;IACxE,QAAQ,CAAC,gBAAgB,EAAE,SAAS,UAAU,EAAE,CAAC;IACjD,mDAAmD;IACnD,QAAQ,CAAC,MAAM,CAAC,EAAE,uBAAuB,CAAC;CAC3C;AAED;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,OAAO,EAAE,yBAAyB,KAAK,MAAM,GAAG,SAAS,CAAC;AAEnG;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,+BAA+B;IAC/B,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,oEAAoE;IACpE,QAAQ,CAAC,SAAS,CAAC,EAAE,kBAAkB,CAAC;IACxC,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,CAAC,EAAE,uBAAuB,CAAC;IAC1C,oFAAoF;IACpF,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,sEAAsE;IACtE,aAAa,CAAC,EAAE,UAAU,CAAC;IAC3B,sCAAsC;IACtC,QAAQ,CAAC,EAAE,mBAAmB,CAAC;IAC/B,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IACzC,6FAA6F;IAC7F,eAAe,CAAC,EAAE,mBAAmB,CAAC;IACtC,iGAAiG;IACjG,cAAc,CAAC,EAAE,yBAAyB,CAAC;IAC3C,iGAAiG;IACjG,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,mFAAmF;IACnF,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB"}
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,74 @@
1
+ import { DtoValidationError, type ValidationIssue } from '@fluojs/validation';
2
+ import type { I18nLocale, I18nTranslationKey } from './types.js';
3
+ import type { I18nService } from './service.js';
4
+ /**
5
+ * Context used to derive translation keys for one validation issue.
6
+ */
7
+ export interface ValidationIssueTranslationKeyContext {
8
+ /** Validation issue being localized. */
9
+ readonly issue: ValidationIssue;
10
+ /** Zero-based index of the issue in the caller-provided issue list. */
11
+ readonly index: number;
12
+ }
13
+ /**
14
+ * Builds candidate i18n translation keys for one validation issue.
15
+ */
16
+ export type ValidationIssueTranslationKeyBuilder = (context: ValidationIssueTranslationKeyContext) => readonly I18nTranslationKey[];
17
+ /**
18
+ * Options for opt-in validation issue localization.
19
+ */
20
+ export interface LocalizeValidationIssuesOptions {
21
+ /** Locale used for validation issue message lookup. */
22
+ readonly locale: I18nLocale;
23
+ /** Optional namespace passed to `I18nService.translate(...)`. Defaults to `validation`. */
24
+ readonly namespace?: I18nTranslationKey;
25
+ /** Optional prefix prepended to generated candidate keys. */
26
+ readonly keyPrefix?: I18nTranslationKey;
27
+ /** Custom key builder for applications that own a different catalog shape. */
28
+ readonly keyBuilder?: ValidationIssueTranslationKeyBuilder;
29
+ /** Whether missing translations should preserve the original issue message. Defaults to `true`. */
30
+ readonly fallbackToIssueMessage?: boolean;
31
+ }
32
+ /**
33
+ * Creates default translation key candidates for a validation issue.
34
+ *
35
+ * @remarks
36
+ * Candidate order is most-specific to least-specific: `source.field.code`, `field.code`, `source.code`, then `code`.
37
+ * The optional `keyPrefix` is prepended to each candidate. Field paths are preserved as authored by
38
+ * `@fluojs/validation`, allowing catalogs to mirror dot/bracket validation paths explicitly.
39
+ *
40
+ * @param issue Validation issue to map into translation keys.
41
+ * @param keyPrefix Optional catalog prefix prepended before generated keys.
42
+ * @returns Ordered translation key candidates.
43
+ */
44
+ export declare function createValidationIssueTranslationKeys(issue: ValidationIssue, keyPrefix?: I18nTranslationKey): readonly I18nTranslationKey[];
45
+ /**
46
+ * Localizes one validation issue by resolving explicit translation key candidates.
47
+ *
48
+ * @param i18n I18n service used for catalog lookup.
49
+ * @param issue Validation issue whose message should be localized.
50
+ * @param options Explicit locale and optional key mapping controls.
51
+ * @param index Zero-based index used only by custom key builders.
52
+ * @returns A new validation issue with a localized message when a candidate resolves.
53
+ * @throws {I18nError} When no translation resolves and `fallbackToIssueMessage` is `false`.
54
+ */
55
+ export declare function localizeValidationIssue(i18n: I18nService, issue: ValidationIssue, options: LocalizeValidationIssuesOptions, index?: number): ValidationIssue;
56
+ /**
57
+ * Localizes validation issues without mutating the original issue objects.
58
+ *
59
+ * @param i18n I18n service used for catalog lookup.
60
+ * @param issues Validation issues from `@fluojs/validation`.
61
+ * @param options Explicit locale and optional key mapping controls.
62
+ * @returns Localized validation issue snapshots.
63
+ */
64
+ export declare function localizeValidationIssues(i18n: I18nService, issues: readonly ValidationIssue[], options: LocalizeValidationIssuesOptions): readonly ValidationIssue[];
65
+ /**
66
+ * Creates a new `DtoValidationError` with localized issue messages.
67
+ *
68
+ * @param i18n I18n service used for catalog lookup.
69
+ * @param error Validation error from `@fluojs/validation`.
70
+ * @param options Explicit locale and optional key mapping controls.
71
+ * @returns A new validation error that preserves the original top-level error message and localized issue snapshots.
72
+ */
73
+ export declare function localizeDtoValidationError(i18n: I18nService, error: DtoValidationError, options: LocalizeValidationIssuesOptions): DtoValidationError;
74
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAG9E,OAAO,KAAK,EAA2B,UAAU,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAC1F,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD;;GAEG;AACH,MAAM,WAAW,oCAAoC;IACnD,wCAAwC;IACxC,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,MAAM,oCAAoC,GAAG,CACjD,OAAO,EAAE,oCAAoC,KAC1C,SAAS,kBAAkB,EAAE,CAAC;AAEnC;;GAEG;AACH,MAAM,WAAW,+BAA+B;IAC9C,uDAAuD;IACvD,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,2FAA2F;IAC3F,QAAQ,CAAC,SAAS,CAAC,EAAE,kBAAkB,CAAC;IACxC,6DAA6D;IAC7D,QAAQ,CAAC,SAAS,CAAC,EAAE,kBAAkB,CAAC;IACxC,8EAA8E;IAC9E,QAAQ,CAAC,UAAU,CAAC,EAAE,oCAAoC,CAAC;IAC3D,mGAAmG;IACnG,QAAQ,CAAC,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAC3C;AAqBD;;;;;;;;;;;GAWG;AACH,wBAAgB,oCAAoC,CAClD,KAAK,EAAE,eAAe,EACtB,SAAS,CAAC,EAAE,kBAAkB,GAC7B,SAAS,kBAAkB,EAAE,CAkB/B;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,eAAe,EACtB,OAAO,EAAE,+BAA+B,EACxC,KAAK,SAAI,GACR,eAAe,CA6BjB;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,WAAW,EACjB,MAAM,EAAE,SAAS,eAAe,EAAE,EAClC,OAAO,EAAE,+BAA+B,GACvC,SAAS,eAAe,EAAE,CAE5B;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,kBAAkB,EACzB,OAAO,EAAE,+BAA+B,GACvC,kBAAkB,CAEpB"}
@@ -0,0 +1,123 @@
1
+ import { DtoValidationError } from '@fluojs/validation';
2
+ import { I18nError } from './errors.js';
3
+
4
+ /**
5
+ * Context used to derive translation keys for one validation issue.
6
+ */
7
+
8
+ /**
9
+ * Builds candidate i18n translation keys for one validation issue.
10
+ */
11
+
12
+ /**
13
+ * Options for opt-in validation issue localization.
14
+ */
15
+
16
+ const DEFAULT_VALIDATION_NAMESPACE = 'validation';
17
+ function isMissingMessageError(error) {
18
+ return error instanceof I18nError && error.code === 'I18N_MISSING_MESSAGE';
19
+ }
20
+ function appendWithPrefix(keys, keyPrefix, key) {
21
+ keys.push(keyPrefix === undefined ? key : `${keyPrefix}.${key}`);
22
+ }
23
+ function createValidationInterpolationValues(issue) {
24
+ return {
25
+ code: issue.code,
26
+ field: issue.field,
27
+ message: issue.message,
28
+ source: issue.source
29
+ };
30
+ }
31
+
32
+ /**
33
+ * Creates default translation key candidates for a validation issue.
34
+ *
35
+ * @remarks
36
+ * Candidate order is most-specific to least-specific: `source.field.code`, `field.code`, `source.code`, then `code`.
37
+ * The optional `keyPrefix` is prepended to each candidate. Field paths are preserved as authored by
38
+ * `@fluojs/validation`, allowing catalogs to mirror dot/bracket validation paths explicitly.
39
+ *
40
+ * @param issue Validation issue to map into translation keys.
41
+ * @param keyPrefix Optional catalog prefix prepended before generated keys.
42
+ * @returns Ordered translation key candidates.
43
+ */
44
+ export function createValidationIssueTranslationKeys(issue, keyPrefix) {
45
+ const keys = [];
46
+ if (issue.source !== undefined && issue.field !== undefined) {
47
+ appendWithPrefix(keys, keyPrefix, `${issue.source}.${issue.field}.${issue.code}`);
48
+ }
49
+ if (issue.field !== undefined) {
50
+ appendWithPrefix(keys, keyPrefix, `${issue.field}.${issue.code}`);
51
+ }
52
+ if (issue.source !== undefined) {
53
+ appendWithPrefix(keys, keyPrefix, `${issue.source}.${issue.code}`);
54
+ }
55
+ appendWithPrefix(keys, keyPrefix, issue.code);
56
+ return Object.freeze(keys);
57
+ }
58
+
59
+ /**
60
+ * Localizes one validation issue by resolving explicit translation key candidates.
61
+ *
62
+ * @param i18n I18n service used for catalog lookup.
63
+ * @param issue Validation issue whose message should be localized.
64
+ * @param options Explicit locale and optional key mapping controls.
65
+ * @param index Zero-based index used only by custom key builders.
66
+ * @returns A new validation issue with a localized message when a candidate resolves.
67
+ * @throws {I18nError} When no translation resolves and `fallbackToIssueMessage` is `false`.
68
+ */
69
+ export function localizeValidationIssue(i18n, issue, options, index = 0) {
70
+ const namespace = options.namespace ?? DEFAULT_VALIDATION_NAMESPACE;
71
+ const keys = options.keyBuilder?.({
72
+ index,
73
+ issue
74
+ }) ?? createValidationIssueTranslationKeys(issue, options.keyPrefix);
75
+ const values = createValidationInterpolationValues(issue);
76
+ for (const key of keys) {
77
+ try {
78
+ return {
79
+ ...issue,
80
+ message: i18n.translate(key, {
81
+ locale: options.locale,
82
+ namespace,
83
+ values
84
+ })
85
+ };
86
+ } catch (error) {
87
+ if (isMissingMessageError(error)) {
88
+ continue;
89
+ }
90
+ throw error;
91
+ }
92
+ }
93
+ if (options.fallbackToIssueMessage === false) {
94
+ throw new I18nError(`Missing validation i18n message for issue code: ${issue.code}`, 'I18N_MISSING_MESSAGE');
95
+ }
96
+ return {
97
+ ...issue
98
+ };
99
+ }
100
+
101
+ /**
102
+ * Localizes validation issues without mutating the original issue objects.
103
+ *
104
+ * @param i18n I18n service used for catalog lookup.
105
+ * @param issues Validation issues from `@fluojs/validation`.
106
+ * @param options Explicit locale and optional key mapping controls.
107
+ * @returns Localized validation issue snapshots.
108
+ */
109
+ export function localizeValidationIssues(i18n, issues, options) {
110
+ return Object.freeze(issues.map((issue, index) => localizeValidationIssue(i18n, issue, options, index)));
111
+ }
112
+
113
+ /**
114
+ * Creates a new `DtoValidationError` with localized issue messages.
115
+ *
116
+ * @param i18n I18n service used for catalog lookup.
117
+ * @param error Validation error from `@fluojs/validation`.
118
+ * @param options Explicit locale and optional key mapping controls.
119
+ * @returns A new validation error that preserves the original top-level error message and localized issue snapshots.
120
+ */
121
+ export function localizeDtoValidationError(i18n, error, options) {
122
+ return new DtoValidationError(error.message, localizeValidationIssues(i18n, error.issues, options));
123
+ }
package/package.json ADDED
@@ -0,0 +1,97 @@
1
+ {
2
+ "name": "@fluojs/i18n",
3
+ "description": "Framework-agnostic internationalization core surface for fluo applications.",
4
+ "keywords": [
5
+ "fluo",
6
+ "i18n",
7
+ "internationalization",
8
+ "localization",
9
+ "translations"
10
+ ],
11
+ "version": "1.0.0-beta.1",
12
+ "private": false,
13
+ "license": "MIT",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/fluojs/fluo.git",
17
+ "directory": "packages/i18n"
18
+ },
19
+ "engines": {
20
+ "node": ">=20.0.0"
21
+ },
22
+ "publishConfig": {
23
+ "access": "public"
24
+ },
25
+ "type": "module",
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "import": "./dist/index.js"
30
+ },
31
+ "./loaders/fs": {
32
+ "types": "./dist/loaders/fs.d.ts",
33
+ "import": "./dist/loaders/fs.js"
34
+ },
35
+ "./loaders/remote": {
36
+ "types": "./dist/loaders/remote.d.ts",
37
+ "import": "./dist/loaders/remote.js"
38
+ },
39
+ "./http": {
40
+ "types": "./dist/http.d.ts",
41
+ "import": "./dist/http.js"
42
+ },
43
+ "./adapters": {
44
+ "types": "./dist/adapters.d.ts",
45
+ "import": "./dist/adapters.js"
46
+ },
47
+ "./icu": {
48
+ "types": "./dist/icu.d.ts",
49
+ "import": "./dist/icu.js"
50
+ },
51
+ "./validation": {
52
+ "types": "./dist/validation.d.ts",
53
+ "import": "./dist/validation.js"
54
+ },
55
+ "./typegen": {
56
+ "types": "./dist/typegen.d.ts",
57
+ "import": "./dist/typegen.js"
58
+ }
59
+ },
60
+ "main": "./dist/index.js",
61
+ "types": "./dist/index.d.ts",
62
+ "files": [
63
+ "dist"
64
+ ],
65
+ "dependencies": {
66
+ "@fluojs/core": "^1.0.0-beta.6"
67
+ },
68
+ "peerDependencies": {
69
+ "intl-messageformat": "^11.2.4",
70
+ "@fluojs/http": "^1.0.0-beta.11",
71
+ "@fluojs/validation": "^1.0.0-beta.4"
72
+ },
73
+ "peerDependenciesMeta": {
74
+ "@fluojs/http": {
75
+ "optional": true
76
+ },
77
+ "@fluojs/validation": {
78
+ "optional": true
79
+ },
80
+ "intl-messageformat": {
81
+ "optional": true
82
+ }
83
+ },
84
+ "devDependencies": {
85
+ "intl-messageformat": "^11.2.4",
86
+ "vitest": "^3.2.4",
87
+ "@fluojs/http": "^1.0.0-beta.11",
88
+ "@fluojs/validation": "^1.0.0-beta.4"
89
+ },
90
+ "scripts": {
91
+ "prebuild": "node ../../tooling/scripts/clean-dist.mjs",
92
+ "build": "pnpm exec babel src --extensions .ts --ignore 'src/**/*.test.ts' --out-dir dist --config-file ../../tooling/babel/babel.config.cjs && pnpm exec tsc -p tsconfig.build.json",
93
+ "typecheck": "pnpm exec tsc -p tsconfig.json --noEmit && pnpm exec tsc -p tsconfig.node.json --noEmit",
94
+ "test": "pnpm exec vitest run -c vitest.config.ts",
95
+ "test:watch": "pnpm exec vitest -c vitest.config.ts"
96
+ }
97
+ }