@lingo.dev/_compiler 0.7.17 → 0.7.18
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.
- package/build/acorn-GCP5ZV2A.mjs +3152 -0
- package/build/acorn-U6XNAJW3.cjs +3152 -0
- package/build/angular-JQSQXFBY.mjs +2937 -0
- package/build/angular-VRWVFJ3P.cjs +2937 -0
- package/build/babel-R5G642DR.mjs +7246 -0
- package/build/babel-XUIPTQVD.cjs +7246 -0
- package/build/chunk-253QCR45.cjs +21 -0
- package/build/chunk-6BWS3CLP.mjs +16 -0
- package/build/chunk-77OA7KVH.cjs +22599 -0
- package/build/chunk-SRWLOKRJ.mjs +22598 -0
- package/build/estree-4GAWSYZ3.cjs +4388 -0
- package/build/estree-XLH46TSP.mjs +4388 -0
- package/build/flow-E755VYYN.mjs +27251 -0
- package/build/flow-Q7PWYY7R.cjs +27251 -0
- package/build/glimmer-CMYCELEM.cjs +2823 -0
- package/build/glimmer-E47Q6F77.mjs +2823 -0
- package/build/graphql-22VX22UI.mjs +1257 -0
- package/build/graphql-ATU26IOQ.cjs +1257 -0
- package/build/html-L366VYHK.cjs +2792 -0
- package/build/html-ZAWF5C3B.mjs +2792 -0
- package/build/index.cjs +36 -29
- package/build/index.d.cts +1 -1
- package/build/index.mjs +16 -7
- package/build/lingo-turbopack-loader.cjs +4 -5
- package/build/lingo-turbopack-loader.d.cts +1 -1
- package/build/lingo-turbopack-loader.mjs +2 -1
- package/build/markdown-5YN6HSRL.mjs +3536 -0
- package/build/markdown-VRQCW4QH.cjs +3536 -0
- package/build/meriyah-FBYDJ6EA.mjs +2631 -0
- package/build/meriyah-QKHCCSUI.cjs +2631 -0
- package/build/postcss-NNGTIRRJ.mjs +5083 -0
- package/build/postcss-PVIIR2IT.cjs +5083 -0
- package/build/typescript-FJLY3MEC.mjs +13205 -0
- package/build/typescript-VKODJRCW.cjs +13205 -0
- package/build/yaml-6I36QTON.cjs +4222 -0
- package/build/yaml-MMD4LQP5.mjs +4222 -0
- package/package.json +12 -5
- package/build/chunk-COKHINWO.mjs +0 -2743
- package/build/chunk-TMPC4O5V.cjs +0 -2743
package/build/chunk-TMPC4O5V.cjs
DELETED
|
@@ -1,2743 +0,0 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class;var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
-
}) : x)(function(x) {
|
|
4
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
-
});
|
|
7
|
-
|
|
8
|
-
// src/_base.ts
|
|
9
|
-
var _generator = require('@babel/generator'); var _generator2 = _interopRequireDefault(_generator);
|
|
10
|
-
var _parser = require('@babel/parser'); var parser = _interopRequireWildcard(_parser);
|
|
11
|
-
function createCodeMutation(spec) {
|
|
12
|
-
return (payload) => {
|
|
13
|
-
const result = spec(payload);
|
|
14
|
-
return result;
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
function createPayload(input) {
|
|
18
|
-
const ast = parser.parse(input.code, {
|
|
19
|
-
sourceType: "module",
|
|
20
|
-
plugins: ["jsx", "typescript"]
|
|
21
|
-
});
|
|
22
|
-
return {
|
|
23
|
-
...input,
|
|
24
|
-
ast
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
function createOutput(payload) {
|
|
28
|
-
const generationResult = _generator2.default.call(void 0, payload.ast, {}, payload.code);
|
|
29
|
-
return {
|
|
30
|
-
code: generationResult.code,
|
|
31
|
-
map: generationResult.map
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
function composeMutations(...mutations) {
|
|
35
|
-
return (input) => {
|
|
36
|
-
let result = input;
|
|
37
|
-
for (const mutate of mutations) {
|
|
38
|
-
const intermediateResult = mutate(result);
|
|
39
|
-
if (!intermediateResult) {
|
|
40
|
-
break;
|
|
41
|
-
} else {
|
|
42
|
-
result = intermediateResult;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return result;
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
var defaultParams = {
|
|
49
|
-
sourceRoot: "src",
|
|
50
|
-
lingoDir: "lingo",
|
|
51
|
-
sourceLocale: "en",
|
|
52
|
-
targetLocales: ["es"],
|
|
53
|
-
rsc: false,
|
|
54
|
-
useDirective: false,
|
|
55
|
-
debug: false,
|
|
56
|
-
models: {},
|
|
57
|
-
prompt: null
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
// src/_const.ts
|
|
61
|
-
var ModuleId = {
|
|
62
|
-
ReactClient: ["lingo.dev/react/client", "lingo.dev/react-client"],
|
|
63
|
-
ReactRSC: ["lingo.dev/react/rsc", "lingo.dev/react-rsc"],
|
|
64
|
-
ReactRouter: ["lingo.dev/react/react-router", "lingo.dev/react-router"]
|
|
65
|
-
};
|
|
66
|
-
var LCP_DICTIONARY_FILE_NAME = "dictionary.js";
|
|
67
|
-
|
|
68
|
-
// src/lib/lcp/cache.ts
|
|
69
|
-
var _fs = require('fs'); var fs = _interopRequireWildcard(_fs); var fs4 = _interopRequireWildcard(_fs);
|
|
70
|
-
var _path = require('path'); var path = _interopRequireWildcard(_path); var path5 = _interopRequireWildcard(_path);
|
|
71
|
-
var _prettier = require('prettier'); var prettier = _interopRequireWildcard(_prettier);
|
|
72
|
-
var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash);
|
|
73
|
-
var LCPCache = class {
|
|
74
|
-
// make sure the cache file exists, otherwise imports will fail
|
|
75
|
-
static ensureDictionaryFile(params) {
|
|
76
|
-
const cachePath = this._getCachePath(params);
|
|
77
|
-
if (!fs.existsSync(cachePath)) {
|
|
78
|
-
const dir = path.dirname(cachePath);
|
|
79
|
-
if (!fs.existsSync(dir)) {
|
|
80
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
81
|
-
}
|
|
82
|
-
fs.writeFileSync(cachePath, "export default {};");
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
// read cache entries for given locale, validate entry hash from LCP schema
|
|
86
|
-
static readLocaleDictionary(locale, params) {
|
|
87
|
-
const cache = this._read(params);
|
|
88
|
-
const dictionary = this._extractLocaleDictionary(cache, locale, params.lcp);
|
|
89
|
-
return dictionary;
|
|
90
|
-
}
|
|
91
|
-
// write cache entries for given locale to existing cache file, use hash from LCP schema
|
|
92
|
-
static async writeLocaleDictionary(dictionary, params) {
|
|
93
|
-
const currentCache = this._read(params);
|
|
94
|
-
const newCache = this._mergeLocaleDictionary(
|
|
95
|
-
currentCache,
|
|
96
|
-
dictionary,
|
|
97
|
-
params.lcp
|
|
98
|
-
);
|
|
99
|
-
await this._write(newCache, params);
|
|
100
|
-
}
|
|
101
|
-
// merge dictionary with current cache, sort files, entries and locales to minimize diffs
|
|
102
|
-
static _mergeLocaleDictionary(currentCache, dictionary, lcp) {
|
|
103
|
-
const files = _lodash2.default.call(void 0, dictionary.files).mapValues((file, fileName) => ({
|
|
104
|
-
...file,
|
|
105
|
-
entries: _lodash2.default.call(void 0, file.entries).mapValues((entry, entryName) => {
|
|
106
|
-
const cachedEntry = _nullishCoalesce(_lodash2.default.get(currentCache, ["files", fileName, "entries", entryName]), () => ( {}));
|
|
107
|
-
const hash = _lodash2.default.get(lcp, [
|
|
108
|
-
"files",
|
|
109
|
-
fileName,
|
|
110
|
-
"scopes",
|
|
111
|
-
entryName,
|
|
112
|
-
"hash"
|
|
113
|
-
]);
|
|
114
|
-
const cachedEntryContent = cachedEntry.hash === hash ? cachedEntry.content : {};
|
|
115
|
-
const content = _lodash2.default.call(void 0, {
|
|
116
|
-
...cachedEntryContent,
|
|
117
|
-
[dictionary.locale]: entry
|
|
118
|
-
}).toPairs().sortBy([0]).fromPairs().value();
|
|
119
|
-
return { content, hash };
|
|
120
|
-
}).toPairs().sortBy([0]).fromPairs().value()
|
|
121
|
-
})).toPairs().sortBy([0]).fromPairs().value();
|
|
122
|
-
const newCache = {
|
|
123
|
-
version: dictionary.version,
|
|
124
|
-
files
|
|
125
|
-
};
|
|
126
|
-
return newCache;
|
|
127
|
-
}
|
|
128
|
-
// extract dictionary from cache for given locale, validate entry hash from LCP schema
|
|
129
|
-
static _extractLocaleDictionary(cache, locale, lcp) {
|
|
130
|
-
const findCachedEntry = (hash) => {
|
|
131
|
-
const cachedEntry = _lodash2.default.call(void 0, cache.files).flatMap((file) => _lodash2.default.values(file.entries)).find((entry) => entry.hash === hash);
|
|
132
|
-
if (cachedEntry) {
|
|
133
|
-
return cachedEntry.content[locale];
|
|
134
|
-
}
|
|
135
|
-
return void 0;
|
|
136
|
-
};
|
|
137
|
-
const files = _lodash2.default.call(void 0, lcp.files).mapValues((file) => {
|
|
138
|
-
return {
|
|
139
|
-
entries: _lodash2.default.call(void 0, file.scopes).mapValues((entry) => {
|
|
140
|
-
return findCachedEntry(entry.hash);
|
|
141
|
-
}).pickBy((value) => value !== void 0).value()
|
|
142
|
-
};
|
|
143
|
-
}).pickBy((file) => !_lodash2.default.isEmpty(file.entries)).value();
|
|
144
|
-
const dictionary = {
|
|
145
|
-
version: cache.version,
|
|
146
|
-
locale,
|
|
147
|
-
files
|
|
148
|
-
};
|
|
149
|
-
return dictionary;
|
|
150
|
-
}
|
|
151
|
-
// format with prettier
|
|
152
|
-
static async _format(cachedContent, cachePath) {
|
|
153
|
-
try {
|
|
154
|
-
const config2 = await prettier.resolveConfig(cachePath);
|
|
155
|
-
const prettierOptions = {
|
|
156
|
-
..._nullishCoalesce(config2, () => ( {})),
|
|
157
|
-
parser: _optionalChain([config2, 'optionalAccess', _12 => _12.parser]) ? config2.parser : "typescript"
|
|
158
|
-
};
|
|
159
|
-
return await prettier.format(cachedContent, prettierOptions);
|
|
160
|
-
} catch (error) {
|
|
161
|
-
}
|
|
162
|
-
return cachedContent;
|
|
163
|
-
}
|
|
164
|
-
// write cache to file as JSON
|
|
165
|
-
static async _write(dictionaryCache, params) {
|
|
166
|
-
const cachePath = this._getCachePath(params);
|
|
167
|
-
const cache = `export default ${JSON.stringify(dictionaryCache, null, 2)};`;
|
|
168
|
-
const formattedCache = await this._format(cache, cachePath);
|
|
169
|
-
fs.writeFileSync(cachePath, formattedCache);
|
|
170
|
-
}
|
|
171
|
-
// read cache from file as JSON
|
|
172
|
-
static _read(params) {
|
|
173
|
-
const cachePath = this._getCachePath(params);
|
|
174
|
-
if (!fs.existsSync(cachePath)) {
|
|
175
|
-
return {
|
|
176
|
-
version: 0.1,
|
|
177
|
-
files: {}
|
|
178
|
-
};
|
|
179
|
-
}
|
|
180
|
-
const jsObjectString = fs.readFileSync(cachePath, "utf8");
|
|
181
|
-
const cache = jsObjectString.replace(/^export default/, "").replace(/;\s*$/, "");
|
|
182
|
-
const obj = new Function(`return (${cache})`)();
|
|
183
|
-
return obj;
|
|
184
|
-
}
|
|
185
|
-
// get cache file path
|
|
186
|
-
static _getCachePath(params) {
|
|
187
|
-
return path.resolve(
|
|
188
|
-
process.cwd(),
|
|
189
|
-
params.sourceRoot,
|
|
190
|
-
params.lingoDir,
|
|
191
|
-
LCP_DICTIONARY_FILE_NAME
|
|
192
|
-
);
|
|
193
|
-
}
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
// src/utils/locales.ts
|
|
197
|
-
function getInvalidLocales(localeModels, sourceLocale, targetLocales) {
|
|
198
|
-
return targetLocales.filter((targetLocale) => {
|
|
199
|
-
const { provider, model } = getLocaleModel(
|
|
200
|
-
localeModels,
|
|
201
|
-
sourceLocale,
|
|
202
|
-
targetLocale
|
|
203
|
-
);
|
|
204
|
-
return provider === void 0 || model === void 0;
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
function getLocaleModel(localeModels, sourceLocale, targetLocale) {
|
|
208
|
-
const localeKeys = [
|
|
209
|
-
`${sourceLocale}:${targetLocale}`,
|
|
210
|
-
`*:${targetLocale}`,
|
|
211
|
-
`${sourceLocale}:*`,
|
|
212
|
-
"*:*"
|
|
213
|
-
];
|
|
214
|
-
const modelKey = localeKeys.find((key) => localeModels.hasOwnProperty(key));
|
|
215
|
-
if (modelKey) {
|
|
216
|
-
const value = localeModels[modelKey];
|
|
217
|
-
const firstColonIndex = _optionalChain([value, 'optionalAccess', _13 => _13.indexOf, 'call', _14 => _14(":")]);
|
|
218
|
-
if (value && firstColonIndex !== -1 && firstColonIndex !== void 0) {
|
|
219
|
-
const provider2 = value.substring(0, firstColonIndex);
|
|
220
|
-
const model2 = value.substring(firstColonIndex + 1);
|
|
221
|
-
if (provider2 && model2) {
|
|
222
|
-
return { provider: provider2, model: model2 };
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
const [provider, model] = _optionalChain([value, 'optionalAccess', _15 => _15.split, 'call', _16 => _16(":")]) || [];
|
|
226
|
-
if (provider && model) {
|
|
227
|
-
return { provider, model };
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
return { provider: void 0, model: void 0 };
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
// src/utils/rc.ts
|
|
234
|
-
var _os = require('os'); var _os2 = _interopRequireDefault(_os);
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
var _ini = require('ini'); var _ini2 = _interopRequireDefault(_ini);
|
|
238
|
-
function getRc() {
|
|
239
|
-
const settingsFile = ".lingodotdevrc";
|
|
240
|
-
const homedir = _os2.default.homedir();
|
|
241
|
-
const settingsFilePath = path.default.join(homedir, settingsFile);
|
|
242
|
-
const content = fs.default.existsSync(settingsFilePath) ? fs.default.readFileSync(settingsFilePath, "utf-8") : "";
|
|
243
|
-
const data = _ini2.default.parse(content);
|
|
244
|
-
return data;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// src/utils/llm-api-key.ts
|
|
248
|
-
|
|
249
|
-
var _dotenv = require('dotenv'); var dotenv = _interopRequireWildcard(_dotenv);
|
|
250
|
-
|
|
251
|
-
function getKeyFromEnv(envVarName) {
|
|
252
|
-
if (process.env[envVarName]) {
|
|
253
|
-
return process.env[envVarName];
|
|
254
|
-
}
|
|
255
|
-
const result = dotenv.config({
|
|
256
|
-
path: [
|
|
257
|
-
path.default.resolve(process.cwd(), ".env"),
|
|
258
|
-
path.default.resolve(process.cwd(), ".env.local"),
|
|
259
|
-
path.default.resolve(process.cwd(), ".env.development")
|
|
260
|
-
]
|
|
261
|
-
});
|
|
262
|
-
return _optionalChain([result, 'optionalAccess', _17 => _17.parsed, 'optionalAccess', _18 => _18[envVarName]]);
|
|
263
|
-
}
|
|
264
|
-
function getKeyFromRc(rcPath) {
|
|
265
|
-
const rc = getRc();
|
|
266
|
-
const result = _lodash2.default.get(rc, rcPath);
|
|
267
|
-
return typeof result === "string" ? result : void 0;
|
|
268
|
-
}
|
|
269
|
-
function getGroqKey() {
|
|
270
|
-
return getGroqKeyFromEnv() || getGroqKeyFromRc();
|
|
271
|
-
}
|
|
272
|
-
function getGroqKeyFromRc() {
|
|
273
|
-
return getKeyFromRc("llm.groqApiKey");
|
|
274
|
-
}
|
|
275
|
-
function getGroqKeyFromEnv() {
|
|
276
|
-
return getKeyFromEnv("GROQ_API_KEY");
|
|
277
|
-
}
|
|
278
|
-
function getLingoDotDevKeyFromEnv() {
|
|
279
|
-
return getKeyFromEnv("LINGODOTDEV_API_KEY");
|
|
280
|
-
}
|
|
281
|
-
function getLingoDotDevKeyFromRc() {
|
|
282
|
-
return getKeyFromRc("auth.apiKey");
|
|
283
|
-
}
|
|
284
|
-
function getLingoDotDevKey() {
|
|
285
|
-
return getLingoDotDevKeyFromEnv() || getLingoDotDevKeyFromRc();
|
|
286
|
-
}
|
|
287
|
-
function getGoogleKey() {
|
|
288
|
-
return getGoogleKeyFromEnv() || getGoogleKeyFromRc();
|
|
289
|
-
}
|
|
290
|
-
function getGoogleKeyFromRc() {
|
|
291
|
-
return getKeyFromRc("llm.googleApiKey");
|
|
292
|
-
}
|
|
293
|
-
function getGoogleKeyFromEnv() {
|
|
294
|
-
return getKeyFromEnv("GOOGLE_API_KEY");
|
|
295
|
-
}
|
|
296
|
-
function getOpenRouterKey() {
|
|
297
|
-
return getOpenRouterKeyFromEnv() || getOpenRouterKeyFromRc();
|
|
298
|
-
}
|
|
299
|
-
function getOpenRouterKeyFromRc() {
|
|
300
|
-
return getKeyFromRc("llm.openrouterApiKey");
|
|
301
|
-
}
|
|
302
|
-
function getOpenRouterKeyFromEnv() {
|
|
303
|
-
return getKeyFromEnv("OPENROUTER_API_KEY");
|
|
304
|
-
}
|
|
305
|
-
function getMistralKey() {
|
|
306
|
-
return getMistralKeyFromEnv() || getMistralKeyFromRc();
|
|
307
|
-
}
|
|
308
|
-
function getMistralKeyFromRc() {
|
|
309
|
-
return getKeyFromRc("llm.mistralApiKey");
|
|
310
|
-
}
|
|
311
|
-
function getMistralKeyFromEnv() {
|
|
312
|
-
return getKeyFromEnv("MISTRAL_API_KEY");
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
// src/utils/env.ts
|
|
316
|
-
|
|
317
|
-
function isRunningInCIOrDocker() {
|
|
318
|
-
return Boolean(process.env.CI) || fs.default.existsSync("/.dockerenv");
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// src/lib/lcp/api/provider-details.ts
|
|
322
|
-
var providerDetails = {
|
|
323
|
-
groq: {
|
|
324
|
-
name: "Groq",
|
|
325
|
-
apiKeyEnvVar: "GROQ_API_KEY",
|
|
326
|
-
apiKeyConfigKey: "llm.groqApiKey",
|
|
327
|
-
getKeyLink: "https://groq.com",
|
|
328
|
-
docsLink: "https://console.groq.com/docs/errors"
|
|
329
|
-
},
|
|
330
|
-
google: {
|
|
331
|
-
name: "Google",
|
|
332
|
-
apiKeyEnvVar: "GOOGLE_API_KEY",
|
|
333
|
-
apiKeyConfigKey: "llm.googleApiKey",
|
|
334
|
-
getKeyLink: "https://ai.google.dev/",
|
|
335
|
-
docsLink: "https://ai.google.dev/gemini-api/docs/troubleshooting"
|
|
336
|
-
},
|
|
337
|
-
openrouter: {
|
|
338
|
-
name: "OpenRouter",
|
|
339
|
-
apiKeyEnvVar: "OPENROUTER_API_KEY",
|
|
340
|
-
apiKeyConfigKey: "llm.openrouterApiKey",
|
|
341
|
-
getKeyLink: "https://openrouter.ai",
|
|
342
|
-
docsLink: "https://openrouter.ai/docs"
|
|
343
|
-
},
|
|
344
|
-
ollama: {
|
|
345
|
-
name: "Ollama",
|
|
346
|
-
apiKeyEnvVar: void 0,
|
|
347
|
-
// Ollama doesn't require an API key
|
|
348
|
-
apiKeyConfigKey: void 0,
|
|
349
|
-
// Ollama doesn't require an API key
|
|
350
|
-
getKeyLink: "https://ollama.com/download",
|
|
351
|
-
docsLink: "https://github.com/ollama/ollama/tree/main/docs"
|
|
352
|
-
},
|
|
353
|
-
mistral: {
|
|
354
|
-
name: "Mistral",
|
|
355
|
-
apiKeyEnvVar: "MISTRAL_API_KEY",
|
|
356
|
-
apiKeyConfigKey: "llm.mistralApiKey",
|
|
357
|
-
getKeyLink: "https://console.mistral.ai",
|
|
358
|
-
docsLink: "https://docs.mistral.ai"
|
|
359
|
-
},
|
|
360
|
-
"lingo.dev": {
|
|
361
|
-
name: "Lingo.dev",
|
|
362
|
-
apiKeyEnvVar: "LINGODOTDEV_API_KEY",
|
|
363
|
-
apiKeyConfigKey: "auth.apiKey",
|
|
364
|
-
getKeyLink: "https://lingo.dev",
|
|
365
|
-
docsLink: "https://lingo.dev/docs"
|
|
366
|
-
}
|
|
367
|
-
};
|
|
368
|
-
|
|
369
|
-
// src/_loader-utils.ts
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
// src/utils/index.ts
|
|
374
|
-
var _traverse = require('@babel/traverse'); var _traverse2 = _interopRequireDefault(_traverse);
|
|
375
|
-
var _types = require('@babel/types'); var t2 = _interopRequireWildcard(_types); var t = _interopRequireWildcard(_types); var t3 = _interopRequireWildcard(_types); var t5 = _interopRequireWildcard(_types); var t4 = _interopRequireWildcard(_types); var t8 = _interopRequireWildcard(_types); var t6 = _interopRequireWildcard(_types); var t7 = _interopRequireWildcard(_types); var t10 = _interopRequireWildcard(_types); var t9 = _interopRequireWildcard(_types); var t11 = _interopRequireWildcard(_types); var t12 = _interopRequireWildcard(_types); var t13 = _interopRequireWildcard(_types); var t14 = _interopRequireWildcard(_types); var t15 = _interopRequireWildcard(_types); var t17 = _interopRequireWildcard(_types); var t16 = _interopRequireWildcard(_types); var t21 = _interopRequireWildcard(_types); var t18 = _interopRequireWildcard(_types); var t19 = _interopRequireWildcard(_types); var t20 = _interopRequireWildcard(_types); var t22 = _interopRequireWildcard(_types); var t23 = _interopRequireWildcard(_types); var t24 = _interopRequireWildcard(_types);
|
|
376
|
-
|
|
377
|
-
// src/utils/jsx-attribute.ts
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
function getJsxAttributesMap(nodePath) {
|
|
381
|
-
const attributes = nodePath.node.openingElement.attributes;
|
|
382
|
-
return _lodash2.default.reduce(
|
|
383
|
-
attributes,
|
|
384
|
-
(result, attr) => {
|
|
385
|
-
if (attr.type !== "JSXAttribute" || attr.name.type !== "JSXIdentifier") {
|
|
386
|
-
return result;
|
|
387
|
-
}
|
|
388
|
-
const name = attr.name.name;
|
|
389
|
-
const value = extractAttributeValue(attr);
|
|
390
|
-
return { ...result, [name]: value };
|
|
391
|
-
},
|
|
392
|
-
{}
|
|
393
|
-
);
|
|
394
|
-
}
|
|
395
|
-
function getJsxAttributeValue(nodePath, attributeName) {
|
|
396
|
-
const attributes = nodePath.node.openingElement.attributes;
|
|
397
|
-
const attribute = _lodash2.default.find(
|
|
398
|
-
attributes,
|
|
399
|
-
(attr) => attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && attr.name.name === attributeName
|
|
400
|
-
);
|
|
401
|
-
if (!attribute) {
|
|
402
|
-
return void 0;
|
|
403
|
-
}
|
|
404
|
-
return extractAttributeValue(attribute);
|
|
405
|
-
}
|
|
406
|
-
function setJsxAttributeValue(nodePath, attributeName, value) {
|
|
407
|
-
const attributes = nodePath.node.openingElement.attributes;
|
|
408
|
-
const attributeIndex = _lodash2.default.findIndex(
|
|
409
|
-
attributes,
|
|
410
|
-
(attr) => attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && attr.name.name === attributeName
|
|
411
|
-
);
|
|
412
|
-
const jsxValue = createAttributeValue(value);
|
|
413
|
-
const jsxAttribute7 = t.jsxAttribute(t.jsxIdentifier(attributeName), jsxValue);
|
|
414
|
-
if (attributeIndex >= 0) {
|
|
415
|
-
attributes[attributeIndex] = jsxAttribute7;
|
|
416
|
-
} else {
|
|
417
|
-
attributes.push(jsxAttribute7);
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
function extractAttributeValue(attribute) {
|
|
421
|
-
if (!attribute.value) {
|
|
422
|
-
return true;
|
|
423
|
-
}
|
|
424
|
-
if (attribute.value.type === "StringLiteral") {
|
|
425
|
-
return attribute.value.value;
|
|
426
|
-
}
|
|
427
|
-
if (attribute.value.type === "JSXExpressionContainer") {
|
|
428
|
-
const expression = attribute.value.expression;
|
|
429
|
-
if (expression.type === "BooleanLiteral") {
|
|
430
|
-
return expression.value;
|
|
431
|
-
}
|
|
432
|
-
if (expression.type === "NumericLiteral") {
|
|
433
|
-
return expression.value;
|
|
434
|
-
}
|
|
435
|
-
if (expression.type === "StringLiteral") {
|
|
436
|
-
return expression.value;
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
return null;
|
|
440
|
-
}
|
|
441
|
-
function createAttributeValue(value) {
|
|
442
|
-
if (value === null || value === void 0) {
|
|
443
|
-
return null;
|
|
444
|
-
}
|
|
445
|
-
if (typeof value === "string") {
|
|
446
|
-
return t.stringLiteral(value);
|
|
447
|
-
}
|
|
448
|
-
if (typeof value === "boolean") {
|
|
449
|
-
return t.jsxExpressionContainer(t.booleanLiteral(value));
|
|
450
|
-
}
|
|
451
|
-
if (typeof value === "number") {
|
|
452
|
-
return t.jsxExpressionContainer(t.numericLiteral(value));
|
|
453
|
-
}
|
|
454
|
-
if (t.isExpression(value)) {
|
|
455
|
-
return t.jsxExpressionContainer(value);
|
|
456
|
-
}
|
|
457
|
-
return t.jsxExpressionContainer(t.stringLiteral(JSON.stringify(value)));
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
// src/utils/index.ts
|
|
461
|
-
function getJsxRoots(node) {
|
|
462
|
-
const result = [];
|
|
463
|
-
_traverse2.default.call(void 0, node, {
|
|
464
|
-
JSXElement(path7) {
|
|
465
|
-
result.push(path7);
|
|
466
|
-
path7.skip();
|
|
467
|
-
}
|
|
468
|
-
});
|
|
469
|
-
return result;
|
|
470
|
-
}
|
|
471
|
-
function getOrCreateImport(ast, params) {
|
|
472
|
-
let importedName = params.exportedName;
|
|
473
|
-
let existingImport = findExistingImport(
|
|
474
|
-
ast,
|
|
475
|
-
params.exportedName,
|
|
476
|
-
params.moduleName
|
|
477
|
-
);
|
|
478
|
-
if (existingImport) {
|
|
479
|
-
return { importedName: existingImport };
|
|
480
|
-
}
|
|
481
|
-
importedName = generateUniqueImportName(ast, params.exportedName);
|
|
482
|
-
createImportDeclaration(
|
|
483
|
-
ast,
|
|
484
|
-
importedName,
|
|
485
|
-
params.exportedName,
|
|
486
|
-
params.moduleName
|
|
487
|
-
);
|
|
488
|
-
return { importedName };
|
|
489
|
-
}
|
|
490
|
-
function findExistingImport(ast, exportedName, moduleName) {
|
|
491
|
-
let result = null;
|
|
492
|
-
_traverse2.default.call(void 0, ast, {
|
|
493
|
-
ImportDeclaration(path7) {
|
|
494
|
-
if (!moduleName.includes(path7.node.source.value)) {
|
|
495
|
-
return;
|
|
496
|
-
}
|
|
497
|
-
if (path7.node.importKind === "type") {
|
|
498
|
-
return;
|
|
499
|
-
}
|
|
500
|
-
for (const specifier of path7.node.specifiers) {
|
|
501
|
-
if (t2.isImportSpecifier(specifier) && // Skip type-only specifiers as they can't be used at runtime
|
|
502
|
-
specifier.importKind !== "type" && (t2.isIdentifier(specifier.imported) && specifier.imported.name === exportedName || specifier.importKind === "value" && t2.isIdentifier(specifier.local) && specifier.local.name === exportedName)) {
|
|
503
|
-
result = specifier.local.name;
|
|
504
|
-
path7.stop();
|
|
505
|
-
return;
|
|
506
|
-
}
|
|
507
|
-
if (t2.isImportDefaultSpecifier(specifier)) {
|
|
508
|
-
result = `${specifier.local.name}.${exportedName}`;
|
|
509
|
-
path7.stop();
|
|
510
|
-
return;
|
|
511
|
-
}
|
|
512
|
-
if (t2.isImportNamespaceSpecifier(specifier)) {
|
|
513
|
-
result = `${specifier.local.name}.${exportedName}`;
|
|
514
|
-
path7.stop();
|
|
515
|
-
return;
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
});
|
|
520
|
-
return result;
|
|
521
|
-
}
|
|
522
|
-
function generateUniqueImportName(ast, baseName) {
|
|
523
|
-
const usedNames = /* @__PURE__ */ new Set();
|
|
524
|
-
_traverse2.default.call(void 0, ast, {
|
|
525
|
-
Identifier(path7) {
|
|
526
|
-
usedNames.add(path7.node.name);
|
|
527
|
-
}
|
|
528
|
-
});
|
|
529
|
-
if (!usedNames.has(baseName)) {
|
|
530
|
-
return baseName;
|
|
531
|
-
}
|
|
532
|
-
let counter = 1;
|
|
533
|
-
let candidateName = `${baseName}${counter}`;
|
|
534
|
-
while (usedNames.has(candidateName)) {
|
|
535
|
-
counter++;
|
|
536
|
-
candidateName = `${baseName}${counter}`;
|
|
537
|
-
}
|
|
538
|
-
return candidateName;
|
|
539
|
-
}
|
|
540
|
-
function createImportDeclaration(ast, localName, exportedName, moduleName) {
|
|
541
|
-
_traverse2.default.call(void 0, ast, {
|
|
542
|
-
Program(path7) {
|
|
543
|
-
const importSpecifier2 = t2.importSpecifier(
|
|
544
|
-
t2.identifier(localName),
|
|
545
|
-
t2.identifier(exportedName)
|
|
546
|
-
);
|
|
547
|
-
const existingImport = path7.get("body").find(
|
|
548
|
-
(nodePath) => t2.isImportDeclaration(nodePath.node) && moduleName.includes(nodePath.node.source.value) && nodePath.node.importKind !== "type"
|
|
549
|
-
);
|
|
550
|
-
if (existingImport && t2.isImportDeclaration(existingImport.node)) {
|
|
551
|
-
existingImport.node.specifiers.push(importSpecifier2);
|
|
552
|
-
} else {
|
|
553
|
-
const importDeclaration2 = t2.importDeclaration(
|
|
554
|
-
[importSpecifier2],
|
|
555
|
-
t2.stringLiteral(moduleName[0])
|
|
556
|
-
);
|
|
557
|
-
const lastImportIndex = findLastImportIndex(path7);
|
|
558
|
-
path7.node.body.splice(lastImportIndex + 1, 0, importDeclaration2);
|
|
559
|
-
}
|
|
560
|
-
path7.stop();
|
|
561
|
-
}
|
|
562
|
-
});
|
|
563
|
-
}
|
|
564
|
-
function findLastImportIndex(programPath) {
|
|
565
|
-
const body = programPath.node.body;
|
|
566
|
-
for (let i = body.length - 1; i >= 0; i--) {
|
|
567
|
-
if (t2.isImportDeclaration(body[i])) {
|
|
568
|
-
return i;
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
return -1;
|
|
572
|
-
}
|
|
573
|
-
function _hasFileDirective(ast, directiveValue) {
|
|
574
|
-
let hasDirective = false;
|
|
575
|
-
_traverse2.default.call(void 0, ast, {
|
|
576
|
-
Directive(path7) {
|
|
577
|
-
if (path7.node.value.value === directiveValue) {
|
|
578
|
-
hasDirective = true;
|
|
579
|
-
path7.stop();
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
});
|
|
583
|
-
return hasDirective;
|
|
584
|
-
}
|
|
585
|
-
function hasI18nDirective(ast) {
|
|
586
|
-
return _hasFileDirective(ast, "use i18n");
|
|
587
|
-
}
|
|
588
|
-
function hasClientDirective(ast) {
|
|
589
|
-
return _hasFileDirective(ast, "use client");
|
|
590
|
-
}
|
|
591
|
-
function getModuleExecutionMode(ast, rscEnabled) {
|
|
592
|
-
if (rscEnabled) {
|
|
593
|
-
if (hasClientDirective(ast)) {
|
|
594
|
-
return "client";
|
|
595
|
-
} else {
|
|
596
|
-
return "server";
|
|
597
|
-
}
|
|
598
|
-
} else {
|
|
599
|
-
return "client";
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
// src/utils/invokations.ts
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
function findInvokations(ast, params) {
|
|
607
|
-
const result = [];
|
|
608
|
-
_traverse2.default.call(void 0, ast, {
|
|
609
|
-
ImportDeclaration(path7) {
|
|
610
|
-
if (!params.moduleName.includes(path7.node.source.value)) return;
|
|
611
|
-
const importNames = /* @__PURE__ */ new Map();
|
|
612
|
-
const specifiers = path7.node.specifiers;
|
|
613
|
-
specifiers.forEach((specifier) => {
|
|
614
|
-
if (t3.isImportSpecifier(specifier) && t3.isIdentifier(specifier.imported) && specifier.imported.name === params.functionName) {
|
|
615
|
-
importNames.set(specifier.local.name, true);
|
|
616
|
-
} else if (t3.isImportDefaultSpecifier(specifier) && params.functionName === "default") {
|
|
617
|
-
importNames.set(specifier.local.name, true);
|
|
618
|
-
} else if (t3.isImportNamespaceSpecifier(specifier)) {
|
|
619
|
-
importNames.set(specifier.local.name, "namespace");
|
|
620
|
-
}
|
|
621
|
-
});
|
|
622
|
-
collectCallExpressions(path7, importNames, result, params.functionName);
|
|
623
|
-
}
|
|
624
|
-
});
|
|
625
|
-
return result;
|
|
626
|
-
}
|
|
627
|
-
function collectCallExpressions(path7, importNames, result, functionName) {
|
|
628
|
-
const program = path7.findParent(
|
|
629
|
-
(p) => p.isProgram()
|
|
630
|
-
);
|
|
631
|
-
if (!program) return;
|
|
632
|
-
program.traverse({
|
|
633
|
-
CallExpression(callPath) {
|
|
634
|
-
const callee = callPath.node.callee;
|
|
635
|
-
if (t3.isIdentifier(callee) && importNames.has(callee.name)) {
|
|
636
|
-
result.push(callPath.node);
|
|
637
|
-
} else if (t3.isMemberExpression(callee) && t3.isIdentifier(callee.object) && importNames.get(callee.object.name) === "namespace" && t3.isIdentifier(callee.property) && callee.property.name === functionName) {
|
|
638
|
-
result.push(callPath.node);
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
});
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
// src/client-dictionary-loader.ts
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
// src/_utils.ts
|
|
648
|
-
|
|
649
|
-
var getDictionaryPath = (params) => {
|
|
650
|
-
const toFile = path.default.resolve(
|
|
651
|
-
params.sourceRoot,
|
|
652
|
-
params.lingoDir,
|
|
653
|
-
LCP_DICTIONARY_FILE_NAME
|
|
654
|
-
);
|
|
655
|
-
const fromDir = path.default.dirname(
|
|
656
|
-
path.default.resolve(params.sourceRoot, params.relativeFilePath)
|
|
657
|
-
);
|
|
658
|
-
const relativePath = path.default.relative(fromDir, toFile);
|
|
659
|
-
const normalizedPath = relativePath.split(path.default.sep).join(path.default.posix.sep);
|
|
660
|
-
return `./${normalizedPath}`;
|
|
661
|
-
};
|
|
662
|
-
|
|
663
|
-
// src/utils/create-locale-import-map.ts
|
|
664
|
-
|
|
665
|
-
function createLocaleImportMap(allLocales, dictionaryPath) {
|
|
666
|
-
return t4.objectExpression(
|
|
667
|
-
allLocales.map(
|
|
668
|
-
(locale) => t4.objectProperty(
|
|
669
|
-
t4.stringLiteral(locale),
|
|
670
|
-
t4.arrowFunctionExpression(
|
|
671
|
-
[],
|
|
672
|
-
t4.callExpression(t4.identifier("import"), [
|
|
673
|
-
t4.stringLiteral(`${dictionaryPath}?locale=${locale}`)
|
|
674
|
-
])
|
|
675
|
-
)
|
|
676
|
-
)
|
|
677
|
-
)
|
|
678
|
-
);
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
// src/client-dictionary-loader.ts
|
|
682
|
-
var clientDictionaryLoaderMutation = createCodeMutation((payload) => {
|
|
683
|
-
const invokations = findInvokations(payload.ast, {
|
|
684
|
-
moduleName: ModuleId.ReactClient,
|
|
685
|
-
functionName: "loadDictionary"
|
|
686
|
-
});
|
|
687
|
-
const allLocales = Array.from(
|
|
688
|
-
/* @__PURE__ */ new Set([payload.params.sourceLocale, ...payload.params.targetLocales])
|
|
689
|
-
);
|
|
690
|
-
for (const invokation of invokations) {
|
|
691
|
-
const internalDictionaryLoader = getOrCreateImport(payload.ast, {
|
|
692
|
-
moduleName: ModuleId.ReactClient,
|
|
693
|
-
exportedName: "loadDictionary_internal"
|
|
694
|
-
});
|
|
695
|
-
if (t5.isIdentifier(invokation.callee)) {
|
|
696
|
-
invokation.callee.name = internalDictionaryLoader.importedName;
|
|
697
|
-
}
|
|
698
|
-
const dictionaryPath = getDictionaryPath({
|
|
699
|
-
sourceRoot: payload.params.sourceRoot,
|
|
700
|
-
lingoDir: payload.params.lingoDir,
|
|
701
|
-
relativeFilePath: payload.relativeFilePath
|
|
702
|
-
});
|
|
703
|
-
const localeImportMap = createLocaleImportMap(allLocales, dictionaryPath);
|
|
704
|
-
invokation.arguments.push(localeImportMap);
|
|
705
|
-
}
|
|
706
|
-
return payload;
|
|
707
|
-
});
|
|
708
|
-
|
|
709
|
-
// src/i18n-directive.ts
|
|
710
|
-
var i18nDirectiveMutation = createCodeMutation((payload) => {
|
|
711
|
-
if (!payload.params.useDirective || hasI18nDirective(payload.ast)) {
|
|
712
|
-
return payload;
|
|
713
|
-
} else {
|
|
714
|
-
return null;
|
|
715
|
-
}
|
|
716
|
-
});
|
|
717
|
-
var i18n_directive_default = i18nDirectiveMutation;
|
|
718
|
-
|
|
719
|
-
// src/jsx-attribute-flag.ts
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
// src/utils/jsx-attribute-scope.ts
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
function collectJsxAttributeScopes(node) {
|
|
726
|
-
const result = [];
|
|
727
|
-
_traverse2.default.call(void 0, node, {
|
|
728
|
-
JSXElement(path7) {
|
|
729
|
-
if (!hasJsxAttributeScopeAttribute(path7)) return;
|
|
730
|
-
const localizableAttributes = getJsxAttributeScopeAttribute(path7);
|
|
731
|
-
if (!localizableAttributes) return;
|
|
732
|
-
result.push([path7, localizableAttributes]);
|
|
733
|
-
}
|
|
734
|
-
});
|
|
735
|
-
return result;
|
|
736
|
-
}
|
|
737
|
-
function getJsxAttributeScopes(node) {
|
|
738
|
-
const result = [];
|
|
739
|
-
const LOCALIZABLE_ATTRIBUTES = [
|
|
740
|
-
"title",
|
|
741
|
-
"aria-label",
|
|
742
|
-
"aria-description",
|
|
743
|
-
"alt",
|
|
744
|
-
"label",
|
|
745
|
-
"description",
|
|
746
|
-
"placeholder",
|
|
747
|
-
"content",
|
|
748
|
-
"subtitle"
|
|
749
|
-
];
|
|
750
|
-
_traverse2.default.call(void 0, node, {
|
|
751
|
-
JSXElement(path7) {
|
|
752
|
-
const openingElement = path7.node.openingElement;
|
|
753
|
-
const elementName = openingElement.name;
|
|
754
|
-
if (!t6.isJSXIdentifier(elementName) || !elementName.name) {
|
|
755
|
-
return;
|
|
756
|
-
}
|
|
757
|
-
const hasAttributeScope = openingElement.attributes.find(
|
|
758
|
-
(attr) => t6.isJSXAttribute(attr) && attr.name.name === "data-jsx-attribute-scope"
|
|
759
|
-
);
|
|
760
|
-
if (hasAttributeScope) {
|
|
761
|
-
return;
|
|
762
|
-
}
|
|
763
|
-
const localizableAttrs = openingElement.attributes.filter(
|
|
764
|
-
(attr) => {
|
|
765
|
-
if (!t6.isJSXAttribute(attr) || !t6.isStringLiteral(attr.value)) {
|
|
766
|
-
return false;
|
|
767
|
-
}
|
|
768
|
-
const name = attr.name.name;
|
|
769
|
-
return typeof name === "string" && LOCALIZABLE_ATTRIBUTES.includes(name);
|
|
770
|
-
}
|
|
771
|
-
).map((attr) => attr.name.name);
|
|
772
|
-
if (localizableAttrs.length > 0) {
|
|
773
|
-
result.push([path7, localizableAttrs]);
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
});
|
|
777
|
-
return result;
|
|
778
|
-
}
|
|
779
|
-
function hasJsxAttributeScopeAttribute(path7) {
|
|
780
|
-
return !!getJsxAttributeScopeAttribute(path7);
|
|
781
|
-
}
|
|
782
|
-
function getJsxAttributeScopeAttribute(path7) {
|
|
783
|
-
const attribute = path7.node.openingElement.attributes.find(
|
|
784
|
-
(attr) => attr.type === "JSXAttribute" && attr.name.name === "data-jsx-attribute-scope"
|
|
785
|
-
);
|
|
786
|
-
if (!attribute || !t6.isJSXAttribute(attribute)) {
|
|
787
|
-
return void 0;
|
|
788
|
-
}
|
|
789
|
-
if (t6.isJSXExpressionContainer(attribute.value) && t6.isArrayExpression(attribute.value.expression)) {
|
|
790
|
-
const arrayExpr = attribute.value.expression;
|
|
791
|
-
return arrayExpr.elements.filter((el) => t6.isStringLiteral(el)).map((el) => el.value);
|
|
792
|
-
}
|
|
793
|
-
if (t6.isStringLiteral(attribute.value)) {
|
|
794
|
-
return [attribute.value.value];
|
|
795
|
-
}
|
|
796
|
-
return void 0;
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
// src/utils/ast-key.ts
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
function getAstKey(nodePath) {
|
|
803
|
-
const keyChunks = [];
|
|
804
|
-
let current = nodePath;
|
|
805
|
-
while (current) {
|
|
806
|
-
keyChunks.push(current.key);
|
|
807
|
-
current = current.parentPath;
|
|
808
|
-
if (t7.isProgram(_optionalChain([current, 'optionalAccess', _19 => _19.node]))) {
|
|
809
|
-
break;
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
const result = keyChunks.reverse().join("/");
|
|
813
|
-
return result;
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
// src/jsx-attribute-flag.ts
|
|
817
|
-
var jsxAttributeFlagMutation = createCodeMutation(
|
|
818
|
-
(payload) => {
|
|
819
|
-
const jsxScopes = getJsxAttributeScopes(payload.ast);
|
|
820
|
-
for (const [jsxScope, attributes] of jsxScopes) {
|
|
821
|
-
const scopeKey = getAstKey(jsxScope);
|
|
822
|
-
jsxScope.node.openingElement.attributes.push(
|
|
823
|
-
t8.jsxAttribute(
|
|
824
|
-
t8.jsxIdentifier("data-jsx-attribute-scope"),
|
|
825
|
-
t8.jsxExpressionContainer(
|
|
826
|
-
t8.arrayExpression(
|
|
827
|
-
attributes.map(
|
|
828
|
-
(attr) => t8.stringLiteral(`${attr}:${scopeKey}-${attr}`)
|
|
829
|
-
)
|
|
830
|
-
)
|
|
831
|
-
)
|
|
832
|
-
)
|
|
833
|
-
);
|
|
834
|
-
}
|
|
835
|
-
return {
|
|
836
|
-
...payload
|
|
837
|
-
};
|
|
838
|
-
}
|
|
839
|
-
);
|
|
840
|
-
var jsx_attribute_flag_default = jsxAttributeFlagMutation;
|
|
841
|
-
|
|
842
|
-
// src/jsx-attribute-scope-inject.ts
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
// src/utils/jsx-element.ts
|
|
846
|
-
|
|
847
|
-
function getJsxElementName(nodePath) {
|
|
848
|
-
const openingElement = nodePath.node.openingElement;
|
|
849
|
-
if (t9.isJSXIdentifier(openingElement.name)) {
|
|
850
|
-
return openingElement.name.name;
|
|
851
|
-
}
|
|
852
|
-
if (t9.isJSXMemberExpression(openingElement.name)) {
|
|
853
|
-
const memberExpr = openingElement.name;
|
|
854
|
-
const parts = [];
|
|
855
|
-
let current = memberExpr;
|
|
856
|
-
while (t9.isJSXMemberExpression(current)) {
|
|
857
|
-
parts.unshift(current.property.name);
|
|
858
|
-
current = current.object;
|
|
859
|
-
}
|
|
860
|
-
if (t9.isJSXIdentifier(current)) {
|
|
861
|
-
parts.unshift(current.name);
|
|
862
|
-
}
|
|
863
|
-
return parts.join(".");
|
|
864
|
-
}
|
|
865
|
-
return null;
|
|
866
|
-
}
|
|
867
|
-
function getNestedJsxElements(nodePath) {
|
|
868
|
-
const nestedElements = [];
|
|
869
|
-
nodePath.traverse({
|
|
870
|
-
JSXElement(path7) {
|
|
871
|
-
if (path7.node !== nodePath.node) {
|
|
872
|
-
nestedElements.push(path7.node);
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
});
|
|
876
|
-
const arrayOfElements = nestedElements.map((element, index) => {
|
|
877
|
-
const param = t9.identifier("children");
|
|
878
|
-
const clonedElement = t9.cloneNode(element);
|
|
879
|
-
clonedElement.children = [t9.jsxExpressionContainer(param)];
|
|
880
|
-
return t9.arrowFunctionExpression(
|
|
881
|
-
[t9.objectPattern([t9.objectProperty(param, param, false, true)])],
|
|
882
|
-
clonedElement
|
|
883
|
-
);
|
|
884
|
-
});
|
|
885
|
-
const result = t9.arrayExpression(arrayOfElements);
|
|
886
|
-
return result;
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
// src/jsx-attribute-scope-inject.ts
|
|
890
|
-
var lingoJsxAttributeScopeInjectMutation = createCodeMutation(
|
|
891
|
-
(payload) => {
|
|
892
|
-
const mode = getModuleExecutionMode(payload.ast, payload.params.rsc);
|
|
893
|
-
const jsxAttributeScopes = collectJsxAttributeScopes(payload.ast);
|
|
894
|
-
for (const [jsxScope, attributes] of jsxAttributeScopes) {
|
|
895
|
-
const packagePath = mode === "client" ? ModuleId.ReactClient : ModuleId.ReactRSC;
|
|
896
|
-
const lingoComponentImport = getOrCreateImport(payload.ast, {
|
|
897
|
-
moduleName: packagePath,
|
|
898
|
-
exportedName: "LingoAttributeComponent"
|
|
899
|
-
});
|
|
900
|
-
const originalJsxElementName = getJsxElementName(jsxScope);
|
|
901
|
-
if (!originalJsxElementName) {
|
|
902
|
-
continue;
|
|
903
|
-
}
|
|
904
|
-
jsxScope.node.openingElement.name = t10.jsxIdentifier(
|
|
905
|
-
lingoComponentImport.importedName
|
|
906
|
-
);
|
|
907
|
-
if (jsxScope.node.closingElement) {
|
|
908
|
-
jsxScope.node.closingElement.name = t10.jsxIdentifier(
|
|
909
|
-
lingoComponentImport.importedName
|
|
910
|
-
);
|
|
911
|
-
}
|
|
912
|
-
const as = /^[A-Z]/.test(originalJsxElementName) ? t10.jsxExpressionContainer(t10.identifier(originalJsxElementName)) : t10.stringLiteral(originalJsxElementName);
|
|
913
|
-
jsxScope.node.openingElement.attributes.push(
|
|
914
|
-
t10.jsxAttribute(t10.jsxIdentifier("$attrAs"), as)
|
|
915
|
-
);
|
|
916
|
-
setJsxAttributeValue(jsxScope, "$fileKey", payload.relativeFilePath);
|
|
917
|
-
setJsxAttributeValue(
|
|
918
|
-
jsxScope,
|
|
919
|
-
"$attributes",
|
|
920
|
-
t10.objectExpression(
|
|
921
|
-
attributes.map((attributeDefinition) => {
|
|
922
|
-
const [attribute, key = ""] = attributeDefinition.split(":");
|
|
923
|
-
return t10.objectProperty(
|
|
924
|
-
t10.stringLiteral(attribute),
|
|
925
|
-
t10.stringLiteral(key)
|
|
926
|
-
);
|
|
927
|
-
})
|
|
928
|
-
)
|
|
929
|
-
);
|
|
930
|
-
if (mode === "server") {
|
|
931
|
-
const loadDictionaryImport = getOrCreateImport(payload.ast, {
|
|
932
|
-
exportedName: "loadDictionary",
|
|
933
|
-
moduleName: ModuleId.ReactRSC
|
|
934
|
-
});
|
|
935
|
-
setJsxAttributeValue(
|
|
936
|
-
jsxScope,
|
|
937
|
-
"$loadDictionary",
|
|
938
|
-
t10.arrowFunctionExpression(
|
|
939
|
-
[t10.identifier("locale")],
|
|
940
|
-
t10.callExpression(t10.identifier(loadDictionaryImport.importedName), [
|
|
941
|
-
t10.identifier("locale")
|
|
942
|
-
])
|
|
943
|
-
)
|
|
944
|
-
);
|
|
945
|
-
}
|
|
946
|
-
}
|
|
947
|
-
return payload;
|
|
948
|
-
}
|
|
949
|
-
);
|
|
950
|
-
|
|
951
|
-
// src/lib/lcp/index.ts
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
var _dedent = require('dedent'); var _dedent2 = _interopRequireDefault(_dedent);
|
|
956
|
-
var LCP_FILE_NAME = "meta.json";
|
|
957
|
-
var LCP = class _LCP {
|
|
958
|
-
constructor(filePath, data = {
|
|
959
|
-
version: 0.1
|
|
960
|
-
}) {
|
|
961
|
-
this.filePath = filePath;
|
|
962
|
-
this.data = data;
|
|
963
|
-
}
|
|
964
|
-
static ensureFile(params) {
|
|
965
|
-
const filePath = path5.resolve(
|
|
966
|
-
process.cwd(),
|
|
967
|
-
params.sourceRoot,
|
|
968
|
-
params.lingoDir,
|
|
969
|
-
LCP_FILE_NAME
|
|
970
|
-
);
|
|
971
|
-
if (!fs4.existsSync(filePath)) {
|
|
972
|
-
const dir = path5.dirname(filePath);
|
|
973
|
-
if (!fs4.existsSync(dir)) {
|
|
974
|
-
fs4.mkdirSync(dir, { recursive: true });
|
|
975
|
-
}
|
|
976
|
-
fs4.writeFileSync(filePath, "{}");
|
|
977
|
-
try {
|
|
978
|
-
fs4.rmdirSync(path5.resolve(process.cwd(), ".next"), {
|
|
979
|
-
recursive: true
|
|
980
|
-
});
|
|
981
|
-
} catch (error) {
|
|
982
|
-
}
|
|
983
|
-
throw new Error(_dedent2.default`
|
|
984
|
-
⚠️ Lingo.dev Compiler detected missing meta.json file in lingo directory.
|
|
985
|
-
Please restart the build / watch command to regenerate all Lingo.dev Compiler files.
|
|
986
|
-
`);
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
static getInstance(params) {
|
|
990
|
-
const filePath = path5.resolve(
|
|
991
|
-
process.cwd(),
|
|
992
|
-
params.sourceRoot,
|
|
993
|
-
params.lingoDir,
|
|
994
|
-
LCP_FILE_NAME
|
|
995
|
-
);
|
|
996
|
-
if (fs4.existsSync(filePath)) {
|
|
997
|
-
return new _LCP(filePath, JSON.parse(fs4.readFileSync(filePath, "utf8")));
|
|
998
|
-
}
|
|
999
|
-
return new _LCP(filePath);
|
|
1000
|
-
}
|
|
1001
|
-
// wait until LCP file stops updating
|
|
1002
|
-
// this ensures all files were transformed before loading / translating dictionaries
|
|
1003
|
-
static async ready(params) {
|
|
1004
|
-
if (params.isDev) {
|
|
1005
|
-
_LCP.ensureFile(params);
|
|
1006
|
-
}
|
|
1007
|
-
const filePath = path5.resolve(
|
|
1008
|
-
process.cwd(),
|
|
1009
|
-
params.sourceRoot,
|
|
1010
|
-
params.lingoDir,
|
|
1011
|
-
LCP_FILE_NAME
|
|
1012
|
-
);
|
|
1013
|
-
if (fs4.existsSync(filePath)) {
|
|
1014
|
-
const stats = fs4.statSync(filePath);
|
|
1015
|
-
if (Date.now() - stats.mtimeMs > 1500) {
|
|
1016
|
-
return;
|
|
1017
|
-
}
|
|
1018
|
-
}
|
|
1019
|
-
return new Promise((resolve3) => {
|
|
1020
|
-
setTimeout(() => {
|
|
1021
|
-
_LCP.ready(params).then(resolve3);
|
|
1022
|
-
}, 750);
|
|
1023
|
-
});
|
|
1024
|
-
}
|
|
1025
|
-
resetScope(fileKey, scopeKey) {
|
|
1026
|
-
if (!_lodash2.default.isObject(
|
|
1027
|
-
_lodash2.default.get(this.data, ["files", fileKey])
|
|
1028
|
-
)) {
|
|
1029
|
-
_lodash2.default.set(this.data, ["files", fileKey], {});
|
|
1030
|
-
}
|
|
1031
|
-
_lodash2.default.set(
|
|
1032
|
-
this.data,
|
|
1033
|
-
[
|
|
1034
|
-
"files",
|
|
1035
|
-
fileKey,
|
|
1036
|
-
"scopes",
|
|
1037
|
-
scopeKey
|
|
1038
|
-
],
|
|
1039
|
-
{}
|
|
1040
|
-
);
|
|
1041
|
-
return this;
|
|
1042
|
-
}
|
|
1043
|
-
setScopeType(fileKey, scopeKey, type) {
|
|
1044
|
-
return this._setScopeField(fileKey, scopeKey, "type", type);
|
|
1045
|
-
}
|
|
1046
|
-
setScopeContext(fileKey, scopeKey, context) {
|
|
1047
|
-
return this._setScopeField(fileKey, scopeKey, "context", context);
|
|
1048
|
-
}
|
|
1049
|
-
setScopeHash(fileKey, scopeKey, hash) {
|
|
1050
|
-
return this._setScopeField(fileKey, scopeKey, "hash", hash);
|
|
1051
|
-
}
|
|
1052
|
-
setScopeSkip(fileKey, scopeKey, skip) {
|
|
1053
|
-
return this._setScopeField(fileKey, scopeKey, "skip", skip);
|
|
1054
|
-
}
|
|
1055
|
-
setScopeOverrides(fileKey, scopeKey, overrides) {
|
|
1056
|
-
return this._setScopeField(fileKey, scopeKey, "overrides", overrides);
|
|
1057
|
-
}
|
|
1058
|
-
setScopeContent(fileKey, scopeKey, content) {
|
|
1059
|
-
return this._setScopeField(fileKey, scopeKey, "content", content);
|
|
1060
|
-
}
|
|
1061
|
-
toJSON() {
|
|
1062
|
-
const files = _lodash2.default.call(void 0, _optionalChain([this, 'access', _20 => _20.data, 'optionalAccess', _21 => _21.files])).mapValues((file, fileName) => {
|
|
1063
|
-
return {
|
|
1064
|
-
...file,
|
|
1065
|
-
scopes: _lodash2.default.call(void 0, _optionalChain([file, 'optionalAccess', _22 => _22.scopes])).toPairs().sortBy([0]).fromPairs().value()
|
|
1066
|
-
};
|
|
1067
|
-
}).toPairs().sortBy([0]).fromPairs().value();
|
|
1068
|
-
return { ...this.data, files };
|
|
1069
|
-
}
|
|
1070
|
-
toString() {
|
|
1071
|
-
return JSON.stringify(this.toJSON(), null, 2) + "\n";
|
|
1072
|
-
}
|
|
1073
|
-
save() {
|
|
1074
|
-
const hasChanges = !fs4.existsSync(this.filePath) || fs4.readFileSync(this.filePath, "utf8") !== this.toString();
|
|
1075
|
-
if (hasChanges) {
|
|
1076
|
-
const dir = path5.dirname(this.filePath);
|
|
1077
|
-
if (!fs4.existsSync(dir)) {
|
|
1078
|
-
fs4.mkdirSync(dir, { recursive: true });
|
|
1079
|
-
}
|
|
1080
|
-
fs4.writeFileSync(this.filePath, this.toString());
|
|
1081
|
-
this._triggerLCPReload();
|
|
1082
|
-
}
|
|
1083
|
-
}
|
|
1084
|
-
_triggerLCPReload() {
|
|
1085
|
-
const dir = path5.dirname(this.filePath);
|
|
1086
|
-
const filePath = path5.resolve(dir, LCP_DICTIONARY_FILE_NAME);
|
|
1087
|
-
if (fs4.existsSync(filePath)) {
|
|
1088
|
-
try {
|
|
1089
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
1090
|
-
fs4.utimesSync(filePath, now, now);
|
|
1091
|
-
} catch (error) {
|
|
1092
|
-
if (_optionalChain([error, 'optionalAccess', _23 => _23.code]) === "EINVAL") {
|
|
1093
|
-
console.warn(
|
|
1094
|
-
_dedent2.default`
|
|
1095
|
-
⚠️ Lingo: Auto-reload disabled - system blocks Node.js timestamp updates.
|
|
1096
|
-
💡 Fix: Adjust security settings to allow Node.js file modifications.
|
|
1097
|
-
⚡ Workaround: Manually refresh browser after translation changes.
|
|
1098
|
-
💬 Need help? Join our Discord: https://lingo.dev/go/discord.
|
|
1099
|
-
`
|
|
1100
|
-
);
|
|
1101
|
-
}
|
|
1102
|
-
}
|
|
1103
|
-
}
|
|
1104
|
-
}
|
|
1105
|
-
_setScopeField(fileKey, scopeKey, field, value) {
|
|
1106
|
-
_lodash2.default.set(
|
|
1107
|
-
this.data,
|
|
1108
|
-
[
|
|
1109
|
-
"files",
|
|
1110
|
-
fileKey,
|
|
1111
|
-
"scopes",
|
|
1112
|
-
scopeKey,
|
|
1113
|
-
field
|
|
1114
|
-
],
|
|
1115
|
-
value
|
|
1116
|
-
);
|
|
1117
|
-
return this;
|
|
1118
|
-
}
|
|
1119
|
-
};
|
|
1120
|
-
|
|
1121
|
-
// src/utils/hash.ts
|
|
1122
|
-
var _objecthash = require('object-hash');
|
|
1123
|
-
function getJsxElementHash(nodePath) {
|
|
1124
|
-
if (!nodePath.node) {
|
|
1125
|
-
return "";
|
|
1126
|
-
}
|
|
1127
|
-
const content = nodePath.node.children.map((child) => child.value).join("");
|
|
1128
|
-
const result = _objecthash.MD5.call(void 0, content);
|
|
1129
|
-
return result;
|
|
1130
|
-
}
|
|
1131
|
-
function getJsxAttributeValueHash(attributeValue) {
|
|
1132
|
-
if (!attributeValue) {
|
|
1133
|
-
return "";
|
|
1134
|
-
}
|
|
1135
|
-
const result = _objecthash.MD5.call(void 0, attributeValue);
|
|
1136
|
-
return result;
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
|
-
// src/jsx-attribute-scopes-export.ts
|
|
1140
|
-
|
|
1141
|
-
function jsxAttributeScopesExportMutation(payload) {
|
|
1142
|
-
const attributeScopes = collectJsxAttributeScopes(payload.ast);
|
|
1143
|
-
if (_lodash2.default.isEmpty(attributeScopes)) {
|
|
1144
|
-
return payload;
|
|
1145
|
-
}
|
|
1146
|
-
const lcp = LCP.getInstance({
|
|
1147
|
-
sourceRoot: payload.params.sourceRoot,
|
|
1148
|
-
lingoDir: payload.params.lingoDir
|
|
1149
|
-
});
|
|
1150
|
-
for (const [scope, attributes] of attributeScopes) {
|
|
1151
|
-
for (const attributeDefinition of attributes) {
|
|
1152
|
-
const [attribute, scopeKey] = attributeDefinition.split(":");
|
|
1153
|
-
lcp.resetScope(payload.relativeFilePath, scopeKey);
|
|
1154
|
-
const attributeValue = getJsxAttributeValue(scope, attribute);
|
|
1155
|
-
if (!attributeValue) {
|
|
1156
|
-
continue;
|
|
1157
|
-
}
|
|
1158
|
-
lcp.setScopeType(payload.relativeFilePath, scopeKey, "attribute");
|
|
1159
|
-
const hash = getJsxAttributeValueHash(String(attributeValue));
|
|
1160
|
-
lcp.setScopeHash(payload.relativeFilePath, scopeKey, hash);
|
|
1161
|
-
lcp.setScopeContext(payload.relativeFilePath, scopeKey, "");
|
|
1162
|
-
lcp.setScopeSkip(payload.relativeFilePath, scopeKey, false);
|
|
1163
|
-
lcp.setScopeOverrides(payload.relativeFilePath, scopeKey, {});
|
|
1164
|
-
lcp.setScopeContent(
|
|
1165
|
-
payload.relativeFilePath,
|
|
1166
|
-
scopeKey,
|
|
1167
|
-
String(attributeValue)
|
|
1168
|
-
);
|
|
1169
|
-
}
|
|
1170
|
-
}
|
|
1171
|
-
lcp.save();
|
|
1172
|
-
return payload;
|
|
1173
|
-
}
|
|
1174
|
-
|
|
1175
|
-
// src/jsx-fragment.ts
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
function jsxFragmentMutation(payload) {
|
|
1179
|
-
const { ast } = payload;
|
|
1180
|
-
let foundFragments = false;
|
|
1181
|
-
let fragmentImportName = null;
|
|
1182
|
-
_traverse2.default.call(void 0, ast, {
|
|
1183
|
-
ImportDeclaration(path7) {
|
|
1184
|
-
if (path7.node.source.value !== "react") return;
|
|
1185
|
-
for (const specifier of path7.node.specifiers) {
|
|
1186
|
-
if (t11.isImportSpecifier(specifier) && t11.isIdentifier(specifier.imported) && specifier.imported.name === "Fragment") {
|
|
1187
|
-
fragmentImportName = specifier.local.name;
|
|
1188
|
-
path7.stop();
|
|
1189
|
-
}
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
});
|
|
1193
|
-
_traverse2.default.call(void 0, ast, {
|
|
1194
|
-
JSXFragment(path7) {
|
|
1195
|
-
foundFragments = true;
|
|
1196
|
-
if (!fragmentImportName) {
|
|
1197
|
-
const result = getOrCreateImport(ast, {
|
|
1198
|
-
exportedName: "Fragment",
|
|
1199
|
-
moduleName: ["react"]
|
|
1200
|
-
});
|
|
1201
|
-
fragmentImportName = result.importedName;
|
|
1202
|
-
}
|
|
1203
|
-
const fragmentElement = t11.jsxElement(
|
|
1204
|
-
t11.jsxOpeningElement(t11.jsxIdentifier(fragmentImportName), [], false),
|
|
1205
|
-
t11.jsxClosingElement(t11.jsxIdentifier(fragmentImportName)),
|
|
1206
|
-
path7.node.children,
|
|
1207
|
-
false
|
|
1208
|
-
);
|
|
1209
|
-
path7.replaceWith(fragmentElement);
|
|
1210
|
-
}
|
|
1211
|
-
});
|
|
1212
|
-
return payload;
|
|
1213
|
-
}
|
|
1214
|
-
|
|
1215
|
-
// src/jsx-html-lang.ts
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
var jsxHtmlLangMutation = createCodeMutation((payload) => {
|
|
1219
|
-
_traverse2.default.call(void 0, payload.ast, {
|
|
1220
|
-
JSXElement: (path7) => {
|
|
1221
|
-
if (_optionalChain([getJsxElementName, 'call', _24 => _24(path7), 'optionalAccess', _25 => _25.toLowerCase, 'call', _26 => _26()]) === "html") {
|
|
1222
|
-
const mode = getModuleExecutionMode(payload.ast, payload.params.rsc);
|
|
1223
|
-
const packagePath = mode === "client" ? ModuleId.ReactClient : ModuleId.ReactRSC;
|
|
1224
|
-
const lingoHtmlComponentImport = getOrCreateImport(payload.ast, {
|
|
1225
|
-
moduleName: packagePath,
|
|
1226
|
-
exportedName: "LingoHtmlComponent"
|
|
1227
|
-
});
|
|
1228
|
-
path7.node.openingElement.name = t12.jsxIdentifier(
|
|
1229
|
-
lingoHtmlComponentImport.importedName
|
|
1230
|
-
);
|
|
1231
|
-
if (path7.node.closingElement) {
|
|
1232
|
-
path7.node.closingElement.name = t12.jsxIdentifier(
|
|
1233
|
-
lingoHtmlComponentImport.importedName
|
|
1234
|
-
);
|
|
1235
|
-
}
|
|
1236
|
-
path7.skip();
|
|
1237
|
-
}
|
|
1238
|
-
}
|
|
1239
|
-
});
|
|
1240
|
-
return payload;
|
|
1241
|
-
});
|
|
1242
|
-
|
|
1243
|
-
// src/jsx-provider.ts
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
var jsxProviderMutation = createCodeMutation((payload) => {
|
|
1247
|
-
_traverse2.default.call(void 0, payload.ast, {
|
|
1248
|
-
JSXElement: (path7) => {
|
|
1249
|
-
if (_optionalChain([getJsxElementName, 'call', _27 => _27(path7), 'optionalAccess', _28 => _28.toLowerCase, 'call', _29 => _29()]) === "html") {
|
|
1250
|
-
const mode = getModuleExecutionMode(payload.ast, payload.params.rsc);
|
|
1251
|
-
if (mode === "client") {
|
|
1252
|
-
return;
|
|
1253
|
-
}
|
|
1254
|
-
const lingoProviderImport = getOrCreateImport(payload.ast, {
|
|
1255
|
-
moduleName: ModuleId.ReactRSC,
|
|
1256
|
-
exportedName: "LingoProvider"
|
|
1257
|
-
});
|
|
1258
|
-
const loadDictionaryImport = getOrCreateImport(payload.ast, {
|
|
1259
|
-
moduleName: ModuleId.ReactRSC,
|
|
1260
|
-
exportedName: "loadDictionary"
|
|
1261
|
-
});
|
|
1262
|
-
const loadDictionaryArrow = t13.arrowFunctionExpression(
|
|
1263
|
-
[t13.identifier("locale")],
|
|
1264
|
-
t13.callExpression(t13.identifier(loadDictionaryImport.importedName), [
|
|
1265
|
-
t13.identifier("locale")
|
|
1266
|
-
])
|
|
1267
|
-
);
|
|
1268
|
-
const providerProps = [
|
|
1269
|
-
t13.jsxAttribute(
|
|
1270
|
-
t13.jsxIdentifier("loadDictionary"),
|
|
1271
|
-
t13.jsxExpressionContainer(loadDictionaryArrow)
|
|
1272
|
-
)
|
|
1273
|
-
];
|
|
1274
|
-
const provider = t13.jsxElement(
|
|
1275
|
-
t13.jsxOpeningElement(
|
|
1276
|
-
t13.jsxIdentifier(lingoProviderImport.importedName),
|
|
1277
|
-
providerProps,
|
|
1278
|
-
false
|
|
1279
|
-
),
|
|
1280
|
-
t13.jsxClosingElement(
|
|
1281
|
-
t13.jsxIdentifier(lingoProviderImport.importedName)
|
|
1282
|
-
),
|
|
1283
|
-
[path7.node],
|
|
1284
|
-
false
|
|
1285
|
-
);
|
|
1286
|
-
path7.replaceWith(provider);
|
|
1287
|
-
path7.skip();
|
|
1288
|
-
}
|
|
1289
|
-
}
|
|
1290
|
-
});
|
|
1291
|
-
return payload;
|
|
1292
|
-
});
|
|
1293
|
-
var jsx_provider_default = jsxProviderMutation;
|
|
1294
|
-
|
|
1295
|
-
// src/jsx-remove-attributes.ts
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
var jsxRemoveAttributesMutation = createCodeMutation(
|
|
1299
|
-
(payload) => {
|
|
1300
|
-
const ATTRIBUTES_TO_REMOVE = [
|
|
1301
|
-
"data-jsx-root",
|
|
1302
|
-
"data-jsx-scope",
|
|
1303
|
-
"data-jsx-attribute-scope"
|
|
1304
|
-
];
|
|
1305
|
-
_traverse2.default.call(void 0, payload.ast, {
|
|
1306
|
-
JSXElement(path7) {
|
|
1307
|
-
const openingElement = path7.node.openingElement;
|
|
1308
|
-
openingElement.attributes = openingElement.attributes.filter((attr) => {
|
|
1309
|
-
const removeAttr = t14.isJSXAttribute(attr) && t14.isJSXIdentifier(attr.name) && ATTRIBUTES_TO_REMOVE.includes(attr.name.name);
|
|
1310
|
-
return !removeAttr;
|
|
1311
|
-
});
|
|
1312
|
-
}
|
|
1313
|
-
});
|
|
1314
|
-
return {
|
|
1315
|
-
...payload
|
|
1316
|
-
};
|
|
1317
|
-
}
|
|
1318
|
-
);
|
|
1319
|
-
|
|
1320
|
-
// src/jsx-root-flag.ts
|
|
1321
|
-
|
|
1322
|
-
var jsxRootFlagMutation = createCodeMutation((payload) => {
|
|
1323
|
-
const jsxRoots = getJsxRoots(payload.ast);
|
|
1324
|
-
for (const jsxElementPath of jsxRoots) {
|
|
1325
|
-
jsxElementPath.node.openingElement.attributes.push(
|
|
1326
|
-
t15.jsxAttribute(t15.jsxIdentifier("data-jsx-root"), null)
|
|
1327
|
-
);
|
|
1328
|
-
}
|
|
1329
|
-
return {
|
|
1330
|
-
...payload
|
|
1331
|
-
};
|
|
1332
|
-
});
|
|
1333
|
-
var jsx_root_flag_default = jsxRootFlagMutation;
|
|
1334
|
-
|
|
1335
|
-
// src/jsx-scope-flag.ts
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
// src/utils/jsx-scope.ts
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
function collectJsxScopes(ast) {
|
|
1342
|
-
const jsxScopes = [];
|
|
1343
|
-
_traverse2.default.call(void 0, ast, {
|
|
1344
|
-
JSXElement: (path7) => {
|
|
1345
|
-
if (!hasJsxScopeAttribute(path7)) return;
|
|
1346
|
-
path7.skip();
|
|
1347
|
-
jsxScopes.push(path7);
|
|
1348
|
-
}
|
|
1349
|
-
});
|
|
1350
|
-
return jsxScopes;
|
|
1351
|
-
}
|
|
1352
|
-
function getJsxScopes(node) {
|
|
1353
|
-
const result = [];
|
|
1354
|
-
_traverse2.default.call(void 0, node, {
|
|
1355
|
-
JSXElement(path7) {
|
|
1356
|
-
if (getJsxElementName(path7) === "LingoProvider") {
|
|
1357
|
-
return;
|
|
1358
|
-
}
|
|
1359
|
-
const hasNonEmptyTextSiblings = path7.getAllPrevSiblings().concat(path7.getAllNextSiblings()).some(
|
|
1360
|
-
(sibling) => t16.isJSXText(sibling.node) && _optionalChain([sibling, 'access', _30 => _30.node, 'access', _31 => _31.value, 'optionalAccess', _32 => _32.trim, 'call', _33 => _33()]) !== ""
|
|
1361
|
-
);
|
|
1362
|
-
if (hasNonEmptyTextSiblings) {
|
|
1363
|
-
return;
|
|
1364
|
-
}
|
|
1365
|
-
const hasNonEmptyTextChild = path7.get("children").some(
|
|
1366
|
-
(child) => t16.isJSXText(child.node) && _optionalChain([child, 'access', _34 => _34.node, 'access', _35 => _35.value, 'optionalAccess', _36 => _36.trim, 'call', _37 => _37()]) !== ""
|
|
1367
|
-
);
|
|
1368
|
-
if (hasNonEmptyTextChild) {
|
|
1369
|
-
result.push(path7);
|
|
1370
|
-
path7.skip();
|
|
1371
|
-
}
|
|
1372
|
-
}
|
|
1373
|
-
});
|
|
1374
|
-
return result;
|
|
1375
|
-
}
|
|
1376
|
-
function hasJsxScopeAttribute(path7) {
|
|
1377
|
-
return !!getJsxScopeAttribute(path7);
|
|
1378
|
-
}
|
|
1379
|
-
function getJsxScopeAttribute(path7) {
|
|
1380
|
-
const attribute = path7.node.openingElement.attributes.find(
|
|
1381
|
-
(attr) => attr.type === "JSXAttribute" && attr.name.name === "data-jsx-scope"
|
|
1382
|
-
);
|
|
1383
|
-
return attribute && t16.isJSXAttribute(attribute) && t16.isStringLiteral(attribute.value) ? attribute.value.value : void 0;
|
|
1384
|
-
}
|
|
1385
|
-
|
|
1386
|
-
// src/jsx-scope-flag.ts
|
|
1387
|
-
var jsxScopeFlagMutation = createCodeMutation((payload) => {
|
|
1388
|
-
const jsxScopes = getJsxScopes(payload.ast);
|
|
1389
|
-
for (const jsxScope of jsxScopes) {
|
|
1390
|
-
jsxScope.node.openingElement.attributes.push(
|
|
1391
|
-
t17.jsxAttribute(
|
|
1392
|
-
t17.jsxIdentifier("data-jsx-scope"),
|
|
1393
|
-
t17.stringLiteral(getAstKey(jsxScope))
|
|
1394
|
-
)
|
|
1395
|
-
);
|
|
1396
|
-
}
|
|
1397
|
-
return {
|
|
1398
|
-
...payload
|
|
1399
|
-
};
|
|
1400
|
-
});
|
|
1401
|
-
var jsx_scope_flag_default = jsxScopeFlagMutation;
|
|
1402
|
-
|
|
1403
|
-
// src/jsx-scope-inject.ts
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
// src/utils/jsx-variables.ts
|
|
1407
|
-
|
|
1408
|
-
var getJsxVariables = (nodePath) => {
|
|
1409
|
-
const variables = /* @__PURE__ */ new Set();
|
|
1410
|
-
nodePath.traverse({
|
|
1411
|
-
JSXOpeningElement(path7) {
|
|
1412
|
-
path7.skip();
|
|
1413
|
-
},
|
|
1414
|
-
JSXExpressionContainer(path7) {
|
|
1415
|
-
if (t18.isIdentifier(path7.node.expression)) {
|
|
1416
|
-
variables.add(path7.node.expression.name);
|
|
1417
|
-
} else if (t18.isMemberExpression(path7.node.expression)) {
|
|
1418
|
-
let current = path7.node.expression;
|
|
1419
|
-
const parts = [];
|
|
1420
|
-
while (t18.isMemberExpression(current)) {
|
|
1421
|
-
if (t18.isIdentifier(current.property)) {
|
|
1422
|
-
if (current.computed) {
|
|
1423
|
-
parts.unshift(`[${current.property.name}]`);
|
|
1424
|
-
} else {
|
|
1425
|
-
parts.unshift(current.property.name);
|
|
1426
|
-
}
|
|
1427
|
-
}
|
|
1428
|
-
current = current.object;
|
|
1429
|
-
}
|
|
1430
|
-
if (t18.isIdentifier(current)) {
|
|
1431
|
-
parts.unshift(current.name);
|
|
1432
|
-
variables.add(parts.join(".").replaceAll(".[", "["));
|
|
1433
|
-
}
|
|
1434
|
-
}
|
|
1435
|
-
path7.skip();
|
|
1436
|
-
}
|
|
1437
|
-
});
|
|
1438
|
-
const properties = Array.from(variables).map(
|
|
1439
|
-
(name) => t18.objectProperty(t18.stringLiteral(name), t18.identifier(name))
|
|
1440
|
-
);
|
|
1441
|
-
const result = t18.objectExpression(properties);
|
|
1442
|
-
return result;
|
|
1443
|
-
};
|
|
1444
|
-
|
|
1445
|
-
// src/utils/jsx-functions.ts
|
|
1446
|
-
|
|
1447
|
-
var getJsxFunctions = (nodePath) => {
|
|
1448
|
-
const functions = /* @__PURE__ */ new Map();
|
|
1449
|
-
let fnCounter = 0;
|
|
1450
|
-
nodePath.traverse({
|
|
1451
|
-
JSXOpeningElement(path7) {
|
|
1452
|
-
path7.skip();
|
|
1453
|
-
},
|
|
1454
|
-
JSXExpressionContainer(path7) {
|
|
1455
|
-
if (t19.isCallExpression(path7.node.expression)) {
|
|
1456
|
-
let key = "";
|
|
1457
|
-
if (t19.isIdentifier(path7.node.expression.callee)) {
|
|
1458
|
-
key = `${path7.node.expression.callee.name}`;
|
|
1459
|
-
} else if (t19.isMemberExpression(path7.node.expression.callee)) {
|
|
1460
|
-
let firstCallee = path7.node.expression.callee;
|
|
1461
|
-
while (t19.isMemberExpression(firstCallee) && t19.isCallExpression(firstCallee.object)) {
|
|
1462
|
-
firstCallee = firstCallee.object.callee;
|
|
1463
|
-
}
|
|
1464
|
-
let current = firstCallee;
|
|
1465
|
-
const parts = [];
|
|
1466
|
-
while (t19.isMemberExpression(current)) {
|
|
1467
|
-
if (t19.isIdentifier(current.property)) {
|
|
1468
|
-
parts.unshift(current.property.name);
|
|
1469
|
-
}
|
|
1470
|
-
current = current.object;
|
|
1471
|
-
}
|
|
1472
|
-
if (t19.isIdentifier(current)) {
|
|
1473
|
-
parts.unshift(current.name);
|
|
1474
|
-
}
|
|
1475
|
-
if (t19.isMemberExpression(firstCallee) && t19.isNewExpression(firstCallee.object) && t19.isIdentifier(firstCallee.object.callee)) {
|
|
1476
|
-
parts.unshift(firstCallee.object.callee.name);
|
|
1477
|
-
}
|
|
1478
|
-
key = parts.join(".");
|
|
1479
|
-
}
|
|
1480
|
-
const existing = _nullishCoalesce(functions.get(key), () => ( []));
|
|
1481
|
-
functions.set(key, [...existing, path7.node.expression]);
|
|
1482
|
-
fnCounter++;
|
|
1483
|
-
}
|
|
1484
|
-
path7.skip();
|
|
1485
|
-
}
|
|
1486
|
-
});
|
|
1487
|
-
const properties = Array.from(functions.entries()).map(
|
|
1488
|
-
([name, callExpr]) => t19.objectProperty(t19.stringLiteral(name), t19.arrayExpression(callExpr))
|
|
1489
|
-
);
|
|
1490
|
-
return t19.objectExpression(properties);
|
|
1491
|
-
};
|
|
1492
|
-
|
|
1493
|
-
// src/utils/jsx-expressions.ts
|
|
1494
|
-
|
|
1495
|
-
var getJsxExpressions = (nodePath) => {
|
|
1496
|
-
const expressions = [];
|
|
1497
|
-
nodePath.traverse({
|
|
1498
|
-
JSXOpeningElement(path7) {
|
|
1499
|
-
path7.skip();
|
|
1500
|
-
},
|
|
1501
|
-
JSXExpressionContainer(path7) {
|
|
1502
|
-
const expr = path7.node.expression;
|
|
1503
|
-
if (!t20.isJSXEmptyExpression(expr) && !t20.isIdentifier(expr) && !t20.isMemberExpression(expr) && !t20.isCallExpression(expr) && !(t20.isStringLiteral(expr) && expr.value === " ")) {
|
|
1504
|
-
expressions.push(expr);
|
|
1505
|
-
}
|
|
1506
|
-
path7.skip();
|
|
1507
|
-
}
|
|
1508
|
-
});
|
|
1509
|
-
return t20.arrayExpression(expressions);
|
|
1510
|
-
};
|
|
1511
|
-
|
|
1512
|
-
// src/jsx-scope-inject.ts
|
|
1513
|
-
var lingoJsxScopeInjectMutation = createCodeMutation((payload) => {
|
|
1514
|
-
const mode = getModuleExecutionMode(payload.ast, payload.params.rsc);
|
|
1515
|
-
const jsxScopes = collectJsxScopes(payload.ast);
|
|
1516
|
-
for (const jsxScope of jsxScopes) {
|
|
1517
|
-
const skip = getJsxAttributeValue(jsxScope, "data-lingo-skip");
|
|
1518
|
-
if (skip) {
|
|
1519
|
-
continue;
|
|
1520
|
-
}
|
|
1521
|
-
const packagePath = mode === "client" ? ModuleId.ReactClient : ModuleId.ReactRSC;
|
|
1522
|
-
const lingoComponentImport = getOrCreateImport(payload.ast, {
|
|
1523
|
-
moduleName: packagePath,
|
|
1524
|
-
exportedName: "LingoComponent"
|
|
1525
|
-
});
|
|
1526
|
-
const originalJsxElementName = getJsxElementName(jsxScope);
|
|
1527
|
-
if (!originalJsxElementName) {
|
|
1528
|
-
continue;
|
|
1529
|
-
}
|
|
1530
|
-
const newNode = t21.jsxElement(
|
|
1531
|
-
t21.jsxOpeningElement(
|
|
1532
|
-
t21.jsxIdentifier(lingoComponentImport.importedName),
|
|
1533
|
-
jsxScope.node.openingElement.attributes.slice(),
|
|
1534
|
-
// original attributes
|
|
1535
|
-
true
|
|
1536
|
-
// selfClosing
|
|
1537
|
-
),
|
|
1538
|
-
null,
|
|
1539
|
-
// no closing element
|
|
1540
|
-
[],
|
|
1541
|
-
// no children
|
|
1542
|
-
true
|
|
1543
|
-
// selfClosing
|
|
1544
|
-
);
|
|
1545
|
-
const newNodePath = {
|
|
1546
|
-
node: newNode
|
|
1547
|
-
};
|
|
1548
|
-
const as = /^[A-Z]/.test(originalJsxElementName) ? t21.identifier(originalJsxElementName) : originalJsxElementName;
|
|
1549
|
-
setJsxAttributeValue(newNodePath, "$as", as);
|
|
1550
|
-
setJsxAttributeValue(newNodePath, "$fileKey", payload.relativeFilePath);
|
|
1551
|
-
setJsxAttributeValue(
|
|
1552
|
-
newNodePath,
|
|
1553
|
-
"$entryKey",
|
|
1554
|
-
getJsxScopeAttribute(jsxScope)
|
|
1555
|
-
);
|
|
1556
|
-
const $variables = getJsxVariables(jsxScope);
|
|
1557
|
-
if ($variables.properties.length > 0) {
|
|
1558
|
-
setJsxAttributeValue(newNodePath, "$variables", $variables);
|
|
1559
|
-
}
|
|
1560
|
-
const $elements = getNestedJsxElements(jsxScope);
|
|
1561
|
-
if ($elements.elements.length > 0) {
|
|
1562
|
-
setJsxAttributeValue(newNodePath, "$elements", $elements);
|
|
1563
|
-
}
|
|
1564
|
-
const $functions = getJsxFunctions(jsxScope);
|
|
1565
|
-
if ($functions.properties.length > 0) {
|
|
1566
|
-
setJsxAttributeValue(newNodePath, "$functions", $functions);
|
|
1567
|
-
}
|
|
1568
|
-
const $expressions = getJsxExpressions(jsxScope);
|
|
1569
|
-
if ($expressions.elements.length > 0) {
|
|
1570
|
-
setJsxAttributeValue(newNodePath, "$expressions", $expressions);
|
|
1571
|
-
}
|
|
1572
|
-
if (mode === "server") {
|
|
1573
|
-
const loadDictionaryImport = getOrCreateImport(payload.ast, {
|
|
1574
|
-
exportedName: "loadDictionary",
|
|
1575
|
-
moduleName: ModuleId.ReactRSC
|
|
1576
|
-
});
|
|
1577
|
-
setJsxAttributeValue(
|
|
1578
|
-
newNodePath,
|
|
1579
|
-
"$loadDictionary",
|
|
1580
|
-
t21.arrowFunctionExpression(
|
|
1581
|
-
[t21.identifier("locale")],
|
|
1582
|
-
t21.callExpression(t21.identifier(loadDictionaryImport.importedName), [
|
|
1583
|
-
t21.identifier("locale")
|
|
1584
|
-
])
|
|
1585
|
-
)
|
|
1586
|
-
);
|
|
1587
|
-
}
|
|
1588
|
-
jsxScope.replaceWith(newNode);
|
|
1589
|
-
}
|
|
1590
|
-
return payload;
|
|
1591
|
-
});
|
|
1592
|
-
|
|
1593
|
-
// src/jsx-scopes-export.ts
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
// src/utils/jsx-content.ts
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
var WHITESPACE_PLACEHOLDER = "[lingo-whitespace-placeholder]";
|
|
1600
|
-
function extractJsxContent(nodePath, replaceWhitespacePlaceholders = true) {
|
|
1601
|
-
const chunks = [];
|
|
1602
|
-
nodePath.traverse({
|
|
1603
|
-
JSXElement(path7) {
|
|
1604
|
-
if (path7.parent === nodePath.node) {
|
|
1605
|
-
const content = extractJsxContent(path7, false);
|
|
1606
|
-
const name = getJsxElementName(path7);
|
|
1607
|
-
chunks.push(`<element:${name}>${content}</element:${name}>`);
|
|
1608
|
-
path7.skip();
|
|
1609
|
-
}
|
|
1610
|
-
},
|
|
1611
|
-
JSXText(path7) {
|
|
1612
|
-
chunks.push(path7.node.value);
|
|
1613
|
-
},
|
|
1614
|
-
JSXExpressionContainer(path7) {
|
|
1615
|
-
if (path7.parent !== nodePath.node) {
|
|
1616
|
-
return;
|
|
1617
|
-
}
|
|
1618
|
-
const expr = path7.node.expression;
|
|
1619
|
-
if (t22.isCallExpression(expr)) {
|
|
1620
|
-
let key = "";
|
|
1621
|
-
if (t22.isIdentifier(expr.callee)) {
|
|
1622
|
-
key = `${expr.callee.name}`;
|
|
1623
|
-
} else if (t22.isMemberExpression(expr.callee)) {
|
|
1624
|
-
let firstCallee = expr.callee;
|
|
1625
|
-
while (t22.isMemberExpression(firstCallee) && t22.isCallExpression(firstCallee.object)) {
|
|
1626
|
-
firstCallee = firstCallee.object.callee;
|
|
1627
|
-
}
|
|
1628
|
-
let current = firstCallee;
|
|
1629
|
-
const parts = [];
|
|
1630
|
-
while (t22.isMemberExpression(current)) {
|
|
1631
|
-
if (t22.isIdentifier(current.property)) {
|
|
1632
|
-
parts.unshift(current.property.name);
|
|
1633
|
-
}
|
|
1634
|
-
current = current.object;
|
|
1635
|
-
}
|
|
1636
|
-
if (t22.isIdentifier(current)) {
|
|
1637
|
-
parts.unshift(current.name);
|
|
1638
|
-
}
|
|
1639
|
-
if (t22.isMemberExpression(firstCallee) && t22.isNewExpression(firstCallee.object) && t22.isIdentifier(firstCallee.object.callee)) {
|
|
1640
|
-
parts.unshift(firstCallee.object.callee.name);
|
|
1641
|
-
}
|
|
1642
|
-
key = parts.join(".");
|
|
1643
|
-
}
|
|
1644
|
-
chunks.push(`<function:${key}/>`);
|
|
1645
|
-
} else if (t22.isIdentifier(expr)) {
|
|
1646
|
-
chunks.push(`{${expr.name}}`);
|
|
1647
|
-
} else if (t22.isMemberExpression(expr)) {
|
|
1648
|
-
let current = expr;
|
|
1649
|
-
const parts = [];
|
|
1650
|
-
while (t22.isMemberExpression(current)) {
|
|
1651
|
-
if (t22.isIdentifier(current.property)) {
|
|
1652
|
-
if (current.computed) {
|
|
1653
|
-
parts.unshift(`[${current.property.name}]`);
|
|
1654
|
-
} else {
|
|
1655
|
-
parts.unshift(current.property.name);
|
|
1656
|
-
}
|
|
1657
|
-
}
|
|
1658
|
-
current = current.object;
|
|
1659
|
-
}
|
|
1660
|
-
if (t22.isIdentifier(current)) {
|
|
1661
|
-
parts.unshift(current.name);
|
|
1662
|
-
chunks.push(`{${parts.join(".").replaceAll(".[", "[")}}`);
|
|
1663
|
-
}
|
|
1664
|
-
} else if (isWhitespace(path7)) {
|
|
1665
|
-
chunks.push(WHITESPACE_PLACEHOLDER);
|
|
1666
|
-
} else if (isExpression2(path7)) {
|
|
1667
|
-
chunks.push("<expression/>");
|
|
1668
|
-
}
|
|
1669
|
-
path7.skip();
|
|
1670
|
-
}
|
|
1671
|
-
});
|
|
1672
|
-
const result = chunks.join("");
|
|
1673
|
-
const normalized = normalizeJsxWhitespace(result);
|
|
1674
|
-
if (replaceWhitespacePlaceholders) {
|
|
1675
|
-
return normalized.replaceAll(WHITESPACE_PLACEHOLDER, " ");
|
|
1676
|
-
}
|
|
1677
|
-
return normalized;
|
|
1678
|
-
}
|
|
1679
|
-
var compilerProps = ["data-jsx-attribute-scope", "data-jsx-scope"];
|
|
1680
|
-
function isExpression2(nodePath) {
|
|
1681
|
-
const isCompilerExpression = !_lodash2.default.isArray(nodePath.container) && t22.isJSXAttribute(nodePath.container) && t22.isJSXIdentifier(nodePath.container.name) && compilerProps.includes(nodePath.container.name.name);
|
|
1682
|
-
return !isCompilerExpression && !t22.isJSXEmptyExpression(nodePath.node.expression);
|
|
1683
|
-
}
|
|
1684
|
-
function isWhitespace(nodePath) {
|
|
1685
|
-
const expr = nodePath.node.expression;
|
|
1686
|
-
return t22.isStringLiteral(expr) && expr.value === " ";
|
|
1687
|
-
}
|
|
1688
|
-
function normalizeJsxWhitespace(input) {
|
|
1689
|
-
if (!input.includes("\n")) {
|
|
1690
|
-
const trimmed = input.trim();
|
|
1691
|
-
if (trimmed.length === 0) return "";
|
|
1692
|
-
const leadingMatch = input.match(/^\s*/);
|
|
1693
|
-
const trailingMatch = input.match(/\s*$/);
|
|
1694
|
-
const leadingSpaces = leadingMatch ? leadingMatch[0].length : 0;
|
|
1695
|
-
const trailingSpaces = trailingMatch ? trailingMatch[0].length : 0;
|
|
1696
|
-
if (leadingSpaces > 1 || trailingSpaces > 1) {
|
|
1697
|
-
return input.replace(/\s+/g, " ").trim();
|
|
1698
|
-
} else {
|
|
1699
|
-
return input.replace(/\s{2,}/g, " ");
|
|
1700
|
-
}
|
|
1701
|
-
}
|
|
1702
|
-
const lines = input.split("\n");
|
|
1703
|
-
let result = "";
|
|
1704
|
-
for (let i = 0; i < lines.length; i++) {
|
|
1705
|
-
const line = lines[i];
|
|
1706
|
-
const trimmedLine = line.trim();
|
|
1707
|
-
if (trimmedLine === "") continue;
|
|
1708
|
-
if (trimmedLine.includes(WHITESPACE_PLACEHOLDER)) {
|
|
1709
|
-
result += trimmedLine;
|
|
1710
|
-
} else if (trimmedLine.startsWith("<element:") || trimmedLine.startsWith("<function:") || trimmedLine.startsWith("{") || trimmedLine.startsWith("<expression/>")) {
|
|
1711
|
-
const shouldAddSpace = result && !result.endsWith(" ") && !result.endsWith(WHITESPACE_PLACEHOLDER) && /\w$/.test(result) && // Check if element content starts with space by looking for "> " pattern
|
|
1712
|
-
trimmedLine.includes("> ");
|
|
1713
|
-
if (shouldAddSpace) {
|
|
1714
|
-
result += " ";
|
|
1715
|
-
}
|
|
1716
|
-
result += trimmedLine;
|
|
1717
|
-
} else {
|
|
1718
|
-
if (result && !result.endsWith(" ") && !result.endsWith(WHITESPACE_PLACEHOLDER)) {
|
|
1719
|
-
result += " ";
|
|
1720
|
-
}
|
|
1721
|
-
result += trimmedLine;
|
|
1722
|
-
}
|
|
1723
|
-
}
|
|
1724
|
-
result = result.replace(/\s{2,}/g, " ");
|
|
1725
|
-
return result.trim();
|
|
1726
|
-
}
|
|
1727
|
-
|
|
1728
|
-
// src/jsx-scopes-export.ts
|
|
1729
|
-
function jsxScopesExportMutation(payload) {
|
|
1730
|
-
const scopes = collectJsxScopes(payload.ast);
|
|
1731
|
-
if (_lodash2.default.isEmpty(scopes)) {
|
|
1732
|
-
return payload;
|
|
1733
|
-
}
|
|
1734
|
-
const lcp = LCP.getInstance({
|
|
1735
|
-
sourceRoot: payload.params.sourceRoot,
|
|
1736
|
-
lingoDir: payload.params.lingoDir
|
|
1737
|
-
});
|
|
1738
|
-
for (const scope of scopes) {
|
|
1739
|
-
const scopeKey = getAstKey(scope);
|
|
1740
|
-
lcp.resetScope(payload.relativeFilePath, scopeKey);
|
|
1741
|
-
lcp.setScopeType(payload.relativeFilePath, scopeKey, "element");
|
|
1742
|
-
const hash = getJsxElementHash(scope);
|
|
1743
|
-
lcp.setScopeHash(payload.relativeFilePath, scopeKey, hash);
|
|
1744
|
-
const context = getJsxAttributeValue(scope, "data-lingo-context");
|
|
1745
|
-
lcp.setScopeContext(
|
|
1746
|
-
payload.relativeFilePath,
|
|
1747
|
-
scopeKey,
|
|
1748
|
-
String(context || "")
|
|
1749
|
-
);
|
|
1750
|
-
const skip = getJsxAttributeValue(scope, "data-lingo-skip");
|
|
1751
|
-
lcp.setScopeSkip(
|
|
1752
|
-
payload.relativeFilePath,
|
|
1753
|
-
scopeKey,
|
|
1754
|
-
Boolean(skip || false)
|
|
1755
|
-
);
|
|
1756
|
-
const attributesMap = getJsxAttributesMap(scope);
|
|
1757
|
-
const overrides = _lodash2.default.chain(attributesMap).entries().filter(
|
|
1758
|
-
([attributeKey]) => attributeKey.startsWith("data-lingo-override-")
|
|
1759
|
-
).map(([k, v]) => [k.split("data-lingo-override-")[1], v]).filter(([k]) => !!k).filter(([, v]) => !!v).fromPairs().value();
|
|
1760
|
-
lcp.setScopeOverrides(payload.relativeFilePath, scopeKey, overrides);
|
|
1761
|
-
const content = extractJsxContent(scope);
|
|
1762
|
-
lcp.setScopeContent(payload.relativeFilePath, scopeKey, content);
|
|
1763
|
-
}
|
|
1764
|
-
lcp.save();
|
|
1765
|
-
return payload;
|
|
1766
|
-
}
|
|
1767
|
-
|
|
1768
|
-
// src/lib/lcp/server.ts
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
// src/lib/lcp/api/index.ts
|
|
1772
|
-
var _groq = require('@ai-sdk/groq');
|
|
1773
|
-
var _google = require('@ai-sdk/google');
|
|
1774
|
-
var _aisdkprovider = require('@openrouter/ai-sdk-provider');
|
|
1775
|
-
var _ollamaaiprovider = require('ollama-ai-provider');
|
|
1776
|
-
var _mistral = require('@ai-sdk/mistral');
|
|
1777
|
-
var _ai = require('ai');
|
|
1778
|
-
var __sdk = require('@lingo.dev/_sdk');
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
// src/lib/lcp/api/prompt.ts
|
|
1782
|
-
var prompt_default = (args) => {
|
|
1783
|
-
return getUserSystemPrompt(args) || getBuiltInSystemPrompt(args);
|
|
1784
|
-
};
|
|
1785
|
-
function getUserSystemPrompt(args) {
|
|
1786
|
-
const userPrompt = _optionalChain([args, 'access', _38 => _38.prompt, 'optionalAccess', _39 => _39.trim, 'call', _40 => _40(), 'optionalAccess', _41 => _41.replace, 'call', _42 => _42("{SOURCE_LOCALE}", args.sourceLocale), 'optionalAccess', _43 => _43.replace, 'call', _44 => _44("{TARGET_LOCALE}", args.targetLocale)]);
|
|
1787
|
-
if (userPrompt) {
|
|
1788
|
-
console.log("\u2728 Compiler is using user-defined prompt.");
|
|
1789
|
-
return userPrompt;
|
|
1790
|
-
}
|
|
1791
|
-
return void 0;
|
|
1792
|
-
}
|
|
1793
|
-
function getBuiltInSystemPrompt(args) {
|
|
1794
|
-
return `
|
|
1795
|
-
# Identity
|
|
1796
|
-
|
|
1797
|
-
You are an advanced AI localization engine. You do state-of-the-art localization for software products.
|
|
1798
|
-
Your task is to localize pieces of data from one locale to another locale.
|
|
1799
|
-
You always consider context, cultural nuances of source and target locales, and specific localization requirements.
|
|
1800
|
-
You replicate the meaning, intent, style, tone, and purpose of the original data.
|
|
1801
|
-
|
|
1802
|
-
## Setup
|
|
1803
|
-
|
|
1804
|
-
Source language (locale code): ${args.sourceLocale}
|
|
1805
|
-
Target language (locale code): ${args.targetLocale}
|
|
1806
|
-
|
|
1807
|
-
## Guidelines
|
|
1808
|
-
|
|
1809
|
-
Follow these guidelines for translation:
|
|
1810
|
-
|
|
1811
|
-
1. Analyze the source text to understand its overall context and purpose
|
|
1812
|
-
2. Translate the meaning and intent rather than word-for-word translation
|
|
1813
|
-
3. Rephrase and restructure sentences to sound natural and fluent in the target language
|
|
1814
|
-
4. Adapt idiomatic expressions and cultural references for the target audience
|
|
1815
|
-
5. Maintain the style and tone of the source text
|
|
1816
|
-
6. You must produce valid UTF-8 encoded output
|
|
1817
|
-
7. YOU MUST ONLY PRODUCE VALID XML.
|
|
1818
|
-
|
|
1819
|
-
## Special Instructions
|
|
1820
|
-
|
|
1821
|
-
Do not localize any of these technical elements:
|
|
1822
|
-
- Variables like {variable}, {variable.key}, {data[type]}
|
|
1823
|
-
- Expressions like <expression/>
|
|
1824
|
-
- Functions like <function:value/>, <function:getDisplayName/>
|
|
1825
|
-
- Elements like <element:strong>, </element:strong>, <element:LuPlus>, </element:LuPlus>, <element:LuSparkles>, </element:LuSparkles>
|
|
1826
|
-
|
|
1827
|
-
Remember, you are a context-aware multilingual assistant helping international companies.
|
|
1828
|
-
Your goal is to perform state-of-the-art localization for software products and content.
|
|
1829
|
-
`;
|
|
1830
|
-
}
|
|
1831
|
-
|
|
1832
|
-
// src/lib/lcp/api/xml2obj.ts
|
|
1833
|
-
var _fastxmlparser = require('fast-xml-parser');
|
|
1834
|
-
|
|
1835
|
-
var TAG_OBJECT = "object";
|
|
1836
|
-
var TAG_ARRAY = "array";
|
|
1837
|
-
var TAG_VALUE = "value";
|
|
1838
|
-
function _toGenericNode(value, key) {
|
|
1839
|
-
if (_lodash2.default.isArray(value)) {
|
|
1840
|
-
const children = _lodash2.default.map(value, (item) => _toGenericNode(item));
|
|
1841
|
-
return {
|
|
1842
|
-
[TAG_ARRAY]: {
|
|
1843
|
-
...key ? { key } : {},
|
|
1844
|
-
..._groupChildren(children)
|
|
1845
|
-
}
|
|
1846
|
-
};
|
|
1847
|
-
}
|
|
1848
|
-
if (_lodash2.default.isPlainObject(value)) {
|
|
1849
|
-
const children = _lodash2.default.map(
|
|
1850
|
-
Object.entries(value),
|
|
1851
|
-
([k, v]) => _toGenericNode(v, k)
|
|
1852
|
-
);
|
|
1853
|
-
return {
|
|
1854
|
-
[TAG_OBJECT]: {
|
|
1855
|
-
...key ? { key } : {},
|
|
1856
|
-
..._groupChildren(children)
|
|
1857
|
-
}
|
|
1858
|
-
};
|
|
1859
|
-
}
|
|
1860
|
-
return {
|
|
1861
|
-
[TAG_VALUE]: {
|
|
1862
|
-
...key ? { key } : {},
|
|
1863
|
-
"#text": _nullishCoalesce(value, () => ( ""))
|
|
1864
|
-
}
|
|
1865
|
-
};
|
|
1866
|
-
}
|
|
1867
|
-
function _groupChildren(nodes) {
|
|
1868
|
-
return _lodash2.default.call(void 0, nodes).groupBy((node) => Object.keys(node)[0]).mapValues((arr) => _lodash2.default.map(arr, (n) => n[Object.keys(n)[0]])).value();
|
|
1869
|
-
}
|
|
1870
|
-
function _fromGenericNode(tag, data) {
|
|
1871
|
-
if (tag === TAG_VALUE) {
|
|
1872
|
-
if (_lodash2.default.isPlainObject(data)) {
|
|
1873
|
-
return _lodash2.default.get(data, "#text", "");
|
|
1874
|
-
}
|
|
1875
|
-
return _nullishCoalesce(data, () => ( ""));
|
|
1876
|
-
}
|
|
1877
|
-
if (tag === TAG_ARRAY) {
|
|
1878
|
-
const result = [];
|
|
1879
|
-
_lodash2.default.forEach([TAG_VALUE, TAG_OBJECT, TAG_ARRAY], (childTag) => {
|
|
1880
|
-
const childNodes = _lodash2.default.castArray(_lodash2.default.get(data, childTag, []));
|
|
1881
|
-
_lodash2.default.forEach(childNodes, (child) => {
|
|
1882
|
-
result.push(_fromGenericNode(childTag, child));
|
|
1883
|
-
});
|
|
1884
|
-
});
|
|
1885
|
-
return result;
|
|
1886
|
-
}
|
|
1887
|
-
const obj = {};
|
|
1888
|
-
_lodash2.default.forEach([TAG_VALUE, TAG_OBJECT, TAG_ARRAY], (childTag) => {
|
|
1889
|
-
const childNodes = _lodash2.default.castArray(_lodash2.default.get(data, childTag, []));
|
|
1890
|
-
_lodash2.default.forEach(childNodes, (child) => {
|
|
1891
|
-
const key = _lodash2.default.get(child, "key", "");
|
|
1892
|
-
obj[key] = _fromGenericNode(childTag, child);
|
|
1893
|
-
});
|
|
1894
|
-
});
|
|
1895
|
-
return obj;
|
|
1896
|
-
}
|
|
1897
|
-
function obj2xml(obj) {
|
|
1898
|
-
const rootNode = _toGenericNode(obj)[TAG_OBJECT];
|
|
1899
|
-
const builder = new (0, _fastxmlparser.XMLBuilder)({
|
|
1900
|
-
ignoreAttributes: false,
|
|
1901
|
-
attributeNamePrefix: "",
|
|
1902
|
-
format: true,
|
|
1903
|
-
suppressEmptyNode: true
|
|
1904
|
-
});
|
|
1905
|
-
return builder.build({ [TAG_OBJECT]: rootNode });
|
|
1906
|
-
}
|
|
1907
|
-
function xml2obj(xml) {
|
|
1908
|
-
const parser2 = new (0, _fastxmlparser.XMLParser)({
|
|
1909
|
-
ignoreAttributes: false,
|
|
1910
|
-
attributeNamePrefix: "",
|
|
1911
|
-
parseTagValue: true,
|
|
1912
|
-
parseAttributeValue: false,
|
|
1913
|
-
processEntities: true,
|
|
1914
|
-
isArray: (name) => [TAG_VALUE, TAG_ARRAY, TAG_OBJECT].includes(name)
|
|
1915
|
-
});
|
|
1916
|
-
const parsed = parser2.parse(xml);
|
|
1917
|
-
const withoutDeclaration = _lodash2.default.omit(parsed, "?xml");
|
|
1918
|
-
const rootTag = Object.keys(withoutDeclaration)[0];
|
|
1919
|
-
const rootNode = _lodash2.default.castArray(withoutDeclaration[rootTag])[0];
|
|
1920
|
-
return _fromGenericNode(rootTag, rootNode);
|
|
1921
|
-
}
|
|
1922
|
-
|
|
1923
|
-
// src/lib/lcp/api/shots.ts
|
|
1924
|
-
var shots_default = [
|
|
1925
|
-
// Shot #1
|
|
1926
|
-
[
|
|
1927
|
-
{
|
|
1928
|
-
version: 0.1,
|
|
1929
|
-
locale: "en",
|
|
1930
|
-
files: {
|
|
1931
|
-
"demo-app/my-custom-header.tsx": {
|
|
1932
|
-
entries: {
|
|
1933
|
-
"1z2x3c4v": "Dashboard",
|
|
1934
|
-
"5t6y7u8i": "Settings",
|
|
1935
|
-
"9o0p1q2r": "Logout"
|
|
1936
|
-
}
|
|
1937
|
-
},
|
|
1938
|
-
"demo-app/my-custom-footer.tsx": {
|
|
1939
|
-
entries: {
|
|
1940
|
-
"9k0l1m2n": "\xA9 2025 Lingo.dev. All rights reserved."
|
|
1941
|
-
}
|
|
1942
|
-
}
|
|
1943
|
-
}
|
|
1944
|
-
},
|
|
1945
|
-
{
|
|
1946
|
-
version: 0.1,
|
|
1947
|
-
locale: "es",
|
|
1948
|
-
files: {
|
|
1949
|
-
"demo-app/my-custom-header.tsx": {
|
|
1950
|
-
entries: {
|
|
1951
|
-
"1z2x3c4v": "Panel de control",
|
|
1952
|
-
"5t6y7u8i": "Configuraci\xF3n",
|
|
1953
|
-
"9o0p1q2r": "Cerrar sesi\xF3n"
|
|
1954
|
-
}
|
|
1955
|
-
},
|
|
1956
|
-
"demo-app/my-custom-footer.tsx": {
|
|
1957
|
-
entries: {
|
|
1958
|
-
"9k0l1m2n": "\xA9 2025 Lingo.dev. Todos los derechos reservados."
|
|
1959
|
-
}
|
|
1960
|
-
}
|
|
1961
|
-
}
|
|
1962
|
-
}
|
|
1963
|
-
]
|
|
1964
|
-
// More shots here...
|
|
1965
|
-
];
|
|
1966
|
-
|
|
1967
|
-
// src/lib/lcp/api/index.ts
|
|
1968
|
-
|
|
1969
|
-
var LCPAPI = class {
|
|
1970
|
-
static async translate(models, sourceDictionary, sourceLocale, targetLocale, prompt) {
|
|
1971
|
-
const timeLabel = `LCPAPI.translate: ${targetLocale}`;
|
|
1972
|
-
console.time(timeLabel);
|
|
1973
|
-
const chunks = this._chunkDictionary(sourceDictionary);
|
|
1974
|
-
const translatedChunks = [];
|
|
1975
|
-
for (const chunk of chunks) {
|
|
1976
|
-
const translatedChunk = await this._translateChunk(
|
|
1977
|
-
models,
|
|
1978
|
-
chunk,
|
|
1979
|
-
sourceLocale,
|
|
1980
|
-
targetLocale,
|
|
1981
|
-
prompt
|
|
1982
|
-
);
|
|
1983
|
-
translatedChunks.push(translatedChunk);
|
|
1984
|
-
}
|
|
1985
|
-
const result = this._mergeDictionaries(translatedChunks);
|
|
1986
|
-
console.timeEnd(timeLabel);
|
|
1987
|
-
return result;
|
|
1988
|
-
}
|
|
1989
|
-
static _chunkDictionary(dictionary) {
|
|
1990
|
-
const MAX_ENTRIES_PER_CHUNK = 100;
|
|
1991
|
-
const { files, ...rest } = dictionary;
|
|
1992
|
-
const chunks = [];
|
|
1993
|
-
let currentChunk = {
|
|
1994
|
-
...rest,
|
|
1995
|
-
files: {}
|
|
1996
|
-
};
|
|
1997
|
-
let currentEntryCount = 0;
|
|
1998
|
-
Object.entries(files).forEach(([fileName, file]) => {
|
|
1999
|
-
const entries = file.entries;
|
|
2000
|
-
const entryPairs = Object.entries(entries);
|
|
2001
|
-
let currentIndex = 0;
|
|
2002
|
-
while (currentIndex < entryPairs.length) {
|
|
2003
|
-
const remainingSpace = MAX_ENTRIES_PER_CHUNK - currentEntryCount;
|
|
2004
|
-
const entriesToAdd = entryPairs.slice(
|
|
2005
|
-
currentIndex,
|
|
2006
|
-
currentIndex + remainingSpace
|
|
2007
|
-
);
|
|
2008
|
-
if (entriesToAdd.length > 0) {
|
|
2009
|
-
currentChunk.files[fileName] = currentChunk.files[fileName] || {
|
|
2010
|
-
entries: {}
|
|
2011
|
-
};
|
|
2012
|
-
currentChunk.files[fileName].entries = {
|
|
2013
|
-
...currentChunk.files[fileName].entries,
|
|
2014
|
-
...Object.fromEntries(entriesToAdd)
|
|
2015
|
-
};
|
|
2016
|
-
currentEntryCount += entriesToAdd.length;
|
|
2017
|
-
}
|
|
2018
|
-
currentIndex += entriesToAdd.length;
|
|
2019
|
-
if (currentEntryCount >= MAX_ENTRIES_PER_CHUNK || currentIndex < entryPairs.length && currentEntryCount + (entryPairs.length - currentIndex) > MAX_ENTRIES_PER_CHUNK) {
|
|
2020
|
-
chunks.push(currentChunk);
|
|
2021
|
-
currentChunk = { ...rest, files: {} };
|
|
2022
|
-
currentEntryCount = 0;
|
|
2023
|
-
}
|
|
2024
|
-
}
|
|
2025
|
-
});
|
|
2026
|
-
if (currentEntryCount > 0) {
|
|
2027
|
-
chunks.push(currentChunk);
|
|
2028
|
-
}
|
|
2029
|
-
return chunks;
|
|
2030
|
-
}
|
|
2031
|
-
static _mergeDictionaries(dictionaries) {
|
|
2032
|
-
const fileNames = _lodash2.default.uniq(
|
|
2033
|
-
_lodash2.default.flatMap(dictionaries, (dict) => Object.keys(dict.files))
|
|
2034
|
-
);
|
|
2035
|
-
const files = _lodash2.default.call(void 0, fileNames).map((fileName) => {
|
|
2036
|
-
const entries = dictionaries.reduce((entries2, dict) => {
|
|
2037
|
-
const file = dict.files[fileName];
|
|
2038
|
-
if (file) {
|
|
2039
|
-
entries2 = _lodash2.default.merge(entries2, file.entries);
|
|
2040
|
-
}
|
|
2041
|
-
return entries2;
|
|
2042
|
-
}, {});
|
|
2043
|
-
return [fileName, { entries }];
|
|
2044
|
-
}).fromPairs().value();
|
|
2045
|
-
const dictionary = {
|
|
2046
|
-
version: dictionaries[0].version,
|
|
2047
|
-
locale: dictionaries[0].locale,
|
|
2048
|
-
files
|
|
2049
|
-
};
|
|
2050
|
-
return dictionary;
|
|
2051
|
-
}
|
|
2052
|
-
static _createLingoDotDevEngine() {
|
|
2053
|
-
if (isRunningInCIOrDocker()) {
|
|
2054
|
-
const apiKeyFromEnv = getLingoDotDevKeyFromEnv();
|
|
2055
|
-
if (!apiKeyFromEnv) {
|
|
2056
|
-
this._failMissingLLMKeyCi("lingo.dev");
|
|
2057
|
-
}
|
|
2058
|
-
}
|
|
2059
|
-
const apiKey = getLingoDotDevKey();
|
|
2060
|
-
if (!apiKey) {
|
|
2061
|
-
throw new Error(
|
|
2062
|
-
"\u26A0\uFE0F Lingo.dev API key not found. Please set LINGODOTDEV_API_KEY environment variable or configure it user-wide."
|
|
2063
|
-
);
|
|
2064
|
-
}
|
|
2065
|
-
console.log(`Creating Lingo.dev client`);
|
|
2066
|
-
return new (0, __sdk.LingoDotDevEngine)({
|
|
2067
|
-
apiKey
|
|
2068
|
-
});
|
|
2069
|
-
}
|
|
2070
|
-
static async _translateChunk(models, sourceDictionary, sourceLocale, targetLocale, prompt) {
|
|
2071
|
-
if (models === "lingo.dev") {
|
|
2072
|
-
try {
|
|
2073
|
-
const lingoDotDevEngine = this._createLingoDotDevEngine();
|
|
2074
|
-
console.log(
|
|
2075
|
-
`\u2728 Using Lingo.dev Engine to localize from "${sourceLocale}" to "${targetLocale}"`
|
|
2076
|
-
);
|
|
2077
|
-
const result = await lingoDotDevEngine.localizeObject(
|
|
2078
|
-
sourceDictionary,
|
|
2079
|
-
{
|
|
2080
|
-
sourceLocale,
|
|
2081
|
-
targetLocale
|
|
2082
|
-
}
|
|
2083
|
-
);
|
|
2084
|
-
return result;
|
|
2085
|
-
} catch (error) {
|
|
2086
|
-
this._failLLMFailureLocal(
|
|
2087
|
-
"lingo.dev",
|
|
2088
|
-
targetLocale,
|
|
2089
|
-
error instanceof Error ? error.message : "Unknown error"
|
|
2090
|
-
);
|
|
2091
|
-
throw error;
|
|
2092
|
-
}
|
|
2093
|
-
} else {
|
|
2094
|
-
const { provider, model } = getLocaleModel(
|
|
2095
|
-
models,
|
|
2096
|
-
sourceLocale,
|
|
2097
|
-
targetLocale
|
|
2098
|
-
);
|
|
2099
|
-
if (!provider || !model) {
|
|
2100
|
-
throw new Error(
|
|
2101
|
-
_dedent2.default`
|
|
2102
|
-
🚫 Lingo.dev Localization Engine Not Configured!
|
|
2103
|
-
|
|
2104
|
-
The "models" parameter is missing or incomplete in your Lingo.dev configuration.
|
|
2105
|
-
|
|
2106
|
-
👉 To fix this, set the "models" parameter to either:
|
|
2107
|
-
• "lingo.dev" (for the default engine)
|
|
2108
|
-
• a map of locale-to-model, e.g. { "models": { "en:es": "openai:gpt-3.5-turbo" } }
|
|
2109
|
-
|
|
2110
|
-
Example:
|
|
2111
|
-
{
|
|
2112
|
-
// ...
|
|
2113
|
-
"models": "lingo.dev"
|
|
2114
|
-
}
|
|
2115
|
-
|
|
2116
|
-
For more details, see: https://lingo.dev/compiler
|
|
2117
|
-
To get help, join our Discord: https://lingo.dev/go/discord
|
|
2118
|
-
`
|
|
2119
|
-
);
|
|
2120
|
-
}
|
|
2121
|
-
try {
|
|
2122
|
-
const aiModel = this._createAiModel(provider, model, targetLocale);
|
|
2123
|
-
console.log(
|
|
2124
|
-
`\u2139\uFE0F Using raw LLM API ("${provider}":"${model}") to translate from "${sourceLocale}" to "${targetLocale}"`
|
|
2125
|
-
);
|
|
2126
|
-
const response = await _ai.generateText.call(void 0, {
|
|
2127
|
-
model: aiModel,
|
|
2128
|
-
messages: [
|
|
2129
|
-
{
|
|
2130
|
-
role: "system",
|
|
2131
|
-
content: prompt_default({
|
|
2132
|
-
sourceLocale,
|
|
2133
|
-
targetLocale,
|
|
2134
|
-
prompt: _nullishCoalesce(prompt, () => ( void 0))
|
|
2135
|
-
})
|
|
2136
|
-
},
|
|
2137
|
-
...shots_default.flatMap((shotsTuple) => [
|
|
2138
|
-
{
|
|
2139
|
-
role: "user",
|
|
2140
|
-
content: obj2xml(shotsTuple[0])
|
|
2141
|
-
},
|
|
2142
|
-
{
|
|
2143
|
-
role: "assistant",
|
|
2144
|
-
content: obj2xml(shotsTuple[1])
|
|
2145
|
-
}
|
|
2146
|
-
]),
|
|
2147
|
-
{
|
|
2148
|
-
role: "user",
|
|
2149
|
-
content: obj2xml(sourceDictionary)
|
|
2150
|
-
}
|
|
2151
|
-
]
|
|
2152
|
-
});
|
|
2153
|
-
console.log("Response text received for", targetLocale);
|
|
2154
|
-
let responseText = response.text;
|
|
2155
|
-
responseText = responseText.substring(
|
|
2156
|
-
responseText.indexOf("<"),
|
|
2157
|
-
responseText.lastIndexOf(">") + 1
|
|
2158
|
-
);
|
|
2159
|
-
return xml2obj(responseText);
|
|
2160
|
-
} catch (error) {
|
|
2161
|
-
this._failLLMFailureLocal(
|
|
2162
|
-
provider,
|
|
2163
|
-
targetLocale,
|
|
2164
|
-
error instanceof Error ? error.message : "Unknown error"
|
|
2165
|
-
);
|
|
2166
|
-
throw error;
|
|
2167
|
-
}
|
|
2168
|
-
}
|
|
2169
|
-
}
|
|
2170
|
-
/**
|
|
2171
|
-
* Instantiates an AI model based on provider and model ID.
|
|
2172
|
-
* Includes CI/CD API key checks.
|
|
2173
|
-
* @param providerId The ID of the AI provider (e.g., "groq", "google").
|
|
2174
|
-
* @param modelId The ID of the specific model (e.g., "llama3-8b-8192", "gemini-2.0-flash").
|
|
2175
|
-
* @param targetLocale The target locale being translated to (for logging/error messages).
|
|
2176
|
-
* @returns An instantiated AI LanguageModel.
|
|
2177
|
-
* @throws Error if the provider is not supported or API key is missing in CI/CD.
|
|
2178
|
-
*/
|
|
2179
|
-
static _createAiModel(providerId, modelId, targetLocale) {
|
|
2180
|
-
switch (providerId) {
|
|
2181
|
-
case "groq": {
|
|
2182
|
-
if (isRunningInCIOrDocker()) {
|
|
2183
|
-
const groqFromEnv = getGroqKeyFromEnv();
|
|
2184
|
-
if (!groqFromEnv) {
|
|
2185
|
-
this._failMissingLLMKeyCi(providerId);
|
|
2186
|
-
}
|
|
2187
|
-
}
|
|
2188
|
-
const groqKey = getGroqKey();
|
|
2189
|
-
if (!groqKey) {
|
|
2190
|
-
throw new Error(
|
|
2191
|
-
"\u26A0\uFE0F GROQ API key not found. Please set GROQ_API_KEY environment variable or configure it user-wide."
|
|
2192
|
-
);
|
|
2193
|
-
}
|
|
2194
|
-
console.log(
|
|
2195
|
-
`Creating Groq client for ${targetLocale} using model ${modelId}`
|
|
2196
|
-
);
|
|
2197
|
-
return _groq.createGroq.call(void 0, { apiKey: groqKey })(modelId);
|
|
2198
|
-
}
|
|
2199
|
-
case "google": {
|
|
2200
|
-
if (isRunningInCIOrDocker()) {
|
|
2201
|
-
const googleFromEnv = getGoogleKeyFromEnv();
|
|
2202
|
-
if (!googleFromEnv) {
|
|
2203
|
-
this._failMissingLLMKeyCi(providerId);
|
|
2204
|
-
}
|
|
2205
|
-
}
|
|
2206
|
-
const googleKey = getGoogleKey();
|
|
2207
|
-
if (!googleKey) {
|
|
2208
|
-
throw new Error(
|
|
2209
|
-
"\u26A0\uFE0F Google API key not found. Please set GOOGLE_API_KEY environment variable or configure it user-wide."
|
|
2210
|
-
);
|
|
2211
|
-
}
|
|
2212
|
-
console.log(
|
|
2213
|
-
`Creating Google Generative AI client for ${targetLocale} using model ${modelId}`
|
|
2214
|
-
);
|
|
2215
|
-
return _google.createGoogleGenerativeAI.call(void 0, { apiKey: googleKey })(modelId);
|
|
2216
|
-
}
|
|
2217
|
-
case "openrouter": {
|
|
2218
|
-
if (isRunningInCIOrDocker()) {
|
|
2219
|
-
const openRouterFromEnv = getOpenRouterKeyFromEnv();
|
|
2220
|
-
if (!openRouterFromEnv) {
|
|
2221
|
-
this._failMissingLLMKeyCi(providerId);
|
|
2222
|
-
}
|
|
2223
|
-
}
|
|
2224
|
-
const openRouterKey = getOpenRouterKey();
|
|
2225
|
-
if (!openRouterKey) {
|
|
2226
|
-
throw new Error(
|
|
2227
|
-
"\u26A0\uFE0F OpenRouter API key not found. Please set OPENROUTER_API_KEY environment variable or configure it user-wide."
|
|
2228
|
-
);
|
|
2229
|
-
}
|
|
2230
|
-
console.log(
|
|
2231
|
-
`Creating OpenRouter client for ${targetLocale} using model ${modelId}`
|
|
2232
|
-
);
|
|
2233
|
-
return _aisdkprovider.createOpenRouter.call(void 0, {
|
|
2234
|
-
apiKey: openRouterKey
|
|
2235
|
-
})(modelId);
|
|
2236
|
-
}
|
|
2237
|
-
case "ollama": {
|
|
2238
|
-
console.log(
|
|
2239
|
-
`Creating Ollama client for ${targetLocale} using model ${modelId} at default Ollama address`
|
|
2240
|
-
);
|
|
2241
|
-
return _ollamaaiprovider.createOllama.call(void 0, )(modelId);
|
|
2242
|
-
}
|
|
2243
|
-
case "mistral": {
|
|
2244
|
-
if (isRunningInCIOrDocker()) {
|
|
2245
|
-
const mistralFromEnv = getMistralKeyFromEnv();
|
|
2246
|
-
if (!mistralFromEnv) {
|
|
2247
|
-
this._failMissingLLMKeyCi(providerId);
|
|
2248
|
-
}
|
|
2249
|
-
}
|
|
2250
|
-
const mistralKey = getMistralKey();
|
|
2251
|
-
if (!mistralKey) {
|
|
2252
|
-
throw new Error(
|
|
2253
|
-
"\u26A0\uFE0F Mistral API key not found. Please set MISTRAL_API_KEY environment variable or configure it user-wide."
|
|
2254
|
-
);
|
|
2255
|
-
}
|
|
2256
|
-
console.log(
|
|
2257
|
-
`Creating Mistral client for ${targetLocale} using model ${modelId}`
|
|
2258
|
-
);
|
|
2259
|
-
return _mistral.createMistral.call(void 0, { apiKey: mistralKey })(modelId);
|
|
2260
|
-
}
|
|
2261
|
-
default: {
|
|
2262
|
-
throw new Error(
|
|
2263
|
-
`\u26A0\uFE0F Provider "${providerId}" for locale "${targetLocale}" is not supported. Only "groq", "google", "openrouter", "ollama", and "mistral" providers are supported at the moment.`
|
|
2264
|
-
);
|
|
2265
|
-
}
|
|
2266
|
-
}
|
|
2267
|
-
}
|
|
2268
|
-
/**
|
|
2269
|
-
* Show an actionable error message and exit the process when the compiler
|
|
2270
|
-
* is running in CI/CD without a required LLM API key.
|
|
2271
|
-
* The message explains why this situation is unusual and how to fix it.
|
|
2272
|
-
* @param providerId The ID of the LLM provider whose key is missing.
|
|
2273
|
-
*/
|
|
2274
|
-
static _failMissingLLMKeyCi(providerId) {
|
|
2275
|
-
let details = providerDetails[providerId];
|
|
2276
|
-
if (!details) {
|
|
2277
|
-
throw new Error(
|
|
2278
|
-
`Internal Error: Missing details for provider "${providerId}" when reporting missing key in CI/CD. You might be using an unsupported provider.`
|
|
2279
|
-
);
|
|
2280
|
-
}
|
|
2281
|
-
const errorMessage = _dedent2.default`
|
|
2282
|
-
💡 You're using Lingo.dev Localization Compiler, and it detected unlocalized components in your app.
|
|
2283
|
-
|
|
2284
|
-
The compiler needs a ${details.name} API key to translate missing strings, but ${details.apiKeyEnvVar} is not set in the environment.
|
|
2285
|
-
|
|
2286
|
-
This is unexpected: typically you run a full build locally, commit the generated translation files, and push them to CI/CD.
|
|
2287
|
-
|
|
2288
|
-
However, If you want CI/CD to translate the new strings, provide the key with:
|
|
2289
|
-
• Session-wide: export ${details.apiKeyEnvVar}=<your-api-key>
|
|
2290
|
-
• Project-wide / CI: add ${details.apiKeyEnvVar}=<your-api-key> to your pipeline environment variables
|
|
2291
|
-
|
|
2292
|
-
⭐️ Also:
|
|
2293
|
-
1. If you don't yet have a ${details.name} API key, get one for free at ${details.getKeyLink}
|
|
2294
|
-
2. If you want to use a different LLM, update your configuration. Refer to documentation for help: https://lingo.dev/compiler
|
|
2295
|
-
3. If the model you want to use isn't supported yet, raise an issue in our open-source repo: https://lingo.dev/go/gh
|
|
2296
|
-
`;
|
|
2297
|
-
console.log(errorMessage);
|
|
2298
|
-
throw new Error(`Missing ${details.name} API key in CI/CD environment.`);
|
|
2299
|
-
}
|
|
2300
|
-
/**
|
|
2301
|
-
* Show an actionable error message and exit the process when an LLM API call
|
|
2302
|
-
* fails during local compilation.
|
|
2303
|
-
* @param providerId The ID of the LLM provider that failed.
|
|
2304
|
-
* @param targetLocale The target locale being translated to.
|
|
2305
|
-
* @param errorMessage The error message received from the API.
|
|
2306
|
-
*/
|
|
2307
|
-
static _failLLMFailureLocal(providerId, targetLocale, errorMessage) {
|
|
2308
|
-
const details = providerDetails[providerId];
|
|
2309
|
-
if (!details) {
|
|
2310
|
-
throw new Error(
|
|
2311
|
-
`Internal Error: Missing details for provider "${providerId}" when reporting local failure. Original Error: ${errorMessage}`
|
|
2312
|
-
);
|
|
2313
|
-
}
|
|
2314
|
-
const isInvalidApiKey = errorMessage.match("Invalid API Key");
|
|
2315
|
-
if (isInvalidApiKey) {
|
|
2316
|
-
const message = _dedent2.default`
|
|
2317
|
-
⚠️ Lingo.dev Compiler requires a valid ${details.name} API key to translate your application.
|
|
2318
|
-
|
|
2319
|
-
It looks like you set ${details.name} API key but it is not valid. Please check your API key and try again.
|
|
2320
|
-
|
|
2321
|
-
Error details from ${details.name} API: ${errorMessage}
|
|
2322
|
-
|
|
2323
|
-
👉 You can set the API key in one of the following ways:
|
|
2324
|
-
1. User-wide: Run npx lingo.dev@latest config set ${details.apiKeyConfigKey} <your-api-key>
|
|
2325
|
-
2. Project-wide: Add ${details.apiKeyEnvVar}=<your-api-key> to .env file in every project that uses Lingo.dev Localization Compiler
|
|
2326
|
-
3 Session-wide: Run export ${details.apiKeyEnvVar}=<your-api-key> in your terminal before running the compiler to set the API key for the current session
|
|
2327
|
-
|
|
2328
|
-
⭐️ Also:
|
|
2329
|
-
1. If you don't yet have a ${details.name} API key, get one for free at ${details.getKeyLink}
|
|
2330
|
-
2. If you want to use a different LLM, raise an issue in our open-source repo: https://lingo.dev/go/gh
|
|
2331
|
-
3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
|
|
2332
|
-
`;
|
|
2333
|
-
console.log(message);
|
|
2334
|
-
throw new Error(`Invalid ${details.name} API key.`);
|
|
2335
|
-
} else {
|
|
2336
|
-
const message = _dedent2.default`
|
|
2337
|
-
⚠️ Lingo.dev Compiler tried to translate your application to "${targetLocale}" locale via ${details.name} but it failed.
|
|
2338
|
-
|
|
2339
|
-
Error details from ${details.name} API: ${errorMessage}
|
|
2340
|
-
|
|
2341
|
-
This error comes from the ${details.name} API, please check their documentation for more details: ${details.docsLink}
|
|
2342
|
-
|
|
2343
|
-
⭐️ Also:
|
|
2344
|
-
1. Did you set ${details.apiKeyEnvVar ? `${details.apiKeyEnvVar}` : "the provider API key"} environment variable correctly ${!details.apiKeyEnvVar ? "(if required)" : ""}?
|
|
2345
|
-
2. Did you reach any limits of your ${details.name} account?
|
|
2346
|
-
3. If you have questions, feature requests, or would like to contribute, join our Discord: https://lingo.dev/go/discord
|
|
2347
|
-
`;
|
|
2348
|
-
console.log(message);
|
|
2349
|
-
throw new Error(
|
|
2350
|
-
`Translation failed for locale "${targetLocale}" using ${details.name}: ${errorMessage}`
|
|
2351
|
-
);
|
|
2352
|
-
}
|
|
2353
|
-
}
|
|
2354
|
-
};
|
|
2355
|
-
|
|
2356
|
-
// src/lib/lcp/server.ts
|
|
2357
|
-
var LCPServer = (_class = class {
|
|
2358
|
-
static __initStatic() {this.inFlightPromise = null}
|
|
2359
|
-
static async loadDictionaries(params) {
|
|
2360
|
-
if (this.inFlightPromise) {
|
|
2361
|
-
return this.inFlightPromise;
|
|
2362
|
-
}
|
|
2363
|
-
this.inFlightPromise = (async () => {
|
|
2364
|
-
try {
|
|
2365
|
-
const targetLocales = _lodash2.default.uniq([
|
|
2366
|
-
...params.targetLocales,
|
|
2367
|
-
params.sourceLocale
|
|
2368
|
-
]);
|
|
2369
|
-
const dictionaries = await Promise.all(
|
|
2370
|
-
targetLocales.map(
|
|
2371
|
-
(targetLocale) => this.loadDictionaryForLocale({ ...params, targetLocale })
|
|
2372
|
-
)
|
|
2373
|
-
);
|
|
2374
|
-
const result = _lodash2.default.fromPairs(
|
|
2375
|
-
targetLocales.map((targetLocale, index) => [
|
|
2376
|
-
targetLocale,
|
|
2377
|
-
dictionaries[index]
|
|
2378
|
-
])
|
|
2379
|
-
);
|
|
2380
|
-
return result;
|
|
2381
|
-
} finally {
|
|
2382
|
-
this.inFlightPromise = null;
|
|
2383
|
-
}
|
|
2384
|
-
})();
|
|
2385
|
-
return this.inFlightPromise;
|
|
2386
|
-
}
|
|
2387
|
-
static async loadDictionaryForLocale(params) {
|
|
2388
|
-
const sourceDictionary = this._extractSourceDictionary(
|
|
2389
|
-
params.lcp,
|
|
2390
|
-
params.sourceLocale,
|
|
2391
|
-
params.targetLocale
|
|
2392
|
-
);
|
|
2393
|
-
const cacheParams = {
|
|
2394
|
-
lcp: params.lcp,
|
|
2395
|
-
sourceLocale: params.sourceLocale,
|
|
2396
|
-
lingoDir: params.lingoDir,
|
|
2397
|
-
sourceRoot: params.sourceRoot
|
|
2398
|
-
};
|
|
2399
|
-
if (this._countDictionaryEntries(sourceDictionary) === 0) {
|
|
2400
|
-
console.log(
|
|
2401
|
-
"Source dictionary is empty, returning empty dictionary for target locale"
|
|
2402
|
-
);
|
|
2403
|
-
return { ...sourceDictionary, locale: params.targetLocale };
|
|
2404
|
-
}
|
|
2405
|
-
const cache = LCPCache.readLocaleDictionary(
|
|
2406
|
-
params.targetLocale,
|
|
2407
|
-
cacheParams
|
|
2408
|
-
);
|
|
2409
|
-
const uncachedSourceDictionary = this._getDictionaryDiff(
|
|
2410
|
-
sourceDictionary,
|
|
2411
|
-
cache
|
|
2412
|
-
);
|
|
2413
|
-
let targetDictionary;
|
|
2414
|
-
let newTranslations;
|
|
2415
|
-
if (this._countDictionaryEntries(uncachedSourceDictionary) === 0) {
|
|
2416
|
-
targetDictionary = cache;
|
|
2417
|
-
} else if (params.targetLocale === params.sourceLocale) {
|
|
2418
|
-
console.log(
|
|
2419
|
-
"\u2139\uFE0F Lingo.dev returns source dictionary - source and target locales are the same"
|
|
2420
|
-
);
|
|
2421
|
-
await LCPCache.writeLocaleDictionary(sourceDictionary, cacheParams);
|
|
2422
|
-
return sourceDictionary;
|
|
2423
|
-
} else {
|
|
2424
|
-
newTranslations = await LCPAPI.translate(
|
|
2425
|
-
params.models,
|
|
2426
|
-
uncachedSourceDictionary,
|
|
2427
|
-
params.sourceLocale,
|
|
2428
|
-
params.targetLocale,
|
|
2429
|
-
params.prompt
|
|
2430
|
-
);
|
|
2431
|
-
targetDictionary = this._mergeDictionaries(newTranslations, cache);
|
|
2432
|
-
targetDictionary = {
|
|
2433
|
-
...targetDictionary,
|
|
2434
|
-
locale: params.targetLocale
|
|
2435
|
-
};
|
|
2436
|
-
await LCPCache.writeLocaleDictionary(targetDictionary, cacheParams);
|
|
2437
|
-
}
|
|
2438
|
-
const targetDictionaryWithFallback = this._mergeDictionaries(
|
|
2439
|
-
targetDictionary,
|
|
2440
|
-
sourceDictionary,
|
|
2441
|
-
true
|
|
2442
|
-
);
|
|
2443
|
-
const result = this._addOverridesToDictionary(
|
|
2444
|
-
targetDictionaryWithFallback,
|
|
2445
|
-
params.lcp,
|
|
2446
|
-
params.targetLocale
|
|
2447
|
-
);
|
|
2448
|
-
if (newTranslations) {
|
|
2449
|
-
console.log(
|
|
2450
|
-
`\u2139\uFE0F Lingo.dev dictionary for ${params.targetLocale}:
|
|
2451
|
-
- %d entries
|
|
2452
|
-
- %d cached
|
|
2453
|
-
- %d uncached
|
|
2454
|
-
- %d translated
|
|
2455
|
-
- %d overrides`,
|
|
2456
|
-
this._countDictionaryEntries(result),
|
|
2457
|
-
this._countDictionaryEntries(cache),
|
|
2458
|
-
this._countDictionaryEntries(uncachedSourceDictionary),
|
|
2459
|
-
newTranslations ? this._countDictionaryEntries(newTranslations) : 0,
|
|
2460
|
-
this._countDictionaryEntries(result) - this._countDictionaryEntries(targetDictionary)
|
|
2461
|
-
);
|
|
2462
|
-
}
|
|
2463
|
-
return result;
|
|
2464
|
-
}
|
|
2465
|
-
static _extractSourceDictionary(lcp, sourceLocale, targetLocale) {
|
|
2466
|
-
const dictionary = {
|
|
2467
|
-
version: 0.1,
|
|
2468
|
-
locale: sourceLocale,
|
|
2469
|
-
files: {}
|
|
2470
|
-
};
|
|
2471
|
-
for (const [fileKey, fileData] of Object.entries(lcp.files || {})) {
|
|
2472
|
-
for (const [scopeKey, scopeData] of Object.entries(
|
|
2473
|
-
fileData.scopes || {}
|
|
2474
|
-
)) {
|
|
2475
|
-
if (scopeData.skip) {
|
|
2476
|
-
continue;
|
|
2477
|
-
}
|
|
2478
|
-
if (this._getScopeLocaleOverride(scopeData, targetLocale)) {
|
|
2479
|
-
continue;
|
|
2480
|
-
}
|
|
2481
|
-
_lodash2.default.set(
|
|
2482
|
-
dictionary,
|
|
2483
|
-
[
|
|
2484
|
-
"files",
|
|
2485
|
-
fileKey,
|
|
2486
|
-
"entries",
|
|
2487
|
-
scopeKey
|
|
2488
|
-
],
|
|
2489
|
-
scopeData.content
|
|
2490
|
-
);
|
|
2491
|
-
}
|
|
2492
|
-
}
|
|
2493
|
-
return dictionary;
|
|
2494
|
-
}
|
|
2495
|
-
static _addOverridesToDictionary(dictionary, lcp, targetLocale) {
|
|
2496
|
-
for (const [fileKey, fileData] of Object.entries(lcp.files || {})) {
|
|
2497
|
-
for (const [scopeKey, scopeData] of Object.entries(
|
|
2498
|
-
fileData.scopes || {}
|
|
2499
|
-
)) {
|
|
2500
|
-
const override = this._getScopeLocaleOverride(scopeData, targetLocale);
|
|
2501
|
-
if (!override) {
|
|
2502
|
-
continue;
|
|
2503
|
-
}
|
|
2504
|
-
_lodash2.default.set(
|
|
2505
|
-
dictionary,
|
|
2506
|
-
[
|
|
2507
|
-
"files",
|
|
2508
|
-
fileKey,
|
|
2509
|
-
"entries",
|
|
2510
|
-
scopeKey
|
|
2511
|
-
],
|
|
2512
|
-
override
|
|
2513
|
-
);
|
|
2514
|
-
}
|
|
2515
|
-
}
|
|
2516
|
-
return dictionary;
|
|
2517
|
-
}
|
|
2518
|
-
static _getScopeLocaleOverride(scopeData, locale) {
|
|
2519
|
-
return _nullishCoalesce(_lodash2.default.get(scopeData.overrides, locale), () => ( null));
|
|
2520
|
-
}
|
|
2521
|
-
static _getDictionaryDiff(sourceDictionary, targetDictionary) {
|
|
2522
|
-
if (this._countDictionaryEntries(targetDictionary) === 0) {
|
|
2523
|
-
return sourceDictionary;
|
|
2524
|
-
}
|
|
2525
|
-
const files = _lodash2.default.call(void 0, sourceDictionary.files).mapValues((file, fileName) => ({
|
|
2526
|
-
...file,
|
|
2527
|
-
entries: _lodash2.default.call(void 0, file.entries).mapValues((entry, entryName) => {
|
|
2528
|
-
const targetEntry = _lodash2.default.get(targetDictionary.files, [
|
|
2529
|
-
fileName,
|
|
2530
|
-
"entries",
|
|
2531
|
-
entryName
|
|
2532
|
-
]);
|
|
2533
|
-
if (targetEntry !== void 0) {
|
|
2534
|
-
return void 0;
|
|
2535
|
-
}
|
|
2536
|
-
return entry;
|
|
2537
|
-
}).pickBy((value) => value !== void 0).value()
|
|
2538
|
-
})).pickBy((value) => Object.keys(value.entries).length > 0).value();
|
|
2539
|
-
const dictionary = {
|
|
2540
|
-
version: sourceDictionary.version,
|
|
2541
|
-
locale: sourceDictionary.locale,
|
|
2542
|
-
files
|
|
2543
|
-
};
|
|
2544
|
-
return dictionary;
|
|
2545
|
-
}
|
|
2546
|
-
static _mergeDictionaries(sourceDictionary, targetDictionary, removeEmptyEntries = false) {
|
|
2547
|
-
const fileNames = _lodash2.default.uniq([
|
|
2548
|
-
...Object.keys(sourceDictionary.files),
|
|
2549
|
-
...Object.keys(targetDictionary.files)
|
|
2550
|
-
]);
|
|
2551
|
-
const files = _lodash2.default.call(void 0, fileNames).map((fileName) => {
|
|
2552
|
-
const sourceFile = _lodash2.default.get(sourceDictionary.files, fileName);
|
|
2553
|
-
const targetFile = _lodash2.default.get(targetDictionary.files, fileName);
|
|
2554
|
-
const entries = removeEmptyEntries ? _lodash2.default.pickBy(
|
|
2555
|
-
_optionalChain([sourceFile, 'optionalAccess', _45 => _45.entries]) || {},
|
|
2556
|
-
(value) => _optionalChain([String, 'call', _46 => _46(value || ""), 'optionalAccess', _47 => _47.trim, 'optionalCall', _48 => _48(), 'optionalAccess', _49 => _49.length]) > 0
|
|
2557
|
-
) : _optionalChain([sourceFile, 'optionalAccess', _50 => _50.entries]) || {};
|
|
2558
|
-
return [
|
|
2559
|
-
fileName,
|
|
2560
|
-
{
|
|
2561
|
-
...targetFile,
|
|
2562
|
-
entries: _lodash2.default.merge({}, _optionalChain([targetFile, 'optionalAccess', _51 => _51.entries]) || {}, entries)
|
|
2563
|
-
}
|
|
2564
|
-
];
|
|
2565
|
-
}).fromPairs().value();
|
|
2566
|
-
const dictionary = {
|
|
2567
|
-
version: sourceDictionary.version,
|
|
2568
|
-
locale: sourceDictionary.locale,
|
|
2569
|
-
files
|
|
2570
|
-
};
|
|
2571
|
-
return dictionary;
|
|
2572
|
-
}
|
|
2573
|
-
static _countDictionaryEntries(dict) {
|
|
2574
|
-
return Object.values(dict.files).reduce(
|
|
2575
|
-
(sum, file) => sum + Object.keys(file.entries).length,
|
|
2576
|
-
0
|
|
2577
|
-
);
|
|
2578
|
-
}
|
|
2579
|
-
}, _class.__initStatic(), _class);
|
|
2580
|
-
|
|
2581
|
-
// src/react-router-dictionary-loader.ts
|
|
2582
|
-
|
|
2583
|
-
var reactRouterDictionaryLoaderMutation = createCodeMutation(
|
|
2584
|
-
(payload) => {
|
|
2585
|
-
const mode = getModuleExecutionMode(payload.ast, payload.params.rsc);
|
|
2586
|
-
if (mode === "server") {
|
|
2587
|
-
return payload;
|
|
2588
|
-
}
|
|
2589
|
-
const invokations = findInvokations(payload.ast, {
|
|
2590
|
-
moduleName: ModuleId.ReactRouter,
|
|
2591
|
-
functionName: "loadDictionary"
|
|
2592
|
-
});
|
|
2593
|
-
const allLocales = Array.from(
|
|
2594
|
-
/* @__PURE__ */ new Set([payload.params.sourceLocale, ...payload.params.targetLocales])
|
|
2595
|
-
);
|
|
2596
|
-
for (const invokation of invokations) {
|
|
2597
|
-
const internalDictionaryLoader = getOrCreateImport(payload.ast, {
|
|
2598
|
-
moduleName: ModuleId.ReactRouter,
|
|
2599
|
-
exportedName: "loadDictionary_internal"
|
|
2600
|
-
});
|
|
2601
|
-
if (t23.isIdentifier(invokation.callee)) {
|
|
2602
|
-
invokation.callee.name = internalDictionaryLoader.importedName;
|
|
2603
|
-
}
|
|
2604
|
-
const dictionaryPath = getDictionaryPath({
|
|
2605
|
-
sourceRoot: payload.params.sourceRoot,
|
|
2606
|
-
lingoDir: payload.params.lingoDir,
|
|
2607
|
-
relativeFilePath: payload.relativeFilePath
|
|
2608
|
-
});
|
|
2609
|
-
const localeImportMap = createLocaleImportMap(allLocales, dictionaryPath);
|
|
2610
|
-
invokation.arguments.push(localeImportMap);
|
|
2611
|
-
}
|
|
2612
|
-
return payload;
|
|
2613
|
-
}
|
|
2614
|
-
);
|
|
2615
|
-
|
|
2616
|
-
// src/rsc-dictionary-loader.ts
|
|
2617
|
-
|
|
2618
|
-
var rscDictionaryLoaderMutation = createCodeMutation((payload) => {
|
|
2619
|
-
const mode = getModuleExecutionMode(payload.ast, payload.params.rsc);
|
|
2620
|
-
if (mode === "client") {
|
|
2621
|
-
return payload;
|
|
2622
|
-
}
|
|
2623
|
-
const invokations = findInvokations(payload.ast, {
|
|
2624
|
-
moduleName: ModuleId.ReactRSC,
|
|
2625
|
-
functionName: "loadDictionary"
|
|
2626
|
-
});
|
|
2627
|
-
const allLocales = Array.from(
|
|
2628
|
-
/* @__PURE__ */ new Set([payload.params.sourceLocale, ...payload.params.targetLocales])
|
|
2629
|
-
);
|
|
2630
|
-
for (const invokation of invokations) {
|
|
2631
|
-
const internalDictionaryLoader = getOrCreateImport(payload.ast, {
|
|
2632
|
-
moduleName: ModuleId.ReactRSC,
|
|
2633
|
-
exportedName: "loadDictionary_internal"
|
|
2634
|
-
});
|
|
2635
|
-
if (t24.isIdentifier(invokation.callee)) {
|
|
2636
|
-
invokation.callee.name = internalDictionaryLoader.importedName;
|
|
2637
|
-
}
|
|
2638
|
-
const dictionaryPath = getDictionaryPath({
|
|
2639
|
-
sourceRoot: payload.params.sourceRoot,
|
|
2640
|
-
lingoDir: payload.params.lingoDir,
|
|
2641
|
-
relativeFilePath: payload.relativeFilePath
|
|
2642
|
-
});
|
|
2643
|
-
const localeImportMap = createLocaleImportMap(allLocales, dictionaryPath);
|
|
2644
|
-
invokation.arguments.push(localeImportMap);
|
|
2645
|
-
}
|
|
2646
|
-
return payload;
|
|
2647
|
-
});
|
|
2648
|
-
|
|
2649
|
-
// src/utils/module-params.ts
|
|
2650
|
-
function parseParametrizedModuleId(rawId) {
|
|
2651
|
-
const moduleUri = new URL(rawId, "module://");
|
|
2652
|
-
return {
|
|
2653
|
-
id: moduleUri.pathname.replace(/^\//, ""),
|
|
2654
|
-
params: Object.fromEntries(moduleUri.searchParams.entries())
|
|
2655
|
-
};
|
|
2656
|
-
}
|
|
2657
|
-
|
|
2658
|
-
// src/_loader-utils.ts
|
|
2659
|
-
async function loadDictionary(options) {
|
|
2660
|
-
const {
|
|
2661
|
-
resourcePath,
|
|
2662
|
-
resourceQuery = "",
|
|
2663
|
-
params,
|
|
2664
|
-
sourceRoot,
|
|
2665
|
-
lingoDir,
|
|
2666
|
-
isDev
|
|
2667
|
-
} = options;
|
|
2668
|
-
const fullResourcePath = `${resourcePath}${resourceQuery}`;
|
|
2669
|
-
if (!resourcePath.match(LCP_DICTIONARY_FILE_NAME)) {
|
|
2670
|
-
return null;
|
|
2671
|
-
}
|
|
2672
|
-
const moduleInfo = parseParametrizedModuleId(fullResourcePath);
|
|
2673
|
-
const locale = moduleInfo.params.locale;
|
|
2674
|
-
if (!locale) {
|
|
2675
|
-
return null;
|
|
2676
|
-
}
|
|
2677
|
-
const lcpParams = {
|
|
2678
|
-
sourceRoot,
|
|
2679
|
-
lingoDir,
|
|
2680
|
-
isDev
|
|
2681
|
-
};
|
|
2682
|
-
await LCP.ready(lcpParams);
|
|
2683
|
-
const lcp = LCP.getInstance(lcpParams);
|
|
2684
|
-
const dictionaries = await LCPServer.loadDictionaries({
|
|
2685
|
-
...params,
|
|
2686
|
-
lcp: lcp.data
|
|
2687
|
-
});
|
|
2688
|
-
const dictionary = dictionaries[locale];
|
|
2689
|
-
if (!dictionary) {
|
|
2690
|
-
throw new Error(
|
|
2691
|
-
`Lingo.dev: Dictionary for locale "${locale}" could not be generated.`
|
|
2692
|
-
);
|
|
2693
|
-
}
|
|
2694
|
-
return dictionary;
|
|
2695
|
-
}
|
|
2696
|
-
function transformComponent(options) {
|
|
2697
|
-
const { code, params, resourcePath, sourceRoot } = options;
|
|
2698
|
-
return _lodash2.default.chain({
|
|
2699
|
-
code,
|
|
2700
|
-
params,
|
|
2701
|
-
relativeFilePath: path.default.relative(path.default.resolve(process.cwd(), sourceRoot), resourcePath).split(path.default.sep).join("/")
|
|
2702
|
-
// Always normalize for consistent dictionaries
|
|
2703
|
-
}).thru(createPayload).thru(
|
|
2704
|
-
composeMutations(
|
|
2705
|
-
i18n_directive_default,
|
|
2706
|
-
jsxFragmentMutation,
|
|
2707
|
-
jsx_attribute_flag_default,
|
|
2708
|
-
jsx_provider_default,
|
|
2709
|
-
jsxHtmlLangMutation,
|
|
2710
|
-
jsx_root_flag_default,
|
|
2711
|
-
jsx_scope_flag_default,
|
|
2712
|
-
jsxAttributeScopesExportMutation,
|
|
2713
|
-
jsxScopesExportMutation,
|
|
2714
|
-
lingoJsxAttributeScopeInjectMutation,
|
|
2715
|
-
lingoJsxScopeInjectMutation,
|
|
2716
|
-
rscDictionaryLoaderMutation,
|
|
2717
|
-
reactRouterDictionaryLoaderMutation,
|
|
2718
|
-
jsxRemoveAttributesMutation,
|
|
2719
|
-
clientDictionaryLoaderMutation
|
|
2720
|
-
)
|
|
2721
|
-
).thru(createOutput).value();
|
|
2722
|
-
}
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
exports.__require = __require; exports.defaultParams = defaultParams; exports.LCP_DICTIONARY_FILE_NAME = LCP_DICTIONARY_FILE_NAME; exports.LCPCache = LCPCache; exports.getInvalidLocales = getInvalidLocales; exports.getRc = getRc; exports.getGroqKeyFromRc = getGroqKeyFromRc; exports.getGroqKeyFromEnv = getGroqKeyFromEnv; exports.getLingoDotDevKeyFromEnv = getLingoDotDevKeyFromEnv; exports.getLingoDotDevKeyFromRc = getLingoDotDevKeyFromRc; exports.getGoogleKeyFromRc = getGoogleKeyFromRc; exports.getGoogleKeyFromEnv = getGoogleKeyFromEnv; exports.getMistralKeyFromRc = getMistralKeyFromRc; exports.getMistralKeyFromEnv = getMistralKeyFromEnv; exports.isRunningInCIOrDocker = isRunningInCIOrDocker; exports.providerDetails = providerDetails; exports.loadDictionary = loadDictionary; exports.transformComponent = transformComponent;
|