core-base.cjs.js 34 KB

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