@intlify/core-base 10.0.0-beta.6 → 10.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * core-base v10.0.0-beta.6
2
+ * core-base v10.0.0
3
3
  * (c) 2024 kazuya kawaguchi
4
4
  * Released under the MIT License.
5
5
  */
@@ -8,402 +8,135 @@
8
8
  var messageCompiler = require('@intlify/message-compiler');
9
9
  var shared = require('@intlify/shared');
10
10
 
11
- const pathStateMachine = [];
12
- pathStateMachine[0 /* States.BEFORE_PATH */] = {
13
- ["w" /* PathCharTypes.WORKSPACE */]: [0 /* States.BEFORE_PATH */],
14
- ["i" /* PathCharTypes.IDENT */]: [3 /* States.IN_IDENT */, 0 /* Actions.APPEND */],
15
- ["[" /* PathCharTypes.LEFT_BRACKET */]: [4 /* States.IN_SUB_PATH */],
16
- ["o" /* PathCharTypes.END_OF_FAIL */]: [7 /* States.AFTER_PATH */]
17
- };
18
- pathStateMachine[1 /* States.IN_PATH */] = {
19
- ["w" /* PathCharTypes.WORKSPACE */]: [1 /* States.IN_PATH */],
20
- ["." /* PathCharTypes.DOT */]: [2 /* States.BEFORE_IDENT */],
21
- ["[" /* PathCharTypes.LEFT_BRACKET */]: [4 /* States.IN_SUB_PATH */],
22
- ["o" /* PathCharTypes.END_OF_FAIL */]: [7 /* States.AFTER_PATH */]
23
- };
24
- pathStateMachine[2 /* States.BEFORE_IDENT */] = {
25
- ["w" /* PathCharTypes.WORKSPACE */]: [2 /* States.BEFORE_IDENT */],
26
- ["i" /* PathCharTypes.IDENT */]: [3 /* States.IN_IDENT */, 0 /* Actions.APPEND */],
27
- ["0" /* PathCharTypes.ZERO */]: [3 /* States.IN_IDENT */, 0 /* Actions.APPEND */]
28
- };
29
- pathStateMachine[3 /* States.IN_IDENT */] = {
30
- ["i" /* PathCharTypes.IDENT */]: [3 /* States.IN_IDENT */, 0 /* Actions.APPEND */],
31
- ["0" /* PathCharTypes.ZERO */]: [3 /* States.IN_IDENT */, 0 /* Actions.APPEND */],
32
- ["w" /* PathCharTypes.WORKSPACE */]: [1 /* States.IN_PATH */, 1 /* Actions.PUSH */],
33
- ["." /* PathCharTypes.DOT */]: [2 /* States.BEFORE_IDENT */, 1 /* Actions.PUSH */],
34
- ["[" /* PathCharTypes.LEFT_BRACKET */]: [4 /* States.IN_SUB_PATH */, 1 /* Actions.PUSH */],
35
- ["o" /* PathCharTypes.END_OF_FAIL */]: [7 /* States.AFTER_PATH */, 1 /* Actions.PUSH */]
36
- };
37
- pathStateMachine[4 /* States.IN_SUB_PATH */] = {
38
- ["'" /* PathCharTypes.SINGLE_QUOTE */]: [5 /* States.IN_SINGLE_QUOTE */, 0 /* Actions.APPEND */],
39
- ["\"" /* PathCharTypes.DOUBLE_QUOTE */]: [6 /* States.IN_DOUBLE_QUOTE */, 0 /* Actions.APPEND */],
40
- ["[" /* PathCharTypes.LEFT_BRACKET */]: [
41
- 4 /* States.IN_SUB_PATH */,
42
- 2 /* Actions.INC_SUB_PATH_DEPTH */
43
- ],
44
- ["]" /* PathCharTypes.RIGHT_BRACKET */]: [1 /* States.IN_PATH */, 3 /* Actions.PUSH_SUB_PATH */],
45
- ["o" /* PathCharTypes.END_OF_FAIL */]: 8 /* States.ERROR */,
46
- ["l" /* PathCharTypes.ELSE */]: [4 /* States.IN_SUB_PATH */, 0 /* Actions.APPEND */]
47
- };
48
- pathStateMachine[5 /* States.IN_SINGLE_QUOTE */] = {
49
- ["'" /* PathCharTypes.SINGLE_QUOTE */]: [4 /* States.IN_SUB_PATH */, 0 /* Actions.APPEND */],
50
- ["o" /* PathCharTypes.END_OF_FAIL */]: 8 /* States.ERROR */,
51
- ["l" /* PathCharTypes.ELSE */]: [5 /* States.IN_SINGLE_QUOTE */, 0 /* Actions.APPEND */]
52
- };
53
- pathStateMachine[6 /* States.IN_DOUBLE_QUOTE */] = {
54
- ["\"" /* PathCharTypes.DOUBLE_QUOTE */]: [4 /* States.IN_SUB_PATH */, 0 /* Actions.APPEND */],
55
- ["o" /* PathCharTypes.END_OF_FAIL */]: 8 /* States.ERROR */,
56
- ["l" /* PathCharTypes.ELSE */]: [6 /* States.IN_DOUBLE_QUOTE */, 0 /* Actions.APPEND */]
57
- };
58
- /**
59
- * Check if an expression is a literal value.
60
- */
61
- const literalValueRE = /^\s?(?:true|false|-?[\d.]+|'[^']*'|"[^"]*")\s?$/;
62
- function isLiteral(exp) {
63
- return literalValueRE.test(exp);
64
- }
65
- /**
66
- * Strip quotes from a string
67
- */
68
- function stripQuotes(str) {
69
- const a = str.charCodeAt(0);
70
- const b = str.charCodeAt(str.length - 1);
71
- return a === b && (a === 0x22 || a === 0x27) ? str.slice(1, -1) : str;
11
+ function format(ast) {
12
+ const msg = (ctx) => formatParts(ctx, ast);
13
+ return msg;
72
14
  }
73
- /**
74
- * Determine the type of a character in a keypath.
75
- */
76
- function getPathCharType(ch) {
77
- if (ch === undefined || ch === null) {
78
- return "o" /* PathCharTypes.END_OF_FAIL */;
15
+ function formatParts(ctx, ast) {
16
+ const body = ast.b || ast.body;
17
+ if ((body.t || body.type) === 1 /* NodeTypes.Plural */) {
18
+ const plural = body;
19
+ const cases = plural.c || plural.cases;
20
+ return ctx.plural(cases.reduce((messages, c) => [
21
+ ...messages,
22
+ formatMessageParts(ctx, c)
23
+ ], []));
79
24
  }
80
- const code = ch.charCodeAt(0);
81
- switch (code) {
82
- case 0x5b: // [
83
- case 0x5d: // ]
84
- case 0x2e: // .
85
- case 0x22: // "
86
- case 0x27: // '
87
- return ch;
88
- case 0x5f: // _
89
- case 0x24: // $
90
- case 0x2d: // -
91
- return "i" /* PathCharTypes.IDENT */;
92
- case 0x09: // Tab (HT)
93
- case 0x0a: // Newline (LF)
94
- case 0x0d: // Return (CR)
95
- case 0xa0: // No-break space (NBSP)
96
- case 0xfeff: // Byte Order Mark (BOM)
97
- case 0x2028: // Line Separator (LS)
98
- case 0x2029: // Paragraph Separator (PS)
99
- return "w" /* PathCharTypes.WORKSPACE */;
25
+ else {
26
+ return formatMessageParts(ctx, body);
100
27
  }
101
- return "i" /* PathCharTypes.IDENT */;
102
28
  }
103
- /**
104
- * Format a subPath, return its plain form if it is
105
- * a literal string or number. Otherwise prepend the
106
- * dynamic indicator (*).
107
- */
108
- function formatSubPath(path) {
109
- const trimmed = path.trim();
110
- // invalid leading 0
111
- if (path.charAt(0) === '0' && isNaN(parseInt(path))) {
112
- return false;
29
+ function formatMessageParts(ctx, node) {
30
+ const _static = node.s || node.static;
31
+ if (_static) {
32
+ return ctx.type === 'text'
33
+ ? _static
34
+ : ctx.normalize([_static]);
113
35
  }
114
- return isLiteral(trimmed)
115
- ? stripQuotes(trimmed)
116
- : "*" /* PathCharTypes.ASTARISK */ + trimmed;
117
- }
118
- /**
119
- * Parse a string path into an array of segments
120
- */
121
- function parse(path) {
122
- const keys = [];
123
- let index = -1;
124
- let mode = 0 /* States.BEFORE_PATH */;
125
- let subPathDepth = 0;
126
- let c;
127
- let key; // eslint-disable-line
128
- let newChar;
129
- let type;
130
- let transition;
131
- let action;
132
- let typeMap;
133
- const actions = [];
134
- actions[0 /* Actions.APPEND */] = () => {
135
- if (key === undefined) {
136
- key = newChar;
137
- }
138
- else {
139
- key += newChar;
140
- }
141
- };
142
- actions[1 /* Actions.PUSH */] = () => {
143
- if (key !== undefined) {
144
- keys.push(key);
145
- key = undefined;
146
- }
147
- };
148
- actions[2 /* Actions.INC_SUB_PATH_DEPTH */] = () => {
149
- actions[0 /* Actions.APPEND */]();
150
- subPathDepth++;
151
- };
152
- actions[3 /* Actions.PUSH_SUB_PATH */] = () => {
153
- if (subPathDepth > 0) {
154
- subPathDepth--;
155
- mode = 4 /* States.IN_SUB_PATH */;
156
- actions[0 /* Actions.APPEND */]();
157
- }
158
- else {
159
- subPathDepth = 0;
160
- if (key === undefined) {
161
- return false;
162
- }
163
- key = formatSubPath(key);
164
- if (key === false) {
165
- return false;
166
- }
167
- else {
168
- actions[1 /* Actions.PUSH */]();
169
- }
170
- }
171
- };
172
- function maybeUnescapeQuote() {
173
- const nextChar = path[index + 1];
174
- if ((mode === 5 /* States.IN_SINGLE_QUOTE */ &&
175
- nextChar === "'" /* PathCharTypes.SINGLE_QUOTE */) ||
176
- (mode === 6 /* States.IN_DOUBLE_QUOTE */ &&
177
- nextChar === "\"" /* PathCharTypes.DOUBLE_QUOTE */)) {
178
- index++;
179
- newChar = '\\' + nextChar;
180
- actions[0 /* Actions.APPEND */]();
181
- return true;
182
- }
36
+ else {
37
+ const messages = (node.i || node.items).reduce((acm, c) => [...acm, formatMessagePart(ctx, c)], []);
38
+ return ctx.normalize(messages);
183
39
  }
184
- while (mode !== null) {
185
- index++;
186
- c = path[index];
187
- if (c === '\\' && maybeUnescapeQuote()) {
188
- continue;
40
+ }
41
+ function formatMessagePart(ctx, node) {
42
+ const type = node.t || node.type;
43
+ switch (type) {
44
+ case 3 /* NodeTypes.Text */: {
45
+ const text = node;
46
+ return (text.v || text.value);
189
47
  }
190
- type = getPathCharType(c);
191
- typeMap = pathStateMachine[mode];
192
- transition = typeMap[type] || typeMap["l" /* PathCharTypes.ELSE */] || 8 /* States.ERROR */;
193
- // check parse error
194
- if (transition === 8 /* States.ERROR */) {
195
- return;
48
+ case 9 /* NodeTypes.Literal */: {
49
+ const literal = node;
50
+ return (literal.v || literal.value);
196
51
  }
197
- mode = transition[0];
198
- if (transition[1] !== undefined) {
199
- action = actions[transition[1]];
200
- if (action) {
201
- newChar = c;
202
- if (action() === false) {
203
- return;
204
- }
205
- }
52
+ case 4 /* NodeTypes.Named */: {
53
+ const named = node;
54
+ return ctx.interpolate(ctx.named(named.k || named.key));
206
55
  }
207
- // check parse finish
208
- if (mode === 7 /* States.AFTER_PATH */) {
209
- return keys;
56
+ case 5 /* NodeTypes.List */: {
57
+ const list = node;
58
+ return ctx.interpolate(ctx.list(list.i != null ? list.i : list.index));
210
59
  }
211
- }
212
- }
213
- // path token cache
214
- const cache = new Map();
215
- /**
216
- * key-value message resolver
217
- *
218
- * @remarks
219
- * Resolves messages with the key-value structure. Note that messages with a hierarchical structure such as objects cannot be resolved
220
- *
221
- * @param obj - A target object to be resolved with path
222
- * @param path - A {@link Path | path} to resolve the value of message
223
- *
224
- * @returns A resolved {@link PathValue | path value}
225
- *
226
- * @VueI18nGeneral
227
- */
228
- function resolveWithKeyValue(obj, path) {
229
- return shared.isObject(obj) ? obj[path] : null;
230
- }
231
- /**
232
- * message resolver
233
- *
234
- * @remarks
235
- * Resolves messages. messages with a hierarchical structure such as objects can be resolved. This resolver is used in VueI18n as default.
236
- *
237
- * @param obj - A target object to be resolved with path
238
- * @param path - A {@link Path | path} to resolve the value of message
239
- *
240
- * @returns A resolved {@link PathValue | path value}
241
- *
242
- * @VueI18nGeneral
243
- */
244
- function resolveValue(obj, path) {
245
- // check object
246
- if (!shared.isObject(obj)) {
247
- return null;
248
- }
249
- // parse path
250
- let hit = cache.get(path);
251
- if (!hit) {
252
- hit = parse(path);
253
- if (hit) {
254
- cache.set(path, hit);
60
+ case 6 /* NodeTypes.Linked */: {
61
+ const linked = node;
62
+ const modifier = linked.m || linked.modifier;
63
+ return ctx.linked(formatMessagePart(ctx, linked.k || linked.key), modifier ? formatMessagePart(ctx, modifier) : undefined, ctx.type);
255
64
  }
256
- }
257
- // check hit
258
- if (!hit) {
259
- return null;
260
- }
261
- // resolve path value
262
- const len = hit.length;
263
- let last = obj;
264
- let i = 0;
265
- while (i < len) {
266
- const val = last[hit[i]];
267
- if (val === undefined) {
268
- return null;
65
+ case 7 /* NodeTypes.LinkedKey */: {
66
+ const linkedKey = node;
67
+ return (linkedKey.v || linkedKey.value);
269
68
  }
270
- if (shared.isFunction(last)) {
271
- return null;
69
+ case 8 /* NodeTypes.LinkedModifier */: {
70
+ const linkedModifier = node;
71
+ return (linkedModifier.v || linkedModifier.value);
272
72
  }
273
- last = val;
274
- i++;
73
+ default:
74
+ throw new Error(`unhandled node type on format message part: ${type}`);
275
75
  }
276
- return last;
277
76
  }
278
77
 
279
- const DEFAULT_MODIFIER = (str) => str;
280
- const DEFAULT_MESSAGE = (ctx) => ''; // eslint-disable-line
281
- const DEFAULT_MESSAGE_DATA_TYPE = 'text';
282
- const DEFAULT_NORMALIZE = (values) => values.length === 0 ? '' : shared.join(values);
283
- const DEFAULT_INTERPOLATE = shared.toDisplayString;
284
- function pluralDefault(choice, choicesLength) {
285
- choice = Math.abs(choice);
286
- if (choicesLength === 2) {
287
- // prettier-ignore
288
- return choice
289
- ? choice > 1
290
- ? 1
291
- : 0
292
- : 1;
293
- }
294
- return choice ? Math.min(choice, 2) : 0;
295
- }
296
- function getPluralIndex(options) {
297
- // prettier-ignore
298
- const index = shared.isNumber(options.pluralIndex)
299
- ? options.pluralIndex
300
- : -1;
301
- // prettier-ignore
302
- return options.named && (shared.isNumber(options.named.count) || shared.isNumber(options.named.n))
303
- ? shared.isNumber(options.named.count)
304
- ? options.named.count
305
- : shared.isNumber(options.named.n)
306
- ? options.named.n
307
- : index
308
- : index;
309
- }
310
- function normalizeNamed(pluralIndex, props) {
311
- if (!props.count) {
312
- props.count = pluralIndex;
313
- }
314
- if (!props.n) {
315
- props.n = pluralIndex;
316
- }
78
+ const defaultOnCacheKey = (message) => message;
79
+ let compileCache = Object.create(null);
80
+ function clearCompileCache() {
81
+ compileCache = Object.create(null);
317
82
  }
318
- function createMessageContext(options = {}) {
319
- const locale = options.locale;
320
- const pluralIndex = getPluralIndex(options);
321
- const pluralRule = shared.isObject(options.pluralRules) &&
322
- shared.isString(locale) &&
323
- shared.isFunction(options.pluralRules[locale])
324
- ? options.pluralRules[locale]
325
- : pluralDefault;
326
- const orgPluralRule = shared.isObject(options.pluralRules) &&
327
- shared.isString(locale) &&
328
- shared.isFunction(options.pluralRules[locale])
329
- ? pluralDefault
330
- : undefined;
331
- const plural = (messages) => {
332
- return messages[pluralRule(pluralIndex, messages.length, orgPluralRule)];
83
+ const isMessageAST = (val) => shared.isObject(val) &&
84
+ (val.t === 0 || val.type === 0) &&
85
+ ('b' in val || 'body' in val);
86
+ function baseCompile(message, options = {}) {
87
+ // error detecting on compile
88
+ let detectError = false;
89
+ const onError = options.onError || messageCompiler.defaultOnError;
90
+ options.onError = (err) => {
91
+ detectError = true;
92
+ onError(err);
333
93
  };
334
- const _list = options.list || [];
335
- const list = (index) => _list[index];
336
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
337
- const _named = options.named || {};
338
- shared.isNumber(options.pluralIndex) && normalizeNamed(pluralIndex, _named);
339
- const named = (key) => _named[key];
340
- function message(key, useLinked) {
341
- // prettier-ignore
342
- const msg = shared.isFunction(options.messages)
343
- ? options.messages(key, !!useLinked)
344
- : shared.isObject(options.messages)
345
- ? options.messages[key]
346
- : false;
347
- return !msg
348
- ? options.parent
349
- ? options.parent.message(key) // resolve from parent messages
350
- : DEFAULT_MESSAGE
351
- : msg;
352
- }
353
- const _modifier = (name) => options.modifiers
354
- ? options.modifiers[name]
355
- : DEFAULT_MODIFIER;
356
- const normalize = shared.isPlainObject(options.processor) && shared.isFunction(options.processor.normalize)
357
- ? options.processor.normalize
358
- : DEFAULT_NORMALIZE;
359
- const interpolate = shared.isPlainObject(options.processor) &&
360
- shared.isFunction(options.processor.interpolate)
361
- ? options.processor.interpolate
362
- : DEFAULT_INTERPOLATE;
363
- const type = shared.isPlainObject(options.processor) && shared.isString(options.processor.type)
364
- ? options.processor.type
365
- : DEFAULT_MESSAGE_DATA_TYPE;
366
- const linked = (key, ...args) => {
367
- const [arg1, arg2] = args;
368
- let type = 'text';
369
- let modifier = '';
370
- if (args.length === 1) {
371
- if (shared.isObject(arg1)) {
372
- modifier = arg1.modifier || modifier;
373
- type = arg1.type || type;
374
- }
375
- else if (shared.isString(arg1)) {
376
- modifier = arg1 || modifier;
94
+ // compile with mesasge-compiler
95
+ return { ...messageCompiler.baseCompile(message, options), detectError };
96
+ }
97
+ /* #__NO_SIDE_EFFECTS__ */
98
+ function compile(message, context) {
99
+ if (shared.isString(message)) {
100
+ // check HTML message
101
+ shared.isBoolean(context.warnHtmlMessage)
102
+ ? context.warnHtmlMessage
103
+ : true;
104
+ // check caches
105
+ const onCacheKey = context.onCacheKey || defaultOnCacheKey;
106
+ const cacheKey = onCacheKey(message);
107
+ const cached = compileCache[cacheKey];
108
+ if (cached) {
109
+ return cached;
110
+ }
111
+ // compile with JIT mode
112
+ const { ast, detectError } = baseCompile(message, {
113
+ ...context,
114
+ location: false,
115
+ jit: true
116
+ });
117
+ // compose message function from AST
118
+ const msg = format(ast);
119
+ // if occurred compile error, don't cache
120
+ return !detectError
121
+ ? (compileCache[cacheKey] = msg)
122
+ : msg;
123
+ }
124
+ else {
125
+ // AST case (passed from bundler)
126
+ const cacheKey = message.cacheKey;
127
+ if (cacheKey) {
128
+ const cached = compileCache[cacheKey];
129
+ if (cached) {
130
+ return cached;
377
131
  }
132
+ // compose message function from message (AST)
133
+ return (compileCache[cacheKey] =
134
+ format(message));
378
135
  }
379
- else if (args.length === 2) {
380
- if (shared.isString(arg1)) {
381
- modifier = arg1 || modifier;
382
- }
383
- if (shared.isString(arg2)) {
384
- type = arg2 || type;
385
- }
136
+ else {
137
+ return format(message);
386
138
  }
387
- const ret = message(key, true)(ctx);
388
- const msg =
389
- // The message in vnode resolved with linked are returned as an array by processor.nomalize
390
- type === 'vnode' && shared.isArray(ret) && modifier
391
- ? ret[0]
392
- : ret;
393
- return modifier ? _modifier(modifier)(msg, type) : msg;
394
- };
395
- const ctx = {
396
- ["list" /* HelperNameMap.LIST */]: list,
397
- ["named" /* HelperNameMap.NAMED */]: named,
398
- ["plural" /* HelperNameMap.PLURAL */]: plural,
399
- ["linked" /* HelperNameMap.LINKED */]: linked,
400
- ["message" /* HelperNameMap.MESSAGE */]: message,
401
- ["type" /* HelperNameMap.TYPE */]: type,
402
- ["interpolate" /* HelperNameMap.INTERPOLATE */]: interpolate,
403
- ["normalize" /* HelperNameMap.NORMALIZE */]: normalize,
404
- ["values" /* HelperNameMap.VALUES */]: shared.assign({}, _list, _named)
405
- };
406
- return ctx;
139
+ }
407
140
  }
408
141
 
409
142
  let devtools = null;
@@ -429,201 +162,469 @@ function createDevToolsHook(hook) {
429
162
  return (payloads) => devtools && devtools.emit(hook, payloads);
430
163
  }
431
164
 
432
- const CoreWarnCodes = {
433
- NOT_FOUND_KEY: 1,
434
- FALLBACK_TO_TRANSLATE: 2,
435
- CANNOT_FORMAT_NUMBER: 3,
436
- FALLBACK_TO_NUMBER_FORMAT: 4,
437
- CANNOT_FORMAT_DATE: 5,
438
- FALLBACK_TO_DATE_FORMAT: 6,
439
- EXPERIMENTAL_CUSTOM_MESSAGE_COMPILER: 7
165
+ const CoreErrorCodes = {
166
+ INVALID_ARGUMENT: messageCompiler.COMPILE_ERROR_CODES_EXTEND_POINT, // 17
167
+ INVALID_DATE_ARGUMENT: 18,
168
+ INVALID_ISO_DATE_ARGUMENT: 19,
169
+ NOT_SUPPORT_NON_STRING_MESSAGE: 20,
170
+ NOT_SUPPORT_LOCALE_PROMISE_VALUE: 21,
171
+ NOT_SUPPORT_LOCALE_ASYNC_FUNCTION: 22,
172
+ NOT_SUPPORT_LOCALE_TYPE: 23
173
+ };
174
+ const CORE_ERROR_CODES_EXTEND_POINT = 24;
175
+ function createCoreError(code) {
176
+ return messageCompiler.createCompileError(code, null, undefined);
177
+ }
178
+ /** @internal */
179
+ ({
180
+ [CoreErrorCodes.INVALID_ARGUMENT]: 'Invalid arguments',
181
+ [CoreErrorCodes.INVALID_DATE_ARGUMENT]: 'The date provided is an invalid Date object.' +
182
+ 'Make sure your Date represents a valid date.',
183
+ [CoreErrorCodes.INVALID_ISO_DATE_ARGUMENT]: 'The argument provided is not a valid ISO date string',
184
+ [CoreErrorCodes.NOT_SUPPORT_NON_STRING_MESSAGE]: 'Not support non-string message',
185
+ [CoreErrorCodes.NOT_SUPPORT_LOCALE_PROMISE_VALUE]: 'cannot support promise value',
186
+ [CoreErrorCodes.NOT_SUPPORT_LOCALE_ASYNC_FUNCTION]: 'cannot support async function',
187
+ [CoreErrorCodes.NOT_SUPPORT_LOCALE_TYPE]: 'cannot support locale type'
188
+ });
189
+
190
+ /** @internal */
191
+ function getLocale(context, options) {
192
+ return options.locale != null
193
+ ? resolveLocale(options.locale)
194
+ : resolveLocale(context.locale);
195
+ }
196
+ let _resolveLocale;
197
+ /** @internal */
198
+ function resolveLocale(locale) {
199
+ if (shared.isString(locale)) {
200
+ return locale;
201
+ }
202
+ else {
203
+ if (shared.isFunction(locale)) {
204
+ if (locale.resolvedOnce && _resolveLocale != null) {
205
+ return _resolveLocale;
206
+ }
207
+ else if (locale.constructor.name === 'Function') {
208
+ const resolve = locale();
209
+ if (shared.isPromise(resolve)) {
210
+ throw createCoreError(CoreErrorCodes.NOT_SUPPORT_LOCALE_PROMISE_VALUE);
211
+ }
212
+ return (_resolveLocale = resolve);
213
+ }
214
+ else {
215
+ throw createCoreError(CoreErrorCodes.NOT_SUPPORT_LOCALE_ASYNC_FUNCTION);
216
+ }
217
+ }
218
+ else {
219
+ throw createCoreError(CoreErrorCodes.NOT_SUPPORT_LOCALE_TYPE);
220
+ }
221
+ }
222
+ }
223
+ /**
224
+ * Fallback with simple implemenation
225
+ *
226
+ * @remarks
227
+ * A fallback locale function implemented with a simple fallback algorithm.
228
+ *
229
+ * Basically, it returns the value as specified in the `fallbackLocale` props, and is processed with the fallback inside intlify.
230
+ *
231
+ * @param ctx - A {@link CoreContext | context}
232
+ * @param fallback - A {@link FallbackLocale | fallback locale}
233
+ * @param start - A starting {@link Locale | locale}
234
+ *
235
+ * @returns Fallback locales
236
+ *
237
+ * @VueI18nGeneral
238
+ */
239
+ function fallbackWithSimple(ctx, fallback, start) {
240
+ // prettier-ignore
241
+ return [...new Set([
242
+ start,
243
+ ...(shared.isArray(fallback)
244
+ ? fallback
245
+ : shared.isObject(fallback)
246
+ ? Object.keys(fallback)
247
+ : shared.isString(fallback)
248
+ ? [fallback]
249
+ : [start])
250
+ ])];
251
+ }
252
+ /**
253
+ * Fallback with locale chain
254
+ *
255
+ * @remarks
256
+ * A fallback locale function implemented with a fallback chain algorithm. It's used in VueI18n as default.
257
+ *
258
+ * @param ctx - A {@link CoreContext | context}
259
+ * @param fallback - A {@link FallbackLocale | fallback locale}
260
+ * @param start - A starting {@link Locale | locale}
261
+ *
262
+ * @returns Fallback locales
263
+ *
264
+ * @VueI18nSee [Fallbacking](../guide/essentials/fallback)
265
+ *
266
+ * @VueI18nGeneral
267
+ */
268
+ function fallbackWithLocaleChain(ctx, fallback, start) {
269
+ const startLocale = shared.isString(start) ? start : DEFAULT_LOCALE;
270
+ const context = ctx;
271
+ if (!context.__localeChainCache) {
272
+ context.__localeChainCache = new Map();
273
+ }
274
+ let chain = context.__localeChainCache.get(startLocale);
275
+ if (!chain) {
276
+ chain = [];
277
+ // first block defined by start
278
+ let block = [start];
279
+ // while any intervening block found
280
+ while (shared.isArray(block)) {
281
+ block = appendBlockToChain(chain, block, fallback);
282
+ }
283
+ // prettier-ignore
284
+ // last block defined by default
285
+ const defaults = shared.isArray(fallback) || !shared.isPlainObject(fallback)
286
+ ? fallback
287
+ : fallback['default']
288
+ ? fallback['default']
289
+ : null;
290
+ // convert defaults to array
291
+ block = shared.isString(defaults) ? [defaults] : defaults;
292
+ if (shared.isArray(block)) {
293
+ appendBlockToChain(chain, block, false);
294
+ }
295
+ context.__localeChainCache.set(startLocale, chain);
296
+ }
297
+ return chain;
298
+ }
299
+ function appendBlockToChain(chain, block, blocks) {
300
+ let follow = true;
301
+ for (let i = 0; i < block.length && shared.isBoolean(follow); i++) {
302
+ const locale = block[i];
303
+ if (shared.isString(locale)) {
304
+ follow = appendLocaleToChain(chain, block[i], blocks);
305
+ }
306
+ }
307
+ return follow;
308
+ }
309
+ function appendLocaleToChain(chain, locale, blocks) {
310
+ let follow;
311
+ const tokens = locale.split('-');
312
+ do {
313
+ const target = tokens.join('-');
314
+ follow = appendItemToChain(chain, target, blocks);
315
+ tokens.splice(-1, 1);
316
+ } while (tokens.length && follow === true);
317
+ return follow;
318
+ }
319
+ function appendItemToChain(chain, target, blocks) {
320
+ let follow = false;
321
+ if (!chain.includes(target)) {
322
+ follow = true;
323
+ if (target) {
324
+ follow = target[target.length - 1] !== '!';
325
+ const locale = target.replace(/!/g, '');
326
+ chain.push(locale);
327
+ if ((shared.isArray(blocks) || shared.isPlainObject(blocks)) &&
328
+ blocks[locale] // eslint-disable-line @typescript-eslint/no-explicit-any
329
+ ) {
330
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
331
+ follow = blocks[locale];
332
+ }
333
+ }
334
+ }
335
+ return follow;
336
+ }
337
+
338
+ const pathStateMachine = [];
339
+ pathStateMachine[0 /* States.BEFORE_PATH */] = {
340
+ ["w" /* PathCharTypes.WORKSPACE */]: [0 /* States.BEFORE_PATH */],
341
+ ["i" /* PathCharTypes.IDENT */]: [3 /* States.IN_IDENT */, 0 /* Actions.APPEND */],
342
+ ["[" /* PathCharTypes.LEFT_BRACKET */]: [4 /* States.IN_SUB_PATH */],
343
+ ["o" /* PathCharTypes.END_OF_FAIL */]: [7 /* States.AFTER_PATH */]
344
+ };
345
+ pathStateMachine[1 /* States.IN_PATH */] = {
346
+ ["w" /* PathCharTypes.WORKSPACE */]: [1 /* States.IN_PATH */],
347
+ ["." /* PathCharTypes.DOT */]: [2 /* States.BEFORE_IDENT */],
348
+ ["[" /* PathCharTypes.LEFT_BRACKET */]: [4 /* States.IN_SUB_PATH */],
349
+ ["o" /* PathCharTypes.END_OF_FAIL */]: [7 /* States.AFTER_PATH */]
350
+ };
351
+ pathStateMachine[2 /* States.BEFORE_IDENT */] = {
352
+ ["w" /* PathCharTypes.WORKSPACE */]: [2 /* States.BEFORE_IDENT */],
353
+ ["i" /* PathCharTypes.IDENT */]: [3 /* States.IN_IDENT */, 0 /* Actions.APPEND */],
354
+ ["0" /* PathCharTypes.ZERO */]: [3 /* States.IN_IDENT */, 0 /* Actions.APPEND */]
355
+ };
356
+ pathStateMachine[3 /* States.IN_IDENT */] = {
357
+ ["i" /* PathCharTypes.IDENT */]: [3 /* States.IN_IDENT */, 0 /* Actions.APPEND */],
358
+ ["0" /* PathCharTypes.ZERO */]: [3 /* States.IN_IDENT */, 0 /* Actions.APPEND */],
359
+ ["w" /* PathCharTypes.WORKSPACE */]: [1 /* States.IN_PATH */, 1 /* Actions.PUSH */],
360
+ ["." /* PathCharTypes.DOT */]: [2 /* States.BEFORE_IDENT */, 1 /* Actions.PUSH */],
361
+ ["[" /* PathCharTypes.LEFT_BRACKET */]: [4 /* States.IN_SUB_PATH */, 1 /* Actions.PUSH */],
362
+ ["o" /* PathCharTypes.END_OF_FAIL */]: [7 /* States.AFTER_PATH */, 1 /* Actions.PUSH */]
363
+ };
364
+ pathStateMachine[4 /* States.IN_SUB_PATH */] = {
365
+ ["'" /* PathCharTypes.SINGLE_QUOTE */]: [5 /* States.IN_SINGLE_QUOTE */, 0 /* Actions.APPEND */],
366
+ ["\"" /* PathCharTypes.DOUBLE_QUOTE */]: [6 /* States.IN_DOUBLE_QUOTE */, 0 /* Actions.APPEND */],
367
+ ["[" /* PathCharTypes.LEFT_BRACKET */]: [
368
+ 4 /* States.IN_SUB_PATH */,
369
+ 2 /* Actions.INC_SUB_PATH_DEPTH */
370
+ ],
371
+ ["]" /* PathCharTypes.RIGHT_BRACKET */]: [1 /* States.IN_PATH */, 3 /* Actions.PUSH_SUB_PATH */],
372
+ ["o" /* PathCharTypes.END_OF_FAIL */]: 8 /* States.ERROR */,
373
+ ["l" /* PathCharTypes.ELSE */]: [4 /* States.IN_SUB_PATH */, 0 /* Actions.APPEND */]
440
374
  };
441
- const CORE_WARN_CODES_EXTEND_POINT = 8;
442
- /** @internal */
443
- const warnMessages = {
444
- [CoreWarnCodes.NOT_FOUND_KEY]: `Not found '{key}' key in '{locale}' locale messages.`,
445
- [CoreWarnCodes.FALLBACK_TO_TRANSLATE]: `Fall back to translate '{key}' key with '{target}' locale.`,
446
- [CoreWarnCodes.CANNOT_FORMAT_NUMBER]: `Cannot format a number value due to not supported Intl.NumberFormat.`,
447
- [CoreWarnCodes.FALLBACK_TO_NUMBER_FORMAT]: `Fall back to number format '{key}' key with '{target}' locale.`,
448
- [CoreWarnCodes.CANNOT_FORMAT_DATE]: `Cannot format a date value due to not supported Intl.DateTimeFormat.`,
449
- [CoreWarnCodes.FALLBACK_TO_DATE_FORMAT]: `Fall back to datetime format '{key}' key with '{target}' locale.`,
450
- [CoreWarnCodes.EXPERIMENTAL_CUSTOM_MESSAGE_COMPILER]: `This project is using Custom Message Compiler, which is an experimental feature. It may receive breaking changes or be removed in the future.`
375
+ pathStateMachine[5 /* States.IN_SINGLE_QUOTE */] = {
376
+ ["'" /* PathCharTypes.SINGLE_QUOTE */]: [4 /* States.IN_SUB_PATH */, 0 /* Actions.APPEND */],
377
+ ["o" /* PathCharTypes.END_OF_FAIL */]: 8 /* States.ERROR */,
378
+ ["l" /* PathCharTypes.ELSE */]: [5 /* States.IN_SINGLE_QUOTE */, 0 /* Actions.APPEND */]
451
379
  };
452
- function getWarnMessage(code, ...args) {
453
- return shared.format(warnMessages[code], ...args);
454
- }
455
-
456
- const CoreErrorCodes = {
457
- INVALID_ARGUMENT: messageCompiler.COMPILE_ERROR_CODES_EXTEND_POINT, // 17
458
- INVALID_DATE_ARGUMENT: 18,
459
- INVALID_ISO_DATE_ARGUMENT: 19,
460
- NOT_SUPPORT_NON_STRING_MESSAGE: 20,
461
- NOT_SUPPORT_LOCALE_PROMISE_VALUE: 21,
462
- NOT_SUPPORT_LOCALE_ASYNC_FUNCTION: 22,
463
- NOT_SUPPORT_LOCALE_TYPE: 23
380
+ pathStateMachine[6 /* States.IN_DOUBLE_QUOTE */] = {
381
+ ["\"" /* PathCharTypes.DOUBLE_QUOTE */]: [4 /* States.IN_SUB_PATH */, 0 /* Actions.APPEND */],
382
+ ["o" /* PathCharTypes.END_OF_FAIL */]: 8 /* States.ERROR */,
383
+ ["l" /* PathCharTypes.ELSE */]: [6 /* States.IN_DOUBLE_QUOTE */, 0 /* Actions.APPEND */]
464
384
  };
465
- const CORE_ERROR_CODES_EXTEND_POINT = 24;
466
- function createCoreError(code) {
467
- return messageCompiler.createCompileError(code, null, undefined);
385
+ /**
386
+ * Check if an expression is a literal value.
387
+ */
388
+ const literalValueRE = /^\s?(?:true|false|-?[\d.]+|'[^']*'|"[^"]*")\s?$/;
389
+ function isLiteral(exp) {
390
+ return literalValueRE.test(exp);
468
391
  }
469
- /** @internal */
470
- ({
471
- [CoreErrorCodes.INVALID_ARGUMENT]: 'Invalid arguments',
472
- [CoreErrorCodes.INVALID_DATE_ARGUMENT]: 'The date provided is an invalid Date object.' +
473
- 'Make sure your Date represents a valid date.',
474
- [CoreErrorCodes.INVALID_ISO_DATE_ARGUMENT]: 'The argument provided is not a valid ISO date string',
475
- [CoreErrorCodes.NOT_SUPPORT_NON_STRING_MESSAGE]: 'Not support non-string message',
476
- [CoreErrorCodes.NOT_SUPPORT_LOCALE_PROMISE_VALUE]: 'cannot support promise value',
477
- [CoreErrorCodes.NOT_SUPPORT_LOCALE_ASYNC_FUNCTION]: 'cannot support async function',
478
- [CoreErrorCodes.NOT_SUPPORT_LOCALE_TYPE]: 'cannot support locale type'
479
- });
480
-
481
- /** @internal */
482
- function getLocale(context, options) {
483
- return options.locale != null
484
- ? resolveLocale(options.locale)
485
- : resolveLocale(context.locale);
392
+ /**
393
+ * Strip quotes from a string
394
+ */
395
+ function stripQuotes(str) {
396
+ const a = str.charCodeAt(0);
397
+ const b = str.charCodeAt(str.length - 1);
398
+ return a === b && (a === 0x22 || a === 0x27) ? str.slice(1, -1) : str;
486
399
  }
487
- let _resolveLocale;
488
- /** @internal */
489
- function resolveLocale(locale) {
490
- if (shared.isString(locale)) {
491
- return locale;
400
+ /**
401
+ * Determine the type of a character in a keypath.
402
+ */
403
+ function getPathCharType(ch) {
404
+ if (ch === undefined || ch === null) {
405
+ return "o" /* PathCharTypes.END_OF_FAIL */;
492
406
  }
493
- else {
494
- if (shared.isFunction(locale)) {
495
- if (locale.resolvedOnce && _resolveLocale != null) {
496
- return _resolveLocale;
407
+ const code = ch.charCodeAt(0);
408
+ switch (code) {
409
+ case 0x5b: // [
410
+ case 0x5d: // ]
411
+ case 0x2e: // .
412
+ case 0x22: // "
413
+ case 0x27: // '
414
+ return ch;
415
+ case 0x5f: // _
416
+ case 0x24: // $
417
+ case 0x2d: // -
418
+ return "i" /* PathCharTypes.IDENT */;
419
+ case 0x09: // Tab (HT)
420
+ case 0x0a: // Newline (LF)
421
+ case 0x0d: // Return (CR)
422
+ case 0xa0: // No-break space (NBSP)
423
+ case 0xfeff: // Byte Order Mark (BOM)
424
+ case 0x2028: // Line Separator (LS)
425
+ case 0x2029: // Paragraph Separator (PS)
426
+ return "w" /* PathCharTypes.WORKSPACE */;
427
+ }
428
+ return "i" /* PathCharTypes.IDENT */;
429
+ }
430
+ /**
431
+ * Format a subPath, return its plain form if it is
432
+ * a literal string or number. Otherwise prepend the
433
+ * dynamic indicator (*).
434
+ */
435
+ function formatSubPath(path) {
436
+ const trimmed = path.trim();
437
+ // invalid leading 0
438
+ if (path.charAt(0) === '0' && isNaN(parseInt(path))) {
439
+ return false;
440
+ }
441
+ return isLiteral(trimmed)
442
+ ? stripQuotes(trimmed)
443
+ : "*" /* PathCharTypes.ASTARISK */ + trimmed;
444
+ }
445
+ /**
446
+ * Parse a string path into an array of segments
447
+ */
448
+ function parse(path) {
449
+ const keys = [];
450
+ let index = -1;
451
+ let mode = 0 /* States.BEFORE_PATH */;
452
+ let subPathDepth = 0;
453
+ let c;
454
+ let key; // eslint-disable-line
455
+ let newChar;
456
+ let type;
457
+ let transition;
458
+ let action;
459
+ let typeMap;
460
+ const actions = [];
461
+ actions[0 /* Actions.APPEND */] = () => {
462
+ if (key === undefined) {
463
+ key = newChar;
464
+ }
465
+ else {
466
+ key += newChar;
467
+ }
468
+ };
469
+ actions[1 /* Actions.PUSH */] = () => {
470
+ if (key !== undefined) {
471
+ keys.push(key);
472
+ key = undefined;
473
+ }
474
+ };
475
+ actions[2 /* Actions.INC_SUB_PATH_DEPTH */] = () => {
476
+ actions[0 /* Actions.APPEND */]();
477
+ subPathDepth++;
478
+ };
479
+ actions[3 /* Actions.PUSH_SUB_PATH */] = () => {
480
+ if (subPathDepth > 0) {
481
+ subPathDepth--;
482
+ mode = 4 /* States.IN_SUB_PATH */;
483
+ actions[0 /* Actions.APPEND */]();
484
+ }
485
+ else {
486
+ subPathDepth = 0;
487
+ if (key === undefined) {
488
+ return false;
497
489
  }
498
- else if (locale.constructor.name === 'Function') {
499
- const resolve = locale();
500
- if (shared.isPromise(resolve)) {
501
- throw createCoreError(CoreErrorCodes.NOT_SUPPORT_LOCALE_PROMISE_VALUE);
502
- }
503
- return (_resolveLocale = resolve);
490
+ key = formatSubPath(key);
491
+ if (key === false) {
492
+ return false;
504
493
  }
505
494
  else {
506
- throw createCoreError(CoreErrorCodes.NOT_SUPPORT_LOCALE_ASYNC_FUNCTION);
495
+ actions[1 /* Actions.PUSH */]();
507
496
  }
508
497
  }
509
- else {
510
- throw createCoreError(CoreErrorCodes.NOT_SUPPORT_LOCALE_TYPE);
498
+ };
499
+ function maybeUnescapeQuote() {
500
+ const nextChar = path[index + 1];
501
+ if ((mode === 5 /* States.IN_SINGLE_QUOTE */ &&
502
+ nextChar === "'" /* PathCharTypes.SINGLE_QUOTE */) ||
503
+ (mode === 6 /* States.IN_DOUBLE_QUOTE */ &&
504
+ nextChar === "\"" /* PathCharTypes.DOUBLE_QUOTE */)) {
505
+ index++;
506
+ newChar = '\\' + nextChar;
507
+ actions[0 /* Actions.APPEND */]();
508
+ return true;
509
+ }
510
+ }
511
+ while (mode !== null) {
512
+ index++;
513
+ c = path[index];
514
+ if (c === '\\' && maybeUnescapeQuote()) {
515
+ continue;
516
+ }
517
+ type = getPathCharType(c);
518
+ typeMap = pathStateMachine[mode];
519
+ transition = typeMap[type] || typeMap["l" /* PathCharTypes.ELSE */] || 8 /* States.ERROR */;
520
+ // check parse error
521
+ if (transition === 8 /* States.ERROR */) {
522
+ return;
523
+ }
524
+ mode = transition[0];
525
+ if (transition[1] !== undefined) {
526
+ action = actions[transition[1]];
527
+ if (action) {
528
+ newChar = c;
529
+ if (action() === false) {
530
+ return;
531
+ }
532
+ }
533
+ }
534
+ // check parse finish
535
+ if (mode === 7 /* States.AFTER_PATH */) {
536
+ return keys;
511
537
  }
512
538
  }
513
539
  }
540
+ // path token cache
541
+ const cache = new Map();
514
542
  /**
515
- * Fallback with simple implemenation
543
+ * key-value message resolver
516
544
  *
517
545
  * @remarks
518
- * A fallback locale function implemented with a simple fallback algorithm.
519
- *
520
- * Basically, it returns the value as specified in the `fallbackLocale` props, and is processed with the fallback inside intlify.
546
+ * Resolves messages with the key-value structure. Note that messages with a hierarchical structure such as objects cannot be resolved
521
547
  *
522
- * @param ctx - A {@link CoreContext | context}
523
- * @param fallback - A {@link FallbackLocale | fallback locale}
524
- * @param start - A starting {@link Locale | locale}
548
+ * @param obj - A target object to be resolved with path
549
+ * @param path - A {@link Path | path} to resolve the value of message
525
550
  *
526
- * @returns Fallback locales
551
+ * @returns A resolved {@link PathValue | path value}
527
552
  *
528
553
  * @VueI18nGeneral
529
554
  */
530
- function fallbackWithSimple(ctx, fallback, start) {
531
- // prettier-ignore
532
- return [...new Set([
533
- start,
534
- ...(shared.isArray(fallback)
535
- ? fallback
536
- : shared.isObject(fallback)
537
- ? Object.keys(fallback)
538
- : shared.isString(fallback)
539
- ? [fallback]
540
- : [start])
541
- ])];
555
+ function resolveWithKeyValue(obj, path) {
556
+ return shared.isObject(obj) ? obj[path] : null;
542
557
  }
543
558
  /**
544
- * Fallback with locale chain
545
- *
546
- * @remarks
547
- * A fallback locale function implemented with a fallback chain algorithm. It's used in VueI18n as default.
559
+ * message resolver
548
560
  *
549
- * @param ctx - A {@link CoreContext | context}
550
- * @param fallback - A {@link FallbackLocale | fallback locale}
551
- * @param start - A starting {@link Locale | locale}
561
+ * @remarks
562
+ * Resolves messages. messages with a hierarchical structure such as objects can be resolved. This resolver is used in VueI18n as default.
552
563
  *
553
- * @returns Fallback locales
564
+ * @param obj - A target object to be resolved with path
565
+ * @param path - A {@link Path | path} to resolve the value of message
554
566
  *
555
- * @VueI18nSee [Fallbacking](../guide/essentials/fallback)
567
+ * @returns A resolved {@link PathValue | path value}
556
568
  *
557
569
  * @VueI18nGeneral
558
570
  */
559
- function fallbackWithLocaleChain(ctx, fallback, start) {
560
- const startLocale = shared.isString(start) ? start : DEFAULT_LOCALE;
561
- const context = ctx;
562
- if (!context.__localeChainCache) {
563
- context.__localeChainCache = new Map();
571
+ function resolveValue(obj, path) {
572
+ // check object
573
+ if (!shared.isObject(obj)) {
574
+ return null;
564
575
  }
565
- let chain = context.__localeChainCache.get(startLocale);
566
- if (!chain) {
567
- chain = [];
568
- // first block defined by start
569
- let block = [start];
570
- // while any intervening block found
571
- while (shared.isArray(block)) {
572
- block = appendBlockToChain(chain, block, fallback);
573
- }
574
- // prettier-ignore
575
- // last block defined by default
576
- const defaults = shared.isArray(fallback) || !shared.isPlainObject(fallback)
577
- ? fallback
578
- : fallback['default']
579
- ? fallback['default']
580
- : null;
581
- // convert defaults to array
582
- block = shared.isString(defaults) ? [defaults] : defaults;
583
- if (shared.isArray(block)) {
584
- appendBlockToChain(chain, block, false);
576
+ // parse path
577
+ let hit = cache.get(path);
578
+ if (!hit) {
579
+ hit = parse(path);
580
+ if (hit) {
581
+ cache.set(path, hit);
585
582
  }
586
- context.__localeChainCache.set(startLocale, chain);
587
583
  }
588
- return chain;
589
- }
590
- function appendBlockToChain(chain, block, blocks) {
591
- let follow = true;
592
- for (let i = 0; i < block.length && shared.isBoolean(follow); i++) {
593
- const locale = block[i];
594
- if (shared.isString(locale)) {
595
- follow = appendLocaleToChain(chain, block[i], blocks);
596
- }
584
+ // check hit
585
+ if (!hit) {
586
+ return null;
597
587
  }
598
- return follow;
599
- }
600
- function appendLocaleToChain(chain, locale, blocks) {
601
- let follow;
602
- const tokens = locale.split('-');
603
- do {
604
- const target = tokens.join('-');
605
- follow = appendItemToChain(chain, target, blocks);
606
- tokens.splice(-1, 1);
607
- } while (tokens.length && follow === true);
608
- return follow;
609
- }
610
- function appendItemToChain(chain, target, blocks) {
611
- let follow = false;
612
- if (!chain.includes(target)) {
613
- follow = true;
614
- if (target) {
615
- follow = target[target.length - 1] !== '!';
616
- const locale = target.replace(/!/g, '');
617
- chain.push(locale);
618
- if ((shared.isArray(blocks) || shared.isPlainObject(blocks)) &&
619
- blocks[locale] // eslint-disable-line @typescript-eslint/no-explicit-any
620
- ) {
621
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
622
- follow = blocks[locale];
623
- }
588
+ // resolve path value
589
+ const len = hit.length;
590
+ let last = obj;
591
+ let i = 0;
592
+ while (i < len) {
593
+ const val = last[hit[i]];
594
+ if (val === undefined) {
595
+ return null;
624
596
  }
597
+ if (shared.isFunction(last)) {
598
+ return null;
599
+ }
600
+ last = val;
601
+ i++;
625
602
  }
626
- return follow;
603
+ return last;
604
+ }
605
+
606
+ const CoreWarnCodes = {
607
+ NOT_FOUND_KEY: 1,
608
+ FALLBACK_TO_TRANSLATE: 2,
609
+ CANNOT_FORMAT_NUMBER: 3,
610
+ FALLBACK_TO_NUMBER_FORMAT: 4,
611
+ CANNOT_FORMAT_DATE: 5,
612
+ FALLBACK_TO_DATE_FORMAT: 6,
613
+ EXPERIMENTAL_CUSTOM_MESSAGE_COMPILER: 7
614
+ };
615
+ const CORE_WARN_CODES_EXTEND_POINT = 8;
616
+ /** @internal */
617
+ const warnMessages = {
618
+ [CoreWarnCodes.NOT_FOUND_KEY]: `Not found '{key}' key in '{locale}' locale messages.`,
619
+ [CoreWarnCodes.FALLBACK_TO_TRANSLATE]: `Fall back to translate '{key}' key with '{target}' locale.`,
620
+ [CoreWarnCodes.CANNOT_FORMAT_NUMBER]: `Cannot format a number value due to not supported Intl.NumberFormat.`,
621
+ [CoreWarnCodes.FALLBACK_TO_NUMBER_FORMAT]: `Fall back to number format '{key}' key with '{target}' locale.`,
622
+ [CoreWarnCodes.CANNOT_FORMAT_DATE]: `Cannot format a date value due to not supported Intl.DateTimeFormat.`,
623
+ [CoreWarnCodes.FALLBACK_TO_DATE_FORMAT]: `Fall back to datetime format '{key}' key with '{target}' locale.`,
624
+ [CoreWarnCodes.EXPERIMENTAL_CUSTOM_MESSAGE_COMPILER]: `This project is using Custom Message Compiler, which is an experimental feature. It may receive breaking changes or be removed in the future.`
625
+ };
626
+ function getWarnMessage(code, ...args) {
627
+ return shared.format(warnMessages[code], ...args);
627
628
  }
628
629
 
629
630
  /* eslint-disable @typescript-eslint/no-explicit-any */
@@ -631,7 +632,7 @@ function appendItemToChain(chain, target, blocks) {
631
632
  * Intlify core-base version
632
633
  * @internal
633
634
  */
634
- const VERSION = '10.0.0-beta.6';
635
+ const VERSION = '10.0.0';
635
636
  const NOT_REOSLVED = -1;
636
637
  const DEFAULT_LOCALE = 'en-US';
637
638
  const MISSING_RESOLVE_VALUE = '';
@@ -830,671 +831,670 @@ function updateFallbackLocale(ctx, locale, fallback) {
830
831
  context.__localeChainCache = new Map();
831
832
  ctx.localeFallbacker(ctx, fallback, locale);
832
833
  }
833
- /** @internal */
834
- function isAlmostSameLocale(locale, compareLocale) {
835
- if (locale === compareLocale)
836
- return false;
837
- return locale.split('-')[0] === compareLocale.split('-')[0];
838
- }
839
- /** @internal */
840
- function isImplicitFallback(targetLocale, locales) {
841
- const index = locales.indexOf(targetLocale);
842
- if (index === -1) {
843
- return false;
844
- }
845
- for (let i = index + 1; i < locales.length; i++) {
846
- if (isAlmostSameLocale(targetLocale, locales[i])) {
847
- return true;
848
- }
849
- }
850
- return false;
851
- }
852
- /* eslint-enable @typescript-eslint/no-explicit-any */
853
-
854
- function format(ast) {
855
- const msg = (ctx) => formatParts(ctx, ast);
856
- return msg;
857
- }
858
- function formatParts(ctx, ast) {
859
- const body = ast.b || ast.body;
860
- if ((body.t || body.type) === 1 /* NodeTypes.Plural */) {
861
- const plural = body;
862
- const cases = plural.c || plural.cases;
863
- return ctx.plural(cases.reduce((messages, c) => [
864
- ...messages,
865
- formatMessageParts(ctx, c)
866
- ], []));
867
- }
868
- else {
869
- return formatMessageParts(ctx, body);
870
- }
871
- }
872
- function formatMessageParts(ctx, node) {
873
- const _static = node.s || node.static;
874
- if (_static) {
875
- return ctx.type === 'text'
876
- ? _static
877
- : ctx.normalize([_static]);
878
- }
879
- else {
880
- const messages = (node.i || node.items).reduce((acm, c) => [...acm, formatMessagePart(ctx, c)], []);
881
- return ctx.normalize(messages);
882
- }
883
- }
884
- function formatMessagePart(ctx, node) {
885
- const type = node.t || node.type;
886
- switch (type) {
887
- case 3 /* NodeTypes.Text */: {
888
- const text = node;
889
- return (text.v || text.value);
890
- }
891
- case 9 /* NodeTypes.Literal */: {
892
- const literal = node;
893
- return (literal.v || literal.value);
894
- }
895
- case 4 /* NodeTypes.Named */: {
896
- const named = node;
897
- return ctx.interpolate(ctx.named(named.k || named.key));
898
- }
899
- case 5 /* NodeTypes.List */: {
900
- const list = node;
901
- return ctx.interpolate(ctx.list(list.i != null ? list.i : list.index));
902
- }
903
- case 6 /* NodeTypes.Linked */: {
904
- const linked = node;
905
- const modifier = linked.m || linked.modifier;
906
- return ctx.linked(formatMessagePart(ctx, linked.k || linked.key), modifier ? formatMessagePart(ctx, modifier) : undefined, ctx.type);
907
- }
908
- case 7 /* NodeTypes.LinkedKey */: {
909
- const linkedKey = node;
910
- return (linkedKey.v || linkedKey.value);
911
- }
912
- case 8 /* NodeTypes.LinkedModifier */: {
913
- const linkedModifier = node;
914
- return (linkedModifier.v || linkedModifier.value);
915
- }
916
- default:
917
- throw new Error(`unhandled node type on format message part: ${type}`);
918
- }
919
- }
920
-
921
- const defaultOnCacheKey = (message) => message;
922
- let compileCache = Object.create(null);
923
- function clearCompileCache() {
924
- compileCache = Object.create(null);
925
- }
926
- const isMessageAST = (val) => shared.isObject(val) &&
927
- (val.t === 0 || val.type === 0) &&
928
- ('b' in val || 'body' in val);
929
- function baseCompile(message, options = {}) {
930
- // error detecting on compile
931
- let detectError = false;
932
- const onError = options.onError || messageCompiler.defaultOnError;
933
- options.onError = (err) => {
934
- detectError = true;
935
- onError(err);
936
- };
937
- // compile with mesasge-compiler
938
- return { ...messageCompiler.baseCompile(message, options), detectError };
939
- }
940
- /* #__NO_SIDE_EFFECTS__ */
941
- function compile(message, context) {
942
- if (shared.isString(message)) {
943
- // check HTML message
944
- shared.isBoolean(context.warnHtmlMessage)
945
- ? context.warnHtmlMessage
946
- : true;
947
- // check caches
948
- const onCacheKey = context.onCacheKey || defaultOnCacheKey;
949
- const cacheKey = onCacheKey(message);
950
- const cached = compileCache[cacheKey];
951
- if (cached) {
952
- return cached;
953
- }
954
- // compile with JIT mode
955
- const { ast, detectError } = baseCompile(message, {
956
- ...context,
957
- location: false,
958
- jit: true
959
- });
960
- // compose message function from AST
961
- const msg = format(ast);
962
- // if occurred compile error, don't cache
963
- return !detectError
964
- ? (compileCache[cacheKey] = msg)
965
- : msg;
834
+ /** @internal */
835
+ function isAlmostSameLocale(locale, compareLocale) {
836
+ if (locale === compareLocale)
837
+ return false;
838
+ return locale.split('-')[0] === compareLocale.split('-')[0];
839
+ }
840
+ /** @internal */
841
+ function isImplicitFallback(targetLocale, locales) {
842
+ const index = locales.indexOf(targetLocale);
843
+ if (index === -1) {
844
+ return false;
966
845
  }
967
- else {
968
- // AST case (passed from bundler)
969
- const cacheKey = message.cacheKey;
970
- if (cacheKey) {
971
- const cached = compileCache[cacheKey];
972
- if (cached) {
973
- return cached;
974
- }
975
- // compose message function from message (AST)
976
- return (compileCache[cacheKey] =
977
- format(message));
978
- }
979
- else {
980
- return format(message);
846
+ for (let i = index + 1; i < locales.length; i++) {
847
+ if (isAlmostSameLocale(targetLocale, locales[i])) {
848
+ return true;
981
849
  }
982
850
  }
851
+ return false;
983
852
  }
853
+ /* eslint-enable @typescript-eslint/no-explicit-any */
984
854
 
985
- const NOOP_MESSAGE_FUNCTION = () => '';
986
- const isMessageFunction = (val) => shared.isFunction(val);
987
- // implementation of `translate` function
988
- function translate(context, ...args) {
989
- const { fallbackFormat, postTranslation, unresolving, messageCompiler, fallbackLocale, messages } = context;
990
- const [key, options] = parseTranslateArgs(...args);
855
+ // implementation of `datetime` function
856
+ function datetime(context, ...args) {
857
+ const { datetimeFormats, unresolving, fallbackLocale, onWarn, localeFallbacker } = context;
858
+ const { __datetimeFormatters } = context;
859
+ const [key, value, options, overrides] = parseDateTimeArgs(...args);
991
860
  const missingWarn = shared.isBoolean(options.missingWarn)
992
861
  ? options.missingWarn
993
862
  : context.missingWarn;
994
- const fallbackWarn = shared.isBoolean(options.fallbackWarn)
863
+ shared.isBoolean(options.fallbackWarn)
995
864
  ? options.fallbackWarn
996
865
  : context.fallbackWarn;
997
- const escapeParameter = shared.isBoolean(options.escapeParameter)
998
- ? options.escapeParameter
999
- : context.escapeParameter;
1000
- const resolvedMessage = !!options.resolvedMessage;
1001
- // prettier-ignore
1002
- const defaultMsgOrKey = shared.isString(options.default) || shared.isBoolean(options.default) // default by function option
1003
- ? !shared.isBoolean(options.default)
1004
- ? options.default
1005
- : (!messageCompiler ? () => key : key)
1006
- : fallbackFormat // default by `fallbackFormat` option
1007
- ? (!messageCompiler ? () => key : key)
1008
- : null;
1009
- const enableDefaultMsg = fallbackFormat ||
1010
- (defaultMsgOrKey != null &&
1011
- (shared.isString(defaultMsgOrKey) || shared.isFunction(defaultMsgOrKey)));
866
+ const part = !!options.part;
1012
867
  const locale = getLocale(context, options);
1013
- // escape params
1014
- escapeParameter && escapeParams(options);
1015
- // resolve message format
1016
- // eslint-disable-next-line prefer-const
1017
- let [formatScope, targetLocale, message] = !resolvedMessage
1018
- ? resolveMessageFormat(context, key, locale, fallbackLocale, fallbackWarn, missingWarn)
1019
- : [
1020
- key,
1021
- locale,
1022
- messages[locale] || {}
1023
- ];
1024
- // NOTE:
1025
- // Fix to work around `ssrTransfrom` bug in Vite.
1026
- // https://github.com/vitejs/vite/issues/4306
1027
- // To get around this, use temporary variables.
1028
- // https://github.com/nuxt/framework/issues/1461#issuecomment-954606243
1029
- let format = formatScope;
1030
- // if you use default message, set it as message format!
1031
- let cacheBaseKey = key;
1032
- if (!resolvedMessage &&
1033
- !(shared.isString(format) ||
1034
- isMessageAST(format) ||
1035
- isMessageFunction(format))) {
1036
- if (enableDefaultMsg) {
1037
- format = defaultMsgOrKey;
1038
- cacheBaseKey = format;
1039
- }
868
+ const locales = localeFallbacker(context, // eslint-disable-line @typescript-eslint/no-explicit-any
869
+ fallbackLocale, locale);
870
+ if (!shared.isString(key) || key === '') {
871
+ return new Intl.DateTimeFormat(locale, overrides).format(value);
1040
872
  }
1041
- // checking message format and target locale
1042
- if (!resolvedMessage &&
1043
- (!(shared.isString(format) ||
1044
- isMessageAST(format) ||
1045
- isMessageFunction(format)) ||
1046
- !shared.isString(targetLocale))) {
873
+ // resolve format
874
+ let datetimeFormat = {};
875
+ let targetLocale;
876
+ let format = null;
877
+ const type = 'datetime format';
878
+ for (let i = 0; i < locales.length; i++) {
879
+ targetLocale = locales[i];
880
+ datetimeFormat =
881
+ datetimeFormats[targetLocale] || {};
882
+ format = datetimeFormat[key];
883
+ if (shared.isPlainObject(format))
884
+ break;
885
+ handleMissing(context, key, targetLocale, missingWarn, type); // eslint-disable-line @typescript-eslint/no-explicit-any
886
+ }
887
+ // checking format and target locale
888
+ if (!shared.isPlainObject(format) || !shared.isString(targetLocale)) {
1047
889
  return unresolving ? NOT_REOSLVED : key;
1048
890
  }
1049
- // setup compile error detecting
1050
- let occurred = false;
1051
- const onError = () => {
1052
- occurred = true;
1053
- };
1054
- // compile message format
1055
- const msg = !isMessageFunction(format)
1056
- ? compileMessageFormat(context, key, targetLocale, format, cacheBaseKey, onError)
1057
- : format;
1058
- // if occurred compile error, return the message format
1059
- if (occurred) {
1060
- return format;
891
+ let id = `${targetLocale}__${key}`;
892
+ if (!shared.isEmptyObject(overrides)) {
893
+ id = `${id}__${JSON.stringify(overrides)}`;
1061
894
  }
1062
- // evaluate message with context
1063
- const ctxOptions = getMessageContextOptions(context, targetLocale, message, options);
1064
- const msgContext = createMessageContext(ctxOptions);
1065
- const messaged = evaluateMessage(context, msg, msgContext);
1066
- // if use post translation option, proceed it with handler
1067
- const ret = postTranslation
1068
- ? postTranslation(messaged, key)
1069
- : messaged;
1070
- return ret;
895
+ let formatter = __datetimeFormatters.get(id);
896
+ if (!formatter) {
897
+ formatter = new Intl.DateTimeFormat(targetLocale, shared.assign({}, format, overrides));
898
+ __datetimeFormatters.set(id, formatter);
899
+ }
900
+ return !part ? formatter.format(value) : formatter.formatToParts(value);
1071
901
  }
1072
- function escapeParams(options) {
1073
- if (shared.isArray(options.list)) {
1074
- options.list = options.list.map(item => shared.isString(item) ? shared.escapeHtml(item) : item);
902
+ /** @internal */
903
+ const DATETIME_FORMAT_OPTIONS_KEYS = [
904
+ 'localeMatcher',
905
+ 'weekday',
906
+ 'era',
907
+ 'year',
908
+ 'month',
909
+ 'day',
910
+ 'hour',
911
+ 'minute',
912
+ 'second',
913
+ 'timeZoneName',
914
+ 'formatMatcher',
915
+ 'hour12',
916
+ 'timeZone',
917
+ 'dateStyle',
918
+ 'timeStyle',
919
+ 'calendar',
920
+ 'dayPeriod',
921
+ 'numberingSystem',
922
+ 'hourCycle',
923
+ 'fractionalSecondDigits'
924
+ ];
925
+ /** @internal */
926
+ function parseDateTimeArgs(...args) {
927
+ const [arg1, arg2, arg3, arg4] = args;
928
+ const options = {};
929
+ let overrides = {};
930
+ let value;
931
+ if (shared.isString(arg1)) {
932
+ // Only allow ISO strings - other date formats are often supported,
933
+ // but may cause different results in different browsers.
934
+ const matches = arg1.match(/(\d{4}-\d{2}-\d{2})(T|\s)?(.*)/);
935
+ if (!matches) {
936
+ throw createCoreError(CoreErrorCodes.INVALID_ISO_DATE_ARGUMENT);
937
+ }
938
+ // Some browsers can not parse the iso datetime separated by space,
939
+ // this is a compromise solution by replace the 'T'/' ' with 'T'
940
+ const dateTime = matches[3]
941
+ ? matches[3].trim().startsWith('T')
942
+ ? `${matches[1].trim()}${matches[3].trim()}`
943
+ : `${matches[1].trim()}T${matches[3].trim()}`
944
+ : matches[1].trim();
945
+ value = new Date(dateTime);
946
+ try {
947
+ // This will fail if the date is not valid
948
+ value.toISOString();
949
+ }
950
+ catch {
951
+ throw createCoreError(CoreErrorCodes.INVALID_ISO_DATE_ARGUMENT);
952
+ }
1075
953
  }
1076
- else if (shared.isObject(options.named)) {
1077
- Object.keys(options.named).forEach(key => {
1078
- if (shared.isString(options.named[key])) {
1079
- options.named[key] = shared.escapeHtml(options.named[key]);
954
+ else if (shared.isDate(arg1)) {
955
+ if (isNaN(arg1.getTime())) {
956
+ throw createCoreError(CoreErrorCodes.INVALID_DATE_ARGUMENT);
957
+ }
958
+ value = arg1;
959
+ }
960
+ else if (shared.isNumber(arg1)) {
961
+ value = arg1;
962
+ }
963
+ else {
964
+ throw createCoreError(CoreErrorCodes.INVALID_ARGUMENT);
965
+ }
966
+ if (shared.isString(arg2)) {
967
+ options.key = arg2;
968
+ }
969
+ else if (shared.isPlainObject(arg2)) {
970
+ Object.keys(arg2).forEach(key => {
971
+ if (DATETIME_FORMAT_OPTIONS_KEYS.includes(key)) {
972
+ overrides[key] = arg2[key];
973
+ }
974
+ else {
975
+ options[key] = arg2[key];
1080
976
  }
1081
977
  });
1082
978
  }
1083
- }
1084
- function resolveMessageFormat(context, key, locale, fallbackLocale, fallbackWarn, missingWarn) {
1085
- const { messages, onWarn, messageResolver: resolveValue, localeFallbacker } = context;
1086
- const locales = localeFallbacker(context, fallbackLocale, locale); // eslint-disable-line @typescript-eslint/no-explicit-any
1087
- let message = {};
979
+ if (shared.isString(arg3)) {
980
+ options.locale = arg3;
981
+ }
982
+ else if (shared.isPlainObject(arg3)) {
983
+ overrides = arg3;
984
+ }
985
+ if (shared.isPlainObject(arg4)) {
986
+ overrides = arg4;
987
+ }
988
+ return [options.key || '', value, options, overrides];
989
+ }
990
+ /** @internal */
991
+ function clearDateTimeFormat(ctx, locale, format) {
992
+ const context = ctx;
993
+ for (const key in format) {
994
+ const id = `${locale}__${key}`;
995
+ if (!context.__datetimeFormatters.has(id)) {
996
+ continue;
997
+ }
998
+ context.__datetimeFormatters.delete(id);
999
+ }
1000
+ }
1001
+
1002
+ // implementation of `number` function
1003
+ function number(context, ...args) {
1004
+ const { numberFormats, unresolving, fallbackLocale, onWarn, localeFallbacker } = context;
1005
+ const { __numberFormatters } = context;
1006
+ const [key, value, options, overrides] = parseNumberArgs(...args);
1007
+ const missingWarn = shared.isBoolean(options.missingWarn)
1008
+ ? options.missingWarn
1009
+ : context.missingWarn;
1010
+ shared.isBoolean(options.fallbackWarn)
1011
+ ? options.fallbackWarn
1012
+ : context.fallbackWarn;
1013
+ const part = !!options.part;
1014
+ const locale = getLocale(context, options);
1015
+ const locales = localeFallbacker(context, // eslint-disable-line @typescript-eslint/no-explicit-any
1016
+ fallbackLocale, locale);
1017
+ if (!shared.isString(key) || key === '') {
1018
+ return new Intl.NumberFormat(locale, overrides).format(value);
1019
+ }
1020
+ // resolve format
1021
+ let numberFormat = {};
1088
1022
  let targetLocale;
1089
1023
  let format = null;
1090
- const type = 'translate';
1024
+ const type = 'number format';
1091
1025
  for (let i = 0; i < locales.length; i++) {
1092
1026
  targetLocale = locales[i];
1093
- message =
1094
- messages[targetLocale] || {};
1095
- if ((format = resolveValue(message, key)) === null) {
1096
- // if null, resolve with object key path
1097
- format = message[key]; // eslint-disable-line @typescript-eslint/no-explicit-any
1098
- }
1099
- if (shared.isString(format) || isMessageAST(format) || isMessageFunction(format)) {
1027
+ numberFormat =
1028
+ numberFormats[targetLocale] || {};
1029
+ format = numberFormat[key];
1030
+ if (shared.isPlainObject(format))
1100
1031
  break;
1101
- }
1102
- if (!isImplicitFallback(targetLocale, locales)) {
1103
- const missingRet = handleMissing(context, // eslint-disable-line @typescript-eslint/no-explicit-any
1104
- key, targetLocale, missingWarn, type);
1105
- if (missingRet !== key) {
1106
- format = missingRet;
1107
- }
1108
- }
1032
+ handleMissing(context, key, targetLocale, missingWarn, type); // eslint-disable-line @typescript-eslint/no-explicit-any
1109
1033
  }
1110
- return [format, targetLocale, message];
1111
- }
1112
- function compileMessageFormat(context, key, targetLocale, format, cacheBaseKey, onError) {
1113
- const { messageCompiler, warnHtmlMessage } = context;
1114
- if (isMessageFunction(format)) {
1115
- const msg = format;
1116
- msg.locale = msg.locale || targetLocale;
1117
- msg.key = msg.key || key;
1118
- return msg;
1034
+ // checking format and target locale
1035
+ if (!shared.isPlainObject(format) || !shared.isString(targetLocale)) {
1036
+ return unresolving ? NOT_REOSLVED : key;
1119
1037
  }
1120
- if (messageCompiler == null) {
1121
- const msg = (() => format);
1122
- msg.locale = targetLocale;
1123
- msg.key = key;
1124
- return msg;
1038
+ let id = `${targetLocale}__${key}`;
1039
+ if (!shared.isEmptyObject(overrides)) {
1040
+ id = `${id}__${JSON.stringify(overrides)}`;
1125
1041
  }
1126
- const msg = messageCompiler(format, getCompileContext(context, targetLocale, cacheBaseKey, format, warnHtmlMessage, onError));
1127
- msg.locale = targetLocale;
1128
- msg.key = key;
1129
- msg.source = format;
1130
- return msg;
1131
- }
1132
- function evaluateMessage(context, msg, msgCtx) {
1133
- const messaged = msg(msgCtx);
1134
- return messaged;
1042
+ let formatter = __numberFormatters.get(id);
1043
+ if (!formatter) {
1044
+ formatter = new Intl.NumberFormat(targetLocale, shared.assign({}, format, overrides));
1045
+ __numberFormatters.set(id, formatter);
1046
+ }
1047
+ return !part ? formatter.format(value) : formatter.formatToParts(value);
1135
1048
  }
1136
1049
  /** @internal */
1137
- function parseTranslateArgs(...args) {
1138
- const [arg1, arg2, arg3] = args;
1050
+ const NUMBER_FORMAT_OPTIONS_KEYS = [
1051
+ 'localeMatcher',
1052
+ 'style',
1053
+ 'currency',
1054
+ 'currencyDisplay',
1055
+ 'currencySign',
1056
+ 'useGrouping',
1057
+ 'minimumIntegerDigits',
1058
+ 'minimumFractionDigits',
1059
+ 'maximumFractionDigits',
1060
+ 'minimumSignificantDigits',
1061
+ 'maximumSignificantDigits',
1062
+ 'compactDisplay',
1063
+ 'notation',
1064
+ 'signDisplay',
1065
+ 'unit',
1066
+ 'unitDisplay',
1067
+ 'roundingMode',
1068
+ 'roundingPriority',
1069
+ 'roundingIncrement',
1070
+ 'trailingZeroDisplay'
1071
+ ];
1072
+ /** @internal */
1073
+ function parseNumberArgs(...args) {
1074
+ const [arg1, arg2, arg3, arg4] = args;
1139
1075
  const options = {};
1140
- if (!shared.isString(arg1) &&
1141
- !shared.isNumber(arg1) &&
1142
- !isMessageFunction(arg1) &&
1143
- !isMessageAST(arg1)) {
1076
+ let overrides = {};
1077
+ if (!shared.isNumber(arg1)) {
1144
1078
  throw createCoreError(CoreErrorCodes.INVALID_ARGUMENT);
1145
1079
  }
1146
- // prettier-ignore
1147
- const key = shared.isNumber(arg1)
1148
- ? String(arg1)
1149
- : isMessageFunction(arg1)
1150
- ? arg1
1151
- : arg1;
1152
- if (shared.isNumber(arg2)) {
1153
- options.plural = arg2;
1080
+ const value = arg1;
1081
+ if (shared.isString(arg2)) {
1082
+ options.key = arg2;
1154
1083
  }
1155
- else if (shared.isString(arg2)) {
1156
- options.default = arg2;
1084
+ else if (shared.isPlainObject(arg2)) {
1085
+ Object.keys(arg2).forEach(key => {
1086
+ if (NUMBER_FORMAT_OPTIONS_KEYS.includes(key)) {
1087
+ overrides[key] = arg2[key];
1088
+ }
1089
+ else {
1090
+ options[key] = arg2[key];
1091
+ }
1092
+ });
1157
1093
  }
1158
- else if (shared.isPlainObject(arg2) && !shared.isEmptyObject(arg2)) {
1159
- options.named = arg2;
1094
+ if (shared.isString(arg3)) {
1095
+ options.locale = arg3;
1160
1096
  }
1161
- else if (shared.isArray(arg2)) {
1162
- options.list = arg2;
1097
+ else if (shared.isPlainObject(arg3)) {
1098
+ overrides = arg3;
1163
1099
  }
1164
- if (shared.isNumber(arg3)) {
1165
- options.plural = arg3;
1100
+ if (shared.isPlainObject(arg4)) {
1101
+ overrides = arg4;
1166
1102
  }
1167
- else if (shared.isString(arg3)) {
1168
- options.default = arg3;
1103
+ return [options.key || '', value, options, overrides];
1104
+ }
1105
+ /** @internal */
1106
+ function clearNumberFormat(ctx, locale, format) {
1107
+ const context = ctx;
1108
+ for (const key in format) {
1109
+ const id = `${locale}__${key}`;
1110
+ if (!context.__numberFormatters.has(id)) {
1111
+ continue;
1112
+ }
1113
+ context.__numberFormatters.delete(id);
1169
1114
  }
1170
- else if (shared.isPlainObject(arg3)) {
1171
- shared.assign(options, arg3);
1115
+ }
1116
+
1117
+ const DEFAULT_MODIFIER = (str) => str;
1118
+ const DEFAULT_MESSAGE = (ctx) => ''; // eslint-disable-line
1119
+ const DEFAULT_MESSAGE_DATA_TYPE = 'text';
1120
+ const DEFAULT_NORMALIZE = (values) => values.length === 0 ? '' : shared.join(values);
1121
+ const DEFAULT_INTERPOLATE = shared.toDisplayString;
1122
+ function pluralDefault(choice, choicesLength) {
1123
+ choice = Math.abs(choice);
1124
+ if (choicesLength === 2) {
1125
+ // prettier-ignore
1126
+ return choice
1127
+ ? choice > 1
1128
+ ? 1
1129
+ : 0
1130
+ : 1;
1172
1131
  }
1173
- return [key, options];
1132
+ return choice ? Math.min(choice, 2) : 0;
1174
1133
  }
1175
- function getCompileContext(context, locale, key, source, warnHtmlMessage, onError) {
1176
- return {
1177
- locale,
1178
- key,
1179
- warnHtmlMessage,
1180
- onError: (err) => {
1181
- onError && onError(err);
1182
- {
1183
- throw err;
1134
+ function getPluralIndex(options) {
1135
+ // prettier-ignore
1136
+ const index = shared.isNumber(options.pluralIndex)
1137
+ ? options.pluralIndex
1138
+ : -1;
1139
+ // prettier-ignore
1140
+ return options.named && (shared.isNumber(options.named.count) || shared.isNumber(options.named.n))
1141
+ ? shared.isNumber(options.named.count)
1142
+ ? options.named.count
1143
+ : shared.isNumber(options.named.n)
1144
+ ? options.named.n
1145
+ : index
1146
+ : index;
1147
+ }
1148
+ function normalizeNamed(pluralIndex, props) {
1149
+ if (!props.count) {
1150
+ props.count = pluralIndex;
1151
+ }
1152
+ if (!props.n) {
1153
+ props.n = pluralIndex;
1154
+ }
1155
+ }
1156
+ function createMessageContext(options = {}) {
1157
+ const locale = options.locale;
1158
+ const pluralIndex = getPluralIndex(options);
1159
+ const pluralRule = shared.isObject(options.pluralRules) &&
1160
+ shared.isString(locale) &&
1161
+ shared.isFunction(options.pluralRules[locale])
1162
+ ? options.pluralRules[locale]
1163
+ : pluralDefault;
1164
+ const orgPluralRule = shared.isObject(options.pluralRules) &&
1165
+ shared.isString(locale) &&
1166
+ shared.isFunction(options.pluralRules[locale])
1167
+ ? pluralDefault
1168
+ : undefined;
1169
+ const plural = (messages) => {
1170
+ return messages[pluralRule(pluralIndex, messages.length, orgPluralRule)];
1171
+ };
1172
+ const _list = options.list || [];
1173
+ const list = (index) => _list[index];
1174
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1175
+ const _named = options.named || {};
1176
+ shared.isNumber(options.pluralIndex) && normalizeNamed(pluralIndex, _named);
1177
+ const named = (key) => _named[key];
1178
+ function message(key, useLinked) {
1179
+ // prettier-ignore
1180
+ const msg = shared.isFunction(options.messages)
1181
+ ? options.messages(key, !!useLinked)
1182
+ : shared.isObject(options.messages)
1183
+ ? options.messages[key]
1184
+ : false;
1185
+ return !msg
1186
+ ? options.parent
1187
+ ? options.parent.message(key) // resolve from parent messages
1188
+ : DEFAULT_MESSAGE
1189
+ : msg;
1190
+ }
1191
+ const _modifier = (name) => options.modifiers
1192
+ ? options.modifiers[name]
1193
+ : DEFAULT_MODIFIER;
1194
+ const normalize = shared.isPlainObject(options.processor) && shared.isFunction(options.processor.normalize)
1195
+ ? options.processor.normalize
1196
+ : DEFAULT_NORMALIZE;
1197
+ const interpolate = shared.isPlainObject(options.processor) &&
1198
+ shared.isFunction(options.processor.interpolate)
1199
+ ? options.processor.interpolate
1200
+ : DEFAULT_INTERPOLATE;
1201
+ const type = shared.isPlainObject(options.processor) && shared.isString(options.processor.type)
1202
+ ? options.processor.type
1203
+ : DEFAULT_MESSAGE_DATA_TYPE;
1204
+ const linked = (key, ...args) => {
1205
+ const [arg1, arg2] = args;
1206
+ let type = 'text';
1207
+ let modifier = '';
1208
+ if (args.length === 1) {
1209
+ if (shared.isObject(arg1)) {
1210
+ modifier = arg1.modifier || modifier;
1211
+ type = arg1.type || type;
1212
+ }
1213
+ else if (shared.isString(arg1)) {
1214
+ modifier = arg1 || modifier;
1184
1215
  }
1185
- },
1186
- onCacheKey: (source) => shared.generateFormatCacheKey(locale, key, source)
1187
- };
1188
- }
1189
- function getMessageContextOptions(context, locale, message, options) {
1190
- const { modifiers, pluralRules, messageResolver: resolveValue, fallbackLocale, fallbackWarn, missingWarn, fallbackContext } = context;
1191
- const resolveMessage = (key, useLinked) => {
1192
- let val = resolveValue(message, key);
1193
- // fallback
1194
- if (val == null && (fallbackContext || useLinked)) {
1195
- const [, , message] = resolveMessageFormat(fallbackContext || context, // NOTE: if has fallbackContext, fallback to root, else if use linked, fallback to local context
1196
- key, locale, fallbackLocale, fallbackWarn, missingWarn);
1197
- val = resolveValue(message, key);
1198
- }
1199
- if (shared.isString(val) || isMessageAST(val)) {
1200
- let occurred = false;
1201
- const onError = () => {
1202
- occurred = true;
1203
- };
1204
- const msg = compileMessageFormat(context, key, locale, val, key, onError);
1205
- return !occurred
1206
- ? msg
1207
- : NOOP_MESSAGE_FUNCTION;
1208
- }
1209
- else if (isMessageFunction(val)) {
1210
- return val;
1211
1216
  }
1212
- else {
1213
- // TODO: should be implemented warning message
1214
- return NOOP_MESSAGE_FUNCTION;
1217
+ else if (args.length === 2) {
1218
+ if (shared.isString(arg1)) {
1219
+ modifier = arg1 || modifier;
1220
+ }
1221
+ if (shared.isString(arg2)) {
1222
+ type = arg2 || type;
1223
+ }
1215
1224
  }
1225
+ const ret = message(key, true)(ctx);
1226
+ const msg =
1227
+ // The message in vnode resolved with linked are returned as an array by processor.nomalize
1228
+ type === 'vnode' && shared.isArray(ret) && modifier
1229
+ ? ret[0]
1230
+ : ret;
1231
+ return modifier ? _modifier(modifier)(msg, type) : msg;
1216
1232
  };
1217
- const ctxOptions = {
1218
- locale,
1219
- modifiers,
1220
- pluralRules,
1221
- messages: resolveMessage
1233
+ const ctx = {
1234
+ ["list" /* HelperNameMap.LIST */]: list,
1235
+ ["named" /* HelperNameMap.NAMED */]: named,
1236
+ ["plural" /* HelperNameMap.PLURAL */]: plural,
1237
+ ["linked" /* HelperNameMap.LINKED */]: linked,
1238
+ ["message" /* HelperNameMap.MESSAGE */]: message,
1239
+ ["type" /* HelperNameMap.TYPE */]: type,
1240
+ ["interpolate" /* HelperNameMap.INTERPOLATE */]: interpolate,
1241
+ ["normalize" /* HelperNameMap.NORMALIZE */]: normalize,
1242
+ ["values" /* HelperNameMap.VALUES */]: shared.assign({}, _list, _named)
1222
1243
  };
1223
- if (context.processor) {
1224
- ctxOptions.processor = context.processor;
1225
- }
1226
- if (options.list) {
1227
- ctxOptions.list = options.list;
1228
- }
1229
- if (options.named) {
1230
- ctxOptions.named = options.named;
1231
- }
1232
- if (shared.isNumber(options.plural)) {
1233
- ctxOptions.pluralIndex = options.plural;
1234
- }
1235
- return ctxOptions;
1244
+ return ctx;
1236
1245
  }
1237
1246
 
1238
- // implementation of `datetime` function
1239
- function datetime(context, ...args) {
1240
- const { datetimeFormats, unresolving, fallbackLocale, onWarn, localeFallbacker } = context;
1241
- const { __datetimeFormatters } = context;
1242
- const [key, value, options, overrides] = parseDateTimeArgs(...args);
1247
+ const NOOP_MESSAGE_FUNCTION = () => '';
1248
+ const isMessageFunction = (val) => shared.isFunction(val);
1249
+ // implementation of `translate` function
1250
+ function translate(context, ...args) {
1251
+ const { fallbackFormat, postTranslation, unresolving, messageCompiler, fallbackLocale, messages } = context;
1252
+ const [key, options] = parseTranslateArgs(...args);
1243
1253
  const missingWarn = shared.isBoolean(options.missingWarn)
1244
1254
  ? options.missingWarn
1245
1255
  : context.missingWarn;
1246
- shared.isBoolean(options.fallbackWarn)
1256
+ const fallbackWarn = shared.isBoolean(options.fallbackWarn)
1247
1257
  ? options.fallbackWarn
1248
1258
  : context.fallbackWarn;
1249
- const part = !!options.part;
1259
+ const escapeParameter = shared.isBoolean(options.escapeParameter)
1260
+ ? options.escapeParameter
1261
+ : context.escapeParameter;
1262
+ const resolvedMessage = !!options.resolvedMessage;
1263
+ // prettier-ignore
1264
+ const defaultMsgOrKey = shared.isString(options.default) || shared.isBoolean(options.default) // default by function option
1265
+ ? !shared.isBoolean(options.default)
1266
+ ? options.default
1267
+ : (!messageCompiler ? () => key : key)
1268
+ : fallbackFormat // default by `fallbackFormat` option
1269
+ ? (!messageCompiler ? () => key : key)
1270
+ : null;
1271
+ const enableDefaultMsg = fallbackFormat ||
1272
+ (defaultMsgOrKey != null &&
1273
+ (shared.isString(defaultMsgOrKey) || shared.isFunction(defaultMsgOrKey)));
1250
1274
  const locale = getLocale(context, options);
1251
- const locales = localeFallbacker(context, // eslint-disable-line @typescript-eslint/no-explicit-any
1252
- fallbackLocale, locale);
1253
- if (!shared.isString(key) || key === '') {
1254
- return new Intl.DateTimeFormat(locale, overrides).format(value);
1255
- }
1256
- // resolve format
1257
- let datetimeFormat = {};
1258
- let targetLocale;
1259
- let format = null;
1260
- const type = 'datetime format';
1261
- for (let i = 0; i < locales.length; i++) {
1262
- targetLocale = locales[i];
1263
- datetimeFormat =
1264
- datetimeFormats[targetLocale] || {};
1265
- format = datetimeFormat[key];
1266
- if (shared.isPlainObject(format))
1267
- break;
1268
- handleMissing(context, key, targetLocale, missingWarn, type); // eslint-disable-line @typescript-eslint/no-explicit-any
1275
+ // escape params
1276
+ escapeParameter && escapeParams(options);
1277
+ // resolve message format
1278
+ // eslint-disable-next-line prefer-const
1279
+ let [formatScope, targetLocale, message] = !resolvedMessage
1280
+ ? resolveMessageFormat(context, key, locale, fallbackLocale, fallbackWarn, missingWarn)
1281
+ : [
1282
+ key,
1283
+ locale,
1284
+ messages[locale] || {}
1285
+ ];
1286
+ // NOTE:
1287
+ // Fix to work around `ssrTransfrom` bug in Vite.
1288
+ // https://github.com/vitejs/vite/issues/4306
1289
+ // To get around this, use temporary variables.
1290
+ // https://github.com/nuxt/framework/issues/1461#issuecomment-954606243
1291
+ let format = formatScope;
1292
+ // if you use default message, set it as message format!
1293
+ let cacheBaseKey = key;
1294
+ if (!resolvedMessage &&
1295
+ !(shared.isString(format) ||
1296
+ isMessageAST(format) ||
1297
+ isMessageFunction(format))) {
1298
+ if (enableDefaultMsg) {
1299
+ format = defaultMsgOrKey;
1300
+ cacheBaseKey = format;
1301
+ }
1269
1302
  }
1270
- // checking format and target locale
1271
- if (!shared.isPlainObject(format) || !shared.isString(targetLocale)) {
1303
+ // checking message format and target locale
1304
+ if (!resolvedMessage &&
1305
+ (!(shared.isString(format) ||
1306
+ isMessageAST(format) ||
1307
+ isMessageFunction(format)) ||
1308
+ !shared.isString(targetLocale))) {
1272
1309
  return unresolving ? NOT_REOSLVED : key;
1273
1310
  }
1274
- let id = `${targetLocale}__${key}`;
1275
- if (!shared.isEmptyObject(overrides)) {
1276
- id = `${id}__${JSON.stringify(overrides)}`;
1277
- }
1278
- let formatter = __datetimeFormatters.get(id);
1279
- if (!formatter) {
1280
- formatter = new Intl.DateTimeFormat(targetLocale, shared.assign({}, format, overrides));
1281
- __datetimeFormatters.set(id, formatter);
1311
+ // setup compile error detecting
1312
+ let occurred = false;
1313
+ const onError = () => {
1314
+ occurred = true;
1315
+ };
1316
+ // compile message format
1317
+ const msg = !isMessageFunction(format)
1318
+ ? compileMessageFormat(context, key, targetLocale, format, cacheBaseKey, onError)
1319
+ : format;
1320
+ // if occurred compile error, return the message format
1321
+ if (occurred) {
1322
+ return format;
1282
1323
  }
1283
- return !part ? formatter.format(value) : formatter.formatToParts(value);
1324
+ // evaluate message with context
1325
+ const ctxOptions = getMessageContextOptions(context, targetLocale, message, options);
1326
+ const msgContext = createMessageContext(ctxOptions);
1327
+ const messaged = evaluateMessage(context, msg, msgContext);
1328
+ // if use post translation option, proceed it with handler
1329
+ const ret = postTranslation
1330
+ ? postTranslation(messaged, key)
1331
+ : messaged;
1332
+ return ret;
1284
1333
  }
1285
- /** @internal */
1286
- const DATETIME_FORMAT_OPTIONS_KEYS = [
1287
- 'localeMatcher',
1288
- 'weekday',
1289
- 'era',
1290
- 'year',
1291
- 'month',
1292
- 'day',
1293
- 'hour',
1294
- 'minute',
1295
- 'second',
1296
- 'timeZoneName',
1297
- 'formatMatcher',
1298
- 'hour12',
1299
- 'timeZone',
1300
- 'dateStyle',
1301
- 'timeStyle',
1302
- 'calendar',
1303
- 'dayPeriod',
1304
- 'numberingSystem',
1305
- 'hourCycle',
1306
- 'fractionalSecondDigits'
1307
- ];
1308
- /** @internal */
1309
- function parseDateTimeArgs(...args) {
1310
- const [arg1, arg2, arg3, arg4] = args;
1311
- const options = {};
1312
- let overrides = {};
1313
- let value;
1314
- if (shared.isString(arg1)) {
1315
- // Only allow ISO strings - other date formats are often supported,
1316
- // but may cause different results in different browsers.
1317
- const matches = arg1.match(/(\d{4}-\d{2}-\d{2})(T|\s)?(.*)/);
1318
- if (!matches) {
1319
- throw createCoreError(CoreErrorCodes.INVALID_ISO_DATE_ARGUMENT);
1320
- }
1321
- // Some browsers can not parse the iso datetime separated by space,
1322
- // this is a compromise solution by replace the 'T'/' ' with 'T'
1323
- const dateTime = matches[3]
1324
- ? matches[3].trim().startsWith('T')
1325
- ? `${matches[1].trim()}${matches[3].trim()}`
1326
- : `${matches[1].trim()}T${matches[3].trim()}`
1327
- : matches[1].trim();
1328
- value = new Date(dateTime);
1329
- try {
1330
- // This will fail if the date is not valid
1331
- value.toISOString();
1332
- }
1333
- catch (e) {
1334
- throw createCoreError(CoreErrorCodes.INVALID_ISO_DATE_ARGUMENT);
1335
- }
1336
- }
1337
- else if (shared.isDate(arg1)) {
1338
- if (isNaN(arg1.getTime())) {
1339
- throw createCoreError(CoreErrorCodes.INVALID_DATE_ARGUMENT);
1340
- }
1341
- value = arg1;
1342
- }
1343
- else if (shared.isNumber(arg1)) {
1344
- value = arg1;
1345
- }
1346
- else {
1347
- throw createCoreError(CoreErrorCodes.INVALID_ARGUMENT);
1348
- }
1349
- if (shared.isString(arg2)) {
1350
- options.key = arg2;
1334
+ function escapeParams(options) {
1335
+ if (shared.isArray(options.list)) {
1336
+ options.list = options.list.map(item => shared.isString(item) ? shared.escapeHtml(item) : item);
1351
1337
  }
1352
- else if (shared.isPlainObject(arg2)) {
1353
- Object.keys(arg2).forEach(key => {
1354
- if (DATETIME_FORMAT_OPTIONS_KEYS.includes(key)) {
1355
- overrides[key] = arg2[key];
1356
- }
1357
- else {
1358
- options[key] = arg2[key];
1338
+ else if (shared.isObject(options.named)) {
1339
+ Object.keys(options.named).forEach(key => {
1340
+ if (shared.isString(options.named[key])) {
1341
+ options.named[key] = shared.escapeHtml(options.named[key]);
1359
1342
  }
1360
1343
  });
1361
1344
  }
1362
- if (shared.isString(arg3)) {
1363
- options.locale = arg3;
1364
- }
1365
- else if (shared.isPlainObject(arg3)) {
1366
- overrides = arg3;
1367
- }
1368
- if (shared.isPlainObject(arg4)) {
1369
- overrides = arg4;
1370
- }
1371
- return [options.key || '', value, options, overrides];
1372
- }
1373
- /** @internal */
1374
- function clearDateTimeFormat(ctx, locale, format) {
1375
- const context = ctx;
1376
- for (const key in format) {
1377
- const id = `${locale}__${key}`;
1378
- if (!context.__datetimeFormatters.has(id)) {
1379
- continue;
1380
- }
1381
- context.__datetimeFormatters.delete(id);
1382
- }
1383
1345
  }
1384
-
1385
- // implementation of `number` function
1386
- function number(context, ...args) {
1387
- const { numberFormats, unresolving, fallbackLocale, onWarn, localeFallbacker } = context;
1388
- const { __numberFormatters } = context;
1389
- const [key, value, options, overrides] = parseNumberArgs(...args);
1390
- const missingWarn = shared.isBoolean(options.missingWarn)
1391
- ? options.missingWarn
1392
- : context.missingWarn;
1393
- shared.isBoolean(options.fallbackWarn)
1394
- ? options.fallbackWarn
1395
- : context.fallbackWarn;
1396
- const part = !!options.part;
1397
- const locale = getLocale(context, options);
1398
- const locales = localeFallbacker(context, // eslint-disable-line @typescript-eslint/no-explicit-any
1399
- fallbackLocale, locale);
1400
- if (!shared.isString(key) || key === '') {
1401
- return new Intl.NumberFormat(locale, overrides).format(value);
1402
- }
1403
- // resolve format
1404
- let numberFormat = {};
1346
+ function resolveMessageFormat(context, key, locale, fallbackLocale, fallbackWarn, missingWarn) {
1347
+ const { messages, onWarn, messageResolver: resolveValue, localeFallbacker } = context;
1348
+ const locales = localeFallbacker(context, fallbackLocale, locale); // eslint-disable-line @typescript-eslint/no-explicit-any
1349
+ let message = {};
1405
1350
  let targetLocale;
1406
1351
  let format = null;
1407
- const type = 'number format';
1352
+ const type = 'translate';
1408
1353
  for (let i = 0; i < locales.length; i++) {
1409
1354
  targetLocale = locales[i];
1410
- numberFormat =
1411
- numberFormats[targetLocale] || {};
1412
- format = numberFormat[key];
1413
- if (shared.isPlainObject(format))
1355
+ message =
1356
+ messages[targetLocale] || {};
1357
+ if ((format = resolveValue(message, key)) === null) {
1358
+ // if null, resolve with object key path
1359
+ format = message[key]; // eslint-disable-line @typescript-eslint/no-explicit-any
1360
+ }
1361
+ if (shared.isString(format) || isMessageAST(format) || isMessageFunction(format)) {
1414
1362
  break;
1415
- handleMissing(context, key, targetLocale, missingWarn, type); // eslint-disable-line @typescript-eslint/no-explicit-any
1416
- }
1417
- // checking format and target locale
1418
- if (!shared.isPlainObject(format) || !shared.isString(targetLocale)) {
1419
- return unresolving ? NOT_REOSLVED : key;
1363
+ }
1364
+ if (!isImplicitFallback(targetLocale, locales)) {
1365
+ const missingRet = handleMissing(context, // eslint-disable-line @typescript-eslint/no-explicit-any
1366
+ key, targetLocale, missingWarn, type);
1367
+ if (missingRet !== key) {
1368
+ format = missingRet;
1369
+ }
1370
+ }
1420
1371
  }
1421
- let id = `${targetLocale}__${key}`;
1422
- if (!shared.isEmptyObject(overrides)) {
1423
- id = `${id}__${JSON.stringify(overrides)}`;
1372
+ return [format, targetLocale, message];
1373
+ }
1374
+ function compileMessageFormat(context, key, targetLocale, format, cacheBaseKey, onError) {
1375
+ const { messageCompiler, warnHtmlMessage } = context;
1376
+ if (isMessageFunction(format)) {
1377
+ const msg = format;
1378
+ msg.locale = msg.locale || targetLocale;
1379
+ msg.key = msg.key || key;
1380
+ return msg;
1424
1381
  }
1425
- let formatter = __numberFormatters.get(id);
1426
- if (!formatter) {
1427
- formatter = new Intl.NumberFormat(targetLocale, shared.assign({}, format, overrides));
1428
- __numberFormatters.set(id, formatter);
1382
+ if (messageCompiler == null) {
1383
+ const msg = (() => format);
1384
+ msg.locale = targetLocale;
1385
+ msg.key = key;
1386
+ return msg;
1429
1387
  }
1430
- return !part ? formatter.format(value) : formatter.formatToParts(value);
1388
+ const msg = messageCompiler(format, getCompileContext(context, targetLocale, cacheBaseKey, format, warnHtmlMessage, onError));
1389
+ msg.locale = targetLocale;
1390
+ msg.key = key;
1391
+ msg.source = format;
1392
+ return msg;
1393
+ }
1394
+ function evaluateMessage(context, msg, msgCtx) {
1395
+ const messaged = msg(msgCtx);
1396
+ return messaged;
1431
1397
  }
1432
1398
  /** @internal */
1433
- const NUMBER_FORMAT_OPTIONS_KEYS = [
1434
- 'localeMatcher',
1435
- 'style',
1436
- 'currency',
1437
- 'currencyDisplay',
1438
- 'currencySign',
1439
- 'useGrouping',
1440
- 'minimumIntegerDigits',
1441
- 'minimumFractionDigits',
1442
- 'maximumFractionDigits',
1443
- 'minimumSignificantDigits',
1444
- 'maximumSignificantDigits',
1445
- 'compactDisplay',
1446
- 'notation',
1447
- 'signDisplay',
1448
- 'unit',
1449
- 'unitDisplay',
1450
- 'roundingMode',
1451
- 'roundingPriority',
1452
- 'roundingIncrement',
1453
- 'trailingZeroDisplay'
1454
- ];
1455
- /** @internal */
1456
- function parseNumberArgs(...args) {
1457
- const [arg1, arg2, arg3, arg4] = args;
1399
+ function parseTranslateArgs(...args) {
1400
+ const [arg1, arg2, arg3] = args;
1458
1401
  const options = {};
1459
- let overrides = {};
1460
- if (!shared.isNumber(arg1)) {
1402
+ if (!shared.isString(arg1) &&
1403
+ !shared.isNumber(arg1) &&
1404
+ !isMessageFunction(arg1) &&
1405
+ !isMessageAST(arg1)) {
1461
1406
  throw createCoreError(CoreErrorCodes.INVALID_ARGUMENT);
1462
1407
  }
1463
- const value = arg1;
1464
- if (shared.isString(arg2)) {
1465
- options.key = arg2;
1408
+ // prettier-ignore
1409
+ const key = shared.isNumber(arg1)
1410
+ ? String(arg1)
1411
+ : isMessageFunction(arg1)
1412
+ ? arg1
1413
+ : arg1;
1414
+ if (shared.isNumber(arg2)) {
1415
+ options.plural = arg2;
1466
1416
  }
1467
- else if (shared.isPlainObject(arg2)) {
1468
- Object.keys(arg2).forEach(key => {
1469
- if (NUMBER_FORMAT_OPTIONS_KEYS.includes(key)) {
1470
- overrides[key] = arg2[key];
1471
- }
1472
- else {
1473
- options[key] = arg2[key];
1474
- }
1475
- });
1417
+ else if (shared.isString(arg2)) {
1418
+ options.default = arg2;
1476
1419
  }
1477
- if (shared.isString(arg3)) {
1478
- options.locale = arg3;
1420
+ else if (shared.isPlainObject(arg2) && !shared.isEmptyObject(arg2)) {
1421
+ options.named = arg2;
1479
1422
  }
1480
- else if (shared.isPlainObject(arg3)) {
1481
- overrides = arg3;
1423
+ else if (shared.isArray(arg2)) {
1424
+ options.list = arg2;
1482
1425
  }
1483
- if (shared.isPlainObject(arg4)) {
1484
- overrides = arg4;
1426
+ if (shared.isNumber(arg3)) {
1427
+ options.plural = arg3;
1485
1428
  }
1486
- return [options.key || '', value, options, overrides];
1429
+ else if (shared.isString(arg3)) {
1430
+ options.default = arg3;
1431
+ }
1432
+ else if (shared.isPlainObject(arg3)) {
1433
+ shared.assign(options, arg3);
1434
+ }
1435
+ return [key, options];
1487
1436
  }
1488
- /** @internal */
1489
- function clearNumberFormat(ctx, locale, format) {
1490
- const context = ctx;
1491
- for (const key in format) {
1492
- const id = `${locale}__${key}`;
1493
- if (!context.__numberFormatters.has(id)) {
1494
- continue;
1437
+ function getCompileContext(context, locale, key, source, warnHtmlMessage, onError) {
1438
+ return {
1439
+ locale,
1440
+ key,
1441
+ warnHtmlMessage,
1442
+ onError: (err) => {
1443
+ onError && onError(err);
1444
+ {
1445
+ throw err;
1446
+ }
1447
+ },
1448
+ onCacheKey: (source) => shared.generateFormatCacheKey(locale, key, source)
1449
+ };
1450
+ }
1451
+ function getMessageContextOptions(context, locale, message, options) {
1452
+ const { modifiers, pluralRules, messageResolver: resolveValue, fallbackLocale, fallbackWarn, missingWarn, fallbackContext } = context;
1453
+ const resolveMessage = (key, useLinked) => {
1454
+ let val = resolveValue(message, key);
1455
+ // fallback
1456
+ if (val == null && (fallbackContext || useLinked)) {
1457
+ const [, , message] = resolveMessageFormat(fallbackContext || context, // NOTE: if has fallbackContext, fallback to root, else if use linked, fallback to local context
1458
+ key, locale, fallbackLocale, fallbackWarn, missingWarn);
1459
+ val = resolveValue(message, key);
1495
1460
  }
1496
- context.__numberFormatters.delete(id);
1461
+ if (shared.isString(val) || isMessageAST(val)) {
1462
+ let occurred = false;
1463
+ const onError = () => {
1464
+ occurred = true;
1465
+ };
1466
+ const msg = compileMessageFormat(context, key, locale, val, key, onError);
1467
+ return !occurred
1468
+ ? msg
1469
+ : NOOP_MESSAGE_FUNCTION;
1470
+ }
1471
+ else if (isMessageFunction(val)) {
1472
+ return val;
1473
+ }
1474
+ else {
1475
+ // TODO: should be implemented warning message
1476
+ return NOOP_MESSAGE_FUNCTION;
1477
+ }
1478
+ };
1479
+ const ctxOptions = {
1480
+ locale,
1481
+ modifiers,
1482
+ pluralRules,
1483
+ messages: resolveMessage
1484
+ };
1485
+ if (context.processor) {
1486
+ ctxOptions.processor = context.processor;
1487
+ }
1488
+ if (options.list) {
1489
+ ctxOptions.list = options.list;
1490
+ }
1491
+ if (options.named) {
1492
+ ctxOptions.named = options.named;
1497
1493
  }
1494
+ if (shared.isNumber(options.plural)) {
1495
+ ctxOptions.pluralIndex = options.plural;
1496
+ }
1497
+ return ctxOptions;
1498
1498
  }
1499
1499
 
1500
1500
  exports.CompileErrorCodes = messageCompiler.CompileErrorCodes;