@intlify/core-base 11.4.7 → 11.4.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * core-base v11.4.7
2
+ * core-base v11.4.9
3
3
  * (c) 2026 kazuya kawaguchi
4
4
  * Released under the MIT License.
5
5
  */
@@ -310,7 +310,7 @@ function resolveLocale(locale) {
310
310
  * @remarks
311
311
  * A fallback locale function implemented with a simple fallback algorithm.
312
312
  *
313
- * Basically, it returns the value as specified in the `fallbackLocale` props, and is processed with the fallback inside intlify.
313
+ * Basically, the chain consists of `start` plus the specified fallback: for a string or array `fallbackLocale`, the value as specified in the props is used; for a map `fallbackLocale`, the map's **keys** are used and the `default` key is skipped since it is not a locale name.
314
314
  *
315
315
  * @param ctx - A {@link CoreContext | context}
316
316
  * @param fallback - A {@link FallbackLocale | fallback locale}
@@ -327,7 +327,7 @@ function fallbackWithSimple(ctx, fallback, start) {
327
327
  ...(shared.isArray(fallback)
328
328
  ? fallback
329
329
  : shared.isObject(fallback)
330
- ? Object.keys(fallback)
330
+ ? Object.keys(fallback).filter(locale => locale !== 'default')
331
331
  : shared.isString(fallback)
332
332
  ? [fallback]
333
333
  : [start])
@@ -355,29 +355,36 @@ function fallbackWithLocaleChain(ctx, fallback, start) {
355
355
  if (!context.__localeChainCache) {
356
356
  context.__localeChainCache = new Map();
357
357
  }
358
- let chain = context.__localeChainCache.get(startLocale);
359
- if (!chain) {
360
- chain = [];
361
- // first block defined by start
362
- let block = [start];
363
- // while any intervening block found
364
- while (shared.isArray(block)) {
365
- block = appendBlockToChain(chain, block, fallback);
366
- }
367
- // prettier-ignore
368
- // last block defined by default
369
- const defaults = shared.isArray(fallback) || !shared.isPlainObject(fallback)
370
- ? fallback
371
- : fallback['default']
372
- ? fallback['default']
373
- : null;
374
- // convert defaults to array
375
- block = shared.isString(defaults) ? [defaults] : defaults;
376
- if (shared.isArray(block)) {
377
- appendBlockToChain(chain, block, false);
378
- }
379
- context.__localeChainCache.set(startLocale, chain);
358
+ const fallbackKey = shared.friendlyJSONstringify(fallback);
359
+ let chains = context.__localeChainCache.get(startLocale);
360
+ if (!chains) {
361
+ chains = new Map();
362
+ context.__localeChainCache.set(startLocale, chains);
363
+ }
364
+ const cached = chains.get(fallbackKey);
365
+ if (cached) {
366
+ return cached;
367
+ }
368
+ const chain = [];
369
+ // first block defined by start
370
+ let block = [start];
371
+ // while any intervening block found
372
+ while (shared.isArray(block)) {
373
+ block = appendBlockToChain(chain, block, fallback);
374
+ }
375
+ // prettier-ignore
376
+ // last block defined by default
377
+ const defaults = shared.isArray(fallback) || !shared.isPlainObject(fallback)
378
+ ? fallback
379
+ : fallback['default']
380
+ ? fallback['default']
381
+ : null;
382
+ // convert defaults to array
383
+ block = shared.isString(defaults) ? [defaults] : defaults;
384
+ if (shared.isArray(block)) {
385
+ appendBlockToChain(chain, block, false);
380
386
  }
387
+ chains.set(fallbackKey, chain);
381
388
  return chain;
382
389
  }
383
390
  function appendBlockToChain(chain, block, blocks) {
@@ -736,7 +743,7 @@ function getWarnMessage(code, ...args) {
736
743
  * Intlify core-base version
737
744
  * @internal
738
745
  */
739
- const VERSION = '11.4.7';
746
+ const VERSION = '11.4.9';
740
747
  const NOT_REOSLVED = -1;
741
748
  const DEFAULT_LOCALE = 'en-US';
742
749
  const MISSING_RESOLVE_VALUE = '';
@@ -957,9 +964,68 @@ function isImplicitFallback(targetLocale, locales) {
957
964
  }
958
965
  /* eslint-enable @typescript-eslint/no-explicit-any */
959
966
 
967
+ function resolveFormatLocale(context, key, locale, formats, missingWarn, fallbackWarn, type) {
968
+ const { fallbackLocale, localeFallbacker, onWarn } = context;
969
+ const locales = localeFallbacker(context, // eslint-disable-line @typescript-eslint/no-explicit-any
970
+ fallbackLocale, locale);
971
+ for (let i = 0; i < locales.length; i++) {
972
+ const targetLocale = locales[i];
973
+ const format = (formats[targetLocale] || {})[key];
974
+ if (shared.isPlainObject(format) && shared.isString(targetLocale)) {
975
+ return targetLocale;
976
+ }
977
+ handleMissing(context, key, targetLocale, missingWarn, type);
978
+ }
979
+ return null;
980
+ }
981
+ function getFormatterCacheKey(locale, key, overrides) {
982
+ let id = `${locale}__${key}`;
983
+ if (shared.isPlainObject(overrides) && !shared.isEmptyObject(overrides)) {
984
+ id = `${id}__${JSON.stringify(overrides)}`;
985
+ }
986
+ return id;
987
+ }
988
+ function clearFormatCache(formatters, locale, format) {
989
+ for (const key in format) {
990
+ const prefix = `${locale}__${key}`;
991
+ for (const id of formatters.keys()) {
992
+ if (id === prefix || id.startsWith(`${prefix}__`)) {
993
+ formatters.delete(id);
994
+ }
995
+ }
996
+ }
997
+ }
998
+ function parseFormatArgs(args, options, initialOverrides, optionsKeys) {
999
+ const [, arg2, arg3, arg4] = args;
1000
+ let overrides = initialOverrides;
1001
+ if (shared.isString(arg2)) {
1002
+ options.key = arg2;
1003
+ }
1004
+ else if (shared.isPlainObject(arg2)) {
1005
+ Object.keys(arg2).forEach(key => {
1006
+ if (optionsKeys.includes(key)) {
1007
+ overrides[key] = arg2[key];
1008
+ }
1009
+ else {
1010
+ options[key] = arg2[key];
1011
+ }
1012
+ });
1013
+ }
1014
+ if (shared.isString(arg3)) {
1015
+ options.locale = arg3;
1016
+ }
1017
+ else if (shared.isPlainObject(arg3)) {
1018
+ overrides = arg3;
1019
+ }
1020
+ if (shared.isPlainObject(arg4)) {
1021
+ overrides = arg4;
1022
+ }
1023
+ return overrides;
1024
+ }
1025
+
960
1026
  // implementation of `datetime` function
961
1027
  function datetime(context, ...args) {
962
- const { datetimeFormats, unresolving, fallbackLocale, onWarn, localeFallbacker } = context;
1028
+ const { datetimeFormats, unresolving, onWarn } = context;
963
1029
  const { __datetimeFormatters } = context;
964
1030
  if (!shared.isString(args[0]) && !shared.isDate(args[0]) && !shared.isNumber(args[0])) {
965
1031
  return MISSING_RESOLVE_VALUE;
@@ -968,39 +1034,21 @@ function datetime(context, ...args) {
968
1034
  const missingWarn = shared.isBoolean(options.missingWarn)
969
1035
  ? options.missingWarn
970
1036
  : context.missingWarn;
971
- shared.isBoolean(options.fallbackWarn)
1037
+ const fallbackWarn = shared.isBoolean(options.fallbackWarn)
972
1038
  ? options.fallbackWarn
973
1039
  : context.fallbackWarn;
974
1040
  const part = !!options.part;
975
1041
  const locale = getLocale(context, options);
976
- const locales = localeFallbacker(context, // eslint-disable-line @typescript-eslint/no-explicit-any
977
- fallbackLocale, locale);
978
1042
  if (!shared.isString(key) || key === '') {
979
1043
  const formatter = new Intl.DateTimeFormat(locale.replace(/!/g, ''), overrides);
980
1044
  return !part ? formatter.format(value) : formatter.formatToParts(value);
981
1045
  }
982
- // resolve format
983
- let datetimeFormat = {};
984
- let targetLocale;
985
- let format = null;
986
- const type = 'datetime format';
987
- for (let i = 0; i < locales.length; i++) {
988
- targetLocale = locales[i];
989
- datetimeFormat =
990
- datetimeFormats[targetLocale] || {};
991
- format = datetimeFormat[key];
992
- if (shared.isPlainObject(format))
993
- break;
994
- handleMissing(context, key, targetLocale, missingWarn, type); // eslint-disable-line @typescript-eslint/no-explicit-any
995
- }
996
- // checking format and target locale
997
- if (!shared.isPlainObject(format) || !shared.isString(targetLocale)) {
1046
+ const targetLocale = resolveFormatLocale(context, key, locale, datetimeFormats, missingWarn, fallbackWarn, 'datetime format');
1047
+ if (!shared.isString(targetLocale)) {
998
1048
  return unresolving ? NOT_REOSLVED : key;
999
1049
  }
1000
- let id = `${targetLocale}__${key}`;
1001
- if (!shared.isEmptyObject(overrides)) {
1002
- id = `${id}__${JSON.stringify(overrides)}`;
1003
- }
1050
+ const format = datetimeFormats[targetLocale][key];
1051
+ const id = getFormatterCacheKey(targetLocale, key, overrides);
1004
1052
  let formatter = __datetimeFormatters.get(id);
1005
1053
  if (!formatter) {
1006
1054
  formatter = new Intl.DateTimeFormat(targetLocale, shared.assign({}, format, overrides));
@@ -1033,9 +1081,9 @@ const DATETIME_FORMAT_OPTIONS_KEYS = [
1033
1081
  ];
1034
1082
  /** @internal */
1035
1083
  function parseDateTimeArgs(...args) {
1036
- const [arg1, arg2, arg3, arg4] = args;
1084
+ const [arg1] = args;
1037
1085
  const options = shared.create();
1038
- let overrides = shared.create();
1086
+ const initialOverrides = shared.create();
1039
1087
  let value;
1040
1088
  if (shared.isString(arg1)) {
1041
1089
  // Only allow ISO strings - other date formats are often supported,
@@ -1072,45 +1120,18 @@ function parseDateTimeArgs(...args) {
1072
1120
  else {
1073
1121
  throw createCoreError(CoreErrorCodes.INVALID_ARGUMENT);
1074
1122
  }
1075
- if (shared.isString(arg2)) {
1076
- options.key = arg2;
1077
- }
1078
- else if (shared.isPlainObject(arg2)) {
1079
- Object.keys(arg2).forEach(key => {
1080
- if (DATETIME_FORMAT_OPTIONS_KEYS.includes(key)) {
1081
- overrides[key] = arg2[key];
1082
- }
1083
- else {
1084
- options[key] = arg2[key];
1085
- }
1086
- });
1087
- }
1088
- if (shared.isString(arg3)) {
1089
- options.locale = arg3;
1090
- }
1091
- else if (shared.isPlainObject(arg3)) {
1092
- overrides = arg3;
1093
- }
1094
- if (shared.isPlainObject(arg4)) {
1095
- overrides = arg4;
1096
- }
1123
+ const overrides = parseFormatArgs(args, options, initialOverrides, DATETIME_FORMAT_OPTIONS_KEYS);
1097
1124
  return [options.key || '', value, options, overrides];
1098
1125
  }
1099
1126
  /** @internal */
1100
1127
  function clearDateTimeFormat(ctx, locale, format) {
1101
1128
  const context = ctx;
1102
- for (const key in format) {
1103
- const id = `${locale}__${key}`;
1104
- if (!context.__datetimeFormatters.has(id)) {
1105
- continue;
1106
- }
1107
- context.__datetimeFormatters.delete(id);
1108
- }
1129
+ clearFormatCache(context.__datetimeFormatters, locale, format);
1109
1130
  }
1110
1131
 
1111
1132
  // implementation of `number` function
1112
1133
  function number(context, ...args) {
1113
- const { numberFormats, unresolving, fallbackLocale, onWarn, localeFallbacker } = context;
1134
+ const { numberFormats, unresolving, onWarn } = context;
1114
1135
  const { __numberFormatters } = context;
1115
1136
  if (!shared.isNumber(args[0])) {
1116
1137
  return MISSING_RESOLVE_VALUE;
@@ -1119,39 +1140,21 @@ function number(context, ...args) {
1119
1140
  const missingWarn = shared.isBoolean(options.missingWarn)
1120
1141
  ? options.missingWarn
1121
1142
  : context.missingWarn;
1122
- shared.isBoolean(options.fallbackWarn)
1143
+ const fallbackWarn = shared.isBoolean(options.fallbackWarn)
1123
1144
  ? options.fallbackWarn
1124
1145
  : context.fallbackWarn;
1125
1146
  const part = !!options.part;
1126
1147
  const locale = getLocale(context, options);
1127
- const locales = localeFallbacker(context, // eslint-disable-line @typescript-eslint/no-explicit-any
1128
- fallbackLocale, locale);
1129
1148
  if (!shared.isString(key) || key === '') {
1130
1149
  const formatter = new Intl.NumberFormat(locale.replace(/!/g, ''), overrides);
1131
1150
  return !part ? formatter.format(value) : formatter.formatToParts(value);
1132
1151
  }
1133
- // resolve format
1134
- let numberFormat = {};
1135
- let targetLocale;
1136
- let format = null;
1137
- const type = 'number format';
1138
- for (let i = 0; i < locales.length; i++) {
1139
- targetLocale = locales[i];
1140
- numberFormat =
1141
- numberFormats[targetLocale] || {};
1142
- format = numberFormat[key];
1143
- if (shared.isPlainObject(format))
1144
- break;
1145
- handleMissing(context, key, targetLocale, missingWarn, type); // eslint-disable-line @typescript-eslint/no-explicit-any
1146
- }
1147
- // checking format and target locale
1148
- if (!shared.isPlainObject(format) || !shared.isString(targetLocale)) {
1152
+ const targetLocale = resolveFormatLocale(context, key, locale, numberFormats, missingWarn, fallbackWarn, 'number format');
1153
+ if (!shared.isString(targetLocale)) {
1149
1154
  return unresolving ? NOT_REOSLVED : key;
1150
1155
  }
1151
- let id = `${targetLocale}__${key}`;
1152
- if (!shared.isEmptyObject(overrides)) {
1153
- id = `${id}__${JSON.stringify(overrides)}`;
1154
- }
1156
+ const format = numberFormats[targetLocale][key];
1157
+ const id = getFormatterCacheKey(targetLocale, key, overrides);
1155
1158
  let formatter = __numberFormatters.get(id);
1156
1159
  if (!formatter) {
1157
1160
  formatter = new Intl.NumberFormat(targetLocale, shared.assign({}, format, overrides));
@@ -1184,47 +1187,20 @@ const NUMBER_FORMAT_OPTIONS_KEYS = [
1184
1187
  ];
1185
1188
  /** @internal */
1186
1189
  function parseNumberArgs(...args) {
1187
- const [arg1, arg2, arg3, arg4] = args;
1190
+ const [arg1] = args;
1188
1191
  const options = shared.create();
1189
- let overrides = shared.create();
1192
+ const initialOverrides = shared.create();
1190
1193
  if (!shared.isNumber(arg1)) {
1191
1194
  throw createCoreError(CoreErrorCodes.INVALID_ARGUMENT);
1192
1195
  }
1193
1196
  const value = arg1;
1194
- if (shared.isString(arg2)) {
1195
- options.key = arg2;
1196
- }
1197
- else if (shared.isPlainObject(arg2)) {
1198
- Object.keys(arg2).forEach(key => {
1199
- if (NUMBER_FORMAT_OPTIONS_KEYS.includes(key)) {
1200
- overrides[key] = arg2[key];
1201
- }
1202
- else {
1203
- options[key] = arg2[key];
1204
- }
1205
- });
1206
- }
1207
- if (shared.isString(arg3)) {
1208
- options.locale = arg3;
1209
- }
1210
- else if (shared.isPlainObject(arg3)) {
1211
- overrides = arg3;
1212
- }
1213
- if (shared.isPlainObject(arg4)) {
1214
- overrides = arg4;
1215
- }
1197
+ const overrides = parseFormatArgs(args, options, initialOverrides, NUMBER_FORMAT_OPTIONS_KEYS);
1216
1198
  return [options.key || '', value, options, overrides];
1217
1199
  }
1218
1200
  /** @internal */
1219
1201
  function clearNumberFormat(ctx, locale, format) {
1220
1202
  const context = ctx;
1221
- for (const key in format) {
1222
- const id = `${locale}__${key}`;
1223
- if (!context.__numberFormatters.has(id)) {
1224
- continue;
1225
- }
1226
- context.__numberFormatters.delete(id);
1227
- }
1203
+ clearFormatCache(context.__numberFormatters, locale, format);
1228
1204
  }
1229
1205
 
1230
1206
  const DEFAULT_MODIFIER = (str) => str;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intlify/core-base",
3
- "version": "11.4.7",
3
+ "version": "11.4.9",
4
4
  "description": "@intlify/core-base",
5
5
  "keywords": [
6
6
  "core",
@@ -33,9 +33,9 @@
33
33
  "jsdelivr": "dist/core-base.global.js",
34
34
  "types": "dist/core-base.d.ts",
35
35
  "dependencies": {
36
- "@intlify/devtools-types": "11.4.7",
37
- "@intlify/message-compiler": "11.4.7",
38
- "@intlify/shared": "11.4.7"
36
+ "@intlify/devtools-types": "11.4.9",
37
+ "@intlify/shared": "11.4.9",
38
+ "@intlify/message-compiler": "11.4.9"
39
39
  },
40
40
  "engines": {
41
41
  "node": ">= 22"