intor-translator 1.5.0 → 1.6.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/dist/index.cjs CHANGED
@@ -50,6 +50,162 @@ var BaseTranslator = class {
50
50
  }
51
51
  };
52
52
 
53
+ // src/formatter/utils/to-cache-key.ts
54
+ function toCacheKey(locale, options) {
55
+ if (!options || Object.keys(options).length === 0) return locale;
56
+ const normalized = Object.entries(options).filter(([, value]) => value !== void 0).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => `${key}:${String(value)}`).join("|");
57
+ return `${locale}__${normalized}`;
58
+ }
59
+
60
+ // src/formatter/date/create-date-time-formatter.ts
61
+ function createDateTimeFormatter() {
62
+ const cache = /* @__PURE__ */ new Map();
63
+ return (locale, options) => {
64
+ const key = toCacheKey(locale, options);
65
+ const cached = cache.get(key);
66
+ if (cached) return cached;
67
+ const formatter = new Intl.DateTimeFormat(locale, options);
68
+ cache.set(key, formatter);
69
+ return formatter;
70
+ };
71
+ }
72
+
73
+ // src/formatter/display-name/create-display-names.ts
74
+ function createDisplayNames() {
75
+ const cache = /* @__PURE__ */ new Map();
76
+ return (locale, options) => {
77
+ const key = toCacheKey(locale, options);
78
+ const cached = cache.get(key);
79
+ if (cached) return cached;
80
+ const displayNames = new Intl.DisplayNames(locale, options);
81
+ cache.set(key, displayNames);
82
+ return displayNames;
83
+ };
84
+ }
85
+
86
+ // src/formatter/list/create-list-formatter.ts
87
+ function createListFormatter() {
88
+ const cache = /* @__PURE__ */ new Map();
89
+ return (locale, options) => {
90
+ const key = toCacheKey(locale, options);
91
+ const cached = cache.get(key);
92
+ if (cached) return cached;
93
+ const formatter = new Intl.ListFormat(locale, options);
94
+ cache.set(key, formatter);
95
+ return formatter;
96
+ };
97
+ }
98
+
99
+ // src/formatter/number/create-number-formatter.ts
100
+ function createNumberFormatter() {
101
+ const cache = /* @__PURE__ */ new Map();
102
+ return (locale, options) => {
103
+ const key = toCacheKey(locale, options);
104
+ const cached = cache.get(key);
105
+ if (cached) return cached;
106
+ const formatter = new Intl.NumberFormat(locale, options);
107
+ cache.set(key, formatter);
108
+ return formatter;
109
+ };
110
+ }
111
+
112
+ // src/formatter/plural/create-plural-rules.ts
113
+ function createPluralRules() {
114
+ const cache = /* @__PURE__ */ new Map();
115
+ return (locale, options) => {
116
+ const key = toCacheKey(locale, options);
117
+ const cached = cache.get(key);
118
+ if (cached) return cached;
119
+ const rules = new Intl.PluralRules(locale, options);
120
+ cache.set(key, rules);
121
+ return rules;
122
+ };
123
+ }
124
+
125
+ // src/formatter/relative-time/create-relative-time-formatter.ts
126
+ function createRelativeTimeFormatter() {
127
+ const cache = /* @__PURE__ */ new Map();
128
+ return (locale, options) => {
129
+ const key = toCacheKey(locale, options);
130
+ const cached = cache.get(key);
131
+ if (cached) return cached;
132
+ const formatter = new Intl.RelativeTimeFormat(locale, options);
133
+ cache.set(key, formatter);
134
+ return formatter;
135
+ };
136
+ }
137
+
138
+ // src/formatter/create-formatter.ts
139
+ function createFormatter({
140
+ getLocale,
141
+ formatDefaults
142
+ }) {
143
+ const getDateTimeFormatter = createDateTimeFormatter();
144
+ const getListFormatter = createListFormatter();
145
+ const getRelativeTimeFormatter = createRelativeTimeFormatter();
146
+ const getNumberFormatter = createNumberFormatter();
147
+ const getDisplayNames = createDisplayNames();
148
+ const getPluralRules = createPluralRules();
149
+ return {
150
+ number(value, options) {
151
+ return getNumberFormatter(getLocale(), {
152
+ ...formatDefaults?.number,
153
+ ...options
154
+ }).format(value);
155
+ },
156
+ currency(value, currency, options) {
157
+ const resolvedCurrency = currency ?? formatDefaults?.currencyCode;
158
+ if (!resolvedCurrency) {
159
+ throw new Error("[intor-translator] currency is required");
160
+ }
161
+ return getNumberFormatter(getLocale(), {
162
+ ...formatDefaults?.currency,
163
+ ...options,
164
+ style: "currency",
165
+ currency: resolvedCurrency
166
+ }).format(value);
167
+ },
168
+ date(value, options) {
169
+ return getDateTimeFormatter(getLocale(), {
170
+ ...formatDefaults?.date,
171
+ ...formatDefaults?.timeZone ? { timeZone: formatDefaults.timeZone } : {},
172
+ ...options
173
+ }).format(value);
174
+ },
175
+ relativeTime(value, unit, options) {
176
+ return getRelativeTimeFormatter(getLocale(), {
177
+ ...formatDefaults?.relativeTime,
178
+ ...options
179
+ }).format(value, unit);
180
+ },
181
+ list(values, options) {
182
+ return getListFormatter(getLocale(), {
183
+ ...formatDefaults?.list,
184
+ ...options
185
+ }).format(values);
186
+ },
187
+ displayName(value, options) {
188
+ const resolvedOptions = {
189
+ ...formatDefaults?.displayName,
190
+ ...options
191
+ };
192
+ if (!resolvedOptions.type) {
193
+ throw new Error("[intor-translator] displayName type is required");
194
+ }
195
+ return getDisplayNames(
196
+ getLocale(),
197
+ resolvedOptions
198
+ ).of(value);
199
+ },
200
+ plural(value, options) {
201
+ return getPluralRules(getLocale(), {
202
+ ...formatDefaults?.plural,
203
+ ...options
204
+ }).select(value);
205
+ }
206
+ };
207
+ }
208
+
53
209
  // src/shared/utils/resolve-candidate-locales.ts
54
210
  var resolveCandidateLocales = (locale, fallbackLocalesMap) => {
55
211
  const fallbacks = fallbackLocalesMap?.[locale] || [];
@@ -78,6 +234,9 @@ var findMessageInLocales = ({
78
234
  for (const locale of candidateLocales) {
79
235
  const messagesForLocale = messages[locale];
80
236
  if (!messagesForLocale) continue;
237
+ if (key in messagesForLocale) {
238
+ return messagesForLocale[key];
239
+ }
81
240
  let candidate = messagesForLocale;
82
241
  const keys = key.split(".");
83
242
  for (const key2 of keys) {
@@ -266,14 +425,27 @@ var CoreTranslator = class extends BaseTranslator {
266
425
  [...DEFAULT_HOOKS],
267
426
  { name: "Intor Translator" }
268
427
  );
428
+ /** Locale-aware formatting helpers. */
429
+ format;
269
430
  constructor(options) {
270
- const { locale, messages, isLoading, hooks, ...translateConfig } = options;
431
+ const {
432
+ locale,
433
+ messages,
434
+ isLoading,
435
+ hooks,
436
+ formatDefaults,
437
+ ...translateConfig
438
+ } = options;
271
439
  super({
272
440
  locale,
273
441
  ...messages !== void 0 && { messages },
274
442
  ...isLoading !== void 0 && { isLoading }
275
443
  });
276
444
  this.translateConfig = translateConfig;
445
+ this.format = createFormatter({
446
+ getLocale: () => this.locale,
447
+ ...formatDefaults !== void 0 && { formatDefaults }
448
+ });
277
449
  if (hooks) for (const hook of hooks) this.use(hook);
278
450
  }
279
451
  /** Registers a pipeline hook. */
@@ -328,6 +500,8 @@ var ScopeTranslator = class extends CoreTranslator {
328
500
  /** Create a scoped translator with a prefix key for resolving nested message paths. */
329
501
  scoped(preKey) {
330
502
  return {
503
+ /** Locale-aware formatting helpers. */
504
+ format: this.format,
331
505
  /** Checks whether a translation key exists. */
332
506
  hasKey: (key, targetLocale) => {
333
507
  const fullKey = getFullKey(preKey, key);