@inlang/paraglide-js 2.0.7 → 2.0.8
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/dist/compiler/compile-bundle.test.js +1 -1
- package/dist/compiler/compile-project.test.js +1 -4
- package/dist/compiler/output-structure/locale-modules.d.ts.map +1 -1
- package/dist/compiler/output-structure/locale-modules.js +6 -72
- package/dist/compiler/output-structure/locale-modules.test.js +1 -0
- package/dist/compiler/output-structure/message-modules.d.ts.map +1 -1
- package/dist/compiler/output-structure/message-modules.js +6 -12
- package/dist/compiler/output-structure/message-modules.test.js +1 -1
- package/dist/compiler/safe-module-id.d.ts.map +1 -1
- package/dist/compiler/safe-module-id.js +7 -1
- package/dist/compiler/safe-module-id.test.js +8 -3
- package/dist/services/env-variables/index.js +1 -1
- package/package.json +3 -3
|
@@ -56,7 +56,7 @@ export const blue_moon_bottle = (inputs, options = {}) => {
|
|
|
56
56
|
const locale = options.locale ?? getLocale()
|
|
57
57
|
trackMessageCall("blue_moon_bottle", locale)
|
|
58
58
|
if (locale === "en") return en.blue_moon_bottle(inputs)
|
|
59
|
-
if (locale === "en-US") return
|
|
59
|
+
if (locale === "en-US") return en_us2.blue_moon_bottle(inputs)
|
|
60
60
|
return "blue_moon_bottle"
|
|
61
61
|
};"`);
|
|
62
62
|
});
|
|
@@ -264,6 +264,7 @@ describe.each([
|
|
|
264
264
|
});
|
|
265
265
|
test("should return the correct message for the current locale", async () => {
|
|
266
266
|
const { m, runtime } = await importCode(code);
|
|
267
|
+
console.log(m);
|
|
267
268
|
runtime.setLocale("en");
|
|
268
269
|
expect(m.sad_penguin_bundle()).toBe("A simple message.");
|
|
269
270
|
runtime.setLocale("de");
|
|
@@ -571,10 +572,6 @@ describe.each([
|
|
|
571
572
|
});
|
|
572
573
|
});
|
|
573
574
|
test("case sensitivity handling for bundle IDs", async () => {
|
|
574
|
-
// skip local modules for now because the option might get removed in the future
|
|
575
|
-
if (compilerOptions.outputStructure === "locale-modules") {
|
|
576
|
-
return;
|
|
577
|
-
}
|
|
578
575
|
const project = await loadProjectInMemory({
|
|
579
576
|
blob: await newProject({
|
|
580
577
|
settings: { locales: ["en"], baseLocale: "en" },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locale-modules.d.ts","sourceRoot":"","sources":["../../../src/compiler/output-structure/locale-modules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"locale-modules.d.ts","sourceRoot":"","sources":["../../../src/compiler/output-structure/locale-modules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAIvE,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,UAE1E;AAED,wBAAgB,cAAc,CAC7B,eAAe,EAAE,0BAA0B,EAAE,EAC7C,QAAQ,EAAE,IAAI,CAAC,eAAe,EAAE,SAAS,GAAG,YAAY,CAAC,EACzD,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAC7C,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAoDxB"}
|
|
@@ -1,66 +1,15 @@
|
|
|
1
1
|
import { toSafeModuleId } from "../safe-module-id.js";
|
|
2
2
|
import { inputsType } from "../jsdoc-types.js";
|
|
3
|
-
// Helper function to escape special characters in a string for use in a regular expression
|
|
4
|
-
function escapeRegExp(string) {
|
|
5
|
-
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6
|
-
}
|
|
7
|
-
// This map will be used to track which bundle IDs have been renamed to which unique IDs
|
|
8
|
-
// It will be populated during the generateOutput function and used in messageReferenceExpression
|
|
9
|
-
const bundleIdToUniqueIdMap = new Map();
|
|
10
3
|
export function messageReferenceExpression(locale, bundleId) {
|
|
11
|
-
|
|
12
|
-
const safeModuleId = toSafeModuleId(bundleId);
|
|
13
|
-
// Check if this bundleId has been mapped to a unique identifier
|
|
14
|
-
const uniqueId = bundleIdToUniqueIdMap.get(bundleId);
|
|
15
|
-
if (uniqueId) {
|
|
16
|
-
return `${toSafeModuleId(locale)}.${uniqueId}`;
|
|
17
|
-
}
|
|
18
|
-
// Otherwise, return the default safe module ID
|
|
19
|
-
return `${toSafeModuleId(locale)}.${safeModuleId}`;
|
|
4
|
+
return `${toSafeModuleId(locale)}.${toSafeModuleId(bundleId)}`;
|
|
20
5
|
}
|
|
21
6
|
export function generateOutput(compiledBundles, settings, fallbackMap) {
|
|
22
|
-
// Create a map to track module IDs in the index file to avoid duplicates
|
|
23
|
-
const indexModuleIdMap = new Map();
|
|
24
|
-
// Process the bundles to ensure no duplicate bundle IDs
|
|
25
|
-
// Generate unique moduleIds for duplicate IDs
|
|
26
|
-
const processedBundleCodes = compiledBundles
|
|
27
|
-
.map(({ bundle }) => {
|
|
28
|
-
const bundleId = bundle.node.id;
|
|
29
|
-
const bundleModuleId = toSafeModuleId(bundleId);
|
|
30
|
-
// Check if this safe module ID has been used before
|
|
31
|
-
if (indexModuleIdMap.has(bundleModuleId)) {
|
|
32
|
-
// Create a unique identifier by adding a counter
|
|
33
|
-
let counter = 1;
|
|
34
|
-
let uniqueModuleId = `${bundleModuleId}${counter}`;
|
|
35
|
-
while (indexModuleIdMap.has(uniqueModuleId)) {
|
|
36
|
-
counter++;
|
|
37
|
-
uniqueModuleId = `${bundleModuleId}${counter}`;
|
|
38
|
-
}
|
|
39
|
-
// Modify the code to use the unique identifier
|
|
40
|
-
const modifiedCode = bundle.code
|
|
41
|
-
.replace(new RegExp(`const ${bundleModuleId} =`, "g"), `const ${uniqueModuleId} =`)
|
|
42
|
-
.replace(new RegExp(`export const ${bundleModuleId} =`, "g"), `export const ${uniqueModuleId} =`)
|
|
43
|
-
.replace(new RegExp(`export { ${bundleModuleId}`, "g"), `export { ${uniqueModuleId}`)
|
|
44
|
-
.replace(
|
|
45
|
-
// Also update the trackMessageCall to use the new identifier
|
|
46
|
-
new RegExp(`trackMessageCall\\("${escapeRegExp(bundleId)}"`, "g"), `trackMessageCall("${bundleId}"`);
|
|
47
|
-
// Store the unique ID mapping
|
|
48
|
-
indexModuleIdMap.set(uniqueModuleId, bundleId);
|
|
49
|
-
// Also store in the global map for messageReferenceExpression to use
|
|
50
|
-
bundleIdToUniqueIdMap.set(bundleId, uniqueModuleId);
|
|
51
|
-
return modifiedCode;
|
|
52
|
-
}
|
|
53
|
-
// Store the mapping
|
|
54
|
-
indexModuleIdMap.set(bundleModuleId, bundleId);
|
|
55
|
-
return bundle.code;
|
|
56
|
-
})
|
|
57
|
-
.join("\n");
|
|
58
7
|
const indexFile = [
|
|
59
8
|
`import { getLocale, trackMessageCall, experimentalMiddlewareLocaleSplitting, isServer } from "../runtime.js"`,
|
|
60
9
|
settings.locales
|
|
61
10
|
.map((locale) => `import * as ${toSafeModuleId(locale)} from "./${locale}.js"`)
|
|
62
11
|
.join("\n"),
|
|
63
|
-
|
|
12
|
+
compiledBundles.map(({ bundle }) => bundle.code).join("\n"),
|
|
64
13
|
].join("\n");
|
|
65
14
|
const output = {
|
|
66
15
|
["messages/_index.js"]: indexFile,
|
|
@@ -69,39 +18,24 @@ export function generateOutput(compiledBundles, settings, fallbackMap) {
|
|
|
69
18
|
for (const locale of settings.locales) {
|
|
70
19
|
const filename = `messages/${locale}.js`;
|
|
71
20
|
let file = "";
|
|
72
|
-
// Keep track of module IDs to avoid duplicates
|
|
73
|
-
const moduleIdMap = new Map();
|
|
74
21
|
for (const compiledBundle of compiledBundles) {
|
|
75
22
|
const compiledMessage = compiledBundle.messages[locale];
|
|
76
|
-
const bundleId = compiledBundle.bundle.node.id;
|
|
77
23
|
const bundleModuleId = toSafeModuleId(compiledBundle.bundle.node.id);
|
|
78
|
-
|
|
79
|
-
let uniqueModuleId = bundleModuleId;
|
|
80
|
-
if (moduleIdMap.has(bundleModuleId)) {
|
|
81
|
-
// If it has, create a unique ID by adding an index
|
|
82
|
-
let counter = 1;
|
|
83
|
-
uniqueModuleId = `${bundleModuleId}${counter}`;
|
|
84
|
-
while (moduleIdMap.has(uniqueModuleId)) {
|
|
85
|
-
counter++;
|
|
86
|
-
uniqueModuleId = `${bundleModuleId}${counter}`;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
// Store this module ID
|
|
90
|
-
moduleIdMap.set(uniqueModuleId, bundleId);
|
|
24
|
+
const bundleId = compiledBundle.bundle.node.id;
|
|
91
25
|
const inputs = compiledBundle.bundle.node.declarations?.filter((decl) => decl.type === "input-variable") ?? [];
|
|
92
26
|
if (!compiledMessage) {
|
|
93
27
|
const fallbackLocale = fallbackMap[locale];
|
|
94
28
|
if (fallbackLocale) {
|
|
95
29
|
// use the fall back locale e.g. render the message in English if the German message is missing
|
|
96
|
-
file += `\nexport { ${
|
|
30
|
+
file += `\nexport { ${bundleModuleId} } from "./${fallbackLocale}.js"`;
|
|
97
31
|
}
|
|
98
32
|
else {
|
|
99
33
|
// no fallback exists, render the bundleId
|
|
100
|
-
file += `\n/** @type {(inputs: ${inputsType(inputs)}) => string} */\nexport const ${
|
|
34
|
+
file += `\n/** @type {(inputs: ${inputsType(inputs)}) => string} */ */\nexport const ${bundleModuleId} = () => '${bundleId}'`;
|
|
101
35
|
}
|
|
102
36
|
continue;
|
|
103
37
|
}
|
|
104
|
-
file += `\n\nexport const ${
|
|
38
|
+
file += `\n\nexport const ${bundleModuleId} = ${compiledMessage.code}`;
|
|
105
39
|
}
|
|
106
40
|
// add import if used
|
|
107
41
|
if (file.includes("registry.")) {
|
|
@@ -97,6 +97,7 @@ test("should handle case sensitivity in message IDs correctly", () => {
|
|
|
97
97
|
const fallbackMap = {};
|
|
98
98
|
const output = generateOutput(bundles, settings, fallbackMap);
|
|
99
99
|
// Check that the output exists
|
|
100
|
+
expect(output).toHaveProperty("messages/_index.js");
|
|
100
101
|
expect(output).toHaveProperty("messages/en.js");
|
|
101
102
|
// The exported constants should not conflict
|
|
102
103
|
const content = output["messages/en.js"];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"message-modules.d.ts","sourceRoot":"","sources":["../../../src/compiler/output-structure/message-modules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAKvE,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,UAE1E;AAED,wBAAgB,cAAc,CAC7B,eAAe,EAAE,0BAA0B,EAAE,EAC7C,QAAQ,EAAE,IAAI,CAAC,eAAe,EAAE,SAAS,GAAG,YAAY,CAAC,EACzD,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAC7C,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"message-modules.d.ts","sourceRoot":"","sources":["../../../src/compiler/output-structure/message-modules.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAKvE,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,UAE1E;AAED,wBAAgB,cAAc,CAC7B,eAAe,EAAE,0BAA0B,EAAE,EAC7C,QAAQ,EAAE,IAAI,CAAC,eAAe,EAAE,SAAS,GAAG,YAAY,CAAC,EACzD,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAC7C,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAkFxB"}
|
|
@@ -9,17 +9,11 @@ export function generateOutput(compiledBundles, settings, fallbackMap) {
|
|
|
9
9
|
const moduleFilenames = new Set();
|
|
10
10
|
for (const compiledBundle of compiledBundles) {
|
|
11
11
|
const bundleId = compiledBundle.bundle.node.id;
|
|
12
|
-
const
|
|
12
|
+
const safeModuleId = toSafeModuleId(compiledBundle.bundle.node.id);
|
|
13
13
|
const inputs = compiledBundle.bundle.node.declarations?.filter((decl) => decl.type === "input-variable") ?? [];
|
|
14
14
|
// bundle file
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
while (output[filename]) {
|
|
18
|
-
// bundle file already exists, need to append to it
|
|
19
|
-
counter += 1;
|
|
20
|
-
filename = `messages/${safeBundleId}${counter}.js`;
|
|
21
|
-
}
|
|
22
|
-
moduleFilenames.add(`${safeBundleId}${counter ? counter : ""}.js`);
|
|
15
|
+
const filename = `messages/${safeModuleId}.js`;
|
|
16
|
+
moduleFilenames.add(`${safeModuleId}.js`);
|
|
23
17
|
// create fresh bundle file
|
|
24
18
|
output[filename] = compiledBundle.bundle.code;
|
|
25
19
|
const needsFallback = [];
|
|
@@ -32,7 +26,7 @@ export function generateOutput(compiledBundles, settings, fallbackMap) {
|
|
|
32
26
|
needsFallback.push(locale);
|
|
33
27
|
}
|
|
34
28
|
else {
|
|
35
|
-
messages.push(`const ${safeLocale}_${
|
|
29
|
+
messages.push(`const ${safeLocale}_${safeModuleId} = ${compiledMessage.code}`);
|
|
36
30
|
}
|
|
37
31
|
}
|
|
38
32
|
// add the fallbacks (needs to be done after the messages to avoid referencing
|
|
@@ -44,11 +38,11 @@ export function generateOutput(compiledBundles, settings, fallbackMap) {
|
|
|
44
38
|
if (fallbackLocale) {
|
|
45
39
|
const safeFallbackLocale = toSafeModuleId(fallbackLocale);
|
|
46
40
|
// take the fallback locale
|
|
47
|
-
messages.push(`/** @type {(inputs: ${inputsType(inputs)}) => string} */\nconst ${safeLocale}_${
|
|
41
|
+
messages.push(`/** @type {(inputs: ${inputsType(inputs)}) => string} */\nconst ${safeLocale}_${safeModuleId} = ${safeFallbackLocale}_${safeModuleId};`);
|
|
48
42
|
}
|
|
49
43
|
else {
|
|
50
44
|
// fallback to just the bundle id
|
|
51
|
-
messages.push(`/** @type {(inputs: ${inputsType(inputs)}) => string} */\nconst ${safeLocale}_${
|
|
45
|
+
messages.push(`/** @type {(inputs: ${inputsType(inputs)}) => string} */\nconst ${safeLocale}_${safeModuleId} = () => '${escapeForSingleQuoteString(bundleId)}'`);
|
|
52
46
|
}
|
|
53
47
|
}
|
|
54
48
|
output[filename] = messages.join("\n\n") + "\n\n" + output[filename];
|
|
@@ -72,6 +72,6 @@ test("handles case senstivity by creating directories and files only in lowercas
|
|
|
72
72
|
const output = generateOutput(resources, settings, {});
|
|
73
73
|
// expecting only lowercase directories and files
|
|
74
74
|
expect(output).toHaveProperty("messages/happyelephant.js");
|
|
75
|
-
expect(output).toHaveProperty("messages/
|
|
75
|
+
expect(output).toHaveProperty("messages/happyelephant2.js");
|
|
76
76
|
expect(output).not.toHaveProperty("messages/HappyElephant.js");
|
|
77
77
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"safe-module-id.d.ts","sourceRoot":"","sources":["../../src/compiler/safe-module-id.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"safe-module-id.d.ts","sourceRoot":"","sources":["../../src/compiler/safe-module-id.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAmBjD;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAElD"}
|
|
@@ -12,7 +12,13 @@ export function toSafeModuleId(id) {
|
|
|
12
12
|
else if (reservedJsKeywords.includes(result)) {
|
|
13
13
|
return "_" + result;
|
|
14
14
|
}
|
|
15
|
-
|
|
15
|
+
let numUppercase = 0;
|
|
16
|
+
for (const char of id) {
|
|
17
|
+
if (char.match(/[A-Z]/)) {
|
|
18
|
+
numUppercase++;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return result + (numUppercase > 0 ? `${numUppercase}` : "");
|
|
16
22
|
}
|
|
17
23
|
export function isSafeModuleId(id) {
|
|
18
24
|
return toSafeModuleId(id) === id;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { test, expect } from "vitest";
|
|
2
2
|
import { toSafeModuleId } from "./safe-module-id.js";
|
|
3
3
|
test("handles emojis (because why not)", () => {
|
|
4
|
-
expect(toSafeModuleId("helloWorld🍌")).toBe("
|
|
4
|
+
expect(toSafeModuleId("helloWorld🍌")).toBe("helloworld__1");
|
|
5
5
|
});
|
|
6
6
|
// https://github.com/opral/inlang-paraglide-js/issues/395
|
|
7
7
|
test("makes everything lowercase", () => {
|
|
8
|
-
expect(toSafeModuleId("HelloWorld")).toBe("
|
|
8
|
+
expect(toSafeModuleId("HelloWorld")).toBe("helloworld2");
|
|
9
9
|
});
|
|
10
10
|
test('escapes "-" to "_"', () => {
|
|
11
|
-
expect(toSafeModuleId("de-DE-bavaria")).toBe("
|
|
11
|
+
expect(toSafeModuleId("de-DE-bavaria")).toBe("de_de_bavaria2");
|
|
12
12
|
});
|
|
13
13
|
test("prefixes with _ if it starts with a number", () => {
|
|
14
14
|
expect(toSafeModuleId("123")).toBe("_123");
|
|
@@ -28,3 +28,8 @@ test("transforms js reserved keywords", async () => {
|
|
|
28
28
|
// https://github.com/opral/inlang-paraglide-js/issues/331
|
|
29
29
|
expect(toSafeModuleId("then")).toBe("_then");
|
|
30
30
|
});
|
|
31
|
+
test("adds an uppercase counter for de-duplication", async () => {
|
|
32
|
+
expect(toSafeModuleId("helloworld")).toBe("helloworld");
|
|
33
|
+
expect(toSafeModuleId("helloWorld")).toBe("helloworld1");
|
|
34
|
+
expect(toSafeModuleId("HelloWorld")).toBe("helloworld2");
|
|
35
|
+
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inlang/paraglide-js",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.0.
|
|
4
|
+
"version": "2.0.8",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public",
|
|
@@ -50,9 +50,9 @@
|
|
|
50
50
|
"typescript": "^5.7.3",
|
|
51
51
|
"typescript-eslint": "^8.20.0",
|
|
52
52
|
"vitest": "2.1.8",
|
|
53
|
-
"@inlang/
|
|
53
|
+
"@inlang/paraglide-js": "2.0.8",
|
|
54
54
|
"@opral/tsconfig": "1.1.0",
|
|
55
|
-
"@inlang/
|
|
55
|
+
"@inlang/plugin-message-format": "4.0.0"
|
|
56
56
|
},
|
|
57
57
|
"keywords": [
|
|
58
58
|
"inlang",
|