@inlang/paraglide-js 2.0.6 → 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.
@@ -1 +1 @@
1
- {"version":3,"file":"unplugin.d.ts","sourceRoot":"","sources":["../../src/bundler-plugins/unplugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAMhD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAavE,eAAO,MAAM,eAAe,EAAE,eAAe,CAAC,eAAe,CAmG3D,CAAC"}
1
+ {"version":3,"file":"unplugin.d.ts","sourceRoot":"","sources":["../../src/bundler-plugins/unplugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAMhD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAavE,eAAO,MAAM,eAAe,EAAE,eAAe,CAAC,eAAe,CAyH3D,CAAC"}
@@ -14,11 +14,16 @@ export const unpluginFactory = (args) => ({
14
14
  name: PLUGIN_NAME,
15
15
  enforce: "pre",
16
16
  async buildStart() {
17
- logger.info("Compiling inlang project...");
17
+ const isProduction = process.env.NODE_ENV === "production";
18
+ // default to locale-modules for development to speed up the dev server
19
+ // https://github.com/opral/inlang-paraglide-js/issues/486
20
+ const outputStructure = args.outputStructure ??
21
+ (isProduction ? "message-modules" : "locale-modules");
18
22
  try {
19
23
  previousCompilation = await compile({
20
24
  fs: wrappedFs,
21
25
  previousCompilation,
26
+ outputStructure,
22
27
  // webpack invokes the `buildStart` api in watch mode,
23
28
  // to avoid cleaning the output directory in watch mode,
24
29
  // we only clean the output directory if there was no previous compilation
@@ -26,7 +31,7 @@ export const unpluginFactory = (args) => ({
26
31
  isServer,
27
32
  ...args,
28
33
  });
29
- logger.success("Compilation complete");
34
+ logger.success(`Compilation complete (${outputStructure})`);
30
35
  }
31
36
  catch (error) {
32
37
  logger.error("Failed to compile project:", error.message);
@@ -44,6 +49,11 @@ export const unpluginFactory = (args) => ({
44
49
  if (shouldCompile === false) {
45
50
  return;
46
51
  }
52
+ const isProduction = process.env.NODE_ENV === "production";
53
+ // default to locale-modules for development to speed up the dev server
54
+ // https://github.com/opral/inlang-paraglide-js/issues/486
55
+ const outputStructure = args.outputStructure ??
56
+ (isProduction ? "message-modules" : "locale-modules");
47
57
  const previouslyReadFiles = new Set(readFiles);
48
58
  try {
49
59
  logger.info(`Re-compiling inlang project... File "${relative(process.cwd(), path)}" has changed.`);
@@ -52,11 +62,12 @@ export const unpluginFactory = (args) => ({
52
62
  previousCompilation = await compile({
53
63
  fs: wrappedFs,
54
64
  previousCompilation,
65
+ outputStructure,
55
66
  cleanOutdir: false,
56
67
  isServer,
57
68
  ...args,
58
69
  });
59
- logger.success("Re-compilation complete");
70
+ logger.success(`Re-compilation complete (${outputStructure})`);
60
71
  // Add any new files to watch
61
72
  for (const filePath of Array.from(readFiles)) {
62
73
  this.addWatchFile(filePath);
@@ -86,17 +97,23 @@ export const unpluginFactory = (args) => ({
86
97
  },
87
98
  };
88
99
  compiler.hooks.beforeRun.tapPromise(PLUGIN_NAME, async () => {
100
+ const isProduction = process.env.NODE_ENV === "production";
101
+ // default to locale-modules for development to speed up the dev server
102
+ // https://github.com/opral/inlang-paraglide-js/issues/486
103
+ const outputStructure = args.outputStructure ??
104
+ (isProduction ? "message-modules" : "locale-modules");
89
105
  try {
90
106
  previousCompilation = await compile({
91
107
  fs: wrappedFs,
92
108
  previousCompilation,
109
+ outputStructure,
93
110
  // clean dir needs to be false. otherwise webpack get's into a race condition
94
111
  // of deleting the output directory and writing files at the same time for
95
112
  // multi environment builds
96
113
  cleanOutdir: false,
97
114
  ...args,
98
115
  });
99
- logger.success("Compilation complete");
116
+ logger.success(`Compilation complete (${outputStructure})`);
100
117
  }
101
118
  catch (error) {
102
119
  logger.warn("Failed to compile project:", error.message);
@@ -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" },
@@ -182,6 +182,10 @@ export type CompilerOptions = {
182
182
  * - `message-modules` - Each module is a message. This is the default.
183
183
  * - `locale-modules` - Each module is a locale.
184
184
  *
185
+ * It is recommended to use `locale-modules` for development and `message-modules` for production.
186
+ * Bundlers speed up the dev mode by bypassing bundling which can lead to many http requests
187
+ * during the dev mode with `message-modules`. See https://github.com/opral/inlang-paraglide-js/issues/486.
188
+ *
185
189
  * **`message-modules`**
186
190
  *
187
191
  * Messages have their own module which eases tree-shaking for bundlers.
@@ -1 +1 @@
1
- {"version":3,"file":"compiler-options.d.ts","sourceRoot":"","sources":["../../src/compiler/compiler-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;CAaU,CAAC;AAE9C,MAAM,MAAM,eAAe,GAAG;IAC7B;;;;;;;;;;OAUG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;;;;;OAUG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/B;;;;;;;;;;;;;;OAcG;IACH,qCAAqC,CAAC,EAAE,OAAO,CAAC;IAChD;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC;;;;;;;;;;;;OAYG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IACrC;;;;OAIG;IACH,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC;;;;;;;;;OASG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC;;;;;;;;;;;;OAYG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6CG;IACH,eAAe,CAAC,EAAE,gBAAgB,GAAG,iBAAiB,CAAC;IACvD;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;;OAIG;IACH,EAAE,CAAC,EAAE,GAAG,CAAC;CACT,CAAC"}
1
+ {"version":3,"file":"compiler-options.d.ts","sourceRoot":"","sources":["../../src/compiler/compiler-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;CAaU,CAAC;AAE9C,MAAM,MAAM,eAAe,GAAG;IAC7B;;;;;;;;;;OAUG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB;;;;;;;;;;OAUG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/B;;;;;;;;;;;;;;OAcG;IACH,qCAAqC,CAAC,EAAE,OAAO,CAAC;IAChD;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC;;;;;;;;;;;;OAYG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IACrC;;;;OAIG;IACH,2BAA2B,CAAC,EAAE,OAAO,CAAC;IACtC;;;;;;;;;OASG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC;;;;;;;;;;;;OAYG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiDG;IACH,eAAe,CAAC,EAAE,gBAAgB,GAAG,iBAAiB,CAAC;IACvD;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;;OAIG;IACH,EAAE,CAAC,EAAE,GAAG,CAAC;CACT,CAAC"}
@@ -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.6",
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.6",
4
+ "version": "2.0.8",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
7
7
  "access": "public",
@@ -32,7 +32,7 @@
32
32
  "unplugin": "^2.1.2",
33
33
  "urlpattern-polyfill": "^10.0.0",
34
34
  "@inlang/recommend-sherlock": "0.2.1",
35
- "@inlang/sdk": "2.4.5"
35
+ "@inlang/sdk": "2.4.6"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@eslint/js": "^9.18.0",
@@ -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",
54
- "@inlang/paraglide-js": "2.0.6",
55
- "@opral/tsconfig": "1.1.0"
53
+ "@inlang/paraglide-js": "2.0.8",
54
+ "@opral/tsconfig": "1.1.0",
55
+ "@inlang/plugin-message-format": "4.0.0"
56
56
  },
57
57
  "keywords": [
58
58
  "inlang",