core-base.mjs 62 KB

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