@intlayer/cli 5.8.1 → 6.0.0-canary.1

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.
Files changed (134) hide show
  1. package/dist/cjs/IntlayerEventListener.cjs +241 -0
  2. package/dist/cjs/IntlayerEventListener.cjs.map +1 -0
  3. package/dist/cjs/cli.cjs +29 -7
  4. package/dist/cjs/cli.cjs.map +1 -1
  5. package/dist/cjs/config.cjs +5 -1
  6. package/dist/cjs/config.cjs.map +1 -1
  7. package/dist/cjs/fill/autoFill.cjs +105 -0
  8. package/dist/cjs/fill/autoFill.cjs.map +1 -0
  9. package/dist/cjs/fill/formatAutoFillData.cjs +108 -0
  10. package/dist/cjs/fill/formatAutoFillData.cjs.map +1 -0
  11. package/dist/cjs/fill/formatAutoFilledFilePath.cjs +46 -0
  12. package/dist/cjs/fill/formatAutoFilledFilePath.cjs.map +1 -0
  13. package/dist/cjs/fill/getTargetDictionary.cjs +86 -0
  14. package/dist/cjs/fill/getTargetDictionary.cjs.map +1 -0
  15. package/dist/cjs/fill/index.cjs +257 -0
  16. package/dist/cjs/fill/index.cjs.map +1 -0
  17. package/dist/cjs/index.cjs +4 -2
  18. package/dist/cjs/index.cjs.map +1 -1
  19. package/dist/cjs/listContentDeclaration.cjs +37 -19
  20. package/dist/cjs/listContentDeclaration.cjs.map +1 -1
  21. package/dist/cjs/liveSync.cjs +254 -0
  22. package/dist/cjs/liveSync.cjs.map +1 -0
  23. package/dist/cjs/pull.cjs +119 -117
  24. package/dist/cjs/pull.cjs.map +1 -1
  25. package/dist/cjs/pullLog.cjs +146 -0
  26. package/dist/cjs/pullLog.cjs.map +1 -0
  27. package/dist/cjs/push.cjs +74 -88
  28. package/dist/cjs/push.cjs.map +1 -1
  29. package/dist/cjs/pushConfig.cjs +10 -25
  30. package/dist/cjs/pushConfig.cjs.map +1 -1
  31. package/dist/cjs/pushLog.cjs +130 -0
  32. package/dist/cjs/pushLog.cjs.map +1 -0
  33. package/dist/cjs/reviewDoc.cjs +45 -36
  34. package/dist/cjs/reviewDoc.cjs.map +1 -1
  35. package/dist/cjs/test/index.cjs +91 -0
  36. package/dist/cjs/test/index.cjs.map +1 -0
  37. package/dist/cjs/test/listMissingTranslations.cjs +73 -0
  38. package/dist/cjs/test/listMissingTranslations.cjs.map +1 -0
  39. package/dist/cjs/translateDoc.cjs +42 -34
  40. package/dist/cjs/translateDoc.cjs.map +1 -1
  41. package/dist/cjs/utils/checkAIAccess.cjs +5 -1
  42. package/dist/cjs/utils/checkAIAccess.cjs.map +1 -1
  43. package/dist/cjs/utils/chunkInference.cjs +7 -14
  44. package/dist/cjs/utils/chunkInference.cjs.map +1 -1
  45. package/dist/esm/IntlayerEventListener.mjs +207 -0
  46. package/dist/esm/IntlayerEventListener.mjs.map +1 -0
  47. package/dist/esm/cli.mjs +26 -4
  48. package/dist/esm/cli.mjs.map +1 -1
  49. package/dist/esm/config.mjs +5 -1
  50. package/dist/esm/config.mjs.map +1 -1
  51. package/dist/esm/fill/autoFill.mjs +92 -0
  52. package/dist/esm/fill/autoFill.mjs.map +1 -0
  53. package/dist/esm/fill/formatAutoFillData.mjs +84 -0
  54. package/dist/esm/fill/formatAutoFillData.mjs.map +1 -0
  55. package/dist/esm/fill/formatAutoFilledFilePath.mjs +22 -0
  56. package/dist/esm/fill/formatAutoFilledFilePath.mjs.map +1 -0
  57. package/dist/esm/fill/getTargetDictionary.mjs +51 -0
  58. package/dist/esm/fill/getTargetDictionary.mjs.map +1 -0
  59. package/dist/esm/fill/index.mjs +240 -0
  60. package/dist/esm/fill/index.mjs.map +1 -0
  61. package/dist/esm/index.mjs +2 -1
  62. package/dist/esm/index.mjs.map +1 -1
  63. package/dist/esm/listContentDeclaration.mjs +38 -17
  64. package/dist/esm/listContentDeclaration.mjs.map +1 -1
  65. package/dist/esm/liveSync.mjs +220 -0
  66. package/dist/esm/liveSync.mjs.map +1 -0
  67. package/dist/esm/pull.mjs +123 -108
  68. package/dist/esm/pull.mjs.map +1 -1
  69. package/dist/esm/pullLog.mjs +127 -0
  70. package/dist/esm/pullLog.mjs.map +1 -0
  71. package/dist/esm/push.mjs +81 -90
  72. package/dist/esm/push.mjs.map +1 -1
  73. package/dist/esm/pushConfig.mjs +11 -26
  74. package/dist/esm/pushConfig.mjs.map +1 -1
  75. package/dist/esm/pushLog.mjs +111 -0
  76. package/dist/esm/pushLog.mjs.map +1 -0
  77. package/dist/esm/reviewDoc.mjs +55 -38
  78. package/dist/esm/reviewDoc.mjs.map +1 -1
  79. package/dist/esm/test/index.mjs +74 -0
  80. package/dist/esm/test/index.mjs.map +1 -0
  81. package/dist/esm/test/listMissingTranslations.mjs +41 -0
  82. package/dist/esm/test/listMissingTranslations.mjs.map +1 -0
  83. package/dist/esm/translateDoc.mjs +52 -37
  84. package/dist/esm/translateDoc.mjs.map +1 -1
  85. package/dist/esm/utils/checkAIAccess.mjs +5 -1
  86. package/dist/esm/utils/checkAIAccess.mjs.map +1 -1
  87. package/dist/esm/utils/chunkInference.mjs +14 -16
  88. package/dist/esm/utils/chunkInference.mjs.map +1 -1
  89. package/dist/types/IntlayerEventListener.d.ts +85 -0
  90. package/dist/types/IntlayerEventListener.d.ts.map +1 -0
  91. package/dist/types/cli.d.ts.map +1 -1
  92. package/dist/types/config.d.ts.map +1 -1
  93. package/dist/types/fill/autoFill.d.ts +4 -0
  94. package/dist/types/fill/autoFill.d.ts.map +1 -0
  95. package/dist/types/fill/formatAutoFillData.d.ts +9 -0
  96. package/dist/types/fill/formatAutoFillData.d.ts.map +1 -0
  97. package/dist/types/fill/formatAutoFilledFilePath.d.ts +3 -0
  98. package/dist/types/fill/formatAutoFilledFilePath.d.ts.map +1 -0
  99. package/dist/types/fill/getTargetDictionary.d.ts +4 -0
  100. package/dist/types/fill/getTargetDictionary.d.ts.map +1 -0
  101. package/dist/types/{fill.d.ts → fill/index.d.ts} +2 -5
  102. package/dist/types/fill/index.d.ts.map +1 -0
  103. package/dist/types/index.d.ts +1 -0
  104. package/dist/types/index.d.ts.map +1 -1
  105. package/dist/types/listContentDeclaration.d.ts +4 -5
  106. package/dist/types/listContentDeclaration.d.ts.map +1 -1
  107. package/dist/types/liveSync.d.ts +6 -0
  108. package/dist/types/liveSync.d.ts.map +1 -0
  109. package/dist/types/pull.d.ts.map +1 -1
  110. package/dist/types/pullLog.d.ts +24 -0
  111. package/dist/types/pullLog.d.ts.map +1 -0
  112. package/dist/types/push.d.ts +1 -1
  113. package/dist/types/push.d.ts.map +1 -1
  114. package/dist/types/pushConfig.d.ts +0 -1
  115. package/dist/types/pushConfig.d.ts.map +1 -1
  116. package/dist/types/pushLog.d.ts +23 -0
  117. package/dist/types/pushLog.d.ts.map +1 -0
  118. package/dist/types/reviewDoc.d.ts +1 -1
  119. package/dist/types/reviewDoc.d.ts.map +1 -1
  120. package/dist/types/test/index.d.ts +8 -0
  121. package/dist/types/test/index.d.ts.map +1 -0
  122. package/dist/types/test/listMissingTranslations.d.ts +12 -0
  123. package/dist/types/test/listMissingTranslations.d.ts.map +1 -0
  124. package/dist/types/translateDoc.d.ts +1 -1
  125. package/dist/types/translateDoc.d.ts.map +1 -1
  126. package/dist/types/utils/checkAIAccess.d.ts.map +1 -1
  127. package/dist/types/utils/chunkInference.d.ts +2 -1
  128. package/dist/types/utils/chunkInference.d.ts.map +1 -1
  129. package/package.json +19 -15
  130. package/dist/cjs/fill.cjs +0 -405
  131. package/dist/cjs/fill.cjs.map +0 -1
  132. package/dist/esm/fill.mjs +0 -385
  133. package/dist/esm/fill.mjs.map +0 -1
  134. package/dist/types/fill.d.ts.map +0 -1
@@ -0,0 +1,92 @@
1
+ import {
2
+ formatLocale,
3
+ formatPath,
4
+ reduceDictionaryContent,
5
+ writeContentDeclaration
6
+ } from "@intlayer/chokidar";
7
+ import {
8
+ colorizeKey,
9
+ getAppLogger
10
+ } from "@intlayer/config";
11
+ import {
12
+ getFilteredLocalesContent,
13
+ getLocalisedContent
14
+ } from "@intlayer/core";
15
+ import { formatAutoFillData } from "./formatAutoFillData.mjs";
16
+ const autoFill = async (fullDictionary, contentDeclarationFile, autoFillOptions, outputLocales, parentLocales, configuration) => {
17
+ const appLogger = getAppLogger(configuration, {
18
+ config: {
19
+ prefix: ""
20
+ }
21
+ });
22
+ let localeList = (outputLocales ?? configuration.internationalization.locales).filter((locale) => !parentLocales?.includes(locale));
23
+ const filePath = contentDeclarationFile.filePath;
24
+ if (!filePath) {
25
+ appLogger("No file path found for dictionary", {
26
+ level: "error"
27
+ });
28
+ return;
29
+ }
30
+ const autoFillData = formatAutoFillData(
31
+ autoFillOptions,
32
+ localeList,
33
+ filePath,
34
+ fullDictionary.key,
35
+ configuration
36
+ );
37
+ for await (const output of autoFillData) {
38
+ const reducedDictionary = reduceDictionaryContent(
39
+ fullDictionary,
40
+ contentDeclarationFile
41
+ );
42
+ if (output.isPerLocale) {
43
+ const sourceLocale = output.localeList[0];
44
+ const sourceLocaleContent = getLocalisedContent(
45
+ reducedDictionary,
46
+ sourceLocale,
47
+ { dictionaryKey: reducedDictionary.key, keyPath: [] }
48
+ );
49
+ await writeContentDeclaration({
50
+ ...fullDictionary,
51
+ locale: sourceLocale,
52
+ autoFilled: true,
53
+ autoFill: void 0,
54
+ content: sourceLocaleContent.content,
55
+ filePath: output.filePath
56
+ });
57
+ if (output.filePath) {
58
+ appLogger(
59
+ `Auto filled per-locale content declaration for '${colorizeKey(fullDictionary.key)}' written to ${formatPath(output.filePath)} for locale ${formatLocale(sourceLocale)}`,
60
+ {
61
+ level: "info"
62
+ }
63
+ );
64
+ }
65
+ } else {
66
+ const content = getFilteredLocalesContent(
67
+ reducedDictionary.content,
68
+ output.localeList,
69
+ { dictionaryKey: reducedDictionary.key, keyPath: [] }
70
+ );
71
+ await writeContentDeclaration({
72
+ ...fullDictionary,
73
+ autoFilled: true,
74
+ autoFill: void 0,
75
+ content,
76
+ filePath: output.filePath
77
+ });
78
+ if (output.filePath) {
79
+ appLogger(
80
+ `Auto filled content declaration for '${colorizeKey(fullDictionary.key)}' written to ${formatPath(output.filePath)}`,
81
+ {
82
+ level: "info"
83
+ }
84
+ );
85
+ }
86
+ }
87
+ }
88
+ };
89
+ export {
90
+ autoFill
91
+ };
92
+ //# sourceMappingURL=autoFill.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/fill/autoFill.ts"],"sourcesContent":["import {\n formatLocale,\n formatPath,\n reduceDictionaryContent,\n writeContentDeclaration,\n} from '@intlayer/chokidar';\nimport {\n colorizeKey,\n getAppLogger,\n type IntlayerConfig,\n Locales,\n} from '@intlayer/config';\nimport {\n type AutoFill,\n type ContentNode,\n type Dictionary,\n getFilteredLocalesContent,\n getLocalisedContent,\n} from '@intlayer/core';\nimport { AutoFillData, formatAutoFillData } from './formatAutoFillData';\n\nexport const autoFill = async (\n fullDictionary: Dictionary,\n contentDeclarationFile: Dictionary,\n autoFillOptions: AutoFill,\n outputLocales: Locales[],\n parentLocales: Locales[],\n configuration: IntlayerConfig\n) => {\n const appLogger = getAppLogger(configuration, {\n config: {\n prefix: '',\n },\n });\n let localeList: Locales[] = (\n outputLocales ?? configuration.internationalization.locales\n ).filter((locale) => !parentLocales?.includes(locale));\n\n const filePath = contentDeclarationFile.filePath;\n\n if (!filePath) {\n appLogger('No file path found for dictionary', {\n level: 'error',\n });\n return;\n }\n\n const autoFillData: AutoFillData[] = formatAutoFillData(\n autoFillOptions,\n localeList,\n filePath,\n fullDictionary.key,\n configuration\n );\n\n for await (const output of autoFillData) {\n const reducedDictionary = reduceDictionaryContent(\n fullDictionary,\n contentDeclarationFile\n );\n\n if (output.isPerLocale) {\n const sourceLocale = output.localeList[0];\n\n const sourceLocaleContent = getLocalisedContent(\n reducedDictionary as unknown as ContentNode,\n sourceLocale,\n { dictionaryKey: reducedDictionary.key, keyPath: [] }\n );\n\n await writeContentDeclaration({\n ...fullDictionary,\n locale: sourceLocale,\n autoFilled: true,\n autoFill: undefined,\n content: sourceLocaleContent.content,\n filePath: output.filePath,\n });\n\n if (output.filePath) {\n appLogger(\n `Auto filled per-locale content declaration for '${colorizeKey(fullDictionary.key)}' written to ${formatPath(output.filePath)} for locale ${formatLocale(sourceLocale)}`,\n {\n level: 'info',\n }\n );\n }\n } else {\n const content = getFilteredLocalesContent(\n reducedDictionary.content as unknown as ContentNode,\n output.localeList,\n { dictionaryKey: reducedDictionary.key, keyPath: [] }\n );\n\n // write file\n await writeContentDeclaration({\n ...fullDictionary,\n autoFilled: true,\n autoFill: undefined,\n content,\n filePath: output.filePath,\n });\n\n if (output.filePath) {\n appLogger(\n `Auto filled content declaration for '${colorizeKey(fullDictionary.key)}' written to ${formatPath(output.filePath)}`,\n {\n level: 'info',\n }\n );\n }\n }\n }\n};\n"],"mappings":"AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AACP;AAAA,EAIE;AAAA,EACA;AAAA,OACK;AACP,SAAuB,0BAA0B;AAE1C,MAAM,WAAW,OACtB,gBACA,wBACA,iBACA,eACA,eACA,kBACG;AACH,QAAM,YAAY,aAAa,eAAe;AAAA,IAC5C,QAAQ;AAAA,MACN,QAAQ;AAAA,IACV;AAAA,EACF,CAAC;AACD,MAAI,cACF,iBAAiB,cAAc,qBAAqB,SACpD,OAAO,CAAC,WAAW,CAAC,eAAe,SAAS,MAAM,CAAC;AAErD,QAAM,WAAW,uBAAuB;AAExC,MAAI,CAAC,UAAU;AACb,cAAU,qCAAqC;AAAA,MAC7C,OAAO;AAAA,IACT,CAAC;AACD;AAAA,EACF;AAEA,QAAM,eAA+B;AAAA,IACnC;AAAA,IACA;AAAA,IACA;AAAA,IACA,eAAe;AAAA,IACf;AAAA,EACF;AAEA,mBAAiB,UAAU,cAAc;AACvC,UAAM,oBAAoB;AAAA,MACxB;AAAA,MACA;AAAA,IACF;AAEA,QAAI,OAAO,aAAa;AACtB,YAAM,eAAe,OAAO,WAAW,CAAC;AAExC,YAAM,sBAAsB;AAAA,QAC1B;AAAA,QACA;AAAA,QACA,EAAE,eAAe,kBAAkB,KAAK,SAAS,CAAC,EAAE;AAAA,MACtD;AAEA,YAAM,wBAAwB;AAAA,QAC5B,GAAG;AAAA,QACH,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,SAAS,oBAAoB;AAAA,QAC7B,UAAU,OAAO;AAAA,MACnB,CAAC;AAED,UAAI,OAAO,UAAU;AACnB;AAAA,UACE,mDAAmD,YAAY,eAAe,GAAG,CAAC,gBAAgB,WAAW,OAAO,QAAQ,CAAC,eAAe,aAAa,YAAY,CAAC;AAAA,UACtK;AAAA,YACE,OAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF;AAAA,IACF,OAAO;AACL,YAAM,UAAU;AAAA,QACd,kBAAkB;AAAA,QAClB,OAAO;AAAA,QACP,EAAE,eAAe,kBAAkB,KAAK,SAAS,CAAC,EAAE;AAAA,MACtD;AAGA,YAAM,wBAAwB;AAAA,QAC5B,GAAG;AAAA,QACH,YAAY;AAAA,QACZ,UAAU;AAAA,QACV;AAAA,QACA,UAAU,OAAO;AAAA,MACnB,CAAC;AAED,UAAI,OAAO,UAAU;AACnB;AAAA,UACE,wCAAwC,YAAY,eAAe,GAAG,CAAC,gBAAgB,WAAW,OAAO,QAAQ,CAAC;AAAA,UAClH;AAAA,YACE,OAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,84 @@
1
+ import { extname } from "path";
2
+ import { formatAutoFilledFilePath } from "./formatAutoFilledFilePath.mjs";
3
+ const formatAutoFillData = (autoFillField, localeList, filePath, dictionaryKey, configuration) => {
4
+ const outputContentDeclarationFile = [];
5
+ const baseDir = configuration.content.baseDir;
6
+ if (!Boolean(autoFillField)) return outputContentDeclarationFile;
7
+ if (autoFillField === true) {
8
+ let jsonFilePath = filePath.replace(extname(filePath), ".json");
9
+ if (filePath === jsonFilePath) {
10
+ jsonFilePath = jsonFilePath.replace(extname(jsonFilePath), ".fill.json");
11
+ }
12
+ outputContentDeclarationFile.push({
13
+ localeList,
14
+ filePath: jsonFilePath,
15
+ isPerLocale: false
16
+ });
17
+ }
18
+ if (typeof autoFillField === "string") {
19
+ if (autoFillField.includes("{{locale}}")) {
20
+ const output = localeList.map((locale) => {
21
+ const formattedFilePath = formatAutoFilledFilePath(
22
+ autoFillField,
23
+ dictionaryKey,
24
+ filePath,
25
+ baseDir,
26
+ locale
27
+ );
28
+ return {
29
+ localeList: [locale],
30
+ filePath: formattedFilePath,
31
+ isPerLocale: true
32
+ };
33
+ });
34
+ outputContentDeclarationFile.push(...output);
35
+ } else {
36
+ const formattedFilePath = formatAutoFilledFilePath(
37
+ autoFillField,
38
+ dictionaryKey,
39
+ filePath,
40
+ baseDir
41
+ );
42
+ outputContentDeclarationFile.push({
43
+ localeList,
44
+ filePath: formattedFilePath,
45
+ isPerLocale: false
46
+ });
47
+ }
48
+ return outputContentDeclarationFile;
49
+ }
50
+ if (typeof autoFillField === "object") {
51
+ const localeList2 = Object.keys(autoFillField).filter(
52
+ (locale) => typeof autoFillField[locale] === "string"
53
+ );
54
+ const output = localeList2.filter((locale) => Boolean(autoFillField[locale])).map((locale) => {
55
+ const formattedFilePath = formatAutoFilledFilePath(
56
+ autoFillField[locale],
57
+ dictionaryKey,
58
+ filePath,
59
+ baseDir,
60
+ locale
61
+ );
62
+ return {
63
+ localeList: [locale],
64
+ filePath: formattedFilePath,
65
+ isPerLocale: true
66
+ };
67
+ });
68
+ const groupedByFilePath = output.reduce((acc, curr) => {
69
+ const existing = acc.find((item) => item.filePath === curr.filePath);
70
+ if (existing) {
71
+ existing.localeList.push(...curr.localeList);
72
+ } else {
73
+ acc.push(curr);
74
+ }
75
+ return acc;
76
+ }, []);
77
+ outputContentDeclarationFile.push(...groupedByFilePath);
78
+ }
79
+ return outputContentDeclarationFile;
80
+ };
81
+ export {
82
+ formatAutoFillData
83
+ };
84
+ //# sourceMappingURL=formatAutoFillData.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/fill/formatAutoFillData.ts"],"sourcesContent":["import { type IntlayerConfig, Locales } from '@intlayer/config';\nimport { type AutoFill } from '@intlayer/core';\nimport { extname } from 'path';\nimport { formatAutoFilledFilePath } from './formatAutoFilledFilePath';\n\nexport type AutoFillData = {\n localeList: Locales[];\n filePath: string;\n isPerLocale: boolean;\n};\n\nexport const formatAutoFillData = (\n autoFillField: AutoFill,\n localeList: Locales[],\n filePath: string,\n dictionaryKey: string,\n configuration: IntlayerConfig\n): AutoFillData[] => {\n const outputContentDeclarationFile: AutoFillData[] = [];\n\n const baseDir = configuration.content.baseDir;\n\n if (!Boolean(autoFillField)) return outputContentDeclarationFile;\n\n if (autoFillField === true) {\n // wanted jsonFilePath: /..../src/components/home/index.content.json\n // replace file extension in json\n let jsonFilePath = filePath.replace(extname(filePath), '.json');\n\n // if both filePath jsonFilePath are same path, change it as : /..../src/components/home/index.fill.content.json\n if (filePath === jsonFilePath) {\n jsonFilePath = jsonFilePath.replace(extname(jsonFilePath), '.fill.json');\n }\n\n outputContentDeclarationFile.push({\n localeList,\n filePath: jsonFilePath,\n isPerLocale: false,\n });\n }\n\n if (typeof autoFillField === 'string') {\n if (autoFillField.includes('{{locale}}')) {\n const output = localeList.map((locale) => {\n const formattedFilePath = formatAutoFilledFilePath(\n autoFillField,\n dictionaryKey,\n filePath,\n baseDir,\n locale\n );\n\n return {\n localeList: [locale],\n filePath: formattedFilePath,\n isPerLocale: true,\n };\n });\n\n outputContentDeclarationFile.push(...output);\n } else {\n const formattedFilePath = formatAutoFilledFilePath(\n autoFillField,\n dictionaryKey,\n filePath,\n baseDir\n );\n\n outputContentDeclarationFile.push({\n localeList,\n filePath: formattedFilePath,\n isPerLocale: false,\n });\n }\n\n return outputContentDeclarationFile;\n }\n\n if (typeof autoFillField === 'object') {\n const localeList = Object.keys(autoFillField).filter(\n (locale) => typeof autoFillField[locale] === 'string'\n ) as Locales[];\n\n const output: AutoFillData[] = localeList\n .filter((locale) => Boolean(autoFillField[locale]))\n .map((locale) => {\n const formattedFilePath = formatAutoFilledFilePath(\n autoFillField[locale],\n dictionaryKey,\n filePath,\n baseDir,\n locale\n );\n\n return {\n localeList: [locale],\n filePath: formattedFilePath,\n isPerLocale: true,\n };\n });\n\n // Group by filePath and merge localeList\n const groupedByFilePath = output.reduce((acc, curr) => {\n const existing = acc.find((item) => item.filePath === curr.filePath);\n if (existing) {\n existing.localeList.push(...curr.localeList);\n } else {\n acc.push(curr);\n }\n return acc;\n }, [] as AutoFillData[]);\n\n outputContentDeclarationFile.push(...groupedByFilePath);\n }\n\n return outputContentDeclarationFile;\n};\n"],"mappings":"AAEA,SAAS,eAAe;AACxB,SAAS,gCAAgC;AAQlC,MAAM,qBAAqB,CAChC,eACA,YACA,UACA,eACA,kBACmB;AACnB,QAAM,+BAA+C,CAAC;AAEtD,QAAM,UAAU,cAAc,QAAQ;AAEtC,MAAI,CAAC,QAAQ,aAAa,EAAG,QAAO;AAEpC,MAAI,kBAAkB,MAAM;AAG1B,QAAI,eAAe,SAAS,QAAQ,QAAQ,QAAQ,GAAG,OAAO;AAG9D,QAAI,aAAa,cAAc;AAC7B,qBAAe,aAAa,QAAQ,QAAQ,YAAY,GAAG,YAAY;AAAA,IACzE;AAEA,iCAA6B,KAAK;AAAA,MAChC;AAAA,MACA,UAAU;AAAA,MACV,aAAa;AAAA,IACf,CAAC;AAAA,EACH;AAEA,MAAI,OAAO,kBAAkB,UAAU;AACrC,QAAI,cAAc,SAAS,YAAY,GAAG;AACxC,YAAM,SAAS,WAAW,IAAI,CAAC,WAAW;AACxC,cAAM,oBAAoB;AAAA,UACxB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAEA,eAAO;AAAA,UACL,YAAY,CAAC,MAAM;AAAA,UACnB,UAAU;AAAA,UACV,aAAa;AAAA,QACf;AAAA,MACF,CAAC;AAED,mCAA6B,KAAK,GAAG,MAAM;AAAA,IAC7C,OAAO;AACL,YAAM,oBAAoB;AAAA,QACxB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAEA,mCAA6B,KAAK;AAAA,QAChC;AAAA,QACA,UAAU;AAAA,QACV,aAAa;AAAA,MACf,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,kBAAkB,UAAU;AACrC,UAAMA,cAAa,OAAO,KAAK,aAAa,EAAE;AAAA,MAC5C,CAAC,WAAW,OAAO,cAAc,MAAM,MAAM;AAAA,IAC/C;AAEA,UAAM,SAAyBA,YAC5B,OAAO,CAAC,WAAW,QAAQ,cAAc,MAAM,CAAC,CAAC,EACjD,IAAI,CAAC,WAAW;AACf,YAAM,oBAAoB;AAAA,QACxB,cAAc,MAAM;AAAA,QACpB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAEA,aAAO;AAAA,QACL,YAAY,CAAC,MAAM;AAAA,QACnB,UAAU;AAAA,QACV,aAAa;AAAA,MACf;AAAA,IACF,CAAC;AAGH,UAAM,oBAAoB,OAAO,OAAO,CAAC,KAAK,SAAS;AACrD,YAAM,WAAW,IAAI,KAAK,CAAC,SAAS,KAAK,aAAa,KAAK,QAAQ;AACnE,UAAI,UAAU;AACZ,iBAAS,WAAW,KAAK,GAAG,KAAK,UAAU;AAAA,MAC7C,OAAO;AACL,YAAI,KAAK,IAAI;AAAA,MACf;AACA,aAAO;AAAA,IACT,GAAG,CAAC,CAAmB;AAEvB,iCAA6B,KAAK,GAAG,iBAAiB;AAAA,EACxD;AAEA,SAAO;AACT;","names":["localeList"]}
@@ -0,0 +1,22 @@
1
+ import { basename, dirname, join } from "path";
2
+ const transformUriToAbsolutePath = (uri, filePath, baseDir) => {
3
+ if (uri.startsWith("/")) {
4
+ return join(baseDir, uri);
5
+ }
6
+ if (uri.startsWith("./")) {
7
+ return join(dirname(filePath), uri);
8
+ }
9
+ return filePath;
10
+ };
11
+ const formatAutoFilledFilePath = (autoFillField, dictionaryKey, dictionaryFilePath, baseDir, locale) => {
12
+ const fileName = basename(dictionaryFilePath).split(".").slice(0, -2).join(".");
13
+ let result = autoFillField.replace("{{key}}", dictionaryKey).replace("{{fileName}}", fileName);
14
+ if (locale) {
15
+ result = result.replace("{{locale}}", locale);
16
+ }
17
+ return transformUriToAbsolutePath(result, dictionaryFilePath, baseDir);
18
+ };
19
+ export {
20
+ formatAutoFilledFilePath
21
+ };
22
+ //# sourceMappingURL=formatAutoFilledFilePath.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/fill/formatAutoFilledFilePath.ts"],"sourcesContent":["import { Locales } from '@intlayer/config';\nimport { basename, dirname, join } from 'path';\n\nconst transformUriToAbsolutePath = (\n uri: string,\n filePath: string,\n baseDir: string\n) => {\n if (uri.startsWith('/')) {\n return join(baseDir, uri);\n }\n\n if (uri.startsWith('./')) {\n return join(dirname(filePath), uri);\n }\n\n return filePath;\n};\n\nexport const formatAutoFilledFilePath = (\n autoFillField: string,\n dictionaryKey: string,\n dictionaryFilePath: string,\n baseDir: string,\n locale?: Locales\n) => {\n // transform `/src/components/home/index.content.json` to `index`\n // transform `./test.content.tsx` to `test`\n const fileName = basename(dictionaryFilePath)\n .split('.')\n .slice(0, -2) // Remove last 2 extensions (.content.tsx)\n .join('.');\n\n let result: string = autoFillField\n .replace('{{key}}', dictionaryKey)\n .replace('{{fileName}}', fileName);\n\n if (locale) {\n result = result.replace('{{locale}}', locale);\n }\n\n return transformUriToAbsolutePath(result, dictionaryFilePath, baseDir);\n};\n"],"mappings":"AACA,SAAS,UAAU,SAAS,YAAY;AAExC,MAAM,6BAA6B,CACjC,KACA,UACA,YACG;AACH,MAAI,IAAI,WAAW,GAAG,GAAG;AACvB,WAAO,KAAK,SAAS,GAAG;AAAA,EAC1B;AAEA,MAAI,IAAI,WAAW,IAAI,GAAG;AACxB,WAAO,KAAK,QAAQ,QAAQ,GAAG,GAAG;AAAA,EACpC;AAEA,SAAO;AACT;AAEO,MAAM,2BAA2B,CACtC,eACA,eACA,oBACA,SACA,WACG;AAGH,QAAM,WAAW,SAAS,kBAAkB,EACzC,MAAM,GAAG,EACT,MAAM,GAAG,EAAE,EACX,KAAK,GAAG;AAEX,MAAI,SAAiB,cAClB,QAAQ,WAAW,aAAa,EAChC,QAAQ,gBAAgB,QAAQ;AAEnC,MAAI,QAAQ;AACV,aAAS,OAAO,QAAQ,cAAc,MAAM;AAAA,EAC9C;AAEA,SAAO,2BAA2B,QAAQ,oBAAoB,OAAO;AACvE;","names":[]}
@@ -0,0 +1,51 @@
1
+ import { listGitFiles } from "@intlayer/chokidar";
2
+ import { getConfiguration } from "@intlayer/config";
3
+ import unmergedDictionariesRecord from "@intlayer/unmerged-dictionaries-entry";
4
+ import { join } from "path";
5
+ const ensureArray = (value) => [value].flat();
6
+ const getTargetDictionary = async (options) => {
7
+ const configuration = getConfiguration(options.configOptions);
8
+ const { baseDir } = configuration.content;
9
+ let result = Object.values(unmergedDictionariesRecord).flat();
10
+ if (typeof options.file !== "undefined") {
11
+ const fileArray = ensureArray(options.file);
12
+ const absoluteFilePaths = fileArray.map((file) => join(baseDir, file));
13
+ result = result.filter(
14
+ (dict) => dict.filePath && (absoluteFilePaths.includes(dict.filePath) || absoluteFilePaths.includes(join(baseDir, dict.filePath)))
15
+ );
16
+ }
17
+ if (typeof options.keys !== "undefined") {
18
+ result = result.filter(
19
+ (dict) => ensureArray(options.keys)?.includes(dict.key)
20
+ );
21
+ }
22
+ if (typeof options.excludedKeys !== "undefined") {
23
+ result = result.filter(
24
+ (dict) => !ensureArray(options.excludedKeys)?.includes(dict.key)
25
+ );
26
+ }
27
+ if (typeof options.pathFilter !== "undefined") {
28
+ result = result.filter(
29
+ (dict) => ensureArray(options.pathFilter)?.includes(dict.filePath ?? "")
30
+ );
31
+ }
32
+ if (typeof options.filter !== "undefined") {
33
+ result = result.filter(options.filter);
34
+ }
35
+ const gitOptions = options.gitOptions;
36
+ if (gitOptions) {
37
+ const gitChangedFiles = await listGitFiles(gitOptions);
38
+ if (gitChangedFiles) {
39
+ result = result.filter((dict) => {
40
+ if (!dict.filePath) return false;
41
+ return gitChangedFiles.some((gitFile) => dict.filePath === gitFile);
42
+ });
43
+ }
44
+ }
45
+ return result.filter((dict) => !dict.autoFilled);
46
+ };
47
+ export {
48
+ ensureArray,
49
+ getTargetDictionary
50
+ };
51
+ //# sourceMappingURL=getTargetDictionary.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/fill/getTargetDictionary.ts"],"sourcesContent":["import { listGitFiles } from '@intlayer/chokidar';\nimport { getConfiguration } from '@intlayer/config';\nimport unmergedDictionariesRecord from '@intlayer/unmerged-dictionaries-entry';\nimport { join } from 'path';\nimport type { FillOptions } from './index';\n\nexport const ensureArray = <T>(value: T | T[]): T[] => [value].flat() as T[];\n\nexport const getTargetDictionary = async (options: FillOptions) => {\n const configuration = getConfiguration(options.configOptions);\n\n const { baseDir } = configuration.content;\n\n let result = Object.values(unmergedDictionariesRecord).flat();\n\n // 1. if filePath not defined, list all content declaration files based on unmerged dictionaries list\n if (typeof options.file !== 'undefined') {\n const fileArray = ensureArray(options.file);\n const absoluteFilePaths = fileArray.map((file) => join(baseDir, file));\n\n result = result.filter(\n (dict) =>\n dict.filePath &&\n (absoluteFilePaths.includes(dict.filePath) ||\n absoluteFilePaths.includes(join(baseDir, dict.filePath)))\n );\n }\n\n if (typeof options.keys !== 'undefined') {\n result = result.filter((dict) =>\n ensureArray(options.keys)?.includes(dict.key)\n );\n }\n\n if (typeof options.excludedKeys !== 'undefined') {\n result = result.filter(\n (dict) => !ensureArray(options.excludedKeys)?.includes(dict.key)\n );\n }\n\n if (typeof options.pathFilter !== 'undefined') {\n result = result.filter((dict) =>\n ensureArray(options.pathFilter)?.includes(dict.filePath ?? '')\n );\n }\n\n if (typeof options.filter !== 'undefined') {\n result = result.filter(options.filter);\n }\n\n const gitOptions = options.gitOptions;\n if (gitOptions) {\n const gitChangedFiles = await listGitFiles(gitOptions);\n\n if (gitChangedFiles) {\n // Convert dictionary file paths to be relative to git root for comparison\n\n // Filter dictionaries based on git changed files\n result = result.filter((dict) => {\n if (!dict.filePath) return false;\n\n return gitChangedFiles.some((gitFile) => dict.filePath === gitFile);\n });\n }\n }\n\n return result.filter((dict) => !dict.autoFilled);\n};\n"],"mappings":"AAAA,SAAS,oBAAoB;AAC7B,SAAS,wBAAwB;AACjC,OAAO,gCAAgC;AACvC,SAAS,YAAY;AAGd,MAAM,cAAc,CAAI,UAAwB,CAAC,KAAK,EAAE,KAAK;AAE7D,MAAM,sBAAsB,OAAO,YAAyB;AACjE,QAAM,gBAAgB,iBAAiB,QAAQ,aAAa;AAE5D,QAAM,EAAE,QAAQ,IAAI,cAAc;AAElC,MAAI,SAAS,OAAO,OAAO,0BAA0B,EAAE,KAAK;AAG5D,MAAI,OAAO,QAAQ,SAAS,aAAa;AACvC,UAAM,YAAY,YAAY,QAAQ,IAAI;AAC1C,UAAM,oBAAoB,UAAU,IAAI,CAAC,SAAS,KAAK,SAAS,IAAI,CAAC;AAErE,aAAS,OAAO;AAAA,MACd,CAAC,SACC,KAAK,aACJ,kBAAkB,SAAS,KAAK,QAAQ,KACvC,kBAAkB,SAAS,KAAK,SAAS,KAAK,QAAQ,CAAC;AAAA,IAC7D;AAAA,EACF;AAEA,MAAI,OAAO,QAAQ,SAAS,aAAa;AACvC,aAAS,OAAO;AAAA,MAAO,CAAC,SACtB,YAAY,QAAQ,IAAI,GAAG,SAAS,KAAK,GAAG;AAAA,IAC9C;AAAA,EACF;AAEA,MAAI,OAAO,QAAQ,iBAAiB,aAAa;AAC/C,aAAS,OAAO;AAAA,MACd,CAAC,SAAS,CAAC,YAAY,QAAQ,YAAY,GAAG,SAAS,KAAK,GAAG;AAAA,IACjE;AAAA,EACF;AAEA,MAAI,OAAO,QAAQ,eAAe,aAAa;AAC7C,aAAS,OAAO;AAAA,MAAO,CAAC,SACtB,YAAY,QAAQ,UAAU,GAAG,SAAS,KAAK,YAAY,EAAE;AAAA,IAC/D;AAAA,EACF;AAEA,MAAI,OAAO,QAAQ,WAAW,aAAa;AACzC,aAAS,OAAO,OAAO,QAAQ,MAAM;AAAA,EACvC;AAEA,QAAM,aAAa,QAAQ;AAC3B,MAAI,YAAY;AACd,UAAM,kBAAkB,MAAM,aAAa,UAAU;AAErD,QAAI,iBAAiB;AAInB,eAAS,OAAO,OAAO,CAAC,SAAS;AAC/B,YAAI,CAAC,KAAK,SAAU,QAAO;AAE3B,eAAO,gBAAgB,KAAK,CAAC,YAAY,KAAK,aAAa,OAAO;AAAA,MACpE,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO,OAAO,OAAO,CAAC,SAAS,CAAC,KAAK,UAAU;AACjD;","names":[]}
@@ -0,0 +1,240 @@
1
+ import { getAiAPI, getOAuthAPI } from "@intlayer/api";
2
+ import {
3
+ formatLocale,
4
+ formatPath,
5
+ mergeDictionaries,
6
+ prepareIntlayer,
7
+ processPerLocaleDictionary,
8
+ reduceDictionaryContent,
9
+ writeContentDeclaration
10
+ } from "@intlayer/chokidar";
11
+ import {
12
+ colorizeKey,
13
+ colorizePath,
14
+ getAppLogger,
15
+ getConfiguration
16
+ } from "@intlayer/config";
17
+ import {
18
+ getFilterTranslationsOnlyContent,
19
+ getLocalisedContent,
20
+ getMissingLocalesContent
21
+ } from "@intlayer/core";
22
+ import dictionariesRecord from "@intlayer/dictionaries-entry";
23
+ import pLimit from "p-limit";
24
+ import { relative } from "path";
25
+ import { checkAIAccess } from "../utils/checkAIAccess.mjs";
26
+ import { autoFill } from "./autoFill.mjs";
27
+ import { ensureArray, getTargetDictionary } from "./getTargetDictionary.mjs";
28
+ const NB_CONCURRENT_TRANSLATIONS = 8;
29
+ const fill = async (options) => {
30
+ const configuration = getConfiguration(options.configOptions);
31
+ const appLogger = getAppLogger(configuration, {
32
+ config: {
33
+ prefix: ""
34
+ }
35
+ });
36
+ if (options.build) {
37
+ await prepareIntlayer(configuration);
38
+ }
39
+ const { defaultLocale, locales } = configuration.internationalization;
40
+ const mode = options.mode ?? "complete";
41
+ const baseLocale = options.sourceLocale ?? defaultLocale;
42
+ const outputLocales = (options.outputLocales ? ensureArray(options.outputLocales) : locales).filter((locale) => locale !== baseLocale);
43
+ checkAIAccess(configuration, options.aiOptions);
44
+ let oAuth2AccessToken;
45
+ if (configuration.editor.clientId) {
46
+ const intlayerAuthAPI = getOAuthAPI(configuration);
47
+ const oAuth2TokenResult = await intlayerAuthAPI.getOAuth2AccessToken();
48
+ oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;
49
+ }
50
+ appLogger("Starting fill function", {
51
+ level: "info"
52
+ });
53
+ const targetUnmergedDictionaries = await getTargetDictionary(options);
54
+ const affectedDictionaryKeys = /* @__PURE__ */ new Set();
55
+ targetUnmergedDictionaries.forEach((dict) => {
56
+ affectedDictionaryKeys.add(dict.key);
57
+ });
58
+ appLogger(
59
+ [
60
+ "Affected dictionary keys for processing:",
61
+ Array.from(affectedDictionaryKeys).map((key) => colorizeKey(key)).join(", ")
62
+ ],
63
+ {
64
+ isVerbose: true
65
+ }
66
+ );
67
+ for (const targetUnmergedDictionary of targetUnmergedDictionaries) {
68
+ const dictionaryKey = targetUnmergedDictionary.key;
69
+ const mainDictionaryToProcess = dictionariesRecord[dictionaryKey];
70
+ const sourceLocale = targetUnmergedDictionary.locale ?? baseLocale;
71
+ if (!mainDictionaryToProcess) {
72
+ appLogger(
73
+ `Dictionary with key '${colorizeKey(dictionaryKey)}' not found in dictionariesRecord. Skipping.`,
74
+ {
75
+ level: "warn"
76
+ }
77
+ );
78
+ continue;
79
+ }
80
+ if (!targetUnmergedDictionary.filePath) {
81
+ appLogger(
82
+ `Dictionary with key '${colorizeKey(dictionaryKey)}' has no file path. Skipping.`,
83
+ {
84
+ level: "warn"
85
+ }
86
+ );
87
+ continue;
88
+ }
89
+ const relativePath = relative(
90
+ configuration.content.baseDir,
91
+ targetUnmergedDictionary.filePath
92
+ );
93
+ appLogger(`Processing content declaration: ${colorizePath(relativePath)}`, {
94
+ level: "info"
95
+ });
96
+ const sourceLocaleContent = getFilterTranslationsOnlyContent(
97
+ mainDictionaryToProcess,
98
+ sourceLocale,
99
+ { dictionaryKey, keyPath: [] }
100
+ );
101
+ if (Object.keys(sourceLocaleContent).length === 0) {
102
+ appLogger(
103
+ `No content found for dictionary '${colorizeKey(dictionaryKey)}' in source locale ${formatLocale(sourceLocale)}. Skipping translation for this dictionary.`,
104
+ {
105
+ level: "warn"
106
+ }
107
+ );
108
+ continue;
109
+ }
110
+ const result = [];
111
+ const limit = pLimit(
112
+ options.nbConcurrentTranslations ?? NB_CONCURRENT_TRANSLATIONS
113
+ );
114
+ let outputLocalesList = outputLocales;
115
+ if (mode === "complete") {
116
+ const missingLocales = getMissingLocalesContent(
117
+ mainDictionaryToProcess,
118
+ outputLocales,
119
+ {
120
+ dictionaryKey: mainDictionaryToProcess.key,
121
+ keyPath: [],
122
+ plugins: []
123
+ }
124
+ );
125
+ outputLocalesList = missingLocales;
126
+ }
127
+ const translationPromises = outputLocalesList.map(
128
+ (targetLocale) => limit(async () => {
129
+ appLogger(
130
+ `Preparing translation for '${colorizeKey(dictionaryKey)}' dictionary from ${formatLocale(sourceLocale)} to ${formatLocale(targetLocale)}`,
131
+ {
132
+ level: "info"
133
+ }
134
+ );
135
+ const presetOutputContent = getLocalisedContent(
136
+ mainDictionaryToProcess,
137
+ targetLocale,
138
+ { dictionaryKey, keyPath: [] }
139
+ );
140
+ try {
141
+ const translationResult = await getAiAPI(
142
+ void 0,
143
+ configuration
144
+ ).translateJSON(
145
+ {
146
+ entryFileContent: sourceLocaleContent.content,
147
+ // Should be JSON, ensure getLocalisedContent provides this.
148
+ presetOutputContent: presetOutputContent.content,
149
+ // Should be JSON
150
+ dictionaryDescription: mainDictionaryToProcess.description,
151
+ entryLocale: sourceLocale,
152
+ outputLocale: targetLocale,
153
+ mode,
154
+ aiOptions: options.aiOptions
155
+ },
156
+ {
157
+ ...oAuth2AccessToken && {
158
+ headers: {
159
+ Authorization: `Bearer ${oAuth2AccessToken}`
160
+ }
161
+ }
162
+ }
163
+ );
164
+ if (!translationResult.data?.fileContent) {
165
+ appLogger(
166
+ `No content result found for '${colorizeKey(dictionaryKey)}' to ${formatLocale(targetLocale)}`,
167
+ {
168
+ level: "error"
169
+ }
170
+ );
171
+ return null;
172
+ }
173
+ const processedPerLocaleDictionary = processPerLocaleDictionary({
174
+ ...mainDictionaryToProcess,
175
+ content: translationResult.data?.fileContent,
176
+ locale: targetLocale
177
+ });
178
+ return processedPerLocaleDictionary;
179
+ } catch (error) {
180
+ appLogger(
181
+ `Error filling '${colorizeKey(dictionaryKey)}' to ${formatLocale(targetLocale)}:` + error,
182
+ {
183
+ level: "error"
184
+ }
185
+ );
186
+ return null;
187
+ }
188
+ })
189
+ );
190
+ const translationResults = await Promise.all(translationPromises);
191
+ translationResults.forEach((translationResult) => {
192
+ if (translationResult) {
193
+ result.push(translationResult);
194
+ }
195
+ });
196
+ const dictionaryToMerge = mode === "review" ? [...result, mainDictionaryToProcess] : [mainDictionaryToProcess, ...result];
197
+ const mergedResults = mergeDictionaries(dictionaryToMerge);
198
+ let formattedDict = targetUnmergedDictionary;
199
+ if (formattedDict.locale) {
200
+ const presetOutputContent = getLocalisedContent(
201
+ mainDictionaryToProcess,
202
+ formattedDict.locale,
203
+ { dictionaryKey, keyPath: [] }
204
+ );
205
+ formattedDict = {
206
+ ...formattedDict,
207
+ content: presetOutputContent.content
208
+ };
209
+ }
210
+ const reducedResult = reduceDictionaryContent(mergedResults, formattedDict);
211
+ if (formattedDict.autoFill || configuration.content.autoFill) {
212
+ await autoFill(
213
+ mergedResults,
214
+ targetUnmergedDictionary,
215
+ formattedDict.autoFill ?? configuration.content.autoFill,
216
+ outputLocalesList,
217
+ [sourceLocale],
218
+ configuration
219
+ );
220
+ } else {
221
+ await writeContentDeclaration(
222
+ { ...formattedDict, content: reducedResult.content },
223
+ configuration,
224
+ formattedDict.filePath
225
+ );
226
+ if (formattedDict.filePath) {
227
+ appLogger(
228
+ `Content declaration for '${colorizeKey(dictionaryKey)}' written to ${formatPath(formattedDict.filePath)}`,
229
+ {
230
+ level: "info"
231
+ }
232
+ );
233
+ }
234
+ }
235
+ }
236
+ };
237
+ export {
238
+ fill
239
+ };
240
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/fill/index.ts"],"sourcesContent":["import { AIOptions, getAiAPI, getOAuthAPI } from '@intlayer/api'; // Importing only getAiAPI for now\nimport {\n formatLocale,\n formatPath,\n ListGitFilesOptions,\n mergeDictionaries,\n prepareIntlayer,\n processPerLocaleDictionary,\n reduceDictionaryContent,\n writeContentDeclaration,\n} from '@intlayer/chokidar';\nimport {\n colorizeKey,\n colorizePath,\n getAppLogger,\n getConfiguration,\n GetConfigurationOptions,\n Locales,\n} from '@intlayer/config';\nimport {\n type ContentNode,\n type Dictionary,\n getFilterTranslationsOnlyContent,\n getLocalisedContent,\n getMissingLocalesContent,\n} from '@intlayer/core';\nimport dictionariesRecord from '@intlayer/dictionaries-entry';\nimport pLimit from 'p-limit';\nimport { relative } from 'path';\nimport { checkAIAccess } from '../utils/checkAIAccess';\nimport { autoFill } from './autoFill';\nimport { ensureArray, getTargetDictionary } from './getTargetDictionary';\n\nconst NB_CONCURRENT_TRANSLATIONS = 8;\n\n// Arguments for the fill function\nexport type FillOptions = {\n sourceLocale?: Locales;\n outputLocales?: Locales | Locales[];\n file?: string | string[];\n mode?: 'complete' | 'review';\n keys?: string | string[];\n excludedKeys?: string | string[];\n filter?: (entry: Dictionary) => boolean; // DictionaryEntry needs to be defined\n pathFilter?: string | string[];\n gitOptions?: ListGitFilesOptions;\n configOptions?: GetConfigurationOptions;\n aiOptions?: AIOptions; // Added aiOptions to be passed to translateJSON\n verbose?: boolean;\n nbConcurrentTranslations?: number;\n build?: boolean;\n};\n\n/**\n * Fill translations based on the provided options.\n */\nexport const fill = async (options: FillOptions): Promise<void> => {\n const configuration = getConfiguration(options.configOptions);\n const appLogger = getAppLogger(configuration, {\n config: {\n prefix: '',\n },\n });\n\n if (options.build) {\n await prepareIntlayer(configuration);\n }\n\n const { defaultLocale, locales } = configuration.internationalization;\n const mode = options.mode ?? 'complete';\n const baseLocale = options.sourceLocale ?? defaultLocale;\n const outputLocales = (\n options.outputLocales ? ensureArray(options.outputLocales) : locales\n ).filter((locale) => locale !== baseLocale);\n\n checkAIAccess(configuration, options.aiOptions);\n\n let oAuth2AccessToken: string | undefined;\n if (configuration.editor.clientId) {\n const intlayerAuthAPI = getOAuthAPI(configuration);\n const oAuth2TokenResult = await intlayerAuthAPI.getOAuth2AccessToken();\n\n oAuth2AccessToken = oAuth2TokenResult.data?.accessToken;\n }\n\n appLogger('Starting fill function', {\n level: 'info',\n });\n\n const targetUnmergedDictionaries = await getTargetDictionary(options);\n\n const affectedDictionaryKeys = new Set<string>();\n targetUnmergedDictionaries.forEach((dict) => {\n affectedDictionaryKeys.add(dict.key);\n });\n\n appLogger(\n [\n 'Affected dictionary keys for processing:',\n Array.from(affectedDictionaryKeys)\n .map((key) => colorizeKey(key))\n .join(', '),\n ],\n {\n isVerbose: true,\n }\n );\n\n for (const targetUnmergedDictionary of targetUnmergedDictionaries) {\n const dictionaryKey = targetUnmergedDictionary.key;\n const mainDictionaryToProcess = dictionariesRecord[dictionaryKey];\n const sourceLocale: Locales =\n (targetUnmergedDictionary.locale as Locales) ?? baseLocale;\n\n if (!mainDictionaryToProcess) {\n appLogger(\n `Dictionary with key '${colorizeKey(dictionaryKey)}' not found in dictionariesRecord. Skipping.`,\n {\n level: 'warn',\n }\n );\n continue;\n }\n\n if (!targetUnmergedDictionary.filePath) {\n appLogger(\n `Dictionary with key '${colorizeKey(dictionaryKey)}' has no file path. Skipping.`,\n {\n level: 'warn',\n }\n );\n continue;\n }\n\n const relativePath = relative(\n configuration.content.baseDir,\n targetUnmergedDictionary.filePath\n );\n\n appLogger(`Processing content declaration: ${colorizePath(relativePath)}`, {\n level: 'info',\n });\n\n const sourceLocaleContent = getFilterTranslationsOnlyContent(\n mainDictionaryToProcess as unknown as ContentNode,\n sourceLocale,\n { dictionaryKey, keyPath: [] }\n );\n\n if (Object.keys(sourceLocaleContent).length === 0) {\n appLogger(\n `No content found for dictionary '${colorizeKey(dictionaryKey)}' in source locale ${formatLocale(sourceLocale)}. Skipping translation for this dictionary.`,\n {\n level: 'warn',\n }\n );\n continue;\n }\n\n const result: Dictionary[] = [];\n\n // 5. for each locale to translate (exclude base locale) generate json translations\n // Limit concurrent translations to 5 at a time\n const limit = pLimit(\n options.nbConcurrentTranslations ?? NB_CONCURRENT_TRANSLATIONS\n );\n\n // Determine output locales\n let outputLocalesList: Locales[] = outputLocales;\n\n // If mode is review, translate all locales\n // If mode is complete, translate only the locales that are not the source locale\n if (mode === 'complete') {\n const missingLocales = getMissingLocalesContent(\n mainDictionaryToProcess as unknown as ContentNode,\n outputLocales,\n {\n dictionaryKey: mainDictionaryToProcess.key,\n keyPath: [],\n plugins: [],\n }\n );\n\n outputLocalesList = missingLocales;\n }\n\n const translationPromises = outputLocalesList.map((targetLocale) =>\n limit(async () => {\n appLogger(\n `Preparing translation for '${colorizeKey(dictionaryKey)}' dictionary from ${formatLocale(sourceLocale)} to ${formatLocale(targetLocale)}`,\n {\n level: 'info',\n }\n );\n\n const presetOutputContent = getLocalisedContent(\n mainDictionaryToProcess as unknown as ContentNode,\n targetLocale,\n { dictionaryKey, keyPath: [] }\n );\n\n try {\n const translationResult = await getAiAPI(\n undefined,\n configuration\n ).translateJSON(\n {\n entryFileContent: sourceLocaleContent.content, // Should be JSON, ensure getLocalisedContent provides this.\n presetOutputContent: presetOutputContent.content, // Should be JSON\n dictionaryDescription: mainDictionaryToProcess.description,\n entryLocale: sourceLocale,\n outputLocale: targetLocale,\n mode,\n aiOptions: options.aiOptions,\n },\n {\n ...(oAuth2AccessToken && {\n headers: {\n Authorization: `Bearer ${oAuth2AccessToken}`,\n },\n }),\n }\n );\n\n if (!translationResult.data?.fileContent) {\n appLogger(\n `No content result found for '${colorizeKey(dictionaryKey)}' to ${formatLocale(targetLocale)}`,\n {\n level: 'error',\n }\n );\n return null;\n }\n\n const processedPerLocaleDictionary = processPerLocaleDictionary({\n ...mainDictionaryToProcess,\n content: translationResult.data?.fileContent,\n locale: targetLocale,\n });\n\n return processedPerLocaleDictionary;\n } catch (error) {\n appLogger(\n `Error filling '${colorizeKey(dictionaryKey)}' to ${formatLocale(targetLocale)}:` +\n error,\n {\n level: 'error',\n }\n );\n return null;\n }\n })\n );\n\n // Wait for all translations to complete\n const translationResults = await Promise.all(translationPromises);\n\n // Filter out null results and add to result array\n translationResults.forEach((translationResult) => {\n if (translationResult) {\n result.push(translationResult);\n }\n });\n\n const dictionaryToMerge =\n mode === 'review'\n ? [...result, mainDictionaryToProcess] // Mode review: generated content will override the base one\n : [mainDictionaryToProcess, ...result]; // Mode complete: base content will override the generated one\n\n const mergedResults = mergeDictionaries(dictionaryToMerge);\n\n let formattedDict = targetUnmergedDictionary;\n\n if (formattedDict.locale) {\n const presetOutputContent = getLocalisedContent(\n mainDictionaryToProcess as unknown as ContentNode,\n formattedDict.locale,\n { dictionaryKey, keyPath: [] }\n );\n\n formattedDict = {\n ...formattedDict,\n content: presetOutputContent.content,\n };\n }\n\n const reducedResult = reduceDictionaryContent(mergedResults, formattedDict);\n\n if (formattedDict.autoFill || configuration.content.autoFill) {\n await autoFill(\n mergedResults,\n targetUnmergedDictionary,\n formattedDict.autoFill ?? configuration.content.autoFill,\n outputLocalesList,\n [sourceLocale],\n configuration\n );\n } else {\n await writeContentDeclaration(\n { ...formattedDict, content: reducedResult.content },\n configuration,\n formattedDict.filePath\n );\n\n if (formattedDict.filePath) {\n appLogger(\n `Content declaration for '${colorizeKey(dictionaryKey)}' written to ${formatPath(formattedDict.filePath)}`,\n {\n level: 'info',\n }\n );\n }\n }\n }\n};\n"],"mappings":"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","names":[]}
@@ -1,10 +1,11 @@
1
1
  export * from "./build.mjs";
2
2
  export * from "./cli.mjs";
3
- export * from "./fill.mjs";
3
+ export * from "./fill/index.mjs";
4
4
  export * from "./listContentDeclaration.mjs";
5
5
  export * from "./pull.mjs";
6
6
  export * from "./push.mjs";
7
7
  export * from "./pushConfig.mjs";
8
8
  export * from "./reviewDoc.mjs";
9
+ export * from "./test/index.mjs";
9
10
  export * from "./translateDoc.mjs";
10
11
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["export type * from '@intlayer/chokidar';\nexport * from './build';\nexport * from './cli';\nexport * from './fill';\nexport * from './listContentDeclaration';\nexport * from './pull';\nexport * from './push';\nexport * from './pushConfig';\nexport * from './reviewDoc';\nexport * from './translateDoc';\n"],"mappings":"AACA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
1
+ {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["export type * from '@intlayer/chokidar';\nexport * from './build';\nexport * from './cli';\nexport * from './fill';\nexport * from './listContentDeclaration';\nexport * from './pull';\nexport * from './push';\nexport * from './pushConfig';\nexport * from './reviewDoc';\nexport * from './test';\nexport * from './translateDoc';\n"],"mappings":"AACA,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
@@ -1,28 +1,49 @@
1
+ import { formatPath } from "@intlayer/chokidar";
1
2
  import {
3
+ colon,
4
+ colorizeKey,
5
+ colorizeNumber,
2
6
  getAppLogger,
3
7
  getConfiguration
4
8
  } from "@intlayer/config";
5
- import fg from "fast-glob";
6
- const getContentDeclaration = (options) => {
7
- const {
8
- content: { watchedFilesPatternWithPath }
9
- } = getConfiguration(options?.configOptions);
10
- const contentDeclarationFilesPath = fg.sync(
11
- watchedFilesPatternWithPath,
12
- {
13
- ignore: options?.exclude
14
- }
15
- );
16
- return contentDeclarationFilesPath;
9
+ import unmergedDictionariesRecord from "@intlayer/unmerged-dictionaries-entry";
10
+ import { relative } from "path";
11
+ const listContentDeclarationRows = (options) => {
12
+ const config = getConfiguration(options?.configOptions);
13
+ const rows = Object.values(unmergedDictionariesRecord).flat().map((dictionary) => ({
14
+ key: dictionary.key ?? "",
15
+ path: relative(config.content.baseDir, dictionary.filePath ?? "Remote")
16
+ }));
17
+ return rows;
17
18
  };
18
19
  const listContentDeclaration = (options) => {
19
- const contentDeclarationFilesPath = getContentDeclaration(options);
20
20
  const config = getConfiguration(options?.configOptions);
21
- const appLogger = getAppLogger(config);
22
- appLogger([contentDeclarationFilesPath]);
21
+ const appLogger = getAppLogger(config, {
22
+ config: {
23
+ prefix: ""
24
+ }
25
+ });
26
+ const rows = listContentDeclarationRows(options);
27
+ const lines = rows.map(
28
+ (r) => [
29
+ colon(` - ${colorizeKey(r.key)}`, {
30
+ colSize: rows.map((r2) => r2.key.length),
31
+ maxSize: 60
32
+ }),
33
+ " - ",
34
+ formatPath(r.path)
35
+ ].join("")
36
+ );
37
+ appLogger(`Content declaration files:`);
38
+ lines.forEach((l) => {
39
+ appLogger(l, {
40
+ level: "info"
41
+ });
42
+ });
43
+ appLogger(`Total content declaration files: ${colorizeNumber(rows.length)}`);
23
44
  };
24
45
  export {
25
- getContentDeclaration,
26
- listContentDeclaration
46
+ listContentDeclaration,
47
+ listContentDeclarationRows
27
48
  };
28
49
  //# sourceMappingURL=listContentDeclaration.mjs.map