@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,10 +1,10 @@
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
  */
6
- import { getGlobalThis, isObject, isFunction, isString, isNumber, isPlainObject, assign, join, toDisplayString, isArray, format as format$1, isPromise, isBoolean, warn, isRegExp, warnOnce, escapeHtml, inBrowser, mark, measure, isEmptyObject, generateCodeFrame, generateFormatCacheKey, isDate } from '@intlify/shared';
7
- import { COMPILE_ERROR_CODES_EXTEND_POINT, createCompileError, detectHtmlTag, defaultOnError, baseCompile as baseCompile$1 } from '@intlify/message-compiler';
6
+ import { getGlobalThis, isObject, isString, isBoolean, warn, format as format$1, isFunction, isPromise, isArray, isPlainObject, assign, isRegExp, warnOnce, isEmptyObject, isDate, isNumber, join, toDisplayString, escapeHtml, inBrowser, mark, measure, generateCodeFrame, generateFormatCacheKey } from '@intlify/shared';
7
+ import { detectHtmlTag, defaultOnError, baseCompile as baseCompile$1, COMPILE_ERROR_CODES_EXTEND_POINT, createCompileError } from '@intlify/message-compiler';
8
8
  export { CompileErrorCodes, createCompileError } from '@intlify/message-compiler';
9
9
 
10
10
  /**
@@ -20,402 +20,147 @@ function initFeatureFlags() {
20
20
  }
21
21
  }
22
22
 
23
- const pathStateMachine = [];
24
- pathStateMachine[0 /* States.BEFORE_PATH */] = {
25
- ["w" /* PathCharTypes.WORKSPACE */]: [0 /* States.BEFORE_PATH */],
26
- ["i" /* PathCharTypes.IDENT */]: [3 /* States.IN_IDENT */, 0 /* Actions.APPEND */],
27
- ["[" /* PathCharTypes.LEFT_BRACKET */]: [4 /* States.IN_SUB_PATH */],
28
- ["o" /* PathCharTypes.END_OF_FAIL */]: [7 /* States.AFTER_PATH */]
29
- };
30
- pathStateMachine[1 /* States.IN_PATH */] = {
31
- ["w" /* PathCharTypes.WORKSPACE */]: [1 /* States.IN_PATH */],
32
- ["." /* PathCharTypes.DOT */]: [2 /* States.BEFORE_IDENT */],
33
- ["[" /* PathCharTypes.LEFT_BRACKET */]: [4 /* States.IN_SUB_PATH */],
34
- ["o" /* PathCharTypes.END_OF_FAIL */]: [7 /* States.AFTER_PATH */]
35
- };
36
- pathStateMachine[2 /* States.BEFORE_IDENT */] = {
37
- ["w" /* PathCharTypes.WORKSPACE */]: [2 /* States.BEFORE_IDENT */],
38
- ["i" /* PathCharTypes.IDENT */]: [3 /* States.IN_IDENT */, 0 /* Actions.APPEND */],
39
- ["0" /* PathCharTypes.ZERO */]: [3 /* States.IN_IDENT */, 0 /* Actions.APPEND */]
40
- };
41
- pathStateMachine[3 /* States.IN_IDENT */] = {
42
- ["i" /* PathCharTypes.IDENT */]: [3 /* States.IN_IDENT */, 0 /* Actions.APPEND */],
43
- ["0" /* PathCharTypes.ZERO */]: [3 /* States.IN_IDENT */, 0 /* Actions.APPEND */],
44
- ["w" /* PathCharTypes.WORKSPACE */]: [1 /* States.IN_PATH */, 1 /* Actions.PUSH */],
45
- ["." /* PathCharTypes.DOT */]: [2 /* States.BEFORE_IDENT */, 1 /* Actions.PUSH */],
46
- ["[" /* PathCharTypes.LEFT_BRACKET */]: [4 /* States.IN_SUB_PATH */, 1 /* Actions.PUSH */],
47
- ["o" /* PathCharTypes.END_OF_FAIL */]: [7 /* States.AFTER_PATH */, 1 /* Actions.PUSH */]
48
- };
49
- pathStateMachine[4 /* States.IN_SUB_PATH */] = {
50
- ["'" /* PathCharTypes.SINGLE_QUOTE */]: [5 /* States.IN_SINGLE_QUOTE */, 0 /* Actions.APPEND */],
51
- ["\"" /* PathCharTypes.DOUBLE_QUOTE */]: [6 /* States.IN_DOUBLE_QUOTE */, 0 /* Actions.APPEND */],
52
- ["[" /* PathCharTypes.LEFT_BRACKET */]: [
53
- 4 /* States.IN_SUB_PATH */,
54
- 2 /* Actions.INC_SUB_PATH_DEPTH */
55
- ],
56
- ["]" /* PathCharTypes.RIGHT_BRACKET */]: [1 /* States.IN_PATH */, 3 /* Actions.PUSH_SUB_PATH */],
57
- ["o" /* PathCharTypes.END_OF_FAIL */]: 8 /* States.ERROR */,
58
- ["l" /* PathCharTypes.ELSE */]: [4 /* States.IN_SUB_PATH */, 0 /* Actions.APPEND */]
59
- };
60
- pathStateMachine[5 /* States.IN_SINGLE_QUOTE */] = {
61
- ["'" /* PathCharTypes.SINGLE_QUOTE */]: [4 /* States.IN_SUB_PATH */, 0 /* Actions.APPEND */],
62
- ["o" /* PathCharTypes.END_OF_FAIL */]: 8 /* States.ERROR */,
63
- ["l" /* PathCharTypes.ELSE */]: [5 /* States.IN_SINGLE_QUOTE */, 0 /* Actions.APPEND */]
64
- };
65
- pathStateMachine[6 /* States.IN_DOUBLE_QUOTE */] = {
66
- ["\"" /* PathCharTypes.DOUBLE_QUOTE */]: [4 /* States.IN_SUB_PATH */, 0 /* Actions.APPEND */],
67
- ["o" /* PathCharTypes.END_OF_FAIL */]: 8 /* States.ERROR */,
68
- ["l" /* PathCharTypes.ELSE */]: [6 /* States.IN_DOUBLE_QUOTE */, 0 /* Actions.APPEND */]
69
- };
70
- /**
71
- * Check if an expression is a literal value.
72
- */
73
- const literalValueRE = /^\s?(?:true|false|-?[\d.]+|'[^']*'|"[^"]*")\s?$/;
74
- function isLiteral(exp) {
75
- return literalValueRE.test(exp);
76
- }
77
- /**
78
- * Strip quotes from a string
79
- */
80
- function stripQuotes(str) {
81
- const a = str.charCodeAt(0);
82
- const b = str.charCodeAt(str.length - 1);
83
- return a === b && (a === 0x22 || a === 0x27) ? str.slice(1, -1) : str;
23
+ function format(ast) {
24
+ const msg = (ctx) => formatParts(ctx, ast);
25
+ return msg;
84
26
  }
85
- /**
86
- * Determine the type of a character in a keypath.
87
- */
88
- function getPathCharType(ch) {
89
- if (ch === undefined || ch === null) {
90
- return "o" /* PathCharTypes.END_OF_FAIL */;
27
+ function formatParts(ctx, ast) {
28
+ const body = ast.b || ast.body;
29
+ if ((body.t || body.type) === 1 /* NodeTypes.Plural */) {
30
+ const plural = body;
31
+ const cases = plural.c || plural.cases;
32
+ return ctx.plural(cases.reduce((messages, c) => [
33
+ ...messages,
34
+ formatMessageParts(ctx, c)
35
+ ], []));
91
36
  }
92
- const code = ch.charCodeAt(0);
93
- switch (code) {
94
- case 0x5b: // [
95
- case 0x5d: // ]
96
- case 0x2e: // .
97
- case 0x22: // "
98
- case 0x27: // '
99
- return ch;
100
- case 0x5f: // _
101
- case 0x24: // $
102
- case 0x2d: // -
103
- return "i" /* PathCharTypes.IDENT */;
104
- case 0x09: // Tab (HT)
105
- case 0x0a: // Newline (LF)
106
- case 0x0d: // Return (CR)
107
- case 0xa0: // No-break space (NBSP)
108
- case 0xfeff: // Byte Order Mark (BOM)
109
- case 0x2028: // Line Separator (LS)
110
- case 0x2029: // Paragraph Separator (PS)
111
- return "w" /* PathCharTypes.WORKSPACE */;
37
+ else {
38
+ return formatMessageParts(ctx, body);
112
39
  }
113
- return "i" /* PathCharTypes.IDENT */;
114
40
  }
115
- /**
116
- * Format a subPath, return its plain form if it is
117
- * a literal string or number. Otherwise prepend the
118
- * dynamic indicator (*).
119
- */
120
- function formatSubPath(path) {
121
- const trimmed = path.trim();
122
- // invalid leading 0
123
- if (path.charAt(0) === '0' && isNaN(parseInt(path))) {
124
- return false;
41
+ function formatMessageParts(ctx, node) {
42
+ const _static = node.s || node.static;
43
+ if (_static) {
44
+ return ctx.type === 'text'
45
+ ? _static
46
+ : ctx.normalize([_static]);
47
+ }
48
+ else {
49
+ const messages = (node.i || node.items).reduce((acm, c) => [...acm, formatMessagePart(ctx, c)], []);
50
+ return ctx.normalize(messages);
125
51
  }
126
- return isLiteral(trimmed)
127
- ? stripQuotes(trimmed)
128
- : "*" /* PathCharTypes.ASTARISK */ + trimmed;
129
52
  }
130
- /**
131
- * Parse a string path into an array of segments
132
- */
133
- function parse(path) {
134
- const keys = [];
135
- let index = -1;
136
- let mode = 0 /* States.BEFORE_PATH */;
137
- let subPathDepth = 0;
138
- let c;
139
- let key; // eslint-disable-line
140
- let newChar;
141
- let type;
142
- let transition;
143
- let action;
144
- let typeMap;
145
- const actions = [];
146
- actions[0 /* Actions.APPEND */] = () => {
147
- if (key === undefined) {
148
- key = newChar;
149
- }
150
- else {
151
- key += newChar;
152
- }
153
- };
154
- actions[1 /* Actions.PUSH */] = () => {
155
- if (key !== undefined) {
156
- keys.push(key);
157
- key = undefined;
158
- }
159
- };
160
- actions[2 /* Actions.INC_SUB_PATH_DEPTH */] = () => {
161
- actions[0 /* Actions.APPEND */]();
162
- subPathDepth++;
163
- };
164
- actions[3 /* Actions.PUSH_SUB_PATH */] = () => {
165
- if (subPathDepth > 0) {
166
- subPathDepth--;
167
- mode = 4 /* States.IN_SUB_PATH */;
168
- actions[0 /* Actions.APPEND */]();
53
+ function formatMessagePart(ctx, node) {
54
+ const type = node.t || node.type;
55
+ switch (type) {
56
+ case 3 /* NodeTypes.Text */: {
57
+ const text = node;
58
+ return (text.v || text.value);
169
59
  }
170
- else {
171
- subPathDepth = 0;
172
- if (key === undefined) {
173
- return false;
174
- }
175
- key = formatSubPath(key);
176
- if (key === false) {
177
- return false;
178
- }
179
- else {
180
- actions[1 /* Actions.PUSH */]();
181
- }
60
+ case 9 /* NodeTypes.Literal */: {
61
+ const literal = node;
62
+ return (literal.v || literal.value);
182
63
  }
183
- };
184
- function maybeUnescapeQuote() {
185
- const nextChar = path[index + 1];
186
- if ((mode === 5 /* States.IN_SINGLE_QUOTE */ &&
187
- nextChar === "'" /* PathCharTypes.SINGLE_QUOTE */) ||
188
- (mode === 6 /* States.IN_DOUBLE_QUOTE */ &&
189
- nextChar === "\"" /* PathCharTypes.DOUBLE_QUOTE */)) {
190
- index++;
191
- newChar = '\\' + nextChar;
192
- actions[0 /* Actions.APPEND */]();
193
- return true;
64
+ case 4 /* NodeTypes.Named */: {
65
+ const named = node;
66
+ return ctx.interpolate(ctx.named(named.k || named.key));
194
67
  }
195
- }
196
- while (mode !== null) {
197
- index++;
198
- c = path[index];
199
- if (c === '\\' && maybeUnescapeQuote()) {
200
- continue;
68
+ case 5 /* NodeTypes.List */: {
69
+ const list = node;
70
+ return ctx.interpolate(ctx.list(list.i != null ? list.i : list.index));
201
71
  }
202
- type = getPathCharType(c);
203
- typeMap = pathStateMachine[mode];
204
- transition = typeMap[type] || typeMap["l" /* PathCharTypes.ELSE */] || 8 /* States.ERROR */;
205
- // check parse error
206
- if (transition === 8 /* States.ERROR */) {
207
- return;
72
+ case 6 /* NodeTypes.Linked */: {
73
+ const linked = node;
74
+ const modifier = linked.m || linked.modifier;
75
+ return ctx.linked(formatMessagePart(ctx, linked.k || linked.key), modifier ? formatMessagePart(ctx, modifier) : undefined, ctx.type);
208
76
  }
209
- mode = transition[0];
210
- if (transition[1] !== undefined) {
211
- action = actions[transition[1]];
212
- if (action) {
213
- newChar = c;
214
- if (action() === false) {
215
- return;
216
- }
217
- }
77
+ case 7 /* NodeTypes.LinkedKey */: {
78
+ const linkedKey = node;
79
+ return (linkedKey.v || linkedKey.value);
218
80
  }
219
- // check parse finish
220
- if (mode === 7 /* States.AFTER_PATH */) {
221
- return keys;
81
+ case 8 /* NodeTypes.LinkedModifier */: {
82
+ const linkedModifier = node;
83
+ return (linkedModifier.v || linkedModifier.value);
222
84
  }
85
+ default:
86
+ throw new Error(`unhandled node type on format message part: ${type}`);
223
87
  }
224
88
  }
225
- // path token cache
226
- const cache = new Map();
227
- /**
228
- * key-value message resolver
229
- *
230
- * @remarks
231
- * Resolves messages with the key-value structure. Note that messages with a hierarchical structure such as objects cannot be resolved
232
- *
233
- * @param obj - A target object to be resolved with path
234
- * @param path - A {@link Path | path} to resolve the value of message
235
- *
236
- * @returns A resolved {@link PathValue | path value}
237
- *
238
- * @VueI18nGeneral
239
- */
240
- function resolveWithKeyValue(obj, path) {
241
- return isObject(obj) ? obj[path] : null;
242
- }
243
- /**
244
- * message resolver
245
- *
246
- * @remarks
247
- * Resolves messages. messages with a hierarchical structure such as objects can be resolved. This resolver is used in VueI18n as default.
248
- *
249
- * @param obj - A target object to be resolved with path
250
- * @param path - A {@link Path | path} to resolve the value of message
251
- *
252
- * @returns A resolved {@link PathValue | path value}
253
- *
254
- * @VueI18nGeneral
255
- */
256
- function resolveValue(obj, path) {
257
- // check object
258
- if (!isObject(obj)) {
259
- return null;
260
- }
261
- // parse path
262
- let hit = cache.get(path);
263
- if (!hit) {
264
- hit = parse(path);
265
- if (hit) {
266
- cache.set(path, hit);
267
- }
268
- }
269
- // check hit
270
- if (!hit) {
271
- return null;
272
- }
273
- // resolve path value
274
- const len = hit.length;
275
- let last = obj;
276
- let i = 0;
277
- while (i < len) {
278
- const val = last[hit[i]];
279
- if (val === undefined) {
280
- return null;
281
- }
282
- if (isFunction(last)) {
283
- return null;
284
- }
285
- last = val;
286
- i++;
287
- }
288
- return last;
289
- }
290
89
 
291
- const DEFAULT_MODIFIER = (str) => str;
292
- const DEFAULT_MESSAGE = (ctx) => ''; // eslint-disable-line
293
- const DEFAULT_MESSAGE_DATA_TYPE = 'text';
294
- const DEFAULT_NORMALIZE = (values) => values.length === 0 ? '' : join(values);
295
- const DEFAULT_INTERPOLATE = toDisplayString;
296
- function pluralDefault(choice, choicesLength) {
297
- choice = Math.abs(choice);
298
- if (choicesLength === 2) {
299
- // prettier-ignore
300
- return choice
301
- ? choice > 1
302
- ? 1
303
- : 0
304
- : 1;
90
+ const WARN_MESSAGE = `Detected HTML in '{source}' message. Recommend not using HTML messages to avoid XSS.`;
91
+ function checkHtmlMessage(source, warnHtmlMessage) {
92
+ if (warnHtmlMessage && detectHtmlTag(source)) {
93
+ warn(format$1(WARN_MESSAGE, { source }));
305
94
  }
306
- return choice ? Math.min(choice, 2) : 0;
307
- }
308
- function getPluralIndex(options) {
309
- // prettier-ignore
310
- const index = isNumber(options.pluralIndex)
311
- ? options.pluralIndex
312
- : -1;
313
- // prettier-ignore
314
- return options.named && (isNumber(options.named.count) || isNumber(options.named.n))
315
- ? isNumber(options.named.count)
316
- ? options.named.count
317
- : isNumber(options.named.n)
318
- ? options.named.n
319
- : index
320
- : index;
321
95
  }
322
- function normalizeNamed(pluralIndex, props) {
323
- if (!props.count) {
324
- props.count = pluralIndex;
325
- }
326
- if (!props.n) {
327
- props.n = pluralIndex;
328
- }
96
+ const defaultOnCacheKey = (message) => message;
97
+ let compileCache = Object.create(null);
98
+ function clearCompileCache() {
99
+ compileCache = Object.create(null);
329
100
  }
330
- function createMessageContext(options = {}) {
331
- const locale = options.locale;
332
- const pluralIndex = getPluralIndex(options);
333
- const pluralRule = isObject(options.pluralRules) &&
334
- isString(locale) &&
335
- isFunction(options.pluralRules[locale])
336
- ? options.pluralRules[locale]
337
- : pluralDefault;
338
- const orgPluralRule = isObject(options.pluralRules) &&
339
- isString(locale) &&
340
- isFunction(options.pluralRules[locale])
341
- ? pluralDefault
342
- : undefined;
343
- const plural = (messages) => {
344
- return messages[pluralRule(pluralIndex, messages.length, orgPluralRule)];
101
+ const isMessageAST = (val) => isObject(val) &&
102
+ (val.t === 0 || val.type === 0) &&
103
+ ('b' in val || 'body' in val);
104
+ function baseCompile(message, options = {}) {
105
+ // error detecting on compile
106
+ let detectError = false;
107
+ const onError = options.onError || defaultOnError;
108
+ options.onError = (err) => {
109
+ detectError = true;
110
+ onError(err);
345
111
  };
346
- const _list = options.list || [];
347
- const list = (index) => _list[index];
348
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
349
- const _named = options.named || {};
350
- isNumber(options.pluralIndex) && normalizeNamed(pluralIndex, _named);
351
- const named = (key) => _named[key];
352
- function message(key, useLinked) {
353
- // prettier-ignore
354
- const msg = isFunction(options.messages)
355
- ? options.messages(key, !!useLinked)
356
- : isObject(options.messages)
357
- ? options.messages[key]
358
- : false;
359
- return !msg
360
- ? options.parent
361
- ? options.parent.message(key) // resolve from parent messages
362
- : DEFAULT_MESSAGE
112
+ // compile with mesasge-compiler
113
+ return { ...baseCompile$1(message, options), detectError };
114
+ }
115
+ /* #__NO_SIDE_EFFECTS__ */
116
+ function compile(message, context) {
117
+ if ((!__INTLIFY_DROP_MESSAGE_COMPILER__) &&
118
+ isString(message)) {
119
+ // check HTML message
120
+ const warnHtmlMessage = isBoolean(context.warnHtmlMessage)
121
+ ? context.warnHtmlMessage
122
+ : true;
123
+ (process.env.NODE_ENV !== 'production') && checkHtmlMessage(message, warnHtmlMessage);
124
+ // check caches
125
+ const onCacheKey = context.onCacheKey || defaultOnCacheKey;
126
+ const cacheKey = onCacheKey(message);
127
+ const cached = compileCache[cacheKey];
128
+ if (cached) {
129
+ return cached;
130
+ }
131
+ // compile with JIT mode
132
+ const { ast, detectError } = baseCompile(message, {
133
+ ...context,
134
+ location: (process.env.NODE_ENV !== 'production'),
135
+ jit: true
136
+ });
137
+ // compose message function from AST
138
+ const msg = format(ast);
139
+ // if occurred compile error, don't cache
140
+ return !detectError
141
+ ? (compileCache[cacheKey] = msg)
363
142
  : msg;
364
143
  }
365
- const _modifier = (name) => options.modifiers
366
- ? options.modifiers[name]
367
- : DEFAULT_MODIFIER;
368
- const normalize = isPlainObject(options.processor) && isFunction(options.processor.normalize)
369
- ? options.processor.normalize
370
- : DEFAULT_NORMALIZE;
371
- const interpolate = isPlainObject(options.processor) &&
372
- isFunction(options.processor.interpolate)
373
- ? options.processor.interpolate
374
- : DEFAULT_INTERPOLATE;
375
- const type = isPlainObject(options.processor) && isString(options.processor.type)
376
- ? options.processor.type
377
- : DEFAULT_MESSAGE_DATA_TYPE;
378
- const linked = (key, ...args) => {
379
- const [arg1, arg2] = args;
380
- let type = 'text';
381
- let modifier = '';
382
- if (args.length === 1) {
383
- if (isObject(arg1)) {
384
- modifier = arg1.modifier || modifier;
385
- type = arg1.type || type;
386
- }
387
- else if (isString(arg1)) {
388
- modifier = arg1 || modifier;
389
- }
144
+ else {
145
+ if ((process.env.NODE_ENV !== 'production') && !isMessageAST(message)) {
146
+ warn(`the message that is resolve with key '${context.key}' is not supported for jit compilation`);
147
+ return (() => message);
390
148
  }
391
- else if (args.length === 2) {
392
- if (isString(arg1)) {
393
- modifier = arg1 || modifier;
394
- }
395
- if (isString(arg2)) {
396
- type = arg2 || type;
149
+ // AST case (passed from bundler)
150
+ const cacheKey = message.cacheKey;
151
+ if (cacheKey) {
152
+ const cached = compileCache[cacheKey];
153
+ if (cached) {
154
+ return cached;
397
155
  }
156
+ // compose message function from message (AST)
157
+ return (compileCache[cacheKey] =
158
+ format(message));
398
159
  }
399
- const ret = message(key, true)(ctx);
400
- const msg =
401
- // The message in vnode resolved with linked are returned as an array by processor.nomalize
402
- type === 'vnode' && isArray(ret) && modifier
403
- ? ret[0]
404
- : ret;
405
- return modifier ? _modifier(modifier)(msg, type) : msg;
406
- };
407
- const ctx = {
408
- ["list" /* HelperNameMap.LIST */]: list,
409
- ["named" /* HelperNameMap.NAMED */]: named,
410
- ["plural" /* HelperNameMap.PLURAL */]: plural,
411
- ["linked" /* HelperNameMap.LINKED */]: linked,
412
- ["message" /* HelperNameMap.MESSAGE */]: message,
413
- ["type" /* HelperNameMap.TYPE */]: type,
414
- ["interpolate" /* HelperNameMap.INTERPOLATE */]: interpolate,
415
- ["normalize" /* HelperNameMap.NORMALIZE */]: normalize,
416
- ["values" /* HelperNameMap.VALUES */]: assign({}, _list, _named)
417
- };
418
- return ctx;
160
+ else {
161
+ return format(message);
162
+ }
163
+ }
419
164
  }
420
165
 
421
166
  let devtools = null;
@@ -441,30 +186,6 @@ function createDevToolsHook(hook) {
441
186
  return (payloads) => devtools && devtools.emit(hook, payloads);
442
187
  }
443
188
 
444
- const CoreWarnCodes = {
445
- NOT_FOUND_KEY: 1,
446
- FALLBACK_TO_TRANSLATE: 2,
447
- CANNOT_FORMAT_NUMBER: 3,
448
- FALLBACK_TO_NUMBER_FORMAT: 4,
449
- CANNOT_FORMAT_DATE: 5,
450
- FALLBACK_TO_DATE_FORMAT: 6,
451
- EXPERIMENTAL_CUSTOM_MESSAGE_COMPILER: 7
452
- };
453
- const CORE_WARN_CODES_EXTEND_POINT = 8;
454
- /** @internal */
455
- const warnMessages = {
456
- [CoreWarnCodes.NOT_FOUND_KEY]: `Not found '{key}' key in '{locale}' locale messages.`,
457
- [CoreWarnCodes.FALLBACK_TO_TRANSLATE]: `Fall back to translate '{key}' key with '{target}' locale.`,
458
- [CoreWarnCodes.CANNOT_FORMAT_NUMBER]: `Cannot format a number value due to not supported Intl.NumberFormat.`,
459
- [CoreWarnCodes.FALLBACK_TO_NUMBER_FORMAT]: `Fall back to number format '{key}' key with '{target}' locale.`,
460
- [CoreWarnCodes.CANNOT_FORMAT_DATE]: `Cannot format a date value due to not supported Intl.DateTimeFormat.`,
461
- [CoreWarnCodes.FALLBACK_TO_DATE_FORMAT]: `Fall back to datetime format '{key}' key with '{target}' locale.`,
462
- [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.`
463
- };
464
- function getWarnMessage(code, ...args) {
465
- return format$1(warnMessages[code], ...args);
466
- }
467
-
468
189
  const CoreErrorCodes = {
469
190
  INVALID_ARGUMENT: COMPILE_ERROR_CODES_EXTEND_POINT, // 17
470
191
  INVALID_DATE_ARGUMENT: 18,
@@ -638,66 +359,358 @@ function appendItemToChain(chain, target, blocks) {
638
359
  return follow;
639
360
  }
640
361
 
641
- /* eslint-disable @typescript-eslint/no-explicit-any */
362
+ const pathStateMachine = [];
363
+ pathStateMachine[0 /* States.BEFORE_PATH */] = {
364
+ ["w" /* PathCharTypes.WORKSPACE */]: [0 /* States.BEFORE_PATH */],
365
+ ["i" /* PathCharTypes.IDENT */]: [3 /* States.IN_IDENT */, 0 /* Actions.APPEND */],
366
+ ["[" /* PathCharTypes.LEFT_BRACKET */]: [4 /* States.IN_SUB_PATH */],
367
+ ["o" /* PathCharTypes.END_OF_FAIL */]: [7 /* States.AFTER_PATH */]
368
+ };
369
+ pathStateMachine[1 /* States.IN_PATH */] = {
370
+ ["w" /* PathCharTypes.WORKSPACE */]: [1 /* States.IN_PATH */],
371
+ ["." /* PathCharTypes.DOT */]: [2 /* States.BEFORE_IDENT */],
372
+ ["[" /* PathCharTypes.LEFT_BRACKET */]: [4 /* States.IN_SUB_PATH */],
373
+ ["o" /* PathCharTypes.END_OF_FAIL */]: [7 /* States.AFTER_PATH */]
374
+ };
375
+ pathStateMachine[2 /* States.BEFORE_IDENT */] = {
376
+ ["w" /* PathCharTypes.WORKSPACE */]: [2 /* States.BEFORE_IDENT */],
377
+ ["i" /* PathCharTypes.IDENT */]: [3 /* States.IN_IDENT */, 0 /* Actions.APPEND */],
378
+ ["0" /* PathCharTypes.ZERO */]: [3 /* States.IN_IDENT */, 0 /* Actions.APPEND */]
379
+ };
380
+ pathStateMachine[3 /* States.IN_IDENT */] = {
381
+ ["i" /* PathCharTypes.IDENT */]: [3 /* States.IN_IDENT */, 0 /* Actions.APPEND */],
382
+ ["0" /* PathCharTypes.ZERO */]: [3 /* States.IN_IDENT */, 0 /* Actions.APPEND */],
383
+ ["w" /* PathCharTypes.WORKSPACE */]: [1 /* States.IN_PATH */, 1 /* Actions.PUSH */],
384
+ ["." /* PathCharTypes.DOT */]: [2 /* States.BEFORE_IDENT */, 1 /* Actions.PUSH */],
385
+ ["[" /* PathCharTypes.LEFT_BRACKET */]: [4 /* States.IN_SUB_PATH */, 1 /* Actions.PUSH */],
386
+ ["o" /* PathCharTypes.END_OF_FAIL */]: [7 /* States.AFTER_PATH */, 1 /* Actions.PUSH */]
387
+ };
388
+ pathStateMachine[4 /* States.IN_SUB_PATH */] = {
389
+ ["'" /* PathCharTypes.SINGLE_QUOTE */]: [5 /* States.IN_SINGLE_QUOTE */, 0 /* Actions.APPEND */],
390
+ ["\"" /* PathCharTypes.DOUBLE_QUOTE */]: [6 /* States.IN_DOUBLE_QUOTE */, 0 /* Actions.APPEND */],
391
+ ["[" /* PathCharTypes.LEFT_BRACKET */]: [
392
+ 4 /* States.IN_SUB_PATH */,
393
+ 2 /* Actions.INC_SUB_PATH_DEPTH */
394
+ ],
395
+ ["]" /* PathCharTypes.RIGHT_BRACKET */]: [1 /* States.IN_PATH */, 3 /* Actions.PUSH_SUB_PATH */],
396
+ ["o" /* PathCharTypes.END_OF_FAIL */]: 8 /* States.ERROR */,
397
+ ["l" /* PathCharTypes.ELSE */]: [4 /* States.IN_SUB_PATH */, 0 /* Actions.APPEND */]
398
+ };
399
+ pathStateMachine[5 /* States.IN_SINGLE_QUOTE */] = {
400
+ ["'" /* PathCharTypes.SINGLE_QUOTE */]: [4 /* States.IN_SUB_PATH */, 0 /* Actions.APPEND */],
401
+ ["o" /* PathCharTypes.END_OF_FAIL */]: 8 /* States.ERROR */,
402
+ ["l" /* PathCharTypes.ELSE */]: [5 /* States.IN_SINGLE_QUOTE */, 0 /* Actions.APPEND */]
403
+ };
404
+ pathStateMachine[6 /* States.IN_DOUBLE_QUOTE */] = {
405
+ ["\"" /* PathCharTypes.DOUBLE_QUOTE */]: [4 /* States.IN_SUB_PATH */, 0 /* Actions.APPEND */],
406
+ ["o" /* PathCharTypes.END_OF_FAIL */]: 8 /* States.ERROR */,
407
+ ["l" /* PathCharTypes.ELSE */]: [6 /* States.IN_DOUBLE_QUOTE */, 0 /* Actions.APPEND */]
408
+ };
642
409
  /**
643
- * Intlify core-base version
644
- * @internal
410
+ * Check if an expression is a literal value.
645
411
  */
646
- const VERSION = '10.0.0-beta.6';
647
- const NOT_REOSLVED = -1;
648
- const DEFAULT_LOCALE = 'en-US';
649
- const MISSING_RESOLVE_VALUE = '';
650
- const capitalize = (str) => `${str.charAt(0).toLocaleUpperCase()}${str.substr(1)}`;
651
- function getDefaultLinkedModifiers() {
652
- return {
653
- upper: (val, type) => {
654
- // prettier-ignore
655
- return type === 'text' && isString(val)
656
- ? val.toUpperCase()
657
- : type === 'vnode' && isObject(val) && '__v_isVNode' in val
658
- ? val.children.toUpperCase()
659
- : val;
660
- },
661
- lower: (val, type) => {
662
- // prettier-ignore
663
- return type === 'text' && isString(val)
664
- ? val.toLowerCase()
665
- : type === 'vnode' && isObject(val) && '__v_isVNode' in val
666
- ? val.children.toLowerCase()
667
- : val;
668
- },
669
- capitalize: (val, type) => {
670
- // prettier-ignore
671
- return (type === 'text' && isString(val)
672
- ? capitalize(val)
673
- : type === 'vnode' && isObject(val) && '__v_isVNode' in val
674
- ? capitalize(val.children)
675
- : val);
412
+ const literalValueRE = /^\s?(?:true|false|-?[\d.]+|'[^']*'|"[^"]*")\s?$/;
413
+ function isLiteral(exp) {
414
+ return literalValueRE.test(exp);
415
+ }
416
+ /**
417
+ * Strip quotes from a string
418
+ */
419
+ function stripQuotes(str) {
420
+ const a = str.charCodeAt(0);
421
+ const b = str.charCodeAt(str.length - 1);
422
+ return a === b && (a === 0x22 || a === 0x27) ? str.slice(1, -1) : str;
423
+ }
424
+ /**
425
+ * Determine the type of a character in a keypath.
426
+ */
427
+ function getPathCharType(ch) {
428
+ if (ch === undefined || ch === null) {
429
+ return "o" /* PathCharTypes.END_OF_FAIL */;
430
+ }
431
+ const code = ch.charCodeAt(0);
432
+ switch (code) {
433
+ case 0x5b: // [
434
+ case 0x5d: // ]
435
+ case 0x2e: // .
436
+ case 0x22: // "
437
+ case 0x27: // '
438
+ return ch;
439
+ case 0x5f: // _
440
+ case 0x24: // $
441
+ case 0x2d: // -
442
+ return "i" /* PathCharTypes.IDENT */;
443
+ case 0x09: // Tab (HT)
444
+ case 0x0a: // Newline (LF)
445
+ case 0x0d: // Return (CR)
446
+ case 0xa0: // No-break space (NBSP)
447
+ case 0xfeff: // Byte Order Mark (BOM)
448
+ case 0x2028: // Line Separator (LS)
449
+ case 0x2029: // Paragraph Separator (PS)
450
+ return "w" /* PathCharTypes.WORKSPACE */;
451
+ }
452
+ return "i" /* PathCharTypes.IDENT */;
453
+ }
454
+ /**
455
+ * Format a subPath, return its plain form if it is
456
+ * a literal string or number. Otherwise prepend the
457
+ * dynamic indicator (*).
458
+ */
459
+ function formatSubPath(path) {
460
+ const trimmed = path.trim();
461
+ // invalid leading 0
462
+ if (path.charAt(0) === '0' && isNaN(parseInt(path))) {
463
+ return false;
464
+ }
465
+ return isLiteral(trimmed)
466
+ ? stripQuotes(trimmed)
467
+ : "*" /* PathCharTypes.ASTARISK */ + trimmed;
468
+ }
469
+ /**
470
+ * Parse a string path into an array of segments
471
+ */
472
+ function parse(path) {
473
+ const keys = [];
474
+ let index = -1;
475
+ let mode = 0 /* States.BEFORE_PATH */;
476
+ let subPathDepth = 0;
477
+ let c;
478
+ let key; // eslint-disable-line
479
+ let newChar;
480
+ let type;
481
+ let transition;
482
+ let action;
483
+ let typeMap;
484
+ const actions = [];
485
+ actions[0 /* Actions.APPEND */] = () => {
486
+ if (key === undefined) {
487
+ key = newChar;
488
+ }
489
+ else {
490
+ key += newChar;
676
491
  }
677
492
  };
493
+ actions[1 /* Actions.PUSH */] = () => {
494
+ if (key !== undefined) {
495
+ keys.push(key);
496
+ key = undefined;
497
+ }
498
+ };
499
+ actions[2 /* Actions.INC_SUB_PATH_DEPTH */] = () => {
500
+ actions[0 /* Actions.APPEND */]();
501
+ subPathDepth++;
502
+ };
503
+ actions[3 /* Actions.PUSH_SUB_PATH */] = () => {
504
+ if (subPathDepth > 0) {
505
+ subPathDepth--;
506
+ mode = 4 /* States.IN_SUB_PATH */;
507
+ actions[0 /* Actions.APPEND */]();
508
+ }
509
+ else {
510
+ subPathDepth = 0;
511
+ if (key === undefined) {
512
+ return false;
513
+ }
514
+ key = formatSubPath(key);
515
+ if (key === false) {
516
+ return false;
517
+ }
518
+ else {
519
+ actions[1 /* Actions.PUSH */]();
520
+ }
521
+ }
522
+ };
523
+ function maybeUnescapeQuote() {
524
+ const nextChar = path[index + 1];
525
+ if ((mode === 5 /* States.IN_SINGLE_QUOTE */ &&
526
+ nextChar === "'" /* PathCharTypes.SINGLE_QUOTE */) ||
527
+ (mode === 6 /* States.IN_DOUBLE_QUOTE */ &&
528
+ nextChar === "\"" /* PathCharTypes.DOUBLE_QUOTE */)) {
529
+ index++;
530
+ newChar = '\\' + nextChar;
531
+ actions[0 /* Actions.APPEND */]();
532
+ return true;
533
+ }
534
+ }
535
+ while (mode !== null) {
536
+ index++;
537
+ c = path[index];
538
+ if (c === '\\' && maybeUnescapeQuote()) {
539
+ continue;
540
+ }
541
+ type = getPathCharType(c);
542
+ typeMap = pathStateMachine[mode];
543
+ transition = typeMap[type] || typeMap["l" /* PathCharTypes.ELSE */] || 8 /* States.ERROR */;
544
+ // check parse error
545
+ if (transition === 8 /* States.ERROR */) {
546
+ return;
547
+ }
548
+ mode = transition[0];
549
+ if (transition[1] !== undefined) {
550
+ action = actions[transition[1]];
551
+ if (action) {
552
+ newChar = c;
553
+ if (action() === false) {
554
+ return;
555
+ }
556
+ }
557
+ }
558
+ // check parse finish
559
+ if (mode === 7 /* States.AFTER_PATH */) {
560
+ return keys;
561
+ }
562
+ }
678
563
  }
679
- let _compiler;
680
- function registerMessageCompiler(compiler) {
681
- _compiler = compiler;
682
- }
683
- let _resolver;
564
+ // path token cache
565
+ const cache = new Map();
684
566
  /**
685
- * Register the message resolver
567
+ * key-value message resolver
686
568
  *
687
- * @param resolver - A {@link MessageResolver} function
569
+ * @remarks
570
+ * Resolves messages with the key-value structure. Note that messages with a hierarchical structure such as objects cannot be resolved
571
+ *
572
+ * @param obj - A target object to be resolved with path
573
+ * @param path - A {@link Path | path} to resolve the value of message
574
+ *
575
+ * @returns A resolved {@link PathValue | path value}
688
576
  *
689
577
  * @VueI18nGeneral
690
578
  */
691
- function registerMessageResolver(resolver) {
692
- _resolver = resolver;
579
+ function resolveWithKeyValue(obj, path) {
580
+ return isObject(obj) ? obj[path] : null;
693
581
  }
694
- let _fallbacker;
695
582
  /**
696
- * Register the locale fallbacker
583
+ * message resolver
697
584
  *
698
- * @param fallbacker - A {@link LocaleFallbacker} function
585
+ * @remarks
586
+ * Resolves messages. messages with a hierarchical structure such as objects can be resolved. This resolver is used in VueI18n as default.
699
587
  *
700
- * @VueI18nGeneral
588
+ * @param obj - A target object to be resolved with path
589
+ * @param path - A {@link Path | path} to resolve the value of message
590
+ *
591
+ * @returns A resolved {@link PathValue | path value}
592
+ *
593
+ * @VueI18nGeneral
594
+ */
595
+ function resolveValue(obj, path) {
596
+ // check object
597
+ if (!isObject(obj)) {
598
+ return null;
599
+ }
600
+ // parse path
601
+ let hit = cache.get(path);
602
+ if (!hit) {
603
+ hit = parse(path);
604
+ if (hit) {
605
+ cache.set(path, hit);
606
+ }
607
+ }
608
+ // check hit
609
+ if (!hit) {
610
+ return null;
611
+ }
612
+ // resolve path value
613
+ const len = hit.length;
614
+ let last = obj;
615
+ let i = 0;
616
+ while (i < len) {
617
+ const val = last[hit[i]];
618
+ if (val === undefined) {
619
+ return null;
620
+ }
621
+ if (isFunction(last)) {
622
+ return null;
623
+ }
624
+ last = val;
625
+ i++;
626
+ }
627
+ return last;
628
+ }
629
+
630
+ const CoreWarnCodes = {
631
+ NOT_FOUND_KEY: 1,
632
+ FALLBACK_TO_TRANSLATE: 2,
633
+ CANNOT_FORMAT_NUMBER: 3,
634
+ FALLBACK_TO_NUMBER_FORMAT: 4,
635
+ CANNOT_FORMAT_DATE: 5,
636
+ FALLBACK_TO_DATE_FORMAT: 6,
637
+ EXPERIMENTAL_CUSTOM_MESSAGE_COMPILER: 7
638
+ };
639
+ const CORE_WARN_CODES_EXTEND_POINT = 8;
640
+ /** @internal */
641
+ const warnMessages = {
642
+ [CoreWarnCodes.NOT_FOUND_KEY]: `Not found '{key}' key in '{locale}' locale messages.`,
643
+ [CoreWarnCodes.FALLBACK_TO_TRANSLATE]: `Fall back to translate '{key}' key with '{target}' locale.`,
644
+ [CoreWarnCodes.CANNOT_FORMAT_NUMBER]: `Cannot format a number value due to not supported Intl.NumberFormat.`,
645
+ [CoreWarnCodes.FALLBACK_TO_NUMBER_FORMAT]: `Fall back to number format '{key}' key with '{target}' locale.`,
646
+ [CoreWarnCodes.CANNOT_FORMAT_DATE]: `Cannot format a date value due to not supported Intl.DateTimeFormat.`,
647
+ [CoreWarnCodes.FALLBACK_TO_DATE_FORMAT]: `Fall back to datetime format '{key}' key with '{target}' locale.`,
648
+ [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.`
649
+ };
650
+ function getWarnMessage(code, ...args) {
651
+ return format$1(warnMessages[code], ...args);
652
+ }
653
+
654
+ /* eslint-disable @typescript-eslint/no-explicit-any */
655
+ /**
656
+ * Intlify core-base version
657
+ * @internal
658
+ */
659
+ const VERSION = '10.0.0';
660
+ const NOT_REOSLVED = -1;
661
+ const DEFAULT_LOCALE = 'en-US';
662
+ const MISSING_RESOLVE_VALUE = '';
663
+ const capitalize = (str) => `${str.charAt(0).toLocaleUpperCase()}${str.substr(1)}`;
664
+ function getDefaultLinkedModifiers() {
665
+ return {
666
+ upper: (val, type) => {
667
+ // prettier-ignore
668
+ return type === 'text' && isString(val)
669
+ ? val.toUpperCase()
670
+ : type === 'vnode' && isObject(val) && '__v_isVNode' in val
671
+ ? val.children.toUpperCase()
672
+ : val;
673
+ },
674
+ lower: (val, type) => {
675
+ // prettier-ignore
676
+ return type === 'text' && isString(val)
677
+ ? val.toLowerCase()
678
+ : type === 'vnode' && isObject(val) && '__v_isVNode' in val
679
+ ? val.children.toLowerCase()
680
+ : val;
681
+ },
682
+ capitalize: (val, type) => {
683
+ // prettier-ignore
684
+ return (type === 'text' && isString(val)
685
+ ? capitalize(val)
686
+ : type === 'vnode' && isObject(val) && '__v_isVNode' in val
687
+ ? capitalize(val.children)
688
+ : val);
689
+ }
690
+ };
691
+ }
692
+ let _compiler;
693
+ function registerMessageCompiler(compiler) {
694
+ _compiler = compiler;
695
+ }
696
+ let _resolver;
697
+ /**
698
+ * Register the message resolver
699
+ *
700
+ * @param resolver - A {@link MessageResolver} function
701
+ *
702
+ * @VueI18nGeneral
703
+ */
704
+ function registerMessageResolver(resolver) {
705
+ _resolver = resolver;
706
+ }
707
+ let _fallbacker;
708
+ /**
709
+ * Register the locale fallbacker
710
+ *
711
+ * @param fallbacker - A {@link LocaleFallbacker} function
712
+ *
713
+ * @VueI18nGeneral
701
714
  */
702
715
  function registerLocaleFallbacker(fallbacker) {
703
716
  _fallbacker = fallbacker;
@@ -811,667 +824,280 @@ function createCoreContext(options = {}) {
811
824
  messageCompiler,
812
825
  messageResolver,
813
826
  localeFallbacker,
814
- fallbackContext,
815
- onWarn,
816
- __meta
817
- };
818
- {
819
- context.datetimeFormats = datetimeFormats;
820
- context.numberFormats = numberFormats;
821
- context.__datetimeFormatters = __datetimeFormatters;
822
- context.__numberFormatters = __numberFormatters;
823
- }
824
- // for vue-devtools timeline event
825
- if ((process.env.NODE_ENV !== 'production')) {
826
- context.__v_emitter =
827
- internalOptions.__v_emitter != null
828
- ? internalOptions.__v_emitter
829
- : undefined;
830
- }
831
- // NOTE: experimental !!
832
- if ((process.env.NODE_ENV !== 'production') || __INTLIFY_PROD_DEVTOOLS__) {
833
- initI18nDevTools(context, version, __meta);
834
- }
835
- return context;
836
- }
837
- /** @internal */
838
- function isTranslateFallbackWarn(fallback, key) {
839
- return fallback instanceof RegExp ? fallback.test(key) : fallback;
840
- }
841
- /** @internal */
842
- function isTranslateMissingWarn(missing, key) {
843
- return missing instanceof RegExp ? missing.test(key) : missing;
844
- }
845
- /** @internal */
846
- function handleMissing(context, key, locale, missingWarn, type) {
847
- const { missing, onWarn } = context;
848
- // for vue-devtools timeline event
849
- if ((process.env.NODE_ENV !== 'production')) {
850
- const emitter = context.__v_emitter;
851
- if (emitter) {
852
- emitter.emit('missing', {
853
- locale,
854
- key,
855
- type,
856
- groupId: `${type}:${key}`
857
- });
858
- }
859
- }
860
- if (missing !== null) {
861
- const ret = missing(context, locale, key, type);
862
- return isString(ret) ? ret : key;
863
- }
864
- else {
865
- if ((process.env.NODE_ENV !== 'production') && isTranslateMissingWarn(missingWarn, key)) {
866
- onWarn(getWarnMessage(CoreWarnCodes.NOT_FOUND_KEY, { key, locale }));
867
- }
868
- return key;
869
- }
870
- }
871
- /** @internal */
872
- function updateFallbackLocale(ctx, locale, fallback) {
873
- const context = ctx;
874
- context.__localeChainCache = new Map();
875
- ctx.localeFallbacker(ctx, fallback, locale);
876
- }
877
- /** @internal */
878
- function isAlmostSameLocale(locale, compareLocale) {
879
- if (locale === compareLocale)
880
- return false;
881
- return locale.split('-')[0] === compareLocale.split('-')[0];
882
- }
883
- /** @internal */
884
- function isImplicitFallback(targetLocale, locales) {
885
- const index = locales.indexOf(targetLocale);
886
- if (index === -1) {
887
- return false;
888
- }
889
- for (let i = index + 1; i < locales.length; i++) {
890
- if (isAlmostSameLocale(targetLocale, locales[i])) {
891
- return true;
892
- }
893
- }
894
- return false;
895
- }
896
- /* eslint-enable @typescript-eslint/no-explicit-any */
897
-
898
- function format(ast) {
899
- const msg = (ctx) => formatParts(ctx, ast);
900
- return msg;
901
- }
902
- function formatParts(ctx, ast) {
903
- const body = ast.b || ast.body;
904
- if ((body.t || body.type) === 1 /* NodeTypes.Plural */) {
905
- const plural = body;
906
- const cases = plural.c || plural.cases;
907
- return ctx.plural(cases.reduce((messages, c) => [
908
- ...messages,
909
- formatMessageParts(ctx, c)
910
- ], []));
911
- }
912
- else {
913
- return formatMessageParts(ctx, body);
914
- }
915
- }
916
- function formatMessageParts(ctx, node) {
917
- const _static = node.s || node.static;
918
- if (_static) {
919
- return ctx.type === 'text'
920
- ? _static
921
- : ctx.normalize([_static]);
922
- }
923
- else {
924
- const messages = (node.i || node.items).reduce((acm, c) => [...acm, formatMessagePart(ctx, c)], []);
925
- return ctx.normalize(messages);
926
- }
927
- }
928
- function formatMessagePart(ctx, node) {
929
- const type = node.t || node.type;
930
- switch (type) {
931
- case 3 /* NodeTypes.Text */: {
932
- const text = node;
933
- return (text.v || text.value);
934
- }
935
- case 9 /* NodeTypes.Literal */: {
936
- const literal = node;
937
- return (literal.v || literal.value);
938
- }
939
- case 4 /* NodeTypes.Named */: {
940
- const named = node;
941
- return ctx.interpolate(ctx.named(named.k || named.key));
942
- }
943
- case 5 /* NodeTypes.List */: {
944
- const list = node;
945
- return ctx.interpolate(ctx.list(list.i != null ? list.i : list.index));
946
- }
947
- case 6 /* NodeTypes.Linked */: {
948
- const linked = node;
949
- const modifier = linked.m || linked.modifier;
950
- return ctx.linked(formatMessagePart(ctx, linked.k || linked.key), modifier ? formatMessagePart(ctx, modifier) : undefined, ctx.type);
951
- }
952
- case 7 /* NodeTypes.LinkedKey */: {
953
- const linkedKey = node;
954
- return (linkedKey.v || linkedKey.value);
955
- }
956
- case 8 /* NodeTypes.LinkedModifier */: {
957
- const linkedModifier = node;
958
- return (linkedModifier.v || linkedModifier.value);
959
- }
960
- default:
961
- throw new Error(`unhandled node type on format message part: ${type}`);
962
- }
963
- }
964
-
965
- const WARN_MESSAGE = `Detected HTML in '{source}' message. Recommend not using HTML messages to avoid XSS.`;
966
- function checkHtmlMessage(source, warnHtmlMessage) {
967
- if (warnHtmlMessage && detectHtmlTag(source)) {
968
- warn(format$1(WARN_MESSAGE, { source }));
969
- }
970
- }
971
- const defaultOnCacheKey = (message) => message;
972
- let compileCache = Object.create(null);
973
- function clearCompileCache() {
974
- compileCache = Object.create(null);
975
- }
976
- const isMessageAST = (val) => isObject(val) &&
977
- (val.t === 0 || val.type === 0) &&
978
- ('b' in val || 'body' in val);
979
- function baseCompile(message, options = {}) {
980
- // error detecting on compile
981
- let detectError = false;
982
- const onError = options.onError || defaultOnError;
983
- options.onError = (err) => {
984
- detectError = true;
985
- onError(err);
986
- };
987
- // compile with mesasge-compiler
988
- return { ...baseCompile$1(message, options), detectError };
989
- }
990
- /* #__NO_SIDE_EFFECTS__ */
991
- function compile(message, context) {
992
- if ((!__INTLIFY_DROP_MESSAGE_COMPILER__) &&
993
- isString(message)) {
994
- // check HTML message
995
- const warnHtmlMessage = isBoolean(context.warnHtmlMessage)
996
- ? context.warnHtmlMessage
997
- : true;
998
- (process.env.NODE_ENV !== 'production') && checkHtmlMessage(message, warnHtmlMessage);
999
- // check caches
1000
- const onCacheKey = context.onCacheKey || defaultOnCacheKey;
1001
- const cacheKey = onCacheKey(message);
1002
- const cached = compileCache[cacheKey];
1003
- if (cached) {
1004
- return cached;
1005
- }
1006
- // compile with JIT mode
1007
- const { ast, detectError } = baseCompile(message, {
1008
- ...context,
1009
- location: (process.env.NODE_ENV !== 'production'),
1010
- jit: true
1011
- });
1012
- // compose message function from AST
1013
- const msg = format(ast);
1014
- // if occurred compile error, don't cache
1015
- return !detectError
1016
- ? (compileCache[cacheKey] = msg)
1017
- : msg;
1018
- }
1019
- else {
1020
- if ((process.env.NODE_ENV !== 'production') && !isMessageAST(message)) {
1021
- warn(`the message that is resolve with key '${context.key}' is not supported for jit compilation`);
1022
- return (() => message);
1023
- }
1024
- // AST case (passed from bundler)
1025
- const cacheKey = message.cacheKey;
1026
- if (cacheKey) {
1027
- const cached = compileCache[cacheKey];
1028
- if (cached) {
1029
- return cached;
1030
- }
1031
- // compose message function from message (AST)
1032
- return (compileCache[cacheKey] =
1033
- format(message));
1034
- }
1035
- else {
1036
- return format(message);
1037
- }
1038
- }
1039
- }
1040
-
1041
- const NOOP_MESSAGE_FUNCTION = () => '';
1042
- const isMessageFunction = (val) => isFunction(val);
1043
- // implementation of `translate` function
1044
- function translate(context, ...args) {
1045
- const { fallbackFormat, postTranslation, unresolving, messageCompiler, fallbackLocale, messages } = context;
1046
- const [key, options] = parseTranslateArgs(...args);
1047
- const missingWarn = isBoolean(options.missingWarn)
1048
- ? options.missingWarn
1049
- : context.missingWarn;
1050
- const fallbackWarn = isBoolean(options.fallbackWarn)
1051
- ? options.fallbackWarn
1052
- : context.fallbackWarn;
1053
- const escapeParameter = isBoolean(options.escapeParameter)
1054
- ? options.escapeParameter
1055
- : context.escapeParameter;
1056
- const resolvedMessage = !!options.resolvedMessage;
1057
- // prettier-ignore
1058
- const defaultMsgOrKey = isString(options.default) || isBoolean(options.default) // default by function option
1059
- ? !isBoolean(options.default)
1060
- ? options.default
1061
- : (!messageCompiler ? () => key : key)
1062
- : fallbackFormat // default by `fallbackFormat` option
1063
- ? (!messageCompiler ? () => key : key)
1064
- : null;
1065
- const enableDefaultMsg = fallbackFormat ||
1066
- (defaultMsgOrKey != null &&
1067
- (isString(defaultMsgOrKey) || isFunction(defaultMsgOrKey)));
1068
- const locale = getLocale(context, options);
1069
- // escape params
1070
- escapeParameter && escapeParams(options);
1071
- // resolve message format
1072
- // eslint-disable-next-line prefer-const
1073
- let [formatScope, targetLocale, message] = !resolvedMessage
1074
- ? resolveMessageFormat(context, key, locale, fallbackLocale, fallbackWarn, missingWarn)
1075
- : [
1076
- key,
1077
- locale,
1078
- messages[locale] || {}
1079
- ];
1080
- // NOTE:
1081
- // Fix to work around `ssrTransfrom` bug in Vite.
1082
- // https://github.com/vitejs/vite/issues/4306
1083
- // To get around this, use temporary variables.
1084
- // https://github.com/nuxt/framework/issues/1461#issuecomment-954606243
1085
- let format = formatScope;
1086
- // if you use default message, set it as message format!
1087
- let cacheBaseKey = key;
1088
- if (!resolvedMessage &&
1089
- !(isString(format) ||
1090
- isMessageAST(format) ||
1091
- isMessageFunction(format))) {
1092
- if (enableDefaultMsg) {
1093
- format = defaultMsgOrKey;
1094
- cacheBaseKey = format;
1095
- }
1096
- }
1097
- // checking message format and target locale
1098
- if (!resolvedMessage &&
1099
- (!(isString(format) ||
1100
- isMessageAST(format) ||
1101
- isMessageFunction(format)) ||
1102
- !isString(targetLocale))) {
1103
- return unresolving ? NOT_REOSLVED : key;
1104
- }
1105
- // TODO: refactor
1106
- if ((process.env.NODE_ENV !== 'production') && isString(format) && context.messageCompiler == null) {
1107
- warn(`The message format compilation is not supported in this build. ` +
1108
- `Because message compiler isn't included. ` +
1109
- `You need to pre-compilation all message format. ` +
1110
- `So translate function return '${key}'.`);
1111
- return key;
1112
- }
1113
- // setup compile error detecting
1114
- let occurred = false;
1115
- const onError = () => {
1116
- occurred = true;
827
+ fallbackContext,
828
+ onWarn,
829
+ __meta
1117
830
  };
1118
- // compile message format
1119
- const msg = !isMessageFunction(format)
1120
- ? compileMessageFormat(context, key, targetLocale, format, cacheBaseKey, onError)
1121
- : format;
1122
- // if occurred compile error, return the message format
1123
- if (occurred) {
1124
- return format;
831
+ {
832
+ context.datetimeFormats = datetimeFormats;
833
+ context.numberFormats = numberFormats;
834
+ context.__datetimeFormatters = __datetimeFormatters;
835
+ context.__numberFormatters = __numberFormatters;
836
+ }
837
+ // for vue-devtools timeline event
838
+ if ((process.env.NODE_ENV !== 'production')) {
839
+ context.__v_emitter =
840
+ internalOptions.__v_emitter != null
841
+ ? internalOptions.__v_emitter
842
+ : undefined;
1125
843
  }
1126
- // evaluate message with context
1127
- const ctxOptions = getMessageContextOptions(context, targetLocale, message, options);
1128
- const msgContext = createMessageContext(ctxOptions);
1129
- const messaged = evaluateMessage(context, msg, msgContext);
1130
- // if use post translation option, proceed it with handler
1131
- const ret = postTranslation
1132
- ? postTranslation(messaged, key)
1133
- : messaged;
1134
844
  // NOTE: experimental !!
1135
845
  if ((process.env.NODE_ENV !== 'production') || __INTLIFY_PROD_DEVTOOLS__) {
1136
- // prettier-ignore
1137
- const payloads = {
1138
- timestamp: Date.now(),
1139
- key: isString(key)
1140
- ? key
1141
- : isMessageFunction(format)
1142
- ? format.key
1143
- : '',
1144
- locale: targetLocale || (isMessageFunction(format)
1145
- ? format.locale
1146
- : ''),
1147
- format: isString(format)
1148
- ? format
1149
- : isMessageFunction(format)
1150
- ? format.source
1151
- : '',
1152
- message: ret
1153
- };
1154
- payloads.meta = assign({}, context.__meta, getAdditionalMeta() || {});
1155
- translateDevTools(payloads);
846
+ initI18nDevTools(context, version, __meta);
1156
847
  }
1157
- return ret;
848
+ return context;
1158
849
  }
1159
- function escapeParams(options) {
1160
- if (isArray(options.list)) {
1161
- options.list = options.list.map(item => isString(item) ? escapeHtml(item) : item);
1162
- }
1163
- else if (isObject(options.named)) {
1164
- Object.keys(options.named).forEach(key => {
1165
- if (isString(options.named[key])) {
1166
- options.named[key] = escapeHtml(options.named[key]);
1167
- }
1168
- });
1169
- }
850
+ /** @internal */
851
+ function isTranslateFallbackWarn(fallback, key) {
852
+ return fallback instanceof RegExp ? fallback.test(key) : fallback;
1170
853
  }
1171
- function resolveMessageFormat(context, key, locale, fallbackLocale, fallbackWarn, missingWarn) {
1172
- const { messages, onWarn, messageResolver: resolveValue, localeFallbacker } = context;
1173
- const locales = localeFallbacker(context, fallbackLocale, locale); // eslint-disable-line @typescript-eslint/no-explicit-any
1174
- let message = {};
1175
- let targetLocale;
1176
- let format = null;
1177
- let from = locale;
1178
- let to = null;
1179
- const type = 'translate';
1180
- for (let i = 0; i < locales.length; i++) {
1181
- targetLocale = to = locales[i];
1182
- if ((process.env.NODE_ENV !== 'production') &&
1183
- locale !== targetLocale &&
1184
- !isAlmostSameLocale(locale, targetLocale) &&
1185
- isTranslateFallbackWarn(fallbackWarn, key)) {
1186
- onWarn(getWarnMessage(CoreWarnCodes.FALLBACK_TO_TRANSLATE, {
854
+ /** @internal */
855
+ function isTranslateMissingWarn(missing, key) {
856
+ return missing instanceof RegExp ? missing.test(key) : missing;
857
+ }
858
+ /** @internal */
859
+ function handleMissing(context, key, locale, missingWarn, type) {
860
+ const { missing, onWarn } = context;
861
+ // for vue-devtools timeline event
862
+ if ((process.env.NODE_ENV !== 'production')) {
863
+ const emitter = context.__v_emitter;
864
+ if (emitter) {
865
+ emitter.emit('missing', {
866
+ locale,
1187
867
  key,
1188
- target: targetLocale
1189
- }));
1190
- }
1191
- // for vue-devtools timeline event
1192
- if ((process.env.NODE_ENV !== 'production') && locale !== targetLocale) {
1193
- const emitter = context.__v_emitter;
1194
- if (emitter) {
1195
- emitter.emit('fallback', {
1196
- type,
1197
- key,
1198
- from,
1199
- to,
1200
- groupId: `${type}:${key}`
1201
- });
1202
- }
1203
- }
1204
- message =
1205
- messages[targetLocale] || {};
1206
- // for vue-devtools timeline event
1207
- let start = null;
1208
- let startTag;
1209
- let endTag;
1210
- if ((process.env.NODE_ENV !== 'production') && inBrowser) {
1211
- start = window.performance.now();
1212
- startTag = 'intlify-message-resolve-start';
1213
- endTag = 'intlify-message-resolve-end';
1214
- mark && mark(startTag);
1215
- }
1216
- if ((format = resolveValue(message, key)) === null) {
1217
- // if null, resolve with object key path
1218
- format = message[key]; // eslint-disable-line @typescript-eslint/no-explicit-any
1219
- }
1220
- // for vue-devtools timeline event
1221
- if ((process.env.NODE_ENV !== 'production') && inBrowser) {
1222
- const end = window.performance.now();
1223
- const emitter = context.__v_emitter;
1224
- if (emitter && start && format) {
1225
- emitter.emit('message-resolve', {
1226
- type: 'message-resolve',
1227
- key,
1228
- message: format,
1229
- time: end - start,
1230
- groupId: `${type}:${key}`
1231
- });
1232
- }
1233
- if (startTag && endTag && mark && measure) {
1234
- mark(endTag);
1235
- measure('intlify message resolve', startTag, endTag);
1236
- }
1237
- }
1238
- if (isString(format) || isMessageAST(format) || isMessageFunction(format)) {
1239
- break;
868
+ type,
869
+ groupId: `${type}:${key}`
870
+ });
1240
871
  }
1241
- if (!isImplicitFallback(targetLocale, locales)) {
1242
- const missingRet = handleMissing(context, // eslint-disable-line @typescript-eslint/no-explicit-any
1243
- key, targetLocale, missingWarn, type);
1244
- if (missingRet !== key) {
1245
- format = missingRet;
1246
- }
872
+ }
873
+ if (missing !== null) {
874
+ const ret = missing(context, locale, key, type);
875
+ return isString(ret) ? ret : key;
876
+ }
877
+ else {
878
+ if ((process.env.NODE_ENV !== 'production') && isTranslateMissingWarn(missingWarn, key)) {
879
+ onWarn(getWarnMessage(CoreWarnCodes.NOT_FOUND_KEY, { key, locale }));
1247
880
  }
1248
- from = to;
881
+ return key;
1249
882
  }
1250
- return [format, targetLocale, message];
1251
883
  }
1252
- function compileMessageFormat(context, key, targetLocale, format, cacheBaseKey, onError) {
1253
- const { messageCompiler, warnHtmlMessage } = context;
1254
- if (isMessageFunction(format)) {
1255
- const msg = format;
1256
- msg.locale = msg.locale || targetLocale;
1257
- msg.key = msg.key || key;
1258
- return msg;
884
+ /** @internal */
885
+ function updateFallbackLocale(ctx, locale, fallback) {
886
+ const context = ctx;
887
+ context.__localeChainCache = new Map();
888
+ ctx.localeFallbacker(ctx, fallback, locale);
889
+ }
890
+ /** @internal */
891
+ function isAlmostSameLocale(locale, compareLocale) {
892
+ if (locale === compareLocale)
893
+ return false;
894
+ return locale.split('-')[0] === compareLocale.split('-')[0];
895
+ }
896
+ /** @internal */
897
+ function isImplicitFallback(targetLocale, locales) {
898
+ const index = locales.indexOf(targetLocale);
899
+ if (index === -1) {
900
+ return false;
1259
901
  }
1260
- if (messageCompiler == null) {
1261
- const msg = (() => format);
1262
- msg.locale = targetLocale;
1263
- msg.key = key;
1264
- return msg;
902
+ for (let i = index + 1; i < locales.length; i++) {
903
+ if (isAlmostSameLocale(targetLocale, locales[i])) {
904
+ return true;
905
+ }
1265
906
  }
1266
- // for vue-devtools timeline event
1267
- let start = null;
1268
- let startTag;
1269
- let endTag;
1270
- if ((process.env.NODE_ENV !== 'production') && inBrowser) {
1271
- start = window.performance.now();
1272
- startTag = 'intlify-message-compilation-start';
1273
- endTag = 'intlify-message-compilation-end';
1274
- mark && mark(startTag);
907
+ return false;
908
+ }
909
+ /* eslint-enable @typescript-eslint/no-explicit-any */
910
+
911
+ const intlDefined = typeof Intl !== 'undefined';
912
+ const Availabilities = {
913
+ dateTimeFormat: intlDefined && typeof Intl.DateTimeFormat !== 'undefined',
914
+ numberFormat: intlDefined && typeof Intl.NumberFormat !== 'undefined'
915
+ };
916
+
917
+ // implementation of `datetime` function
918
+ function datetime(context, ...args) {
919
+ const { datetimeFormats, unresolving, fallbackLocale, onWarn, localeFallbacker } = context;
920
+ const { __datetimeFormatters } = context;
921
+ if ((process.env.NODE_ENV !== 'production') && !Availabilities.dateTimeFormat) {
922
+ onWarn(getWarnMessage(CoreWarnCodes.CANNOT_FORMAT_DATE));
923
+ return MISSING_RESOLVE_VALUE;
1275
924
  }
1276
- const msg = messageCompiler(format, getCompileContext(context, targetLocale, cacheBaseKey, format, warnHtmlMessage, onError));
1277
- // for vue-devtools timeline event
1278
- if ((process.env.NODE_ENV !== 'production') && inBrowser) {
1279
- const end = window.performance.now();
1280
- const emitter = context.__v_emitter;
1281
- if (emitter && start) {
1282
- emitter.emit('message-compilation', {
1283
- type: 'message-compilation',
1284
- message: format,
1285
- time: end - start,
1286
- groupId: `${'translate'}:${key}`
1287
- });
925
+ const [key, value, options, overrides] = parseDateTimeArgs(...args);
926
+ const missingWarn = isBoolean(options.missingWarn)
927
+ ? options.missingWarn
928
+ : context.missingWarn;
929
+ const fallbackWarn = isBoolean(options.fallbackWarn)
930
+ ? options.fallbackWarn
931
+ : context.fallbackWarn;
932
+ const part = !!options.part;
933
+ const locale = getLocale(context, options);
934
+ const locales = localeFallbacker(context, // eslint-disable-line @typescript-eslint/no-explicit-any
935
+ fallbackLocale, locale);
936
+ if (!isString(key) || key === '') {
937
+ return new Intl.DateTimeFormat(locale, overrides).format(value);
938
+ }
939
+ // resolve format
940
+ let datetimeFormat = {};
941
+ let targetLocale;
942
+ let format = null;
943
+ let from = locale;
944
+ let to = null;
945
+ const type = 'datetime format';
946
+ for (let i = 0; i < locales.length; i++) {
947
+ targetLocale = to = locales[i];
948
+ if ((process.env.NODE_ENV !== 'production') &&
949
+ locale !== targetLocale &&
950
+ isTranslateFallbackWarn(fallbackWarn, key)) {
951
+ onWarn(getWarnMessage(CoreWarnCodes.FALLBACK_TO_DATE_FORMAT, {
952
+ key,
953
+ target: targetLocale
954
+ }));
1288
955
  }
1289
- if (startTag && endTag && mark && measure) {
1290
- mark(endTag);
1291
- measure('intlify message compilation', startTag, endTag);
956
+ // for vue-devtools timeline event
957
+ if ((process.env.NODE_ENV !== 'production') && locale !== targetLocale) {
958
+ const emitter = context.__v_emitter;
959
+ if (emitter) {
960
+ emitter.emit('fallback', {
961
+ type,
962
+ key,
963
+ from,
964
+ to,
965
+ groupId: `${type}:${key}`
966
+ });
967
+ }
1292
968
  }
969
+ datetimeFormat =
970
+ datetimeFormats[targetLocale] || {};
971
+ format = datetimeFormat[key];
972
+ if (isPlainObject(format))
973
+ break;
974
+ handleMissing(context, key, targetLocale, missingWarn, type); // eslint-disable-line @typescript-eslint/no-explicit-any
975
+ from = to;
1293
976
  }
1294
- msg.locale = targetLocale;
1295
- msg.key = key;
1296
- msg.source = format;
1297
- return msg;
1298
- }
1299
- function evaluateMessage(context, msg, msgCtx) {
1300
- // for vue-devtools timeline event
1301
- let start = null;
1302
- let startTag;
1303
- let endTag;
1304
- if ((process.env.NODE_ENV !== 'production') && inBrowser) {
1305
- start = window.performance.now();
1306
- startTag = 'intlify-message-evaluation-start';
1307
- endTag = 'intlify-message-evaluation-end';
1308
- mark && mark(startTag);
977
+ // checking format and target locale
978
+ if (!isPlainObject(format) || !isString(targetLocale)) {
979
+ return unresolving ? NOT_REOSLVED : key;
1309
980
  }
1310
- const messaged = msg(msgCtx);
1311
- // for vue-devtools timeline event
1312
- if ((process.env.NODE_ENV !== 'production') && inBrowser) {
1313
- const end = window.performance.now();
1314
- const emitter = context.__v_emitter;
1315
- if (emitter && start) {
1316
- emitter.emit('message-evaluation', {
1317
- type: 'message-evaluation',
1318
- value: messaged,
1319
- time: end - start,
1320
- groupId: `${'translate'}:${msg.key}`
1321
- });
1322
- }
1323
- if (startTag && endTag && mark && measure) {
1324
- mark(endTag);
1325
- measure('intlify message evaluation', startTag, endTag);
1326
- }
981
+ let id = `${targetLocale}__${key}`;
982
+ if (!isEmptyObject(overrides)) {
983
+ id = `${id}__${JSON.stringify(overrides)}`;
1327
984
  }
1328
- return messaged;
985
+ let formatter = __datetimeFormatters.get(id);
986
+ if (!formatter) {
987
+ formatter = new Intl.DateTimeFormat(targetLocale, assign({}, format, overrides));
988
+ __datetimeFormatters.set(id, formatter);
989
+ }
990
+ return !part ? formatter.format(value) : formatter.formatToParts(value);
1329
991
  }
1330
992
  /** @internal */
1331
- function parseTranslateArgs(...args) {
1332
- const [arg1, arg2, arg3] = args;
993
+ const DATETIME_FORMAT_OPTIONS_KEYS = [
994
+ 'localeMatcher',
995
+ 'weekday',
996
+ 'era',
997
+ 'year',
998
+ 'month',
999
+ 'day',
1000
+ 'hour',
1001
+ 'minute',
1002
+ 'second',
1003
+ 'timeZoneName',
1004
+ 'formatMatcher',
1005
+ 'hour12',
1006
+ 'timeZone',
1007
+ 'dateStyle',
1008
+ 'timeStyle',
1009
+ 'calendar',
1010
+ 'dayPeriod',
1011
+ 'numberingSystem',
1012
+ 'hourCycle',
1013
+ 'fractionalSecondDigits'
1014
+ ];
1015
+ /** @internal */
1016
+ function parseDateTimeArgs(...args) {
1017
+ const [arg1, arg2, arg3, arg4] = args;
1333
1018
  const options = {};
1334
- if (!isString(arg1) &&
1335
- !isNumber(arg1) &&
1336
- !isMessageFunction(arg1) &&
1337
- !isMessageAST(arg1)) {
1338
- throw createCoreError(CoreErrorCodes.INVALID_ARGUMENT);
1339
- }
1340
- // prettier-ignore
1341
- const key = isNumber(arg1)
1342
- ? String(arg1)
1343
- : isMessageFunction(arg1)
1344
- ? arg1
1345
- : arg1;
1346
- if (isNumber(arg2)) {
1347
- options.plural = arg2;
1348
- }
1349
- else if (isString(arg2)) {
1350
- options.default = arg2;
1351
- }
1352
- else if (isPlainObject(arg2) && !isEmptyObject(arg2)) {
1353
- options.named = arg2;
1019
+ let overrides = {};
1020
+ let value;
1021
+ if (isString(arg1)) {
1022
+ // Only allow ISO strings - other date formats are often supported,
1023
+ // but may cause different results in different browsers.
1024
+ const matches = arg1.match(/(\d{4}-\d{2}-\d{2})(T|\s)?(.*)/);
1025
+ if (!matches) {
1026
+ throw createCoreError(CoreErrorCodes.INVALID_ISO_DATE_ARGUMENT);
1027
+ }
1028
+ // Some browsers can not parse the iso datetime separated by space,
1029
+ // this is a compromise solution by replace the 'T'/' ' with 'T'
1030
+ const dateTime = matches[3]
1031
+ ? matches[3].trim().startsWith('T')
1032
+ ? `${matches[1].trim()}${matches[3].trim()}`
1033
+ : `${matches[1].trim()}T${matches[3].trim()}`
1034
+ : matches[1].trim();
1035
+ value = new Date(dateTime);
1036
+ try {
1037
+ // This will fail if the date is not valid
1038
+ value.toISOString();
1039
+ }
1040
+ catch {
1041
+ throw createCoreError(CoreErrorCodes.INVALID_ISO_DATE_ARGUMENT);
1042
+ }
1354
1043
  }
1355
- else if (isArray(arg2)) {
1356
- options.list = arg2;
1044
+ else if (isDate(arg1)) {
1045
+ if (isNaN(arg1.getTime())) {
1046
+ throw createCoreError(CoreErrorCodes.INVALID_DATE_ARGUMENT);
1047
+ }
1048
+ value = arg1;
1357
1049
  }
1358
- if (isNumber(arg3)) {
1359
- options.plural = arg3;
1050
+ else if (isNumber(arg1)) {
1051
+ value = arg1;
1360
1052
  }
1361
- else if (isString(arg3)) {
1362
- options.default = arg3;
1053
+ else {
1054
+ throw createCoreError(CoreErrorCodes.INVALID_ARGUMENT);
1363
1055
  }
1364
- else if (isPlainObject(arg3)) {
1365
- assign(options, arg3);
1056
+ if (isString(arg2)) {
1057
+ options.key = arg2;
1366
1058
  }
1367
- return [key, options];
1368
- }
1369
- function getCompileContext(context, locale, key, source, warnHtmlMessage, onError) {
1370
- return {
1371
- locale,
1372
- key,
1373
- warnHtmlMessage,
1374
- onError: (err) => {
1375
- onError && onError(err);
1376
- if ((process.env.NODE_ENV !== 'production')) {
1377
- const _source = getSourceForCodeFrame(source);
1378
- const message = `Message compilation error: ${err.message}`;
1379
- const codeFrame = err.location &&
1380
- _source &&
1381
- generateCodeFrame(_source, err.location.start.offset, err.location.end.offset);
1382
- const emitter = context.__v_emitter;
1383
- if (emitter && _source) {
1384
- emitter.emit('compile-error', {
1385
- message: _source,
1386
- error: err.message,
1387
- start: err.location && err.location.start.offset,
1388
- end: err.location && err.location.end.offset,
1389
- groupId: `${'translate'}:${key}`
1390
- });
1391
- }
1392
- console.error(codeFrame ? `${message}\n${codeFrame}` : message);
1059
+ else if (isPlainObject(arg2)) {
1060
+ Object.keys(arg2).forEach(key => {
1061
+ if (DATETIME_FORMAT_OPTIONS_KEYS.includes(key)) {
1062
+ overrides[key] = arg2[key];
1393
1063
  }
1394
1064
  else {
1395
- throw err;
1065
+ options[key] = arg2[key];
1396
1066
  }
1397
- },
1398
- onCacheKey: (source) => generateFormatCacheKey(locale, key, source)
1399
- };
1400
- }
1401
- function getSourceForCodeFrame(source) {
1402
- if (isString(source)) {
1403
- return source;
1404
- }
1405
- else {
1406
- if (source.loc && source.loc.source) {
1407
- return source.loc.source;
1408
- }
1409
- }
1410
- }
1411
- function getMessageContextOptions(context, locale, message, options) {
1412
- const { modifiers, pluralRules, messageResolver: resolveValue, fallbackLocale, fallbackWarn, missingWarn, fallbackContext } = context;
1413
- const resolveMessage = (key, useLinked) => {
1414
- let val = resolveValue(message, key);
1415
- // fallback
1416
- if (val == null && (fallbackContext || useLinked)) {
1417
- const [, , message] = resolveMessageFormat(fallbackContext || context, // NOTE: if has fallbackContext, fallback to root, else if use linked, fallback to local context
1418
- key, locale, fallbackLocale, fallbackWarn, missingWarn);
1419
- val = resolveValue(message, key);
1420
- }
1421
- if (isString(val) || isMessageAST(val)) {
1422
- let occurred = false;
1423
- const onError = () => {
1424
- occurred = true;
1425
- };
1426
- const msg = compileMessageFormat(context, key, locale, val, key, onError);
1427
- return !occurred
1428
- ? msg
1429
- : NOOP_MESSAGE_FUNCTION;
1430
- }
1431
- else if (isMessageFunction(val)) {
1432
- return val;
1433
- }
1434
- else {
1435
- // TODO: should be implemented warning message
1436
- return NOOP_MESSAGE_FUNCTION;
1437
- }
1438
- };
1439
- const ctxOptions = {
1440
- locale,
1441
- modifiers,
1442
- pluralRules,
1443
- messages: resolveMessage
1444
- };
1445
- if (context.processor) {
1446
- ctxOptions.processor = context.processor;
1067
+ });
1447
1068
  }
1448
- if (options.list) {
1449
- ctxOptions.list = options.list;
1069
+ if (isString(arg3)) {
1070
+ options.locale = arg3;
1450
1071
  }
1451
- if (options.named) {
1452
- ctxOptions.named = options.named;
1072
+ else if (isPlainObject(arg3)) {
1073
+ overrides = arg3;
1453
1074
  }
1454
- if (isNumber(options.plural)) {
1455
- ctxOptions.pluralIndex = options.plural;
1075
+ if (isPlainObject(arg4)) {
1076
+ overrides = arg4;
1077
+ }
1078
+ return [options.key || '', value, options, overrides];
1079
+ }
1080
+ /** @internal */
1081
+ function clearDateTimeFormat(ctx, locale, format) {
1082
+ const context = ctx;
1083
+ for (const key in format) {
1084
+ const id = `${locale}__${key}`;
1085
+ if (!context.__datetimeFormatters.has(id)) {
1086
+ continue;
1087
+ }
1088
+ context.__datetimeFormatters.delete(id);
1456
1089
  }
1457
- return ctxOptions;
1458
1090
  }
1459
1091
 
1460
- const intlDefined = typeof Intl !== 'undefined';
1461
- const Availabilities = {
1462
- dateTimeFormat: intlDefined && typeof Intl.DateTimeFormat !== 'undefined',
1463
- numberFormat: intlDefined && typeof Intl.NumberFormat !== 'undefined'
1464
- };
1465
-
1466
- // implementation of `datetime` function
1467
- function datetime(context, ...args) {
1468
- const { datetimeFormats, unresolving, fallbackLocale, onWarn, localeFallbacker } = context;
1469
- const { __datetimeFormatters } = context;
1470
- if ((process.env.NODE_ENV !== 'production') && !Availabilities.dateTimeFormat) {
1471
- onWarn(getWarnMessage(CoreWarnCodes.CANNOT_FORMAT_DATE));
1092
+ // implementation of `number` function
1093
+ function number(context, ...args) {
1094
+ const { numberFormats, unresolving, fallbackLocale, onWarn, localeFallbacker } = context;
1095
+ const { __numberFormatters } = context;
1096
+ if ((process.env.NODE_ENV !== 'production') && !Availabilities.numberFormat) {
1097
+ onWarn(getWarnMessage(CoreWarnCodes.CANNOT_FORMAT_NUMBER));
1472
1098
  return MISSING_RESOLVE_VALUE;
1473
1099
  }
1474
- const [key, value, options, overrides] = parseDateTimeArgs(...args);
1100
+ const [key, value, options, overrides] = parseNumberArgs(...args);
1475
1101
  const missingWarn = isBoolean(options.missingWarn)
1476
1102
  ? options.missingWarn
1477
1103
  : context.missingWarn;
@@ -1483,21 +1109,21 @@ function datetime(context, ...args) {
1483
1109
  const locales = localeFallbacker(context, // eslint-disable-line @typescript-eslint/no-explicit-any
1484
1110
  fallbackLocale, locale);
1485
1111
  if (!isString(key) || key === '') {
1486
- return new Intl.DateTimeFormat(locale, overrides).format(value);
1112
+ return new Intl.NumberFormat(locale, overrides).format(value);
1487
1113
  }
1488
1114
  // resolve format
1489
- let datetimeFormat = {};
1115
+ let numberFormat = {};
1490
1116
  let targetLocale;
1491
1117
  let format = null;
1492
1118
  let from = locale;
1493
1119
  let to = null;
1494
- const type = 'datetime format';
1120
+ const type = 'number format';
1495
1121
  for (let i = 0; i < locales.length; i++) {
1496
1122
  targetLocale = to = locales[i];
1497
1123
  if ((process.env.NODE_ENV !== 'production') &&
1498
1124
  locale !== targetLocale &&
1499
1125
  isTranslateFallbackWarn(fallbackWarn, key)) {
1500
- onWarn(getWarnMessage(CoreWarnCodes.FALLBACK_TO_DATE_FORMAT, {
1126
+ onWarn(getWarnMessage(CoreWarnCodes.FALLBACK_TO_NUMBER_FORMAT, {
1501
1127
  key,
1502
1128
  target: targetLocale
1503
1129
  }));
@@ -1515,9 +1141,9 @@ function datetime(context, ...args) {
1515
1141
  });
1516
1142
  }
1517
1143
  }
1518
- datetimeFormat =
1519
- datetimeFormats[targetLocale] || {};
1520
- format = datetimeFormat[key];
1144
+ numberFormat =
1145
+ numberFormats[targetLocale] || {};
1146
+ format = numberFormat[key];
1521
1147
  if (isPlainObject(format))
1522
1148
  break;
1523
1149
  handleMissing(context, key, targetLocale, missingWarn, type); // eslint-disable-line @typescript-eslint/no-explicit-any
@@ -1531,148 +1157,357 @@ function datetime(context, ...args) {
1531
1157
  if (!isEmptyObject(overrides)) {
1532
1158
  id = `${id}__${JSON.stringify(overrides)}`;
1533
1159
  }
1534
- let formatter = __datetimeFormatters.get(id);
1160
+ let formatter = __numberFormatters.get(id);
1535
1161
  if (!formatter) {
1536
- formatter = new Intl.DateTimeFormat(targetLocale, assign({}, format, overrides));
1537
- __datetimeFormatters.set(id, formatter);
1162
+ formatter = new Intl.NumberFormat(targetLocale, assign({}, format, overrides));
1163
+ __numberFormatters.set(id, formatter);
1538
1164
  }
1539
1165
  return !part ? formatter.format(value) : formatter.formatToParts(value);
1540
1166
  }
1541
1167
  /** @internal */
1542
- const DATETIME_FORMAT_OPTIONS_KEYS = [
1168
+ const NUMBER_FORMAT_OPTIONS_KEYS = [
1543
1169
  'localeMatcher',
1544
- 'weekday',
1545
- 'era',
1546
- 'year',
1547
- 'month',
1548
- 'day',
1549
- 'hour',
1550
- 'minute',
1551
- 'second',
1552
- 'timeZoneName',
1553
- 'formatMatcher',
1554
- 'hour12',
1555
- 'timeZone',
1556
- 'dateStyle',
1557
- 'timeStyle',
1558
- 'calendar',
1559
- 'dayPeriod',
1560
- 'numberingSystem',
1561
- 'hourCycle',
1562
- 'fractionalSecondDigits'
1170
+ 'style',
1171
+ 'currency',
1172
+ 'currencyDisplay',
1173
+ 'currencySign',
1174
+ 'useGrouping',
1175
+ 'minimumIntegerDigits',
1176
+ 'minimumFractionDigits',
1177
+ 'maximumFractionDigits',
1178
+ 'minimumSignificantDigits',
1179
+ 'maximumSignificantDigits',
1180
+ 'compactDisplay',
1181
+ 'notation',
1182
+ 'signDisplay',
1183
+ 'unit',
1184
+ 'unitDisplay',
1185
+ 'roundingMode',
1186
+ 'roundingPriority',
1187
+ 'roundingIncrement',
1188
+ 'trailingZeroDisplay'
1563
1189
  ];
1564
1190
  /** @internal */
1565
- function parseDateTimeArgs(...args) {
1191
+ function parseNumberArgs(...args) {
1566
1192
  const [arg1, arg2, arg3, arg4] = args;
1567
1193
  const options = {};
1568
1194
  let overrides = {};
1569
- let value;
1570
- if (isString(arg1)) {
1571
- // Only allow ISO strings - other date formats are often supported,
1572
- // but may cause different results in different browsers.
1573
- const matches = arg1.match(/(\d{4}-\d{2}-\d{2})(T|\s)?(.*)/);
1574
- if (!matches) {
1575
- throw createCoreError(CoreErrorCodes.INVALID_ISO_DATE_ARGUMENT);
1576
- }
1577
- // Some browsers can not parse the iso datetime separated by space,
1578
- // this is a compromise solution by replace the 'T'/' ' with 'T'
1579
- const dateTime = matches[3]
1580
- ? matches[3].trim().startsWith('T')
1581
- ? `${matches[1].trim()}${matches[3].trim()}`
1582
- : `${matches[1].trim()}T${matches[3].trim()}`
1583
- : matches[1].trim();
1584
- value = new Date(dateTime);
1585
- try {
1586
- // This will fail if the date is not valid
1587
- value.toISOString();
1588
- }
1589
- catch (e) {
1590
- throw createCoreError(CoreErrorCodes.INVALID_ISO_DATE_ARGUMENT);
1591
- }
1592
- }
1593
- else if (isDate(arg1)) {
1594
- if (isNaN(arg1.getTime())) {
1595
- throw createCoreError(CoreErrorCodes.INVALID_DATE_ARGUMENT);
1596
- }
1597
- value = arg1;
1598
- }
1599
- else if (isNumber(arg1)) {
1600
- value = arg1;
1601
- }
1602
- else {
1195
+ if (!isNumber(arg1)) {
1603
1196
  throw createCoreError(CoreErrorCodes.INVALID_ARGUMENT);
1604
1197
  }
1198
+ const value = arg1;
1605
1199
  if (isString(arg2)) {
1606
1200
  options.key = arg2;
1607
1201
  }
1608
1202
  else if (isPlainObject(arg2)) {
1609
1203
  Object.keys(arg2).forEach(key => {
1610
- if (DATETIME_FORMAT_OPTIONS_KEYS.includes(key)) {
1204
+ if (NUMBER_FORMAT_OPTIONS_KEYS.includes(key)) {
1611
1205
  overrides[key] = arg2[key];
1612
1206
  }
1613
- else {
1614
- options[key] = arg2[key];
1207
+ else {
1208
+ options[key] = arg2[key];
1209
+ }
1210
+ });
1211
+ }
1212
+ if (isString(arg3)) {
1213
+ options.locale = arg3;
1214
+ }
1215
+ else if (isPlainObject(arg3)) {
1216
+ overrides = arg3;
1217
+ }
1218
+ if (isPlainObject(arg4)) {
1219
+ overrides = arg4;
1220
+ }
1221
+ return [options.key || '', value, options, overrides];
1222
+ }
1223
+ /** @internal */
1224
+ function clearNumberFormat(ctx, locale, format) {
1225
+ const context = ctx;
1226
+ for (const key in format) {
1227
+ const id = `${locale}__${key}`;
1228
+ if (!context.__numberFormatters.has(id)) {
1229
+ continue;
1230
+ }
1231
+ context.__numberFormatters.delete(id);
1232
+ }
1233
+ }
1234
+
1235
+ const DEFAULT_MODIFIER = (str) => str;
1236
+ const DEFAULT_MESSAGE = (ctx) => ''; // eslint-disable-line
1237
+ const DEFAULT_MESSAGE_DATA_TYPE = 'text';
1238
+ const DEFAULT_NORMALIZE = (values) => values.length === 0 ? '' : join(values);
1239
+ const DEFAULT_INTERPOLATE = toDisplayString;
1240
+ function pluralDefault(choice, choicesLength) {
1241
+ choice = Math.abs(choice);
1242
+ if (choicesLength === 2) {
1243
+ // prettier-ignore
1244
+ return choice
1245
+ ? choice > 1
1246
+ ? 1
1247
+ : 0
1248
+ : 1;
1249
+ }
1250
+ return choice ? Math.min(choice, 2) : 0;
1251
+ }
1252
+ function getPluralIndex(options) {
1253
+ // prettier-ignore
1254
+ const index = isNumber(options.pluralIndex)
1255
+ ? options.pluralIndex
1256
+ : -1;
1257
+ // prettier-ignore
1258
+ return options.named && (isNumber(options.named.count) || isNumber(options.named.n))
1259
+ ? isNumber(options.named.count)
1260
+ ? options.named.count
1261
+ : isNumber(options.named.n)
1262
+ ? options.named.n
1263
+ : index
1264
+ : index;
1265
+ }
1266
+ function normalizeNamed(pluralIndex, props) {
1267
+ if (!props.count) {
1268
+ props.count = pluralIndex;
1269
+ }
1270
+ if (!props.n) {
1271
+ props.n = pluralIndex;
1272
+ }
1273
+ }
1274
+ function createMessageContext(options = {}) {
1275
+ const locale = options.locale;
1276
+ const pluralIndex = getPluralIndex(options);
1277
+ const pluralRule = isObject(options.pluralRules) &&
1278
+ isString(locale) &&
1279
+ isFunction(options.pluralRules[locale])
1280
+ ? options.pluralRules[locale]
1281
+ : pluralDefault;
1282
+ const orgPluralRule = isObject(options.pluralRules) &&
1283
+ isString(locale) &&
1284
+ isFunction(options.pluralRules[locale])
1285
+ ? pluralDefault
1286
+ : undefined;
1287
+ const plural = (messages) => {
1288
+ return messages[pluralRule(pluralIndex, messages.length, orgPluralRule)];
1289
+ };
1290
+ const _list = options.list || [];
1291
+ const list = (index) => _list[index];
1292
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1293
+ const _named = options.named || {};
1294
+ isNumber(options.pluralIndex) && normalizeNamed(pluralIndex, _named);
1295
+ const named = (key) => _named[key];
1296
+ function message(key, useLinked) {
1297
+ // prettier-ignore
1298
+ const msg = isFunction(options.messages)
1299
+ ? options.messages(key, !!useLinked)
1300
+ : isObject(options.messages)
1301
+ ? options.messages[key]
1302
+ : false;
1303
+ return !msg
1304
+ ? options.parent
1305
+ ? options.parent.message(key) // resolve from parent messages
1306
+ : DEFAULT_MESSAGE
1307
+ : msg;
1308
+ }
1309
+ const _modifier = (name) => options.modifiers
1310
+ ? options.modifiers[name]
1311
+ : DEFAULT_MODIFIER;
1312
+ const normalize = isPlainObject(options.processor) && isFunction(options.processor.normalize)
1313
+ ? options.processor.normalize
1314
+ : DEFAULT_NORMALIZE;
1315
+ const interpolate = isPlainObject(options.processor) &&
1316
+ isFunction(options.processor.interpolate)
1317
+ ? options.processor.interpolate
1318
+ : DEFAULT_INTERPOLATE;
1319
+ const type = isPlainObject(options.processor) && isString(options.processor.type)
1320
+ ? options.processor.type
1321
+ : DEFAULT_MESSAGE_DATA_TYPE;
1322
+ const linked = (key, ...args) => {
1323
+ const [arg1, arg2] = args;
1324
+ let type = 'text';
1325
+ let modifier = '';
1326
+ if (args.length === 1) {
1327
+ if (isObject(arg1)) {
1328
+ modifier = arg1.modifier || modifier;
1329
+ type = arg1.type || type;
1330
+ }
1331
+ else if (isString(arg1)) {
1332
+ modifier = arg1 || modifier;
1615
1333
  }
1616
- });
1617
- }
1618
- if (isString(arg3)) {
1619
- options.locale = arg3;
1620
- }
1621
- else if (isPlainObject(arg3)) {
1622
- overrides = arg3;
1623
- }
1624
- if (isPlainObject(arg4)) {
1625
- overrides = arg4;
1626
- }
1627
- return [options.key || '', value, options, overrides];
1628
- }
1629
- /** @internal */
1630
- function clearDateTimeFormat(ctx, locale, format) {
1631
- const context = ctx;
1632
- for (const key in format) {
1633
- const id = `${locale}__${key}`;
1634
- if (!context.__datetimeFormatters.has(id)) {
1635
- continue;
1636
1334
  }
1637
- context.__datetimeFormatters.delete(id);
1638
- }
1335
+ else if (args.length === 2) {
1336
+ if (isString(arg1)) {
1337
+ modifier = arg1 || modifier;
1338
+ }
1339
+ if (isString(arg2)) {
1340
+ type = arg2 || type;
1341
+ }
1342
+ }
1343
+ const ret = message(key, true)(ctx);
1344
+ const msg =
1345
+ // The message in vnode resolved with linked are returned as an array by processor.nomalize
1346
+ type === 'vnode' && isArray(ret) && modifier
1347
+ ? ret[0]
1348
+ : ret;
1349
+ return modifier ? _modifier(modifier)(msg, type) : msg;
1350
+ };
1351
+ const ctx = {
1352
+ ["list" /* HelperNameMap.LIST */]: list,
1353
+ ["named" /* HelperNameMap.NAMED */]: named,
1354
+ ["plural" /* HelperNameMap.PLURAL */]: plural,
1355
+ ["linked" /* HelperNameMap.LINKED */]: linked,
1356
+ ["message" /* HelperNameMap.MESSAGE */]: message,
1357
+ ["type" /* HelperNameMap.TYPE */]: type,
1358
+ ["interpolate" /* HelperNameMap.INTERPOLATE */]: interpolate,
1359
+ ["normalize" /* HelperNameMap.NORMALIZE */]: normalize,
1360
+ ["values" /* HelperNameMap.VALUES */]: assign({}, _list, _named)
1361
+ };
1362
+ return ctx;
1639
1363
  }
1640
1364
 
1641
- // implementation of `number` function
1642
- function number(context, ...args) {
1643
- const { numberFormats, unresolving, fallbackLocale, onWarn, localeFallbacker } = context;
1644
- const { __numberFormatters } = context;
1645
- if ((process.env.NODE_ENV !== 'production') && !Availabilities.numberFormat) {
1646
- onWarn(getWarnMessage(CoreWarnCodes.CANNOT_FORMAT_NUMBER));
1647
- return MISSING_RESOLVE_VALUE;
1648
- }
1649
- const [key, value, options, overrides] = parseNumberArgs(...args);
1365
+ const NOOP_MESSAGE_FUNCTION = () => '';
1366
+ const isMessageFunction = (val) => isFunction(val);
1367
+ // implementation of `translate` function
1368
+ function translate(context, ...args) {
1369
+ const { fallbackFormat, postTranslation, unresolving, messageCompiler, fallbackLocale, messages } = context;
1370
+ const [key, options] = parseTranslateArgs(...args);
1650
1371
  const missingWarn = isBoolean(options.missingWarn)
1651
1372
  ? options.missingWarn
1652
1373
  : context.missingWarn;
1653
1374
  const fallbackWarn = isBoolean(options.fallbackWarn)
1654
1375
  ? options.fallbackWarn
1655
1376
  : context.fallbackWarn;
1656
- const part = !!options.part;
1377
+ const escapeParameter = isBoolean(options.escapeParameter)
1378
+ ? options.escapeParameter
1379
+ : context.escapeParameter;
1380
+ const resolvedMessage = !!options.resolvedMessage;
1381
+ // prettier-ignore
1382
+ const defaultMsgOrKey = isString(options.default) || isBoolean(options.default) // default by function option
1383
+ ? !isBoolean(options.default)
1384
+ ? options.default
1385
+ : (!messageCompiler ? () => key : key)
1386
+ : fallbackFormat // default by `fallbackFormat` option
1387
+ ? (!messageCompiler ? () => key : key)
1388
+ : null;
1389
+ const enableDefaultMsg = fallbackFormat ||
1390
+ (defaultMsgOrKey != null &&
1391
+ (isString(defaultMsgOrKey) || isFunction(defaultMsgOrKey)));
1657
1392
  const locale = getLocale(context, options);
1658
- const locales = localeFallbacker(context, // eslint-disable-line @typescript-eslint/no-explicit-any
1659
- fallbackLocale, locale);
1660
- if (!isString(key) || key === '') {
1661
- return new Intl.NumberFormat(locale, overrides).format(value);
1393
+ // escape params
1394
+ escapeParameter && escapeParams(options);
1395
+ // resolve message format
1396
+ // eslint-disable-next-line prefer-const
1397
+ let [formatScope, targetLocale, message] = !resolvedMessage
1398
+ ? resolveMessageFormat(context, key, locale, fallbackLocale, fallbackWarn, missingWarn)
1399
+ : [
1400
+ key,
1401
+ locale,
1402
+ messages[locale] || {}
1403
+ ];
1404
+ // NOTE:
1405
+ // Fix to work around `ssrTransfrom` bug in Vite.
1406
+ // https://github.com/vitejs/vite/issues/4306
1407
+ // To get around this, use temporary variables.
1408
+ // https://github.com/nuxt/framework/issues/1461#issuecomment-954606243
1409
+ let format = formatScope;
1410
+ // if you use default message, set it as message format!
1411
+ let cacheBaseKey = key;
1412
+ if (!resolvedMessage &&
1413
+ !(isString(format) ||
1414
+ isMessageAST(format) ||
1415
+ isMessageFunction(format))) {
1416
+ if (enableDefaultMsg) {
1417
+ format = defaultMsgOrKey;
1418
+ cacheBaseKey = format;
1419
+ }
1662
1420
  }
1663
- // resolve format
1664
- let numberFormat = {};
1421
+ // checking message format and target locale
1422
+ if (!resolvedMessage &&
1423
+ (!(isString(format) ||
1424
+ isMessageAST(format) ||
1425
+ isMessageFunction(format)) ||
1426
+ !isString(targetLocale))) {
1427
+ return unresolving ? NOT_REOSLVED : key;
1428
+ }
1429
+ // TODO: refactor
1430
+ if ((process.env.NODE_ENV !== 'production') && isString(format) && context.messageCompiler == null) {
1431
+ warn(`The message format compilation is not supported in this build. ` +
1432
+ `Because message compiler isn't included. ` +
1433
+ `You need to pre-compilation all message format. ` +
1434
+ `So translate function return '${key}'.`);
1435
+ return key;
1436
+ }
1437
+ // setup compile error detecting
1438
+ let occurred = false;
1439
+ const onError = () => {
1440
+ occurred = true;
1441
+ };
1442
+ // compile message format
1443
+ const msg = !isMessageFunction(format)
1444
+ ? compileMessageFormat(context, key, targetLocale, format, cacheBaseKey, onError)
1445
+ : format;
1446
+ // if occurred compile error, return the message format
1447
+ if (occurred) {
1448
+ return format;
1449
+ }
1450
+ // evaluate message with context
1451
+ const ctxOptions = getMessageContextOptions(context, targetLocale, message, options);
1452
+ const msgContext = createMessageContext(ctxOptions);
1453
+ const messaged = evaluateMessage(context, msg, msgContext);
1454
+ // if use post translation option, proceed it with handler
1455
+ const ret = postTranslation
1456
+ ? postTranslation(messaged, key)
1457
+ : messaged;
1458
+ // NOTE: experimental !!
1459
+ if ((process.env.NODE_ENV !== 'production') || __INTLIFY_PROD_DEVTOOLS__) {
1460
+ // prettier-ignore
1461
+ const payloads = {
1462
+ timestamp: Date.now(),
1463
+ key: isString(key)
1464
+ ? key
1465
+ : isMessageFunction(format)
1466
+ ? format.key
1467
+ : '',
1468
+ locale: targetLocale || (isMessageFunction(format)
1469
+ ? format.locale
1470
+ : ''),
1471
+ format: isString(format)
1472
+ ? format
1473
+ : isMessageFunction(format)
1474
+ ? format.source
1475
+ : '',
1476
+ message: ret
1477
+ };
1478
+ payloads.meta = assign({}, context.__meta, getAdditionalMeta() || {});
1479
+ translateDevTools(payloads);
1480
+ }
1481
+ return ret;
1482
+ }
1483
+ function escapeParams(options) {
1484
+ if (isArray(options.list)) {
1485
+ options.list = options.list.map(item => isString(item) ? escapeHtml(item) : item);
1486
+ }
1487
+ else if (isObject(options.named)) {
1488
+ Object.keys(options.named).forEach(key => {
1489
+ if (isString(options.named[key])) {
1490
+ options.named[key] = escapeHtml(options.named[key]);
1491
+ }
1492
+ });
1493
+ }
1494
+ }
1495
+ function resolveMessageFormat(context, key, locale, fallbackLocale, fallbackWarn, missingWarn) {
1496
+ const { messages, onWarn, messageResolver: resolveValue, localeFallbacker } = context;
1497
+ const locales = localeFallbacker(context, fallbackLocale, locale); // eslint-disable-line @typescript-eslint/no-explicit-any
1498
+ let message = {};
1665
1499
  let targetLocale;
1666
1500
  let format = null;
1667
1501
  let from = locale;
1668
1502
  let to = null;
1669
- const type = 'number format';
1503
+ const type = 'translate';
1670
1504
  for (let i = 0; i < locales.length; i++) {
1671
1505
  targetLocale = to = locales[i];
1672
1506
  if ((process.env.NODE_ENV !== 'production') &&
1673
1507
  locale !== targetLocale &&
1508
+ !isAlmostSameLocale(locale, targetLocale) &&
1674
1509
  isTranslateFallbackWarn(fallbackWarn, key)) {
1675
- onWarn(getWarnMessage(CoreWarnCodes.FALLBACK_TO_NUMBER_FORMAT, {
1510
+ onWarn(getWarnMessage(CoreWarnCodes.FALLBACK_TO_TRANSLATE, {
1676
1511
  key,
1677
1512
  target: targetLocale
1678
1513
  }));
@@ -1690,95 +1525,260 @@ function number(context, ...args) {
1690
1525
  });
1691
1526
  }
1692
1527
  }
1693
- numberFormat =
1694
- numberFormats[targetLocale] || {};
1695
- format = numberFormat[key];
1696
- if (isPlainObject(format))
1528
+ message =
1529
+ messages[targetLocale] || {};
1530
+ // for vue-devtools timeline event
1531
+ let start = null;
1532
+ let startTag;
1533
+ let endTag;
1534
+ if ((process.env.NODE_ENV !== 'production') && inBrowser) {
1535
+ start = window.performance.now();
1536
+ startTag = 'intlify-message-resolve-start';
1537
+ endTag = 'intlify-message-resolve-end';
1538
+ mark && mark(startTag);
1539
+ }
1540
+ if ((format = resolveValue(message, key)) === null) {
1541
+ // if null, resolve with object key path
1542
+ format = message[key]; // eslint-disable-line @typescript-eslint/no-explicit-any
1543
+ }
1544
+ // for vue-devtools timeline event
1545
+ if ((process.env.NODE_ENV !== 'production') && inBrowser) {
1546
+ const end = window.performance.now();
1547
+ const emitter = context.__v_emitter;
1548
+ if (emitter && start && format) {
1549
+ emitter.emit('message-resolve', {
1550
+ type: 'message-resolve',
1551
+ key,
1552
+ message: format,
1553
+ time: end - start,
1554
+ groupId: `${type}:${key}`
1555
+ });
1556
+ }
1557
+ if (startTag && endTag && mark && measure) {
1558
+ mark(endTag);
1559
+ measure('intlify message resolve', startTag, endTag);
1560
+ }
1561
+ }
1562
+ if (isString(format) || isMessageAST(format) || isMessageFunction(format)) {
1697
1563
  break;
1698
- handleMissing(context, key, targetLocale, missingWarn, type); // eslint-disable-line @typescript-eslint/no-explicit-any
1564
+ }
1565
+ if (!isImplicitFallback(targetLocale, locales)) {
1566
+ const missingRet = handleMissing(context, // eslint-disable-line @typescript-eslint/no-explicit-any
1567
+ key, targetLocale, missingWarn, type);
1568
+ if (missingRet !== key) {
1569
+ format = missingRet;
1570
+ }
1571
+ }
1699
1572
  from = to;
1700
1573
  }
1701
- // checking format and target locale
1702
- if (!isPlainObject(format) || !isString(targetLocale)) {
1703
- return unresolving ? NOT_REOSLVED : key;
1574
+ return [format, targetLocale, message];
1575
+ }
1576
+ function compileMessageFormat(context, key, targetLocale, format, cacheBaseKey, onError) {
1577
+ const { messageCompiler, warnHtmlMessage } = context;
1578
+ if (isMessageFunction(format)) {
1579
+ const msg = format;
1580
+ msg.locale = msg.locale || targetLocale;
1581
+ msg.key = msg.key || key;
1582
+ return msg;
1704
1583
  }
1705
- let id = `${targetLocale}__${key}`;
1706
- if (!isEmptyObject(overrides)) {
1707
- id = `${id}__${JSON.stringify(overrides)}`;
1584
+ if (messageCompiler == null) {
1585
+ const msg = (() => format);
1586
+ msg.locale = targetLocale;
1587
+ msg.key = key;
1588
+ return msg;
1708
1589
  }
1709
- let formatter = __numberFormatters.get(id);
1710
- if (!formatter) {
1711
- formatter = new Intl.NumberFormat(targetLocale, assign({}, format, overrides));
1712
- __numberFormatters.set(id, formatter);
1590
+ // for vue-devtools timeline event
1591
+ let start = null;
1592
+ let startTag;
1593
+ let endTag;
1594
+ if ((process.env.NODE_ENV !== 'production') && inBrowser) {
1595
+ start = window.performance.now();
1596
+ startTag = 'intlify-message-compilation-start';
1597
+ endTag = 'intlify-message-compilation-end';
1598
+ mark && mark(startTag);
1713
1599
  }
1714
- return !part ? formatter.format(value) : formatter.formatToParts(value);
1600
+ const msg = messageCompiler(format, getCompileContext(context, targetLocale, cacheBaseKey, format, warnHtmlMessage, onError));
1601
+ // for vue-devtools timeline event
1602
+ if ((process.env.NODE_ENV !== 'production') && inBrowser) {
1603
+ const end = window.performance.now();
1604
+ const emitter = context.__v_emitter;
1605
+ if (emitter && start) {
1606
+ emitter.emit('message-compilation', {
1607
+ type: 'message-compilation',
1608
+ message: format,
1609
+ time: end - start,
1610
+ groupId: `${'translate'}:${key}`
1611
+ });
1612
+ }
1613
+ if (startTag && endTag && mark && measure) {
1614
+ mark(endTag);
1615
+ measure('intlify message compilation', startTag, endTag);
1616
+ }
1617
+ }
1618
+ msg.locale = targetLocale;
1619
+ msg.key = key;
1620
+ msg.source = format;
1621
+ return msg;
1622
+ }
1623
+ function evaluateMessage(context, msg, msgCtx) {
1624
+ // for vue-devtools timeline event
1625
+ let start = null;
1626
+ let startTag;
1627
+ let endTag;
1628
+ if ((process.env.NODE_ENV !== 'production') && inBrowser) {
1629
+ start = window.performance.now();
1630
+ startTag = 'intlify-message-evaluation-start';
1631
+ endTag = 'intlify-message-evaluation-end';
1632
+ mark && mark(startTag);
1633
+ }
1634
+ const messaged = msg(msgCtx);
1635
+ // for vue-devtools timeline event
1636
+ if ((process.env.NODE_ENV !== 'production') && inBrowser) {
1637
+ const end = window.performance.now();
1638
+ const emitter = context.__v_emitter;
1639
+ if (emitter && start) {
1640
+ emitter.emit('message-evaluation', {
1641
+ type: 'message-evaluation',
1642
+ value: messaged,
1643
+ time: end - start,
1644
+ groupId: `${'translate'}:${msg.key}`
1645
+ });
1646
+ }
1647
+ if (startTag && endTag && mark && measure) {
1648
+ mark(endTag);
1649
+ measure('intlify message evaluation', startTag, endTag);
1650
+ }
1651
+ }
1652
+ return messaged;
1715
1653
  }
1716
1654
  /** @internal */
1717
- const NUMBER_FORMAT_OPTIONS_KEYS = [
1718
- 'localeMatcher',
1719
- 'style',
1720
- 'currency',
1721
- 'currencyDisplay',
1722
- 'currencySign',
1723
- 'useGrouping',
1724
- 'minimumIntegerDigits',
1725
- 'minimumFractionDigits',
1726
- 'maximumFractionDigits',
1727
- 'minimumSignificantDigits',
1728
- 'maximumSignificantDigits',
1729
- 'compactDisplay',
1730
- 'notation',
1731
- 'signDisplay',
1732
- 'unit',
1733
- 'unitDisplay',
1734
- 'roundingMode',
1735
- 'roundingPriority',
1736
- 'roundingIncrement',
1737
- 'trailingZeroDisplay'
1738
- ];
1739
- /** @internal */
1740
- function parseNumberArgs(...args) {
1741
- const [arg1, arg2, arg3, arg4] = args;
1655
+ function parseTranslateArgs(...args) {
1656
+ const [arg1, arg2, arg3] = args;
1742
1657
  const options = {};
1743
- let overrides = {};
1744
- if (!isNumber(arg1)) {
1658
+ if (!isString(arg1) &&
1659
+ !isNumber(arg1) &&
1660
+ !isMessageFunction(arg1) &&
1661
+ !isMessageAST(arg1)) {
1745
1662
  throw createCoreError(CoreErrorCodes.INVALID_ARGUMENT);
1746
1663
  }
1747
- const value = arg1;
1748
- if (isString(arg2)) {
1749
- options.key = arg2;
1664
+ // prettier-ignore
1665
+ const key = isNumber(arg1)
1666
+ ? String(arg1)
1667
+ : isMessageFunction(arg1)
1668
+ ? arg1
1669
+ : arg1;
1670
+ if (isNumber(arg2)) {
1671
+ options.plural = arg2;
1750
1672
  }
1751
- else if (isPlainObject(arg2)) {
1752
- Object.keys(arg2).forEach(key => {
1753
- if (NUMBER_FORMAT_OPTIONS_KEYS.includes(key)) {
1754
- overrides[key] = arg2[key];
1755
- }
1756
- else {
1757
- options[key] = arg2[key];
1758
- }
1759
- });
1673
+ else if (isString(arg2)) {
1674
+ options.default = arg2;
1760
1675
  }
1761
- if (isString(arg3)) {
1762
- options.locale = arg3;
1676
+ else if (isPlainObject(arg2) && !isEmptyObject(arg2)) {
1677
+ options.named = arg2;
1678
+ }
1679
+ else if (isArray(arg2)) {
1680
+ options.list = arg2;
1681
+ }
1682
+ if (isNumber(arg3)) {
1683
+ options.plural = arg3;
1684
+ }
1685
+ else if (isString(arg3)) {
1686
+ options.default = arg3;
1763
1687
  }
1764
1688
  else if (isPlainObject(arg3)) {
1765
- overrides = arg3;
1689
+ assign(options, arg3);
1766
1690
  }
1767
- if (isPlainObject(arg4)) {
1768
- overrides = arg4;
1691
+ return [key, options];
1692
+ }
1693
+ function getCompileContext(context, locale, key, source, warnHtmlMessage, onError) {
1694
+ return {
1695
+ locale,
1696
+ key,
1697
+ warnHtmlMessage,
1698
+ onError: (err) => {
1699
+ onError && onError(err);
1700
+ if ((process.env.NODE_ENV !== 'production')) {
1701
+ const _source = getSourceForCodeFrame(source);
1702
+ const message = `Message compilation error: ${err.message}`;
1703
+ const codeFrame = err.location &&
1704
+ _source &&
1705
+ generateCodeFrame(_source, err.location.start.offset, err.location.end.offset);
1706
+ const emitter = context.__v_emitter;
1707
+ if (emitter && _source) {
1708
+ emitter.emit('compile-error', {
1709
+ message: _source,
1710
+ error: err.message,
1711
+ start: err.location && err.location.start.offset,
1712
+ end: err.location && err.location.end.offset,
1713
+ groupId: `${'translate'}:${key}`
1714
+ });
1715
+ }
1716
+ console.error(codeFrame ? `${message}\n${codeFrame}` : message);
1717
+ }
1718
+ else {
1719
+ throw err;
1720
+ }
1721
+ },
1722
+ onCacheKey: (source) => generateFormatCacheKey(locale, key, source)
1723
+ };
1724
+ }
1725
+ function getSourceForCodeFrame(source) {
1726
+ if (isString(source)) {
1727
+ return source;
1728
+ }
1729
+ else {
1730
+ if (source.loc && source.loc.source) {
1731
+ return source.loc.source;
1732
+ }
1769
1733
  }
1770
- return [options.key || '', value, options, overrides];
1771
1734
  }
1772
- /** @internal */
1773
- function clearNumberFormat(ctx, locale, format) {
1774
- const context = ctx;
1775
- for (const key in format) {
1776
- const id = `${locale}__${key}`;
1777
- if (!context.__numberFormatters.has(id)) {
1778
- continue;
1735
+ function getMessageContextOptions(context, locale, message, options) {
1736
+ const { modifiers, pluralRules, messageResolver: resolveValue, fallbackLocale, fallbackWarn, missingWarn, fallbackContext } = context;
1737
+ const resolveMessage = (key, useLinked) => {
1738
+ let val = resolveValue(message, key);
1739
+ // fallback
1740
+ if (val == null && (fallbackContext || useLinked)) {
1741
+ const [, , message] = resolveMessageFormat(fallbackContext || context, // NOTE: if has fallbackContext, fallback to root, else if use linked, fallback to local context
1742
+ key, locale, fallbackLocale, fallbackWarn, missingWarn);
1743
+ val = resolveValue(message, key);
1779
1744
  }
1780
- context.__numberFormatters.delete(id);
1745
+ if (isString(val) || isMessageAST(val)) {
1746
+ let occurred = false;
1747
+ const onError = () => {
1748
+ occurred = true;
1749
+ };
1750
+ const msg = compileMessageFormat(context, key, locale, val, key, onError);
1751
+ return !occurred
1752
+ ? msg
1753
+ : NOOP_MESSAGE_FUNCTION;
1754
+ }
1755
+ else if (isMessageFunction(val)) {
1756
+ return val;
1757
+ }
1758
+ else {
1759
+ // TODO: should be implemented warning message
1760
+ return NOOP_MESSAGE_FUNCTION;
1761
+ }
1762
+ };
1763
+ const ctxOptions = {
1764
+ locale,
1765
+ modifiers,
1766
+ pluralRules,
1767
+ messages: resolveMessage
1768
+ };
1769
+ if (context.processor) {
1770
+ ctxOptions.processor = context.processor;
1771
+ }
1772
+ if (options.list) {
1773
+ ctxOptions.list = options.list;
1774
+ }
1775
+ if (options.named) {
1776
+ ctxOptions.named = options.named;
1781
1777
  }
1778
+ if (isNumber(options.plural)) {
1779
+ ctxOptions.pluralIndex = options.plural;
1780
+ }
1781
+ return ctxOptions;
1782
1782
  }
1783
1783
 
1784
1784
  {