vue-i18n 11.2.8 → 11.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/vue-i18n.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /*!
2
- * vue-i18n v11.2.8
3
- * (c) 2025 kazuya kawaguchi
2
+ * vue-i18n v11.3.1
3
+ * (c) 2026 kazuya kawaguchi
4
4
  * Released under the MIT License.
5
5
  */
6
6
  'use strict';
@@ -30,7 +30,7 @@ var Vue__namespace = /*#__PURE__*/_interopNamespaceDefault(Vue);
30
30
  *
31
31
  * @VueI18nGeneral
32
32
  */
33
- const VERSION = '11.2.8';
33
+ const VERSION = '11.3.1';
34
34
 
35
35
  const I18nErrorCodes = {
36
36
  // composer module errors
@@ -535,11 +535,25 @@ function createComposer(options = {}) {
535
535
  return false;
536
536
  }
537
537
  const targetLocale = shared.isString(locale) ? locale : _locale.value;
538
- const message = getLocaleMessage(targetLocale);
539
- const resolved = _context.messageResolver(message, key);
540
- return (coreBase.isMessageAST(resolved) ||
541
- coreBase.isMessageFunction(resolved) ||
542
- shared.isString(resolved));
538
+ // When locale is explicitly specified, check only that locale (no fallback chain)
539
+ // When locale is not specified, check the fallback locale chain
540
+ const locales = shared.isString(locale)
541
+ ? [targetLocale]
542
+ : coreBase.fallbackWithLocaleChain(_context, _fallbackLocale.value, targetLocale);
543
+ for (let i = 0; i < locales.length; i++) {
544
+ const message = getLocaleMessage(locales[i]);
545
+ let resolved = _context.messageResolver(message, key);
546
+ // if null, resolve with object key path (for flat keys containing dots)
547
+ if (resolved === null) {
548
+ resolved = message[key];
549
+ }
550
+ if (coreBase.isMessageAST(resolved) ||
551
+ coreBase.isMessageFunction(resolved) ||
552
+ shared.isString(resolved)) {
553
+ return true;
554
+ }
555
+ }
556
+ return false;
543
557
  }, () => [key], 'translate exists', root => {
544
558
  return Reflect.apply(root.te, root, [key, locale]);
545
559
  }, NOOP_RETURN_FALSE, val => shared.isBoolean(val));
@@ -1414,8 +1428,7 @@ function vTDirective(i18n) {
1414
1428
  };
1415
1429
  const register = (el, binding) => {
1416
1430
  const [textContent, composer] = _process(binding);
1417
- if (shared.inBrowser && i18n.global === composer) {
1418
- // global scope only
1431
+ if (shared.inBrowser) {
1419
1432
  el.__i18nWatcher = Vue.watch(composer.locale, () => {
1420
1433
  binding.instance && binding.instance.$forceUpdate();
1421
1434
  });
@@ -3684,7 +3684,7 @@ declare module 'vue' {
3684
3684
  * @returns formatted value
3685
3685
  */
3686
3686
  $d<
3687
- Value extends number | Date = number,
3687
+ Value extends number | Date | string = number,
3688
3688
  Key extends string = string,
3689
3689
  DefinedDateTimeFormat extends
3690
3690
  RemovedIndexResources<DefineDateTimeFormat> = RemovedIndexResources<DefineDateTimeFormat>,
@@ -3711,7 +3711,7 @@ declare module 'vue' {
3711
3711
  * @returns formatted value
3712
3712
  */
3713
3713
  $d<
3714
- Value extends number | Date = number,
3714
+ Value extends number | Date | string = number,
3715
3715
  Key extends string = string,
3716
3716
  DefinedDateTimeFormat extends
3717
3717
  RemovedIndexResources<DefineDateTimeFormat> = RemovedIndexResources<DefineDateTimeFormat>,
@@ -3764,7 +3764,7 @@ declare module 'vue' {
3764
3764
  * @returns formatted value
3765
3765
  */
3766
3766
  $d<
3767
- Value extends number | Date = number,
3767
+ Value extends number | Date | string = number,
3768
3768
  Key extends string = string,
3769
3769
  DefinedDateTimeFormat extends
3770
3770
  RemovedIndexResources<DefineDateTimeFormat> = RemovedIndexResources<DefineDateTimeFormat>,
@@ -3791,7 +3791,7 @@ declare module 'vue' {
3791
3791
  * @returns formatted value
3792
3792
  */
3793
3793
  $d<
3794
- Value extends number | Date = number,
3794
+ Value extends number | Date | string = number,
3795
3795
  Key extends string = string,
3796
3796
  DefinedDateTimeFormat extends
3797
3797
  RemovedIndexResources<DefineDateTimeFormat> = RemovedIndexResources<DefineDateTimeFormat>,
@@ -3863,7 +3863,7 @@ declare module 'vue' {
3863
3863
  $n<
3864
3864
  Key extends string = string,
3865
3865
  DefinedNumberFormat extends
3866
- RemovedIndexResources<DefineDateTimeFormat> = RemovedIndexResources<DefineDateTimeFormat>,
3866
+ RemovedIndexResources<DefineNumberFormat> = RemovedIndexResources<DefineNumberFormat>,
3867
3867
  Keys = IsEmptyObject<DefinedNumberFormat> extends false
3868
3868
  ? PickupFormatPathKeys<{
3869
3869
  [K in keyof DefinedNumberFormat]: DefinedNumberFormat[K]
@@ -3889,7 +3889,7 @@ declare module 'vue' {
3889
3889
  $n<
3890
3890
  Key extends string = string,
3891
3891
  DefinedNumberFormat extends
3892
- RemovedIndexResources<DefineDateTimeFormat> = RemovedIndexResources<DefineDateTimeFormat>,
3892
+ RemovedIndexResources<DefineNumberFormat> = RemovedIndexResources<DefineNumberFormat>,
3893
3893
  Keys = IsEmptyObject<DefinedNumberFormat> extends false
3894
3894
  ? PickupFormatPathKeys<{
3895
3895
  [K in keyof DefinedNumberFormat]: DefinedNumberFormat[K]
@@ -3977,7 +3977,7 @@ declare module 'vue' {
3977
3977
  $n<
3978
3978
  Key extends string = string,
3979
3979
  DefinedNumberFormat extends
3980
- RemovedIndexResources<DefineDateTimeFormat> = RemovedIndexResources<DefineDateTimeFormat>,
3980
+ RemovedIndexResources<DefineNumberFormat> = RemovedIndexResources<DefineNumberFormat>,
3981
3981
  Keys = IsEmptyObject<DefinedNumberFormat> extends false
3982
3982
  ? PickupFormatPathKeys<{
3983
3983
  [K in keyof DefinedNumberFormat]: DefinedNumberFormat[K]
@@ -4003,7 +4003,7 @@ declare module 'vue' {
4003
4003
  $n<
4004
4004
  Key extends string = string,
4005
4005
  DefinedNumberFormat extends
4006
- RemovedIndexResources<DefineDateTimeFormat> = RemovedIndexResources<DefineDateTimeFormat>,
4006
+ RemovedIndexResources<DefineNumberFormat> = RemovedIndexResources<DefineNumberFormat>,
4007
4007
  Keys = IsEmptyObject<DefinedNumberFormat> extends false
4008
4008
  ? PickupFormatPathKeys<{
4009
4009
  [K in keyof DefinedNumberFormat]: DefinedNumberFormat[K]
@@ -4029,7 +4029,7 @@ declare module 'vue' {
4029
4029
  $n<
4030
4030
  Key extends string,
4031
4031
  DefinedNumberFormat extends
4032
- RemovedIndexResources<DefineDateTimeFormat> = RemovedIndexResources<DefineDateTimeFormat>,
4032
+ RemovedIndexResources<DefineNumberFormat> = RemovedIndexResources<DefineNumberFormat>,
4033
4033
  Keys = IsEmptyObject<DefinedNumberFormat> extends false
4034
4034
  ? PickupFormatPathKeys<{
4035
4035
  [K in keyof DefinedNumberFormat]: DefinedNumberFormat[K]
@@ -1,6 +1,6 @@
1
1
  /*!
2
- * vue-i18n v11.2.8
3
- * (c) 2025 kazuya kawaguchi
2
+ * vue-i18n v11.3.1
3
+ * (c) 2026 kazuya kawaguchi
4
4
  * Released under the MIT License.
5
5
  */
6
6
  import * as Vue from 'vue';
@@ -716,7 +716,24 @@ function createTokenizer(source, options = {}) {
716
716
  let buf = '';
717
717
  while (true) {
718
718
  const ch = scnr.currentChar();
719
- if (ch === "{" /* TokenChars.BraceLeft */ ||
719
+ if (ch === '\\') {
720
+ const nextCh = scnr.peek();
721
+ if (nextCh === "{" /* TokenChars.BraceLeft */ ||
722
+ nextCh === "}" /* TokenChars.BraceRight */ ||
723
+ nextCh === "@" /* TokenChars.LinkedAlias */ ||
724
+ nextCh === "|" /* TokenChars.Pipe */ ||
725
+ nextCh === '\\') {
726
+ buf += ch + nextCh;
727
+ scnr.next();
728
+ scnr.next();
729
+ }
730
+ else {
731
+ scnr.resetPeek();
732
+ buf += ch;
733
+ scnr.next();
734
+ }
735
+ }
736
+ else if (ch === "{" /* TokenChars.BraceLeft */ ||
720
737
  ch === "}" /* TokenChars.BraceRight */ ||
721
738
  ch === "@" /* TokenChars.LinkedAlias */ ||
722
739
  ch === "|" /* TokenChars.Pipe */ ||
@@ -1102,6 +1119,11 @@ function createTokenizer(source, options = {}) {
1102
1119
  const ERROR_DOMAIN$2 = 'parser';
1103
1120
  // Backslash backslash, backslash quote, uHHHH, UHHHHHH.
1104
1121
  const KNOWN_ESCAPES = /(?:\\\\|\\'|\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{6}))/g;
1122
+ // Text context escape sequences: \\, \@, \{, \}, \|
1123
+ const TEXT_ESCAPES = /\\([\\@{}|])/g;
1124
+ function fromTextEscapeSequence(_match, char) {
1125
+ return char;
1126
+ }
1105
1127
  function fromEscapeSequence(match, codePoint4, codePoint6) {
1106
1128
  switch (match) {
1107
1129
  case `\\\\`:
@@ -1157,7 +1179,7 @@ function createParser(options = {}) {
1157
1179
  function parseText(tokenizer, value) {
1158
1180
  const context = tokenizer.context();
1159
1181
  const node = startNode(3 /* NodeTypes.Text */, context.offset, context.startLoc);
1160
- node.value = value;
1182
+ node.value = value.replace(TEXT_ESCAPES, fromTextEscapeSequence);
1161
1183
  endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
1162
1184
  return node;
1163
1185
  }
@@ -2462,6 +2484,7 @@ function resolveValue(obj, path) {
2462
2484
  }
2463
2485
  // resolve path value
2464
2486
  const len = hit.length;
2487
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- for generic object
2465
2488
  let last = obj;
2466
2489
  let i = 0;
2467
2490
  while (i < len) {
@@ -2474,6 +2497,12 @@ function resolveValue(obj, path) {
2474
2497
  if (AST_NODE_PROPS_KEYS.includes(key) && isMessageAST(last)) {
2475
2498
  return null;
2476
2499
  }
2500
+ if (!isObject(last)) {
2501
+ return null;
2502
+ }
2503
+ if (!hasOwn(last, key)) {
2504
+ return null;
2505
+ }
2477
2506
  const val = last[key];
2478
2507
  if (val === undefined) {
2479
2508
  return null;
@@ -2494,9 +2523,11 @@ const CoreWarnCodes = {
2494
2523
  FALLBACK_TO_NUMBER_FORMAT: 4,
2495
2524
  CANNOT_FORMAT_DATE: 5,
2496
2525
  FALLBACK_TO_DATE_FORMAT: 6,
2497
- EXPERIMENTAL_CUSTOM_MESSAGE_COMPILER: 7
2526
+ EXPERIMENTAL_CUSTOM_MESSAGE_COMPILER: 7,
2527
+ INVALID_NUMBER_ARGUMENT: 8,
2528
+ INVALID_DATE_ARGUMENT: 9
2498
2529
  };
2499
- const CORE_WARN_CODES_EXTEND_POINT = 8;
2530
+ const CORE_WARN_CODES_EXTEND_POINT = 10;
2500
2531
  /** @internal */
2501
2532
  const warnMessages$1 = {
2502
2533
  [CoreWarnCodes.NOT_FOUND_KEY]: `Not found '{key}' key in '{locale}' locale messages.`,
@@ -2505,7 +2536,9 @@ const warnMessages$1 = {
2505
2536
  [CoreWarnCodes.FALLBACK_TO_NUMBER_FORMAT]: `Fall back to number format '{key}' key with '{target}' locale.`,
2506
2537
  [CoreWarnCodes.CANNOT_FORMAT_DATE]: `Cannot format a date value due to not supported Intl.DateTimeFormat.`,
2507
2538
  [CoreWarnCodes.FALLBACK_TO_DATE_FORMAT]: `Fall back to datetime format '{key}' key with '{target}' locale.`,
2508
- [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.`
2539
+ [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.`,
2540
+ [CoreWarnCodes.INVALID_NUMBER_ARGUMENT]: `Invalid argument for number formatting: expected a number but received '{value}'.`,
2541
+ [CoreWarnCodes.INVALID_DATE_ARGUMENT]: `Invalid argument for datetime formatting: expected a Date, number, or ISO string but received '{value}'.`
2509
2542
  };
2510
2543
  function getWarnMessage$1(code, ...args) {
2511
2544
  return format$1(warnMessages$1[code], ...args);
@@ -2516,7 +2549,7 @@ function getWarnMessage$1(code, ...args) {
2516
2549
  * Intlify core-base version
2517
2550
  * @internal
2518
2551
  */
2519
- const VERSION$1 = '11.2.8';
2552
+ const VERSION$1 = '11.3.1';
2520
2553
  const NOT_REOSLVED = -1;
2521
2554
  const DEFAULT_LOCALE = 'en-US';
2522
2555
  const MISSING_RESOLVE_VALUE = '';
@@ -2780,6 +2813,14 @@ function datetime(context, ...args) {
2780
2813
  onWarn(getWarnMessage$1(CoreWarnCodes.CANNOT_FORMAT_DATE));
2781
2814
  return MISSING_RESOLVE_VALUE;
2782
2815
  }
2816
+ if (!isString(args[0]) && !isDate(args[0]) && !isNumber(args[0])) {
2817
+ {
2818
+ onWarn(getWarnMessage$1(CoreWarnCodes.INVALID_DATE_ARGUMENT, {
2819
+ value: String(args[0])
2820
+ }));
2821
+ }
2822
+ return MISSING_RESOLVE_VALUE;
2823
+ }
2783
2824
  const [key, value, options, overrides] = parseDateTimeArgs(...args);
2784
2825
  const missingWarn = isBoolean(options.missingWarn)
2785
2826
  ? options.missingWarn
@@ -2792,7 +2833,7 @@ function datetime(context, ...args) {
2792
2833
  const locales = localeFallbacker(context, // eslint-disable-line @typescript-eslint/no-explicit-any
2793
2834
  fallbackLocale, locale);
2794
2835
  if (!isString(key) || key === '') {
2795
- return new Intl.DateTimeFormat(locale, overrides).format(value);
2836
+ return new Intl.DateTimeFormat(locale.replace(/!/g, ''), overrides).format(value);
2796
2837
  }
2797
2838
  // resolve format
2798
2839
  let datetimeFormat = {};
@@ -2954,6 +2995,14 @@ function number(context, ...args) {
2954
2995
  onWarn(getWarnMessage$1(CoreWarnCodes.CANNOT_FORMAT_NUMBER));
2955
2996
  return MISSING_RESOLVE_VALUE;
2956
2997
  }
2998
+ if (!isNumber(args[0])) {
2999
+ {
3000
+ onWarn(getWarnMessage$1(CoreWarnCodes.INVALID_NUMBER_ARGUMENT, {
3001
+ value: String(args[0])
3002
+ }));
3003
+ }
3004
+ return MISSING_RESOLVE_VALUE;
3005
+ }
2957
3006
  const [key, value, options, overrides] = parseNumberArgs(...args);
2958
3007
  const missingWarn = isBoolean(options.missingWarn)
2959
3008
  ? options.missingWarn
@@ -2966,7 +3015,7 @@ function number(context, ...args) {
2966
3015
  const locales = localeFallbacker(context, // eslint-disable-line @typescript-eslint/no-explicit-any
2967
3016
  fallbackLocale, locale);
2968
3017
  if (!isString(key) || key === '') {
2969
- return new Intl.NumberFormat(locale, overrides).format(value);
3018
+ return new Intl.NumberFormat(locale.replace(/!/g, ''), overrides).format(value);
2970
3019
  }
2971
3020
  // resolve format
2972
3021
  let numberFormat = {};
@@ -3095,59 +3144,43 @@ const DEFAULT_NORMALIZE = (values) => values.length === 0 ? '' : join(values);
3095
3144
  const DEFAULT_INTERPOLATE = toDisplayString;
3096
3145
  function pluralDefault(choice, choicesLength) {
3097
3146
  choice = Math.abs(choice);
3147
+ // singular (0) | plural (1)
3098
3148
  if (choicesLength === 2) {
3099
3149
  // prettier-ignore
3100
- return choice
3101
- ? choice > 1
3102
- ? 1
3103
- : 0
3150
+ return choice === 1
3151
+ ? 0
3104
3152
  : 1;
3105
3153
  }
3106
- return choice ? Math.min(choice, 2) : 0;
3154
+ // zero (0) | singular (1) | plural (2)
3155
+ return Math.min(choice, 2);
3107
3156
  }
3108
3157
  function getPluralIndex(options) {
3109
3158
  // prettier-ignore
3110
3159
  const index = isNumber(options.pluralIndex)
3111
3160
  ? options.pluralIndex
3112
3161
  : -1;
3113
- // prettier-ignore
3114
- return options.named && (isNumber(options.named.count) || isNumber(options.named.n))
3115
- ? isNumber(options.named.count)
3116
- ? options.named.count
3117
- : isNumber(options.named.n)
3118
- ? options.named.n
3119
- : index
3120
- : index;
3121
- }
3122
- function normalizeNamed(pluralIndex, props) {
3123
- if (!props.count) {
3124
- props.count = pluralIndex;
3125
- }
3126
- if (!props.n) {
3127
- props.n = pluralIndex;
3128
- }
3162
+ return isNumber(options.named?.count)
3163
+ ? options.named.count
3164
+ : isNumber(options.named?.n)
3165
+ ? options.named.n
3166
+ : index;
3129
3167
  }
3130
3168
  function createMessageContext(options = {}) {
3131
3169
  const locale = options.locale;
3132
3170
  const pluralIndex = getPluralIndex(options);
3133
- const pluralRule = isObject(options.pluralRules) &&
3134
- isString(locale) &&
3135
- isFunction(options.pluralRules[locale])
3171
+ const pluralRule = isString(locale) && isFunction(options.pluralRules?.[locale])
3136
3172
  ? options.pluralRules[locale]
3137
3173
  : pluralDefault;
3138
- const orgPluralRule = isObject(options.pluralRules) &&
3139
- isString(locale) &&
3140
- isFunction(options.pluralRules[locale])
3141
- ? pluralDefault
3142
- : undefined;
3143
- const plural = (messages) => {
3144
- return messages[pluralRule(pluralIndex, messages.length, orgPluralRule)];
3145
- };
3174
+ const orgPluralRule = pluralRule === pluralDefault ? undefined : pluralDefault;
3175
+ const plural = (messages) => messages[pluralRule(pluralIndex, messages.length, orgPluralRule)];
3146
3176
  const _list = options.list || [];
3147
3177
  const list = (index) => _list[index];
3148
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
3149
- const _named = options.named || create();
3150
- isNumber(options.pluralIndex) && normalizeNamed(pluralIndex, _named);
3178
+ const _named = options.named || create(); // eslint-disable-line @typescript-eslint/no-explicit-any
3179
+ // normalize named
3180
+ if (isNumber(options.pluralIndex)) {
3181
+ _named.count ||= options.pluralIndex;
3182
+ _named.n ||= options.pluralIndex;
3183
+ }
3151
3184
  const named = (key) => _named[key];
3152
3185
  function message(key, useLinked) {
3153
3186
  // prettier-ignore
@@ -3165,14 +3198,13 @@ function createMessageContext(options = {}) {
3165
3198
  const _modifier = (name) => options.modifiers
3166
3199
  ? options.modifiers[name]
3167
3200
  : DEFAULT_MODIFIER;
3168
- const normalize = isPlainObject(options.processor) && isFunction(options.processor.normalize)
3201
+ const normalize = isFunction(options.processor?.normalize)
3169
3202
  ? options.processor.normalize
3170
3203
  : DEFAULT_NORMALIZE;
3171
- const interpolate = isPlainObject(options.processor) &&
3172
- isFunction(options.processor.interpolate)
3204
+ const interpolate = isFunction(options.processor?.interpolate)
3173
3205
  ? options.processor.interpolate
3174
3206
  : DEFAULT_INTERPOLATE;
3175
- const type = isPlainObject(options.processor) && isString(options.processor.type)
3207
+ const type = isString(options.processor?.type)
3176
3208
  ? options.processor.type
3177
3209
  : DEFAULT_MESSAGE_DATA_TYPE;
3178
3210
  const linked = (key, ...args) => {
@@ -3197,11 +3229,13 @@ function createMessageContext(options = {}) {
3197
3229
  }
3198
3230
  }
3199
3231
  const ret = message(key, true)(ctx);
3232
+ // If the linked message is not resolved (empty string), fall back to the key itself
3233
+ const resolved = ret === '' || ret === undefined ? key : ret;
3200
3234
  const msg =
3201
3235
  // The message in vnode resolved with linked are returned as an array by processor.nomalize
3202
- type === 'vnode' && isArray(ret) && modifier
3203
- ? ret[0]
3204
- : ret;
3236
+ type === 'vnode' && isArray(resolved) && modifier
3237
+ ? resolved[0]
3238
+ : resolved;
3205
3239
  return modifier ? _modifier(modifier)(msg, type) : msg;
3206
3240
  };
3207
3241
  const ctx = {
@@ -3558,7 +3592,6 @@ function getCompileContext(context, locale, key, source, warnHtmlMessage, onErro
3558
3592
  onError && onError(err);
3559
3593
  {
3560
3594
  const _source = getSourceForCodeFrame(source);
3561
- const message = `Message compilation error: ${err.message}`;
3562
3595
  const codeFrame = err.location &&
3563
3596
  _source &&
3564
3597
  generateCodeFrame(_source, err.location.start.offset, err.location.end.offset);
@@ -3572,7 +3605,8 @@ function getCompileContext(context, locale, key, source, warnHtmlMessage, onErro
3572
3605
  groupId: `${'translate'}:${key}`
3573
3606
  });
3574
3607
  }
3575
- console.error(codeFrame ? `${message}\n${codeFrame}` : message);
3608
+ const message = `Message compilation error: ${err.message}`;
3609
+ throw new SyntaxError(codeFrame ? `${message}\n${codeFrame}` : message);
3576
3610
  }
3577
3611
  },
3578
3612
  onCacheKey: (source) => generateFormatCacheKey(locale, key, source)
@@ -3594,9 +3628,9 @@ function getMessageContextOptions(context, locale, message, options) {
3594
3628
  let val = resolveValue(message, key);
3595
3629
  // fallback
3596
3630
  if (val == null && (fallbackContext || useLinked)) {
3597
- const [, , message] = resolveMessageFormat(fallbackContext || context, // NOTE: if has fallbackContext, fallback to root, else if use linked, fallback to local context
3631
+ const [format, , message] = resolveMessageFormat(fallbackContext || context, // NOTE: if has fallbackContext, fallback to root, else if use linked, fallback to local context
3598
3632
  key, locale, fallbackLocale, fallbackWarn, missingWarn);
3599
- val = resolveValue(message, key);
3633
+ val = format ?? resolveValue(message, key);
3600
3634
  }
3601
3635
  if (isString(val) || isMessageAST(val)) {
3602
3636
  let occurred = false;
@@ -3645,7 +3679,7 @@ function getMessageContextOptions(context, locale, message, options) {
3645
3679
  *
3646
3680
  * @VueI18nGeneral
3647
3681
  */
3648
- const VERSION = '11.2.8';
3682
+ const VERSION = '11.3.1';
3649
3683
  /**
3650
3684
  * This is only called development env
3651
3685
  * istanbul-ignore-next
@@ -3709,19 +3743,20 @@ const InejctWithOptionSymbol =
3709
3743
  const DisposeSymbol = /* #__PURE__*/ makeSymbol('__dispose');
3710
3744
 
3711
3745
  const I18nWarnCodes = {
3712
- FALLBACK_TO_ROOT: CORE_WARN_CODES_EXTEND_POINT, // 8
3713
- NOT_FOUND_PARENT_SCOPE: 9,
3714
- IGNORE_OBJ_FLATTEN: 10,
3746
+ FALLBACK_TO_ROOT: CORE_WARN_CODES_EXTEND_POINT, // 10
3747
+ NOT_FOUND_PARENT_SCOPE: (CORE_WARN_CODES_EXTEND_POINT + 1),
3748
+ IGNORE_OBJ_FLATTEN: (CORE_WARN_CODES_EXTEND_POINT + 2),
3715
3749
  /**
3716
3750
  * @deprecated will be removed at vue-i18n v12
3717
3751
  */
3718
- DEPRECATE_LEGACY_MODE: 11,
3752
+ DEPRECATE_LEGACY_MODE: (CORE_WARN_CODES_EXTEND_POINT + 3),
3719
3753
  /**
3720
3754
  * @deprecated will be removed at vue-i18n v12
3721
3755
  */
3722
- DEPRECATE_TRANSLATE_CUSTOME_DIRECTIVE: 12,
3756
+ DEPRECATE_TRANSLATE_CUSTOME_DIRECTIVE: (CORE_WARN_CODES_EXTEND_POINT +
3757
+ 4),
3723
3758
  // duplicate `useI18n` calling
3724
- DUPLICATE_USE_I18N_CALLING: 13
3759
+ DUPLICATE_USE_I18N_CALLING: (CORE_WARN_CODES_EXTEND_POINT + 5)
3725
3760
  };
3726
3761
  const warnMessages = {
3727
3762
  [I18nWarnCodes.FALLBACK_TO_ROOT]: `Fall back to {type} '{key}' with root locale.`,
@@ -4246,11 +4281,25 @@ function createComposer(options = {}) {
4246
4281
  return false;
4247
4282
  }
4248
4283
  const targetLocale = isString(locale) ? locale : _locale.value;
4249
- const message = getLocaleMessage(targetLocale);
4250
- const resolved = _context.messageResolver(message, key);
4251
- return (isMessageAST(resolved) ||
4252
- isMessageFunction(resolved) ||
4253
- isString(resolved));
4284
+ // When locale is explicitly specified, check only that locale (no fallback chain)
4285
+ // When locale is not specified, check the fallback locale chain
4286
+ const locales = isString(locale)
4287
+ ? [targetLocale]
4288
+ : fallbackWithLocaleChain(_context, _fallbackLocale.value, targetLocale);
4289
+ for (let i = 0; i < locales.length; i++) {
4290
+ const message = getLocaleMessage(locales[i]);
4291
+ let resolved = _context.messageResolver(message, key);
4292
+ // if null, resolve with object key path (for flat keys containing dots)
4293
+ if (resolved === null) {
4294
+ resolved = message[key];
4295
+ }
4296
+ if (isMessageAST(resolved) ||
4297
+ isMessageFunction(resolved) ||
4298
+ isString(resolved)) {
4299
+ return true;
4300
+ }
4301
+ }
4302
+ return false;
4254
4303
  }, () => [key], 'translate exists', root => {
4255
4304
  return Reflect.apply(root.te, root, [key, locale]);
4256
4305
  }, NOOP_RETURN_FALSE, val => isBoolean(val));
@@ -5723,8 +5772,7 @@ function vTDirective(i18n) {
5723
5772
  };
5724
5773
  const register = (el, binding) => {
5725
5774
  const [textContent, composer] = _process(binding);
5726
- if (inBrowser && i18n.global === composer) {
5727
- // global scope only
5775
+ if (inBrowser) {
5728
5776
  el.__i18nWatcher = watch(composer.locale, () => {
5729
5777
  binding.instance && binding.instance.$forceUpdate();
5730
5778
  });