@intlify/core-base 10.0.0-beta.5 → 10.0.0-rc.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.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * core-base v10.0.0-beta.5
2
+ * core-base v10.0.0-rc.1
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) {
341
- // prettier-ignore
342
- const msg = shared.isFunction(options.messages)
343
- ? options.messages(key)
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
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)
351
122
  : msg;
352
123
  }
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;
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)(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,30 +162,6 @@ 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
440
- };
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.`
451
- };
452
- function getWarnMessage(code, ...args) {
453
- return shared.format(warnMessages[code], ...args);
454
- }
455
-
456
165
  const CoreErrorCodes = {
457
166
  INVALID_ARGUMENT: messageCompiler.COMPILE_ERROR_CODES_EXTEND_POINT, // 17
458
167
  INVALID_DATE_ARGUMENT: 18,
@@ -595,35 +304,327 @@ function appendBlockToChain(chain, block, blocks) {
595
304
  follow = appendLocaleToChain(chain, block[i], blocks);
596
305
  }
597
306
  }
598
- return follow;
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 */]
374
+ };
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 */]
379
+ };
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 */]
384
+ };
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);
391
+ }
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;
399
+ }
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 */;
406
+ }
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;
489
+ }
490
+ key = formatSubPath(key);
491
+ if (key === false) {
492
+ return false;
493
+ }
494
+ else {
495
+ actions[1 /* Actions.PUSH */]();
496
+ }
497
+ }
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;
537
+ }
538
+ }
599
539
  }
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;
540
+ // path token cache
541
+ const cache = new Map();
542
+ /**
543
+ * key-value message resolver
544
+ *
545
+ * @remarks
546
+ * Resolves messages with the key-value structure. Note that messages with a hierarchical structure such as objects cannot be resolved
547
+ *
548
+ * @param obj - A target object to be resolved with path
549
+ * @param path - A {@link Path | path} to resolve the value of message
550
+ *
551
+ * @returns A resolved {@link PathValue | path value}
552
+ *
553
+ * @VueI18nGeneral
554
+ */
555
+ function resolveWithKeyValue(obj, path) {
556
+ return shared.isObject(obj) ? obj[path] : null;
609
557
  }
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
- }
558
+ /**
559
+ * message resolver
560
+ *
561
+ * @remarks
562
+ * Resolves messages. messages with a hierarchical structure such as objects can be resolved. This resolver is used in VueI18n as default.
563
+ *
564
+ * @param obj - A target object to be resolved with path
565
+ * @param path - A {@link Path | path} to resolve the value of message
566
+ *
567
+ * @returns A resolved {@link PathValue | path value}
568
+ *
569
+ * @VueI18nGeneral
570
+ */
571
+ function resolveValue(obj, path) {
572
+ // check object
573
+ if (!shared.isObject(obj)) {
574
+ return null;
575
+ }
576
+ // parse path
577
+ let hit = cache.get(path);
578
+ if (!hit) {
579
+ hit = parse(path);
580
+ if (hit) {
581
+ cache.set(path, hit);
624
582
  }
625
583
  }
626
- return follow;
584
+ // check hit
585
+ if (!hit) {
586
+ return null;
587
+ }
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;
596
+ }
597
+ if (shared.isFunction(last)) {
598
+ return null;
599
+ }
600
+ last = val;
601
+ i++;
602
+ }
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.5';
635
+ const VERSION = '10.0.0-rc.1';
635
636
  const NOT_REOSLVED = -1;
636
637
  const DEFAULT_LOCALE = 'en-US';
637
638
  const MISSING_RESOLVE_VALUE = '';
@@ -817,683 +818,683 @@ function isTranslateMissingWarn(missing, key) {
817
818
  function handleMissing(context, key, locale, missingWarn, type) {
818
819
  const { missing, onWarn } = context;
819
820
  if (missing !== null) {
820
- const ret = missing(context, locale, key, type);
821
- return shared.isString(ret) ? ret : key;
822
- }
823
- else {
824
- return key;
825
- }
826
- }
827
- /** @internal */
828
- function updateFallbackLocale(ctx, locale, fallback) {
829
- const context = ctx;
830
- context.__localeChainCache = new Map();
831
- ctx.localeFallbacker(ctx, fallback, locale);
832
- }
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;
821
+ const ret = missing(context, locale, key, type);
822
+ return shared.isString(ret) ? ret : key;
966
823
  }
967
824
  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);
825
+ return key;
826
+ }
827
+ }
828
+ /** @internal */
829
+ function updateFallbackLocale(ctx, locale, fallback) {
830
+ const context = ctx;
831
+ context.__localeChainCache = new Map();
832
+ ctx.localeFallbacker(ctx, fallback, locale);
833
+ }
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;
845
+ }
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) => {
1192
- let val = resolveValue(message, key);
1193
- // fallback to root context
1194
- if (val == null && fallbackContext) {
1195
- const [, , message] = resolveMessageFormat(fallbackContext, key, locale, fallbackLocale, fallbackWarn, missingWarn);
1196
- val = resolveValue(message, key);
1197
- }
1198
- if (shared.isString(val) || isMessageAST(val)) {
1199
- let occurred = false;
1200
- const onError = () => {
1201
- occurred = true;
1202
- };
1203
- const msg = compileMessageFormat(context, key, locale, val, key, onError);
1204
- return !occurred
1205
- ? msg
1206
- : NOOP_MESSAGE_FUNCTION;
1207
- }
1208
- else if (isMessageFunction(val)) {
1209
- return val;
1210
1216
  }
1211
- else {
1212
- // TODO: should be implemented warning message
1213
- 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
+ }
1214
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;
1215
1232
  };
1216
- const ctxOptions = {
1217
- locale,
1218
- modifiers,
1219
- pluralRules,
1220
- 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)
1221
1243
  };
1222
- if (context.processor) {
1223
- ctxOptions.processor = context.processor;
1224
- }
1225
- if (options.list) {
1226
- ctxOptions.list = options.list;
1227
- }
1228
- if (options.named) {
1229
- ctxOptions.named = options.named;
1230
- }
1231
- if (shared.isNumber(options.plural)) {
1232
- ctxOptions.pluralIndex = options.plural;
1233
- }
1234
- return ctxOptions;
1244
+ return ctx;
1235
1245
  }
1236
1246
 
1237
- // implementation of `datetime` function
1238
- function datetime(context, ...args) {
1239
- const { datetimeFormats, unresolving, fallbackLocale, onWarn, localeFallbacker } = context;
1240
- const { __datetimeFormatters } = context;
1241
- 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);
1242
1253
  const missingWarn = shared.isBoolean(options.missingWarn)
1243
1254
  ? options.missingWarn
1244
1255
  : context.missingWarn;
1245
- shared.isBoolean(options.fallbackWarn)
1256
+ const fallbackWarn = shared.isBoolean(options.fallbackWarn)
1246
1257
  ? options.fallbackWarn
1247
1258
  : context.fallbackWarn;
1248
- 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)));
1249
1274
  const locale = getLocale(context, options);
1250
- const locales = localeFallbacker(context, // eslint-disable-line @typescript-eslint/no-explicit-any
1251
- fallbackLocale, locale);
1252
- if (!shared.isString(key) || key === '') {
1253
- return new Intl.DateTimeFormat(locale, overrides).format(value);
1254
- }
1255
- // resolve format
1256
- let datetimeFormat = {};
1257
- let targetLocale;
1258
- let format = null;
1259
- const type = 'datetime format';
1260
- for (let i = 0; i < locales.length; i++) {
1261
- targetLocale = locales[i];
1262
- datetimeFormat =
1263
- datetimeFormats[targetLocale] || {};
1264
- format = datetimeFormat[key];
1265
- if (shared.isPlainObject(format))
1266
- break;
1267
- handleMissing(context, key, targetLocale, missingWarn, type); // eslint-disable-line @typescript-eslint/no-explicit-any
1268
- }
1269
- // checking format and target locale
1270
- if (!shared.isPlainObject(format) || !shared.isString(targetLocale)) {
1271
- return unresolving ? NOT_REOSLVED : key;
1272
- }
1273
- let id = `${targetLocale}__${key}`;
1274
- if (!shared.isEmptyObject(overrides)) {
1275
- id = `${id}__${JSON.stringify(overrides)}`;
1276
- }
1277
- let formatter = __datetimeFormatters.get(id);
1278
- if (!formatter) {
1279
- formatter = new Intl.DateTimeFormat(targetLocale, shared.assign({}, format, overrides));
1280
- __datetimeFormatters.set(id, formatter);
1281
- }
1282
- return !part ? formatter.format(value) : formatter.formatToParts(value);
1283
- }
1284
- /** @internal */
1285
- const DATETIME_FORMAT_OPTIONS_KEYS = [
1286
- 'localeMatcher',
1287
- 'weekday',
1288
- 'era',
1289
- 'year',
1290
- 'month',
1291
- 'day',
1292
- 'hour',
1293
- 'minute',
1294
- 'second',
1295
- 'timeZoneName',
1296
- 'formatMatcher',
1297
- 'hour12',
1298
- 'timeZone',
1299
- 'dateStyle',
1300
- 'timeStyle',
1301
- 'calendar',
1302
- 'dayPeriod',
1303
- 'numberingSystem',
1304
- 'hourCycle',
1305
- 'fractionalSecondDigits'
1306
- ];
1307
- /** @internal */
1308
- function parseDateTimeArgs(...args) {
1309
- const [arg1, arg2, arg3, arg4] = args;
1310
- const options = {};
1311
- let overrides = {};
1312
- let value;
1313
- if (shared.isString(arg1)) {
1314
- // Only allow ISO strings - other date formats are often supported,
1315
- // but may cause different results in different browsers.
1316
- const matches = arg1.match(/(\d{4}-\d{2}-\d{2})(T|\s)?(.*)/);
1317
- if (!matches) {
1318
- throw createCoreError(CoreErrorCodes.INVALID_ISO_DATE_ARGUMENT);
1319
- }
1320
- // Some browsers can not parse the iso datetime separated by space,
1321
- // this is a compromise solution by replace the 'T'/' ' with 'T'
1322
- const dateTime = matches[3]
1323
- ? matches[3].trim().startsWith('T')
1324
- ? `${matches[1].trim()}${matches[3].trim()}`
1325
- : `${matches[1].trim()}T${matches[3].trim()}`
1326
- : matches[1].trim();
1327
- value = new Date(dateTime);
1328
- try {
1329
- // This will fail if the date is not valid
1330
- value.toISOString();
1331
- }
1332
- catch (e) {
1333
- throw createCoreError(CoreErrorCodes.INVALID_ISO_DATE_ARGUMENT);
1334
- }
1335
- }
1336
- else if (shared.isDate(arg1)) {
1337
- if (isNaN(arg1.getTime())) {
1338
- throw createCoreError(CoreErrorCodes.INVALID_DATE_ARGUMENT);
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;
1339
1301
  }
1340
- value = arg1;
1341
1302
  }
1342
- else if (shared.isNumber(arg1)) {
1343
- value = arg1;
1303
+ // checking message format and target locale
1304
+ if (!resolvedMessage &&
1305
+ (!(shared.isString(format) ||
1306
+ isMessageAST(format) ||
1307
+ isMessageFunction(format)) ||
1308
+ !shared.isString(targetLocale))) {
1309
+ return unresolving ? NOT_REOSLVED : key;
1344
1310
  }
1345
- else {
1346
- throw createCoreError(CoreErrorCodes.INVALID_ARGUMENT);
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;
1347
1323
  }
1348
- if (shared.isString(arg2)) {
1349
- options.key = arg2;
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;
1333
+ }
1334
+ function escapeParams(options) {
1335
+ if (shared.isArray(options.list)) {
1336
+ options.list = options.list.map(item => shared.isString(item) ? shared.escapeHtml(item) : item);
1350
1337
  }
1351
- else if (shared.isPlainObject(arg2)) {
1352
- Object.keys(arg2).forEach(key => {
1353
- if (DATETIME_FORMAT_OPTIONS_KEYS.includes(key)) {
1354
- overrides[key] = arg2[key];
1355
- }
1356
- else {
1357
- 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]);
1358
1342
  }
1359
1343
  });
1360
1344
  }
1361
- if (shared.isString(arg3)) {
1362
- options.locale = arg3;
1363
- }
1364
- else if (shared.isPlainObject(arg3)) {
1365
- overrides = arg3;
1366
- }
1367
- if (shared.isPlainObject(arg4)) {
1368
- overrides = arg4;
1369
- }
1370
- return [options.key || '', value, options, overrides];
1371
- }
1372
- /** @internal */
1373
- function clearDateTimeFormat(ctx, locale, format) {
1374
- const context = ctx;
1375
- for (const key in format) {
1376
- const id = `${locale}__${key}`;
1377
- if (!context.__datetimeFormatters.has(id)) {
1378
- continue;
1379
- }
1380
- context.__datetimeFormatters.delete(id);
1381
- }
1382
1345
  }
1383
-
1384
- // implementation of `number` function
1385
- function number(context, ...args) {
1386
- const { numberFormats, unresolving, fallbackLocale, onWarn, localeFallbacker } = context;
1387
- const { __numberFormatters } = context;
1388
- const [key, value, options, overrides] = parseNumberArgs(...args);
1389
- const missingWarn = shared.isBoolean(options.missingWarn)
1390
- ? options.missingWarn
1391
- : context.missingWarn;
1392
- shared.isBoolean(options.fallbackWarn)
1393
- ? options.fallbackWarn
1394
- : context.fallbackWarn;
1395
- const part = !!options.part;
1396
- const locale = getLocale(context, options);
1397
- const locales = localeFallbacker(context, // eslint-disable-line @typescript-eslint/no-explicit-any
1398
- fallbackLocale, locale);
1399
- if (!shared.isString(key) || key === '') {
1400
- return new Intl.NumberFormat(locale, overrides).format(value);
1401
- }
1402
- // resolve format
1403
- 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 = {};
1404
1350
  let targetLocale;
1405
1351
  let format = null;
1406
- const type = 'number format';
1352
+ const type = 'translate';
1407
1353
  for (let i = 0; i < locales.length; i++) {
1408
1354
  targetLocale = locales[i];
1409
- numberFormat =
1410
- numberFormats[targetLocale] || {};
1411
- format = numberFormat[key];
1412
- 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)) {
1413
1362
  break;
1414
- handleMissing(context, key, targetLocale, missingWarn, type); // eslint-disable-line @typescript-eslint/no-explicit-any
1415
- }
1416
- // checking format and target locale
1417
- if (!shared.isPlainObject(format) || !shared.isString(targetLocale)) {
1418
- 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
+ }
1419
1371
  }
1420
- let id = `${targetLocale}__${key}`;
1421
- if (!shared.isEmptyObject(overrides)) {
1422
- 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;
1423
1381
  }
1424
- let formatter = __numberFormatters.get(id);
1425
- if (!formatter) {
1426
- formatter = new Intl.NumberFormat(targetLocale, shared.assign({}, format, overrides));
1427
- __numberFormatters.set(id, formatter);
1382
+ if (messageCompiler == null) {
1383
+ const msg = (() => format);
1384
+ msg.locale = targetLocale;
1385
+ msg.key = key;
1386
+ return msg;
1428
1387
  }
1429
- 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;
1430
1397
  }
1431
1398
  /** @internal */
1432
- const NUMBER_FORMAT_OPTIONS_KEYS = [
1433
- 'localeMatcher',
1434
- 'style',
1435
- 'currency',
1436
- 'currencyDisplay',
1437
- 'currencySign',
1438
- 'useGrouping',
1439
- 'minimumIntegerDigits',
1440
- 'minimumFractionDigits',
1441
- 'maximumFractionDigits',
1442
- 'minimumSignificantDigits',
1443
- 'maximumSignificantDigits',
1444
- 'compactDisplay',
1445
- 'notation',
1446
- 'signDisplay',
1447
- 'unit',
1448
- 'unitDisplay',
1449
- 'roundingMode',
1450
- 'roundingPriority',
1451
- 'roundingIncrement',
1452
- 'trailingZeroDisplay'
1453
- ];
1454
- /** @internal */
1455
- function parseNumberArgs(...args) {
1456
- const [arg1, arg2, arg3, arg4] = args;
1399
+ function parseTranslateArgs(...args) {
1400
+ const [arg1, arg2, arg3] = args;
1457
1401
  const options = {};
1458
- let overrides = {};
1459
- if (!shared.isNumber(arg1)) {
1402
+ if (!shared.isString(arg1) &&
1403
+ !shared.isNumber(arg1) &&
1404
+ !isMessageFunction(arg1) &&
1405
+ !isMessageAST(arg1)) {
1460
1406
  throw createCoreError(CoreErrorCodes.INVALID_ARGUMENT);
1461
1407
  }
1462
- const value = arg1;
1463
- if (shared.isString(arg2)) {
1464
- 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;
1465
1416
  }
1466
- else if (shared.isPlainObject(arg2)) {
1467
- Object.keys(arg2).forEach(key => {
1468
- if (NUMBER_FORMAT_OPTIONS_KEYS.includes(key)) {
1469
- overrides[key] = arg2[key];
1470
- }
1471
- else {
1472
- options[key] = arg2[key];
1473
- }
1474
- });
1417
+ else if (shared.isString(arg2)) {
1418
+ options.default = arg2;
1475
1419
  }
1476
- if (shared.isString(arg3)) {
1477
- options.locale = arg3;
1420
+ else if (shared.isPlainObject(arg2) && !shared.isEmptyObject(arg2)) {
1421
+ options.named = arg2;
1478
1422
  }
1479
- else if (shared.isPlainObject(arg3)) {
1480
- overrides = arg3;
1423
+ else if (shared.isArray(arg2)) {
1424
+ options.list = arg2;
1481
1425
  }
1482
- if (shared.isPlainObject(arg4)) {
1483
- overrides = arg4;
1426
+ if (shared.isNumber(arg3)) {
1427
+ options.plural = arg3;
1484
1428
  }
1485
- 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];
1486
1436
  }
1487
- /** @internal */
1488
- function clearNumberFormat(ctx, locale, format) {
1489
- const context = ctx;
1490
- for (const key in format) {
1491
- const id = `${locale}__${key}`;
1492
- if (!context.__numberFormatters.has(id)) {
1493
- 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);
1494
1460
  }
1495
- 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;
1496
1493
  }
1494
+ if (shared.isNumber(options.plural)) {
1495
+ ctxOptions.pluralIndex = options.plural;
1496
+ }
1497
+ return ctxOptions;
1497
1498
  }
1498
1499
 
1499
1500
  exports.CompileErrorCodes = messageCompiler.CompileErrorCodes;