core-base.prod.cjs 52 KB

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