@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.
@@ -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 en_us.blue_moon_bottle(inputs)
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;AAavE,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,UAY1E;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,CAgIxB"}
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
- // First convert to safe module ID
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
- processedBundleCodes,
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
- // Check if this module ID has already been used
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 { ${uniqueModuleId} } from "./${fallbackLocale}.js"`;
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 ${uniqueModuleId} = () => '${bundleId}'`;
34
+ file += `\n/** @type {(inputs: ${inputsType(inputs)}) => string} */ */\nexport const ${bundleModuleId} = () => '${bundleId}'`;
101
35
  }
102
36
  continue;
103
37
  }
104
- file += `\n\nexport const ${uniqueModuleId} = ${compiledMessage.code}`;
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,CAyFxB"}
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 safeBundleId = toSafeModuleId(compiledBundle.bundle.node.id);
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
- let filename = `messages/${safeBundleId}.js`;
16
- let counter = 0;
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}_${safeBundleId} = ${compiledMessage.code}`);
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}_${safeBundleId} = ${safeFallbackLocale}_${safeBundleId};`);
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}_${safeBundleId} = () => '${escapeForSingleQuoteString(bundleId)}'`);
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/happyelephant1.js");
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,CAYjD;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAElD"}
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
- return result;
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("helloworld__");
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("helloworld");
8
+ expect(toSafeModuleId("HelloWorld")).toBe("helloworld2");
9
9
  });
10
10
  test('escapes "-" to "_"', () => {
11
- expect(toSafeModuleId("de-DE-bavaria")).toBe("de_de_bavaria");
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
+ });
@@ -1,5 +1,5 @@
1
1
  export const ENV_VARIABLES = {
2
2
  PARJS_APP_ID: "library.inlang.paraglideJs",
3
3
  PARJS_POSTHOG_TOKEN: "phc_m5yJZCxjOGxF8CJvP5sQ3H0d76xpnLrsmiZHduT4jDz",
4
- PARJS_PACKAGE_VERSION: "2.0.7",
4
+ PARJS_PACKAGE_VERSION: "2.0.8",
5
5
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@inlang/paraglide-js",
3
3
  "type": "module",
4
- "version": "2.0.7",
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/plugin-message-format": "4.0.0",
53
+ "@inlang/paraglide-js": "2.0.8",
54
54
  "@opral/tsconfig": "1.1.0",
55
- "@inlang/paraglide-js": "2.0.7"
55
+ "@inlang/plugin-message-format": "4.0.0"
56
56
  },
57
57
  "keywords": [
58
58
  "inlang",