core-base.esm-bundler.js 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965
  1. /*!
  2. * @intlify/core-base v9.1.9
  3. * (c) 2021 kazuya kawaguchi
  4. * Released under the MIT License.
  5. */
  6. import { format, isString, isArray, isPlainObject, assign, isFunction, isBoolean, isRegExp, warn, isObject, escapeHtml, inBrowser, mark, measure, generateCodeFrame, generateFormatCacheKey, isNumber, isEmptyObject, isDate, getGlobalThis } from '@intlify/shared';
  7. import { resolveValue } from '@intlify/message-resolver';
  8. export * from '@intlify/message-resolver';
  9. import { createMessageContext } from '@intlify/runtime';
  10. export * from '@intlify/runtime';
  11. import { defaultOnError, baseCompile, createCompileError } from '@intlify/message-compiler';
  12. export { createCompileError } from '@intlify/message-compiler';
  13. import { IntlifyDevToolsHooks } from '@intlify/devtools-if';
  14. let devtools = null;
  15. function setDevToolsHook(hook) {
  16. devtools = hook;
  17. }
  18. function getDevToolsHook() {
  19. return devtools;
  20. }
  21. function initI18nDevTools(i18n, version, meta) {
  22. // TODO: queue if devtools is undefined
  23. devtools &&
  24. devtools.emit(IntlifyDevToolsHooks.I18nInit, {
  25. timestamp: Date.now(),
  26. i18n,
  27. version,
  28. meta
  29. });
  30. }
  31. const translateDevTools = /* #__PURE__*/ createDevToolsHook(IntlifyDevToolsHooks.FunctionTranslate);
  32. function createDevToolsHook(hook) {
  33. return (payloads) => devtools && devtools.emit(hook, payloads);
  34. }
  35. /** @internal */
  36. const warnMessages = {
  37. [0 /* NOT_FOUND_KEY */]: `Not found '{key}' key in '{locale}' locale messages.`,
  38. [1 /* FALLBACK_TO_TRANSLATE */]: `Fall back to translate '{key}' key with '{target}' locale.`,
  39. [2 /* CANNOT_FORMAT_NUMBER */]: `Cannot format a number value due to not supported Intl.NumberFormat.`,
  40. [3 /* FALLBACK_TO_NUMBER_FORMAT */]: `Fall back to number format '{key}' key with '{target}' locale.`,
  41. [4 /* CANNOT_FORMAT_DATE */]: `Cannot format a date value due to not supported Intl.DateTimeFormat.`,
  42. [5 /* FALLBACK_TO_DATE_FORMAT */]: `Fall back to datetime format '{key}' key with '{target}' locale.`
  43. };
  44. function getWarnMessage(code, ...args) {
  45. return format(warnMessages[code], ...args);
  46. }
  47. /**
  48. * Intlify core-base version
  49. * @internal
  50. */
  51. const VERSION = '9.1.9';
  52. const NOT_REOSLVED = -1;
  53. const MISSING_RESOLVE_VALUE = '';
  54. function getDefaultLinkedModifiers() {
  55. return {
  56. upper: (val) => (isString(val) ? val.toUpperCase() : val),
  57. lower: (val) => (isString(val) ? val.toLowerCase() : val),
  58. // prettier-ignore
  59. capitalize: (val) => (isString(val)
  60. ? `${val.charAt(0).toLocaleUpperCase()}${val.substr(1)}`
  61. : val)
  62. };
  63. }
  64. let _compiler;
  65. function registerMessageCompiler(compiler) {
  66. _compiler = compiler;
  67. }
  68. // Additional Meta for Intlify DevTools
  69. let _additionalMeta = null;
  70. const setAdditionalMeta = /* #__PURE__*/ (meta) => {
  71. _additionalMeta = meta;
  72. };
  73. const getAdditionalMeta = /* #__PURE__*/ () => _additionalMeta;
  74. // ID for CoreContext
  75. let _cid = 0;
  76. function createCoreContext(options = {}) {
  77. // setup options
  78. const version = isString(options.version) ? options.version : VERSION;
  79. const locale = isString(options.locale) ? options.locale : 'en-US';
  80. const fallbackLocale = isArray(options.fallbackLocale) ||
  81. isPlainObject(options.fallbackLocale) ||
  82. isString(options.fallbackLocale) ||
  83. options.fallbackLocale === false
  84. ? options.fallbackLocale
  85. : locale;
  86. const messages = isPlainObject(options.messages)
  87. ? options.messages
  88. : { [locale]: {} };
  89. const datetimeFormats = isPlainObject(options.datetimeFormats)
  90. ? options.datetimeFormats
  91. : { [locale]: {} };
  92. const numberFormats = isPlainObject(options.numberFormats)
  93. ? options.numberFormats
  94. : { [locale]: {} };
  95. const modifiers = assign({}, options.modifiers || {}, getDefaultLinkedModifiers());
  96. const pluralRules = options.pluralRules || {};
  97. const missing = isFunction(options.missing) ? options.missing : null;
  98. const missingWarn = isBoolean(options.missingWarn) || isRegExp(options.missingWarn)
  99. ? options.missingWarn
  100. : true;
  101. const fallbackWarn = isBoolean(options.fallbackWarn) || isRegExp(options.fallbackWarn)
  102. ? options.fallbackWarn
  103. : true;
  104. const fallbackFormat = !!options.fallbackFormat;
  105. const unresolving = !!options.unresolving;
  106. const postTranslation = isFunction(options.postTranslation)
  107. ? options.postTranslation
  108. : null;
  109. const processor = isPlainObject(options.processor) ? options.processor : null;
  110. const warnHtmlMessage = isBoolean(options.warnHtmlMessage)
  111. ? options.warnHtmlMessage
  112. : true;
  113. const escapeParameter = !!options.escapeParameter;
  114. const messageCompiler = isFunction(options.messageCompiler)
  115. ? options.messageCompiler
  116. : _compiler;
  117. const onWarn = isFunction(options.onWarn) ? options.onWarn : warn;
  118. // setup internal options
  119. const internalOptions = options;
  120. const __datetimeFormatters = isObject(internalOptions.__datetimeFormatters)
  121. ? internalOptions.__datetimeFormatters
  122. : new Map();
  123. const __numberFormatters = isObject(internalOptions.__numberFormatters)
  124. ? internalOptions.__numberFormatters
  125. : new Map();
  126. const __meta = isObject(internalOptions.__meta) ? internalOptions.__meta : {};
  127. _cid++;
  128. const context = {
  129. version,
  130. cid: _cid,
  131. locale,
  132. fallbackLocale,
  133. messages,
  134. datetimeFormats,
  135. numberFormats,
  136. modifiers,
  137. pluralRules,
  138. missing,
  139. missingWarn,
  140. fallbackWarn,
  141. fallbackFormat,
  142. unresolving,
  143. postTranslation,
  144. processor,
  145. warnHtmlMessage,
  146. escapeParameter,
  147. messageCompiler,
  148. onWarn,
  149. __datetimeFormatters,
  150. __numberFormatters,
  151. __meta
  152. };
  153. // for vue-devtools timeline event
  154. if ((process.env.NODE_ENV !== 'production')) {
  155. context.__v_emitter =
  156. internalOptions.__v_emitter != null
  157. ? internalOptions.__v_emitter
  158. : undefined;
  159. }
  160. // NOTE: experimental !!
  161. if ((process.env.NODE_ENV !== 'production') || __INTLIFY_PROD_DEVTOOLS__) {
  162. initI18nDevTools(context, version, __meta);
  163. }
  164. return context;
  165. }
  166. /** @internal */
  167. function isTranslateFallbackWarn(fallback, key) {
  168. return fallback instanceof RegExp ? fallback.test(key) : fallback;
  169. }
  170. /** @internal */
  171. function isTranslateMissingWarn(missing, key) {
  172. return missing instanceof RegExp ? missing.test(key) : missing;
  173. }
  174. /** @internal */
  175. function handleMissing(context, key, locale, missingWarn, type) {
  176. const { missing, onWarn } = context;
  177. // for vue-devtools timeline event
  178. if ((process.env.NODE_ENV !== 'production')) {
  179. const emitter = context.__v_emitter;
  180. if (emitter) {
  181. emitter.emit("missing" /* MISSING */, {
  182. locale,
  183. key,
  184. type,
  185. groupId: `${type}:${key}`
  186. });
  187. }
  188. }
  189. if (missing !== null) {
  190. const ret = missing(context, locale, key, type);
  191. return isString(ret) ? ret : key;
  192. }
  193. else {
  194. if ((process.env.NODE_ENV !== 'production') && isTranslateMissingWarn(missingWarn, key)) {
  195. onWarn(getWarnMessage(0 /* NOT_FOUND_KEY */, { key, locale }));
  196. }
  197. return key;
  198. }
  199. }
  200. /** @internal */
  201. function getLocaleChain(ctx, fallback, start) {
  202. const context = ctx;
  203. if (!context.__localeChainCache) {
  204. context.__localeChainCache = new Map();
  205. }
  206. let chain = context.__localeChainCache.get(start);
  207. if (!chain) {
  208. chain = [];
  209. // first block defined by start
  210. let block = [start];
  211. // while any intervening block found
  212. while (isArray(block)) {
  213. block = appendBlockToChain(chain, block, fallback);
  214. }
  215. // prettier-ignore
  216. // last block defined by default
  217. const defaults = isArray(fallback)
  218. ? fallback
  219. : isPlainObject(fallback)
  220. ? fallback['default']
  221. ? fallback['default']
  222. : null
  223. : fallback;
  224. // convert defaults to array
  225. block = isString(defaults) ? [defaults] : defaults;
  226. if (isArray(block)) {
  227. appendBlockToChain(chain, block, false);
  228. }
  229. context.__localeChainCache.set(start, chain);
  230. }
  231. return chain;
  232. }
  233. function appendBlockToChain(chain, block, blocks) {
  234. let follow = true;
  235. for (let i = 0; i < block.length && isBoolean(follow); i++) {
  236. const locale = block[i];
  237. if (isString(locale)) {
  238. follow = appendLocaleToChain(chain, block[i], blocks);
  239. }
  240. }
  241. return follow;
  242. }
  243. function appendLocaleToChain(chain, locale, blocks) {
  244. let follow;
  245. const tokens = locale.split('-');
  246. do {
  247. const target = tokens.join('-');
  248. follow = appendItemToChain(chain, target, blocks);
  249. tokens.splice(-1, 1);
  250. } while (tokens.length && follow === true);
  251. return follow;
  252. }
  253. function appendItemToChain(chain, target, blocks) {
  254. let follow = false;
  255. if (!chain.includes(target)) {
  256. follow = true;
  257. if (target) {
  258. follow = target[target.length - 1] !== '!';
  259. const locale = target.replace(/!/g, '');
  260. chain.push(locale);
  261. if ((isArray(blocks) || isPlainObject(blocks)) &&
  262. blocks[locale] // eslint-disable-line @typescript-eslint/no-explicit-any
  263. ) {
  264. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  265. follow = blocks[locale];
  266. }
  267. }
  268. }
  269. return follow;
  270. }
  271. /** @internal */
  272. function updateFallbackLocale(ctx, locale, fallback) {
  273. const context = ctx;
  274. context.__localeChainCache = new Map();
  275. getLocaleChain(ctx, fallback, locale);
  276. }
  277. const RE_HTML_TAG = /<\/?[\w\s="/.':;#-\/]+>/;
  278. const WARN_MESSAGE = `Detected HTML in '{source}' message. Recommend not using HTML messages to avoid XSS.`;
  279. function checkHtmlMessage(source, options) {
  280. const warnHtmlMessage = isBoolean(options.warnHtmlMessage)
  281. ? options.warnHtmlMessage
  282. : true;
  283. if (warnHtmlMessage && RE_HTML_TAG.test(source)) {
  284. warn(format(WARN_MESSAGE, { source }));
  285. }
  286. }
  287. const defaultOnCacheKey = (source) => source;
  288. let compileCache = Object.create(null);
  289. function clearCompileCache() {
  290. compileCache = Object.create(null);
  291. }
  292. function compileToFunction(source, options = {}) {
  293. {
  294. // check HTML message
  295. (process.env.NODE_ENV !== 'production') && checkHtmlMessage(source, options);
  296. // check caches
  297. const onCacheKey = options.onCacheKey || defaultOnCacheKey;
  298. const key = onCacheKey(source);
  299. const cached = compileCache[key];
  300. if (cached) {
  301. return cached;
  302. }
  303. // compile error detecting
  304. let occurred = false;
  305. const onError = options.onError || defaultOnError;
  306. options.onError = (err) => {
  307. occurred = true;
  308. onError(err);
  309. };
  310. // compile
  311. const { code } = baseCompile(source, options);
  312. // evaluate function
  313. const msg = new Function(`return ${code}`)();
  314. // if occurred compile error, don't cache
  315. return !occurred ? (compileCache[key] = msg) : msg;
  316. }
  317. }
  318. function createCoreError(code) {
  319. return createCompileError(code, null, (process.env.NODE_ENV !== 'production') ? { messages: errorMessages } : undefined);
  320. }
  321. /** @internal */
  322. const errorMessages = {
  323. [14 /* INVALID_ARGUMENT */]: 'Invalid arguments',
  324. [15 /* INVALID_DATE_ARGUMENT */]: 'The date provided is an invalid Date object.' +
  325. 'Make sure your Date represents a valid date.',
  326. [16 /* INVALID_ISO_DATE_ARGUMENT */]: 'The argument provided is not a valid ISO date string'
  327. };
  328. const NOOP_MESSAGE_FUNCTION = () => '';
  329. const isMessageFunction = (val) => isFunction(val);
  330. // implementation of `translate` function
  331. function translate(context, ...args) {
  332. const { fallbackFormat, postTranslation, unresolving, fallbackLocale, messages } = context;
  333. const [key, options] = parseTranslateArgs(...args);
  334. const missingWarn = isBoolean(options.missingWarn)
  335. ? options.missingWarn
  336. : context.missingWarn;
  337. const fallbackWarn = isBoolean(options.fallbackWarn)
  338. ? options.fallbackWarn
  339. : context.fallbackWarn;
  340. const escapeParameter = isBoolean(options.escapeParameter)
  341. ? options.escapeParameter
  342. : context.escapeParameter;
  343. const resolvedMessage = !!options.resolvedMessage;
  344. // prettier-ignore
  345. const defaultMsgOrKey = isString(options.default) || isBoolean(options.default) // default by function option
  346. ? !isBoolean(options.default)
  347. ? options.default
  348. : key
  349. : fallbackFormat // default by `fallbackFormat` option
  350. ? key
  351. : '';
  352. const enableDefaultMsg = fallbackFormat || defaultMsgOrKey !== '';
  353. const locale = isString(options.locale) ? options.locale : context.locale;
  354. // escape params
  355. escapeParameter && escapeParams(options);
  356. // resolve message format
  357. // eslint-disable-next-line prefer-const
  358. let [format, targetLocale, message] = !resolvedMessage
  359. ? resolveMessageFormat(context, key, locale, fallbackLocale, fallbackWarn, missingWarn)
  360. : [
  361. key,
  362. locale,
  363. messages[locale] || {}
  364. ];
  365. // if you use default message, set it as message format!
  366. let cacheBaseKey = key;
  367. if (!resolvedMessage &&
  368. !(isString(format) || isMessageFunction(format))) {
  369. if (enableDefaultMsg) {
  370. format = defaultMsgOrKey;
  371. cacheBaseKey = format;
  372. }
  373. }
  374. // checking message format and target locale
  375. if (!resolvedMessage &&
  376. (!(isString(format) || isMessageFunction(format)) ||
  377. !isString(targetLocale))) {
  378. return unresolving ? NOT_REOSLVED : key;
  379. }
  380. if ((process.env.NODE_ENV !== 'production') && isString(format) && context.messageCompiler == null) {
  381. warn(`The message format compilation is not supported in this build. ` +
  382. `Because message compiler isn't included. ` +
  383. `You need to pre-compilation all message format. ` +
  384. `So translate function return '${key}'.`);
  385. return key;
  386. }
  387. // setup compile error detecting
  388. let occurred = false;
  389. const errorDetector = () => {
  390. occurred = true;
  391. };
  392. // compile message format
  393. const msg = !isMessageFunction(format)
  394. ? compileMessageFormat(context, key, targetLocale, format, cacheBaseKey, errorDetector)
  395. : format;
  396. // if occurred compile error, return the message format
  397. if (occurred) {
  398. return format;
  399. }
  400. // evaluate message with context
  401. const ctxOptions = getMessageContextOptions(context, targetLocale, message, options);
  402. const msgContext = createMessageContext(ctxOptions);
  403. const messaged = evaluateMessage(context, msg, msgContext);
  404. // if use post translation option, proceed it with handler
  405. const ret = postTranslation ? postTranslation(messaged) : messaged;
  406. // NOTE: experimental !!
  407. if ((process.env.NODE_ENV !== 'production') || __INTLIFY_PROD_DEVTOOLS__) {
  408. // prettier-ignore
  409. const payloads = {
  410. timestamp: Date.now(),
  411. key: isString(key)
  412. ? key
  413. : isMessageFunction(format)
  414. ? format.key
  415. : '',
  416. locale: targetLocale || (isMessageFunction(format)
  417. ? format.locale
  418. : ''),
  419. format: isString(format)
  420. ? format
  421. : isMessageFunction(format)
  422. ? format.source
  423. : '',
  424. message: ret
  425. };
  426. payloads.meta = assign({}, context.__meta, getAdditionalMeta() || {});
  427. translateDevTools(payloads);
  428. }
  429. return ret;
  430. }
  431. function escapeParams(options) {
  432. if (isArray(options.list)) {
  433. options.list = options.list.map(item => isString(item) ? escapeHtml(item) : item);
  434. }
  435. else if (isObject(options.named)) {
  436. Object.keys(options.named).forEach(key => {
  437. if (isString(options.named[key])) {
  438. options.named[key] = escapeHtml(options.named[key]);
  439. }
  440. });
  441. }
  442. }
  443. function resolveMessageFormat(context, key, locale, fallbackLocale, fallbackWarn, missingWarn) {
  444. const { messages, onWarn } = context;
  445. const locales = getLocaleChain(context, fallbackLocale, locale);
  446. let message = {};
  447. let targetLocale;
  448. let format = null;
  449. let from = locale;
  450. let to = null;
  451. const type = 'translate';
  452. for (let i = 0; i < locales.length; i++) {
  453. targetLocale = to = locales[i];
  454. if ((process.env.NODE_ENV !== 'production') &&
  455. locale !== targetLocale &&
  456. isTranslateFallbackWarn(fallbackWarn, key)) {
  457. onWarn(getWarnMessage(1 /* FALLBACK_TO_TRANSLATE */, {
  458. key,
  459. target: targetLocale
  460. }));
  461. }
  462. // for vue-devtools timeline event
  463. if ((process.env.NODE_ENV !== 'production') && locale !== targetLocale) {
  464. const emitter = context.__v_emitter;
  465. if (emitter) {
  466. emitter.emit("fallback" /* FALBACK */, {
  467. type,
  468. key,
  469. from,
  470. to,
  471. groupId: `${type}:${key}`
  472. });
  473. }
  474. }
  475. message =
  476. messages[targetLocale] || {};
  477. // for vue-devtools timeline event
  478. let start = null;
  479. let startTag;
  480. let endTag;
  481. if ((process.env.NODE_ENV !== 'production') && inBrowser) {
  482. start = window.performance.now();
  483. startTag = 'intlify-message-resolve-start';
  484. endTag = 'intlify-message-resolve-end';
  485. mark && mark(startTag);
  486. }
  487. if ((format = resolveValue(message, key)) === null) {
  488. // if null, resolve with object key path
  489. format = message[key]; // eslint-disable-line @typescript-eslint/no-explicit-any
  490. }
  491. // for vue-devtools timeline event
  492. if ((process.env.NODE_ENV !== 'production') && inBrowser) {
  493. const end = window.performance.now();
  494. const emitter = context.__v_emitter;
  495. if (emitter && start && format) {
  496. emitter.emit("message-resolve" /* MESSAGE_RESOLVE */, {
  497. type: "message-resolve" /* MESSAGE_RESOLVE */,
  498. key,
  499. message: format,
  500. time: end - start,
  501. groupId: `${type}:${key}`
  502. });
  503. }
  504. if (startTag && endTag && mark && measure) {
  505. mark(endTag);
  506. measure('intlify message resolve', startTag, endTag);
  507. }
  508. }
  509. if (isString(format) || isFunction(format))
  510. break;
  511. const missingRet = handleMissing(context, key, targetLocale, missingWarn, type);
  512. if (missingRet !== key) {
  513. format = missingRet;
  514. }
  515. from = to;
  516. }
  517. return [format, targetLocale, message];
  518. }
  519. function compileMessageFormat(context, key, targetLocale, format, cacheBaseKey, errorDetector) {
  520. const { messageCompiler, warnHtmlMessage } = context;
  521. if (isMessageFunction(format)) {
  522. const msg = format;
  523. msg.locale = msg.locale || targetLocale;
  524. msg.key = msg.key || key;
  525. return msg;
  526. }
  527. // for vue-devtools timeline event
  528. let start = null;
  529. let startTag;
  530. let endTag;
  531. if ((process.env.NODE_ENV !== 'production') && inBrowser) {
  532. start = window.performance.now();
  533. startTag = 'intlify-message-compilation-start';
  534. endTag = 'intlify-message-compilation-end';
  535. mark && mark(startTag);
  536. }
  537. const msg = messageCompiler(format, getCompileOptions(context, targetLocale, cacheBaseKey, format, warnHtmlMessage, errorDetector));
  538. // for vue-devtools timeline event
  539. if ((process.env.NODE_ENV !== 'production') && inBrowser) {
  540. const end = window.performance.now();
  541. const emitter = context.__v_emitter;
  542. if (emitter && start) {
  543. emitter.emit("message-compilation" /* MESSAGE_COMPILATION */, {
  544. type: "message-compilation" /* MESSAGE_COMPILATION */,
  545. message: format,
  546. time: end - start,
  547. groupId: `${'translate'}:${key}`
  548. });
  549. }
  550. if (startTag && endTag && mark && measure) {
  551. mark(endTag);
  552. measure('intlify message compilation', startTag, endTag);
  553. }
  554. }
  555. msg.locale = targetLocale;
  556. msg.key = key;
  557. msg.source = format;
  558. return msg;
  559. }
  560. function evaluateMessage(context, msg, msgCtx) {
  561. // for vue-devtools timeline event
  562. let start = null;
  563. let startTag;
  564. let endTag;
  565. if ((process.env.NODE_ENV !== 'production') && inBrowser) {
  566. start = window.performance.now();
  567. startTag = 'intlify-message-evaluation-start';
  568. endTag = 'intlify-message-evaluation-end';
  569. mark && mark(startTag);
  570. }
  571. const messaged = msg(msgCtx);
  572. // for vue-devtools timeline event
  573. if ((process.env.NODE_ENV !== 'production') && inBrowser) {
  574. const end = window.performance.now();
  575. const emitter = context.__v_emitter;
  576. if (emitter && start) {
  577. emitter.emit("message-evaluation" /* MESSAGE_EVALUATION */, {
  578. type: "message-evaluation" /* MESSAGE_EVALUATION */,
  579. value: messaged,
  580. time: end - start,
  581. groupId: `${'translate'}:${msg.key}`
  582. });
  583. }
  584. if (startTag && endTag && mark && measure) {
  585. mark(endTag);
  586. measure('intlify message evaluation', startTag, endTag);
  587. }
  588. }
  589. return messaged;
  590. }
  591. /** @internal */
  592. function parseTranslateArgs(...args) {
  593. const [arg1, arg2, arg3] = args;
  594. const options = {};
  595. if (!isString(arg1) && !isNumber(arg1) && !isMessageFunction(arg1)) {
  596. throw createCoreError(14 /* INVALID_ARGUMENT */);
  597. }
  598. // prettier-ignore
  599. const key = isNumber(arg1)
  600. ? String(arg1)
  601. : isMessageFunction(arg1)
  602. ? arg1
  603. : arg1;
  604. if (isNumber(arg2)) {
  605. options.plural = arg2;
  606. }
  607. else if (isString(arg2)) {
  608. options.default = arg2;
  609. }
  610. else if (isPlainObject(arg2) && !isEmptyObject(arg2)) {
  611. options.named = arg2;
  612. }
  613. else if (isArray(arg2)) {
  614. options.list = arg2;
  615. }
  616. if (isNumber(arg3)) {
  617. options.plural = arg3;
  618. }
  619. else if (isString(arg3)) {
  620. options.default = arg3;
  621. }
  622. else if (isPlainObject(arg3)) {
  623. assign(options, arg3);
  624. }
  625. return [key, options];
  626. }
  627. function getCompileOptions(context, locale, key, source, warnHtmlMessage, errorDetector) {
  628. return {
  629. warnHtmlMessage,
  630. onError: (err) => {
  631. errorDetector && errorDetector(err);
  632. if ((process.env.NODE_ENV !== 'production')) {
  633. const message = `Message compilation error: ${err.message}`;
  634. const codeFrame = err.location &&
  635. generateCodeFrame(source, err.location.start.offset, err.location.end.offset);
  636. const emitter = context
  637. .__v_emitter;
  638. if (emitter) {
  639. emitter.emit("compile-error" /* COMPILE_ERROR */, {
  640. message: source,
  641. error: err.message,
  642. start: err.location && err.location.start.offset,
  643. end: err.location && err.location.end.offset,
  644. groupId: `${'translate'}:${key}`
  645. });
  646. }
  647. console.error(codeFrame ? `${message}\n${codeFrame}` : message);
  648. }
  649. else {
  650. throw err;
  651. }
  652. },
  653. onCacheKey: (source) => generateFormatCacheKey(locale, key, source)
  654. };
  655. }
  656. function getMessageContextOptions(context, locale, message, options) {
  657. const { modifiers, pluralRules } = context;
  658. const resolveMessage = (key) => {
  659. const val = resolveValue(message, key);
  660. if (isString(val)) {
  661. let occurred = false;
  662. const errorDetector = () => {
  663. occurred = true;
  664. };
  665. const msg = compileMessageFormat(context, key, locale, val, key, errorDetector);
  666. return !occurred
  667. ? msg
  668. : NOOP_MESSAGE_FUNCTION;
  669. }
  670. else if (isMessageFunction(val)) {
  671. return val;
  672. }
  673. else {
  674. // TODO: should be implemented warning message
  675. return NOOP_MESSAGE_FUNCTION;
  676. }
  677. };
  678. const ctxOptions = {
  679. locale,
  680. modifiers,
  681. pluralRules,
  682. messages: resolveMessage
  683. };
  684. if (context.processor) {
  685. ctxOptions.processor = context.processor;
  686. }
  687. if (options.list) {
  688. ctxOptions.list = options.list;
  689. }
  690. if (options.named) {
  691. ctxOptions.named = options.named;
  692. }
  693. if (isNumber(options.plural)) {
  694. ctxOptions.pluralIndex = options.plural;
  695. }
  696. return ctxOptions;
  697. }
  698. const intlDefined = typeof Intl !== 'undefined';
  699. const Availabilities = {
  700. dateTimeFormat: intlDefined && typeof Intl.DateTimeFormat !== 'undefined',
  701. numberFormat: intlDefined && typeof Intl.NumberFormat !== 'undefined'
  702. };
  703. // implementation of `datetime` function
  704. function datetime(context, ...args) {
  705. const { datetimeFormats, unresolving, fallbackLocale, onWarn } = context;
  706. const { __datetimeFormatters } = context;
  707. if ((process.env.NODE_ENV !== 'production') && !Availabilities.dateTimeFormat) {
  708. onWarn(getWarnMessage(4 /* CANNOT_FORMAT_DATE */));
  709. return MISSING_RESOLVE_VALUE;
  710. }
  711. const [key, value, options, overrides] = parseDateTimeArgs(...args);
  712. const missingWarn = isBoolean(options.missingWarn)
  713. ? options.missingWarn
  714. : context.missingWarn;
  715. const fallbackWarn = isBoolean(options.fallbackWarn)
  716. ? options.fallbackWarn
  717. : context.fallbackWarn;
  718. const part = !!options.part;
  719. const locale = isString(options.locale) ? options.locale : context.locale;
  720. const locales = getLocaleChain(context, fallbackLocale, locale);
  721. if (!isString(key) || key === '') {
  722. return new Intl.DateTimeFormat(locale).format(value);
  723. }
  724. // resolve format
  725. let datetimeFormat = {};
  726. let targetLocale;
  727. let format = null;
  728. let from = locale;
  729. let to = null;
  730. const type = 'datetime format';
  731. for (let i = 0; i < locales.length; i++) {
  732. targetLocale = to = locales[i];
  733. if ((process.env.NODE_ENV !== 'production') &&
  734. locale !== targetLocale &&
  735. isTranslateFallbackWarn(fallbackWarn, key)) {
  736. onWarn(getWarnMessage(5 /* FALLBACK_TO_DATE_FORMAT */, {
  737. key,
  738. target: targetLocale
  739. }));
  740. }
  741. // for vue-devtools timeline event
  742. if ((process.env.NODE_ENV !== 'production') && locale !== targetLocale) {
  743. const emitter = context.__v_emitter;
  744. if (emitter) {
  745. emitter.emit("fallback" /* FALBACK */, {
  746. type,
  747. key,
  748. from,
  749. to,
  750. groupId: `${type}:${key}`
  751. });
  752. }
  753. }
  754. datetimeFormat =
  755. datetimeFormats[targetLocale] || {};
  756. format = datetimeFormat[key];
  757. if (isPlainObject(format))
  758. break;
  759. handleMissing(context, key, targetLocale, missingWarn, type);
  760. from = to;
  761. }
  762. // checking format and target locale
  763. if (!isPlainObject(format) || !isString(targetLocale)) {
  764. return unresolving ? NOT_REOSLVED : key;
  765. }
  766. let id = `${targetLocale}__${key}`;
  767. if (!isEmptyObject(overrides)) {
  768. id = `${id}__${JSON.stringify(overrides)}`;
  769. }
  770. let formatter = __datetimeFormatters.get(id);
  771. if (!formatter) {
  772. formatter = new Intl.DateTimeFormat(targetLocale, assign({}, format, overrides));
  773. __datetimeFormatters.set(id, formatter);
  774. }
  775. return !part ? formatter.format(value) : formatter.formatToParts(value);
  776. }
  777. /** @internal */
  778. function parseDateTimeArgs(...args) {
  779. const [arg1, arg2, arg3, arg4] = args;
  780. let options = {};
  781. let overrides = {};
  782. let value;
  783. if (isString(arg1)) {
  784. // Only allow ISO strings - other date formats are often supported,
  785. // but may cause different results in different browsers.
  786. if (!/\d{4}-\d{2}-\d{2}(T.*)?/.test(arg1)) {
  787. throw createCoreError(16 /* INVALID_ISO_DATE_ARGUMENT */);
  788. }
  789. value = new Date(arg1);
  790. try {
  791. // This will fail if the date is not valid
  792. value.toISOString();
  793. }
  794. catch (e) {
  795. throw createCoreError(16 /* INVALID_ISO_DATE_ARGUMENT */);
  796. }
  797. }
  798. else if (isDate(arg1)) {
  799. if (isNaN(arg1.getTime())) {
  800. throw createCoreError(15 /* INVALID_DATE_ARGUMENT */);
  801. }
  802. value = arg1;
  803. }
  804. else if (isNumber(arg1)) {
  805. value = arg1;
  806. }
  807. else {
  808. throw createCoreError(14 /* INVALID_ARGUMENT */);
  809. }
  810. if (isString(arg2)) {
  811. options.key = arg2;
  812. }
  813. else if (isPlainObject(arg2)) {
  814. options = arg2;
  815. }
  816. if (isString(arg3)) {
  817. options.locale = arg3;
  818. }
  819. else if (isPlainObject(arg3)) {
  820. overrides = arg3;
  821. }
  822. if (isPlainObject(arg4)) {
  823. overrides = arg4;
  824. }
  825. return [options.key || '', value, options, overrides];
  826. }
  827. /** @internal */
  828. function clearDateTimeFormat(ctx, locale, format) {
  829. const context = ctx;
  830. for (const key in format) {
  831. const id = `${locale}__${key}`;
  832. if (!context.__datetimeFormatters.has(id)) {
  833. continue;
  834. }
  835. context.__datetimeFormatters.delete(id);
  836. }
  837. }
  838. // implementation of `number` function
  839. function number(context, ...args) {
  840. const { numberFormats, unresolving, fallbackLocale, onWarn } = context;
  841. const { __numberFormatters } = context;
  842. if ((process.env.NODE_ENV !== 'production') && !Availabilities.numberFormat) {
  843. onWarn(getWarnMessage(2 /* CANNOT_FORMAT_NUMBER */));
  844. return MISSING_RESOLVE_VALUE;
  845. }
  846. const [key, value, options, overrides] = parseNumberArgs(...args);
  847. const missingWarn = isBoolean(options.missingWarn)
  848. ? options.missingWarn
  849. : context.missingWarn;
  850. const fallbackWarn = isBoolean(options.fallbackWarn)
  851. ? options.fallbackWarn
  852. : context.fallbackWarn;
  853. const part = !!options.part;
  854. const locale = isString(options.locale) ? options.locale : context.locale;
  855. const locales = getLocaleChain(context, fallbackLocale, locale);
  856. if (!isString(key) || key === '') {
  857. return new Intl.NumberFormat(locale).format(value);
  858. }
  859. // resolve format
  860. let numberFormat = {};
  861. let targetLocale;
  862. let format = null;
  863. let from = locale;
  864. let to = null;
  865. const type = 'number format';
  866. for (let i = 0; i < locales.length; i++) {
  867. targetLocale = to = locales[i];
  868. if ((process.env.NODE_ENV !== 'production') &&
  869. locale !== targetLocale &&
  870. isTranslateFallbackWarn(fallbackWarn, key)) {
  871. onWarn(getWarnMessage(3 /* FALLBACK_TO_NUMBER_FORMAT */, {
  872. key,
  873. target: targetLocale
  874. }));
  875. }
  876. // for vue-devtools timeline event
  877. if ((process.env.NODE_ENV !== 'production') && locale !== targetLocale) {
  878. const emitter = context.__v_emitter;
  879. if (emitter) {
  880. emitter.emit("fallback" /* FALBACK */, {
  881. type,
  882. key,
  883. from,
  884. to,
  885. groupId: `${type}:${key}`
  886. });
  887. }
  888. }
  889. numberFormat =
  890. numberFormats[targetLocale] || {};
  891. format = numberFormat[key];
  892. if (isPlainObject(format))
  893. break;
  894. handleMissing(context, key, targetLocale, missingWarn, type);
  895. from = to;
  896. }
  897. // checking format and target locale
  898. if (!isPlainObject(format) || !isString(targetLocale)) {
  899. return unresolving ? NOT_REOSLVED : key;
  900. }
  901. let id = `${targetLocale}__${key}`;
  902. if (!isEmptyObject(overrides)) {
  903. id = `${id}__${JSON.stringify(overrides)}`;
  904. }
  905. let formatter = __numberFormatters.get(id);
  906. if (!formatter) {
  907. formatter = new Intl.NumberFormat(targetLocale, assign({}, format, overrides));
  908. __numberFormatters.set(id, formatter);
  909. }
  910. return !part ? formatter.format(value) : formatter.formatToParts(value);
  911. }
  912. /** @internal */
  913. function parseNumberArgs(...args) {
  914. const [arg1, arg2, arg3, arg4] = args;
  915. let options = {};
  916. let overrides = {};
  917. if (!isNumber(arg1)) {
  918. throw createCoreError(14 /* INVALID_ARGUMENT */);
  919. }
  920. const value = arg1;
  921. if (isString(arg2)) {
  922. options.key = arg2;
  923. }
  924. else if (isPlainObject(arg2)) {
  925. options = arg2;
  926. }
  927. if (isString(arg3)) {
  928. options.locale = arg3;
  929. }
  930. else if (isPlainObject(arg3)) {
  931. overrides = arg3;
  932. }
  933. if (isPlainObject(arg4)) {
  934. overrides = arg4;
  935. }
  936. return [options.key || '', value, options, overrides];
  937. }
  938. /** @internal */
  939. function clearNumberFormat(ctx, locale, format) {
  940. const context = ctx;
  941. for (const key in format) {
  942. const id = `${locale}__${key}`;
  943. if (!context.__numberFormatters.has(id)) {
  944. continue;
  945. }
  946. context.__numberFormatters.delete(id);
  947. }
  948. }
  949. {
  950. if (typeof __INTLIFY_PROD_DEVTOOLS__ !== 'boolean') {
  951. getGlobalThis().__INTLIFY_PROD_DEVTOOLS__ = false;
  952. }
  953. }
  954. export { MISSING_RESOLVE_VALUE, NOT_REOSLVED, VERSION, clearCompileCache, clearDateTimeFormat, clearNumberFormat, compileToFunction, createCoreContext, createCoreError, datetime, getAdditionalMeta, getDevToolsHook, getLocaleChain, getWarnMessage, handleMissing, initI18nDevTools, isMessageFunction, isTranslateFallbackWarn, isTranslateMissingWarn, number, parseDateTimeArgs, parseNumberArgs, parseTranslateArgs, registerMessageCompiler, setAdditionalMeta, setDevToolsHook, translate, translateDevTools, updateFallbackLocale };