core-base.global.js 101 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809
  1. /*!
  2. * @intlify/core-base v9.1.9
  3. * (c) 2021 kazuya kawaguchi
  4. * Released under the MIT License.
  5. */
  6. var IntlifyCoreBase = (function (exports) {
  7. 'use strict';
  8. /**
  9. * Original Utilities
  10. * written by kazuya kawaguchi
  11. */
  12. const inBrowser = typeof window !== 'undefined';
  13. let mark;
  14. let measure;
  15. {
  16. const perf = inBrowser && window.performance;
  17. if (perf &&
  18. perf.mark &&
  19. perf.measure &&
  20. perf.clearMarks &&
  21. perf.clearMeasures) {
  22. mark = (tag) => perf.mark(tag);
  23. measure = (name, startTag, endTag) => {
  24. perf.measure(name, startTag, endTag);
  25. perf.clearMarks(startTag);
  26. perf.clearMarks(endTag);
  27. };
  28. }
  29. }
  30. const RE_ARGS = /\{([0-9a-zA-Z]+)\}/g;
  31. /* eslint-disable */
  32. function format(message, ...args) {
  33. if (args.length === 1 && isObject(args[0])) {
  34. args = args[0];
  35. }
  36. if (!args || !args.hasOwnProperty) {
  37. args = {};
  38. }
  39. return message.replace(RE_ARGS, (match, identifier) => {
  40. return args.hasOwnProperty(identifier) ? args[identifier] : '';
  41. });
  42. }
  43. const generateFormatCacheKey = (locale, key, source) => friendlyJSONstringify({ l: locale, k: key, s: source });
  44. const friendlyJSONstringify = (json) => JSON.stringify(json)
  45. .replace(/\u2028/g, '\\u2028')
  46. .replace(/\u2029/g, '\\u2029')
  47. .replace(/\u0027/g, '\\u0027');
  48. const isNumber = (val) => typeof val === 'number' && isFinite(val);
  49. const isDate = (val) => toTypeString(val) === '[object Date]';
  50. const isRegExp = (val) => toTypeString(val) === '[object RegExp]';
  51. const isEmptyObject = (val) => isPlainObject(val) && Object.keys(val).length === 0;
  52. function warn(msg, err) {
  53. if (typeof console !== 'undefined') {
  54. console.warn(`[intlify] ` + msg);
  55. /* istanbul ignore if */
  56. if (err) {
  57. console.warn(err.stack);
  58. }
  59. }
  60. }
  61. const assign = Object.assign;
  62. function escapeHtml(rawText) {
  63. return rawText
  64. .replace(/</g, '&lt;')
  65. .replace(/>/g, '&gt;')
  66. .replace(/"/g, '&quot;')
  67. .replace(/'/g, '&apos;');
  68. }
  69. const hasOwnProperty = Object.prototype.hasOwnProperty;
  70. function hasOwn(obj, key) {
  71. return hasOwnProperty.call(obj, key);
  72. }
  73. /* eslint-enable */
  74. /**
  75. * Useful Utilities By Evan you
  76. * Modified by kazuya kawaguchi
  77. * MIT License
  78. * https://github.com/vuejs/vue-next/blob/master/packages/shared/src/index.ts
  79. * https://github.com/vuejs/vue-next/blob/master/packages/shared/src/codeframe.ts
  80. */
  81. const isArray = Array.isArray;
  82. const isFunction = (val) => typeof val === 'function';
  83. const isString = (val) => typeof val === 'string';
  84. const isBoolean = (val) => typeof val === 'boolean';
  85. const isObject = (val) => // eslint-disable-line
  86. val !== null && typeof val === 'object';
  87. const objectToString = Object.prototype.toString;
  88. const toTypeString = (value) => objectToString.call(value);
  89. const isPlainObject = (val) => toTypeString(val) === '[object Object]';
  90. // for converting list and named values to displayed strings.
  91. const toDisplayString = (val) => {
  92. return val == null
  93. ? ''
  94. : isArray(val) || (isPlainObject(val) && val.toString === objectToString)
  95. ? JSON.stringify(val, null, 2)
  96. : String(val);
  97. };
  98. const RANGE = 2;
  99. function generateCodeFrame(source, start = 0, end = source.length) {
  100. const lines = source.split(/\r?\n/);
  101. let count = 0;
  102. const res = [];
  103. for (let i = 0; i < lines.length; i++) {
  104. count += lines[i].length + 1;
  105. if (count >= start) {
  106. for (let j = i - RANGE; j <= i + RANGE || end > count; j++) {
  107. if (j < 0 || j >= lines.length)
  108. continue;
  109. const line = j + 1;
  110. res.push(`${line}${' '.repeat(3 - String(line).length)}| ${lines[j]}`);
  111. const lineLength = lines[j].length;
  112. if (j === i) {
  113. // push underline
  114. const pad = start - (count - lineLength) + 1;
  115. const length = Math.max(1, end > count ? lineLength - pad : end - start);
  116. res.push(` | ` + ' '.repeat(pad) + '^'.repeat(length));
  117. }
  118. else if (j > i) {
  119. if (end > count) {
  120. const length = Math.max(Math.min(end - count, lineLength), 1);
  121. res.push(` | ` + '^'.repeat(length));
  122. }
  123. count += lineLength + 1;
  124. }
  125. }
  126. break;
  127. }
  128. }
  129. return res.join('\n');
  130. }
  131. const pathStateMachine = [];
  132. pathStateMachine[0 /* BEFORE_PATH */] = {
  133. ["w" /* WORKSPACE */]: [0 /* BEFORE_PATH */],
  134. ["i" /* IDENT */]: [3 /* IN_IDENT */, 0 /* APPEND */],
  135. ["[" /* LEFT_BRACKET */]: [4 /* IN_SUB_PATH */],
  136. ["o" /* END_OF_FAIL */]: [7 /* AFTER_PATH */]
  137. };
  138. pathStateMachine[1 /* IN_PATH */] = {
  139. ["w" /* WORKSPACE */]: [1 /* IN_PATH */],
  140. ["." /* DOT */]: [2 /* BEFORE_IDENT */],
  141. ["[" /* LEFT_BRACKET */]: [4 /* IN_SUB_PATH */],
  142. ["o" /* END_OF_FAIL */]: [7 /* AFTER_PATH */]
  143. };
  144. pathStateMachine[2 /* BEFORE_IDENT */] = {
  145. ["w" /* WORKSPACE */]: [2 /* BEFORE_IDENT */],
  146. ["i" /* IDENT */]: [3 /* IN_IDENT */, 0 /* APPEND */],
  147. ["0" /* ZERO */]: [3 /* IN_IDENT */, 0 /* APPEND */]
  148. };
  149. pathStateMachine[3 /* IN_IDENT */] = {
  150. ["i" /* IDENT */]: [3 /* IN_IDENT */, 0 /* APPEND */],
  151. ["0" /* ZERO */]: [3 /* IN_IDENT */, 0 /* APPEND */],
  152. ["w" /* WORKSPACE */]: [1 /* IN_PATH */, 1 /* PUSH */],
  153. ["." /* DOT */]: [2 /* BEFORE_IDENT */, 1 /* PUSH */],
  154. ["[" /* LEFT_BRACKET */]: [4 /* IN_SUB_PATH */, 1 /* PUSH */],
  155. ["o" /* END_OF_FAIL */]: [7 /* AFTER_PATH */, 1 /* PUSH */]
  156. };
  157. pathStateMachine[4 /* IN_SUB_PATH */] = {
  158. ["'" /* SINGLE_QUOTE */]: [5 /* IN_SINGLE_QUOTE */, 0 /* APPEND */],
  159. ["\"" /* DOUBLE_QUOTE */]: [6 /* IN_DOUBLE_QUOTE */, 0 /* APPEND */],
  160. ["[" /* LEFT_BRACKET */]: [
  161. 4 /* IN_SUB_PATH */,
  162. 2 /* INC_SUB_PATH_DEPTH */
  163. ],
  164. ["]" /* RIGHT_BRACKET */]: [1 /* IN_PATH */, 3 /* PUSH_SUB_PATH */],
  165. ["o" /* END_OF_FAIL */]: 8 /* ERROR */,
  166. ["l" /* ELSE */]: [4 /* IN_SUB_PATH */, 0 /* APPEND */]
  167. };
  168. pathStateMachine[5 /* IN_SINGLE_QUOTE */] = {
  169. ["'" /* SINGLE_QUOTE */]: [4 /* IN_SUB_PATH */, 0 /* APPEND */],
  170. ["o" /* END_OF_FAIL */]: 8 /* ERROR */,
  171. ["l" /* ELSE */]: [5 /* IN_SINGLE_QUOTE */, 0 /* APPEND */]
  172. };
  173. pathStateMachine[6 /* IN_DOUBLE_QUOTE */] = {
  174. ["\"" /* DOUBLE_QUOTE */]: [4 /* IN_SUB_PATH */, 0 /* APPEND */],
  175. ["o" /* END_OF_FAIL */]: 8 /* ERROR */,
  176. ["l" /* ELSE */]: [6 /* IN_DOUBLE_QUOTE */, 0 /* APPEND */]
  177. };
  178. /**
  179. * Check if an expression is a literal value.
  180. */
  181. const literalValueRE = /^\s?(?:true|false|-?[\d.]+|'[^']*'|"[^"]*")\s?$/;
  182. function isLiteral(exp) {
  183. return literalValueRE.test(exp);
  184. }
  185. /**
  186. * Strip quotes from a string
  187. */
  188. function stripQuotes(str) {
  189. const a = str.charCodeAt(0);
  190. const b = str.charCodeAt(str.length - 1);
  191. return a === b && (a === 0x22 || a === 0x27) ? str.slice(1, -1) : str;
  192. }
  193. /**
  194. * Determine the type of a character in a keypath.
  195. */
  196. function getPathCharType(ch) {
  197. if (ch === undefined || ch === null) {
  198. return "o" /* END_OF_FAIL */;
  199. }
  200. const code = ch.charCodeAt(0);
  201. switch (code) {
  202. case 0x5b: // [
  203. case 0x5d: // ]
  204. case 0x2e: // .
  205. case 0x22: // "
  206. case 0x27: // '
  207. return ch;
  208. case 0x5f: // _
  209. case 0x24: // $
  210. case 0x2d: // -
  211. return "i" /* IDENT */;
  212. case 0x09: // Tab (HT)
  213. case 0x0a: // Newline (LF)
  214. case 0x0d: // Return (CR)
  215. case 0xa0: // No-break space (NBSP)
  216. case 0xfeff: // Byte Order Mark (BOM)
  217. case 0x2028: // Line Separator (LS)
  218. case 0x2029: // Paragraph Separator (PS)
  219. return "w" /* WORKSPACE */;
  220. }
  221. return "i" /* IDENT */;
  222. }
  223. /**
  224. * Format a subPath, return its plain form if it is
  225. * a literal string or number. Otherwise prepend the
  226. * dynamic indicator (*).
  227. */
  228. function formatSubPath(path) {
  229. const trimmed = path.trim();
  230. // invalid leading 0
  231. if (path.charAt(0) === '0' && isNaN(parseInt(path))) {
  232. return false;
  233. }
  234. return isLiteral(trimmed)
  235. ? stripQuotes(trimmed)
  236. : "*" /* ASTARISK */ + trimmed;
  237. }
  238. /**
  239. * Parse a string path into an array of segments
  240. */
  241. function parse(path) {
  242. const keys = [];
  243. let index = -1;
  244. let mode = 0 /* BEFORE_PATH */;
  245. let subPathDepth = 0;
  246. let c;
  247. let key; // eslint-disable-line
  248. let newChar;
  249. let type;
  250. let transition;
  251. let action;
  252. let typeMap;
  253. const actions = [];
  254. actions[0 /* APPEND */] = () => {
  255. if (key === undefined) {
  256. key = newChar;
  257. }
  258. else {
  259. key += newChar;
  260. }
  261. };
  262. actions[1 /* PUSH */] = () => {
  263. if (key !== undefined) {
  264. keys.push(key);
  265. key = undefined;
  266. }
  267. };
  268. actions[2 /* INC_SUB_PATH_DEPTH */] = () => {
  269. actions[0 /* APPEND */]();
  270. subPathDepth++;
  271. };
  272. actions[3 /* PUSH_SUB_PATH */] = () => {
  273. if (subPathDepth > 0) {
  274. subPathDepth--;
  275. mode = 4 /* IN_SUB_PATH */;
  276. actions[0 /* APPEND */]();
  277. }
  278. else {
  279. subPathDepth = 0;
  280. if (key === undefined) {
  281. return false;
  282. }
  283. key = formatSubPath(key);
  284. if (key === false) {
  285. return false;
  286. }
  287. else {
  288. actions[1 /* PUSH */]();
  289. }
  290. }
  291. };
  292. function maybeUnescapeQuote() {
  293. const nextChar = path[index + 1];
  294. if ((mode === 5 /* IN_SINGLE_QUOTE */ &&
  295. nextChar === "'" /* SINGLE_QUOTE */) ||
  296. (mode === 6 /* IN_DOUBLE_QUOTE */ &&
  297. nextChar === "\"" /* DOUBLE_QUOTE */)) {
  298. index++;
  299. newChar = '\\' + nextChar;
  300. actions[0 /* APPEND */]();
  301. return true;
  302. }
  303. }
  304. while (mode !== null) {
  305. index++;
  306. c = path[index];
  307. if (c === '\\' && maybeUnescapeQuote()) {
  308. continue;
  309. }
  310. type = getPathCharType(c);
  311. typeMap = pathStateMachine[mode];
  312. transition = typeMap[type] || typeMap["l" /* ELSE */] || 8 /* ERROR */;
  313. // check parse error
  314. if (transition === 8 /* ERROR */) {
  315. return;
  316. }
  317. mode = transition[0];
  318. if (transition[1] !== undefined) {
  319. action = actions[transition[1]];
  320. if (action) {
  321. newChar = c;
  322. if (action() === false) {
  323. return;
  324. }
  325. }
  326. }
  327. // check parse finish
  328. if (mode === 7 /* AFTER_PATH */) {
  329. return keys;
  330. }
  331. }
  332. }
  333. // path token cache
  334. const cache = new Map();
  335. function resolveValue(obj, path) {
  336. // check object
  337. if (!isObject(obj)) {
  338. return null;
  339. }
  340. // parse path
  341. let hit = cache.get(path);
  342. if (!hit) {
  343. hit = parse(path);
  344. if (hit) {
  345. cache.set(path, hit);
  346. }
  347. }
  348. // check hit
  349. if (!hit) {
  350. return null;
  351. }
  352. // resolve path value
  353. const len = hit.length;
  354. let last = obj;
  355. let i = 0;
  356. while (i < len) {
  357. const val = last[hit[i]];
  358. if (val === undefined) {
  359. return null;
  360. }
  361. last = val;
  362. i++;
  363. }
  364. return last;
  365. }
  366. /**
  367. * Transform flat json in obj to normal json in obj
  368. */
  369. function handleFlatJson(obj) {
  370. // check obj
  371. if (!isObject(obj)) {
  372. return obj;
  373. }
  374. for (const key in obj) {
  375. // check key
  376. if (!hasOwn(obj, key)) {
  377. continue;
  378. }
  379. // handle for normal json
  380. if (!key.includes("." /* DOT */)) {
  381. // recursive process value if value is also a object
  382. if (isObject(obj[key])) {
  383. handleFlatJson(obj[key]);
  384. }
  385. }
  386. // handle for flat json, transform to normal json
  387. else {
  388. // go to the last object
  389. const subKeys = key.split("." /* DOT */);
  390. const lastIndex = subKeys.length - 1;
  391. let currentObj = obj;
  392. for (let i = 0; i < lastIndex; i++) {
  393. if (!(subKeys[i] in currentObj)) {
  394. currentObj[subKeys[i]] = {};
  395. }
  396. currentObj = currentObj[subKeys[i]];
  397. }
  398. // update last object value, delete old property
  399. currentObj[subKeys[lastIndex]] = obj[key];
  400. delete obj[key];
  401. // recursive process value if value is also a object
  402. if (isObject(currentObj[subKeys[lastIndex]])) {
  403. handleFlatJson(currentObj[subKeys[lastIndex]]);
  404. }
  405. }
  406. }
  407. return obj;
  408. }
  409. const DEFAULT_MODIFIER = (str) => str;
  410. const DEFAULT_MESSAGE = (ctx) => ''; // eslint-disable-line
  411. const DEFAULT_MESSAGE_DATA_TYPE = 'text';
  412. const DEFAULT_NORMALIZE = (values) => values.length === 0 ? '' : values.join('');
  413. const DEFAULT_INTERPOLATE = toDisplayString;
  414. function pluralDefault(choice, choicesLength) {
  415. choice = Math.abs(choice);
  416. if (choicesLength === 2) {
  417. // prettier-ignore
  418. return choice
  419. ? choice > 1
  420. ? 1
  421. : 0
  422. : 1;
  423. }
  424. return choice ? Math.min(choice, 2) : 0;
  425. }
  426. function getPluralIndex(options) {
  427. // prettier-ignore
  428. const index = isNumber(options.pluralIndex)
  429. ? options.pluralIndex
  430. : -1;
  431. // prettier-ignore
  432. return options.named && (isNumber(options.named.count) || isNumber(options.named.n))
  433. ? isNumber(options.named.count)
  434. ? options.named.count
  435. : isNumber(options.named.n)
  436. ? options.named.n
  437. : index
  438. : index;
  439. }
  440. function normalizeNamed(pluralIndex, props) {
  441. if (!props.count) {
  442. props.count = pluralIndex;
  443. }
  444. if (!props.n) {
  445. props.n = pluralIndex;
  446. }
  447. }
  448. function createMessageContext(options = {}) {
  449. const locale = options.locale;
  450. const pluralIndex = getPluralIndex(options);
  451. const pluralRule = isObject(options.pluralRules) &&
  452. isString(locale) &&
  453. isFunction(options.pluralRules[locale])
  454. ? options.pluralRules[locale]
  455. : pluralDefault;
  456. const orgPluralRule = isObject(options.pluralRules) &&
  457. isString(locale) &&
  458. isFunction(options.pluralRules[locale])
  459. ? pluralDefault
  460. : undefined;
  461. const plural = (messages) => messages[pluralRule(pluralIndex, messages.length, orgPluralRule)];
  462. const _list = options.list || [];
  463. const list = (index) => _list[index];
  464. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  465. const _named = options.named || {};
  466. isNumber(options.pluralIndex) && normalizeNamed(pluralIndex, _named);
  467. const named = (key) => _named[key];
  468. // TODO: need to design resolve message function?
  469. function message(key) {
  470. // prettier-ignore
  471. const msg = isFunction(options.messages)
  472. ? options.messages(key)
  473. : isObject(options.messages)
  474. ? options.messages[key]
  475. : false;
  476. return !msg
  477. ? options.parent
  478. ? options.parent.message(key) // resolve from parent messages
  479. : DEFAULT_MESSAGE
  480. : msg;
  481. }
  482. const _modifier = (name) => options.modifiers
  483. ? options.modifiers[name]
  484. : DEFAULT_MODIFIER;
  485. const normalize = isPlainObject(options.processor) && isFunction(options.processor.normalize)
  486. ? options.processor.normalize
  487. : DEFAULT_NORMALIZE;
  488. const interpolate = isPlainObject(options.processor) &&
  489. isFunction(options.processor.interpolate)
  490. ? options.processor.interpolate
  491. : DEFAULT_INTERPOLATE;
  492. const type = isPlainObject(options.processor) && isString(options.processor.type)
  493. ? options.processor.type
  494. : DEFAULT_MESSAGE_DATA_TYPE;
  495. const ctx = {
  496. ["list" /* LIST */]: list,
  497. ["named" /* NAMED */]: named,
  498. ["plural" /* PLURAL */]: plural,
  499. ["linked" /* LINKED */]: (key, modifier) => {
  500. // TODO: should check `key`
  501. const msg = message(key)(ctx);
  502. return isString(modifier) ? _modifier(modifier)(msg) : msg;
  503. },
  504. ["message" /* MESSAGE */]: message,
  505. ["type" /* TYPE */]: type,
  506. ["interpolate" /* INTERPOLATE */]: interpolate,
  507. ["normalize" /* NORMALIZE */]: normalize
  508. };
  509. return ctx;
  510. }
  511. /** @internal */
  512. const errorMessages$1 = {
  513. // tokenizer error messages
  514. [0 /* EXPECTED_TOKEN */]: `Expected token: '{0}'`,
  515. [1 /* INVALID_TOKEN_IN_PLACEHOLDER */]: `Invalid token in placeholder: '{0}'`,
  516. [2 /* UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER */]: `Unterminated single quote in placeholder`,
  517. [3 /* UNKNOWN_ESCAPE_SEQUENCE */]: `Unknown escape sequence: \\{0}`,
  518. [4 /* INVALID_UNICODE_ESCAPE_SEQUENCE */]: `Invalid unicode escape sequence: {0}`,
  519. [5 /* UNBALANCED_CLOSING_BRACE */]: `Unbalanced closing brace`,
  520. [6 /* UNTERMINATED_CLOSING_BRACE */]: `Unterminated closing brace`,
  521. [7 /* EMPTY_PLACEHOLDER */]: `Empty placeholder`,
  522. [8 /* NOT_ALLOW_NEST_PLACEHOLDER */]: `Not allowed nest placeholder`,
  523. [9 /* INVALID_LINKED_FORMAT */]: `Invalid linked format`,
  524. // parser error messages
  525. [10 /* MUST_HAVE_MESSAGES_IN_PLURAL */]: `Plural must have messages`,
  526. [11 /* UNEXPECTED_EMPTY_LINKED_MODIFIER */]: `Unexpected empty linked modifier`,
  527. [12 /* UNEXPECTED_EMPTY_LINKED_KEY */]: `Unexpected empty linked key`,
  528. [13 /* UNEXPECTED_LEXICAL_ANALYSIS */]: `Unexpected lexical analysis in token: '{0}'`
  529. };
  530. function createCompileError(code, loc, options = {}) {
  531. const { domain, messages, args } = options;
  532. const msg = format((messages || errorMessages$1)[code] || '', ...(args || []))
  533. ;
  534. const error = new SyntaxError(String(msg));
  535. error.code = code;
  536. if (loc) {
  537. error.location = loc;
  538. }
  539. error.domain = domain;
  540. return error;
  541. }
  542. /** @internal */
  543. function defaultOnError(error) {
  544. throw error;
  545. }
  546. function createPosition(line, column, offset) {
  547. return { line, column, offset };
  548. }
  549. function createLocation(start, end, source) {
  550. const loc = { start, end };
  551. if (source != null) {
  552. loc.source = source;
  553. }
  554. return loc;
  555. }
  556. const CHAR_SP = ' ';
  557. const CHAR_CR = '\r';
  558. const CHAR_LF = '\n';
  559. const CHAR_LS = String.fromCharCode(0x2028);
  560. const CHAR_PS = String.fromCharCode(0x2029);
  561. function createScanner(str) {
  562. const _buf = str;
  563. let _index = 0;
  564. let _line = 1;
  565. let _column = 1;
  566. let _peekOffset = 0;
  567. const isCRLF = (index) => _buf[index] === CHAR_CR && _buf[index + 1] === CHAR_LF;
  568. const isLF = (index) => _buf[index] === CHAR_LF;
  569. const isPS = (index) => _buf[index] === CHAR_PS;
  570. const isLS = (index) => _buf[index] === CHAR_LS;
  571. const isLineEnd = (index) => isCRLF(index) || isLF(index) || isPS(index) || isLS(index);
  572. const index = () => _index;
  573. const line = () => _line;
  574. const column = () => _column;
  575. const peekOffset = () => _peekOffset;
  576. const charAt = (offset) => isCRLF(offset) || isPS(offset) || isLS(offset) ? CHAR_LF : _buf[offset];
  577. const currentChar = () => charAt(_index);
  578. const currentPeek = () => charAt(_index + _peekOffset);
  579. function next() {
  580. _peekOffset = 0;
  581. if (isLineEnd(_index)) {
  582. _line++;
  583. _column = 0;
  584. }
  585. if (isCRLF(_index)) {
  586. _index++;
  587. }
  588. _index++;
  589. _column++;
  590. return _buf[_index];
  591. }
  592. function peek() {
  593. if (isCRLF(_index + _peekOffset)) {
  594. _peekOffset++;
  595. }
  596. _peekOffset++;
  597. return _buf[_index + _peekOffset];
  598. }
  599. function reset() {
  600. _index = 0;
  601. _line = 1;
  602. _column = 1;
  603. _peekOffset = 0;
  604. }
  605. function resetPeek(offset = 0) {
  606. _peekOffset = offset;
  607. }
  608. function skipToPeek() {
  609. const target = _index + _peekOffset;
  610. // eslint-disable-next-line no-unmodified-loop-condition
  611. while (target !== _index) {
  612. next();
  613. }
  614. _peekOffset = 0;
  615. }
  616. return {
  617. index,
  618. line,
  619. column,
  620. peekOffset,
  621. charAt,
  622. currentChar,
  623. currentPeek,
  624. next,
  625. peek,
  626. reset,
  627. resetPeek,
  628. skipToPeek
  629. };
  630. }
  631. const EOF = undefined;
  632. const LITERAL_DELIMITER = "'";
  633. const ERROR_DOMAIN$1 = 'tokenizer';
  634. function createTokenizer(source, options = {}) {
  635. const location = options.location !== false;
  636. const _scnr = createScanner(source);
  637. const currentOffset = () => _scnr.index();
  638. const currentPosition = () => createPosition(_scnr.line(), _scnr.column(), _scnr.index());
  639. const _initLoc = currentPosition();
  640. const _initOffset = currentOffset();
  641. const _context = {
  642. currentType: 14 /* EOF */,
  643. offset: _initOffset,
  644. startLoc: _initLoc,
  645. endLoc: _initLoc,
  646. lastType: 14 /* EOF */,
  647. lastOffset: _initOffset,
  648. lastStartLoc: _initLoc,
  649. lastEndLoc: _initLoc,
  650. braceNest: 0,
  651. inLinked: false,
  652. text: ''
  653. };
  654. const context = () => _context;
  655. const { onError } = options;
  656. function emitError(code, pos, offset, ...args) {
  657. const ctx = context();
  658. pos.column += offset;
  659. pos.offset += offset;
  660. if (onError) {
  661. const loc = createLocation(ctx.startLoc, pos);
  662. const err = createCompileError(code, loc, {
  663. domain: ERROR_DOMAIN$1,
  664. args
  665. });
  666. onError(err);
  667. }
  668. }
  669. function getToken(context, type, value) {
  670. context.endLoc = currentPosition();
  671. context.currentType = type;
  672. const token = { type };
  673. if (location) {
  674. token.loc = createLocation(context.startLoc, context.endLoc);
  675. }
  676. if (value != null) {
  677. token.value = value;
  678. }
  679. return token;
  680. }
  681. const getEndToken = (context) => getToken(context, 14 /* EOF */);
  682. function eat(scnr, ch) {
  683. if (scnr.currentChar() === ch) {
  684. scnr.next();
  685. return ch;
  686. }
  687. else {
  688. emitError(0 /* EXPECTED_TOKEN */, currentPosition(), 0, ch);
  689. return '';
  690. }
  691. }
  692. function peekSpaces(scnr) {
  693. let buf = '';
  694. while (scnr.currentPeek() === CHAR_SP || scnr.currentPeek() === CHAR_LF) {
  695. buf += scnr.currentPeek();
  696. scnr.peek();
  697. }
  698. return buf;
  699. }
  700. function skipSpaces(scnr) {
  701. const buf = peekSpaces(scnr);
  702. scnr.skipToPeek();
  703. return buf;
  704. }
  705. function isIdentifierStart(ch) {
  706. if (ch === EOF) {
  707. return false;
  708. }
  709. const cc = ch.charCodeAt(0);
  710. return ((cc >= 97 && cc <= 122) || // a-z
  711. (cc >= 65 && cc <= 90) || // A-Z
  712. cc === 95 // _
  713. );
  714. }
  715. function isNumberStart(ch) {
  716. if (ch === EOF) {
  717. return false;
  718. }
  719. const cc = ch.charCodeAt(0);
  720. return cc >= 48 && cc <= 57; // 0-9
  721. }
  722. function isNamedIdentifierStart(scnr, context) {
  723. const { currentType } = context;
  724. if (currentType !== 2 /* BraceLeft */) {
  725. return false;
  726. }
  727. peekSpaces(scnr);
  728. const ret = isIdentifierStart(scnr.currentPeek());
  729. scnr.resetPeek();
  730. return ret;
  731. }
  732. function isListIdentifierStart(scnr, context) {
  733. const { currentType } = context;
  734. if (currentType !== 2 /* BraceLeft */) {
  735. return false;
  736. }
  737. peekSpaces(scnr);
  738. const ch = scnr.currentPeek() === '-' ? scnr.peek() : scnr.currentPeek();
  739. const ret = isNumberStart(ch);
  740. scnr.resetPeek();
  741. return ret;
  742. }
  743. function isLiteralStart(scnr, context) {
  744. const { currentType } = context;
  745. if (currentType !== 2 /* BraceLeft */) {
  746. return false;
  747. }
  748. peekSpaces(scnr);
  749. const ret = scnr.currentPeek() === LITERAL_DELIMITER;
  750. scnr.resetPeek();
  751. return ret;
  752. }
  753. function isLinkedDotStart(scnr, context) {
  754. const { currentType } = context;
  755. if (currentType !== 8 /* LinkedAlias */) {
  756. return false;
  757. }
  758. peekSpaces(scnr);
  759. const ret = scnr.currentPeek() === "." /* LinkedDot */;
  760. scnr.resetPeek();
  761. return ret;
  762. }
  763. function isLinkedModifierStart(scnr, context) {
  764. const { currentType } = context;
  765. if (currentType !== 9 /* LinkedDot */) {
  766. return false;
  767. }
  768. peekSpaces(scnr);
  769. const ret = isIdentifierStart(scnr.currentPeek());
  770. scnr.resetPeek();
  771. return ret;
  772. }
  773. function isLinkedDelimiterStart(scnr, context) {
  774. const { currentType } = context;
  775. if (!(currentType === 8 /* LinkedAlias */ ||
  776. currentType === 12 /* LinkedModifier */)) {
  777. return false;
  778. }
  779. peekSpaces(scnr);
  780. const ret = scnr.currentPeek() === ":" /* LinkedDelimiter */;
  781. scnr.resetPeek();
  782. return ret;
  783. }
  784. function isLinkedReferStart(scnr, context) {
  785. const { currentType } = context;
  786. if (currentType !== 10 /* LinkedDelimiter */) {
  787. return false;
  788. }
  789. const fn = () => {
  790. const ch = scnr.currentPeek();
  791. if (ch === "{" /* BraceLeft */) {
  792. return isIdentifierStart(scnr.peek());
  793. }
  794. else if (ch === "@" /* LinkedAlias */ ||
  795. ch === "%" /* Modulo */ ||
  796. ch === "|" /* Pipe */ ||
  797. ch === ":" /* LinkedDelimiter */ ||
  798. ch === "." /* LinkedDot */ ||
  799. ch === CHAR_SP ||
  800. !ch) {
  801. return false;
  802. }
  803. else if (ch === CHAR_LF) {
  804. scnr.peek();
  805. return fn();
  806. }
  807. else {
  808. // other characters
  809. return isIdentifierStart(ch);
  810. }
  811. };
  812. const ret = fn();
  813. scnr.resetPeek();
  814. return ret;
  815. }
  816. function isPluralStart(scnr) {
  817. peekSpaces(scnr);
  818. const ret = scnr.currentPeek() === "|" /* Pipe */;
  819. scnr.resetPeek();
  820. return ret;
  821. }
  822. function isTextStart(scnr, reset = true) {
  823. const fn = (hasSpace = false, prev = '', detectModulo = false) => {
  824. const ch = scnr.currentPeek();
  825. if (ch === "{" /* BraceLeft */) {
  826. return prev === "%" /* Modulo */ ? false : hasSpace;
  827. }
  828. else if (ch === "@" /* LinkedAlias */ || !ch) {
  829. return prev === "%" /* Modulo */ ? true : hasSpace;
  830. }
  831. else if (ch === "%" /* Modulo */) {
  832. scnr.peek();
  833. return fn(hasSpace, "%" /* Modulo */, true);
  834. }
  835. else if (ch === "|" /* Pipe */) {
  836. return prev === "%" /* Modulo */ || detectModulo
  837. ? true
  838. : !(prev === CHAR_SP || prev === CHAR_LF);
  839. }
  840. else if (ch === CHAR_SP) {
  841. scnr.peek();
  842. return fn(true, CHAR_SP, detectModulo);
  843. }
  844. else if (ch === CHAR_LF) {
  845. scnr.peek();
  846. return fn(true, CHAR_LF, detectModulo);
  847. }
  848. else {
  849. return true;
  850. }
  851. };
  852. const ret = fn();
  853. reset && scnr.resetPeek();
  854. return ret;
  855. }
  856. function takeChar(scnr, fn) {
  857. const ch = scnr.currentChar();
  858. if (ch === EOF) {
  859. return EOF;
  860. }
  861. if (fn(ch)) {
  862. scnr.next();
  863. return ch;
  864. }
  865. return null;
  866. }
  867. function takeIdentifierChar(scnr) {
  868. const closure = (ch) => {
  869. const cc = ch.charCodeAt(0);
  870. return ((cc >= 97 && cc <= 122) || // a-z
  871. (cc >= 65 && cc <= 90) || // A-Z
  872. (cc >= 48 && cc <= 57) || // 0-9
  873. cc === 95 || // _
  874. cc === 36 // $
  875. );
  876. };
  877. return takeChar(scnr, closure);
  878. }
  879. function takeDigit(scnr) {
  880. const closure = (ch) => {
  881. const cc = ch.charCodeAt(0);
  882. return cc >= 48 && cc <= 57; // 0-9
  883. };
  884. return takeChar(scnr, closure);
  885. }
  886. function takeHexDigit(scnr) {
  887. const closure = (ch) => {
  888. const cc = ch.charCodeAt(0);
  889. return ((cc >= 48 && cc <= 57) || // 0-9
  890. (cc >= 65 && cc <= 70) || // A-F
  891. (cc >= 97 && cc <= 102)); // a-f
  892. };
  893. return takeChar(scnr, closure);
  894. }
  895. function getDigits(scnr) {
  896. let ch = '';
  897. let num = '';
  898. while ((ch = takeDigit(scnr))) {
  899. num += ch;
  900. }
  901. return num;
  902. }
  903. function readText(scnr) {
  904. let buf = '';
  905. while (true) {
  906. const ch = scnr.currentChar();
  907. if (ch === "{" /* BraceLeft */ ||
  908. ch === "}" /* BraceRight */ ||
  909. ch === "@" /* LinkedAlias */ ||
  910. ch === "|" /* Pipe */ ||
  911. !ch) {
  912. break;
  913. }
  914. else if (ch === "%" /* Modulo */) {
  915. if (isTextStart(scnr)) {
  916. buf += ch;
  917. scnr.next();
  918. }
  919. else {
  920. break;
  921. }
  922. }
  923. else if (ch === CHAR_SP || ch === CHAR_LF) {
  924. if (isTextStart(scnr)) {
  925. buf += ch;
  926. scnr.next();
  927. }
  928. else if (isPluralStart(scnr)) {
  929. break;
  930. }
  931. else {
  932. buf += ch;
  933. scnr.next();
  934. }
  935. }
  936. else {
  937. buf += ch;
  938. scnr.next();
  939. }
  940. }
  941. return buf;
  942. }
  943. function readNamedIdentifier(scnr) {
  944. skipSpaces(scnr);
  945. let ch = '';
  946. let name = '';
  947. while ((ch = takeIdentifierChar(scnr))) {
  948. name += ch;
  949. }
  950. if (scnr.currentChar() === EOF) {
  951. emitError(6 /* UNTERMINATED_CLOSING_BRACE */, currentPosition(), 0);
  952. }
  953. return name;
  954. }
  955. function readListIdentifier(scnr) {
  956. skipSpaces(scnr);
  957. let value = '';
  958. if (scnr.currentChar() === '-') {
  959. scnr.next();
  960. value += `-${getDigits(scnr)}`;
  961. }
  962. else {
  963. value += getDigits(scnr);
  964. }
  965. if (scnr.currentChar() === EOF) {
  966. emitError(6 /* UNTERMINATED_CLOSING_BRACE */, currentPosition(), 0);
  967. }
  968. return value;
  969. }
  970. function readLiteral(scnr) {
  971. skipSpaces(scnr);
  972. eat(scnr, `\'`);
  973. let ch = '';
  974. let literal = '';
  975. const fn = (x) => x !== LITERAL_DELIMITER && x !== CHAR_LF;
  976. while ((ch = takeChar(scnr, fn))) {
  977. if (ch === '\\') {
  978. literal += readEscapeSequence(scnr);
  979. }
  980. else {
  981. literal += ch;
  982. }
  983. }
  984. const current = scnr.currentChar();
  985. if (current === CHAR_LF || current === EOF) {
  986. emitError(2 /* UNTERMINATED_SINGLE_QUOTE_IN_PLACEHOLDER */, currentPosition(), 0);
  987. // TODO: Is it correct really?
  988. if (current === CHAR_LF) {
  989. scnr.next();
  990. eat(scnr, `\'`);
  991. }
  992. return literal;
  993. }
  994. eat(scnr, `\'`);
  995. return literal;
  996. }
  997. function readEscapeSequence(scnr) {
  998. const ch = scnr.currentChar();
  999. switch (ch) {
  1000. case '\\':
  1001. case `\'`:
  1002. scnr.next();
  1003. return `\\${ch}`;
  1004. case 'u':
  1005. return readUnicodeEscapeSequence(scnr, ch, 4);
  1006. case 'U':
  1007. return readUnicodeEscapeSequence(scnr, ch, 6);
  1008. default:
  1009. emitError(3 /* UNKNOWN_ESCAPE_SEQUENCE */, currentPosition(), 0, ch);
  1010. return '';
  1011. }
  1012. }
  1013. function readUnicodeEscapeSequence(scnr, unicode, digits) {
  1014. eat(scnr, unicode);
  1015. let sequence = '';
  1016. for (let i = 0; i < digits; i++) {
  1017. const ch = takeHexDigit(scnr);
  1018. if (!ch) {
  1019. emitError(4 /* INVALID_UNICODE_ESCAPE_SEQUENCE */, currentPosition(), 0, `\\${unicode}${sequence}${scnr.currentChar()}`);
  1020. break;
  1021. }
  1022. sequence += ch;
  1023. }
  1024. return `\\${unicode}${sequence}`;
  1025. }
  1026. function readInvalidIdentifier(scnr) {
  1027. skipSpaces(scnr);
  1028. let ch = '';
  1029. let identifiers = '';
  1030. const closure = (ch) => ch !== "{" /* BraceLeft */ &&
  1031. ch !== "}" /* BraceRight */ &&
  1032. ch !== CHAR_SP &&
  1033. ch !== CHAR_LF;
  1034. while ((ch = takeChar(scnr, closure))) {
  1035. identifiers += ch;
  1036. }
  1037. return identifiers;
  1038. }
  1039. function readLinkedModifier(scnr) {
  1040. let ch = '';
  1041. let name = '';
  1042. while ((ch = takeIdentifierChar(scnr))) {
  1043. name += ch;
  1044. }
  1045. return name;
  1046. }
  1047. function readLinkedRefer(scnr) {
  1048. const fn = (detect = false, buf) => {
  1049. const ch = scnr.currentChar();
  1050. if (ch === "{" /* BraceLeft */ ||
  1051. ch === "%" /* Modulo */ ||
  1052. ch === "@" /* LinkedAlias */ ||
  1053. ch === "|" /* Pipe */ ||
  1054. !ch) {
  1055. return buf;
  1056. }
  1057. else if (ch === CHAR_SP) {
  1058. return buf;
  1059. }
  1060. else if (ch === CHAR_LF) {
  1061. buf += ch;
  1062. scnr.next();
  1063. return fn(detect, buf);
  1064. }
  1065. else {
  1066. buf += ch;
  1067. scnr.next();
  1068. return fn(true, buf);
  1069. }
  1070. };
  1071. return fn(false, '');
  1072. }
  1073. function readPlural(scnr) {
  1074. skipSpaces(scnr);
  1075. const plural = eat(scnr, "|" /* Pipe */);
  1076. skipSpaces(scnr);
  1077. return plural;
  1078. }
  1079. // TODO: We need refactoring of token parsing ...
  1080. function readTokenInPlaceholder(scnr, context) {
  1081. let token = null;
  1082. const ch = scnr.currentChar();
  1083. switch (ch) {
  1084. case "{" /* BraceLeft */:
  1085. if (context.braceNest >= 1) {
  1086. emitError(8 /* NOT_ALLOW_NEST_PLACEHOLDER */, currentPosition(), 0);
  1087. }
  1088. scnr.next();
  1089. token = getToken(context, 2 /* BraceLeft */, "{" /* BraceLeft */);
  1090. skipSpaces(scnr);
  1091. context.braceNest++;
  1092. return token;
  1093. case "}" /* BraceRight */:
  1094. if (context.braceNest > 0 &&
  1095. context.currentType === 2 /* BraceLeft */) {
  1096. emitError(7 /* EMPTY_PLACEHOLDER */, currentPosition(), 0);
  1097. }
  1098. scnr.next();
  1099. token = getToken(context, 3 /* BraceRight */, "}" /* BraceRight */);
  1100. context.braceNest--;
  1101. context.braceNest > 0 && skipSpaces(scnr);
  1102. if (context.inLinked && context.braceNest === 0) {
  1103. context.inLinked = false;
  1104. }
  1105. return token;
  1106. case "@" /* LinkedAlias */:
  1107. if (context.braceNest > 0) {
  1108. emitError(6 /* UNTERMINATED_CLOSING_BRACE */, currentPosition(), 0);
  1109. }
  1110. token = readTokenInLinked(scnr, context) || getEndToken(context);
  1111. context.braceNest = 0;
  1112. return token;
  1113. default:
  1114. let validNamedIdentifier = true;
  1115. let validListIdentifier = true;
  1116. let validLiteral = true;
  1117. if (isPluralStart(scnr)) {
  1118. if (context.braceNest > 0) {
  1119. emitError(6 /* UNTERMINATED_CLOSING_BRACE */, currentPosition(), 0);
  1120. }
  1121. token = getToken(context, 1 /* Pipe */, readPlural(scnr));
  1122. // reset
  1123. context.braceNest = 0;
  1124. context.inLinked = false;
  1125. return token;
  1126. }
  1127. if (context.braceNest > 0 &&
  1128. (context.currentType === 5 /* Named */ ||
  1129. context.currentType === 6 /* List */ ||
  1130. context.currentType === 7 /* Literal */)) {
  1131. emitError(6 /* UNTERMINATED_CLOSING_BRACE */, currentPosition(), 0);
  1132. context.braceNest = 0;
  1133. return readToken(scnr, context);
  1134. }
  1135. if ((validNamedIdentifier = isNamedIdentifierStart(scnr, context))) {
  1136. token = getToken(context, 5 /* Named */, readNamedIdentifier(scnr));
  1137. skipSpaces(scnr);
  1138. return token;
  1139. }
  1140. if ((validListIdentifier = isListIdentifierStart(scnr, context))) {
  1141. token = getToken(context, 6 /* List */, readListIdentifier(scnr));
  1142. skipSpaces(scnr);
  1143. return token;
  1144. }
  1145. if ((validLiteral = isLiteralStart(scnr, context))) {
  1146. token = getToken(context, 7 /* Literal */, readLiteral(scnr));
  1147. skipSpaces(scnr);
  1148. return token;
  1149. }
  1150. if (!validNamedIdentifier && !validListIdentifier && !validLiteral) {
  1151. // TODO: we should be re-designed invalid cases, when we will extend message syntax near the future ...
  1152. token = getToken(context, 13 /* InvalidPlace */, readInvalidIdentifier(scnr));
  1153. emitError(1 /* INVALID_TOKEN_IN_PLACEHOLDER */, currentPosition(), 0, token.value);
  1154. skipSpaces(scnr);
  1155. return token;
  1156. }
  1157. break;
  1158. }
  1159. return token;
  1160. }
  1161. // TODO: We need refactoring of token parsing ...
  1162. function readTokenInLinked(scnr, context) {
  1163. const { currentType } = context;
  1164. let token = null;
  1165. const ch = scnr.currentChar();
  1166. if ((currentType === 8 /* LinkedAlias */ ||
  1167. currentType === 9 /* LinkedDot */ ||
  1168. currentType === 12 /* LinkedModifier */ ||
  1169. currentType === 10 /* LinkedDelimiter */) &&
  1170. (ch === CHAR_LF || ch === CHAR_SP)) {
  1171. emitError(9 /* INVALID_LINKED_FORMAT */, currentPosition(), 0);
  1172. }
  1173. switch (ch) {
  1174. case "@" /* LinkedAlias */:
  1175. scnr.next();
  1176. token = getToken(context, 8 /* LinkedAlias */, "@" /* LinkedAlias */);
  1177. context.inLinked = true;
  1178. return token;
  1179. case "." /* LinkedDot */:
  1180. skipSpaces(scnr);
  1181. scnr.next();
  1182. return getToken(context, 9 /* LinkedDot */, "." /* LinkedDot */);
  1183. case ":" /* LinkedDelimiter */:
  1184. skipSpaces(scnr);
  1185. scnr.next();
  1186. return getToken(context, 10 /* LinkedDelimiter */, ":" /* LinkedDelimiter */);
  1187. default:
  1188. if (isPluralStart(scnr)) {
  1189. token = getToken(context, 1 /* Pipe */, readPlural(scnr));
  1190. // reset
  1191. context.braceNest = 0;
  1192. context.inLinked = false;
  1193. return token;
  1194. }
  1195. if (isLinkedDotStart(scnr, context) ||
  1196. isLinkedDelimiterStart(scnr, context)) {
  1197. skipSpaces(scnr);
  1198. return readTokenInLinked(scnr, context);
  1199. }
  1200. if (isLinkedModifierStart(scnr, context)) {
  1201. skipSpaces(scnr);
  1202. return getToken(context, 12 /* LinkedModifier */, readLinkedModifier(scnr));
  1203. }
  1204. if (isLinkedReferStart(scnr, context)) {
  1205. skipSpaces(scnr);
  1206. if (ch === "{" /* BraceLeft */) {
  1207. // scan the placeholder
  1208. return readTokenInPlaceholder(scnr, context) || token;
  1209. }
  1210. else {
  1211. return getToken(context, 11 /* LinkedKey */, readLinkedRefer(scnr));
  1212. }
  1213. }
  1214. if (currentType === 8 /* LinkedAlias */) {
  1215. emitError(9 /* INVALID_LINKED_FORMAT */, currentPosition(), 0);
  1216. }
  1217. context.braceNest = 0;
  1218. context.inLinked = false;
  1219. return readToken(scnr, context);
  1220. }
  1221. }
  1222. // TODO: We need refactoring of token parsing ...
  1223. function readToken(scnr, context) {
  1224. let token = { type: 14 /* EOF */ };
  1225. if (context.braceNest > 0) {
  1226. return readTokenInPlaceholder(scnr, context) || getEndToken(context);
  1227. }
  1228. if (context.inLinked) {
  1229. return readTokenInLinked(scnr, context) || getEndToken(context);
  1230. }
  1231. const ch = scnr.currentChar();
  1232. switch (ch) {
  1233. case "{" /* BraceLeft */:
  1234. return readTokenInPlaceholder(scnr, context) || getEndToken(context);
  1235. case "}" /* BraceRight */:
  1236. emitError(5 /* UNBALANCED_CLOSING_BRACE */, currentPosition(), 0);
  1237. scnr.next();
  1238. return getToken(context, 3 /* BraceRight */, "}" /* BraceRight */);
  1239. case "@" /* LinkedAlias */:
  1240. return readTokenInLinked(scnr, context) || getEndToken(context);
  1241. default:
  1242. if (isPluralStart(scnr)) {
  1243. token = getToken(context, 1 /* Pipe */, readPlural(scnr));
  1244. // reset
  1245. context.braceNest = 0;
  1246. context.inLinked = false;
  1247. return token;
  1248. }
  1249. if (isTextStart(scnr)) {
  1250. return getToken(context, 0 /* Text */, readText(scnr));
  1251. }
  1252. if (ch === "%" /* Modulo */) {
  1253. scnr.next();
  1254. return getToken(context, 4 /* Modulo */, "%" /* Modulo */);
  1255. }
  1256. break;
  1257. }
  1258. return token;
  1259. }
  1260. function nextToken() {
  1261. const { currentType, offset, startLoc, endLoc } = _context;
  1262. _context.lastType = currentType;
  1263. _context.lastOffset = offset;
  1264. _context.lastStartLoc = startLoc;
  1265. _context.lastEndLoc = endLoc;
  1266. _context.offset = currentOffset();
  1267. _context.startLoc = currentPosition();
  1268. if (_scnr.currentChar() === EOF) {
  1269. return getToken(_context, 14 /* EOF */);
  1270. }
  1271. return readToken(_scnr, _context);
  1272. }
  1273. return {
  1274. nextToken,
  1275. currentOffset,
  1276. currentPosition,
  1277. context
  1278. };
  1279. }
  1280. const ERROR_DOMAIN = 'parser';
  1281. // Backslash backslash, backslash quote, uHHHH, UHHHHHH.
  1282. const KNOWN_ESCAPES = /(?:\\\\|\\'|\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{6}))/g;
  1283. function fromEscapeSequence(match, codePoint4, codePoint6) {
  1284. switch (match) {
  1285. case `\\\\`:
  1286. return `\\`;
  1287. case `\\\'`:
  1288. return `\'`;
  1289. default: {
  1290. const codePoint = parseInt(codePoint4 || codePoint6, 16);
  1291. if (codePoint <= 0xd7ff || codePoint >= 0xe000) {
  1292. return String.fromCodePoint(codePoint);
  1293. }
  1294. // invalid ...
  1295. // Replace them with U+FFFD REPLACEMENT CHARACTER.
  1296. return '�';
  1297. }
  1298. }
  1299. }
  1300. function createParser(options = {}) {
  1301. const location = options.location !== false;
  1302. const { onError } = options;
  1303. function emitError(tokenzer, code, start, offset, ...args) {
  1304. const end = tokenzer.currentPosition();
  1305. end.offset += offset;
  1306. end.column += offset;
  1307. if (onError) {
  1308. const loc = createLocation(start, end);
  1309. const err = createCompileError(code, loc, {
  1310. domain: ERROR_DOMAIN,
  1311. args
  1312. });
  1313. onError(err);
  1314. }
  1315. }
  1316. function startNode(type, offset, loc) {
  1317. const node = {
  1318. type,
  1319. start: offset,
  1320. end: offset
  1321. };
  1322. if (location) {
  1323. node.loc = { start: loc, end: loc };
  1324. }
  1325. return node;
  1326. }
  1327. function endNode(node, offset, pos, type) {
  1328. node.end = offset;
  1329. if (type) {
  1330. node.type = type;
  1331. }
  1332. if (location && node.loc) {
  1333. node.loc.end = pos;
  1334. }
  1335. }
  1336. function parseText(tokenizer, value) {
  1337. const context = tokenizer.context();
  1338. const node = startNode(3 /* Text */, context.offset, context.startLoc);
  1339. node.value = value;
  1340. endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
  1341. return node;
  1342. }
  1343. function parseList(tokenizer, index) {
  1344. const context = tokenizer.context();
  1345. const { lastOffset: offset, lastStartLoc: loc } = context; // get brace left loc
  1346. const node = startNode(5 /* List */, offset, loc);
  1347. node.index = parseInt(index, 10);
  1348. tokenizer.nextToken(); // skip brach right
  1349. endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
  1350. return node;
  1351. }
  1352. function parseNamed(tokenizer, key) {
  1353. const context = tokenizer.context();
  1354. const { lastOffset: offset, lastStartLoc: loc } = context; // get brace left loc
  1355. const node = startNode(4 /* Named */, offset, loc);
  1356. node.key = key;
  1357. tokenizer.nextToken(); // skip brach right
  1358. endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
  1359. return node;
  1360. }
  1361. function parseLiteral(tokenizer, value) {
  1362. const context = tokenizer.context();
  1363. const { lastOffset: offset, lastStartLoc: loc } = context; // get brace left loc
  1364. const node = startNode(9 /* Literal */, offset, loc);
  1365. node.value = value.replace(KNOWN_ESCAPES, fromEscapeSequence);
  1366. tokenizer.nextToken(); // skip brach right
  1367. endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
  1368. return node;
  1369. }
  1370. function parseLinkedModifier(tokenizer) {
  1371. const token = tokenizer.nextToken();
  1372. const context = tokenizer.context();
  1373. const { lastOffset: offset, lastStartLoc: loc } = context; // get linked dot loc
  1374. const node = startNode(8 /* LinkedModifier */, offset, loc);
  1375. if (token.type !== 12 /* LinkedModifier */) {
  1376. // empty modifier
  1377. emitError(tokenizer, 11 /* UNEXPECTED_EMPTY_LINKED_MODIFIER */, context.lastStartLoc, 0);
  1378. node.value = '';
  1379. endNode(node, offset, loc);
  1380. return {
  1381. nextConsumeToken: token,
  1382. node
  1383. };
  1384. }
  1385. // check token
  1386. if (token.value == null) {
  1387. emitError(tokenizer, 13 /* UNEXPECTED_LEXICAL_ANALYSIS */, context.lastStartLoc, 0, getTokenCaption(token));
  1388. }
  1389. node.value = token.value || '';
  1390. endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
  1391. return {
  1392. node
  1393. };
  1394. }
  1395. function parseLinkedKey(tokenizer, value) {
  1396. const context = tokenizer.context();
  1397. const node = startNode(7 /* LinkedKey */, context.offset, context.startLoc);
  1398. node.value = value;
  1399. endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
  1400. return node;
  1401. }
  1402. function parseLinked(tokenizer) {
  1403. const context = tokenizer.context();
  1404. const linkedNode = startNode(6 /* Linked */, context.offset, context.startLoc);
  1405. let token = tokenizer.nextToken();
  1406. if (token.type === 9 /* LinkedDot */) {
  1407. const parsed = parseLinkedModifier(tokenizer);
  1408. linkedNode.modifier = parsed.node;
  1409. token = parsed.nextConsumeToken || tokenizer.nextToken();
  1410. }
  1411. // asset check token
  1412. if (token.type !== 10 /* LinkedDelimiter */) {
  1413. emitError(tokenizer, 13 /* UNEXPECTED_LEXICAL_ANALYSIS */, context.lastStartLoc, 0, getTokenCaption(token));
  1414. }
  1415. token = tokenizer.nextToken();
  1416. // skip brace left
  1417. if (token.type === 2 /* BraceLeft */) {
  1418. token = tokenizer.nextToken();
  1419. }
  1420. switch (token.type) {
  1421. case 11 /* LinkedKey */:
  1422. if (token.value == null) {
  1423. emitError(tokenizer, 13 /* UNEXPECTED_LEXICAL_ANALYSIS */, context.lastStartLoc, 0, getTokenCaption(token));
  1424. }
  1425. linkedNode.key = parseLinkedKey(tokenizer, token.value || '');
  1426. break;
  1427. case 5 /* Named */:
  1428. if (token.value == null) {
  1429. emitError(tokenizer, 13 /* UNEXPECTED_LEXICAL_ANALYSIS */, context.lastStartLoc, 0, getTokenCaption(token));
  1430. }
  1431. linkedNode.key = parseNamed(tokenizer, token.value || '');
  1432. break;
  1433. case 6 /* List */:
  1434. if (token.value == null) {
  1435. emitError(tokenizer, 13 /* UNEXPECTED_LEXICAL_ANALYSIS */, context.lastStartLoc, 0, getTokenCaption(token));
  1436. }
  1437. linkedNode.key = parseList(tokenizer, token.value || '');
  1438. break;
  1439. case 7 /* Literal */:
  1440. if (token.value == null) {
  1441. emitError(tokenizer, 13 /* UNEXPECTED_LEXICAL_ANALYSIS */, context.lastStartLoc, 0, getTokenCaption(token));
  1442. }
  1443. linkedNode.key = parseLiteral(tokenizer, token.value || '');
  1444. break;
  1445. default:
  1446. // empty key
  1447. emitError(tokenizer, 12 /* UNEXPECTED_EMPTY_LINKED_KEY */, context.lastStartLoc, 0);
  1448. const nextContext = tokenizer.context();
  1449. const emptyLinkedKeyNode = startNode(7 /* LinkedKey */, nextContext.offset, nextContext.startLoc);
  1450. emptyLinkedKeyNode.value = '';
  1451. endNode(emptyLinkedKeyNode, nextContext.offset, nextContext.startLoc);
  1452. linkedNode.key = emptyLinkedKeyNode;
  1453. endNode(linkedNode, nextContext.offset, nextContext.startLoc);
  1454. return {
  1455. nextConsumeToken: token,
  1456. node: linkedNode
  1457. };
  1458. }
  1459. endNode(linkedNode, tokenizer.currentOffset(), tokenizer.currentPosition());
  1460. return {
  1461. node: linkedNode
  1462. };
  1463. }
  1464. function parseMessage(tokenizer) {
  1465. const context = tokenizer.context();
  1466. const startOffset = context.currentType === 1 /* Pipe */
  1467. ? tokenizer.currentOffset()
  1468. : context.offset;
  1469. const startLoc = context.currentType === 1 /* Pipe */
  1470. ? context.endLoc
  1471. : context.startLoc;
  1472. const node = startNode(2 /* Message */, startOffset, startLoc);
  1473. node.items = [];
  1474. let nextToken = null;
  1475. do {
  1476. const token = nextToken || tokenizer.nextToken();
  1477. nextToken = null;
  1478. switch (token.type) {
  1479. case 0 /* Text */:
  1480. if (token.value == null) {
  1481. emitError(tokenizer, 13 /* UNEXPECTED_LEXICAL_ANALYSIS */, context.lastStartLoc, 0, getTokenCaption(token));
  1482. }
  1483. node.items.push(parseText(tokenizer, token.value || ''));
  1484. break;
  1485. case 6 /* List */:
  1486. if (token.value == null) {
  1487. emitError(tokenizer, 13 /* UNEXPECTED_LEXICAL_ANALYSIS */, context.lastStartLoc, 0, getTokenCaption(token));
  1488. }
  1489. node.items.push(parseList(tokenizer, token.value || ''));
  1490. break;
  1491. case 5 /* Named */:
  1492. if (token.value == null) {
  1493. emitError(tokenizer, 13 /* UNEXPECTED_LEXICAL_ANALYSIS */, context.lastStartLoc, 0, getTokenCaption(token));
  1494. }
  1495. node.items.push(parseNamed(tokenizer, token.value || ''));
  1496. break;
  1497. case 7 /* Literal */:
  1498. if (token.value == null) {
  1499. emitError(tokenizer, 13 /* UNEXPECTED_LEXICAL_ANALYSIS */, context.lastStartLoc, 0, getTokenCaption(token));
  1500. }
  1501. node.items.push(parseLiteral(tokenizer, token.value || ''));
  1502. break;
  1503. case 8 /* LinkedAlias */:
  1504. const parsed = parseLinked(tokenizer);
  1505. node.items.push(parsed.node);
  1506. nextToken = parsed.nextConsumeToken || null;
  1507. break;
  1508. }
  1509. } while (context.currentType !== 14 /* EOF */ &&
  1510. context.currentType !== 1 /* Pipe */);
  1511. // adjust message node loc
  1512. const endOffset = context.currentType === 1 /* Pipe */
  1513. ? context.lastOffset
  1514. : tokenizer.currentOffset();
  1515. const endLoc = context.currentType === 1 /* Pipe */
  1516. ? context.lastEndLoc
  1517. : tokenizer.currentPosition();
  1518. endNode(node, endOffset, endLoc);
  1519. return node;
  1520. }
  1521. function parsePlural(tokenizer, offset, loc, msgNode) {
  1522. const context = tokenizer.context();
  1523. let hasEmptyMessage = msgNode.items.length === 0;
  1524. const node = startNode(1 /* Plural */, offset, loc);
  1525. node.cases = [];
  1526. node.cases.push(msgNode);
  1527. do {
  1528. const msg = parseMessage(tokenizer);
  1529. if (!hasEmptyMessage) {
  1530. hasEmptyMessage = msg.items.length === 0;
  1531. }
  1532. node.cases.push(msg);
  1533. } while (context.currentType !== 14 /* EOF */);
  1534. if (hasEmptyMessage) {
  1535. emitError(tokenizer, 10 /* MUST_HAVE_MESSAGES_IN_PLURAL */, loc, 0);
  1536. }
  1537. endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
  1538. return node;
  1539. }
  1540. function parseResource(tokenizer) {
  1541. const context = tokenizer.context();
  1542. const { offset, startLoc } = context;
  1543. const msgNode = parseMessage(tokenizer);
  1544. if (context.currentType === 14 /* EOF */) {
  1545. return msgNode;
  1546. }
  1547. else {
  1548. return parsePlural(tokenizer, offset, startLoc, msgNode);
  1549. }
  1550. }
  1551. function parse(source) {
  1552. const tokenizer = createTokenizer(source, assign({}, options));
  1553. const context = tokenizer.context();
  1554. const node = startNode(0 /* Resource */, context.offset, context.startLoc);
  1555. if (location && node.loc) {
  1556. node.loc.source = source;
  1557. }
  1558. node.body = parseResource(tokenizer);
  1559. // assert whether achieved to EOF
  1560. if (context.currentType !== 14 /* EOF */) {
  1561. emitError(tokenizer, 13 /* UNEXPECTED_LEXICAL_ANALYSIS */, context.lastStartLoc, 0, source[context.offset] || '');
  1562. }
  1563. endNode(node, tokenizer.currentOffset(), tokenizer.currentPosition());
  1564. return node;
  1565. }
  1566. return { parse };
  1567. }
  1568. function getTokenCaption(token) {
  1569. if (token.type === 14 /* EOF */) {
  1570. return 'EOF';
  1571. }
  1572. const name = (token.value || '').replace(/\r?\n/gu, '\\n');
  1573. return name.length > 10 ? name.slice(0, 9) + '…' : name;
  1574. }
  1575. function createTransformer(ast, options = {} // eslint-disable-line
  1576. ) {
  1577. const _context = {
  1578. ast,
  1579. helpers: new Set()
  1580. };
  1581. const context = () => _context;
  1582. const helper = (name) => {
  1583. _context.helpers.add(name);
  1584. return name;
  1585. };
  1586. return { context, helper };
  1587. }
  1588. function traverseNodes(nodes, transformer) {
  1589. for (let i = 0; i < nodes.length; i++) {
  1590. traverseNode(nodes[i], transformer);
  1591. }
  1592. }
  1593. function traverseNode(node, transformer) {
  1594. // TODO: if we need pre-hook of transform, should be implemented to here
  1595. switch (node.type) {
  1596. case 1 /* Plural */:
  1597. traverseNodes(node.cases, transformer);
  1598. transformer.helper("plural" /* PLURAL */);
  1599. break;
  1600. case 2 /* Message */:
  1601. traverseNodes(node.items, transformer);
  1602. break;
  1603. case 6 /* Linked */:
  1604. const linked = node;
  1605. traverseNode(linked.key, transformer);
  1606. transformer.helper("linked" /* LINKED */);
  1607. break;
  1608. case 5 /* List */:
  1609. transformer.helper("interpolate" /* INTERPOLATE */);
  1610. transformer.helper("list" /* LIST */);
  1611. break;
  1612. case 4 /* Named */:
  1613. transformer.helper("interpolate" /* INTERPOLATE */);
  1614. transformer.helper("named" /* NAMED */);
  1615. break;
  1616. }
  1617. // TODO: if we need post-hook of transform, should be implemented to here
  1618. }
  1619. // transform AST
  1620. function transform(ast, options = {} // eslint-disable-line
  1621. ) {
  1622. const transformer = createTransformer(ast);
  1623. transformer.helper("normalize" /* NORMALIZE */);
  1624. // traverse
  1625. ast.body && traverseNode(ast.body, transformer);
  1626. // set meta information
  1627. const context = transformer.context();
  1628. ast.helpers = Array.from(context.helpers);
  1629. }
  1630. function createCodeGenerator(ast, options) {
  1631. const { sourceMap, filename, breakLineCode, needIndent: _needIndent } = options;
  1632. const _context = {
  1633. source: ast.loc.source,
  1634. filename,
  1635. code: '',
  1636. column: 1,
  1637. line: 1,
  1638. offset: 0,
  1639. map: undefined,
  1640. breakLineCode,
  1641. needIndent: _needIndent,
  1642. indentLevel: 0
  1643. };
  1644. const context = () => _context;
  1645. function push(code, node) {
  1646. _context.code += code;
  1647. }
  1648. function _newline(n, withBreakLine = true) {
  1649. const _breakLineCode = withBreakLine ? breakLineCode : '';
  1650. push(_needIndent ? _breakLineCode + ` `.repeat(n) : _breakLineCode);
  1651. }
  1652. function indent(withNewLine = true) {
  1653. const level = ++_context.indentLevel;
  1654. withNewLine && _newline(level);
  1655. }
  1656. function deindent(withNewLine = true) {
  1657. const level = --_context.indentLevel;
  1658. withNewLine && _newline(level);
  1659. }
  1660. function newline() {
  1661. _newline(_context.indentLevel);
  1662. }
  1663. const helper = (key) => `_${key}`;
  1664. const needIndent = () => _context.needIndent;
  1665. return {
  1666. context,
  1667. push,
  1668. indent,
  1669. deindent,
  1670. newline,
  1671. helper,
  1672. needIndent
  1673. };
  1674. }
  1675. function generateLinkedNode(generator, node) {
  1676. const { helper } = generator;
  1677. generator.push(`${helper("linked" /* LINKED */)}(`);
  1678. generateNode(generator, node.key);
  1679. if (node.modifier) {
  1680. generator.push(`, `);
  1681. generateNode(generator, node.modifier);
  1682. }
  1683. generator.push(`)`);
  1684. }
  1685. function generateMessageNode(generator, node) {
  1686. const { helper, needIndent } = generator;
  1687. generator.push(`${helper("normalize" /* NORMALIZE */)}([`);
  1688. generator.indent(needIndent());
  1689. const length = node.items.length;
  1690. for (let i = 0; i < length; i++) {
  1691. generateNode(generator, node.items[i]);
  1692. if (i === length - 1) {
  1693. break;
  1694. }
  1695. generator.push(', ');
  1696. }
  1697. generator.deindent(needIndent());
  1698. generator.push('])');
  1699. }
  1700. function generatePluralNode(generator, node) {
  1701. const { helper, needIndent } = generator;
  1702. if (node.cases.length > 1) {
  1703. generator.push(`${helper("plural" /* PLURAL */)}([`);
  1704. generator.indent(needIndent());
  1705. const length = node.cases.length;
  1706. for (let i = 0; i < length; i++) {
  1707. generateNode(generator, node.cases[i]);
  1708. if (i === length - 1) {
  1709. break;
  1710. }
  1711. generator.push(', ');
  1712. }
  1713. generator.deindent(needIndent());
  1714. generator.push(`])`);
  1715. }
  1716. }
  1717. function generateResource(generator, node) {
  1718. if (node.body) {
  1719. generateNode(generator, node.body);
  1720. }
  1721. else {
  1722. generator.push('null');
  1723. }
  1724. }
  1725. function generateNode(generator, node) {
  1726. const { helper } = generator;
  1727. switch (node.type) {
  1728. case 0 /* Resource */:
  1729. generateResource(generator, node);
  1730. break;
  1731. case 1 /* Plural */:
  1732. generatePluralNode(generator, node);
  1733. break;
  1734. case 2 /* Message */:
  1735. generateMessageNode(generator, node);
  1736. break;
  1737. case 6 /* Linked */:
  1738. generateLinkedNode(generator, node);
  1739. break;
  1740. case 8 /* LinkedModifier */:
  1741. generator.push(JSON.stringify(node.value), node);
  1742. break;
  1743. case 7 /* LinkedKey */:
  1744. generator.push(JSON.stringify(node.value), node);
  1745. break;
  1746. case 5 /* List */:
  1747. generator.push(`${helper("interpolate" /* INTERPOLATE */)}(${helper("list" /* LIST */)}(${node.index}))`, node);
  1748. break;
  1749. case 4 /* Named */:
  1750. generator.push(`${helper("interpolate" /* INTERPOLATE */)}(${helper("named" /* NAMED */)}(${JSON.stringify(node.key)}))`, node);
  1751. break;
  1752. case 9 /* Literal */:
  1753. generator.push(JSON.stringify(node.value), node);
  1754. break;
  1755. case 3 /* Text */:
  1756. generator.push(JSON.stringify(node.value), node);
  1757. break;
  1758. default:
  1759. {
  1760. throw new Error(`unhandled codegen node type: ${node.type}`);
  1761. }
  1762. }
  1763. }
  1764. // generate code from AST
  1765. const generate = (ast, options = {} // eslint-disable-line
  1766. ) => {
  1767. const mode = isString(options.mode) ? options.mode : 'normal';
  1768. const filename = isString(options.filename)
  1769. ? options.filename
  1770. : 'message.intl';
  1771. const sourceMap = !!options.sourceMap;
  1772. // prettier-ignore
  1773. const breakLineCode = options.breakLineCode != null
  1774. ? options.breakLineCode
  1775. : mode === 'arrow'
  1776. ? ';'
  1777. : '\n';
  1778. const needIndent = options.needIndent ? options.needIndent : mode !== 'arrow';
  1779. const helpers = ast.helpers || [];
  1780. const generator = createCodeGenerator(ast, {
  1781. mode,
  1782. filename,
  1783. sourceMap,
  1784. breakLineCode,
  1785. needIndent
  1786. });
  1787. generator.push(mode === 'normal' ? `function __msg__ (ctx) {` : `(ctx) => {`);
  1788. generator.indent(needIndent);
  1789. if (helpers.length > 0) {
  1790. generator.push(`const { ${helpers.map(s => `${s}: _${s}`).join(', ')} } = ctx`);
  1791. generator.newline();
  1792. }
  1793. generator.push(`return `);
  1794. generateNode(generator, ast);
  1795. generator.deindent(needIndent);
  1796. generator.push(`}`);
  1797. const { code, map } = generator.context();
  1798. return {
  1799. ast,
  1800. code,
  1801. map: map ? map.toJSON() : undefined // eslint-disable-line @typescript-eslint/no-explicit-any
  1802. };
  1803. };
  1804. function baseCompile(source, options = {}) {
  1805. const assignedOptions = assign({}, options);
  1806. // parse source codes
  1807. const parser = createParser(assignedOptions);
  1808. const ast = parser.parse(source);
  1809. // transform ASTs
  1810. transform(ast, assignedOptions);
  1811. // generate javascript codes
  1812. return generate(ast, assignedOptions);
  1813. }
  1814. const IntlifyDevToolsHooks = {
  1815. I18nInit: 'i18n:init',
  1816. FunctionTranslate: 'function:translate'
  1817. };
  1818. let devtools = null;
  1819. function setDevToolsHook(hook) {
  1820. devtools = hook;
  1821. }
  1822. function getDevToolsHook() {
  1823. return devtools;
  1824. }
  1825. function initI18nDevTools(i18n, version, meta) {
  1826. // TODO: queue if devtools is undefined
  1827. devtools &&
  1828. devtools.emit(IntlifyDevToolsHooks.I18nInit, {
  1829. timestamp: Date.now(),
  1830. i18n,
  1831. version,
  1832. meta
  1833. });
  1834. }
  1835. const translateDevTools = /* #__PURE__*/ createDevToolsHook(IntlifyDevToolsHooks.FunctionTranslate);
  1836. function createDevToolsHook(hook) {
  1837. return (payloads) => devtools && devtools.emit(hook, payloads);
  1838. }
  1839. /** @internal */
  1840. const warnMessages = {
  1841. [0 /* NOT_FOUND_KEY */]: `Not found '{key}' key in '{locale}' locale messages.`,
  1842. [1 /* FALLBACK_TO_TRANSLATE */]: `Fall back to translate '{key}' key with '{target}' locale.`,
  1843. [2 /* CANNOT_FORMAT_NUMBER */]: `Cannot format a number value due to not supported Intl.NumberFormat.`,
  1844. [3 /* FALLBACK_TO_NUMBER_FORMAT */]: `Fall back to number format '{key}' key with '{target}' locale.`,
  1845. [4 /* CANNOT_FORMAT_DATE */]: `Cannot format a date value due to not supported Intl.DateTimeFormat.`,
  1846. [5 /* FALLBACK_TO_DATE_FORMAT */]: `Fall back to datetime format '{key}' key with '{target}' locale.`
  1847. };
  1848. function getWarnMessage(code, ...args) {
  1849. return format(warnMessages[code], ...args);
  1850. }
  1851. /**
  1852. * Intlify core-base version
  1853. * @internal
  1854. */
  1855. const VERSION = '9.1.9';
  1856. const NOT_REOSLVED = -1;
  1857. const MISSING_RESOLVE_VALUE = '';
  1858. function getDefaultLinkedModifiers() {
  1859. return {
  1860. upper: (val) => (isString(val) ? val.toUpperCase() : val),
  1861. lower: (val) => (isString(val) ? val.toLowerCase() : val),
  1862. // prettier-ignore
  1863. capitalize: (val) => (isString(val)
  1864. ? `${val.charAt(0).toLocaleUpperCase()}${val.substr(1)}`
  1865. : val)
  1866. };
  1867. }
  1868. let _compiler;
  1869. function registerMessageCompiler(compiler) {
  1870. _compiler = compiler;
  1871. }
  1872. // Additional Meta for Intlify DevTools
  1873. let _additionalMeta = null;
  1874. const setAdditionalMeta = /* #__PURE__*/ (meta) => {
  1875. _additionalMeta = meta;
  1876. };
  1877. const getAdditionalMeta = /* #__PURE__*/ () => _additionalMeta;
  1878. // ID for CoreContext
  1879. let _cid = 0;
  1880. function createCoreContext(options = {}) {
  1881. // setup options
  1882. const version = isString(options.version) ? options.version : VERSION;
  1883. const locale = isString(options.locale) ? options.locale : 'en-US';
  1884. const fallbackLocale = isArray(options.fallbackLocale) ||
  1885. isPlainObject(options.fallbackLocale) ||
  1886. isString(options.fallbackLocale) ||
  1887. options.fallbackLocale === false
  1888. ? options.fallbackLocale
  1889. : locale;
  1890. const messages = isPlainObject(options.messages)
  1891. ? options.messages
  1892. : { [locale]: {} };
  1893. const datetimeFormats = isPlainObject(options.datetimeFormats)
  1894. ? options.datetimeFormats
  1895. : { [locale]: {} };
  1896. const numberFormats = isPlainObject(options.numberFormats)
  1897. ? options.numberFormats
  1898. : { [locale]: {} };
  1899. const modifiers = assign({}, options.modifiers || {}, getDefaultLinkedModifiers());
  1900. const pluralRules = options.pluralRules || {};
  1901. const missing = isFunction(options.missing) ? options.missing : null;
  1902. const missingWarn = isBoolean(options.missingWarn) || isRegExp(options.missingWarn)
  1903. ? options.missingWarn
  1904. : true;
  1905. const fallbackWarn = isBoolean(options.fallbackWarn) || isRegExp(options.fallbackWarn)
  1906. ? options.fallbackWarn
  1907. : true;
  1908. const fallbackFormat = !!options.fallbackFormat;
  1909. const unresolving = !!options.unresolving;
  1910. const postTranslation = isFunction(options.postTranslation)
  1911. ? options.postTranslation
  1912. : null;
  1913. const processor = isPlainObject(options.processor) ? options.processor : null;
  1914. const warnHtmlMessage = isBoolean(options.warnHtmlMessage)
  1915. ? options.warnHtmlMessage
  1916. : true;
  1917. const escapeParameter = !!options.escapeParameter;
  1918. const messageCompiler = isFunction(options.messageCompiler)
  1919. ? options.messageCompiler
  1920. : _compiler;
  1921. const onWarn = isFunction(options.onWarn) ? options.onWarn : warn;
  1922. // setup internal options
  1923. const internalOptions = options;
  1924. const __datetimeFormatters = isObject(internalOptions.__datetimeFormatters)
  1925. ? internalOptions.__datetimeFormatters
  1926. : new Map();
  1927. const __numberFormatters = isObject(internalOptions.__numberFormatters)
  1928. ? internalOptions.__numberFormatters
  1929. : new Map();
  1930. const __meta = isObject(internalOptions.__meta) ? internalOptions.__meta : {};
  1931. _cid++;
  1932. const context = {
  1933. version,
  1934. cid: _cid,
  1935. locale,
  1936. fallbackLocale,
  1937. messages,
  1938. datetimeFormats,
  1939. numberFormats,
  1940. modifiers,
  1941. pluralRules,
  1942. missing,
  1943. missingWarn,
  1944. fallbackWarn,
  1945. fallbackFormat,
  1946. unresolving,
  1947. postTranslation,
  1948. processor,
  1949. warnHtmlMessage,
  1950. escapeParameter,
  1951. messageCompiler,
  1952. onWarn,
  1953. __datetimeFormatters,
  1954. __numberFormatters,
  1955. __meta
  1956. };
  1957. // for vue-devtools timeline event
  1958. {
  1959. context.__v_emitter =
  1960. internalOptions.__v_emitter != null
  1961. ? internalOptions.__v_emitter
  1962. : undefined;
  1963. }
  1964. // NOTE: experimental !!
  1965. {
  1966. initI18nDevTools(context, version, __meta);
  1967. }
  1968. return context;
  1969. }
  1970. /** @internal */
  1971. function isTranslateFallbackWarn(fallback, key) {
  1972. return fallback instanceof RegExp ? fallback.test(key) : fallback;
  1973. }
  1974. /** @internal */
  1975. function isTranslateMissingWarn(missing, key) {
  1976. return missing instanceof RegExp ? missing.test(key) : missing;
  1977. }
  1978. /** @internal */
  1979. function handleMissing(context, key, locale, missingWarn, type) {
  1980. const { missing, onWarn } = context;
  1981. // for vue-devtools timeline event
  1982. {
  1983. const emitter = context.__v_emitter;
  1984. if (emitter) {
  1985. emitter.emit("missing" /* MISSING */, {
  1986. locale,
  1987. key,
  1988. type,
  1989. groupId: `${type}:${key}`
  1990. });
  1991. }
  1992. }
  1993. if (missing !== null) {
  1994. const ret = missing(context, locale, key, type);
  1995. return isString(ret) ? ret : key;
  1996. }
  1997. else {
  1998. if (isTranslateMissingWarn(missingWarn, key)) {
  1999. onWarn(getWarnMessage(0 /* NOT_FOUND_KEY */, { key, locale }));
  2000. }
  2001. return key;
  2002. }
  2003. }
  2004. /** @internal */
  2005. function getLocaleChain(ctx, fallback, start) {
  2006. const context = ctx;
  2007. if (!context.__localeChainCache) {
  2008. context.__localeChainCache = new Map();
  2009. }
  2010. let chain = context.__localeChainCache.get(start);
  2011. if (!chain) {
  2012. chain = [];
  2013. // first block defined by start
  2014. let block = [start];
  2015. // while any intervening block found
  2016. while (isArray(block)) {
  2017. block = appendBlockToChain(chain, block, fallback);
  2018. }
  2019. // prettier-ignore
  2020. // last block defined by default
  2021. const defaults = isArray(fallback)
  2022. ? fallback
  2023. : isPlainObject(fallback)
  2024. ? fallback['default']
  2025. ? fallback['default']
  2026. : null
  2027. : fallback;
  2028. // convert defaults to array
  2029. block = isString(defaults) ? [defaults] : defaults;
  2030. if (isArray(block)) {
  2031. appendBlockToChain(chain, block, false);
  2032. }
  2033. context.__localeChainCache.set(start, chain);
  2034. }
  2035. return chain;
  2036. }
  2037. function appendBlockToChain(chain, block, blocks) {
  2038. let follow = true;
  2039. for (let i = 0; i < block.length && isBoolean(follow); i++) {
  2040. const locale = block[i];
  2041. if (isString(locale)) {
  2042. follow = appendLocaleToChain(chain, block[i], blocks);
  2043. }
  2044. }
  2045. return follow;
  2046. }
  2047. function appendLocaleToChain(chain, locale, blocks) {
  2048. let follow;
  2049. const tokens = locale.split('-');
  2050. do {
  2051. const target = tokens.join('-');
  2052. follow = appendItemToChain(chain, target, blocks);
  2053. tokens.splice(-1, 1);
  2054. } while (tokens.length && follow === true);
  2055. return follow;
  2056. }
  2057. function appendItemToChain(chain, target, blocks) {
  2058. let follow = false;
  2059. if (!chain.includes(target)) {
  2060. follow = true;
  2061. if (target) {
  2062. follow = target[target.length - 1] !== '!';
  2063. const locale = target.replace(/!/g, '');
  2064. chain.push(locale);
  2065. if ((isArray(blocks) || isPlainObject(blocks)) &&
  2066. blocks[locale] // eslint-disable-line @typescript-eslint/no-explicit-any
  2067. ) {
  2068. // eslint-disable-next-line @typescript-eslint/no-explicit-any
  2069. follow = blocks[locale];
  2070. }
  2071. }
  2072. }
  2073. return follow;
  2074. }
  2075. /** @internal */
  2076. function updateFallbackLocale(ctx, locale, fallback) {
  2077. const context = ctx;
  2078. context.__localeChainCache = new Map();
  2079. getLocaleChain(ctx, fallback, locale);
  2080. }
  2081. const RE_HTML_TAG = /<\/?[\w\s="/.':;#-\/]+>/;
  2082. const WARN_MESSAGE = `Detected HTML in '{source}' message. Recommend not using HTML messages to avoid XSS.`;
  2083. function checkHtmlMessage(source, options) {
  2084. const warnHtmlMessage = isBoolean(options.warnHtmlMessage)
  2085. ? options.warnHtmlMessage
  2086. : true;
  2087. if (warnHtmlMessage && RE_HTML_TAG.test(source)) {
  2088. warn(format(WARN_MESSAGE, { source }));
  2089. }
  2090. }
  2091. const defaultOnCacheKey = (source) => source;
  2092. let compileCache = Object.create(null);
  2093. function clearCompileCache() {
  2094. compileCache = Object.create(null);
  2095. }
  2096. function compileToFunction(source, options = {}) {
  2097. {
  2098. // check HTML message
  2099. checkHtmlMessage(source, options);
  2100. // check caches
  2101. const onCacheKey = options.onCacheKey || defaultOnCacheKey;
  2102. const key = onCacheKey(source);
  2103. const cached = compileCache[key];
  2104. if (cached) {
  2105. return cached;
  2106. }
  2107. // compile error detecting
  2108. let occurred = false;
  2109. const onError = options.onError || defaultOnError;
  2110. options.onError = (err) => {
  2111. occurred = true;
  2112. onError(err);
  2113. };
  2114. // compile
  2115. const { code } = baseCompile(source, options);
  2116. // evaluate function
  2117. const msg = new Function(`return ${code}`)();
  2118. // if occurred compile error, don't cache
  2119. return !occurred ? (compileCache[key] = msg) : msg;
  2120. }
  2121. }
  2122. function createCoreError(code) {
  2123. return createCompileError(code, null, { messages: errorMessages } );
  2124. }
  2125. /** @internal */
  2126. const errorMessages = {
  2127. [14 /* INVALID_ARGUMENT */]: 'Invalid arguments',
  2128. [15 /* INVALID_DATE_ARGUMENT */]: 'The date provided is an invalid Date object.' +
  2129. 'Make sure your Date represents a valid date.',
  2130. [16 /* INVALID_ISO_DATE_ARGUMENT */]: 'The argument provided is not a valid ISO date string'
  2131. };
  2132. const NOOP_MESSAGE_FUNCTION = () => '';
  2133. const isMessageFunction = (val) => isFunction(val);
  2134. // implementation of `translate` function
  2135. function translate(context, ...args) {
  2136. const { fallbackFormat, postTranslation, unresolving, fallbackLocale, messages } = context;
  2137. const [key, options] = parseTranslateArgs(...args);
  2138. const missingWarn = isBoolean(options.missingWarn)
  2139. ? options.missingWarn
  2140. : context.missingWarn;
  2141. const fallbackWarn = isBoolean(options.fallbackWarn)
  2142. ? options.fallbackWarn
  2143. : context.fallbackWarn;
  2144. const escapeParameter = isBoolean(options.escapeParameter)
  2145. ? options.escapeParameter
  2146. : context.escapeParameter;
  2147. const resolvedMessage = !!options.resolvedMessage;
  2148. // prettier-ignore
  2149. const defaultMsgOrKey = isString(options.default) || isBoolean(options.default) // default by function option
  2150. ? !isBoolean(options.default)
  2151. ? options.default
  2152. : key
  2153. : fallbackFormat // default by `fallbackFormat` option
  2154. ? key
  2155. : '';
  2156. const enableDefaultMsg = fallbackFormat || defaultMsgOrKey !== '';
  2157. const locale = isString(options.locale) ? options.locale : context.locale;
  2158. // escape params
  2159. escapeParameter && escapeParams(options);
  2160. // resolve message format
  2161. // eslint-disable-next-line prefer-const
  2162. let [format, targetLocale, message] = !resolvedMessage
  2163. ? resolveMessageFormat(context, key, locale, fallbackLocale, fallbackWarn, missingWarn)
  2164. : [
  2165. key,
  2166. locale,
  2167. messages[locale] || {}
  2168. ];
  2169. // if you use default message, set it as message format!
  2170. let cacheBaseKey = key;
  2171. if (!resolvedMessage &&
  2172. !(isString(format) || isMessageFunction(format))) {
  2173. if (enableDefaultMsg) {
  2174. format = defaultMsgOrKey;
  2175. cacheBaseKey = format;
  2176. }
  2177. }
  2178. // checking message format and target locale
  2179. if (!resolvedMessage &&
  2180. (!(isString(format) || isMessageFunction(format)) ||
  2181. !isString(targetLocale))) {
  2182. return unresolving ? NOT_REOSLVED : key;
  2183. }
  2184. if (isString(format) && context.messageCompiler == null) {
  2185. warn(`The message format compilation is not supported in this build. ` +
  2186. `Because message compiler isn't included. ` +
  2187. `You need to pre-compilation all message format. ` +
  2188. `So translate function return '${key}'.`);
  2189. return key;
  2190. }
  2191. // setup compile error detecting
  2192. let occurred = false;
  2193. const errorDetector = () => {
  2194. occurred = true;
  2195. };
  2196. // compile message format
  2197. const msg = !isMessageFunction(format)
  2198. ? compileMessageFormat(context, key, targetLocale, format, cacheBaseKey, errorDetector)
  2199. : format;
  2200. // if occurred compile error, return the message format
  2201. if (occurred) {
  2202. return format;
  2203. }
  2204. // evaluate message with context
  2205. const ctxOptions = getMessageContextOptions(context, targetLocale, message, options);
  2206. const msgContext = createMessageContext(ctxOptions);
  2207. const messaged = evaluateMessage(context, msg, msgContext);
  2208. // if use post translation option, proceed it with handler
  2209. const ret = postTranslation ? postTranslation(messaged) : messaged;
  2210. // NOTE: experimental !!
  2211. {
  2212. // prettier-ignore
  2213. const payloads = {
  2214. timestamp: Date.now(),
  2215. key: isString(key)
  2216. ? key
  2217. : isMessageFunction(format)
  2218. ? format.key
  2219. : '',
  2220. locale: targetLocale || (isMessageFunction(format)
  2221. ? format.locale
  2222. : ''),
  2223. format: isString(format)
  2224. ? format
  2225. : isMessageFunction(format)
  2226. ? format.source
  2227. : '',
  2228. message: ret
  2229. };
  2230. payloads.meta = assign({}, context.__meta, getAdditionalMeta() || {});
  2231. translateDevTools(payloads);
  2232. }
  2233. return ret;
  2234. }
  2235. function escapeParams(options) {
  2236. if (isArray(options.list)) {
  2237. options.list = options.list.map(item => isString(item) ? escapeHtml(item) : item);
  2238. }
  2239. else if (isObject(options.named)) {
  2240. Object.keys(options.named).forEach(key => {
  2241. if (isString(options.named[key])) {
  2242. options.named[key] = escapeHtml(options.named[key]);
  2243. }
  2244. });
  2245. }
  2246. }
  2247. function resolveMessageFormat(context, key, locale, fallbackLocale, fallbackWarn, missingWarn) {
  2248. const { messages, onWarn } = context;
  2249. const locales = getLocaleChain(context, fallbackLocale, locale);
  2250. let message = {};
  2251. let targetLocale;
  2252. let format = null;
  2253. let from = locale;
  2254. let to = null;
  2255. const type = 'translate';
  2256. for (let i = 0; i < locales.length; i++) {
  2257. targetLocale = to = locales[i];
  2258. if (locale !== targetLocale &&
  2259. isTranslateFallbackWarn(fallbackWarn, key)) {
  2260. onWarn(getWarnMessage(1 /* FALLBACK_TO_TRANSLATE */, {
  2261. key,
  2262. target: targetLocale
  2263. }));
  2264. }
  2265. // for vue-devtools timeline event
  2266. if (locale !== targetLocale) {
  2267. const emitter = context.__v_emitter;
  2268. if (emitter) {
  2269. emitter.emit("fallback" /* FALBACK */, {
  2270. type,
  2271. key,
  2272. from,
  2273. to,
  2274. groupId: `${type}:${key}`
  2275. });
  2276. }
  2277. }
  2278. message =
  2279. messages[targetLocale] || {};
  2280. // for vue-devtools timeline event
  2281. let start = null;
  2282. let startTag;
  2283. let endTag;
  2284. if (inBrowser) {
  2285. start = window.performance.now();
  2286. startTag = 'intlify-message-resolve-start';
  2287. endTag = 'intlify-message-resolve-end';
  2288. mark && mark(startTag);
  2289. }
  2290. if ((format = resolveValue(message, key)) === null) {
  2291. // if null, resolve with object key path
  2292. format = message[key]; // eslint-disable-line @typescript-eslint/no-explicit-any
  2293. }
  2294. // for vue-devtools timeline event
  2295. if (inBrowser) {
  2296. const end = window.performance.now();
  2297. const emitter = context.__v_emitter;
  2298. if (emitter && start && format) {
  2299. emitter.emit("message-resolve" /* MESSAGE_RESOLVE */, {
  2300. type: "message-resolve" /* MESSAGE_RESOLVE */,
  2301. key,
  2302. message: format,
  2303. time: end - start,
  2304. groupId: `${type}:${key}`
  2305. });
  2306. }
  2307. if (startTag && endTag && mark && measure) {
  2308. mark(endTag);
  2309. measure('intlify message resolve', startTag, endTag);
  2310. }
  2311. }
  2312. if (isString(format) || isFunction(format))
  2313. break;
  2314. const missingRet = handleMissing(context, key, targetLocale, missingWarn, type);
  2315. if (missingRet !== key) {
  2316. format = missingRet;
  2317. }
  2318. from = to;
  2319. }
  2320. return [format, targetLocale, message];
  2321. }
  2322. function compileMessageFormat(context, key, targetLocale, format, cacheBaseKey, errorDetector) {
  2323. const { messageCompiler, warnHtmlMessage } = context;
  2324. if (isMessageFunction(format)) {
  2325. const msg = format;
  2326. msg.locale = msg.locale || targetLocale;
  2327. msg.key = msg.key || key;
  2328. return msg;
  2329. }
  2330. // for vue-devtools timeline event
  2331. let start = null;
  2332. let startTag;
  2333. let endTag;
  2334. if (inBrowser) {
  2335. start = window.performance.now();
  2336. startTag = 'intlify-message-compilation-start';
  2337. endTag = 'intlify-message-compilation-end';
  2338. mark && mark(startTag);
  2339. }
  2340. const msg = messageCompiler(format, getCompileOptions(context, targetLocale, cacheBaseKey, format, warnHtmlMessage, errorDetector));
  2341. // for vue-devtools timeline event
  2342. if (inBrowser) {
  2343. const end = window.performance.now();
  2344. const emitter = context.__v_emitter;
  2345. if (emitter && start) {
  2346. emitter.emit("message-compilation" /* MESSAGE_COMPILATION */, {
  2347. type: "message-compilation" /* MESSAGE_COMPILATION */,
  2348. message: format,
  2349. time: end - start,
  2350. groupId: `${'translate'}:${key}`
  2351. });
  2352. }
  2353. if (startTag && endTag && mark && measure) {
  2354. mark(endTag);
  2355. measure('intlify message compilation', startTag, endTag);
  2356. }
  2357. }
  2358. msg.locale = targetLocale;
  2359. msg.key = key;
  2360. msg.source = format;
  2361. return msg;
  2362. }
  2363. function evaluateMessage(context, msg, msgCtx) {
  2364. // for vue-devtools timeline event
  2365. let start = null;
  2366. let startTag;
  2367. let endTag;
  2368. if (inBrowser) {
  2369. start = window.performance.now();
  2370. startTag = 'intlify-message-evaluation-start';
  2371. endTag = 'intlify-message-evaluation-end';
  2372. mark && mark(startTag);
  2373. }
  2374. const messaged = msg(msgCtx);
  2375. // for vue-devtools timeline event
  2376. if (inBrowser) {
  2377. const end = window.performance.now();
  2378. const emitter = context.__v_emitter;
  2379. if (emitter && start) {
  2380. emitter.emit("message-evaluation" /* MESSAGE_EVALUATION */, {
  2381. type: "message-evaluation" /* MESSAGE_EVALUATION */,
  2382. value: messaged,
  2383. time: end - start,
  2384. groupId: `${'translate'}:${msg.key}`
  2385. });
  2386. }
  2387. if (startTag && endTag && mark && measure) {
  2388. mark(endTag);
  2389. measure('intlify message evaluation', startTag, endTag);
  2390. }
  2391. }
  2392. return messaged;
  2393. }
  2394. /** @internal */
  2395. function parseTranslateArgs(...args) {
  2396. const [arg1, arg2, arg3] = args;
  2397. const options = {};
  2398. if (!isString(arg1) && !isNumber(arg1) && !isMessageFunction(arg1)) {
  2399. throw createCoreError(14 /* INVALID_ARGUMENT */);
  2400. }
  2401. // prettier-ignore
  2402. const key = isNumber(arg1)
  2403. ? String(arg1)
  2404. : isMessageFunction(arg1)
  2405. ? arg1
  2406. : arg1;
  2407. if (isNumber(arg2)) {
  2408. options.plural = arg2;
  2409. }
  2410. else if (isString(arg2)) {
  2411. options.default = arg2;
  2412. }
  2413. else if (isPlainObject(arg2) && !isEmptyObject(arg2)) {
  2414. options.named = arg2;
  2415. }
  2416. else if (isArray(arg2)) {
  2417. options.list = arg2;
  2418. }
  2419. if (isNumber(arg3)) {
  2420. options.plural = arg3;
  2421. }
  2422. else if (isString(arg3)) {
  2423. options.default = arg3;
  2424. }
  2425. else if (isPlainObject(arg3)) {
  2426. assign(options, arg3);
  2427. }
  2428. return [key, options];
  2429. }
  2430. function getCompileOptions(context, locale, key, source, warnHtmlMessage, errorDetector) {
  2431. return {
  2432. warnHtmlMessage,
  2433. onError: (err) => {
  2434. errorDetector && errorDetector(err);
  2435. {
  2436. const message = `Message compilation error: ${err.message}`;
  2437. const codeFrame = err.location &&
  2438. generateCodeFrame(source, err.location.start.offset, err.location.end.offset);
  2439. const emitter = context
  2440. .__v_emitter;
  2441. if (emitter) {
  2442. emitter.emit("compile-error" /* COMPILE_ERROR */, {
  2443. message: source,
  2444. error: err.message,
  2445. start: err.location && err.location.start.offset,
  2446. end: err.location && err.location.end.offset,
  2447. groupId: `${'translate'}:${key}`
  2448. });
  2449. }
  2450. console.error(codeFrame ? `${message}\n${codeFrame}` : message);
  2451. }
  2452. },
  2453. onCacheKey: (source) => generateFormatCacheKey(locale, key, source)
  2454. };
  2455. }
  2456. function getMessageContextOptions(context, locale, message, options) {
  2457. const { modifiers, pluralRules } = context;
  2458. const resolveMessage = (key) => {
  2459. const val = resolveValue(message, key);
  2460. if (isString(val)) {
  2461. let occurred = false;
  2462. const errorDetector = () => {
  2463. occurred = true;
  2464. };
  2465. const msg = compileMessageFormat(context, key, locale, val, key, errorDetector);
  2466. return !occurred
  2467. ? msg
  2468. : NOOP_MESSAGE_FUNCTION;
  2469. }
  2470. else if (isMessageFunction(val)) {
  2471. return val;
  2472. }
  2473. else {
  2474. // TODO: should be implemented warning message
  2475. return NOOP_MESSAGE_FUNCTION;
  2476. }
  2477. };
  2478. const ctxOptions = {
  2479. locale,
  2480. modifiers,
  2481. pluralRules,
  2482. messages: resolveMessage
  2483. };
  2484. if (context.processor) {
  2485. ctxOptions.processor = context.processor;
  2486. }
  2487. if (options.list) {
  2488. ctxOptions.list = options.list;
  2489. }
  2490. if (options.named) {
  2491. ctxOptions.named = options.named;
  2492. }
  2493. if (isNumber(options.plural)) {
  2494. ctxOptions.pluralIndex = options.plural;
  2495. }
  2496. return ctxOptions;
  2497. }
  2498. const intlDefined = typeof Intl !== 'undefined';
  2499. const Availabilities = {
  2500. dateTimeFormat: intlDefined && typeof Intl.DateTimeFormat !== 'undefined',
  2501. numberFormat: intlDefined && typeof Intl.NumberFormat !== 'undefined'
  2502. };
  2503. // implementation of `datetime` function
  2504. function datetime(context, ...args) {
  2505. const { datetimeFormats, unresolving, fallbackLocale, onWarn } = context;
  2506. const { __datetimeFormatters } = context;
  2507. if (!Availabilities.dateTimeFormat) {
  2508. onWarn(getWarnMessage(4 /* CANNOT_FORMAT_DATE */));
  2509. return MISSING_RESOLVE_VALUE;
  2510. }
  2511. const [key, value, options, overrides] = parseDateTimeArgs(...args);
  2512. const missingWarn = isBoolean(options.missingWarn)
  2513. ? options.missingWarn
  2514. : context.missingWarn;
  2515. const fallbackWarn = isBoolean(options.fallbackWarn)
  2516. ? options.fallbackWarn
  2517. : context.fallbackWarn;
  2518. const part = !!options.part;
  2519. const locale = isString(options.locale) ? options.locale : context.locale;
  2520. const locales = getLocaleChain(context, fallbackLocale, locale);
  2521. if (!isString(key) || key === '') {
  2522. return new Intl.DateTimeFormat(locale).format(value);
  2523. }
  2524. // resolve format
  2525. let datetimeFormat = {};
  2526. let targetLocale;
  2527. let format = null;
  2528. let from = locale;
  2529. let to = null;
  2530. const type = 'datetime format';
  2531. for (let i = 0; i < locales.length; i++) {
  2532. targetLocale = to = locales[i];
  2533. if (locale !== targetLocale &&
  2534. isTranslateFallbackWarn(fallbackWarn, key)) {
  2535. onWarn(getWarnMessage(5 /* FALLBACK_TO_DATE_FORMAT */, {
  2536. key,
  2537. target: targetLocale
  2538. }));
  2539. }
  2540. // for vue-devtools timeline event
  2541. if (locale !== targetLocale) {
  2542. const emitter = context.__v_emitter;
  2543. if (emitter) {
  2544. emitter.emit("fallback" /* FALBACK */, {
  2545. type,
  2546. key,
  2547. from,
  2548. to,
  2549. groupId: `${type}:${key}`
  2550. });
  2551. }
  2552. }
  2553. datetimeFormat =
  2554. datetimeFormats[targetLocale] || {};
  2555. format = datetimeFormat[key];
  2556. if (isPlainObject(format))
  2557. break;
  2558. handleMissing(context, key, targetLocale, missingWarn, type);
  2559. from = to;
  2560. }
  2561. // checking format and target locale
  2562. if (!isPlainObject(format) || !isString(targetLocale)) {
  2563. return unresolving ? NOT_REOSLVED : key;
  2564. }
  2565. let id = `${targetLocale}__${key}`;
  2566. if (!isEmptyObject(overrides)) {
  2567. id = `${id}__${JSON.stringify(overrides)}`;
  2568. }
  2569. let formatter = __datetimeFormatters.get(id);
  2570. if (!formatter) {
  2571. formatter = new Intl.DateTimeFormat(targetLocale, assign({}, format, overrides));
  2572. __datetimeFormatters.set(id, formatter);
  2573. }
  2574. return !part ? formatter.format(value) : formatter.formatToParts(value);
  2575. }
  2576. /** @internal */
  2577. function parseDateTimeArgs(...args) {
  2578. const [arg1, arg2, arg3, arg4] = args;
  2579. let options = {};
  2580. let overrides = {};
  2581. let value;
  2582. if (isString(arg1)) {
  2583. // Only allow ISO strings - other date formats are often supported,
  2584. // but may cause different results in different browsers.
  2585. if (!/\d{4}-\d{2}-\d{2}(T.*)?/.test(arg1)) {
  2586. throw createCoreError(16 /* INVALID_ISO_DATE_ARGUMENT */);
  2587. }
  2588. value = new Date(arg1);
  2589. try {
  2590. // This will fail if the date is not valid
  2591. value.toISOString();
  2592. }
  2593. catch (e) {
  2594. throw createCoreError(16 /* INVALID_ISO_DATE_ARGUMENT */);
  2595. }
  2596. }
  2597. else if (isDate(arg1)) {
  2598. if (isNaN(arg1.getTime())) {
  2599. throw createCoreError(15 /* INVALID_DATE_ARGUMENT */);
  2600. }
  2601. value = arg1;
  2602. }
  2603. else if (isNumber(arg1)) {
  2604. value = arg1;
  2605. }
  2606. else {
  2607. throw createCoreError(14 /* INVALID_ARGUMENT */);
  2608. }
  2609. if (isString(arg2)) {
  2610. options.key = arg2;
  2611. }
  2612. else if (isPlainObject(arg2)) {
  2613. options = arg2;
  2614. }
  2615. if (isString(arg3)) {
  2616. options.locale = arg3;
  2617. }
  2618. else if (isPlainObject(arg3)) {
  2619. overrides = arg3;
  2620. }
  2621. if (isPlainObject(arg4)) {
  2622. overrides = arg4;
  2623. }
  2624. return [options.key || '', value, options, overrides];
  2625. }
  2626. /** @internal */
  2627. function clearDateTimeFormat(ctx, locale, format) {
  2628. const context = ctx;
  2629. for (const key in format) {
  2630. const id = `${locale}__${key}`;
  2631. if (!context.__datetimeFormatters.has(id)) {
  2632. continue;
  2633. }
  2634. context.__datetimeFormatters.delete(id);
  2635. }
  2636. }
  2637. // implementation of `number` function
  2638. function number(context, ...args) {
  2639. const { numberFormats, unresolving, fallbackLocale, onWarn } = context;
  2640. const { __numberFormatters } = context;
  2641. if (!Availabilities.numberFormat) {
  2642. onWarn(getWarnMessage(2 /* CANNOT_FORMAT_NUMBER */));
  2643. return MISSING_RESOLVE_VALUE;
  2644. }
  2645. const [key, value, options, overrides] = parseNumberArgs(...args);
  2646. const missingWarn = isBoolean(options.missingWarn)
  2647. ? options.missingWarn
  2648. : context.missingWarn;
  2649. const fallbackWarn = isBoolean(options.fallbackWarn)
  2650. ? options.fallbackWarn
  2651. : context.fallbackWarn;
  2652. const part = !!options.part;
  2653. const locale = isString(options.locale) ? options.locale : context.locale;
  2654. const locales = getLocaleChain(context, fallbackLocale, locale);
  2655. if (!isString(key) || key === '') {
  2656. return new Intl.NumberFormat(locale).format(value);
  2657. }
  2658. // resolve format
  2659. let numberFormat = {};
  2660. let targetLocale;
  2661. let format = null;
  2662. let from = locale;
  2663. let to = null;
  2664. const type = 'number format';
  2665. for (let i = 0; i < locales.length; i++) {
  2666. targetLocale = to = locales[i];
  2667. if (locale !== targetLocale &&
  2668. isTranslateFallbackWarn(fallbackWarn, key)) {
  2669. onWarn(getWarnMessage(3 /* FALLBACK_TO_NUMBER_FORMAT */, {
  2670. key,
  2671. target: targetLocale
  2672. }));
  2673. }
  2674. // for vue-devtools timeline event
  2675. if (locale !== targetLocale) {
  2676. const emitter = context.__v_emitter;
  2677. if (emitter) {
  2678. emitter.emit("fallback" /* FALBACK */, {
  2679. type,
  2680. key,
  2681. from,
  2682. to,
  2683. groupId: `${type}:${key}`
  2684. });
  2685. }
  2686. }
  2687. numberFormat =
  2688. numberFormats[targetLocale] || {};
  2689. format = numberFormat[key];
  2690. if (isPlainObject(format))
  2691. break;
  2692. handleMissing(context, key, targetLocale, missingWarn, type);
  2693. from = to;
  2694. }
  2695. // checking format and target locale
  2696. if (!isPlainObject(format) || !isString(targetLocale)) {
  2697. return unresolving ? NOT_REOSLVED : key;
  2698. }
  2699. let id = `${targetLocale}__${key}`;
  2700. if (!isEmptyObject(overrides)) {
  2701. id = `${id}__${JSON.stringify(overrides)}`;
  2702. }
  2703. let formatter = __numberFormatters.get(id);
  2704. if (!formatter) {
  2705. formatter = new Intl.NumberFormat(targetLocale, assign({}, format, overrides));
  2706. __numberFormatters.set(id, formatter);
  2707. }
  2708. return !part ? formatter.format(value) : formatter.formatToParts(value);
  2709. }
  2710. /** @internal */
  2711. function parseNumberArgs(...args) {
  2712. const [arg1, arg2, arg3, arg4] = args;
  2713. let options = {};
  2714. let overrides = {};
  2715. if (!isNumber(arg1)) {
  2716. throw createCoreError(14 /* INVALID_ARGUMENT */);
  2717. }
  2718. const value = arg1;
  2719. if (isString(arg2)) {
  2720. options.key = arg2;
  2721. }
  2722. else if (isPlainObject(arg2)) {
  2723. options = arg2;
  2724. }
  2725. if (isString(arg3)) {
  2726. options.locale = arg3;
  2727. }
  2728. else if (isPlainObject(arg3)) {
  2729. overrides = arg3;
  2730. }
  2731. if (isPlainObject(arg4)) {
  2732. overrides = arg4;
  2733. }
  2734. return [options.key || '', value, options, overrides];
  2735. }
  2736. /** @internal */
  2737. function clearNumberFormat(ctx, locale, format) {
  2738. const context = ctx;
  2739. for (const key in format) {
  2740. const id = `${locale}__${key}`;
  2741. if (!context.__numberFormatters.has(id)) {
  2742. continue;
  2743. }
  2744. context.__numberFormatters.delete(id);
  2745. }
  2746. }
  2747. exports.DEFAULT_MESSAGE_DATA_TYPE = DEFAULT_MESSAGE_DATA_TYPE;
  2748. exports.MISSING_RESOLVE_VALUE = MISSING_RESOLVE_VALUE;
  2749. exports.NOT_REOSLVED = NOT_REOSLVED;
  2750. exports.VERSION = VERSION;
  2751. exports.clearCompileCache = clearCompileCache;
  2752. exports.clearDateTimeFormat = clearDateTimeFormat;
  2753. exports.clearNumberFormat = clearNumberFormat;
  2754. exports.compileToFunction = compileToFunction;
  2755. exports.createCompileError = createCompileError;
  2756. exports.createCoreContext = createCoreContext;
  2757. exports.createCoreError = createCoreError;
  2758. exports.createMessageContext = createMessageContext;
  2759. exports.datetime = datetime;
  2760. exports.getAdditionalMeta = getAdditionalMeta;
  2761. exports.getDevToolsHook = getDevToolsHook;
  2762. exports.getLocaleChain = getLocaleChain;
  2763. exports.getWarnMessage = getWarnMessage;
  2764. exports.handleFlatJson = handleFlatJson;
  2765. exports.handleMissing = handleMissing;
  2766. exports.initI18nDevTools = initI18nDevTools;
  2767. exports.isMessageFunction = isMessageFunction;
  2768. exports.isTranslateFallbackWarn = isTranslateFallbackWarn;
  2769. exports.isTranslateMissingWarn = isTranslateMissingWarn;
  2770. exports.number = number;
  2771. exports.parse = parse;
  2772. exports.parseDateTimeArgs = parseDateTimeArgs;
  2773. exports.parseNumberArgs = parseNumberArgs;
  2774. exports.parseTranslateArgs = parseTranslateArgs;
  2775. exports.registerMessageCompiler = registerMessageCompiler;
  2776. exports.resolveValue = resolveValue;
  2777. exports.setAdditionalMeta = setAdditionalMeta;
  2778. exports.setDevToolsHook = setDevToolsHook;
  2779. exports.translate = translate;
  2780. exports.translateDevTools = translateDevTools;
  2781. exports.updateFallbackLocale = updateFallbackLocale;
  2782. Object.defineProperty(exports, '__esModule', { value: true });
  2783. return exports;
  2784. }({}));