@vocab/core 1.7.4 → 1.7.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,23 @@
1
- const require_icu_handler = require('./icu-handler-CuHzcwEH.cjs');
1
+ const require_rolldown_runtime = require('./rolldown-runtime-y5NzCiFd.cjs');
2
+ let intl_messageformat = require("intl-messageformat");
2
3
 
3
- exports.getParsedICUMessages = require_icu_handler.getParsedICUMessages;
4
+ //#region src/icu-handler.ts
5
+ const moduleCache = /* @__PURE__ */ new WeakMap();
6
+ const getParsedICUMessages = (m, locale) => {
7
+ const moduleCachedResult = moduleCache.get(m);
8
+ if (moduleCachedResult && moduleCachedResult[locale]) return moduleCachedResult[locale];
9
+ const parsedICUMessages = {};
10
+ for (const translation of Object.keys(m)) {
11
+ const intlMessageFormat = new intl_messageformat.IntlMessageFormat(m[translation], locale);
12
+ parsedICUMessages[translation] = { format: (params) => intlMessageFormat.format(params) };
13
+ }
14
+ moduleCache.set(m, {
15
+ ...moduleCachedResult,
16
+ [locale]: parsedICUMessages
17
+ });
18
+ return parsedICUMessages;
19
+ };
20
+
21
+ //#endregion
22
+ exports.getParsedICUMessages = getParsedICUMessages;
23
+ //# sourceMappingURL=icu-handler.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icu-handler.cjs","names":["parsedICUMessages: ParsedICUMessages<any>","IntlMessageFormat"],"sources":["../src/icu-handler.ts"],"sourcesContent":["import type { ParsedICUMessages, TranslationMessagesByKey } from './types';\nimport { IntlMessageFormat } from 'intl-messageformat';\n\ntype ICUMessagesByLocale = Record<string, ParsedICUMessages<any>>;\n\nconst moduleCache = new WeakMap<\n TranslationMessagesByKey,\n ICUMessagesByLocale\n>();\n\nexport const getParsedICUMessages = (\n m: TranslationMessagesByKey,\n locale: string,\n): ParsedICUMessages<any> => {\n const moduleCachedResult = moduleCache.get(m);\n\n if (moduleCachedResult && moduleCachedResult[locale]) {\n return moduleCachedResult[locale];\n }\n\n const parsedICUMessages: ParsedICUMessages<any> = {};\n\n for (const translation of Object.keys(m)) {\n const intlMessageFormat = new IntlMessageFormat(m[translation], locale);\n parsedICUMessages[translation] = {\n format: (params: any) => intlMessageFormat.format(params),\n };\n }\n\n moduleCache.set(m, { ...moduleCachedResult, [locale]: parsedICUMessages });\n\n return parsedICUMessages;\n};\n"],"mappings":";;;;AAKA,MAAM,8BAAc,IAAI,SAGrB;AAEH,MAAa,wBACX,GACA,WAC2B;CAC3B,MAAM,qBAAqB,YAAY,IAAI,EAAE;AAE7C,KAAI,sBAAsB,mBAAmB,QAC3C,QAAO,mBAAmB;CAG5B,MAAMA,oBAA4C,EAAE;AAEpD,MAAK,MAAM,eAAe,OAAO,KAAK,EAAE,EAAE;EACxC,MAAM,oBAAoB,IAAIC,qCAAkB,EAAE,cAAc,OAAO;AACvE,oBAAkB,eAAe,EAC/B,SAAS,WAAgB,kBAAkB,OAAO,OAAO,EAC1D;;AAGH,aAAY,IAAI,GAAG;EAAE,GAAG;GAAqB,SAAS;EAAmB,CAAC;AAE1E,QAAO"}
@@ -1,4 +1,4 @@
1
- import { l as ParsedICUMessages, y as TranslationMessagesByKey } from "./types-DpryIirw.mjs";
1
+ import { l as ParsedICUMessages, y as TranslationMessagesByKey } from "./types-oikDld6a.mjs";
2
2
 
3
3
  //#region src/icu-handler.d.ts
4
4
  declare const getParsedICUMessages: (m: TranslationMessagesByKey, locale: string) => ParsedICUMessages<any>;
@@ -1,3 +1,22 @@
1
- import { t as getParsedICUMessages } from "./icu-handler-DpDWxKGr.mjs";
1
+ import { IntlMessageFormat } from "intl-messageformat";
2
2
 
3
- export { getParsedICUMessages };
3
+ //#region src/icu-handler.ts
4
+ const moduleCache = /* @__PURE__ */ new WeakMap();
5
+ const getParsedICUMessages = (m, locale) => {
6
+ const moduleCachedResult = moduleCache.get(m);
7
+ if (moduleCachedResult && moduleCachedResult[locale]) return moduleCachedResult[locale];
8
+ const parsedICUMessages = {};
9
+ for (const translation of Object.keys(m)) {
10
+ const intlMessageFormat = new IntlMessageFormat(m[translation], locale);
11
+ parsedICUMessages[translation] = { format: (params) => intlMessageFormat.format(params) };
12
+ }
13
+ moduleCache.set(m, {
14
+ ...moduleCachedResult,
15
+ [locale]: parsedICUMessages
16
+ });
17
+ return parsedICUMessages;
18
+ };
19
+
20
+ //#endregion
21
+ export { getParsedICUMessages };
22
+ //# sourceMappingURL=icu-handler.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"icu-handler.mjs","names":["parsedICUMessages: ParsedICUMessages<any>"],"sources":["../src/icu-handler.ts"],"sourcesContent":["import type { ParsedICUMessages, TranslationMessagesByKey } from './types';\nimport { IntlMessageFormat } from 'intl-messageformat';\n\ntype ICUMessagesByLocale = Record<string, ParsedICUMessages<any>>;\n\nconst moduleCache = new WeakMap<\n TranslationMessagesByKey,\n ICUMessagesByLocale\n>();\n\nexport const getParsedICUMessages = (\n m: TranslationMessagesByKey,\n locale: string,\n): ParsedICUMessages<any> => {\n const moduleCachedResult = moduleCache.get(m);\n\n if (moduleCachedResult && moduleCachedResult[locale]) {\n return moduleCachedResult[locale];\n }\n\n const parsedICUMessages: ParsedICUMessages<any> = {};\n\n for (const translation of Object.keys(m)) {\n const intlMessageFormat = new IntlMessageFormat(m[translation], locale);\n parsedICUMessages[translation] = {\n format: (params: any) => intlMessageFormat.format(params),\n };\n }\n\n moduleCache.set(m, { ...moduleCachedResult, [locale]: parsedICUMessages });\n\n return parsedICUMessages;\n};\n"],"mappings":";;;AAKA,MAAM,8BAAc,IAAI,SAGrB;AAEH,MAAa,wBACX,GACA,WAC2B;CAC3B,MAAM,qBAAqB,YAAY,IAAI,EAAE;AAE7C,KAAI,sBAAsB,mBAAmB,QAC3C,QAAO,mBAAmB;CAG5B,MAAMA,oBAA4C,EAAE;AAEpD,MAAK,MAAM,eAAe,OAAO,KAAK,EAAE,EAAE;EACxC,MAAM,oBAAoB,IAAI,kBAAkB,EAAE,cAAc,OAAO;AACvE,oBAAkB,eAAe,EAC/B,SAAS,WAAgB,kBAAkB,OAAO,OAAO,EAC1D;;AAGH,aAAY,IAAI,GAAG;EAAE,GAAG;GAAqB,SAAS;EAAmB,CAAC;AAE1E,QAAO"}
package/dist/index.cjs CHANGED
@@ -4,7 +4,7 @@ let path = require("path");
4
4
  path = require_rolldown_runtime.__toESM(path);
5
5
  let picomatch = require("picomatch");
6
6
  picomatch = require_rolldown_runtime.__toESM(picomatch);
7
- let __formatjs_icu_messageformat_parser = require("@formatjs/icu-messageformat-parser");
7
+ let _formatjs_icu_messageformat_parser = require("@formatjs/icu-messageformat-parser");
8
8
  let prettier = require("prettier");
9
9
  prettier = require_rolldown_runtime.__toESM(prettier);
10
10
  let picocolors = require("picocolors");
@@ -13,7 +13,7 @@ let debug = require("debug");
13
13
  debug = require_rolldown_runtime.__toESM(debug);
14
14
  let tinyglobby = require("tinyglobby");
15
15
  let intl_messageformat = require("intl-messageformat");
16
- let __formatjs_icu_messageformat_parser_printer_js = require("@formatjs/icu-messageformat-parser/printer.js");
16
+ let _formatjs_icu_messageformat_parser_printer_js = require("@formatjs/icu-messageformat-parser/printer.js");
17
17
  let find_up = require("find-up");
18
18
  find_up = require_rolldown_runtime.__toESM(find_up);
19
19
  let fastest_validator = require("fastest-validator");
@@ -96,7 +96,7 @@ function generateLanguageFromTranslations({ baseTranslations, generator }) {
96
96
  for (const translationKey of translationKeys) {
97
97
  const translation = baseTranslations[translationKey];
98
98
  let transformedMessage = translation.message;
99
- if (generator.transformElement) transformedMessage = (0, __formatjs_icu_messageformat_parser_printer_js.printAST)(new intl_messageformat.IntlMessageFormat(translation.message).getAst().map(transformMessageFormatElement(generator.transformElement)));
99
+ if (generator.transformElement) transformedMessage = (0, _formatjs_icu_messageformat_parser_printer_js.printAST)(new intl_messageformat.IntlMessageFormat(translation.message).getAst().map(transformMessageFormatElement(generator.transformElement)));
100
100
  if (generator.transformMessage) transformedMessage = generator.transformMessage(transformedMessage);
101
101
  generatedTranslations[translationKey] = { message: transformedMessage };
102
102
  }
@@ -106,15 +106,15 @@ function transformMessageFormatElement(transformElement) {
106
106
  return (messageFormatElement) => {
107
107
  const transformedMessageFormatElement = { ...messageFormatElement };
108
108
  switch (transformedMessageFormatElement.type) {
109
- case __formatjs_icu_messageformat_parser.TYPE.literal:
109
+ case _formatjs_icu_messageformat_parser.TYPE.literal:
110
110
  transformedMessageFormatElement.value = transformElement(transformedMessageFormatElement.value);
111
111
  break;
112
- case __formatjs_icu_messageformat_parser.TYPE.select:
113
- case __formatjs_icu_messageformat_parser.TYPE.plural:
112
+ case _formatjs_icu_messageformat_parser.TYPE.select:
113
+ case _formatjs_icu_messageformat_parser.TYPE.plural:
114
114
  const transformedOptions = { ...transformedMessageFormatElement.options };
115
115
  for (const key of Object.keys(transformedOptions)) transformedOptions[key].value = transformedOptions[key].value.map(transformMessageFormatElement(transformElement));
116
116
  break;
117
- case __formatjs_icu_messageformat_parser.TYPE.tag:
117
+ case _formatjs_icu_messageformat_parser.TYPE.tag:
118
118
  transformedMessageFormatElement.children = transformedMessageFormatElement.children.map(transformMessageFormatElement(transformElement));
119
119
  break;
120
120
  default: break;
@@ -279,6 +279,7 @@ async function loadAllTranslations({ fallbacks, includeNodeModules, withTags },
279
279
  const { projectRoot, ignore = [] } = config;
280
280
  const translationFiles = await (0, tinyglobby.glob)(getDevTranslationFileGlob(config), {
281
281
  ignore: includeNodeModules ? ignore : [...ignore, "**/node_modules/**"],
282
+ dot: true,
282
283
  absolute: true,
283
284
  cwd: projectRoot,
284
285
  expandDirectories: false
@@ -314,17 +315,17 @@ async function loadAllTranslations({ fallbacks, includeNodeModules, withTags },
314
315
  //#region src/compile.ts
315
316
  function extractHasTags(ast) {
316
317
  return ast.some((element) => {
317
- if ((0, __formatjs_icu_messageformat_parser.isSelectElement)(element) || (0, __formatjs_icu_messageformat_parser.isPluralElement)(element)) return Object.values(element.options).map((o) => o.value).some((child) => extractHasTags(child));
318
- return (0, __formatjs_icu_messageformat_parser.isTagElement)(element);
318
+ if ((0, _formatjs_icu_messageformat_parser.isSelectElement)(element) || (0, _formatjs_icu_messageformat_parser.isPluralElement)(element)) return Object.values(element.options).map((o) => o.value).some((child) => extractHasTags(child));
319
+ return (0, _formatjs_icu_messageformat_parser.isTagElement)(element);
319
320
  });
320
321
  }
321
322
  function extractParamTypes(ast, currentParams) {
322
323
  let params = { ...currentParams };
323
324
  let vocabTypesImports = /* @__PURE__ */ new Set();
324
- for (const element of ast) if ((0, __formatjs_icu_messageformat_parser.isArgumentElement)(element)) {
325
+ for (const element of ast) if ((0, _formatjs_icu_messageformat_parser.isArgumentElement)(element)) {
325
326
  if (!(element.value in params)) params[element.value] = "string";
326
- } else if ((0, __formatjs_icu_messageformat_parser.isNumberElement)(element)) params[element.value] = "number";
327
- else if ((0, __formatjs_icu_messageformat_parser.isPluralElement)(element)) {
327
+ } else if ((0, _formatjs_icu_messageformat_parser.isNumberElement)(element)) params[element.value] = "number";
328
+ else if ((0, _formatjs_icu_messageformat_parser.isPluralElement)(element)) {
328
329
  params[element.value] = "number";
329
330
  const children = Object.values(element.options).map((o) => o.value);
330
331
  for (const child of children) {
@@ -332,14 +333,14 @@ function extractParamTypes(ast, currentParams) {
332
333
  vocabTypesImports = new Set([...vocabTypesImports, ...subImports]);
333
334
  params = newParams;
334
335
  }
335
- } else if ((0, __formatjs_icu_messageformat_parser.isDateElement)(element) || (0, __formatjs_icu_messageformat_parser.isTimeElement)(element)) params[element.value] = "Date | number";
336
- else if ((0, __formatjs_icu_messageformat_parser.isTagElement)(element)) {
336
+ } else if ((0, _formatjs_icu_messageformat_parser.isDateElement)(element) || (0, _formatjs_icu_messageformat_parser.isTimeElement)(element)) params[element.value] = "Date | number";
337
+ else if ((0, _formatjs_icu_messageformat_parser.isTagElement)(element)) {
337
338
  params[element.value] = "FormatXMLElementFn<T>";
338
339
  vocabTypesImports.add("FormatXMLElementFn");
339
340
  const [newParams, subImports] = extractParamTypes(element.children, params);
340
341
  vocabTypesImports = new Set([...vocabTypesImports, ...subImports]);
341
342
  params = newParams;
342
- } else if ((0, __formatjs_icu_messageformat_parser.isSelectElement)(element)) {
343
+ } else if ((0, _formatjs_icu_messageformat_parser.isSelectElement)(element)) {
343
344
  const nonOtherOptionsUnion = Object.keys(element.options).filter((o) => o !== "other").map((o) => `'${o}'`).join(" | ");
344
345
  params[element.value] = `StringWithSuggestions<${nonOtherOptionsUnion}>`;
345
346
  vocabTypesImports.add("StringWithSuggestions");
@@ -359,7 +360,7 @@ function serialiseObjectToType(v) {
359
360
  }
360
361
  const serializeTypeImports = (imports, moduleName) => {
361
362
  if (imports.size === 0) return "";
362
- return `import type { ${Array.from(imports).join(", ")} } from '${moduleName}';`;
363
+ return `import type { ${Array.from(imports).sort().join(", ")} } from '${moduleName}';`;
363
364
  };
364
365
  function serialiseTranslationRuntime(value, imports, loadedTranslation) {
365
366
  trace("Serialising translations:", loadedTranslation);
@@ -379,9 +380,8 @@ function serialiseTranslationRuntime(value, imports, loadedTranslation) {
379
380
  // This file is automatically generated by Vocab.
380
381
  // To make changes update translation.json files directly.
381
382
 
382
- ${serializeTypeImports(imports, "@vocab/core")}
383
+ ${serializeTypeImports(new Set([...imports, "TranslationFile"]), "@vocab/core")}
383
384
  import { createLanguage, createTranslationFile } from '@vocab/core/runtime';
384
- import type { TranslationFile } from '@vocab/core';
385
385
 
386
386
  const translations: TranslationFile<
387
387
  ${languagesUnionAsString},
@@ -404,7 +404,7 @@ async function generateRuntime(loadedTranslation) {
404
404
  const messages = /* @__PURE__ */ new Set();
405
405
  let hasTags = false;
406
406
  for (const translatedLanguage of Object.values(loadedLanguages)) if (translatedLanguage[key]) {
407
- const ast = (0, __formatjs_icu_messageformat_parser.parse)(translatedLanguage[key].message);
407
+ const ast = (0, _formatjs_icu_messageformat_parser.parse)(translatedLanguage[key].message);
408
408
  hasTags = hasTags || extractHasTags(ast);
409
409
  const [parsedParams, vocabTypesImports] = extractParamTypes(ast, params);
410
410
  imports = new Set([...imports, ...vocabTypesImports]);
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["newObj: any","generatedTranslations: TranslationsByKey<string>","IntlMessageFormat","TYPE","transformedOptions: Record<string, PluralOrSelectOption>","newLanguage: TranslationsByKey","fallbackLanguageOrder: string[]","pc","validKeys: TranslationsByKey","languageSet: Record<\n string,\n Record<string, { message: string; description?: string | undefined }>\n >","namespace: string","loadedTranslations: LoadedTranslation[]","translationsType: any","params: ICUParams","pm","result: Record<LanguageName, string[]>","pc","pc","Validator","foundLanguages: string[]","foundGeneratedLanguages: string[]","findUp"],"sources":["../src/logger.ts","../src/utils.ts","../src/generate-language.ts","../src/load-translations.ts","../src/compile.ts","../src/validate/index.ts","../src/ValidationError.ts","../src/config.ts"],"sourcesContent":["import pc from 'picocolors';\nimport debug from 'debug';\n\nexport const trace = debug(`vocab:core`);\n\nexport const log = (...params: unknown[]) => {\n // eslint-disable-next-line no-console\n console.log(pc.yellow('Vocab'), ...params);\n};\n","import path from 'path';\n\nimport type {\n LanguageName,\n LanguageTarget,\n TranslationsByKey,\n TranslationMessagesByKey,\n UserConfig,\n} from './types';\nimport { trace } from './logger';\n\nexport const defaultTranslationDirSuffix = '.vocab';\nexport const devTranslationFileName = 'translations.json';\n\nexport type Fallback = 'none' | 'valid' | 'all';\n\nconst globAnyPathWithOptionalPrefix = '**/?(*)';\n\nexport const compiledVocabFileFilter = /\\.vocab[\\\\/]index\\.(?:ts|js|cjs|mjs)$/;\n\nexport function isDevLanguageFile(filePath: string) {\n return (\n filePath.endsWith(`/${devTranslationFileName}`) ||\n filePath === devTranslationFileName\n );\n}\nexport function isAltLanguageFile(filePath: string) {\n return filePath.endsWith('.translations.json');\n}\nexport function isTranslationDirectory(\n filePath: string,\n {\n translationsDirectorySuffix = defaultTranslationDirSuffix,\n }: {\n translationsDirectorySuffix?: string;\n },\n) {\n return filePath.endsWith(translationsDirectorySuffix);\n}\n\nexport function getDevTranslationFileGlob({\n translationsDirectorySuffix = defaultTranslationDirSuffix,\n}: {\n translationsDirectorySuffix?: string;\n}) {\n const result = `${globAnyPathWithOptionalPrefix}${translationsDirectorySuffix}/${devTranslationFileName}`;\n\n trace('getDevTranslationFileGlob', result);\n\n return result;\n}\n\nexport function getAltTranslationFileGlob(config: UserConfig) {\n const altLanguages = getAltLanguages(config);\n const langMatch =\n altLanguages.length === 1 ? altLanguages[0] : `{${altLanguages.join(',')}}`;\n\n const { translationsDirectorySuffix = defaultTranslationDirSuffix } = config;\n const result = `${globAnyPathWithOptionalPrefix}${translationsDirectorySuffix}/${langMatch}.${devTranslationFileName}`;\n\n trace('getAltTranslationFileGlob', result);\n\n return result;\n}\n\nexport function getAltLanguages({\n devLanguage,\n languages,\n}: {\n devLanguage: LanguageName;\n languages: LanguageTarget[];\n}) {\n return languages.map((v) => v.name).filter((lang) => lang !== devLanguage);\n}\n\nexport function getDevLanguageFileFromTsFile(tsFilePath: string) {\n const directory = path.dirname(tsFilePath);\n const result = path.normalize(path.join(directory, devTranslationFileName));\n\n trace(`Returning dev language path ${result} for path ${tsFilePath}`);\n return result;\n}\n\nexport function getDevLanguageFileFromAltLanguageFile(\n altLanguageFilePath: string,\n) {\n const directory = path.dirname(altLanguageFilePath);\n const result = path.normalize(path.join(directory, devTranslationFileName));\n trace(\n `Returning dev language path ${result} for path ${altLanguageFilePath}`,\n );\n return result;\n}\n\nexport function getTSFileFromDevLanguageFile(devLanguageFilePath: string) {\n const directory = path.dirname(devLanguageFilePath);\n const result = path.normalize(path.join(directory, 'index.ts'));\n\n trace(`Returning TS path ${result} for path ${devLanguageFilePath}`);\n return result;\n}\n\nexport function getAltLanguageFilePath(\n devLanguageFilePath: string,\n language: string,\n) {\n const directory = path.dirname(devLanguageFilePath);\n const result = path.normalize(\n path.join(directory, `${language}.translations.json`),\n );\n trace(\n `Returning alt language path ${result} for path ${devLanguageFilePath}`,\n );\n return path.normalize(result);\n}\n\nexport function mapValues<Key extends string, OriginalValue, ReturnValue>(\n obj: Record<Key, OriginalValue>,\n func: (val: OriginalValue) => ReturnValue,\n): TranslationMessagesByKey<Key> {\n const newObj: any = {};\n const keys = Object.keys(obj) as Key[];\n for (const key of keys) {\n newObj[key] = func(obj[key]);\n }\n return newObj;\n}\n\nexport function getTranslationMessages<Key extends string>(\n translations: TranslationsByKey<Key>,\n): TranslationMessagesByKey<Key> {\n return mapValues(translations, (v) => v.message);\n}\n","import { IntlMessageFormat } from 'intl-messageformat';\nimport {\n type MessageFormatElement,\n type PluralOrSelectOption,\n TYPE,\n} from '@formatjs/icu-messageformat-parser';\nimport { printAST } from '@formatjs/icu-messageformat-parser/printer.js';\nimport type { MessageGenerator, TranslationsByKey } from './types';\n\nexport function generateLanguageFromTranslations({\n baseTranslations,\n generator,\n}: {\n baseTranslations: TranslationsByKey<string>;\n generator: MessageGenerator;\n}): TranslationsByKey<string> {\n if (!generator.transformElement && !generator.transformMessage) {\n return baseTranslations;\n }\n\n const translationKeys = Object.keys(baseTranslations);\n const generatedTranslations: TranslationsByKey<string> = {};\n\n for (const translationKey of translationKeys) {\n const translation = baseTranslations[translationKey];\n let transformedMessage = translation.message;\n\n if (generator.transformElement) {\n const messageAst = new IntlMessageFormat(translation.message).getAst();\n const transformedAst = messageAst.map(\n transformMessageFormatElement(generator.transformElement),\n );\n transformedMessage = printAST(transformedAst);\n }\n\n if (generator.transformMessage) {\n transformedMessage = generator.transformMessage(transformedMessage);\n }\n\n generatedTranslations[translationKey] = {\n message: transformedMessage,\n };\n }\n\n return generatedTranslations;\n}\n\nfunction transformMessageFormatElement(\n transformElement: (message: string) => string,\n): (messageFormatElement: MessageFormatElement) => MessageFormatElement {\n return (messageFormatElement: MessageFormatElement) => {\n const transformedMessageFormatElement = { ...messageFormatElement };\n\n switch (transformedMessageFormatElement.type) {\n case TYPE.literal:\n const transformedValue = transformElement(\n transformedMessageFormatElement.value,\n );\n transformedMessageFormatElement.value = transformedValue;\n break;\n\n case TYPE.select:\n case TYPE.plural:\n const transformedOptions: Record<string, PluralOrSelectOption> = {\n ...transformedMessageFormatElement.options,\n };\n\n for (const key of Object.keys(transformedOptions)) {\n transformedOptions[key].value = transformedOptions[key].value.map(\n transformMessageFormatElement(transformElement),\n );\n }\n\n break;\n\n case TYPE.tag:\n const transformedChildren =\n transformedMessageFormatElement.children.map(\n transformMessageFormatElement(transformElement),\n );\n transformedMessageFormatElement.children = transformedChildren;\n break;\n\n default:\n break;\n }\n\n return transformedMessageFormatElement;\n };\n}\n","import path from 'path';\n\nimport { glob } from 'tinyglobby';\nimport type {\n TranslationsByKey,\n UserConfig,\n LoadedTranslation,\n LanguageTarget,\n LanguageName,\n TranslationFileMetadata,\n TranslationFileContents,\n} from './types';\nimport pc from 'picocolors';\n\nimport { trace } from './logger';\nimport {\n defaultTranslationDirSuffix,\n type Fallback,\n getAltLanguageFilePath,\n getAltLanguages,\n getDevTranslationFileGlob,\n} from './utils';\nimport { generateLanguageFromTranslations } from './generate-language';\n\nexport function getUniqueKey(key: string, namespace: string) {\n return `${key}.${namespace}`;\n}\n\nexport function mergeWithDevLanguageTranslation({\n translation,\n devTranslation,\n}: {\n translation: TranslationsByKey;\n devTranslation: TranslationsByKey;\n}) {\n // Only use keys from the dev translation\n const keys = Object.keys(devTranslation);\n const newLanguage: TranslationsByKey = {};\n\n for (const key of keys) {\n if (translation[key]) {\n newLanguage[key] = {\n message: translation[key].message,\n description: devTranslation[key].description,\n };\n }\n }\n\n return newLanguage;\n}\n\nfunction getLanguageFallbacks({ languages }: { languages: LanguageTarget[] }) {\n const languageFallbackMap = new Map<LanguageName, LanguageName>();\n\n for (const lang of languages) {\n if (lang.extends) {\n languageFallbackMap.set(lang.name, lang.extends);\n }\n }\n\n return languageFallbackMap;\n}\n\nexport function getLanguageHierarchy({\n languages,\n}: {\n languages: LanguageTarget[];\n}) {\n const hierarchyMap = new Map<LanguageName, LanguageName[]>();\n const fallbacks = getLanguageFallbacks({ languages });\n\n for (const lang of languages) {\n const langHierarchy = [];\n let currLang = lang.extends;\n\n while (currLang) {\n langHierarchy.push(currLang);\n\n currLang = fallbacks.get(currLang);\n }\n\n hierarchyMap.set(lang.name, langHierarchy);\n }\n\n return hierarchyMap;\n}\n\nexport function getFallbackLanguageOrder({\n languages,\n languageName,\n devLanguage,\n fallbacks,\n}: {\n languages: LanguageTarget[];\n languageName: string;\n devLanguage: string;\n fallbacks: Fallback;\n}) {\n const languageHierarchy = getLanguageHierarchy({ languages }).get(\n languageName,\n );\n\n if (!languageHierarchy) {\n throw new Error(`Missing language hierarchy for ${languageName}`);\n }\n\n const fallbackLanguageOrder: string[] = [languageName];\n\n if (fallbacks !== 'none') {\n fallbackLanguageOrder.unshift(...languageHierarchy.reverse());\n\n if (fallbacks === 'all' && fallbackLanguageOrder[0] !== devLanguage) {\n fallbackLanguageOrder.unshift(devLanguage);\n }\n }\n\n return fallbackLanguageOrder;\n}\n\nfunction getNamespaceByFilePath(\n relativePath: string,\n { translationsDirectorySuffix = defaultTranslationDirSuffix }: UserConfig,\n) {\n let namespace = path\n .dirname(relativePath)\n .replace(/^src\\//, '')\n .replace(/\\//g, '_');\n\n if (namespace.endsWith(translationsDirectorySuffix)) {\n namespace = namespace.slice(0, -translationsDirectorySuffix.length);\n }\n\n return namespace;\n}\n\nfunction printValidationError(...params: unknown[]) {\n // eslint-disable-next-line no-console\n console.error(pc.red('Error loading translation:'), ...params);\n}\n\nfunction getTranslationsFromFile(\n translationFileContents: unknown,\n {\n isAltLanguage,\n filePath,\n withTags,\n }: { isAltLanguage: boolean; filePath: string; withTags?: boolean },\n): {\n $namespace: unknown;\n keys: TranslationsByKey;\n metadata: TranslationFileMetadata;\n} {\n if (!translationFileContents || typeof translationFileContents !== 'object') {\n throw new Error(\n `Unable to read translation file ${filePath}. Translations must be an object.`,\n );\n }\n\n const { $namespace, _meta, ...keys } =\n translationFileContents as TranslationFileContents;\n\n if (isAltLanguage && $namespace) {\n printValidationError(\n `Found $namespace in alt language file in ${filePath}. $namespace is only used in the dev language and will be ignored.`,\n );\n }\n\n if (!isAltLanguage && $namespace && typeof $namespace !== 'string') {\n printValidationError(\n `Found non-string $namespace in language file in ${filePath}. $namespace must be a string.`,\n );\n }\n\n if (isAltLanguage && _meta?.tags) {\n printValidationError(\n `Found _meta.tags in alt language file in ${filePath}. _meta.tags is only used in the dev language and will be ignored.`,\n );\n }\n\n // Never return tags if we're fetching translations for an alt language\n const includeTags = !isAltLanguage && withTags;\n const validKeys: TranslationsByKey = {};\n\n for (const [translationKey, { tags, ...translation }] of Object.entries(\n keys,\n )) {\n if (typeof translation === 'string') {\n printValidationError(\n `Found string for a translation \"${translationKey}\" in ${filePath}. Translation must be an object of the format {message: string}.`,\n );\n continue;\n }\n\n if (!translation) {\n printValidationError(\n `Found empty translation \"${translationKey}\" in ${filePath}. Translation must be an object of the format {message: string}.`,\n );\n continue;\n }\n\n if (!translation.message || typeof translation.message !== 'string') {\n printValidationError(\n `No message found for translation \"${translationKey}\" in ${filePath}. Translation must be an object of the format {message: string}.`,\n );\n continue;\n }\n\n validKeys[translationKey] = {\n ...translation,\n tags: includeTags ? tags : undefined,\n };\n }\n\n const metadata = { tags: includeTags ? _meta?.tags : undefined };\n\n return { $namespace, keys: validKeys, metadata };\n}\n\nexport function loadAltLanguageFile(\n {\n filePath,\n languageName,\n devTranslation,\n fallbacks,\n }: {\n filePath: string;\n languageName: string;\n devTranslation: TranslationsByKey;\n fallbacks: Fallback;\n },\n { devLanguage, languages }: UserConfig,\n): TranslationsByKey {\n const altLanguageTranslation = {};\n\n const fallbackLanguageOrder = getFallbackLanguageOrder({\n languages,\n languageName,\n devLanguage,\n fallbacks,\n });\n\n trace(\n `Loading alt language file with precedence: ${fallbackLanguageOrder\n .slice()\n .reverse()\n .join(' -> ')}`,\n );\n\n for (const fallbackLanguage of fallbackLanguageOrder) {\n if (fallbackLanguage !== devLanguage) {\n try {\n const altFilePath = getAltLanguageFilePath(filePath, fallbackLanguage);\n delete require.cache[altFilePath];\n\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const translationFile = require(altFilePath);\n const { keys: fallbackLanguageTranslation } = getTranslationsFromFile(\n translationFile,\n {\n filePath: altFilePath,\n isAltLanguage: true,\n },\n );\n Object.assign(\n altLanguageTranslation,\n mergeWithDevLanguageTranslation({\n translation: fallbackLanguageTranslation,\n devTranslation,\n }),\n );\n } catch {\n trace(`Missing alt language file ${getAltLanguageFilePath(\n filePath,\n fallbackLanguage,\n )}\n `);\n }\n } else {\n Object.assign(altLanguageTranslation, devTranslation);\n }\n }\n\n return altLanguageTranslation;\n}\n\nfunction stripTagsFromTranslations(translations: TranslationsByKey) {\n return Object.fromEntries(\n Object.entries(translations).map(([key, { tags, ...rest }]) => [key, rest]),\n );\n}\n\nexport function loadTranslation(\n {\n filePath,\n fallbacks,\n withTags,\n }: {\n filePath: string;\n fallbacks: Fallback;\n withTags?: boolean;\n },\n userConfig: UserConfig,\n): LoadedTranslation {\n trace(\n `Loading translation file in \"${fallbacks}\" fallback mode: \"${filePath}\"`,\n );\n\n const languageSet: Record<\n string,\n Record<string, { message: string; description?: string | undefined }>\n > = {};\n\n delete require.cache[filePath];\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const translationContent = require(filePath);\n const relativePath = path.relative(\n userConfig.projectRoot || process.cwd(),\n filePath,\n );\n const {\n $namespace,\n keys: devTranslation,\n metadata,\n } = getTranslationsFromFile(translationContent, {\n filePath,\n isAltLanguage: false,\n withTags,\n });\n const namespace: string =\n typeof $namespace === 'string'\n ? $namespace\n : getNamespaceByFilePath(relativePath, userConfig);\n\n trace(`Found file ${filePath}. Using namespace ${namespace}`);\n\n languageSet[userConfig.devLanguage] = devTranslation;\n\n const devTranslationNoTags = withTags\n ? stripTagsFromTranslations(devTranslation)\n : devTranslation;\n const altLanguages = getAltLanguages(userConfig);\n for (const languageName of altLanguages) {\n languageSet[languageName] = loadAltLanguageFile(\n {\n filePath,\n languageName,\n devTranslation: devTranslationNoTags,\n fallbacks,\n },\n userConfig,\n );\n }\n\n for (const generatedLanguage of userConfig.generatedLanguages || []) {\n const { name: generatedLanguageName, generator } = generatedLanguage;\n const baseLanguage = generatedLanguage.extends || userConfig.devLanguage;\n const baseTranslations = languageSet[baseLanguage];\n\n languageSet[generatedLanguageName] = generateLanguageFromTranslations({\n baseTranslations,\n generator,\n });\n }\n\n return {\n filePath,\n keys: Object.keys(devTranslation),\n namespace,\n relativePath,\n languages: languageSet,\n metadata,\n };\n}\n\nexport async function loadAllTranslations(\n {\n fallbacks,\n includeNodeModules,\n withTags,\n }: { fallbacks: Fallback; includeNodeModules: boolean; withTags?: boolean },\n config: UserConfig,\n): Promise<LoadedTranslation[]> {\n const { projectRoot, ignore = [] } = config;\n\n const translationFiles = await glob(getDevTranslationFileGlob(config), {\n ignore: includeNodeModules ? ignore : [...ignore, '**/node_modules/**'],\n absolute: true,\n cwd: projectRoot,\n expandDirectories: false,\n });\n\n trace(`Found ${translationFiles.length} translation files`);\n\n const loadedTranslations: LoadedTranslation[] = [];\n const keys = new Set<string>();\n\n for (const translationFile of translationFiles) {\n const loadedTranslation = loadTranslation(\n { filePath: translationFile, fallbacks, withTags },\n config,\n );\n\n loadedTranslations.push(loadedTranslation);\n\n for (const key of loadedTranslation.keys) {\n const uniqueKey = getUniqueKey(key, loadedTranslation.namespace);\n if (keys.has(uniqueKey)) {\n trace(`Duplicate keys found`);\n throw new Error(\n `Duplicate keys found. Key with namespace ${loadedTranslation.namespace} and key ${key} was found multiple times.`,\n );\n }\n keys.add(uniqueKey);\n\n const globalKey =\n loadedTranslation.languages[config.devLanguage][key].globalKey;\n if (globalKey) {\n if (keys.has(globalKey)) {\n throw new Error(\n `Duplicate keys found. Key with global key ${globalKey} and key ${key} was found multiple times`,\n );\n }\n keys.add(globalKey);\n }\n }\n }\n\n return loadedTranslations;\n}\n","import { promises as fs, existsSync } from 'fs';\nimport path from 'path';\nimport pm from 'picomatch';\n\nimport type { LoadedTranslation, UserConfig } from './types';\nimport {\n isArgumentElement,\n isDateElement,\n isNumberElement,\n isPluralElement,\n isSelectElement,\n isTagElement,\n isTimeElement,\n type MessageFormatElement,\n parse,\n} from '@formatjs/icu-messageformat-parser';\nimport prettier from 'prettier';\n\nimport {\n getTranslationMessages,\n getDevTranslationFileGlob,\n getTSFileFromDevLanguageFile,\n getDevLanguageFileFromAltLanguageFile,\n getAltTranslationFileGlob,\n isDevLanguageFile,\n isAltLanguageFile,\n devTranslationFileName,\n isTranslationDirectory,\n} from './utils';\nimport { trace } from './logger';\nimport { loadAllTranslations, loadTranslation } from './load-translations';\n\ntype ICUParams = Record<string, string>;\n\ninterface TranslationTypeInfo {\n params: ICUParams;\n message: string;\n hasTags: boolean;\n}\n\nfunction extractHasTags(ast: MessageFormatElement[]): boolean {\n return ast.some((element) => {\n if (isSelectElement(element) || isPluralElement(element)) {\n const children = Object.values(element.options).map((o) => o.value);\n return children.some((child) => extractHasTags(child));\n }\n\n return isTagElement(element);\n });\n}\n\nfunction extractParamTypes(\n ast: MessageFormatElement[],\n currentParams: ICUParams,\n): [params: ICUParams, vocabTypesImports: Set<string>] {\n let params = { ...currentParams };\n let vocabTypesImports = new Set<string>();\n\n for (const element of ast) {\n if (isArgumentElement(element)) {\n if (!(element.value in params)) {\n // Preserve existing types for parameters that we've already parsed\n // This applies to self-referential parameters, for example `{foo, plural, 1 {{foo} thing} other {{foo} things}}`\n params[element.value] = 'string';\n }\n } else if (isNumberElement(element)) {\n params[element.value] = 'number';\n } else if (isPluralElement(element)) {\n params[element.value] = 'number';\n\n const children = Object.values(element.options).map((o) => o.value);\n\n for (const child of children) {\n const [newParams, subImports] = extractParamTypes(child, params);\n\n vocabTypesImports = new Set([...vocabTypesImports, ...subImports]);\n params = newParams;\n }\n } else if (isDateElement(element) || isTimeElement(element)) {\n params[element.value] = 'Date | number';\n } else if (isTagElement(element)) {\n params[element.value] = 'FormatXMLElementFn<T>';\n vocabTypesImports.add('FormatXMLElementFn');\n\n const [newParams, subImports] = extractParamTypes(\n element.children,\n params,\n );\n\n vocabTypesImports = new Set([...vocabTypesImports, ...subImports]);\n params = newParams;\n } else if (isSelectElement(element)) {\n const options = Object.keys(element.options);\n\n // `other` will always be an option as the parser enforces this by default\n const nonOtherOptions = options.filter((o) => o !== 'other');\n const nonOtherOptionsUnion = nonOtherOptions\n .map((o) => `'${o}'`)\n .join(' | ');\n\n params[element.value] = `StringWithSuggestions<${nonOtherOptionsUnion}>`;\n vocabTypesImports.add('StringWithSuggestions');\n\n const children = Object.values(element.options).map((o) => o.value);\n\n for (const child of children) {\n const [newParams, subImports] = extractParamTypes(child, params);\n\n vocabTypesImports = new Set([...vocabTypesImports, ...subImports]);\n params = newParams;\n }\n }\n }\n\n return [params, vocabTypesImports];\n}\n\nfunction serialiseObjectToType(v: any) {\n let result = '';\n\n for (const [key, value] of Object.entries(v)) {\n result += `${JSON.stringify(key)}: ${\n value && typeof value === 'object' ? serialiseObjectToType(value) : value\n },`;\n }\n\n return `{ ${result} }`;\n}\n\nconst serializeTypeImports = (imports: Set<string>, moduleName: string) => {\n if (imports.size === 0) {\n return '';\n }\n\n const importNames = Array.from(imports);\n return `import type { ${importNames.join(', ')} } from '${moduleName}';`;\n};\n\nfunction serialiseTranslationRuntime(\n value: Map<string, TranslationTypeInfo>,\n imports: Set<string>,\n loadedTranslation: LoadedTranslation,\n) {\n trace('Serialising translations:', loadedTranslation);\n const translationsType: any = {};\n\n for (const [key, { params, message, hasTags }] of value.entries()) {\n let translationFunctionString = `() => ${message}`;\n\n if (Object.keys(params).length > 0) {\n const formatGeneric = hasTags ? '<T = string>' : '';\n const formatReturn =\n hasTags && imports.has('FormatXMLElementFn')\n ? 'ReturnType<FormatXMLElementFn<T>>'\n : 'string';\n translationFunctionString = `${formatGeneric}(values: ${serialiseObjectToType(\n params,\n )}) => ${formatReturn}`;\n }\n\n translationsType[key] = translationFunctionString;\n }\n\n const languagesUnionAsString = Object.keys(loadedTranslation.languages)\n .map((l) => `'${l}'`)\n .join(' | ');\n const languageEntries = Object.entries(loadedTranslation.languages)\n .map(\n ([languageName, translations]) =>\n `${JSON.stringify(languageName)}: createLanguage(${JSON.stringify(\n getTranslationMessages(translations),\n )})`,\n )\n .join(',');\n\n return /* ts */ `\n // This file is automatically generated by Vocab.\n // To make changes update translation.json files directly.\n\n ${serializeTypeImports(imports, '@vocab/core')}\n import { createLanguage, createTranslationFile } from '@vocab/core/runtime';\n import type { TranslationFile } from '@vocab/core';\n\n const translations: TranslationFile<\n ${languagesUnionAsString},\n ${serialiseObjectToType(translationsType)}\n > = createTranslationFile\n ({\n ${languageEntries}\n });\n\n export default translations;\n `;\n}\n\nexport async function generateRuntime(loadedTranslation: LoadedTranslation) {\n const { languages: loadedLanguages, filePath } = loadedTranslation;\n\n trace('Generating types for', filePath);\n const translationTypes = new Map<string, TranslationTypeInfo>();\n\n let imports = new Set<string>();\n\n for (const key of loadedTranslation.keys) {\n let params: ICUParams = {};\n const messages = new Set();\n let hasTags = false;\n\n for (const translatedLanguage of Object.values(loadedLanguages)) {\n if (translatedLanguage[key]) {\n const ast = parse(translatedLanguage[key].message);\n\n hasTags = hasTags || extractHasTags(ast);\n\n const [parsedParams, vocabTypesImports] = extractParamTypes(\n ast,\n params,\n );\n\n imports = new Set([...imports, ...vocabTypesImports]);\n params = parsedParams;\n\n messages.add(JSON.stringify(translatedLanguage[key].message));\n }\n }\n\n translationTypes.set(key, {\n params,\n hasTags,\n message: Array.from(messages).join(' | '),\n });\n }\n\n const prettierConfig = await prettier.resolveConfig(filePath);\n const serializedTranslationType = serialiseTranslationRuntime(\n translationTypes,\n imports,\n loadedTranslation,\n );\n const declaration = await prettier.format(serializedTranslationType, {\n ...prettierConfig,\n parser: 'typescript',\n });\n const outputFilePath = getTSFileFromDevLanguageFile(filePath);\n trace(`Writing translation types to ${outputFilePath}`);\n await writeIfChanged(outputFilePath, declaration);\n}\n\nexport async function watch(config: UserConfig) {\n const cwd = config.projectRoot || process.cwd();\n\n const ignorePatterns = [\n ...(config.ignore || []),\n '**/node_modules/**',\n '**/.git/**',\n ];\n\n const ignoredFunction = (pathToCheck: string) =>\n pm.isMatch(pathToCheck, ignorePatterns);\n\n const chokidar = await import('chokidar');\n const watcher = chokidar.watch(cwd, {\n ignored: ignoredFunction,\n ignoreInitial: true,\n });\n\n const devFileGlob = getDevTranslationFileGlob(config);\n const altFileGlob = getAltTranslationFileGlob(config);\n\n const onTranslationChange = async (relativePath: string) => {\n const matchesTranslationFiles = pm.isMatch(relativePath, [\n devFileGlob,\n altFileGlob,\n ]);\n\n if (!matchesTranslationFiles) {\n return;\n }\n\n trace(`Detected change for file ${relativePath}`);\n\n let targetFile;\n\n if (isDevLanguageFile(relativePath)) {\n targetFile = path.resolve(cwd, relativePath);\n } else if (isAltLanguageFile(relativePath)) {\n targetFile = getDevLanguageFileFromAltLanguageFile(\n path.resolve(cwd, relativePath),\n );\n }\n\n if (targetFile) {\n watcher.add(targetFile);\n try {\n const loadedTranslation = loadTranslation(\n { filePath: targetFile, fallbacks: 'all' },\n config,\n );\n\n await generateRuntime(loadedTranslation);\n } catch (e) {\n // eslint-disable-next-line no-console\n console.log('Failed to generate types for', relativePath);\n // eslint-disable-next-line no-console\n console.error(e);\n }\n }\n };\n\n const onNewDirectory = async (relativePath: string) => {\n trace('Detected new directory', relativePath);\n\n if (!isTranslationDirectory(relativePath, config)) {\n trace('Ignoring non-translation directory:', relativePath);\n return;\n }\n\n const newFilePath = path.join(relativePath, devTranslationFileName);\n if (!existsSync(newFilePath)) {\n await fs.writeFile(newFilePath, JSON.stringify({}, null, 2));\n trace('Created new empty translation file:', newFilePath);\n } else {\n trace(\n `New directory already contains translation file. Skipping creation. Existing file ${newFilePath}`,\n );\n }\n };\n\n watcher.on('addDir', onNewDirectory);\n watcher.on('add', onTranslationChange).on('change', onTranslationChange);\n\n return () => watcher.close();\n}\n\nexport async function compile(\n { watch: shouldWatch = false } = {},\n config: UserConfig,\n) {\n const translations = await loadAllTranslations(\n { fallbacks: 'all', includeNodeModules: false },\n config,\n );\n\n for (const loadedTranslation of translations) {\n await generateRuntime(loadedTranslation);\n }\n\n if (shouldWatch) {\n trace('Listening for changes to files...');\n return watch(config);\n }\n}\n\nasync function writeIfChanged(filepath: string, contents: string) {\n let hasChanged = true;\n\n try {\n const existingContents = await fs.readFile(filepath, { encoding: 'utf-8' });\n\n hasChanged = existingContents !== contents;\n } catch {\n // ignore error, likely a file doesn't exist error so we want to write anyway\n }\n\n if (hasChanged) {\n await fs.writeFile(filepath, contents, { encoding: 'utf-8' });\n }\n}\n","/* eslint-disable no-console */\nimport type { UserConfig, LoadedTranslation, LanguageName } from '../types';\nimport pc from 'picocolors';\n\nimport { loadAllTranslations } from '../load-translations';\nimport { getAltLanguages } from '../utils';\n\nexport function findMissingKeys(\n loadedTranslation: LoadedTranslation,\n devLanguageName: LanguageName,\n altLanguages: LanguageName[],\n) {\n const devLanguage = loadedTranslation.languages[devLanguageName];\n\n if (!devLanguage) {\n throw new Error(\n `Failed to load dev language: ${loadedTranslation.filePath}`,\n );\n }\n\n const result: Record<LanguageName, string[]> = {};\n let valid = true;\n\n const requiredKeys = Object.keys(devLanguage);\n\n if (requiredKeys.length > 0) {\n for (const altLanguageName of altLanguages) {\n const altLanguage = loadedTranslation.languages[altLanguageName] ?? {};\n\n for (const key of requiredKeys) {\n if (typeof altLanguage[key]?.message !== 'string') {\n if (!result[altLanguageName]) {\n result[altLanguageName] = [];\n }\n\n result[altLanguageName].push(key);\n valid = false;\n }\n }\n }\n }\n return [valid, result] as const;\n}\n\nexport async function validate(config: UserConfig) {\n const allTranslations = await loadAllTranslations(\n { fallbacks: 'valid', includeNodeModules: true },\n config,\n );\n\n let valid = true;\n\n for (const loadedTranslation of allTranslations) {\n const [translationValid, result] = findMissingKeys(\n loadedTranslation,\n config.devLanguage,\n getAltLanguages(config),\n );\n\n if (!translationValid) {\n valid = false;\n console.log(\n pc.red(\n `Incomplete translations: \"${pc.bold(\n loadedTranslation.relativePath,\n )}\"`,\n ),\n );\n\n for (const lang of Object.keys(result)) {\n const missingKeys = result[lang];\n\n console.log(\n pc.yellow(lang),\n '->',\n missingKeys.map((v) => `\"${v}\"`).join(', '),\n );\n }\n }\n }\n\n return valid;\n}\n","export class ValidationError extends Error {\n code: string;\n rawMessage: string;\n constructor(code: string, message: string) {\n super(`Invalid vocab.config.js: ${code} - ${message}`);\n this.code = code;\n this.rawMessage = message;\n }\n}\n","import type { UserConfig } from './types';\nimport path from 'path';\n\nimport pc from 'picocolors';\nimport findUp from 'find-up';\nimport Validator from 'fastest-validator';\nimport { ValidationError } from './ValidationError';\nimport { trace } from './logger';\n\nconst boldCyan = (s: string) => pc.bold(pc.cyan(s));\n\nconst validator = new Validator();\nconst schema = {\n $$strict: true,\n devLanguage: {\n type: 'string',\n },\n languages: {\n type: 'array',\n items: {\n type: 'object',\n props: {\n name: { type: 'string' },\n extends: { type: 'string', optional: true },\n },\n },\n },\n generatedLanguages: {\n type: 'array',\n items: {\n type: 'object',\n props: {\n name: { type: 'string' },\n extends: { type: 'string', optional: true },\n generator: {\n type: 'object',\n props: {\n transformElement: { type: 'function', optional: true },\n transformMessage: { type: 'function', optional: true },\n },\n },\n },\n },\n optional: true,\n },\n translationsDirectorySuffix: { type: 'string', optional: true },\n projectRoot: { type: 'string', optional: true },\n ignore: {\n type: 'array',\n items: 'string',\n optional: true,\n },\n};\nconst checkConfigFile = validator.compile(schema);\n\nconst splitMap = (message: string, callback: (value: string) => string) =>\n message\n .split(' ,')\n .map((v) => callback(v))\n .join(' ,');\n\nexport function validateConfig(c: UserConfig) {\n trace('Validating configuration file');\n // Note: checkConfigFile mutates the config file by applying defaults\n const isValid = checkConfigFile(c);\n if (isValid !== true) {\n throw new ValidationError(\n 'InvalidStructure',\n (Array.isArray(isValid) ? isValid : [])\n .map((v) => {\n if (v.type === 'objectStrict') {\n return `Invalid key(s) ${splitMap(\n v.actual,\n (m) => `\"${pc.cyan(m)}\"`,\n )}. Expected one of ${splitMap(v.expected, pc.green)}`;\n }\n if (v.field) {\n return v.message?.replace(v.field, pc.cyan(v.field));\n }\n return v.message;\n })\n .join(' \\n'),\n );\n }\n\n const languageStrings = c.languages.map((v) => v.name);\n\n // Dev Language should exist in languages\n if (!languageStrings.includes(c.devLanguage)) {\n throw new ValidationError(\n 'InvalidDevLanguage',\n `The dev language \"${boldCyan(\n c.devLanguage,\n )}\" was not found in languages ${languageStrings.join(', ')}.`,\n );\n }\n\n const foundLanguages: string[] = [];\n for (const lang of c.languages) {\n // Languages must only exist once\n if (foundLanguages.includes(lang.name)) {\n throw new ValidationError(\n 'DuplicateLanguage',\n `The language \"${boldCyan(lang.name)}\" was defined multiple times.`,\n );\n }\n foundLanguages.push(lang.name);\n\n // Any extends must be in languages\n if (lang.extends && !languageStrings.includes(lang.extends)) {\n throw new ValidationError(\n 'InvalidExtends',\n `The language \"${boldCyan(lang.name)}\"'s extends of ${boldCyan(\n lang.extends,\n )} was not found in languages ${languageStrings.join(', ')}.`,\n );\n }\n }\n\n const foundGeneratedLanguages: string[] = [];\n for (const generatedLang of c.generatedLanguages || []) {\n // Generated languages must only exist once\n if (foundGeneratedLanguages.includes(generatedLang.name)) {\n throw new ValidationError(\n 'DuplicateGeneratedLanguage',\n `The generated language \"${boldCyan(\n generatedLang.name,\n )}\" was defined multiple times.`,\n );\n }\n foundGeneratedLanguages.push(generatedLang.name);\n\n // Generated language names must not conflict with language names\n if (languageStrings.includes(generatedLang.name)) {\n throw new ValidationError(\n 'InvalidGeneratedLanguage',\n `The generated language \"${boldCyan(\n generatedLang.name,\n )}\" is already defined as a language.`,\n );\n }\n\n // Any extends must be in languages\n if (\n generatedLang.extends &&\n !languageStrings.includes(generatedLang.extends)\n ) {\n throw new ValidationError(\n 'InvalidExtends',\n `The generated language \"${boldCyan(\n generatedLang.name,\n )}\"'s extends of ${boldCyan(\n generatedLang.extends,\n )} was not found in languages ${languageStrings.join(', ')}.`,\n );\n }\n }\n\n trace('Configuration file is valid');\n\n return true;\n}\n\nfunction createConfig(configFilePath: string) {\n const cwd = path.dirname(configFilePath);\n\n return {\n projectRoot: cwd,\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n ...(require(configFilePath) as UserConfig),\n };\n}\n\nexport async function resolveConfig(\n customConfigFilePath?: string,\n): Promise<UserConfig | null> {\n const configFilePath = customConfigFilePath\n ? path.resolve(customConfigFilePath)\n : await findUp(['vocab.config.js', 'vocab.config.cjs']);\n\n if (configFilePath) {\n trace(`Resolved configuration file to ${configFilePath}`);\n return createConfig(configFilePath);\n }\n trace('No configuration file found');\n return null;\n}\n\nexport function resolveConfigSync(\n customConfigFilePath?: string,\n): UserConfig | null {\n const configFilePath = customConfigFilePath\n ? path.resolve(customConfigFilePath)\n : findUp.sync(['vocab.config.js', 'vocab.config.cjs']);\n\n if (configFilePath) {\n trace(`Resolved configuration file to ${configFilePath}`);\n return createConfig(configFilePath);\n }\n trace('No configuration file found');\n\n return null;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["newObj: any","generatedTranslations: TranslationsByKey<string>","IntlMessageFormat","TYPE","transformedOptions: Record<string, PluralOrSelectOption>","newLanguage: TranslationsByKey","fallbackLanguageOrder: string[]","pc","validKeys: TranslationsByKey","languageSet: Record<\n string,\n Record<string, { message: string; description?: string | undefined }>\n >","namespace: string","loadedTranslations: LoadedTranslation[]","translationsType: any","params: ICUParams","pm","result: Record<LanguageName, string[]>","pc","pc","Validator","foundLanguages: string[]","foundGeneratedLanguages: string[]","findUp"],"sources":["../src/logger.ts","../src/utils.ts","../src/generate-language.ts","../src/load-translations.ts","../src/compile.ts","../src/validate/index.ts","../src/ValidationError.ts","../src/config.ts"],"sourcesContent":["import pc from 'picocolors';\nimport debug from 'debug';\n\nexport const trace = debug(`vocab:core`);\n\nexport const log = (...params: unknown[]) => {\n // eslint-disable-next-line no-console\n console.log(pc.yellow('Vocab'), ...params);\n};\n","import path from 'path';\n\nimport type {\n LanguageName,\n LanguageTarget,\n TranslationsByKey,\n TranslationMessagesByKey,\n UserConfig,\n} from './types';\nimport { trace } from './logger';\n\nexport const defaultTranslationDirSuffix = '.vocab';\nexport const devTranslationFileName = 'translations.json';\n\nexport type Fallback = 'none' | 'valid' | 'all';\n\nconst globAnyPathWithOptionalPrefix = '**/?(*)';\n\nexport const compiledVocabFileFilter = /\\.vocab[\\\\/]index\\.(?:ts|js|cjs|mjs)$/;\n\nexport function isDevLanguageFile(filePath: string) {\n return (\n filePath.endsWith(`/${devTranslationFileName}`) ||\n filePath === devTranslationFileName\n );\n}\nexport function isAltLanguageFile(filePath: string) {\n return filePath.endsWith('.translations.json');\n}\nexport function isTranslationDirectory(\n filePath: string,\n {\n translationsDirectorySuffix = defaultTranslationDirSuffix,\n }: {\n translationsDirectorySuffix?: string;\n },\n) {\n return filePath.endsWith(translationsDirectorySuffix);\n}\n\nexport function getDevTranslationFileGlob({\n translationsDirectorySuffix = defaultTranslationDirSuffix,\n}: {\n translationsDirectorySuffix?: string;\n}) {\n const result = `${globAnyPathWithOptionalPrefix}${translationsDirectorySuffix}/${devTranslationFileName}`;\n\n trace('getDevTranslationFileGlob', result);\n\n return result;\n}\n\nexport function getAltTranslationFileGlob(config: UserConfig) {\n const altLanguages = getAltLanguages(config);\n const langMatch =\n altLanguages.length === 1 ? altLanguages[0] : `{${altLanguages.join(',')}}`;\n\n const { translationsDirectorySuffix = defaultTranslationDirSuffix } = config;\n const result = `${globAnyPathWithOptionalPrefix}${translationsDirectorySuffix}/${langMatch}.${devTranslationFileName}`;\n\n trace('getAltTranslationFileGlob', result);\n\n return result;\n}\n\nexport function getAltLanguages({\n devLanguage,\n languages,\n}: {\n devLanguage: LanguageName;\n languages: LanguageTarget[];\n}) {\n return languages.map((v) => v.name).filter((lang) => lang !== devLanguage);\n}\n\nexport function getDevLanguageFileFromTsFile(tsFilePath: string) {\n const directory = path.dirname(tsFilePath);\n const result = path.normalize(path.join(directory, devTranslationFileName));\n\n trace(`Returning dev language path ${result} for path ${tsFilePath}`);\n return result;\n}\n\nexport function getDevLanguageFileFromAltLanguageFile(\n altLanguageFilePath: string,\n) {\n const directory = path.dirname(altLanguageFilePath);\n const result = path.normalize(path.join(directory, devTranslationFileName));\n trace(\n `Returning dev language path ${result} for path ${altLanguageFilePath}`,\n );\n return result;\n}\n\nexport function getTSFileFromDevLanguageFile(devLanguageFilePath: string) {\n const directory = path.dirname(devLanguageFilePath);\n const result = path.normalize(path.join(directory, 'index.ts'));\n\n trace(`Returning TS path ${result} for path ${devLanguageFilePath}`);\n return result;\n}\n\nexport function getAltLanguageFilePath(\n devLanguageFilePath: string,\n language: string,\n) {\n const directory = path.dirname(devLanguageFilePath);\n const result = path.normalize(\n path.join(directory, `${language}.translations.json`),\n );\n trace(\n `Returning alt language path ${result} for path ${devLanguageFilePath}`,\n );\n return path.normalize(result);\n}\n\nexport function mapValues<Key extends string, OriginalValue, ReturnValue>(\n obj: Record<Key, OriginalValue>,\n func: (val: OriginalValue) => ReturnValue,\n): TranslationMessagesByKey<Key> {\n const newObj: any = {};\n const keys = Object.keys(obj) as Key[];\n for (const key of keys) {\n newObj[key] = func(obj[key]);\n }\n return newObj;\n}\n\nexport function getTranslationMessages<Key extends string>(\n translations: TranslationsByKey<Key>,\n): TranslationMessagesByKey<Key> {\n return mapValues(translations, (v) => v.message);\n}\n","import { IntlMessageFormat } from 'intl-messageformat';\nimport {\n type MessageFormatElement,\n type PluralOrSelectOption,\n TYPE,\n} from '@formatjs/icu-messageformat-parser';\nimport { printAST } from '@formatjs/icu-messageformat-parser/printer.js';\nimport type { MessageGenerator, TranslationsByKey } from './types';\n\nexport function generateLanguageFromTranslations({\n baseTranslations,\n generator,\n}: {\n baseTranslations: TranslationsByKey<string>;\n generator: MessageGenerator;\n}): TranslationsByKey<string> {\n if (!generator.transformElement && !generator.transformMessage) {\n return baseTranslations;\n }\n\n const translationKeys = Object.keys(baseTranslations);\n const generatedTranslations: TranslationsByKey<string> = {};\n\n for (const translationKey of translationKeys) {\n const translation = baseTranslations[translationKey];\n let transformedMessage = translation.message;\n\n if (generator.transformElement) {\n const messageAst = new IntlMessageFormat(translation.message).getAst();\n const transformedAst = messageAst.map(\n transformMessageFormatElement(generator.transformElement),\n );\n transformedMessage = printAST(transformedAst);\n }\n\n if (generator.transformMessage) {\n transformedMessage = generator.transformMessage(transformedMessage);\n }\n\n generatedTranslations[translationKey] = {\n message: transformedMessage,\n };\n }\n\n return generatedTranslations;\n}\n\nfunction transformMessageFormatElement(\n transformElement: (message: string) => string,\n): (messageFormatElement: MessageFormatElement) => MessageFormatElement {\n return (messageFormatElement: MessageFormatElement) => {\n const transformedMessageFormatElement = { ...messageFormatElement };\n\n switch (transformedMessageFormatElement.type) {\n case TYPE.literal:\n const transformedValue = transformElement(\n transformedMessageFormatElement.value,\n );\n transformedMessageFormatElement.value = transformedValue;\n break;\n\n case TYPE.select:\n case TYPE.plural:\n const transformedOptions: Record<string, PluralOrSelectOption> = {\n ...transformedMessageFormatElement.options,\n };\n\n for (const key of Object.keys(transformedOptions)) {\n transformedOptions[key].value = transformedOptions[key].value.map(\n transformMessageFormatElement(transformElement),\n );\n }\n\n break;\n\n case TYPE.tag:\n const transformedChildren =\n transformedMessageFormatElement.children.map(\n transformMessageFormatElement(transformElement),\n );\n transformedMessageFormatElement.children = transformedChildren;\n break;\n\n default:\n break;\n }\n\n return transformedMessageFormatElement;\n };\n}\n","import path from 'path';\n\nimport { glob } from 'tinyglobby';\nimport type {\n TranslationsByKey,\n UserConfig,\n LoadedTranslation,\n LanguageTarget,\n LanguageName,\n TranslationFileMetadata,\n TranslationFileContents,\n} from './types';\nimport pc from 'picocolors';\n\nimport { trace } from './logger';\nimport {\n defaultTranslationDirSuffix,\n type Fallback,\n getAltLanguageFilePath,\n getAltLanguages,\n getDevTranslationFileGlob,\n} from './utils';\nimport { generateLanguageFromTranslations } from './generate-language';\n\nexport function getUniqueKey(key: string, namespace: string) {\n return `${key}.${namespace}`;\n}\n\nexport function mergeWithDevLanguageTranslation({\n translation,\n devTranslation,\n}: {\n translation: TranslationsByKey;\n devTranslation: TranslationsByKey;\n}) {\n // Only use keys from the dev translation\n const keys = Object.keys(devTranslation);\n const newLanguage: TranslationsByKey = {};\n\n for (const key of keys) {\n if (translation[key]) {\n newLanguage[key] = {\n message: translation[key].message,\n description: devTranslation[key].description,\n };\n }\n }\n\n return newLanguage;\n}\n\nfunction getLanguageFallbacks({ languages }: { languages: LanguageTarget[] }) {\n const languageFallbackMap = new Map<LanguageName, LanguageName>();\n\n for (const lang of languages) {\n if (lang.extends) {\n languageFallbackMap.set(lang.name, lang.extends);\n }\n }\n\n return languageFallbackMap;\n}\n\nexport function getLanguageHierarchy({\n languages,\n}: {\n languages: LanguageTarget[];\n}) {\n const hierarchyMap = new Map<LanguageName, LanguageName[]>();\n const fallbacks = getLanguageFallbacks({ languages });\n\n for (const lang of languages) {\n const langHierarchy = [];\n let currLang = lang.extends;\n\n while (currLang) {\n langHierarchy.push(currLang);\n\n currLang = fallbacks.get(currLang);\n }\n\n hierarchyMap.set(lang.name, langHierarchy);\n }\n\n return hierarchyMap;\n}\n\nexport function getFallbackLanguageOrder({\n languages,\n languageName,\n devLanguage,\n fallbacks,\n}: {\n languages: LanguageTarget[];\n languageName: string;\n devLanguage: string;\n fallbacks: Fallback;\n}) {\n const languageHierarchy = getLanguageHierarchy({ languages }).get(\n languageName,\n );\n\n if (!languageHierarchy) {\n throw new Error(`Missing language hierarchy for ${languageName}`);\n }\n\n const fallbackLanguageOrder: string[] = [languageName];\n\n if (fallbacks !== 'none') {\n fallbackLanguageOrder.unshift(...languageHierarchy.reverse());\n\n if (fallbacks === 'all' && fallbackLanguageOrder[0] !== devLanguage) {\n fallbackLanguageOrder.unshift(devLanguage);\n }\n }\n\n return fallbackLanguageOrder;\n}\n\nfunction getNamespaceByFilePath(\n relativePath: string,\n { translationsDirectorySuffix = defaultTranslationDirSuffix }: UserConfig,\n) {\n let namespace = path\n .dirname(relativePath)\n .replace(/^src\\//, '')\n .replace(/\\//g, '_');\n\n if (namespace.endsWith(translationsDirectorySuffix)) {\n namespace = namespace.slice(0, -translationsDirectorySuffix.length);\n }\n\n return namespace;\n}\n\nfunction printValidationError(...params: unknown[]) {\n // eslint-disable-next-line no-console\n console.error(pc.red('Error loading translation:'), ...params);\n}\n\nfunction getTranslationsFromFile(\n translationFileContents: unknown,\n {\n isAltLanguage,\n filePath,\n withTags,\n }: { isAltLanguage: boolean; filePath: string; withTags?: boolean },\n): {\n $namespace: unknown;\n keys: TranslationsByKey;\n metadata: TranslationFileMetadata;\n} {\n if (!translationFileContents || typeof translationFileContents !== 'object') {\n throw new Error(\n `Unable to read translation file ${filePath}. Translations must be an object.`,\n );\n }\n\n const { $namespace, _meta, ...keys } =\n translationFileContents as TranslationFileContents;\n\n if (isAltLanguage && $namespace) {\n printValidationError(\n `Found $namespace in alt language file in ${filePath}. $namespace is only used in the dev language and will be ignored.`,\n );\n }\n\n if (!isAltLanguage && $namespace && typeof $namespace !== 'string') {\n printValidationError(\n `Found non-string $namespace in language file in ${filePath}. $namespace must be a string.`,\n );\n }\n\n if (isAltLanguage && _meta?.tags) {\n printValidationError(\n `Found _meta.tags in alt language file in ${filePath}. _meta.tags is only used in the dev language and will be ignored.`,\n );\n }\n\n // Never return tags if we're fetching translations for an alt language\n const includeTags = !isAltLanguage && withTags;\n const validKeys: TranslationsByKey = {};\n\n for (const [translationKey, { tags, ...translation }] of Object.entries(\n keys,\n )) {\n if (typeof translation === 'string') {\n printValidationError(\n `Found string for a translation \"${translationKey}\" in ${filePath}. Translation must be an object of the format {message: string}.`,\n );\n continue;\n }\n\n if (!translation) {\n printValidationError(\n `Found empty translation \"${translationKey}\" in ${filePath}. Translation must be an object of the format {message: string}.`,\n );\n continue;\n }\n\n if (!translation.message || typeof translation.message !== 'string') {\n printValidationError(\n `No message found for translation \"${translationKey}\" in ${filePath}. Translation must be an object of the format {message: string}.`,\n );\n continue;\n }\n\n validKeys[translationKey] = {\n ...translation,\n tags: includeTags ? tags : undefined,\n };\n }\n\n const metadata = { tags: includeTags ? _meta?.tags : undefined };\n\n return { $namespace, keys: validKeys, metadata };\n}\n\nexport function loadAltLanguageFile(\n {\n filePath,\n languageName,\n devTranslation,\n fallbacks,\n }: {\n filePath: string;\n languageName: string;\n devTranslation: TranslationsByKey;\n fallbacks: Fallback;\n },\n { devLanguage, languages }: UserConfig,\n): TranslationsByKey {\n const altLanguageTranslation = {};\n\n const fallbackLanguageOrder = getFallbackLanguageOrder({\n languages,\n languageName,\n devLanguage,\n fallbacks,\n });\n\n trace(\n `Loading alt language file with precedence: ${fallbackLanguageOrder\n .slice()\n .reverse()\n .join(' -> ')}`,\n );\n\n for (const fallbackLanguage of fallbackLanguageOrder) {\n if (fallbackLanguage !== devLanguage) {\n try {\n const altFilePath = getAltLanguageFilePath(filePath, fallbackLanguage);\n delete require.cache[altFilePath];\n\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const translationFile = require(altFilePath);\n const { keys: fallbackLanguageTranslation } = getTranslationsFromFile(\n translationFile,\n {\n filePath: altFilePath,\n isAltLanguage: true,\n },\n );\n Object.assign(\n altLanguageTranslation,\n mergeWithDevLanguageTranslation({\n translation: fallbackLanguageTranslation,\n devTranslation,\n }),\n );\n } catch {\n trace(`Missing alt language file ${getAltLanguageFilePath(\n filePath,\n fallbackLanguage,\n )}\n `);\n }\n } else {\n Object.assign(altLanguageTranslation, devTranslation);\n }\n }\n\n return altLanguageTranslation;\n}\n\nfunction stripTagsFromTranslations(translations: TranslationsByKey) {\n return Object.fromEntries(\n Object.entries(translations).map(([key, { tags, ...rest }]) => [key, rest]),\n );\n}\n\nexport function loadTranslation(\n {\n filePath,\n fallbacks,\n withTags,\n }: {\n filePath: string;\n fallbacks: Fallback;\n withTags?: boolean;\n },\n userConfig: UserConfig,\n): LoadedTranslation {\n trace(\n `Loading translation file in \"${fallbacks}\" fallback mode: \"${filePath}\"`,\n );\n\n const languageSet: Record<\n string,\n Record<string, { message: string; description?: string | undefined }>\n > = {};\n\n delete require.cache[filePath];\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const translationContent = require(filePath);\n const relativePath = path.relative(\n userConfig.projectRoot || process.cwd(),\n filePath,\n );\n const {\n $namespace,\n keys: devTranslation,\n metadata,\n } = getTranslationsFromFile(translationContent, {\n filePath,\n isAltLanguage: false,\n withTags,\n });\n const namespace: string =\n typeof $namespace === 'string'\n ? $namespace\n : getNamespaceByFilePath(relativePath, userConfig);\n\n trace(`Found file ${filePath}. Using namespace ${namespace}`);\n\n languageSet[userConfig.devLanguage] = devTranslation;\n\n const devTranslationNoTags = withTags\n ? stripTagsFromTranslations(devTranslation)\n : devTranslation;\n const altLanguages = getAltLanguages(userConfig);\n for (const languageName of altLanguages) {\n languageSet[languageName] = loadAltLanguageFile(\n {\n filePath,\n languageName,\n devTranslation: devTranslationNoTags,\n fallbacks,\n },\n userConfig,\n );\n }\n\n for (const generatedLanguage of userConfig.generatedLanguages || []) {\n const { name: generatedLanguageName, generator } = generatedLanguage;\n const baseLanguage = generatedLanguage.extends || userConfig.devLanguage;\n const baseTranslations = languageSet[baseLanguage];\n\n languageSet[generatedLanguageName] = generateLanguageFromTranslations({\n baseTranslations,\n generator,\n });\n }\n\n return {\n filePath,\n keys: Object.keys(devTranslation),\n namespace,\n relativePath,\n languages: languageSet,\n metadata,\n };\n}\n\nexport async function loadAllTranslations(\n {\n fallbacks,\n includeNodeModules,\n withTags,\n }: { fallbacks: Fallback; includeNodeModules: boolean; withTags?: boolean },\n config: UserConfig,\n): Promise<LoadedTranslation[]> {\n const { projectRoot, ignore = [] } = config;\n\n const translationFiles = await glob(getDevTranslationFileGlob(config), {\n ignore: includeNodeModules ? ignore : [...ignore, '**/node_modules/**'],\n dot: true,\n absolute: true,\n cwd: projectRoot,\n expandDirectories: false,\n });\n\n trace(`Found ${translationFiles.length} translation files`);\n\n const loadedTranslations: LoadedTranslation[] = [];\n const keys = new Set<string>();\n\n for (const translationFile of translationFiles) {\n const loadedTranslation = loadTranslation(\n { filePath: translationFile, fallbacks, withTags },\n config,\n );\n\n loadedTranslations.push(loadedTranslation);\n\n for (const key of loadedTranslation.keys) {\n const uniqueKey = getUniqueKey(key, loadedTranslation.namespace);\n if (keys.has(uniqueKey)) {\n trace(`Duplicate keys found`);\n throw new Error(\n `Duplicate keys found. Key with namespace ${loadedTranslation.namespace} and key ${key} was found multiple times.`,\n );\n }\n keys.add(uniqueKey);\n\n const globalKey =\n loadedTranslation.languages[config.devLanguage][key].globalKey;\n if (globalKey) {\n if (keys.has(globalKey)) {\n throw new Error(\n `Duplicate keys found. Key with global key ${globalKey} and key ${key} was found multiple times`,\n );\n }\n keys.add(globalKey);\n }\n }\n }\n\n return loadedTranslations;\n}\n","import { promises as fs, existsSync } from 'fs';\nimport path from 'path';\nimport pm from 'picomatch';\n\nimport type { LoadedTranslation, UserConfig } from './types';\nimport {\n isArgumentElement,\n isDateElement,\n isNumberElement,\n isPluralElement,\n isSelectElement,\n isTagElement,\n isTimeElement,\n type MessageFormatElement,\n parse,\n} from '@formatjs/icu-messageformat-parser';\nimport prettier from 'prettier';\n\nimport {\n getTranslationMessages,\n getDevTranslationFileGlob,\n getTSFileFromDevLanguageFile,\n getDevLanguageFileFromAltLanguageFile,\n getAltTranslationFileGlob,\n isDevLanguageFile,\n isAltLanguageFile,\n devTranslationFileName,\n isTranslationDirectory,\n} from './utils';\nimport { trace } from './logger';\nimport { loadAllTranslations, loadTranslation } from './load-translations';\n\ntype ICUParams = Record<string, string>;\n\ninterface TranslationTypeInfo {\n params: ICUParams;\n message: string;\n hasTags: boolean;\n}\n\nfunction extractHasTags(ast: MessageFormatElement[]): boolean {\n return ast.some((element) => {\n if (isSelectElement(element) || isPluralElement(element)) {\n const children = Object.values(element.options).map((o) => o.value);\n return children.some((child) => extractHasTags(child));\n }\n\n return isTagElement(element);\n });\n}\n\nfunction extractParamTypes(\n ast: MessageFormatElement[],\n currentParams: ICUParams,\n): [params: ICUParams, vocabTypesImports: Set<string>] {\n let params = { ...currentParams };\n let vocabTypesImports = new Set<string>();\n\n for (const element of ast) {\n if (isArgumentElement(element)) {\n if (!(element.value in params)) {\n // Preserve existing types for parameters that we've already parsed\n // This applies to self-referential parameters, for example `{foo, plural, 1 {{foo} thing} other {{foo} things}}`\n params[element.value] = 'string';\n }\n } else if (isNumberElement(element)) {\n params[element.value] = 'number';\n } else if (isPluralElement(element)) {\n params[element.value] = 'number';\n\n const children = Object.values(element.options).map((o) => o.value);\n\n for (const child of children) {\n const [newParams, subImports] = extractParamTypes(child, params);\n\n vocabTypesImports = new Set([...vocabTypesImports, ...subImports]);\n params = newParams;\n }\n } else if (isDateElement(element) || isTimeElement(element)) {\n params[element.value] = 'Date | number';\n } else if (isTagElement(element)) {\n params[element.value] = 'FormatXMLElementFn<T>';\n vocabTypesImports.add('FormatXMLElementFn');\n\n const [newParams, subImports] = extractParamTypes(\n element.children,\n params,\n );\n\n vocabTypesImports = new Set([...vocabTypesImports, ...subImports]);\n params = newParams;\n } else if (isSelectElement(element)) {\n const options = Object.keys(element.options);\n\n // `other` will always be an option as the parser enforces this by default\n const nonOtherOptions = options.filter((o) => o !== 'other');\n const nonOtherOptionsUnion = nonOtherOptions\n .map((o) => `'${o}'`)\n .join(' | ');\n\n params[element.value] = `StringWithSuggestions<${nonOtherOptionsUnion}>`;\n vocabTypesImports.add('StringWithSuggestions');\n\n const children = Object.values(element.options).map((o) => o.value);\n\n for (const child of children) {\n const [newParams, subImports] = extractParamTypes(child, params);\n\n vocabTypesImports = new Set([...vocabTypesImports, ...subImports]);\n params = newParams;\n }\n }\n }\n\n return [params, vocabTypesImports];\n}\n\nfunction serialiseObjectToType(v: any) {\n let result = '';\n\n for (const [key, value] of Object.entries(v)) {\n result += `${JSON.stringify(key)}: ${\n value && typeof value === 'object' ? serialiseObjectToType(value) : value\n },`;\n }\n\n return `{ ${result} }`;\n}\n\nconst serializeTypeImports = (imports: Set<string>, moduleName: string) => {\n if (imports.size === 0) {\n return '';\n }\n\n const importNames = Array.from(imports).sort();\n return `import type { ${importNames.join(', ')} } from '${moduleName}';`;\n};\n\nfunction serialiseTranslationRuntime(\n value: Map<string, TranslationTypeInfo>,\n imports: Set<string>,\n loadedTranslation: LoadedTranslation,\n) {\n trace('Serialising translations:', loadedTranslation);\n const translationsType: any = {};\n\n for (const [key, { params, message, hasTags }] of value.entries()) {\n let translationFunctionString = `() => ${message}`;\n\n if (Object.keys(params).length > 0) {\n const formatGeneric = hasTags ? '<T = string>' : '';\n const formatReturn =\n hasTags && imports.has('FormatXMLElementFn')\n ? 'ReturnType<FormatXMLElementFn<T>>'\n : 'string';\n translationFunctionString = `${formatGeneric}(values: ${serialiseObjectToType(\n params,\n )}) => ${formatReturn}`;\n }\n\n translationsType[key] = translationFunctionString;\n }\n\n const languagesUnionAsString = Object.keys(loadedTranslation.languages)\n .map((l) => `'${l}'`)\n .join(' | ');\n const languageEntries = Object.entries(loadedTranslation.languages)\n .map(\n ([languageName, translations]) =>\n `${JSON.stringify(languageName)}: createLanguage(${JSON.stringify(\n getTranslationMessages(translations),\n )})`,\n )\n .join(',');\n\n // TranslationFile is now always imported\n const typeImports = new Set([...imports, 'TranslationFile']);\n\n return /* ts */ `\n // This file is automatically generated by Vocab.\n // To make changes update translation.json files directly.\n\n ${serializeTypeImports(typeImports, '@vocab/core')}\n import { createLanguage, createTranslationFile } from '@vocab/core/runtime';\n\n const translations: TranslationFile<\n ${languagesUnionAsString},\n ${serialiseObjectToType(translationsType)}\n > = createTranslationFile\n ({\n ${languageEntries}\n });\n\n export default translations;\n `;\n}\n\nexport async function generateRuntime(loadedTranslation: LoadedTranslation) {\n const { languages: loadedLanguages, filePath } = loadedTranslation;\n\n trace('Generating types for', filePath);\n const translationTypes = new Map<string, TranslationTypeInfo>();\n\n let imports = new Set<string>();\n\n for (const key of loadedTranslation.keys) {\n let params: ICUParams = {};\n const messages = new Set();\n let hasTags = false;\n\n for (const translatedLanguage of Object.values(loadedLanguages)) {\n if (translatedLanguage[key]) {\n const ast = parse(translatedLanguage[key].message);\n\n hasTags = hasTags || extractHasTags(ast);\n\n const [parsedParams, vocabTypesImports] = extractParamTypes(\n ast,\n params,\n );\n\n imports = new Set([...imports, ...vocabTypesImports]);\n params = parsedParams;\n\n messages.add(JSON.stringify(translatedLanguage[key].message));\n }\n }\n\n translationTypes.set(key, {\n params,\n hasTags,\n message: Array.from(messages).join(' | '),\n });\n }\n\n const prettierConfig = await prettier.resolveConfig(filePath);\n const serializedTranslationType = serialiseTranslationRuntime(\n translationTypes,\n imports,\n loadedTranslation,\n );\n const declaration = await prettier.format(serializedTranslationType, {\n ...prettierConfig,\n parser: 'typescript',\n });\n const outputFilePath = getTSFileFromDevLanguageFile(filePath);\n trace(`Writing translation types to ${outputFilePath}`);\n await writeIfChanged(outputFilePath, declaration);\n}\n\nexport async function watch(config: UserConfig) {\n const cwd = config.projectRoot || process.cwd();\n\n const ignorePatterns = [\n ...(config.ignore || []),\n '**/node_modules/**',\n '**/.git/**',\n ];\n\n const ignoredFunction = (pathToCheck: string) =>\n pm.isMatch(pathToCheck, ignorePatterns);\n\n const chokidar = await import('chokidar');\n const watcher = chokidar.watch(cwd, {\n ignored: ignoredFunction,\n ignoreInitial: true,\n });\n\n const devFileGlob = getDevTranslationFileGlob(config);\n const altFileGlob = getAltTranslationFileGlob(config);\n\n const onTranslationChange = async (relativePath: string) => {\n const matchesTranslationFiles = pm.isMatch(relativePath, [\n devFileGlob,\n altFileGlob,\n ]);\n\n if (!matchesTranslationFiles) {\n return;\n }\n\n trace(`Detected change for file ${relativePath}`);\n\n let targetFile;\n\n if (isDevLanguageFile(relativePath)) {\n targetFile = path.resolve(cwd, relativePath);\n } else if (isAltLanguageFile(relativePath)) {\n targetFile = getDevLanguageFileFromAltLanguageFile(\n path.resolve(cwd, relativePath),\n );\n }\n\n if (targetFile) {\n watcher.add(targetFile);\n try {\n const loadedTranslation = loadTranslation(\n { filePath: targetFile, fallbacks: 'all' },\n config,\n );\n\n await generateRuntime(loadedTranslation);\n } catch (e) {\n // eslint-disable-next-line no-console\n console.log('Failed to generate types for', relativePath);\n // eslint-disable-next-line no-console\n console.error(e);\n }\n }\n };\n\n const onNewDirectory = async (relativePath: string) => {\n trace('Detected new directory', relativePath);\n\n if (!isTranslationDirectory(relativePath, config)) {\n trace('Ignoring non-translation directory:', relativePath);\n return;\n }\n\n const newFilePath = path.join(relativePath, devTranslationFileName);\n if (!existsSync(newFilePath)) {\n await fs.writeFile(newFilePath, JSON.stringify({}, null, 2));\n trace('Created new empty translation file:', newFilePath);\n } else {\n trace(\n `New directory already contains translation file. Skipping creation. Existing file ${newFilePath}`,\n );\n }\n };\n\n watcher.on('addDir', onNewDirectory);\n watcher.on('add', onTranslationChange).on('change', onTranslationChange);\n\n return () => watcher.close();\n}\n\nexport async function compile(\n { watch: shouldWatch = false } = {},\n config: UserConfig,\n) {\n const translations = await loadAllTranslations(\n { fallbacks: 'all', includeNodeModules: false },\n config,\n );\n\n for (const loadedTranslation of translations) {\n await generateRuntime(loadedTranslation);\n }\n\n if (shouldWatch) {\n trace('Listening for changes to files...');\n return watch(config);\n }\n}\n\nasync function writeIfChanged(filepath: string, contents: string) {\n let hasChanged = true;\n\n try {\n const existingContents = await fs.readFile(filepath, { encoding: 'utf-8' });\n\n hasChanged = existingContents !== contents;\n } catch {\n // ignore error, likely a file doesn't exist error so we want to write anyway\n }\n\n if (hasChanged) {\n await fs.writeFile(filepath, contents, { encoding: 'utf-8' });\n }\n}\n","/* eslint-disable no-console */\nimport type { UserConfig, LoadedTranslation, LanguageName } from '../types';\nimport pc from 'picocolors';\n\nimport { loadAllTranslations } from '../load-translations';\nimport { getAltLanguages } from '../utils';\n\nexport function findMissingKeys(\n loadedTranslation: LoadedTranslation,\n devLanguageName: LanguageName,\n altLanguages: LanguageName[],\n) {\n const devLanguage = loadedTranslation.languages[devLanguageName];\n\n if (!devLanguage) {\n throw new Error(\n `Failed to load dev language: ${loadedTranslation.filePath}`,\n );\n }\n\n const result: Record<LanguageName, string[]> = {};\n let valid = true;\n\n const requiredKeys = Object.keys(devLanguage);\n\n if (requiredKeys.length > 0) {\n for (const altLanguageName of altLanguages) {\n const altLanguage = loadedTranslation.languages[altLanguageName] ?? {};\n\n for (const key of requiredKeys) {\n if (typeof altLanguage[key]?.message !== 'string') {\n if (!result[altLanguageName]) {\n result[altLanguageName] = [];\n }\n\n result[altLanguageName].push(key);\n valid = false;\n }\n }\n }\n }\n return [valid, result] as const;\n}\n\nexport async function validate(config: UserConfig) {\n const allTranslations = await loadAllTranslations(\n { fallbacks: 'valid', includeNodeModules: true },\n config,\n );\n\n let valid = true;\n\n for (const loadedTranslation of allTranslations) {\n const [translationValid, result] = findMissingKeys(\n loadedTranslation,\n config.devLanguage,\n getAltLanguages(config),\n );\n\n if (!translationValid) {\n valid = false;\n console.log(\n pc.red(\n `Incomplete translations: \"${pc.bold(\n loadedTranslation.relativePath,\n )}\"`,\n ),\n );\n\n for (const lang of Object.keys(result)) {\n const missingKeys = result[lang];\n\n console.log(\n pc.yellow(lang),\n '->',\n missingKeys.map((v) => `\"${v}\"`).join(', '),\n );\n }\n }\n }\n\n return valid;\n}\n","export class ValidationError extends Error {\n code: string;\n rawMessage: string;\n constructor(code: string, message: string) {\n super(`Invalid vocab.config.js: ${code} - ${message}`);\n this.code = code;\n this.rawMessage = message;\n }\n}\n","import type { UserConfig } from './types';\nimport path from 'path';\n\nimport pc from 'picocolors';\nimport findUp from 'find-up';\nimport Validator from 'fastest-validator';\nimport { ValidationError } from './ValidationError';\nimport { trace } from './logger';\n\nconst boldCyan = (s: string) => pc.bold(pc.cyan(s));\n\nconst validator = new Validator();\nconst schema = {\n $$strict: true,\n devLanguage: {\n type: 'string',\n },\n languages: {\n type: 'array',\n items: {\n type: 'object',\n props: {\n name: { type: 'string' },\n extends: { type: 'string', optional: true },\n },\n },\n },\n generatedLanguages: {\n type: 'array',\n items: {\n type: 'object',\n props: {\n name: { type: 'string' },\n extends: { type: 'string', optional: true },\n generator: {\n type: 'object',\n props: {\n transformElement: { type: 'function', optional: true },\n transformMessage: { type: 'function', optional: true },\n },\n },\n },\n },\n optional: true,\n },\n translationsDirectorySuffix: { type: 'string', optional: true },\n projectRoot: { type: 'string', optional: true },\n ignore: {\n type: 'array',\n items: 'string',\n optional: true,\n },\n};\nconst checkConfigFile = validator.compile(schema);\n\nconst splitMap = (message: string, callback: (value: string) => string) =>\n message\n .split(' ,')\n .map((v) => callback(v))\n .join(' ,');\n\nexport function validateConfig(c: UserConfig) {\n trace('Validating configuration file');\n // Note: checkConfigFile mutates the config file by applying defaults\n const isValid = checkConfigFile(c);\n if (isValid !== true) {\n throw new ValidationError(\n 'InvalidStructure',\n (Array.isArray(isValid) ? isValid : [])\n .map((v) => {\n if (v.type === 'objectStrict') {\n return `Invalid key(s) ${splitMap(\n v.actual,\n (m) => `\"${pc.cyan(m)}\"`,\n )}. Expected one of ${splitMap(v.expected, pc.green)}`;\n }\n if (v.field) {\n return v.message?.replace(v.field, pc.cyan(v.field));\n }\n return v.message;\n })\n .join(' \\n'),\n );\n }\n\n const languageStrings = c.languages.map((v) => v.name);\n\n // Dev Language should exist in languages\n if (!languageStrings.includes(c.devLanguage)) {\n throw new ValidationError(\n 'InvalidDevLanguage',\n `The dev language \"${boldCyan(\n c.devLanguage,\n )}\" was not found in languages ${languageStrings.join(', ')}.`,\n );\n }\n\n const foundLanguages: string[] = [];\n for (const lang of c.languages) {\n // Languages must only exist once\n if (foundLanguages.includes(lang.name)) {\n throw new ValidationError(\n 'DuplicateLanguage',\n `The language \"${boldCyan(lang.name)}\" was defined multiple times.`,\n );\n }\n foundLanguages.push(lang.name);\n\n // Any extends must be in languages\n if (lang.extends && !languageStrings.includes(lang.extends)) {\n throw new ValidationError(\n 'InvalidExtends',\n `The language \"${boldCyan(lang.name)}\"'s extends of ${boldCyan(\n lang.extends,\n )} was not found in languages ${languageStrings.join(', ')}.`,\n );\n }\n }\n\n const foundGeneratedLanguages: string[] = [];\n for (const generatedLang of c.generatedLanguages || []) {\n // Generated languages must only exist once\n if (foundGeneratedLanguages.includes(generatedLang.name)) {\n throw new ValidationError(\n 'DuplicateGeneratedLanguage',\n `The generated language \"${boldCyan(\n generatedLang.name,\n )}\" was defined multiple times.`,\n );\n }\n foundGeneratedLanguages.push(generatedLang.name);\n\n // Generated language names must not conflict with language names\n if (languageStrings.includes(generatedLang.name)) {\n throw new ValidationError(\n 'InvalidGeneratedLanguage',\n `The generated language \"${boldCyan(\n generatedLang.name,\n )}\" is already defined as a language.`,\n );\n }\n\n // Any extends must be in languages\n if (\n generatedLang.extends &&\n !languageStrings.includes(generatedLang.extends)\n ) {\n throw new ValidationError(\n 'InvalidExtends',\n `The generated language \"${boldCyan(\n generatedLang.name,\n )}\"'s extends of ${boldCyan(\n generatedLang.extends,\n )} was not found in languages ${languageStrings.join(', ')}.`,\n );\n }\n }\n\n trace('Configuration file is valid');\n\n return true;\n}\n\nfunction createConfig(configFilePath: string) {\n const cwd = path.dirname(configFilePath);\n\n return {\n projectRoot: cwd,\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n ...(require(configFilePath) as UserConfig),\n };\n}\n\nexport async function resolveConfig(\n customConfigFilePath?: string,\n): Promise<UserConfig | null> {\n const configFilePath = customConfigFilePath\n ? path.resolve(customConfigFilePath)\n : await findUp(['vocab.config.js', 'vocab.config.cjs']);\n\n if (configFilePath) {\n trace(`Resolved configuration file to ${configFilePath}`);\n return createConfig(configFilePath);\n }\n trace('No configuration file found');\n return null;\n}\n\nexport function resolveConfigSync(\n customConfigFilePath?: string,\n): UserConfig | null {\n const configFilePath = customConfigFilePath\n ? path.resolve(customConfigFilePath)\n : findUp.sync(['vocab.config.js', 'vocab.config.cjs']);\n\n if (configFilePath) {\n trace(`Resolved configuration file to ${configFilePath}`);\n return createConfig(configFilePath);\n }\n trace('No configuration file found');\n\n return null;\n}\n"],"mappings":"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"}
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as TranslationsByLanguage, S as TranslationsByKey, _ as TranslationKeys, a as LoadedTranslation, b as TranslationModule, c as ParsedFormatFnByKey, d as Tags, f as TranslationData, g as TranslationKey, h as TranslationFileMetadata, i as LanguageTarget, l as ParsedICUMessages, m as TranslationFileContents, n as GeneratedLanguageTarget, o as MessageGenerator, p as TranslationFile, r as LanguageName, s as ParsedFormatFn, t as FormatXMLElementFn, u as StringWithSuggestions, v as TranslationMessage, w as UserConfig, x as TranslationModuleByLanguage, y as TranslationMessagesByKey } from "./types-DpryIirw.mjs";
1
+ import { C as TranslationsByLanguage, S as TranslationsByKey, _ as TranslationKeys, a as LoadedTranslation, b as TranslationModule, c as ParsedFormatFnByKey, d as Tags, f as TranslationData, g as TranslationKey, h as TranslationFileMetadata, i as LanguageTarget, l as ParsedICUMessages, m as TranslationFileContents, n as GeneratedLanguageTarget, o as MessageGenerator, p as TranslationFile, r as LanguageName, s as ParsedFormatFn, t as FormatXMLElementFn, u as StringWithSuggestions, v as TranslationMessage, w as UserConfig, x as TranslationModuleByLanguage, y as TranslationMessagesByKey } from "./types-oikDld6a.mjs";
2
2
 
3
3
  //#region src/compile.d.ts
4
4
  declare function watch(config: UserConfig): Promise<() => Promise<void>>;
package/dist/index.mjs CHANGED
@@ -272,6 +272,7 @@ async function loadAllTranslations({ fallbacks, includeNodeModules, withTags },
272
272
  const { projectRoot, ignore = [] } = config;
273
273
  const translationFiles = await glob(getDevTranslationFileGlob(config), {
274
274
  ignore: includeNodeModules ? ignore : [...ignore, "**/node_modules/**"],
275
+ dot: true,
275
276
  absolute: true,
276
277
  cwd: projectRoot,
277
278
  expandDirectories: false
@@ -352,7 +353,7 @@ function serialiseObjectToType(v) {
352
353
  }
353
354
  const serializeTypeImports = (imports, moduleName) => {
354
355
  if (imports.size === 0) return "";
355
- return `import type { ${Array.from(imports).join(", ")} } from '${moduleName}';`;
356
+ return `import type { ${Array.from(imports).sort().join(", ")} } from '${moduleName}';`;
356
357
  };
357
358
  function serialiseTranslationRuntime(value, imports, loadedTranslation) {
358
359
  trace("Serialising translations:", loadedTranslation);
@@ -372,9 +373,8 @@ function serialiseTranslationRuntime(value, imports, loadedTranslation) {
372
373
  // This file is automatically generated by Vocab.
373
374
  // To make changes update translation.json files directly.
374
375
 
375
- ${serializeTypeImports(imports, "@vocab/core")}
376
+ ${serializeTypeImports(new Set([...imports, "TranslationFile"]), "@vocab/core")}
376
377
  import { createLanguage, createTranslationFile } from '@vocab/core/runtime';
377
- import type { TranslationFile } from '@vocab/core';
378
378
 
379
379
  const translations: TranslationFile<
380
380
  ${languagesUnionAsString},
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["newObj: any","generatedTranslations: TranslationsByKey<string>","transformedOptions: Record<string, PluralOrSelectOption>","newLanguage: TranslationsByKey","fallbackLanguageOrder: string[]","validKeys: TranslationsByKey","languageSet: Record<\n string,\n Record<string, { message: string; description?: string | undefined }>\n >","namespace: string","loadedTranslations: LoadedTranslation[]","translationsType: any","params: ICUParams","fs","result: Record<LanguageName, string[]>","foundLanguages: string[]","foundGeneratedLanguages: string[]"],"sources":["../src/logger.ts","../src/utils.ts","../src/generate-language.ts","../src/load-translations.ts","../src/compile.ts","../src/validate/index.ts","../src/ValidationError.ts","../src/config.ts"],"sourcesContent":["import pc from 'picocolors';\nimport debug from 'debug';\n\nexport const trace = debug(`vocab:core`);\n\nexport const log = (...params: unknown[]) => {\n // eslint-disable-next-line no-console\n console.log(pc.yellow('Vocab'), ...params);\n};\n","import path from 'path';\n\nimport type {\n LanguageName,\n LanguageTarget,\n TranslationsByKey,\n TranslationMessagesByKey,\n UserConfig,\n} from './types';\nimport { trace } from './logger';\n\nexport const defaultTranslationDirSuffix = '.vocab';\nexport const devTranslationFileName = 'translations.json';\n\nexport type Fallback = 'none' | 'valid' | 'all';\n\nconst globAnyPathWithOptionalPrefix = '**/?(*)';\n\nexport const compiledVocabFileFilter = /\\.vocab[\\\\/]index\\.(?:ts|js|cjs|mjs)$/;\n\nexport function isDevLanguageFile(filePath: string) {\n return (\n filePath.endsWith(`/${devTranslationFileName}`) ||\n filePath === devTranslationFileName\n );\n}\nexport function isAltLanguageFile(filePath: string) {\n return filePath.endsWith('.translations.json');\n}\nexport function isTranslationDirectory(\n filePath: string,\n {\n translationsDirectorySuffix = defaultTranslationDirSuffix,\n }: {\n translationsDirectorySuffix?: string;\n },\n) {\n return filePath.endsWith(translationsDirectorySuffix);\n}\n\nexport function getDevTranslationFileGlob({\n translationsDirectorySuffix = defaultTranslationDirSuffix,\n}: {\n translationsDirectorySuffix?: string;\n}) {\n const result = `${globAnyPathWithOptionalPrefix}${translationsDirectorySuffix}/${devTranslationFileName}`;\n\n trace('getDevTranslationFileGlob', result);\n\n return result;\n}\n\nexport function getAltTranslationFileGlob(config: UserConfig) {\n const altLanguages = getAltLanguages(config);\n const langMatch =\n altLanguages.length === 1 ? altLanguages[0] : `{${altLanguages.join(',')}}`;\n\n const { translationsDirectorySuffix = defaultTranslationDirSuffix } = config;\n const result = `${globAnyPathWithOptionalPrefix}${translationsDirectorySuffix}/${langMatch}.${devTranslationFileName}`;\n\n trace('getAltTranslationFileGlob', result);\n\n return result;\n}\n\nexport function getAltLanguages({\n devLanguage,\n languages,\n}: {\n devLanguage: LanguageName;\n languages: LanguageTarget[];\n}) {\n return languages.map((v) => v.name).filter((lang) => lang !== devLanguage);\n}\n\nexport function getDevLanguageFileFromTsFile(tsFilePath: string) {\n const directory = path.dirname(tsFilePath);\n const result = path.normalize(path.join(directory, devTranslationFileName));\n\n trace(`Returning dev language path ${result} for path ${tsFilePath}`);\n return result;\n}\n\nexport function getDevLanguageFileFromAltLanguageFile(\n altLanguageFilePath: string,\n) {\n const directory = path.dirname(altLanguageFilePath);\n const result = path.normalize(path.join(directory, devTranslationFileName));\n trace(\n `Returning dev language path ${result} for path ${altLanguageFilePath}`,\n );\n return result;\n}\n\nexport function getTSFileFromDevLanguageFile(devLanguageFilePath: string) {\n const directory = path.dirname(devLanguageFilePath);\n const result = path.normalize(path.join(directory, 'index.ts'));\n\n trace(`Returning TS path ${result} for path ${devLanguageFilePath}`);\n return result;\n}\n\nexport function getAltLanguageFilePath(\n devLanguageFilePath: string,\n language: string,\n) {\n const directory = path.dirname(devLanguageFilePath);\n const result = path.normalize(\n path.join(directory, `${language}.translations.json`),\n );\n trace(\n `Returning alt language path ${result} for path ${devLanguageFilePath}`,\n );\n return path.normalize(result);\n}\n\nexport function mapValues<Key extends string, OriginalValue, ReturnValue>(\n obj: Record<Key, OriginalValue>,\n func: (val: OriginalValue) => ReturnValue,\n): TranslationMessagesByKey<Key> {\n const newObj: any = {};\n const keys = Object.keys(obj) as Key[];\n for (const key of keys) {\n newObj[key] = func(obj[key]);\n }\n return newObj;\n}\n\nexport function getTranslationMessages<Key extends string>(\n translations: TranslationsByKey<Key>,\n): TranslationMessagesByKey<Key> {\n return mapValues(translations, (v) => v.message);\n}\n","import { IntlMessageFormat } from 'intl-messageformat';\nimport {\n type MessageFormatElement,\n type PluralOrSelectOption,\n TYPE,\n} from '@formatjs/icu-messageformat-parser';\nimport { printAST } from '@formatjs/icu-messageformat-parser/printer.js';\nimport type { MessageGenerator, TranslationsByKey } from './types';\n\nexport function generateLanguageFromTranslations({\n baseTranslations,\n generator,\n}: {\n baseTranslations: TranslationsByKey<string>;\n generator: MessageGenerator;\n}): TranslationsByKey<string> {\n if (!generator.transformElement && !generator.transformMessage) {\n return baseTranslations;\n }\n\n const translationKeys = Object.keys(baseTranslations);\n const generatedTranslations: TranslationsByKey<string> = {};\n\n for (const translationKey of translationKeys) {\n const translation = baseTranslations[translationKey];\n let transformedMessage = translation.message;\n\n if (generator.transformElement) {\n const messageAst = new IntlMessageFormat(translation.message).getAst();\n const transformedAst = messageAst.map(\n transformMessageFormatElement(generator.transformElement),\n );\n transformedMessage = printAST(transformedAst);\n }\n\n if (generator.transformMessage) {\n transformedMessage = generator.transformMessage(transformedMessage);\n }\n\n generatedTranslations[translationKey] = {\n message: transformedMessage,\n };\n }\n\n return generatedTranslations;\n}\n\nfunction transformMessageFormatElement(\n transformElement: (message: string) => string,\n): (messageFormatElement: MessageFormatElement) => MessageFormatElement {\n return (messageFormatElement: MessageFormatElement) => {\n const transformedMessageFormatElement = { ...messageFormatElement };\n\n switch (transformedMessageFormatElement.type) {\n case TYPE.literal:\n const transformedValue = transformElement(\n transformedMessageFormatElement.value,\n );\n transformedMessageFormatElement.value = transformedValue;\n break;\n\n case TYPE.select:\n case TYPE.plural:\n const transformedOptions: Record<string, PluralOrSelectOption> = {\n ...transformedMessageFormatElement.options,\n };\n\n for (const key of Object.keys(transformedOptions)) {\n transformedOptions[key].value = transformedOptions[key].value.map(\n transformMessageFormatElement(transformElement),\n );\n }\n\n break;\n\n case TYPE.tag:\n const transformedChildren =\n transformedMessageFormatElement.children.map(\n transformMessageFormatElement(transformElement),\n );\n transformedMessageFormatElement.children = transformedChildren;\n break;\n\n default:\n break;\n }\n\n return transformedMessageFormatElement;\n };\n}\n","import path from 'path';\n\nimport { glob } from 'tinyglobby';\nimport type {\n TranslationsByKey,\n UserConfig,\n LoadedTranslation,\n LanguageTarget,\n LanguageName,\n TranslationFileMetadata,\n TranslationFileContents,\n} from './types';\nimport pc from 'picocolors';\n\nimport { trace } from './logger';\nimport {\n defaultTranslationDirSuffix,\n type Fallback,\n getAltLanguageFilePath,\n getAltLanguages,\n getDevTranslationFileGlob,\n} from './utils';\nimport { generateLanguageFromTranslations } from './generate-language';\n\nexport function getUniqueKey(key: string, namespace: string) {\n return `${key}.${namespace}`;\n}\n\nexport function mergeWithDevLanguageTranslation({\n translation,\n devTranslation,\n}: {\n translation: TranslationsByKey;\n devTranslation: TranslationsByKey;\n}) {\n // Only use keys from the dev translation\n const keys = Object.keys(devTranslation);\n const newLanguage: TranslationsByKey = {};\n\n for (const key of keys) {\n if (translation[key]) {\n newLanguage[key] = {\n message: translation[key].message,\n description: devTranslation[key].description,\n };\n }\n }\n\n return newLanguage;\n}\n\nfunction getLanguageFallbacks({ languages }: { languages: LanguageTarget[] }) {\n const languageFallbackMap = new Map<LanguageName, LanguageName>();\n\n for (const lang of languages) {\n if (lang.extends) {\n languageFallbackMap.set(lang.name, lang.extends);\n }\n }\n\n return languageFallbackMap;\n}\n\nexport function getLanguageHierarchy({\n languages,\n}: {\n languages: LanguageTarget[];\n}) {\n const hierarchyMap = new Map<LanguageName, LanguageName[]>();\n const fallbacks = getLanguageFallbacks({ languages });\n\n for (const lang of languages) {\n const langHierarchy = [];\n let currLang = lang.extends;\n\n while (currLang) {\n langHierarchy.push(currLang);\n\n currLang = fallbacks.get(currLang);\n }\n\n hierarchyMap.set(lang.name, langHierarchy);\n }\n\n return hierarchyMap;\n}\n\nexport function getFallbackLanguageOrder({\n languages,\n languageName,\n devLanguage,\n fallbacks,\n}: {\n languages: LanguageTarget[];\n languageName: string;\n devLanguage: string;\n fallbacks: Fallback;\n}) {\n const languageHierarchy = getLanguageHierarchy({ languages }).get(\n languageName,\n );\n\n if (!languageHierarchy) {\n throw new Error(`Missing language hierarchy for ${languageName}`);\n }\n\n const fallbackLanguageOrder: string[] = [languageName];\n\n if (fallbacks !== 'none') {\n fallbackLanguageOrder.unshift(...languageHierarchy.reverse());\n\n if (fallbacks === 'all' && fallbackLanguageOrder[0] !== devLanguage) {\n fallbackLanguageOrder.unshift(devLanguage);\n }\n }\n\n return fallbackLanguageOrder;\n}\n\nfunction getNamespaceByFilePath(\n relativePath: string,\n { translationsDirectorySuffix = defaultTranslationDirSuffix }: UserConfig,\n) {\n let namespace = path\n .dirname(relativePath)\n .replace(/^src\\//, '')\n .replace(/\\//g, '_');\n\n if (namespace.endsWith(translationsDirectorySuffix)) {\n namespace = namespace.slice(0, -translationsDirectorySuffix.length);\n }\n\n return namespace;\n}\n\nfunction printValidationError(...params: unknown[]) {\n // eslint-disable-next-line no-console\n console.error(pc.red('Error loading translation:'), ...params);\n}\n\nfunction getTranslationsFromFile(\n translationFileContents: unknown,\n {\n isAltLanguage,\n filePath,\n withTags,\n }: { isAltLanguage: boolean; filePath: string; withTags?: boolean },\n): {\n $namespace: unknown;\n keys: TranslationsByKey;\n metadata: TranslationFileMetadata;\n} {\n if (!translationFileContents || typeof translationFileContents !== 'object') {\n throw new Error(\n `Unable to read translation file ${filePath}. Translations must be an object.`,\n );\n }\n\n const { $namespace, _meta, ...keys } =\n translationFileContents as TranslationFileContents;\n\n if (isAltLanguage && $namespace) {\n printValidationError(\n `Found $namespace in alt language file in ${filePath}. $namespace is only used in the dev language and will be ignored.`,\n );\n }\n\n if (!isAltLanguage && $namespace && typeof $namespace !== 'string') {\n printValidationError(\n `Found non-string $namespace in language file in ${filePath}. $namespace must be a string.`,\n );\n }\n\n if (isAltLanguage && _meta?.tags) {\n printValidationError(\n `Found _meta.tags in alt language file in ${filePath}. _meta.tags is only used in the dev language and will be ignored.`,\n );\n }\n\n // Never return tags if we're fetching translations for an alt language\n const includeTags = !isAltLanguage && withTags;\n const validKeys: TranslationsByKey = {};\n\n for (const [translationKey, { tags, ...translation }] of Object.entries(\n keys,\n )) {\n if (typeof translation === 'string') {\n printValidationError(\n `Found string for a translation \"${translationKey}\" in ${filePath}. Translation must be an object of the format {message: string}.`,\n );\n continue;\n }\n\n if (!translation) {\n printValidationError(\n `Found empty translation \"${translationKey}\" in ${filePath}. Translation must be an object of the format {message: string}.`,\n );\n continue;\n }\n\n if (!translation.message || typeof translation.message !== 'string') {\n printValidationError(\n `No message found for translation \"${translationKey}\" in ${filePath}. Translation must be an object of the format {message: string}.`,\n );\n continue;\n }\n\n validKeys[translationKey] = {\n ...translation,\n tags: includeTags ? tags : undefined,\n };\n }\n\n const metadata = { tags: includeTags ? _meta?.tags : undefined };\n\n return { $namespace, keys: validKeys, metadata };\n}\n\nexport function loadAltLanguageFile(\n {\n filePath,\n languageName,\n devTranslation,\n fallbacks,\n }: {\n filePath: string;\n languageName: string;\n devTranslation: TranslationsByKey;\n fallbacks: Fallback;\n },\n { devLanguage, languages }: UserConfig,\n): TranslationsByKey {\n const altLanguageTranslation = {};\n\n const fallbackLanguageOrder = getFallbackLanguageOrder({\n languages,\n languageName,\n devLanguage,\n fallbacks,\n });\n\n trace(\n `Loading alt language file with precedence: ${fallbackLanguageOrder\n .slice()\n .reverse()\n .join(' -> ')}`,\n );\n\n for (const fallbackLanguage of fallbackLanguageOrder) {\n if (fallbackLanguage !== devLanguage) {\n try {\n const altFilePath = getAltLanguageFilePath(filePath, fallbackLanguage);\n delete require.cache[altFilePath];\n\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const translationFile = require(altFilePath);\n const { keys: fallbackLanguageTranslation } = getTranslationsFromFile(\n translationFile,\n {\n filePath: altFilePath,\n isAltLanguage: true,\n },\n );\n Object.assign(\n altLanguageTranslation,\n mergeWithDevLanguageTranslation({\n translation: fallbackLanguageTranslation,\n devTranslation,\n }),\n );\n } catch {\n trace(`Missing alt language file ${getAltLanguageFilePath(\n filePath,\n fallbackLanguage,\n )}\n `);\n }\n } else {\n Object.assign(altLanguageTranslation, devTranslation);\n }\n }\n\n return altLanguageTranslation;\n}\n\nfunction stripTagsFromTranslations(translations: TranslationsByKey) {\n return Object.fromEntries(\n Object.entries(translations).map(([key, { tags, ...rest }]) => [key, rest]),\n );\n}\n\nexport function loadTranslation(\n {\n filePath,\n fallbacks,\n withTags,\n }: {\n filePath: string;\n fallbacks: Fallback;\n withTags?: boolean;\n },\n userConfig: UserConfig,\n): LoadedTranslation {\n trace(\n `Loading translation file in \"${fallbacks}\" fallback mode: \"${filePath}\"`,\n );\n\n const languageSet: Record<\n string,\n Record<string, { message: string; description?: string | undefined }>\n > = {};\n\n delete require.cache[filePath];\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const translationContent = require(filePath);\n const relativePath = path.relative(\n userConfig.projectRoot || process.cwd(),\n filePath,\n );\n const {\n $namespace,\n keys: devTranslation,\n metadata,\n } = getTranslationsFromFile(translationContent, {\n filePath,\n isAltLanguage: false,\n withTags,\n });\n const namespace: string =\n typeof $namespace === 'string'\n ? $namespace\n : getNamespaceByFilePath(relativePath, userConfig);\n\n trace(`Found file ${filePath}. Using namespace ${namespace}`);\n\n languageSet[userConfig.devLanguage] = devTranslation;\n\n const devTranslationNoTags = withTags\n ? stripTagsFromTranslations(devTranslation)\n : devTranslation;\n const altLanguages = getAltLanguages(userConfig);\n for (const languageName of altLanguages) {\n languageSet[languageName] = loadAltLanguageFile(\n {\n filePath,\n languageName,\n devTranslation: devTranslationNoTags,\n fallbacks,\n },\n userConfig,\n );\n }\n\n for (const generatedLanguage of userConfig.generatedLanguages || []) {\n const { name: generatedLanguageName, generator } = generatedLanguage;\n const baseLanguage = generatedLanguage.extends || userConfig.devLanguage;\n const baseTranslations = languageSet[baseLanguage];\n\n languageSet[generatedLanguageName] = generateLanguageFromTranslations({\n baseTranslations,\n generator,\n });\n }\n\n return {\n filePath,\n keys: Object.keys(devTranslation),\n namespace,\n relativePath,\n languages: languageSet,\n metadata,\n };\n}\n\nexport async function loadAllTranslations(\n {\n fallbacks,\n includeNodeModules,\n withTags,\n }: { fallbacks: Fallback; includeNodeModules: boolean; withTags?: boolean },\n config: UserConfig,\n): Promise<LoadedTranslation[]> {\n const { projectRoot, ignore = [] } = config;\n\n const translationFiles = await glob(getDevTranslationFileGlob(config), {\n ignore: includeNodeModules ? ignore : [...ignore, '**/node_modules/**'],\n absolute: true,\n cwd: projectRoot,\n expandDirectories: false,\n });\n\n trace(`Found ${translationFiles.length} translation files`);\n\n const loadedTranslations: LoadedTranslation[] = [];\n const keys = new Set<string>();\n\n for (const translationFile of translationFiles) {\n const loadedTranslation = loadTranslation(\n { filePath: translationFile, fallbacks, withTags },\n config,\n );\n\n loadedTranslations.push(loadedTranslation);\n\n for (const key of loadedTranslation.keys) {\n const uniqueKey = getUniqueKey(key, loadedTranslation.namespace);\n if (keys.has(uniqueKey)) {\n trace(`Duplicate keys found`);\n throw new Error(\n `Duplicate keys found. Key with namespace ${loadedTranslation.namespace} and key ${key} was found multiple times.`,\n );\n }\n keys.add(uniqueKey);\n\n const globalKey =\n loadedTranslation.languages[config.devLanguage][key].globalKey;\n if (globalKey) {\n if (keys.has(globalKey)) {\n throw new Error(\n `Duplicate keys found. Key with global key ${globalKey} and key ${key} was found multiple times`,\n );\n }\n keys.add(globalKey);\n }\n }\n }\n\n return loadedTranslations;\n}\n","import { promises as fs, existsSync } from 'fs';\nimport path from 'path';\nimport pm from 'picomatch';\n\nimport type { LoadedTranslation, UserConfig } from './types';\nimport {\n isArgumentElement,\n isDateElement,\n isNumberElement,\n isPluralElement,\n isSelectElement,\n isTagElement,\n isTimeElement,\n type MessageFormatElement,\n parse,\n} from '@formatjs/icu-messageformat-parser';\nimport prettier from 'prettier';\n\nimport {\n getTranslationMessages,\n getDevTranslationFileGlob,\n getTSFileFromDevLanguageFile,\n getDevLanguageFileFromAltLanguageFile,\n getAltTranslationFileGlob,\n isDevLanguageFile,\n isAltLanguageFile,\n devTranslationFileName,\n isTranslationDirectory,\n} from './utils';\nimport { trace } from './logger';\nimport { loadAllTranslations, loadTranslation } from './load-translations';\n\ntype ICUParams = Record<string, string>;\n\ninterface TranslationTypeInfo {\n params: ICUParams;\n message: string;\n hasTags: boolean;\n}\n\nfunction extractHasTags(ast: MessageFormatElement[]): boolean {\n return ast.some((element) => {\n if (isSelectElement(element) || isPluralElement(element)) {\n const children = Object.values(element.options).map((o) => o.value);\n return children.some((child) => extractHasTags(child));\n }\n\n return isTagElement(element);\n });\n}\n\nfunction extractParamTypes(\n ast: MessageFormatElement[],\n currentParams: ICUParams,\n): [params: ICUParams, vocabTypesImports: Set<string>] {\n let params = { ...currentParams };\n let vocabTypesImports = new Set<string>();\n\n for (const element of ast) {\n if (isArgumentElement(element)) {\n if (!(element.value in params)) {\n // Preserve existing types for parameters that we've already parsed\n // This applies to self-referential parameters, for example `{foo, plural, 1 {{foo} thing} other {{foo} things}}`\n params[element.value] = 'string';\n }\n } else if (isNumberElement(element)) {\n params[element.value] = 'number';\n } else if (isPluralElement(element)) {\n params[element.value] = 'number';\n\n const children = Object.values(element.options).map((o) => o.value);\n\n for (const child of children) {\n const [newParams, subImports] = extractParamTypes(child, params);\n\n vocabTypesImports = new Set([...vocabTypesImports, ...subImports]);\n params = newParams;\n }\n } else if (isDateElement(element) || isTimeElement(element)) {\n params[element.value] = 'Date | number';\n } else if (isTagElement(element)) {\n params[element.value] = 'FormatXMLElementFn<T>';\n vocabTypesImports.add('FormatXMLElementFn');\n\n const [newParams, subImports] = extractParamTypes(\n element.children,\n params,\n );\n\n vocabTypesImports = new Set([...vocabTypesImports, ...subImports]);\n params = newParams;\n } else if (isSelectElement(element)) {\n const options = Object.keys(element.options);\n\n // `other` will always be an option as the parser enforces this by default\n const nonOtherOptions = options.filter((o) => o !== 'other');\n const nonOtherOptionsUnion = nonOtherOptions\n .map((o) => `'${o}'`)\n .join(' | ');\n\n params[element.value] = `StringWithSuggestions<${nonOtherOptionsUnion}>`;\n vocabTypesImports.add('StringWithSuggestions');\n\n const children = Object.values(element.options).map((o) => o.value);\n\n for (const child of children) {\n const [newParams, subImports] = extractParamTypes(child, params);\n\n vocabTypesImports = new Set([...vocabTypesImports, ...subImports]);\n params = newParams;\n }\n }\n }\n\n return [params, vocabTypesImports];\n}\n\nfunction serialiseObjectToType(v: any) {\n let result = '';\n\n for (const [key, value] of Object.entries(v)) {\n result += `${JSON.stringify(key)}: ${\n value && typeof value === 'object' ? serialiseObjectToType(value) : value\n },`;\n }\n\n return `{ ${result} }`;\n}\n\nconst serializeTypeImports = (imports: Set<string>, moduleName: string) => {\n if (imports.size === 0) {\n return '';\n }\n\n const importNames = Array.from(imports);\n return `import type { ${importNames.join(', ')} } from '${moduleName}';`;\n};\n\nfunction serialiseTranslationRuntime(\n value: Map<string, TranslationTypeInfo>,\n imports: Set<string>,\n loadedTranslation: LoadedTranslation,\n) {\n trace('Serialising translations:', loadedTranslation);\n const translationsType: any = {};\n\n for (const [key, { params, message, hasTags }] of value.entries()) {\n let translationFunctionString = `() => ${message}`;\n\n if (Object.keys(params).length > 0) {\n const formatGeneric = hasTags ? '<T = string>' : '';\n const formatReturn =\n hasTags && imports.has('FormatXMLElementFn')\n ? 'ReturnType<FormatXMLElementFn<T>>'\n : 'string';\n translationFunctionString = `${formatGeneric}(values: ${serialiseObjectToType(\n params,\n )}) => ${formatReturn}`;\n }\n\n translationsType[key] = translationFunctionString;\n }\n\n const languagesUnionAsString = Object.keys(loadedTranslation.languages)\n .map((l) => `'${l}'`)\n .join(' | ');\n const languageEntries = Object.entries(loadedTranslation.languages)\n .map(\n ([languageName, translations]) =>\n `${JSON.stringify(languageName)}: createLanguage(${JSON.stringify(\n getTranslationMessages(translations),\n )})`,\n )\n .join(',');\n\n return /* ts */ `\n // This file is automatically generated by Vocab.\n // To make changes update translation.json files directly.\n\n ${serializeTypeImports(imports, '@vocab/core')}\n import { createLanguage, createTranslationFile } from '@vocab/core/runtime';\n import type { TranslationFile } from '@vocab/core';\n\n const translations: TranslationFile<\n ${languagesUnionAsString},\n ${serialiseObjectToType(translationsType)}\n > = createTranslationFile\n ({\n ${languageEntries}\n });\n\n export default translations;\n `;\n}\n\nexport async function generateRuntime(loadedTranslation: LoadedTranslation) {\n const { languages: loadedLanguages, filePath } = loadedTranslation;\n\n trace('Generating types for', filePath);\n const translationTypes = new Map<string, TranslationTypeInfo>();\n\n let imports = new Set<string>();\n\n for (const key of loadedTranslation.keys) {\n let params: ICUParams = {};\n const messages = new Set();\n let hasTags = false;\n\n for (const translatedLanguage of Object.values(loadedLanguages)) {\n if (translatedLanguage[key]) {\n const ast = parse(translatedLanguage[key].message);\n\n hasTags = hasTags || extractHasTags(ast);\n\n const [parsedParams, vocabTypesImports] = extractParamTypes(\n ast,\n params,\n );\n\n imports = new Set([...imports, ...vocabTypesImports]);\n params = parsedParams;\n\n messages.add(JSON.stringify(translatedLanguage[key].message));\n }\n }\n\n translationTypes.set(key, {\n params,\n hasTags,\n message: Array.from(messages).join(' | '),\n });\n }\n\n const prettierConfig = await prettier.resolveConfig(filePath);\n const serializedTranslationType = serialiseTranslationRuntime(\n translationTypes,\n imports,\n loadedTranslation,\n );\n const declaration = await prettier.format(serializedTranslationType, {\n ...prettierConfig,\n parser: 'typescript',\n });\n const outputFilePath = getTSFileFromDevLanguageFile(filePath);\n trace(`Writing translation types to ${outputFilePath}`);\n await writeIfChanged(outputFilePath, declaration);\n}\n\nexport async function watch(config: UserConfig) {\n const cwd = config.projectRoot || process.cwd();\n\n const ignorePatterns = [\n ...(config.ignore || []),\n '**/node_modules/**',\n '**/.git/**',\n ];\n\n const ignoredFunction = (pathToCheck: string) =>\n pm.isMatch(pathToCheck, ignorePatterns);\n\n const chokidar = await import('chokidar');\n const watcher = chokidar.watch(cwd, {\n ignored: ignoredFunction,\n ignoreInitial: true,\n });\n\n const devFileGlob = getDevTranslationFileGlob(config);\n const altFileGlob = getAltTranslationFileGlob(config);\n\n const onTranslationChange = async (relativePath: string) => {\n const matchesTranslationFiles = pm.isMatch(relativePath, [\n devFileGlob,\n altFileGlob,\n ]);\n\n if (!matchesTranslationFiles) {\n return;\n }\n\n trace(`Detected change for file ${relativePath}`);\n\n let targetFile;\n\n if (isDevLanguageFile(relativePath)) {\n targetFile = path.resolve(cwd, relativePath);\n } else if (isAltLanguageFile(relativePath)) {\n targetFile = getDevLanguageFileFromAltLanguageFile(\n path.resolve(cwd, relativePath),\n );\n }\n\n if (targetFile) {\n watcher.add(targetFile);\n try {\n const loadedTranslation = loadTranslation(\n { filePath: targetFile, fallbacks: 'all' },\n config,\n );\n\n await generateRuntime(loadedTranslation);\n } catch (e) {\n // eslint-disable-next-line no-console\n console.log('Failed to generate types for', relativePath);\n // eslint-disable-next-line no-console\n console.error(e);\n }\n }\n };\n\n const onNewDirectory = async (relativePath: string) => {\n trace('Detected new directory', relativePath);\n\n if (!isTranslationDirectory(relativePath, config)) {\n trace('Ignoring non-translation directory:', relativePath);\n return;\n }\n\n const newFilePath = path.join(relativePath, devTranslationFileName);\n if (!existsSync(newFilePath)) {\n await fs.writeFile(newFilePath, JSON.stringify({}, null, 2));\n trace('Created new empty translation file:', newFilePath);\n } else {\n trace(\n `New directory already contains translation file. Skipping creation. Existing file ${newFilePath}`,\n );\n }\n };\n\n watcher.on('addDir', onNewDirectory);\n watcher.on('add', onTranslationChange).on('change', onTranslationChange);\n\n return () => watcher.close();\n}\n\nexport async function compile(\n { watch: shouldWatch = false } = {},\n config: UserConfig,\n) {\n const translations = await loadAllTranslations(\n { fallbacks: 'all', includeNodeModules: false },\n config,\n );\n\n for (const loadedTranslation of translations) {\n await generateRuntime(loadedTranslation);\n }\n\n if (shouldWatch) {\n trace('Listening for changes to files...');\n return watch(config);\n }\n}\n\nasync function writeIfChanged(filepath: string, contents: string) {\n let hasChanged = true;\n\n try {\n const existingContents = await fs.readFile(filepath, { encoding: 'utf-8' });\n\n hasChanged = existingContents !== contents;\n } catch {\n // ignore error, likely a file doesn't exist error so we want to write anyway\n }\n\n if (hasChanged) {\n await fs.writeFile(filepath, contents, { encoding: 'utf-8' });\n }\n}\n","/* eslint-disable no-console */\nimport type { UserConfig, LoadedTranslation, LanguageName } from '../types';\nimport pc from 'picocolors';\n\nimport { loadAllTranslations } from '../load-translations';\nimport { getAltLanguages } from '../utils';\n\nexport function findMissingKeys(\n loadedTranslation: LoadedTranslation,\n devLanguageName: LanguageName,\n altLanguages: LanguageName[],\n) {\n const devLanguage = loadedTranslation.languages[devLanguageName];\n\n if (!devLanguage) {\n throw new Error(\n `Failed to load dev language: ${loadedTranslation.filePath}`,\n );\n }\n\n const result: Record<LanguageName, string[]> = {};\n let valid = true;\n\n const requiredKeys = Object.keys(devLanguage);\n\n if (requiredKeys.length > 0) {\n for (const altLanguageName of altLanguages) {\n const altLanguage = loadedTranslation.languages[altLanguageName] ?? {};\n\n for (const key of requiredKeys) {\n if (typeof altLanguage[key]?.message !== 'string') {\n if (!result[altLanguageName]) {\n result[altLanguageName] = [];\n }\n\n result[altLanguageName].push(key);\n valid = false;\n }\n }\n }\n }\n return [valid, result] as const;\n}\n\nexport async function validate(config: UserConfig) {\n const allTranslations = await loadAllTranslations(\n { fallbacks: 'valid', includeNodeModules: true },\n config,\n );\n\n let valid = true;\n\n for (const loadedTranslation of allTranslations) {\n const [translationValid, result] = findMissingKeys(\n loadedTranslation,\n config.devLanguage,\n getAltLanguages(config),\n );\n\n if (!translationValid) {\n valid = false;\n console.log(\n pc.red(\n `Incomplete translations: \"${pc.bold(\n loadedTranslation.relativePath,\n )}\"`,\n ),\n );\n\n for (const lang of Object.keys(result)) {\n const missingKeys = result[lang];\n\n console.log(\n pc.yellow(lang),\n '->',\n missingKeys.map((v) => `\"${v}\"`).join(', '),\n );\n }\n }\n }\n\n return valid;\n}\n","export class ValidationError extends Error {\n code: string;\n rawMessage: string;\n constructor(code: string, message: string) {\n super(`Invalid vocab.config.js: ${code} - ${message}`);\n this.code = code;\n this.rawMessage = message;\n }\n}\n","import type { UserConfig } from './types';\nimport path from 'path';\n\nimport pc from 'picocolors';\nimport findUp from 'find-up';\nimport Validator from 'fastest-validator';\nimport { ValidationError } from './ValidationError';\nimport { trace } from './logger';\n\nconst boldCyan = (s: string) => pc.bold(pc.cyan(s));\n\nconst validator = new Validator();\nconst schema = {\n $$strict: true,\n devLanguage: {\n type: 'string',\n },\n languages: {\n type: 'array',\n items: {\n type: 'object',\n props: {\n name: { type: 'string' },\n extends: { type: 'string', optional: true },\n },\n },\n },\n generatedLanguages: {\n type: 'array',\n items: {\n type: 'object',\n props: {\n name: { type: 'string' },\n extends: { type: 'string', optional: true },\n generator: {\n type: 'object',\n props: {\n transformElement: { type: 'function', optional: true },\n transformMessage: { type: 'function', optional: true },\n },\n },\n },\n },\n optional: true,\n },\n translationsDirectorySuffix: { type: 'string', optional: true },\n projectRoot: { type: 'string', optional: true },\n ignore: {\n type: 'array',\n items: 'string',\n optional: true,\n },\n};\nconst checkConfigFile = validator.compile(schema);\n\nconst splitMap = (message: string, callback: (value: string) => string) =>\n message\n .split(' ,')\n .map((v) => callback(v))\n .join(' ,');\n\nexport function validateConfig(c: UserConfig) {\n trace('Validating configuration file');\n // Note: checkConfigFile mutates the config file by applying defaults\n const isValid = checkConfigFile(c);\n if (isValid !== true) {\n throw new ValidationError(\n 'InvalidStructure',\n (Array.isArray(isValid) ? isValid : [])\n .map((v) => {\n if (v.type === 'objectStrict') {\n return `Invalid key(s) ${splitMap(\n v.actual,\n (m) => `\"${pc.cyan(m)}\"`,\n )}. Expected one of ${splitMap(v.expected, pc.green)}`;\n }\n if (v.field) {\n return v.message?.replace(v.field, pc.cyan(v.field));\n }\n return v.message;\n })\n .join(' \\n'),\n );\n }\n\n const languageStrings = c.languages.map((v) => v.name);\n\n // Dev Language should exist in languages\n if (!languageStrings.includes(c.devLanguage)) {\n throw new ValidationError(\n 'InvalidDevLanguage',\n `The dev language \"${boldCyan(\n c.devLanguage,\n )}\" was not found in languages ${languageStrings.join(', ')}.`,\n );\n }\n\n const foundLanguages: string[] = [];\n for (const lang of c.languages) {\n // Languages must only exist once\n if (foundLanguages.includes(lang.name)) {\n throw new ValidationError(\n 'DuplicateLanguage',\n `The language \"${boldCyan(lang.name)}\" was defined multiple times.`,\n );\n }\n foundLanguages.push(lang.name);\n\n // Any extends must be in languages\n if (lang.extends && !languageStrings.includes(lang.extends)) {\n throw new ValidationError(\n 'InvalidExtends',\n `The language \"${boldCyan(lang.name)}\"'s extends of ${boldCyan(\n lang.extends,\n )} was not found in languages ${languageStrings.join(', ')}.`,\n );\n }\n }\n\n const foundGeneratedLanguages: string[] = [];\n for (const generatedLang of c.generatedLanguages || []) {\n // Generated languages must only exist once\n if (foundGeneratedLanguages.includes(generatedLang.name)) {\n throw new ValidationError(\n 'DuplicateGeneratedLanguage',\n `The generated language \"${boldCyan(\n generatedLang.name,\n )}\" was defined multiple times.`,\n );\n }\n foundGeneratedLanguages.push(generatedLang.name);\n\n // Generated language names must not conflict with language names\n if (languageStrings.includes(generatedLang.name)) {\n throw new ValidationError(\n 'InvalidGeneratedLanguage',\n `The generated language \"${boldCyan(\n generatedLang.name,\n )}\" is already defined as a language.`,\n );\n }\n\n // Any extends must be in languages\n if (\n generatedLang.extends &&\n !languageStrings.includes(generatedLang.extends)\n ) {\n throw new ValidationError(\n 'InvalidExtends',\n `The generated language \"${boldCyan(\n generatedLang.name,\n )}\"'s extends of ${boldCyan(\n generatedLang.extends,\n )} was not found in languages ${languageStrings.join(', ')}.`,\n );\n }\n }\n\n trace('Configuration file is valid');\n\n return true;\n}\n\nfunction createConfig(configFilePath: string) {\n const cwd = path.dirname(configFilePath);\n\n return {\n projectRoot: cwd,\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n ...(require(configFilePath) as UserConfig),\n };\n}\n\nexport async function resolveConfig(\n customConfigFilePath?: string,\n): Promise<UserConfig | null> {\n const configFilePath = customConfigFilePath\n ? path.resolve(customConfigFilePath)\n : await findUp(['vocab.config.js', 'vocab.config.cjs']);\n\n if (configFilePath) {\n trace(`Resolved configuration file to ${configFilePath}`);\n return createConfig(configFilePath);\n }\n trace('No configuration file found');\n return null;\n}\n\nexport function resolveConfigSync(\n customConfigFilePath?: string,\n): UserConfig | null {\n const configFilePath = customConfigFilePath\n ? path.resolve(customConfigFilePath)\n : findUp.sync(['vocab.config.js', 'vocab.config.cjs']);\n\n if (configFilePath) {\n trace(`Resolved configuration file to ${configFilePath}`);\n return createConfig(configFilePath);\n }\n trace('No configuration file found');\n\n return null;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["newObj: any","generatedTranslations: TranslationsByKey<string>","transformedOptions: Record<string, PluralOrSelectOption>","newLanguage: TranslationsByKey","fallbackLanguageOrder: string[]","validKeys: TranslationsByKey","languageSet: Record<\n string,\n Record<string, { message: string; description?: string | undefined }>\n >","namespace: string","loadedTranslations: LoadedTranslation[]","translationsType: any","params: ICUParams","fs","result: Record<LanguageName, string[]>","foundLanguages: string[]","foundGeneratedLanguages: string[]"],"sources":["../src/logger.ts","../src/utils.ts","../src/generate-language.ts","../src/load-translations.ts","../src/compile.ts","../src/validate/index.ts","../src/ValidationError.ts","../src/config.ts"],"sourcesContent":["import pc from 'picocolors';\nimport debug from 'debug';\n\nexport const trace = debug(`vocab:core`);\n\nexport const log = (...params: unknown[]) => {\n // eslint-disable-next-line no-console\n console.log(pc.yellow('Vocab'), ...params);\n};\n","import path from 'path';\n\nimport type {\n LanguageName,\n LanguageTarget,\n TranslationsByKey,\n TranslationMessagesByKey,\n UserConfig,\n} from './types';\nimport { trace } from './logger';\n\nexport const defaultTranslationDirSuffix = '.vocab';\nexport const devTranslationFileName = 'translations.json';\n\nexport type Fallback = 'none' | 'valid' | 'all';\n\nconst globAnyPathWithOptionalPrefix = '**/?(*)';\n\nexport const compiledVocabFileFilter = /\\.vocab[\\\\/]index\\.(?:ts|js|cjs|mjs)$/;\n\nexport function isDevLanguageFile(filePath: string) {\n return (\n filePath.endsWith(`/${devTranslationFileName}`) ||\n filePath === devTranslationFileName\n );\n}\nexport function isAltLanguageFile(filePath: string) {\n return filePath.endsWith('.translations.json');\n}\nexport function isTranslationDirectory(\n filePath: string,\n {\n translationsDirectorySuffix = defaultTranslationDirSuffix,\n }: {\n translationsDirectorySuffix?: string;\n },\n) {\n return filePath.endsWith(translationsDirectorySuffix);\n}\n\nexport function getDevTranslationFileGlob({\n translationsDirectorySuffix = defaultTranslationDirSuffix,\n}: {\n translationsDirectorySuffix?: string;\n}) {\n const result = `${globAnyPathWithOptionalPrefix}${translationsDirectorySuffix}/${devTranslationFileName}`;\n\n trace('getDevTranslationFileGlob', result);\n\n return result;\n}\n\nexport function getAltTranslationFileGlob(config: UserConfig) {\n const altLanguages = getAltLanguages(config);\n const langMatch =\n altLanguages.length === 1 ? altLanguages[0] : `{${altLanguages.join(',')}}`;\n\n const { translationsDirectorySuffix = defaultTranslationDirSuffix } = config;\n const result = `${globAnyPathWithOptionalPrefix}${translationsDirectorySuffix}/${langMatch}.${devTranslationFileName}`;\n\n trace('getAltTranslationFileGlob', result);\n\n return result;\n}\n\nexport function getAltLanguages({\n devLanguage,\n languages,\n}: {\n devLanguage: LanguageName;\n languages: LanguageTarget[];\n}) {\n return languages.map((v) => v.name).filter((lang) => lang !== devLanguage);\n}\n\nexport function getDevLanguageFileFromTsFile(tsFilePath: string) {\n const directory = path.dirname(tsFilePath);\n const result = path.normalize(path.join(directory, devTranslationFileName));\n\n trace(`Returning dev language path ${result} for path ${tsFilePath}`);\n return result;\n}\n\nexport function getDevLanguageFileFromAltLanguageFile(\n altLanguageFilePath: string,\n) {\n const directory = path.dirname(altLanguageFilePath);\n const result = path.normalize(path.join(directory, devTranslationFileName));\n trace(\n `Returning dev language path ${result} for path ${altLanguageFilePath}`,\n );\n return result;\n}\n\nexport function getTSFileFromDevLanguageFile(devLanguageFilePath: string) {\n const directory = path.dirname(devLanguageFilePath);\n const result = path.normalize(path.join(directory, 'index.ts'));\n\n trace(`Returning TS path ${result} for path ${devLanguageFilePath}`);\n return result;\n}\n\nexport function getAltLanguageFilePath(\n devLanguageFilePath: string,\n language: string,\n) {\n const directory = path.dirname(devLanguageFilePath);\n const result = path.normalize(\n path.join(directory, `${language}.translations.json`),\n );\n trace(\n `Returning alt language path ${result} for path ${devLanguageFilePath}`,\n );\n return path.normalize(result);\n}\n\nexport function mapValues<Key extends string, OriginalValue, ReturnValue>(\n obj: Record<Key, OriginalValue>,\n func: (val: OriginalValue) => ReturnValue,\n): TranslationMessagesByKey<Key> {\n const newObj: any = {};\n const keys = Object.keys(obj) as Key[];\n for (const key of keys) {\n newObj[key] = func(obj[key]);\n }\n return newObj;\n}\n\nexport function getTranslationMessages<Key extends string>(\n translations: TranslationsByKey<Key>,\n): TranslationMessagesByKey<Key> {\n return mapValues(translations, (v) => v.message);\n}\n","import { IntlMessageFormat } from 'intl-messageformat';\nimport {\n type MessageFormatElement,\n type PluralOrSelectOption,\n TYPE,\n} from '@formatjs/icu-messageformat-parser';\nimport { printAST } from '@formatjs/icu-messageformat-parser/printer.js';\nimport type { MessageGenerator, TranslationsByKey } from './types';\n\nexport function generateLanguageFromTranslations({\n baseTranslations,\n generator,\n}: {\n baseTranslations: TranslationsByKey<string>;\n generator: MessageGenerator;\n}): TranslationsByKey<string> {\n if (!generator.transformElement && !generator.transformMessage) {\n return baseTranslations;\n }\n\n const translationKeys = Object.keys(baseTranslations);\n const generatedTranslations: TranslationsByKey<string> = {};\n\n for (const translationKey of translationKeys) {\n const translation = baseTranslations[translationKey];\n let transformedMessage = translation.message;\n\n if (generator.transformElement) {\n const messageAst = new IntlMessageFormat(translation.message).getAst();\n const transformedAst = messageAst.map(\n transformMessageFormatElement(generator.transformElement),\n );\n transformedMessage = printAST(transformedAst);\n }\n\n if (generator.transformMessage) {\n transformedMessage = generator.transformMessage(transformedMessage);\n }\n\n generatedTranslations[translationKey] = {\n message: transformedMessage,\n };\n }\n\n return generatedTranslations;\n}\n\nfunction transformMessageFormatElement(\n transformElement: (message: string) => string,\n): (messageFormatElement: MessageFormatElement) => MessageFormatElement {\n return (messageFormatElement: MessageFormatElement) => {\n const transformedMessageFormatElement = { ...messageFormatElement };\n\n switch (transformedMessageFormatElement.type) {\n case TYPE.literal:\n const transformedValue = transformElement(\n transformedMessageFormatElement.value,\n );\n transformedMessageFormatElement.value = transformedValue;\n break;\n\n case TYPE.select:\n case TYPE.plural:\n const transformedOptions: Record<string, PluralOrSelectOption> = {\n ...transformedMessageFormatElement.options,\n };\n\n for (const key of Object.keys(transformedOptions)) {\n transformedOptions[key].value = transformedOptions[key].value.map(\n transformMessageFormatElement(transformElement),\n );\n }\n\n break;\n\n case TYPE.tag:\n const transformedChildren =\n transformedMessageFormatElement.children.map(\n transformMessageFormatElement(transformElement),\n );\n transformedMessageFormatElement.children = transformedChildren;\n break;\n\n default:\n break;\n }\n\n return transformedMessageFormatElement;\n };\n}\n","import path from 'path';\n\nimport { glob } from 'tinyglobby';\nimport type {\n TranslationsByKey,\n UserConfig,\n LoadedTranslation,\n LanguageTarget,\n LanguageName,\n TranslationFileMetadata,\n TranslationFileContents,\n} from './types';\nimport pc from 'picocolors';\n\nimport { trace } from './logger';\nimport {\n defaultTranslationDirSuffix,\n type Fallback,\n getAltLanguageFilePath,\n getAltLanguages,\n getDevTranslationFileGlob,\n} from './utils';\nimport { generateLanguageFromTranslations } from './generate-language';\n\nexport function getUniqueKey(key: string, namespace: string) {\n return `${key}.${namespace}`;\n}\n\nexport function mergeWithDevLanguageTranslation({\n translation,\n devTranslation,\n}: {\n translation: TranslationsByKey;\n devTranslation: TranslationsByKey;\n}) {\n // Only use keys from the dev translation\n const keys = Object.keys(devTranslation);\n const newLanguage: TranslationsByKey = {};\n\n for (const key of keys) {\n if (translation[key]) {\n newLanguage[key] = {\n message: translation[key].message,\n description: devTranslation[key].description,\n };\n }\n }\n\n return newLanguage;\n}\n\nfunction getLanguageFallbacks({ languages }: { languages: LanguageTarget[] }) {\n const languageFallbackMap = new Map<LanguageName, LanguageName>();\n\n for (const lang of languages) {\n if (lang.extends) {\n languageFallbackMap.set(lang.name, lang.extends);\n }\n }\n\n return languageFallbackMap;\n}\n\nexport function getLanguageHierarchy({\n languages,\n}: {\n languages: LanguageTarget[];\n}) {\n const hierarchyMap = new Map<LanguageName, LanguageName[]>();\n const fallbacks = getLanguageFallbacks({ languages });\n\n for (const lang of languages) {\n const langHierarchy = [];\n let currLang = lang.extends;\n\n while (currLang) {\n langHierarchy.push(currLang);\n\n currLang = fallbacks.get(currLang);\n }\n\n hierarchyMap.set(lang.name, langHierarchy);\n }\n\n return hierarchyMap;\n}\n\nexport function getFallbackLanguageOrder({\n languages,\n languageName,\n devLanguage,\n fallbacks,\n}: {\n languages: LanguageTarget[];\n languageName: string;\n devLanguage: string;\n fallbacks: Fallback;\n}) {\n const languageHierarchy = getLanguageHierarchy({ languages }).get(\n languageName,\n );\n\n if (!languageHierarchy) {\n throw new Error(`Missing language hierarchy for ${languageName}`);\n }\n\n const fallbackLanguageOrder: string[] = [languageName];\n\n if (fallbacks !== 'none') {\n fallbackLanguageOrder.unshift(...languageHierarchy.reverse());\n\n if (fallbacks === 'all' && fallbackLanguageOrder[0] !== devLanguage) {\n fallbackLanguageOrder.unshift(devLanguage);\n }\n }\n\n return fallbackLanguageOrder;\n}\n\nfunction getNamespaceByFilePath(\n relativePath: string,\n { translationsDirectorySuffix = defaultTranslationDirSuffix }: UserConfig,\n) {\n let namespace = path\n .dirname(relativePath)\n .replace(/^src\\//, '')\n .replace(/\\//g, '_');\n\n if (namespace.endsWith(translationsDirectorySuffix)) {\n namespace = namespace.slice(0, -translationsDirectorySuffix.length);\n }\n\n return namespace;\n}\n\nfunction printValidationError(...params: unknown[]) {\n // eslint-disable-next-line no-console\n console.error(pc.red('Error loading translation:'), ...params);\n}\n\nfunction getTranslationsFromFile(\n translationFileContents: unknown,\n {\n isAltLanguage,\n filePath,\n withTags,\n }: { isAltLanguage: boolean; filePath: string; withTags?: boolean },\n): {\n $namespace: unknown;\n keys: TranslationsByKey;\n metadata: TranslationFileMetadata;\n} {\n if (!translationFileContents || typeof translationFileContents !== 'object') {\n throw new Error(\n `Unable to read translation file ${filePath}. Translations must be an object.`,\n );\n }\n\n const { $namespace, _meta, ...keys } =\n translationFileContents as TranslationFileContents;\n\n if (isAltLanguage && $namespace) {\n printValidationError(\n `Found $namespace in alt language file in ${filePath}. $namespace is only used in the dev language and will be ignored.`,\n );\n }\n\n if (!isAltLanguage && $namespace && typeof $namespace !== 'string') {\n printValidationError(\n `Found non-string $namespace in language file in ${filePath}. $namespace must be a string.`,\n );\n }\n\n if (isAltLanguage && _meta?.tags) {\n printValidationError(\n `Found _meta.tags in alt language file in ${filePath}. _meta.tags is only used in the dev language and will be ignored.`,\n );\n }\n\n // Never return tags if we're fetching translations for an alt language\n const includeTags = !isAltLanguage && withTags;\n const validKeys: TranslationsByKey = {};\n\n for (const [translationKey, { tags, ...translation }] of Object.entries(\n keys,\n )) {\n if (typeof translation === 'string') {\n printValidationError(\n `Found string for a translation \"${translationKey}\" in ${filePath}. Translation must be an object of the format {message: string}.`,\n );\n continue;\n }\n\n if (!translation) {\n printValidationError(\n `Found empty translation \"${translationKey}\" in ${filePath}. Translation must be an object of the format {message: string}.`,\n );\n continue;\n }\n\n if (!translation.message || typeof translation.message !== 'string') {\n printValidationError(\n `No message found for translation \"${translationKey}\" in ${filePath}. Translation must be an object of the format {message: string}.`,\n );\n continue;\n }\n\n validKeys[translationKey] = {\n ...translation,\n tags: includeTags ? tags : undefined,\n };\n }\n\n const metadata = { tags: includeTags ? _meta?.tags : undefined };\n\n return { $namespace, keys: validKeys, metadata };\n}\n\nexport function loadAltLanguageFile(\n {\n filePath,\n languageName,\n devTranslation,\n fallbacks,\n }: {\n filePath: string;\n languageName: string;\n devTranslation: TranslationsByKey;\n fallbacks: Fallback;\n },\n { devLanguage, languages }: UserConfig,\n): TranslationsByKey {\n const altLanguageTranslation = {};\n\n const fallbackLanguageOrder = getFallbackLanguageOrder({\n languages,\n languageName,\n devLanguage,\n fallbacks,\n });\n\n trace(\n `Loading alt language file with precedence: ${fallbackLanguageOrder\n .slice()\n .reverse()\n .join(' -> ')}`,\n );\n\n for (const fallbackLanguage of fallbackLanguageOrder) {\n if (fallbackLanguage !== devLanguage) {\n try {\n const altFilePath = getAltLanguageFilePath(filePath, fallbackLanguage);\n delete require.cache[altFilePath];\n\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const translationFile = require(altFilePath);\n const { keys: fallbackLanguageTranslation } = getTranslationsFromFile(\n translationFile,\n {\n filePath: altFilePath,\n isAltLanguage: true,\n },\n );\n Object.assign(\n altLanguageTranslation,\n mergeWithDevLanguageTranslation({\n translation: fallbackLanguageTranslation,\n devTranslation,\n }),\n );\n } catch {\n trace(`Missing alt language file ${getAltLanguageFilePath(\n filePath,\n fallbackLanguage,\n )}\n `);\n }\n } else {\n Object.assign(altLanguageTranslation, devTranslation);\n }\n }\n\n return altLanguageTranslation;\n}\n\nfunction stripTagsFromTranslations(translations: TranslationsByKey) {\n return Object.fromEntries(\n Object.entries(translations).map(([key, { tags, ...rest }]) => [key, rest]),\n );\n}\n\nexport function loadTranslation(\n {\n filePath,\n fallbacks,\n withTags,\n }: {\n filePath: string;\n fallbacks: Fallback;\n withTags?: boolean;\n },\n userConfig: UserConfig,\n): LoadedTranslation {\n trace(\n `Loading translation file in \"${fallbacks}\" fallback mode: \"${filePath}\"`,\n );\n\n const languageSet: Record<\n string,\n Record<string, { message: string; description?: string | undefined }>\n > = {};\n\n delete require.cache[filePath];\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const translationContent = require(filePath);\n const relativePath = path.relative(\n userConfig.projectRoot || process.cwd(),\n filePath,\n );\n const {\n $namespace,\n keys: devTranslation,\n metadata,\n } = getTranslationsFromFile(translationContent, {\n filePath,\n isAltLanguage: false,\n withTags,\n });\n const namespace: string =\n typeof $namespace === 'string'\n ? $namespace\n : getNamespaceByFilePath(relativePath, userConfig);\n\n trace(`Found file ${filePath}. Using namespace ${namespace}`);\n\n languageSet[userConfig.devLanguage] = devTranslation;\n\n const devTranslationNoTags = withTags\n ? stripTagsFromTranslations(devTranslation)\n : devTranslation;\n const altLanguages = getAltLanguages(userConfig);\n for (const languageName of altLanguages) {\n languageSet[languageName] = loadAltLanguageFile(\n {\n filePath,\n languageName,\n devTranslation: devTranslationNoTags,\n fallbacks,\n },\n userConfig,\n );\n }\n\n for (const generatedLanguage of userConfig.generatedLanguages || []) {\n const { name: generatedLanguageName, generator } = generatedLanguage;\n const baseLanguage = generatedLanguage.extends || userConfig.devLanguage;\n const baseTranslations = languageSet[baseLanguage];\n\n languageSet[generatedLanguageName] = generateLanguageFromTranslations({\n baseTranslations,\n generator,\n });\n }\n\n return {\n filePath,\n keys: Object.keys(devTranslation),\n namespace,\n relativePath,\n languages: languageSet,\n metadata,\n };\n}\n\nexport async function loadAllTranslations(\n {\n fallbacks,\n includeNodeModules,\n withTags,\n }: { fallbacks: Fallback; includeNodeModules: boolean; withTags?: boolean },\n config: UserConfig,\n): Promise<LoadedTranslation[]> {\n const { projectRoot, ignore = [] } = config;\n\n const translationFiles = await glob(getDevTranslationFileGlob(config), {\n ignore: includeNodeModules ? ignore : [...ignore, '**/node_modules/**'],\n dot: true,\n absolute: true,\n cwd: projectRoot,\n expandDirectories: false,\n });\n\n trace(`Found ${translationFiles.length} translation files`);\n\n const loadedTranslations: LoadedTranslation[] = [];\n const keys = new Set<string>();\n\n for (const translationFile of translationFiles) {\n const loadedTranslation = loadTranslation(\n { filePath: translationFile, fallbacks, withTags },\n config,\n );\n\n loadedTranslations.push(loadedTranslation);\n\n for (const key of loadedTranslation.keys) {\n const uniqueKey = getUniqueKey(key, loadedTranslation.namespace);\n if (keys.has(uniqueKey)) {\n trace(`Duplicate keys found`);\n throw new Error(\n `Duplicate keys found. Key with namespace ${loadedTranslation.namespace} and key ${key} was found multiple times.`,\n );\n }\n keys.add(uniqueKey);\n\n const globalKey =\n loadedTranslation.languages[config.devLanguage][key].globalKey;\n if (globalKey) {\n if (keys.has(globalKey)) {\n throw new Error(\n `Duplicate keys found. Key with global key ${globalKey} and key ${key} was found multiple times`,\n );\n }\n keys.add(globalKey);\n }\n }\n }\n\n return loadedTranslations;\n}\n","import { promises as fs, existsSync } from 'fs';\nimport path from 'path';\nimport pm from 'picomatch';\n\nimport type { LoadedTranslation, UserConfig } from './types';\nimport {\n isArgumentElement,\n isDateElement,\n isNumberElement,\n isPluralElement,\n isSelectElement,\n isTagElement,\n isTimeElement,\n type MessageFormatElement,\n parse,\n} from '@formatjs/icu-messageformat-parser';\nimport prettier from 'prettier';\n\nimport {\n getTranslationMessages,\n getDevTranslationFileGlob,\n getTSFileFromDevLanguageFile,\n getDevLanguageFileFromAltLanguageFile,\n getAltTranslationFileGlob,\n isDevLanguageFile,\n isAltLanguageFile,\n devTranslationFileName,\n isTranslationDirectory,\n} from './utils';\nimport { trace } from './logger';\nimport { loadAllTranslations, loadTranslation } from './load-translations';\n\ntype ICUParams = Record<string, string>;\n\ninterface TranslationTypeInfo {\n params: ICUParams;\n message: string;\n hasTags: boolean;\n}\n\nfunction extractHasTags(ast: MessageFormatElement[]): boolean {\n return ast.some((element) => {\n if (isSelectElement(element) || isPluralElement(element)) {\n const children = Object.values(element.options).map((o) => o.value);\n return children.some((child) => extractHasTags(child));\n }\n\n return isTagElement(element);\n });\n}\n\nfunction extractParamTypes(\n ast: MessageFormatElement[],\n currentParams: ICUParams,\n): [params: ICUParams, vocabTypesImports: Set<string>] {\n let params = { ...currentParams };\n let vocabTypesImports = new Set<string>();\n\n for (const element of ast) {\n if (isArgumentElement(element)) {\n if (!(element.value in params)) {\n // Preserve existing types for parameters that we've already parsed\n // This applies to self-referential parameters, for example `{foo, plural, 1 {{foo} thing} other {{foo} things}}`\n params[element.value] = 'string';\n }\n } else if (isNumberElement(element)) {\n params[element.value] = 'number';\n } else if (isPluralElement(element)) {\n params[element.value] = 'number';\n\n const children = Object.values(element.options).map((o) => o.value);\n\n for (const child of children) {\n const [newParams, subImports] = extractParamTypes(child, params);\n\n vocabTypesImports = new Set([...vocabTypesImports, ...subImports]);\n params = newParams;\n }\n } else if (isDateElement(element) || isTimeElement(element)) {\n params[element.value] = 'Date | number';\n } else if (isTagElement(element)) {\n params[element.value] = 'FormatXMLElementFn<T>';\n vocabTypesImports.add('FormatXMLElementFn');\n\n const [newParams, subImports] = extractParamTypes(\n element.children,\n params,\n );\n\n vocabTypesImports = new Set([...vocabTypesImports, ...subImports]);\n params = newParams;\n } else if (isSelectElement(element)) {\n const options = Object.keys(element.options);\n\n // `other` will always be an option as the parser enforces this by default\n const nonOtherOptions = options.filter((o) => o !== 'other');\n const nonOtherOptionsUnion = nonOtherOptions\n .map((o) => `'${o}'`)\n .join(' | ');\n\n params[element.value] = `StringWithSuggestions<${nonOtherOptionsUnion}>`;\n vocabTypesImports.add('StringWithSuggestions');\n\n const children = Object.values(element.options).map((o) => o.value);\n\n for (const child of children) {\n const [newParams, subImports] = extractParamTypes(child, params);\n\n vocabTypesImports = new Set([...vocabTypesImports, ...subImports]);\n params = newParams;\n }\n }\n }\n\n return [params, vocabTypesImports];\n}\n\nfunction serialiseObjectToType(v: any) {\n let result = '';\n\n for (const [key, value] of Object.entries(v)) {\n result += `${JSON.stringify(key)}: ${\n value && typeof value === 'object' ? serialiseObjectToType(value) : value\n },`;\n }\n\n return `{ ${result} }`;\n}\n\nconst serializeTypeImports = (imports: Set<string>, moduleName: string) => {\n if (imports.size === 0) {\n return '';\n }\n\n const importNames = Array.from(imports).sort();\n return `import type { ${importNames.join(', ')} } from '${moduleName}';`;\n};\n\nfunction serialiseTranslationRuntime(\n value: Map<string, TranslationTypeInfo>,\n imports: Set<string>,\n loadedTranslation: LoadedTranslation,\n) {\n trace('Serialising translations:', loadedTranslation);\n const translationsType: any = {};\n\n for (const [key, { params, message, hasTags }] of value.entries()) {\n let translationFunctionString = `() => ${message}`;\n\n if (Object.keys(params).length > 0) {\n const formatGeneric = hasTags ? '<T = string>' : '';\n const formatReturn =\n hasTags && imports.has('FormatXMLElementFn')\n ? 'ReturnType<FormatXMLElementFn<T>>'\n : 'string';\n translationFunctionString = `${formatGeneric}(values: ${serialiseObjectToType(\n params,\n )}) => ${formatReturn}`;\n }\n\n translationsType[key] = translationFunctionString;\n }\n\n const languagesUnionAsString = Object.keys(loadedTranslation.languages)\n .map((l) => `'${l}'`)\n .join(' | ');\n const languageEntries = Object.entries(loadedTranslation.languages)\n .map(\n ([languageName, translations]) =>\n `${JSON.stringify(languageName)}: createLanguage(${JSON.stringify(\n getTranslationMessages(translations),\n )})`,\n )\n .join(',');\n\n // TranslationFile is now always imported\n const typeImports = new Set([...imports, 'TranslationFile']);\n\n return /* ts */ `\n // This file is automatically generated by Vocab.\n // To make changes update translation.json files directly.\n\n ${serializeTypeImports(typeImports, '@vocab/core')}\n import { createLanguage, createTranslationFile } from '@vocab/core/runtime';\n\n const translations: TranslationFile<\n ${languagesUnionAsString},\n ${serialiseObjectToType(translationsType)}\n > = createTranslationFile\n ({\n ${languageEntries}\n });\n\n export default translations;\n `;\n}\n\nexport async function generateRuntime(loadedTranslation: LoadedTranslation) {\n const { languages: loadedLanguages, filePath } = loadedTranslation;\n\n trace('Generating types for', filePath);\n const translationTypes = new Map<string, TranslationTypeInfo>();\n\n let imports = new Set<string>();\n\n for (const key of loadedTranslation.keys) {\n let params: ICUParams = {};\n const messages = new Set();\n let hasTags = false;\n\n for (const translatedLanguage of Object.values(loadedLanguages)) {\n if (translatedLanguage[key]) {\n const ast = parse(translatedLanguage[key].message);\n\n hasTags = hasTags || extractHasTags(ast);\n\n const [parsedParams, vocabTypesImports] = extractParamTypes(\n ast,\n params,\n );\n\n imports = new Set([...imports, ...vocabTypesImports]);\n params = parsedParams;\n\n messages.add(JSON.stringify(translatedLanguage[key].message));\n }\n }\n\n translationTypes.set(key, {\n params,\n hasTags,\n message: Array.from(messages).join(' | '),\n });\n }\n\n const prettierConfig = await prettier.resolveConfig(filePath);\n const serializedTranslationType = serialiseTranslationRuntime(\n translationTypes,\n imports,\n loadedTranslation,\n );\n const declaration = await prettier.format(serializedTranslationType, {\n ...prettierConfig,\n parser: 'typescript',\n });\n const outputFilePath = getTSFileFromDevLanguageFile(filePath);\n trace(`Writing translation types to ${outputFilePath}`);\n await writeIfChanged(outputFilePath, declaration);\n}\n\nexport async function watch(config: UserConfig) {\n const cwd = config.projectRoot || process.cwd();\n\n const ignorePatterns = [\n ...(config.ignore || []),\n '**/node_modules/**',\n '**/.git/**',\n ];\n\n const ignoredFunction = (pathToCheck: string) =>\n pm.isMatch(pathToCheck, ignorePatterns);\n\n const chokidar = await import('chokidar');\n const watcher = chokidar.watch(cwd, {\n ignored: ignoredFunction,\n ignoreInitial: true,\n });\n\n const devFileGlob = getDevTranslationFileGlob(config);\n const altFileGlob = getAltTranslationFileGlob(config);\n\n const onTranslationChange = async (relativePath: string) => {\n const matchesTranslationFiles = pm.isMatch(relativePath, [\n devFileGlob,\n altFileGlob,\n ]);\n\n if (!matchesTranslationFiles) {\n return;\n }\n\n trace(`Detected change for file ${relativePath}`);\n\n let targetFile;\n\n if (isDevLanguageFile(relativePath)) {\n targetFile = path.resolve(cwd, relativePath);\n } else if (isAltLanguageFile(relativePath)) {\n targetFile = getDevLanguageFileFromAltLanguageFile(\n path.resolve(cwd, relativePath),\n );\n }\n\n if (targetFile) {\n watcher.add(targetFile);\n try {\n const loadedTranslation = loadTranslation(\n { filePath: targetFile, fallbacks: 'all' },\n config,\n );\n\n await generateRuntime(loadedTranslation);\n } catch (e) {\n // eslint-disable-next-line no-console\n console.log('Failed to generate types for', relativePath);\n // eslint-disable-next-line no-console\n console.error(e);\n }\n }\n };\n\n const onNewDirectory = async (relativePath: string) => {\n trace('Detected new directory', relativePath);\n\n if (!isTranslationDirectory(relativePath, config)) {\n trace('Ignoring non-translation directory:', relativePath);\n return;\n }\n\n const newFilePath = path.join(relativePath, devTranslationFileName);\n if (!existsSync(newFilePath)) {\n await fs.writeFile(newFilePath, JSON.stringify({}, null, 2));\n trace('Created new empty translation file:', newFilePath);\n } else {\n trace(\n `New directory already contains translation file. Skipping creation. Existing file ${newFilePath}`,\n );\n }\n };\n\n watcher.on('addDir', onNewDirectory);\n watcher.on('add', onTranslationChange).on('change', onTranslationChange);\n\n return () => watcher.close();\n}\n\nexport async function compile(\n { watch: shouldWatch = false } = {},\n config: UserConfig,\n) {\n const translations = await loadAllTranslations(\n { fallbacks: 'all', includeNodeModules: false },\n config,\n );\n\n for (const loadedTranslation of translations) {\n await generateRuntime(loadedTranslation);\n }\n\n if (shouldWatch) {\n trace('Listening for changes to files...');\n return watch(config);\n }\n}\n\nasync function writeIfChanged(filepath: string, contents: string) {\n let hasChanged = true;\n\n try {\n const existingContents = await fs.readFile(filepath, { encoding: 'utf-8' });\n\n hasChanged = existingContents !== contents;\n } catch {\n // ignore error, likely a file doesn't exist error so we want to write anyway\n }\n\n if (hasChanged) {\n await fs.writeFile(filepath, contents, { encoding: 'utf-8' });\n }\n}\n","/* eslint-disable no-console */\nimport type { UserConfig, LoadedTranslation, LanguageName } from '../types';\nimport pc from 'picocolors';\n\nimport { loadAllTranslations } from '../load-translations';\nimport { getAltLanguages } from '../utils';\n\nexport function findMissingKeys(\n loadedTranslation: LoadedTranslation,\n devLanguageName: LanguageName,\n altLanguages: LanguageName[],\n) {\n const devLanguage = loadedTranslation.languages[devLanguageName];\n\n if (!devLanguage) {\n throw new Error(\n `Failed to load dev language: ${loadedTranslation.filePath}`,\n );\n }\n\n const result: Record<LanguageName, string[]> = {};\n let valid = true;\n\n const requiredKeys = Object.keys(devLanguage);\n\n if (requiredKeys.length > 0) {\n for (const altLanguageName of altLanguages) {\n const altLanguage = loadedTranslation.languages[altLanguageName] ?? {};\n\n for (const key of requiredKeys) {\n if (typeof altLanguage[key]?.message !== 'string') {\n if (!result[altLanguageName]) {\n result[altLanguageName] = [];\n }\n\n result[altLanguageName].push(key);\n valid = false;\n }\n }\n }\n }\n return [valid, result] as const;\n}\n\nexport async function validate(config: UserConfig) {\n const allTranslations = await loadAllTranslations(\n { fallbacks: 'valid', includeNodeModules: true },\n config,\n );\n\n let valid = true;\n\n for (const loadedTranslation of allTranslations) {\n const [translationValid, result] = findMissingKeys(\n loadedTranslation,\n config.devLanguage,\n getAltLanguages(config),\n );\n\n if (!translationValid) {\n valid = false;\n console.log(\n pc.red(\n `Incomplete translations: \"${pc.bold(\n loadedTranslation.relativePath,\n )}\"`,\n ),\n );\n\n for (const lang of Object.keys(result)) {\n const missingKeys = result[lang];\n\n console.log(\n pc.yellow(lang),\n '->',\n missingKeys.map((v) => `\"${v}\"`).join(', '),\n );\n }\n }\n }\n\n return valid;\n}\n","export class ValidationError extends Error {\n code: string;\n rawMessage: string;\n constructor(code: string, message: string) {\n super(`Invalid vocab.config.js: ${code} - ${message}`);\n this.code = code;\n this.rawMessage = message;\n }\n}\n","import type { UserConfig } from './types';\nimport path from 'path';\n\nimport pc from 'picocolors';\nimport findUp from 'find-up';\nimport Validator from 'fastest-validator';\nimport { ValidationError } from './ValidationError';\nimport { trace } from './logger';\n\nconst boldCyan = (s: string) => pc.bold(pc.cyan(s));\n\nconst validator = new Validator();\nconst schema = {\n $$strict: true,\n devLanguage: {\n type: 'string',\n },\n languages: {\n type: 'array',\n items: {\n type: 'object',\n props: {\n name: { type: 'string' },\n extends: { type: 'string', optional: true },\n },\n },\n },\n generatedLanguages: {\n type: 'array',\n items: {\n type: 'object',\n props: {\n name: { type: 'string' },\n extends: { type: 'string', optional: true },\n generator: {\n type: 'object',\n props: {\n transformElement: { type: 'function', optional: true },\n transformMessage: { type: 'function', optional: true },\n },\n },\n },\n },\n optional: true,\n },\n translationsDirectorySuffix: { type: 'string', optional: true },\n projectRoot: { type: 'string', optional: true },\n ignore: {\n type: 'array',\n items: 'string',\n optional: true,\n },\n};\nconst checkConfigFile = validator.compile(schema);\n\nconst splitMap = (message: string, callback: (value: string) => string) =>\n message\n .split(' ,')\n .map((v) => callback(v))\n .join(' ,');\n\nexport function validateConfig(c: UserConfig) {\n trace('Validating configuration file');\n // Note: checkConfigFile mutates the config file by applying defaults\n const isValid = checkConfigFile(c);\n if (isValid !== true) {\n throw new ValidationError(\n 'InvalidStructure',\n (Array.isArray(isValid) ? isValid : [])\n .map((v) => {\n if (v.type === 'objectStrict') {\n return `Invalid key(s) ${splitMap(\n v.actual,\n (m) => `\"${pc.cyan(m)}\"`,\n )}. Expected one of ${splitMap(v.expected, pc.green)}`;\n }\n if (v.field) {\n return v.message?.replace(v.field, pc.cyan(v.field));\n }\n return v.message;\n })\n .join(' \\n'),\n );\n }\n\n const languageStrings = c.languages.map((v) => v.name);\n\n // Dev Language should exist in languages\n if (!languageStrings.includes(c.devLanguage)) {\n throw new ValidationError(\n 'InvalidDevLanguage',\n `The dev language \"${boldCyan(\n c.devLanguage,\n )}\" was not found in languages ${languageStrings.join(', ')}.`,\n );\n }\n\n const foundLanguages: string[] = [];\n for (const lang of c.languages) {\n // Languages must only exist once\n if (foundLanguages.includes(lang.name)) {\n throw new ValidationError(\n 'DuplicateLanguage',\n `The language \"${boldCyan(lang.name)}\" was defined multiple times.`,\n );\n }\n foundLanguages.push(lang.name);\n\n // Any extends must be in languages\n if (lang.extends && !languageStrings.includes(lang.extends)) {\n throw new ValidationError(\n 'InvalidExtends',\n `The language \"${boldCyan(lang.name)}\"'s extends of ${boldCyan(\n lang.extends,\n )} was not found in languages ${languageStrings.join(', ')}.`,\n );\n }\n }\n\n const foundGeneratedLanguages: string[] = [];\n for (const generatedLang of c.generatedLanguages || []) {\n // Generated languages must only exist once\n if (foundGeneratedLanguages.includes(generatedLang.name)) {\n throw new ValidationError(\n 'DuplicateGeneratedLanguage',\n `The generated language \"${boldCyan(\n generatedLang.name,\n )}\" was defined multiple times.`,\n );\n }\n foundGeneratedLanguages.push(generatedLang.name);\n\n // Generated language names must not conflict with language names\n if (languageStrings.includes(generatedLang.name)) {\n throw new ValidationError(\n 'InvalidGeneratedLanguage',\n `The generated language \"${boldCyan(\n generatedLang.name,\n )}\" is already defined as a language.`,\n );\n }\n\n // Any extends must be in languages\n if (\n generatedLang.extends &&\n !languageStrings.includes(generatedLang.extends)\n ) {\n throw new ValidationError(\n 'InvalidExtends',\n `The generated language \"${boldCyan(\n generatedLang.name,\n )}\"'s extends of ${boldCyan(\n generatedLang.extends,\n )} was not found in languages ${languageStrings.join(', ')}.`,\n );\n }\n }\n\n trace('Configuration file is valid');\n\n return true;\n}\n\nfunction createConfig(configFilePath: string) {\n const cwd = path.dirname(configFilePath);\n\n return {\n projectRoot: cwd,\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n ...(require(configFilePath) as UserConfig),\n };\n}\n\nexport async function resolveConfig(\n customConfigFilePath?: string,\n): Promise<UserConfig | null> {\n const configFilePath = customConfigFilePath\n ? path.resolve(customConfigFilePath)\n : await findUp(['vocab.config.js', 'vocab.config.cjs']);\n\n if (configFilePath) {\n trace(`Resolved configuration file to ${configFilePath}`);\n return createConfig(configFilePath);\n }\n trace('No configuration file found');\n return null;\n}\n\nexport function resolveConfigSync(\n customConfigFilePath?: string,\n): UserConfig | null {\n const configFilePath = customConfigFilePath\n ? path.resolve(customConfigFilePath)\n : findUp.sync(['vocab.config.js', 'vocab.config.cjs']);\n\n if (configFilePath) {\n trace(`Resolved configuration file to ${configFilePath}`);\n return createConfig(configFilePath);\n }\n trace('No configuration file found');\n\n return null;\n}\n"],"mappings":"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"}
package/dist/runtime.cjs CHANGED
@@ -1,5 +1,5 @@
1
- const require_icu_handler = require('./icu-handler-CuHzcwEH.cjs');
2
- const require_translation_file = require('./translation-file-rax5G8Pd.cjs');
1
+ const require_icu_handler = require('./icu-handler.cjs');
2
+ const require_translation_file = require('./translation-file.cjs');
3
3
 
4
4
  //#region src/runtime.ts
5
5
  const createLanguage = (module$1) => ({
@@ -1,5 +1,5 @@
1
1
  import { b as TranslationModule, y as TranslationMessagesByKey } from "./types-C00NNtxU.cjs";
2
- import { t as createTranslationFile } from "./translation-file-CqTkqKMS.cjs";
2
+ import { createTranslationFile } from "./translation-file.cjs";
3
3
 
4
4
  //#region src/runtime.d.ts
5
5
  declare const createLanguage: (module: TranslationMessagesByKey) => TranslationModule<any>;
@@ -1,5 +1,5 @@
1
- import { b as TranslationModule, y as TranslationMessagesByKey } from "./types-DpryIirw.mjs";
2
- import { t as createTranslationFile } from "./translation-file-Ca5lZ9Dd.mjs";
1
+ import { b as TranslationModule, y as TranslationMessagesByKey } from "./types-oikDld6a.mjs";
2
+ import { createTranslationFile } from "./translation-file.mjs";
3
3
 
4
4
  //#region src/runtime.d.ts
5
5
  declare const createLanguage: (module: TranslationMessagesByKey) => TranslationModule<any>;
package/dist/runtime.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { t as getParsedICUMessages } from "./icu-handler-DpDWxKGr.mjs";
2
- import { t as createTranslationFile } from "./translation-file-U7k1_uqE.mjs";
1
+ import { getParsedICUMessages } from "./icu-handler.mjs";
2
+ import { createTranslationFile } from "./translation-file.mjs";
3
3
 
4
4
  //#region src/runtime.ts
5
5
  const createLanguage = (module) => ({
@@ -1,3 +1,29 @@
1
- const require_translation_file = require('./translation-file-rax5G8Pd.cjs');
2
1
 
3
- exports.createTranslationFile = require_translation_file.createTranslationFile;
2
+ //#region src/translation-file.ts
3
+ function createTranslationFile(translationsByLanguage) {
4
+ function getByLanguage(language) {
5
+ const translationModule = translationsByLanguage[language];
6
+ if (!translationModule) throw new Error(`Attempted to retrieve translations for unknown language "${language}"`);
7
+ return translationModule;
8
+ }
9
+ return {
10
+ getLoadedMessages(language, locale) {
11
+ return getByLanguage(language).getValue(locale || language) || null;
12
+ },
13
+ getMessages(language, locale) {
14
+ const translationModule = getByLanguage(language);
15
+ return translationModule.load().then(() => {
16
+ const result = translationModule.getValue(locale || language);
17
+ if (!result) throw new Error(`Unable to find translations for ${language} after attempting to load. Module may have failed to load or an internal error may have occurred.`);
18
+ return result;
19
+ });
20
+ },
21
+ load(language) {
22
+ return getByLanguage(language).load();
23
+ }
24
+ };
25
+ }
26
+
27
+ //#endregion
28
+ exports.createTranslationFile = createTranslationFile;
29
+ //# sourceMappingURL=translation-file.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translation-file.cjs","names":[],"sources":["../src/translation-file.ts"],"sourcesContent":["import type {\n TranslationModule,\n TranslationModuleByLanguage,\n ParsedICUMessages,\n LanguageName,\n ParsedFormatFnByKey,\n TranslationFile,\n} from './types';\n\nexport function createTranslationFile<\n Language extends LanguageName,\n FormatFnByKey extends ParsedFormatFnByKey,\n>(\n translationsByLanguage: TranslationModuleByLanguage<Language, FormatFnByKey>,\n): TranslationFile<Language, FormatFnByKey> {\n function getByLanguage(language: Language): TranslationModule<FormatFnByKey> {\n const translationModule = translationsByLanguage[language];\n if (!translationModule) {\n throw new Error(\n `Attempted to retrieve translations for unknown language \"${language}\"`,\n );\n }\n return translationModule;\n }\n\n return {\n getLoadedMessages(\n language: Language,\n locale?: string,\n ): ParsedICUMessages<FormatFnByKey> | null {\n const translationModule = getByLanguage(language);\n return translationModule.getValue(locale || language) || null;\n },\n getMessages(\n language: Language,\n locale?: string,\n ): Promise<ParsedICUMessages<FormatFnByKey>> {\n const translationModule = getByLanguage(language);\n return translationModule.load().then(() => {\n const result = translationModule.getValue(locale || language);\n if (!result) {\n throw new Error(\n `Unable to find translations for ${language} after attempting to load. Module may have failed to load or an internal error may have occurred.`,\n );\n }\n return result;\n });\n },\n load(language: Language): Promise<void> {\n const translationModule = getByLanguage(language);\n return translationModule.load();\n },\n };\n}\n"],"mappings":";;AASA,SAAgB,sBAId,wBAC0C;CAC1C,SAAS,cAAc,UAAsD;EAC3E,MAAM,oBAAoB,uBAAuB;AACjD,MAAI,CAAC,kBACH,OAAM,IAAI,MACR,4DAA4D,SAAS,GACtE;AAEH,SAAO;;AAGT,QAAO;EACL,kBACE,UACA,QACyC;AAEzC,UAD0B,cAAc,SAAS,CACxB,SAAS,UAAU,SAAS,IAAI;;EAE3D,YACE,UACA,QAC2C;GAC3C,MAAM,oBAAoB,cAAc,SAAS;AACjD,UAAO,kBAAkB,MAAM,CAAC,WAAW;IACzC,MAAM,SAAS,kBAAkB,SAAS,UAAU,SAAS;AAC7D,QAAI,CAAC,OACH,OAAM,IAAI,MACR,mCAAmC,SAAS,mGAC7C;AAEH,WAAO;KACP;;EAEJ,KAAK,UAAmC;AAEtC,UAD0B,cAAc,SAAS,CACxB,MAAM;;EAElC"}
@@ -1,2 +1,7 @@
1
- import { t as createTranslationFile } from "./translation-file-CqTkqKMS.cjs";
2
- export { createTranslationFile };
1
+ import { c as ParsedFormatFnByKey, p as TranslationFile, r as LanguageName, x as TranslationModuleByLanguage } from "./types-C00NNtxU.cjs";
2
+
3
+ //#region src/translation-file.d.ts
4
+ declare function createTranslationFile<Language extends LanguageName, FormatFnByKey extends ParsedFormatFnByKey>(translationsByLanguage: TranslationModuleByLanguage<Language, FormatFnByKey>): TranslationFile<Language, FormatFnByKey>;
5
+ //#endregion
6
+ export { createTranslationFile };
7
+ //# sourceMappingURL=translation-file.d.cts.map
@@ -1,3 +1,7 @@
1
- import "./types-DpryIirw.mjs";
2
- import { t as createTranslationFile } from "./translation-file-Ca5lZ9Dd.mjs";
3
- export { createTranslationFile };
1
+ import { c as ParsedFormatFnByKey, p as TranslationFile, r as LanguageName, x as TranslationModuleByLanguage } from "./types-oikDld6a.mjs";
2
+
3
+ //#region src/translation-file.d.ts
4
+ declare function createTranslationFile<Language extends LanguageName, FormatFnByKey extends ParsedFormatFnByKey>(translationsByLanguage: TranslationModuleByLanguage<Language, FormatFnByKey>): TranslationFile<Language, FormatFnByKey>;
5
+ //#endregion
6
+ export { createTranslationFile };
7
+ //# sourceMappingURL=translation-file.d.mts.map
@@ -1,3 +1,28 @@
1
- import { t as createTranslationFile } from "./translation-file-U7k1_uqE.mjs";
1
+ //#region src/translation-file.ts
2
+ function createTranslationFile(translationsByLanguage) {
3
+ function getByLanguage(language) {
4
+ const translationModule = translationsByLanguage[language];
5
+ if (!translationModule) throw new Error(`Attempted to retrieve translations for unknown language "${language}"`);
6
+ return translationModule;
7
+ }
8
+ return {
9
+ getLoadedMessages(language, locale) {
10
+ return getByLanguage(language).getValue(locale || language) || null;
11
+ },
12
+ getMessages(language, locale) {
13
+ const translationModule = getByLanguage(language);
14
+ return translationModule.load().then(() => {
15
+ const result = translationModule.getValue(locale || language);
16
+ if (!result) throw new Error(`Unable to find translations for ${language} after attempting to load. Module may have failed to load or an internal error may have occurred.`);
17
+ return result;
18
+ });
19
+ },
20
+ load(language) {
21
+ return getByLanguage(language).load();
22
+ }
23
+ };
24
+ }
2
25
 
3
- export { createTranslationFile };
26
+ //#endregion
27
+ export { createTranslationFile };
28
+ //# sourceMappingURL=translation-file.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translation-file.mjs","names":[],"sources":["../src/translation-file.ts"],"sourcesContent":["import type {\n TranslationModule,\n TranslationModuleByLanguage,\n ParsedICUMessages,\n LanguageName,\n ParsedFormatFnByKey,\n TranslationFile,\n} from './types';\n\nexport function createTranslationFile<\n Language extends LanguageName,\n FormatFnByKey extends ParsedFormatFnByKey,\n>(\n translationsByLanguage: TranslationModuleByLanguage<Language, FormatFnByKey>,\n): TranslationFile<Language, FormatFnByKey> {\n function getByLanguage(language: Language): TranslationModule<FormatFnByKey> {\n const translationModule = translationsByLanguage[language];\n if (!translationModule) {\n throw new Error(\n `Attempted to retrieve translations for unknown language \"${language}\"`,\n );\n }\n return translationModule;\n }\n\n return {\n getLoadedMessages(\n language: Language,\n locale?: string,\n ): ParsedICUMessages<FormatFnByKey> | null {\n const translationModule = getByLanguage(language);\n return translationModule.getValue(locale || language) || null;\n },\n getMessages(\n language: Language,\n locale?: string,\n ): Promise<ParsedICUMessages<FormatFnByKey>> {\n const translationModule = getByLanguage(language);\n return translationModule.load().then(() => {\n const result = translationModule.getValue(locale || language);\n if (!result) {\n throw new Error(\n `Unable to find translations for ${language} after attempting to load. Module may have failed to load or an internal error may have occurred.`,\n );\n }\n return result;\n });\n },\n load(language: Language): Promise<void> {\n const translationModule = getByLanguage(language);\n return translationModule.load();\n },\n };\n}\n"],"mappings":";AASA,SAAgB,sBAId,wBAC0C;CAC1C,SAAS,cAAc,UAAsD;EAC3E,MAAM,oBAAoB,uBAAuB;AACjD,MAAI,CAAC,kBACH,OAAM,IAAI,MACR,4DAA4D,SAAS,GACtE;AAEH,SAAO;;AAGT,QAAO;EACL,kBACE,UACA,QACyC;AAEzC,UAD0B,cAAc,SAAS,CACxB,SAAS,UAAU,SAAS,IAAI;;EAE3D,YACE,UACA,QAC2C;GAC3C,MAAM,oBAAoB,cAAc,SAAS;AACjD,UAAO,kBAAkB,MAAM,CAAC,WAAW;IACzC,MAAM,SAAS,kBAAkB,SAAS,UAAU,SAAS;AAC7D,QAAI,CAAC,OACH,OAAM,IAAI,MACR,mCAAmC,SAAS,mGAC7C;AAEH,WAAO;KACP;;EAEJ,KAAK,UAAmC;AAEtC,UAD0B,cAAc,SAAS,CACxB,MAAM;;EAElC"}
@@ -143,4 +143,4 @@ type LoadedTranslation<Key extends TranslationKey = string> = {
143
143
  };
144
144
  //#endregion
145
145
  export { TranslationsByLanguage as C, TranslationsByKey as S, TranslationKeys as _, LoadedTranslation as a, TranslationModule as b, ParsedFormatFnByKey as c, Tags as d, TranslationData as f, TranslationKey as g, TranslationFileMetadata as h, LanguageTarget as i, ParsedICUMessages as l, TranslationFileContents as m, GeneratedLanguageTarget as n, MessageGenerator as o, TranslationFile as p, LanguageName as r, ParsedFormatFn as s, FormatXMLElementFn as t, StringWithSuggestions as u, TranslationMessage as v, UserConfig as w, TranslationModuleByLanguage as x, TranslationMessagesByKey as y };
146
- //# sourceMappingURL=types-DpryIirw.d.mts.map
146
+ //# sourceMappingURL=types-oikDld6a.d.mts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vocab/core",
3
- "version": "1.7.4",
3
+ "version": "1.7.6",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/seek-oss/vocab.git",
@@ -1,28 +0,0 @@
1
- const require_rolldown_runtime = require('./rolldown-runtime-y5NzCiFd.cjs');
2
- let intl_messageformat = require("intl-messageformat");
3
-
4
- //#region src/icu-handler.ts
5
- const moduleCache = /* @__PURE__ */ new WeakMap();
6
- const getParsedICUMessages = (m, locale) => {
7
- const moduleCachedResult = moduleCache.get(m);
8
- if (moduleCachedResult && moduleCachedResult[locale]) return moduleCachedResult[locale];
9
- const parsedICUMessages = {};
10
- for (const translation of Object.keys(m)) {
11
- const intlMessageFormat = new intl_messageformat.IntlMessageFormat(m[translation], locale);
12
- parsedICUMessages[translation] = { format: (params) => intlMessageFormat.format(params) };
13
- }
14
- moduleCache.set(m, {
15
- ...moduleCachedResult,
16
- [locale]: parsedICUMessages
17
- });
18
- return parsedICUMessages;
19
- };
20
-
21
- //#endregion
22
- Object.defineProperty(exports, 'getParsedICUMessages', {
23
- enumerable: true,
24
- get: function () {
25
- return getParsedICUMessages;
26
- }
27
- });
28
- //# sourceMappingURL=icu-handler-CuHzcwEH.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"icu-handler-CuHzcwEH.cjs","names":["parsedICUMessages: ParsedICUMessages<any>","IntlMessageFormat"],"sources":["../src/icu-handler.ts"],"sourcesContent":["import type { ParsedICUMessages, TranslationMessagesByKey } from './types';\nimport { IntlMessageFormat } from 'intl-messageformat';\n\ntype ICUMessagesByLocale = Record<string, ParsedICUMessages<any>>;\n\nconst moduleCache = new WeakMap<\n TranslationMessagesByKey,\n ICUMessagesByLocale\n>();\n\nexport const getParsedICUMessages = (\n m: TranslationMessagesByKey,\n locale: string,\n): ParsedICUMessages<any> => {\n const moduleCachedResult = moduleCache.get(m);\n\n if (moduleCachedResult && moduleCachedResult[locale]) {\n return moduleCachedResult[locale];\n }\n\n const parsedICUMessages: ParsedICUMessages<any> = {};\n\n for (const translation of Object.keys(m)) {\n const intlMessageFormat = new IntlMessageFormat(m[translation], locale);\n parsedICUMessages[translation] = {\n format: (params: any) => intlMessageFormat.format(params),\n };\n }\n\n moduleCache.set(m, { ...moduleCachedResult, [locale]: parsedICUMessages });\n\n return parsedICUMessages;\n};\n"],"mappings":";;;;AAKA,MAAM,8BAAc,IAAI,SAGrB;AAEH,MAAa,wBACX,GACA,WAC2B;CAC3B,MAAM,qBAAqB,YAAY,IAAI,EAAE;AAE7C,KAAI,sBAAsB,mBAAmB,QAC3C,QAAO,mBAAmB;CAG5B,MAAMA,oBAA4C,EAAE;AAEpD,MAAK,MAAM,eAAe,OAAO,KAAK,EAAE,EAAE;EACxC,MAAM,oBAAoB,IAAIC,qCAAkB,EAAE,cAAc,OAAO;AACvE,oBAAkB,eAAe,EAC/B,SAAS,WAAgB,kBAAkB,OAAO,OAAO,EAC1D;;AAGH,aAAY,IAAI,GAAG;EAAE,GAAG;GAAqB,SAAS;EAAmB,CAAC;AAE1E,QAAO"}
@@ -1,22 +0,0 @@
1
- import { IntlMessageFormat } from "intl-messageformat";
2
-
3
- //#region src/icu-handler.ts
4
- const moduleCache = /* @__PURE__ */ new WeakMap();
5
- const getParsedICUMessages = (m, locale) => {
6
- const moduleCachedResult = moduleCache.get(m);
7
- if (moduleCachedResult && moduleCachedResult[locale]) return moduleCachedResult[locale];
8
- const parsedICUMessages = {};
9
- for (const translation of Object.keys(m)) {
10
- const intlMessageFormat = new IntlMessageFormat(m[translation], locale);
11
- parsedICUMessages[translation] = { format: (params) => intlMessageFormat.format(params) };
12
- }
13
- moduleCache.set(m, {
14
- ...moduleCachedResult,
15
- [locale]: parsedICUMessages
16
- });
17
- return parsedICUMessages;
18
- };
19
-
20
- //#endregion
21
- export { getParsedICUMessages as t };
22
- //# sourceMappingURL=icu-handler-DpDWxKGr.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"icu-handler-DpDWxKGr.mjs","names":["parsedICUMessages: ParsedICUMessages<any>"],"sources":["../src/icu-handler.ts"],"sourcesContent":["import type { ParsedICUMessages, TranslationMessagesByKey } from './types';\nimport { IntlMessageFormat } from 'intl-messageformat';\n\ntype ICUMessagesByLocale = Record<string, ParsedICUMessages<any>>;\n\nconst moduleCache = new WeakMap<\n TranslationMessagesByKey,\n ICUMessagesByLocale\n>();\n\nexport const getParsedICUMessages = (\n m: TranslationMessagesByKey,\n locale: string,\n): ParsedICUMessages<any> => {\n const moduleCachedResult = moduleCache.get(m);\n\n if (moduleCachedResult && moduleCachedResult[locale]) {\n return moduleCachedResult[locale];\n }\n\n const parsedICUMessages: ParsedICUMessages<any> = {};\n\n for (const translation of Object.keys(m)) {\n const intlMessageFormat = new IntlMessageFormat(m[translation], locale);\n parsedICUMessages[translation] = {\n format: (params: any) => intlMessageFormat.format(params),\n };\n }\n\n moduleCache.set(m, { ...moduleCachedResult, [locale]: parsedICUMessages });\n\n return parsedICUMessages;\n};\n"],"mappings":";;;AAKA,MAAM,8BAAc,IAAI,SAGrB;AAEH,MAAa,wBACX,GACA,WAC2B;CAC3B,MAAM,qBAAqB,YAAY,IAAI,EAAE;AAE7C,KAAI,sBAAsB,mBAAmB,QAC3C,QAAO,mBAAmB;CAG5B,MAAMA,oBAA4C,EAAE;AAEpD,MAAK,MAAM,eAAe,OAAO,KAAK,EAAE,EAAE;EACxC,MAAM,oBAAoB,IAAI,kBAAkB,EAAE,cAAc,OAAO;AACvE,oBAAkB,eAAe,EAC/B,SAAS,WAAgB,kBAAkB,OAAO,OAAO,EAC1D;;AAGH,aAAY,IAAI,GAAG;EAAE,GAAG;GAAqB,SAAS;EAAmB,CAAC;AAE1E,QAAO"}
@@ -1,7 +0,0 @@
1
- import { c as ParsedFormatFnByKey, p as TranslationFile, r as LanguageName, x as TranslationModuleByLanguage } from "./types-DpryIirw.mjs";
2
-
3
- //#region src/translation-file.d.ts
4
- declare function createTranslationFile<Language extends LanguageName, FormatFnByKey extends ParsedFormatFnByKey>(translationsByLanguage: TranslationModuleByLanguage<Language, FormatFnByKey>): TranslationFile<Language, FormatFnByKey>;
5
- //#endregion
6
- export { createTranslationFile as t };
7
- //# sourceMappingURL=translation-file-Ca5lZ9Dd.d.mts.map
@@ -1,7 +0,0 @@
1
- import { c as ParsedFormatFnByKey, p as TranslationFile, r as LanguageName, x as TranslationModuleByLanguage } from "./types-C00NNtxU.cjs";
2
-
3
- //#region src/translation-file.d.ts
4
- declare function createTranslationFile<Language extends LanguageName, FormatFnByKey extends ParsedFormatFnByKey>(translationsByLanguage: TranslationModuleByLanguage<Language, FormatFnByKey>): TranslationFile<Language, FormatFnByKey>;
5
- //#endregion
6
- export { createTranslationFile as t };
7
- //# sourceMappingURL=translation-file-CqTkqKMS.d.cts.map
@@ -1,28 +0,0 @@
1
- //#region src/translation-file.ts
2
- function createTranslationFile(translationsByLanguage) {
3
- function getByLanguage(language) {
4
- const translationModule = translationsByLanguage[language];
5
- if (!translationModule) throw new Error(`Attempted to retrieve translations for unknown language "${language}"`);
6
- return translationModule;
7
- }
8
- return {
9
- getLoadedMessages(language, locale) {
10
- return getByLanguage(language).getValue(locale || language) || null;
11
- },
12
- getMessages(language, locale) {
13
- const translationModule = getByLanguage(language);
14
- return translationModule.load().then(() => {
15
- const result = translationModule.getValue(locale || language);
16
- if (!result) throw new Error(`Unable to find translations for ${language} after attempting to load. Module may have failed to load or an internal error may have occurred.`);
17
- return result;
18
- });
19
- },
20
- load(language) {
21
- return getByLanguage(language).load();
22
- }
23
- };
24
- }
25
-
26
- //#endregion
27
- export { createTranslationFile as t };
28
- //# sourceMappingURL=translation-file-U7k1_uqE.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"translation-file-U7k1_uqE.mjs","names":[],"sources":["../src/translation-file.ts"],"sourcesContent":["import type {\n TranslationModule,\n TranslationModuleByLanguage,\n ParsedICUMessages,\n LanguageName,\n ParsedFormatFnByKey,\n TranslationFile,\n} from './types';\n\nexport function createTranslationFile<\n Language extends LanguageName,\n FormatFnByKey extends ParsedFormatFnByKey,\n>(\n translationsByLanguage: TranslationModuleByLanguage<Language, FormatFnByKey>,\n): TranslationFile<Language, FormatFnByKey> {\n function getByLanguage(language: Language): TranslationModule<FormatFnByKey> {\n const translationModule = translationsByLanguage[language];\n if (!translationModule) {\n throw new Error(\n `Attempted to retrieve translations for unknown language \"${language}\"`,\n );\n }\n return translationModule;\n }\n\n return {\n getLoadedMessages(\n language: Language,\n locale?: string,\n ): ParsedICUMessages<FormatFnByKey> | null {\n const translationModule = getByLanguage(language);\n return translationModule.getValue(locale || language) || null;\n },\n getMessages(\n language: Language,\n locale?: string,\n ): Promise<ParsedICUMessages<FormatFnByKey>> {\n const translationModule = getByLanguage(language);\n return translationModule.load().then(() => {\n const result = translationModule.getValue(locale || language);\n if (!result) {\n throw new Error(\n `Unable to find translations for ${language} after attempting to load. Module may have failed to load or an internal error may have occurred.`,\n );\n }\n return result;\n });\n },\n load(language: Language): Promise<void> {\n const translationModule = getByLanguage(language);\n return translationModule.load();\n },\n };\n}\n"],"mappings":";AASA,SAAgB,sBAId,wBAC0C;CAC1C,SAAS,cAAc,UAAsD;EAC3E,MAAM,oBAAoB,uBAAuB;AACjD,MAAI,CAAC,kBACH,OAAM,IAAI,MACR,4DAA4D,SAAS,GACtE;AAEH,SAAO;;AAGT,QAAO;EACL,kBACE,UACA,QACyC;AAEzC,UAD0B,cAAc,SAAS,CACxB,SAAS,UAAU,SAAS,IAAI;;EAE3D,YACE,UACA,QAC2C;GAC3C,MAAM,oBAAoB,cAAc,SAAS;AACjD,UAAO,kBAAkB,MAAM,CAAC,WAAW;IACzC,MAAM,SAAS,kBAAkB,SAAS,UAAU,SAAS;AAC7D,QAAI,CAAC,OACH,OAAM,IAAI,MACR,mCAAmC,SAAS,mGAC7C;AAEH,WAAO;KACP;;EAEJ,KAAK,UAAmC;AAEtC,UAD0B,cAAc,SAAS,CACxB,MAAM;;EAElC"}
@@ -1,34 +0,0 @@
1
-
2
- //#region src/translation-file.ts
3
- function createTranslationFile(translationsByLanguage) {
4
- function getByLanguage(language) {
5
- const translationModule = translationsByLanguage[language];
6
- if (!translationModule) throw new Error(`Attempted to retrieve translations for unknown language "${language}"`);
7
- return translationModule;
8
- }
9
- return {
10
- getLoadedMessages(language, locale) {
11
- return getByLanguage(language).getValue(locale || language) || null;
12
- },
13
- getMessages(language, locale) {
14
- const translationModule = getByLanguage(language);
15
- return translationModule.load().then(() => {
16
- const result = translationModule.getValue(locale || language);
17
- if (!result) throw new Error(`Unable to find translations for ${language} after attempting to load. Module may have failed to load or an internal error may have occurred.`);
18
- return result;
19
- });
20
- },
21
- load(language) {
22
- return getByLanguage(language).load();
23
- }
24
- };
25
- }
26
-
27
- //#endregion
28
- Object.defineProperty(exports, 'createTranslationFile', {
29
- enumerable: true,
30
- get: function () {
31
- return createTranslationFile;
32
- }
33
- });
34
- //# sourceMappingURL=translation-file-rax5G8Pd.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"translation-file-rax5G8Pd.cjs","names":[],"sources":["../src/translation-file.ts"],"sourcesContent":["import type {\n TranslationModule,\n TranslationModuleByLanguage,\n ParsedICUMessages,\n LanguageName,\n ParsedFormatFnByKey,\n TranslationFile,\n} from './types';\n\nexport function createTranslationFile<\n Language extends LanguageName,\n FormatFnByKey extends ParsedFormatFnByKey,\n>(\n translationsByLanguage: TranslationModuleByLanguage<Language, FormatFnByKey>,\n): TranslationFile<Language, FormatFnByKey> {\n function getByLanguage(language: Language): TranslationModule<FormatFnByKey> {\n const translationModule = translationsByLanguage[language];\n if (!translationModule) {\n throw new Error(\n `Attempted to retrieve translations for unknown language \"${language}\"`,\n );\n }\n return translationModule;\n }\n\n return {\n getLoadedMessages(\n language: Language,\n locale?: string,\n ): ParsedICUMessages<FormatFnByKey> | null {\n const translationModule = getByLanguage(language);\n return translationModule.getValue(locale || language) || null;\n },\n getMessages(\n language: Language,\n locale?: string,\n ): Promise<ParsedICUMessages<FormatFnByKey>> {\n const translationModule = getByLanguage(language);\n return translationModule.load().then(() => {\n const result = translationModule.getValue(locale || language);\n if (!result) {\n throw new Error(\n `Unable to find translations for ${language} after attempting to load. Module may have failed to load or an internal error may have occurred.`,\n );\n }\n return result;\n });\n },\n load(language: Language): Promise<void> {\n const translationModule = getByLanguage(language);\n return translationModule.load();\n },\n };\n}\n"],"mappings":";;AASA,SAAgB,sBAId,wBAC0C;CAC1C,SAAS,cAAc,UAAsD;EAC3E,MAAM,oBAAoB,uBAAuB;AACjD,MAAI,CAAC,kBACH,OAAM,IAAI,MACR,4DAA4D,SAAS,GACtE;AAEH,SAAO;;AAGT,QAAO;EACL,kBACE,UACA,QACyC;AAEzC,UAD0B,cAAc,SAAS,CACxB,SAAS,UAAU,SAAS,IAAI;;EAE3D,YACE,UACA,QAC2C;GAC3C,MAAM,oBAAoB,cAAc,SAAS;AACjD,UAAO,kBAAkB,MAAM,CAAC,WAAW;IACzC,MAAM,SAAS,kBAAkB,SAAS,UAAU,SAAS;AAC7D,QAAI,CAAC,OACH,OAAM,IAAI,MACR,mCAAmC,SAAS,mGAC7C;AAEH,WAAO;KACP;;EAEJ,KAAK,UAAmC;AAEtC,UAD0B,cAAc,SAAS,CACxB,MAAM;;EAElC"}