@inlang/paraglide-js 2.0.0-beta.20 → 2.0.0-beta.21
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/bundler-plugins/rollup.d.ts +1 -1
- package/dist/bundler-plugins/rollup.d.ts.map +1 -1
- package/dist/bundler-plugins/unplugin.d.ts.map +1 -1
- package/dist/bundler-plugins/unplugin.js +10 -17
- package/dist/compiler/compile-bundle.d.ts.map +1 -1
- package/dist/compiler/compile-bundle.js +9 -21
- package/dist/compiler/compile-bundle.test.js +62 -39
- package/dist/compiler/compile-message.d.ts.map +1 -1
- package/dist/compiler/compile-message.js +5 -2
- package/dist/compiler/compile-message.test.js +23 -0
- package/dist/compiler/compile-project.test.js +26 -0
- package/dist/compiler/compile.d.ts +6 -3
- package/dist/compiler/compile.d.ts.map +1 -1
- package/dist/compiler/compile.js +6 -2
- package/dist/compiler/compile.test.js +6 -2
- package/dist/compiler/compiler-options.d.ts +1 -1
- package/dist/compiler/compiler-options.js +1 -1
- package/dist/compiler/output-structure/locale-modules.d.ts.map +1 -1
- package/dist/compiler/output-structure/locale-modules.js +6 -5
- package/dist/compiler/output-structure/message-modules.d.ts.map +1 -1
- package/dist/compiler/output-structure/message-modules.js +37 -24
- package/dist/compiler/output-structure/message-modules.test.js +48 -0
- package/dist/compiler/runtime/create-runtime.d.ts.map +1 -1
- package/dist/compiler/runtime/create-runtime.js +6 -3
- package/dist/compiler/runtime/extract-locale-from-url.d.ts +2 -2
- package/dist/compiler/runtime/extract-locale-from-url.d.ts.map +1 -1
- package/dist/compiler/runtime/extract-locale-from-url.js +24 -2
- package/dist/compiler/runtime/extract-locale-from-url.test.js +12 -0
- package/dist/compiler/runtime/localize-href.d.ts +63 -27
- package/dist/compiler/runtime/localize-href.d.ts.map +1 -1
- package/dist/compiler/runtime/localize-href.js +64 -38
- package/dist/compiler/runtime/localize-url.d.ts +80 -8
- package/dist/compiler/runtime/localize-url.d.ts.map +1 -1
- package/dist/compiler/runtime/localize-url.js +146 -16
- package/dist/compiler/runtime/localize-url.test.js +84 -0
- package/dist/compiler/runtime/server-middleware.d.ts +1 -3
- package/dist/compiler/runtime/server-middleware.d.ts.map +1 -1
- package/dist/compiler/runtime/server-middleware.js +1 -3
- package/dist/compiler/runtime/variables.d.ts +1 -0
- package/dist/compiler/runtime/variables.d.ts.map +1 -1
- package/dist/compiler/runtime/variables.js +1 -0
- package/dist/compiler/safe-module-id.d.ts +8 -0
- package/dist/compiler/safe-module-id.d.ts.map +1 -0
- package/dist/compiler/safe-module-id.js +71 -0
- package/dist/compiler/safe-module-id.test.d.ts +2 -0
- package/dist/compiler/safe-module-id.test.d.ts.map +1 -0
- package/dist/compiler/safe-module-id.test.js +27 -0
- package/dist/services/env-variables/index.js +1 -1
- package/dist/services/file-handling/write-output.d.ts +1 -1
- package/dist/services/file-handling/write-output.d.ts.map +1 -1
- package/dist/services/file-handling/write-output.js +1 -1
- package/dist/services/file-handling/write-output.test.js +2 -1
- package/package.json +3 -3
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const paraglideRollupPlugin: (options: import("../index.js").CompilerOptions) => import("
|
|
1
|
+
export declare const paraglideRollupPlugin: (options: import("../index.js").CompilerOptions) => import("rollup").Plugin<any> | import("rollup").Plugin<any>[];
|
|
2
2
|
//# sourceMappingURL=rollup.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rollup.d.ts","sourceRoot":"","sources":["../../src/bundler-plugins/rollup.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,qBAAqB,
|
|
1
|
+
{"version":3,"file":"rollup.d.ts","sourceRoot":"","sources":["../../src/bundler-plugins/rollup.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,qBAAqB,mHAAsC,CAAC"}
|
|
@@ -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;
|
|
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;AAQvE,eAAO,MAAM,eAAe,EAAE,eAAe,CAAC,eAAe,CAiF3D,CAAC"}
|
|
@@ -5,23 +5,16 @@ import { nodeNormalizePath } from "../utilities/node-normalize-path.js";
|
|
|
5
5
|
import { Logger } from "../services/logger/index.js";
|
|
6
6
|
const PLUGIN_NAME = "unplugin-paraglide-js";
|
|
7
7
|
const logger = new Logger();
|
|
8
|
-
let
|
|
9
|
-
// https://github.com/opral/inlang-paraglide-js/issues/371
|
|
10
|
-
//
|
|
11
|
-
// has the second benefit that paraglide js only compiles once
|
|
12
|
-
// per enviornment build (browser, server, etc.)
|
|
13
|
-
let hasInitiallyCompiled = false;
|
|
8
|
+
let previousCompilation;
|
|
14
9
|
export const unpluginFactory = (args) => ({
|
|
15
10
|
name: PLUGIN_NAME,
|
|
16
11
|
enforce: "pre",
|
|
17
12
|
async buildStart() {
|
|
18
|
-
if (hasInitiallyCompiled === true) {
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
13
|
logger.info("Compiling inlang project...");
|
|
22
14
|
try {
|
|
23
|
-
|
|
15
|
+
previousCompilation = await compile({
|
|
24
16
|
fs: wrappedFs,
|
|
17
|
+
previousCompilation,
|
|
25
18
|
...args,
|
|
26
19
|
});
|
|
27
20
|
logger.success("Compilation complete");
|
|
@@ -35,7 +28,6 @@ export const unpluginFactory = (args) => ({
|
|
|
35
28
|
for (const path of Array.from(readFiles)) {
|
|
36
29
|
this.addWatchFile(path);
|
|
37
30
|
}
|
|
38
|
-
hasInitiallyCompiled = true;
|
|
39
31
|
}
|
|
40
32
|
},
|
|
41
33
|
async watchChange(path) {
|
|
@@ -48,10 +40,11 @@ export const unpluginFactory = (args) => ({
|
|
|
48
40
|
logger.info(`Re-compiling inlang project... File "${relative(process.cwd(), path)}" has changed.`);
|
|
49
41
|
// Clear readFiles to track fresh file reads
|
|
50
42
|
readFiles.clear();
|
|
51
|
-
|
|
43
|
+
previousCompilation = await compile({
|
|
52
44
|
fs: wrappedFs,
|
|
45
|
+
previousCompilation,
|
|
53
46
|
...args,
|
|
54
|
-
}
|
|
47
|
+
});
|
|
55
48
|
logger.success("Compilation complete");
|
|
56
49
|
// Add any new files to watch
|
|
57
50
|
for (const filePath of Array.from(readFiles)) {
|
|
@@ -61,7 +54,7 @@ export const unpluginFactory = (args) => ({
|
|
|
61
54
|
catch (e) {
|
|
62
55
|
readFiles = previouslyReadFiles;
|
|
63
56
|
// Reset compilation result on error
|
|
64
|
-
|
|
57
|
+
previousCompilation = undefined;
|
|
65
58
|
logger.warn("Failed to re-compile project:", e.message);
|
|
66
59
|
}
|
|
67
60
|
},
|
|
@@ -74,14 +67,14 @@ export const unpluginFactory = (args) => ({
|
|
|
74
67
|
async_hooks: false,
|
|
75
68
|
},
|
|
76
69
|
};
|
|
77
|
-
//we need the compiler to run before the build so that the message-modules will be present
|
|
78
|
-
//In the other bundlers `buildStart` already runs before the build. In webpack it's a race condition
|
|
79
70
|
compiler.hooks.beforeRun.tapPromise(PLUGIN_NAME, async () => {
|
|
80
71
|
try {
|
|
81
|
-
await compile({
|
|
72
|
+
previousCompilation = await compile({
|
|
82
73
|
fs: wrappedFs,
|
|
74
|
+
previousCompilation,
|
|
83
75
|
...args,
|
|
84
76
|
});
|
|
77
|
+
logger.success("Compilation complete");
|
|
85
78
|
}
|
|
86
79
|
catch (error) {
|
|
87
80
|
logger.warn("Failed to compile project:", error.message);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compile-bundle.d.ts","sourceRoot":"","sources":["../../src/compiler/compile-bundle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"compile-bundle.d.ts","sourceRoot":"","sources":["../../src/compiler/compile-bundle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAK3C,MAAM,MAAM,0BAA0B,GAAG;IACxC,kDAAkD;IAClD,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IACzB,gDAAgD;IAChD,QAAQ,EAAE;QACT,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;KACpC,CAAC;CACF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,SAAU;IACnC,MAAM,EAAE,YAAY,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;CAChD,KAAG,0BAyBH,CAAC"}
|
|
@@ -1,21 +1,12 @@
|
|
|
1
1
|
import { compileMessage } from "./compile-message.js";
|
|
2
|
-
import { jsIdentifier } from "../services/codegen/identifier.js";
|
|
3
|
-
import { isValidJSIdentifier } from "../services/valid-js-identifier/index.js";
|
|
4
|
-
import { escapeForDoubleQuoteString } from "../services/codegen/escape.js";
|
|
5
2
|
import { jsDocBundleFunctionTypes } from "./jsdoc-types.js";
|
|
6
|
-
import {
|
|
3
|
+
import { toSafeModuleId } from "./safe-module-id.js";
|
|
4
|
+
import { escapeForDoubleQuoteString } from "../services/codegen/escape.js";
|
|
7
5
|
/**
|
|
8
6
|
* Compiles all the messages in the bundle and returns an index-function + each compiled message
|
|
9
7
|
*/
|
|
10
8
|
export const compileBundle = (args) => {
|
|
11
9
|
const compiledMessages = {};
|
|
12
|
-
if (KEYWORDS.includes(args.bundle.id) || args.bundle.id === "then") {
|
|
13
|
-
throw new Error([
|
|
14
|
-
`You are using a reserved JS keyword as id "${args.bundle.id}".`,
|
|
15
|
-
"Rename the message bundle id to something else.",
|
|
16
|
-
"See https://github.com/opral/inlang-paraglide-js/issues/331",
|
|
17
|
-
].join("\n"));
|
|
18
|
-
}
|
|
19
10
|
for (const message of args.bundle.messages) {
|
|
20
11
|
if (compiledMessages[message.locale]) {
|
|
21
12
|
throw new Error(`Duplicate locale: ${message.locale}`);
|
|
@@ -35,6 +26,8 @@ export const compileBundle = (args) => {
|
|
|
35
26
|
const compileBundleFunction = (args) => {
|
|
36
27
|
const inputs = args.bundle.declarations.filter((decl) => decl.type === "input-variable");
|
|
37
28
|
const hasInputs = inputs.length > 0;
|
|
29
|
+
const safeBundleId = toSafeModuleId(args.bundle.id);
|
|
30
|
+
const isSafeBundleId = safeBundleId === args.bundle.id;
|
|
38
31
|
let code = `/**
|
|
39
32
|
* This function has been compiled by [Paraglide JS](https://inlang.com/m/gerre34r).
|
|
40
33
|
*
|
|
@@ -45,20 +38,15 @@ const compileBundleFunction = (args) => {
|
|
|
45
38
|
* ${jsDocBundleFunctionTypes({ inputs, locales: args.availableLocales })}
|
|
46
39
|
*/
|
|
47
40
|
/* @__NO_SIDE_EFFECTS__ */
|
|
48
|
-
const ${
|
|
41
|
+
${isSafeBundleId ? "export" : ""} const ${safeBundleId} = (inputs${hasInputs ? "" : "= {}"}, options = {}) => {
|
|
49
42
|
const locale = options.locale ?? getLocale()
|
|
50
43
|
${args.availableLocales
|
|
51
|
-
.map((locale, index) => `${index > 0 ? " " : ""}if (locale === "${locale}") return ${
|
|
44
|
+
.map((locale, index) => `${index > 0 ? " " : ""}if (locale === "${locale}") return ${toSafeModuleId(locale)}.${safeBundleId}(inputs)`)
|
|
52
45
|
.join("\n")}
|
|
53
46
|
return "${args.bundle.id}"
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (isValidJSIdentifier(args.bundle.id)) {
|
|
58
|
-
code += `\nexport { ${args.bundle.id} }`;
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
code += `\nexport { ${jsIdentifier(args.bundle.id)} as "${escapeForDoubleQuoteString(args.bundle.id)}" }`;
|
|
47
|
+
};`;
|
|
48
|
+
if (isSafeBundleId === false) {
|
|
49
|
+
code += `\nexport { ${safeBundleId} as "${escapeForDoubleQuoteString(args.bundle.id)}" }`;
|
|
62
50
|
}
|
|
63
51
|
return {
|
|
64
52
|
code,
|
|
@@ -1,6 +1,33 @@
|
|
|
1
1
|
import { test, expect } from "vitest";
|
|
2
2
|
import { compileBundle } from "./compile-bundle.js";
|
|
3
|
+
import { toSafeModuleId } from "./safe-module-id.js";
|
|
3
4
|
test("compiles to jsdoc", async () => {
|
|
5
|
+
const mockBundle = {
|
|
6
|
+
id: "blue_moon_bottle",
|
|
7
|
+
declarations: [{ type: "input-variable", name: "age" }],
|
|
8
|
+
messages: [
|
|
9
|
+
{
|
|
10
|
+
id: "message-id",
|
|
11
|
+
bundleId: "blue_moon_bottle",
|
|
12
|
+
locale: "en",
|
|
13
|
+
selectors: [],
|
|
14
|
+
variants: [
|
|
15
|
+
{
|
|
16
|
+
id: "1",
|
|
17
|
+
messageId: "message-id",
|
|
18
|
+
matches: [],
|
|
19
|
+
pattern: [
|
|
20
|
+
{ type: "text", value: "Hello" },
|
|
21
|
+
{
|
|
22
|
+
type: "expression",
|
|
23
|
+
arg: { type: "variable-reference", name: "age" },
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
};
|
|
4
31
|
const result = compileBundle({
|
|
5
32
|
fallbackMap: {
|
|
6
33
|
en: "en",
|
|
@@ -21,48 +48,44 @@ test("compiles to jsdoc", async () => {
|
|
|
21
48
|
* @returns {string}
|
|
22
49
|
*/
|
|
23
50
|
/* @__NO_SIDE_EFFECTS__ */
|
|
24
|
-
const blue_moon_bottle = (inputs, options = {}) => {
|
|
51
|
+
export const blue_moon_bottle = (inputs, options = {}) => {
|
|
25
52
|
const locale = options.locale ?? getLocale()
|
|
26
53
|
if (locale === "en") return en.blue_moon_bottle(inputs)
|
|
27
|
-
if (locale === "en-US") return
|
|
54
|
+
if (locale === "en-US") return en_us.blue_moon_bottle(inputs)
|
|
28
55
|
return "blue_moon_bottle"
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export { blue_moon_bottle }"`);
|
|
56
|
+
};"`);
|
|
32
57
|
});
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
{
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
type: "
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
// https://github.com/opral/inlang-paraglide-js/issues/285
|
|
59
|
+
test("compiles bundles with arbitrary module identifiers", async () => {
|
|
60
|
+
const mockBundle = {
|
|
61
|
+
id: "$p@44🍌",
|
|
62
|
+
declarations: [{ type: "input-variable", name: "age" }],
|
|
63
|
+
messages: [
|
|
64
|
+
{
|
|
65
|
+
id: "message-id",
|
|
66
|
+
bundleId: "$p@44🍌",
|
|
67
|
+
locale: "en",
|
|
68
|
+
selectors: [],
|
|
69
|
+
variants: [
|
|
70
|
+
{
|
|
71
|
+
id: "1",
|
|
72
|
+
messageId: "message-id",
|
|
73
|
+
matches: [],
|
|
74
|
+
pattern: [
|
|
75
|
+
{ type: "text", value: "Hello" },
|
|
76
|
+
{
|
|
77
|
+
type: "expression",
|
|
78
|
+
arg: { type: "variable-reference", name: "age" },
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
};
|
|
86
|
+
const result = compileBundle({
|
|
61
87
|
fallbackMap: {},
|
|
62
|
-
bundle:
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
messages: [],
|
|
66
|
-
},
|
|
67
|
-
})).toThrow();
|
|
88
|
+
bundle: mockBundle,
|
|
89
|
+
});
|
|
90
|
+
expect(result.bundle.code).includes(`export { ${toSafeModuleId("$p@44🍌")} as "$p@44🍌" }`);
|
|
68
91
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compile-message.d.ts","sourceRoot":"","sources":["../../src/compiler/compile-message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"compile-message.d.ts","sourceRoot":"","sources":["../../src/compiler/compile-message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAM3C;;;GAGG;AACH,eAAO,MAAM,cAAc,iBACZ,WAAW,EAAE,WAClB,OAAO,YACN,OAAO,EAAE,KACjB,QAAQ,CAAC,OAAO,CAUlB,CAAC"}
|
|
@@ -2,6 +2,7 @@ import { compilePattern } from "./compile-pattern.js";
|
|
|
2
2
|
import { doubleQuote } from "../services/codegen/quotes.js";
|
|
3
3
|
import { inputsType } from "./jsdoc-types.js";
|
|
4
4
|
import { compileLocalVariable } from "./compile-local-variable.js";
|
|
5
|
+
import { toSafeModuleId } from "./safe-module-id.js";
|
|
5
6
|
/**
|
|
6
7
|
* Returns the compiled message as a string
|
|
7
8
|
*
|
|
@@ -33,8 +34,9 @@ function compileMessageWithOneVariant(declarations, message, variants) {
|
|
|
33
34
|
compiledLocalVariables.push(compileLocalVariable({ declaration, locale: message.locale }));
|
|
34
35
|
}
|
|
35
36
|
}
|
|
37
|
+
const safeModuleId = toSafeModuleId(message.bundleId);
|
|
36
38
|
const code = `/** @type {(inputs: ${inputsType(inputs)}) => string} */
|
|
37
|
-
export const ${
|
|
39
|
+
export const ${safeModuleId} = (${hasInputs ? "i" : ""}) => {
|
|
38
40
|
${compiledLocalVariables.join("\n\t")}return ${compiledPattern.code}
|
|
39
41
|
};`;
|
|
40
42
|
return { code, node: message };
|
|
@@ -81,8 +83,9 @@ function compileMessageWithMultipleVariants(declarations, message, variants) {
|
|
|
81
83
|
compiledLocalVariables.push(compileLocalVariable({ declaration, locale: message.locale }));
|
|
82
84
|
}
|
|
83
85
|
}
|
|
86
|
+
const safeModuleId = toSafeModuleId(message.bundleId);
|
|
84
87
|
const code = `/** @type {(inputs: ${inputsType(inputs)}) => string} */
|
|
85
|
-
export const ${
|
|
88
|
+
export const ${safeModuleId} = (${hasInputs ? "i" : ""}) => {
|
|
86
89
|
${compiledLocalVariables.join("\n\t")}
|
|
87
90
|
${compiledVariants.join("\n\t")}
|
|
88
91
|
return \`${message.id}\`;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { test, expect } from "vitest";
|
|
2
2
|
import { compileMessage } from "./compile-message.js";
|
|
3
3
|
import { createRegistry } from "./registry.js";
|
|
4
|
+
import { toSafeModuleId } from "./safe-module-id.js";
|
|
4
5
|
test("compiles a message with a single variant", async () => {
|
|
5
6
|
const declarations = [];
|
|
6
7
|
const message = {
|
|
@@ -254,3 +255,25 @@ test("compiles messages that use datetime a function with options", async () =>
|
|
|
254
255
|
expect(enMessage({ date: "2022-03-31" })).toMatch(/Today is March \d{1,2}\./);
|
|
255
256
|
expect(deMessage({ date: "2022-03-31" })).toMatch(/Today is \d{1,2}\. März\./);
|
|
256
257
|
});
|
|
258
|
+
// https://github.com/opral/inlang-paraglide-js/issues/285
|
|
259
|
+
test("compiles messages with arbitrary module identifiers", async () => {
|
|
260
|
+
const declarations = [];
|
|
261
|
+
const message = {
|
|
262
|
+
locale: "en",
|
|
263
|
+
bundleId: "$p@44🍌",
|
|
264
|
+
id: "message-id",
|
|
265
|
+
selectors: [],
|
|
266
|
+
};
|
|
267
|
+
const variants = [
|
|
268
|
+
{
|
|
269
|
+
id: "1",
|
|
270
|
+
messageId: "message-id",
|
|
271
|
+
matches: [],
|
|
272
|
+
pattern: [{ type: "text", value: "Hello" }],
|
|
273
|
+
},
|
|
274
|
+
];
|
|
275
|
+
const compiled = compileMessage(declarations, message, variants);
|
|
276
|
+
const m = await import("data:text/javascript;base64," +
|
|
277
|
+
Buffer.from(compiled.code).toString("base64"));
|
|
278
|
+
expect(m[toSafeModuleId("$p@44🍌")]()).toBe("Hello");
|
|
279
|
+
});
|
|
@@ -328,6 +328,32 @@ describe.each([
|
|
|
328
328
|
runtime.setLocale("en-US");
|
|
329
329
|
expect(m.missingInGerman()).toBe("A simple message.");
|
|
330
330
|
});
|
|
331
|
+
test("arbitrary module identifiers work", async () => {
|
|
332
|
+
const project = await loadProjectInMemory({
|
|
333
|
+
blob: await newProject({
|
|
334
|
+
settings: { locales: ["en", "de"], baseLocale: "en" },
|
|
335
|
+
}),
|
|
336
|
+
});
|
|
337
|
+
await insertBundleNested(project.db, createBundleNested({
|
|
338
|
+
id: "$502.23-hello_world",
|
|
339
|
+
messages: [
|
|
340
|
+
{
|
|
341
|
+
locale: "en",
|
|
342
|
+
variants: [
|
|
343
|
+
{ pattern: [{ type: "text", value: "A simple message." }] },
|
|
344
|
+
],
|
|
345
|
+
},
|
|
346
|
+
],
|
|
347
|
+
}));
|
|
348
|
+
const output = await compileProject({
|
|
349
|
+
project,
|
|
350
|
+
compilerOptions,
|
|
351
|
+
});
|
|
352
|
+
const code = await bundleCode(output, `export * as m from "./paraglide/messages.js"
|
|
353
|
+
export * as runtime from "./paraglide/runtime.js"`);
|
|
354
|
+
const { m } = await importCode(code);
|
|
355
|
+
expect(m["$502.23-hello_world"]()).toBe("A simple message.");
|
|
356
|
+
});
|
|
331
357
|
test("falls back to parent locale if message doesn't exist", async () => {
|
|
332
358
|
const project = await loadProjectInMemory({
|
|
333
359
|
blob: await newProject({
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { type CompilerOptions } from "./compiler-options.js";
|
|
2
|
+
export type CompilationResult = {
|
|
3
|
+
outputHashes: Record<string, string> | undefined;
|
|
4
|
+
};
|
|
2
5
|
/**
|
|
3
6
|
* Loads, compiles, and writes the output to disk.
|
|
4
7
|
*
|
|
@@ -12,7 +15,7 @@ import { type CompilerOptions } from "./compiler-options.js";
|
|
|
12
15
|
* outdir: 'path/to/output',
|
|
13
16
|
* })
|
|
14
17
|
*/
|
|
15
|
-
export declare function compile(options: CompilerOptions
|
|
16
|
-
|
|
17
|
-
}>;
|
|
18
|
+
export declare function compile(options: CompilerOptions & {
|
|
19
|
+
previousCompilation?: CompilationResult;
|
|
20
|
+
}): Promise<CompilationResult>;
|
|
18
21
|
//# sourceMappingURL=compile.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/compiler/compile.ts"],"names":[],"mappings":"AASA,OAAO,EAEN,KAAK,eAAe,EACpB,MAAM,uBAAuB,CAAC;AAQ/B
|
|
1
|
+
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/compiler/compile.ts"],"names":[],"mappings":"AASA,OAAO,EAEN,KAAK,eAAe,EACpB,MAAM,uBAAuB,CAAC;AAQ/B,MAAM,MAAM,iBAAiB,GAAG;IAC/B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;CACjD,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,wBAAsB,OAAO,CAC5B,OAAO,EAAE,eAAe,GAAG;IAC1B,mBAAmB,CAAC,EAAE,iBAAiB,CAAC;CACxC,GACC,OAAO,CAAC,iBAAiB,CAAC,CAgE5B"}
|
package/dist/compiler/compile.js
CHANGED
|
@@ -21,7 +21,7 @@ let compilationInProgress = null;
|
|
|
21
21
|
* outdir: 'path/to/output',
|
|
22
22
|
* })
|
|
23
23
|
*/
|
|
24
|
-
export async function compile(options
|
|
24
|
+
export async function compile(options) {
|
|
25
25
|
const withDefaultOptions = {
|
|
26
26
|
...defaultCompilerOptions,
|
|
27
27
|
...options,
|
|
@@ -48,7 +48,7 @@ export async function compile(options, previousOutputHashes) {
|
|
|
48
48
|
directory: absoluteOutdir,
|
|
49
49
|
output,
|
|
50
50
|
fs: fs.promises,
|
|
51
|
-
previousOutputHashes,
|
|
51
|
+
previousOutputHashes: options.previousCompilation?.outputHashes,
|
|
52
52
|
});
|
|
53
53
|
if (!localAccount) {
|
|
54
54
|
const activeAccount = await project.lix.db
|
|
@@ -60,6 +60,10 @@ export async function compile(options, previousOutputHashes) {
|
|
|
60
60
|
await project.close();
|
|
61
61
|
return { outputHashes };
|
|
62
62
|
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
console.error(e);
|
|
65
|
+
return { outputHashes: undefined };
|
|
66
|
+
}
|
|
63
67
|
finally {
|
|
64
68
|
// release the lock
|
|
65
69
|
compilationInProgress = null;
|
|
@@ -216,11 +216,15 @@ test("includes eslint-disable comment", async () => {
|
|
|
216
216
|
const messagesWithoutComment = await fs.promises.readFile("/output/messages.js", "utf8");
|
|
217
217
|
expect(messagesWithoutComment).not.toContain("// eslint-disable");
|
|
218
218
|
});
|
|
219
|
-
test("default compiler options should include variable and baseLocale to ensure easy try out of paraglide js, working both in server and browser environemnts", () => {
|
|
219
|
+
test("default compiler options should include cookied, variable and baseLocale to ensure easy try out of paraglide js, working both in server and browser environemnts", () => {
|
|
220
220
|
// someone trying out paraglide js should be able to call `getLocale()` and `setLocale()`
|
|
221
221
|
// without getting an error slammed in their face saying "define your strategy".
|
|
222
222
|
//
|
|
223
223
|
// instead, make the apis work out of the box and once the developer is convinced that
|
|
224
224
|
// paraglide js is the right tool for them, they can then define their own strategy.
|
|
225
|
-
expect(defaultCompilerOptions.strategy).toEqual(
|
|
225
|
+
expect(defaultCompilerOptions.strategy).toEqual([
|
|
226
|
+
"cookie",
|
|
227
|
+
"globalVariable",
|
|
228
|
+
"baseLocale",
|
|
229
|
+
]);
|
|
226
230
|
});
|
|
@@ -4,7 +4,7 @@ export declare const defaultCompilerOptions: {
|
|
|
4
4
|
readonly emitGitIgnore: true;
|
|
5
5
|
readonly includeEslintDisableComment: true;
|
|
6
6
|
readonly emitPrettierIgnore: true;
|
|
7
|
-
readonly strategy: ["
|
|
7
|
+
readonly strategy: ["cookie", "globalVariable", "baseLocale"];
|
|
8
8
|
readonly cookieName: "PARAGLIDE_LOCALE";
|
|
9
9
|
};
|
|
10
10
|
export type CompilerOptions = {
|
|
@@ -3,6 +3,6 @@ export const defaultCompilerOptions = {
|
|
|
3
3
|
emitGitIgnore: true,
|
|
4
4
|
includeEslintDisableComment: true,
|
|
5
5
|
emitPrettierIgnore: true,
|
|
6
|
-
strategy: ["
|
|
6
|
+
strategy: ["cookie", "globalVariable", "baseLocale"],
|
|
7
7
|
cookieName: "PARAGLIDE_LOCALE",
|
|
8
8
|
};
|
|
@@ -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;AAGvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAG9D,wBAAgB,qBAAqB,CACpC,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,EAC/C,eAAe,EAAE;IAChB,QAAQ,EAAE,WAAW,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC;IACnD,UAAU,EAAE,WAAW,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,CAAC;CACvD,GACC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA2DxB"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { jsIdentifier } from "../../services/codegen/identifier.js";
|
|
2
1
|
import { createRuntimeFile } from "../runtime/create-runtime.js";
|
|
3
2
|
import { createRegistry } from "../registry.js";
|
|
3
|
+
import { toSafeModuleId } from "../safe-module-id.js";
|
|
4
4
|
export function generateLocaleModules(compiledBundles, settings, fallbackMap, compilerOptions) {
|
|
5
5
|
const indexFile = [
|
|
6
6
|
`import { getLocale } from "../runtime.js"`,
|
|
7
7
|
settings.locales
|
|
8
|
-
.map((locale) => `import * as ${
|
|
8
|
+
.map((locale) => `import * as ${toSafeModuleId(locale)} from "./${locale}.js"`)
|
|
9
9
|
.join("\n"),
|
|
10
10
|
compiledBundles.map(({ bundle }) => bundle.code).join("\n"),
|
|
11
11
|
].join("\n");
|
|
@@ -29,16 +29,17 @@ export function generateLocaleModules(compiledBundles, settings, fallbackMap, co
|
|
|
29
29
|
let file = "";
|
|
30
30
|
for (const compiledBundle of compiledBundles) {
|
|
31
31
|
const compiledMessage = compiledBundle.messages[locale];
|
|
32
|
-
const
|
|
32
|
+
const bundleModuleId = toSafeModuleId(compiledBundle.bundle.node.id);
|
|
33
|
+
const bundleId = compiledBundle.bundle.node.id;
|
|
33
34
|
if (!compiledMessage) {
|
|
34
35
|
const fallbackLocale = fallbackMap[locale];
|
|
35
36
|
if (fallbackLocale) {
|
|
36
37
|
// use the fall back locale e.g. render the message in English if the German message is missing
|
|
37
|
-
file += `\nexport { ${
|
|
38
|
+
file += `\nexport { ${bundleModuleId} } from "./${fallbackLocale}.js"`;
|
|
38
39
|
}
|
|
39
40
|
else {
|
|
40
41
|
// no fallback exists, render the bundleId
|
|
41
|
-
file += `\nexport const ${
|
|
42
|
+
file += `\n/** @type {(inputs?: Record<string, never>) => string} */\nexport const ${bundleModuleId} = () => '${bundleId}'`;
|
|
42
43
|
}
|
|
43
44
|
continue;
|
|
44
45
|
}
|
|
@@ -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;
|
|
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;AAIvE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAG9D,wBAAgB,sBAAsB,CACrC,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,EAC/C,eAAe,EAAE;IAChB,QAAQ,EAAE,WAAW,CAAC,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC;IACnD,UAAU,EAAE,WAAW,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,CAAC;CACvD,GACC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAoFxB"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createRuntimeFile } from "../runtime/create-runtime.js";
|
|
2
2
|
import { createRegistry } from "../registry.js";
|
|
3
|
-
import { jsIdentifier } from "../../services/codegen/identifier.js";
|
|
4
3
|
import { escapeForSingleQuoteString } from "../../services/codegen/escape.js";
|
|
4
|
+
import { toSafeModuleId } from "../safe-module-id.js";
|
|
5
5
|
export function generateMessageModules(compiledBundles, settings, fallbackMap, compilerOptions) {
|
|
6
6
|
const output = {
|
|
7
7
|
["runtime.js"]: createRuntimeFile({
|
|
@@ -11,33 +11,40 @@ export function generateMessageModules(compiledBundles, settings, fallbackMap, c
|
|
|
11
11
|
}),
|
|
12
12
|
["registry.js"]: createRegistry(),
|
|
13
13
|
};
|
|
14
|
-
// messages index file
|
|
14
|
+
// all messages index file
|
|
15
15
|
output["messages/_index.js"] = [
|
|
16
|
-
...compiledBundles.map(({ bundle }) => `export * from './${bundle.node.id}/index.js'`),
|
|
16
|
+
...compiledBundles.map(({ bundle }) => `export * from './${toSafeModuleId(bundle.node.id)}/index.js'`),
|
|
17
17
|
].join("\n");
|
|
18
18
|
output["messages.js"] = [
|
|
19
19
|
"export * from './messages/_index.js'",
|
|
20
20
|
"// enabling auto-import by exposing all messages as m",
|
|
21
21
|
"export * as m from './messages/_index.js'",
|
|
22
22
|
].join("\n");
|
|
23
|
-
// Creates a per message index file
|
|
24
23
|
for (const compiledBundle of compiledBundles) {
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
24
|
+
const bundleFileId = toSafeModuleId(compiledBundle.bundle.node.id);
|
|
25
|
+
// bundle file
|
|
26
|
+
const indexFilename = `messages/${bundleFileId}/index.js`;
|
|
27
|
+
if (output[indexFilename]) {
|
|
28
|
+
// bundle file already exists, need to append to it
|
|
29
|
+
output[indexFilename] += `\n${compiledBundle.bundle.code}`;
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
// create fresh bundle file
|
|
33
|
+
const code = [
|
|
34
|
+
settings.locales
|
|
35
|
+
.map((locale) => `import * as ${toSafeModuleId(locale)} from "./${locale}.js"`)
|
|
36
|
+
.join("\n"),
|
|
37
|
+
`import { getLocale } from '../../runtime.js'`,
|
|
38
|
+
"",
|
|
39
|
+
compiledBundle.bundle.code,
|
|
40
|
+
].join("\n");
|
|
41
|
+
output[indexFilename] = code;
|
|
42
|
+
}
|
|
43
|
+
// message files
|
|
44
|
+
for (const locale of settings.locales) {
|
|
38
45
|
let file = "";
|
|
39
46
|
const compiledMessage = compiledBundle.messages[locale];
|
|
40
|
-
const id =
|
|
47
|
+
const id = toSafeModuleId(compiledBundle.bundle.node.id);
|
|
41
48
|
if (!compiledMessage) {
|
|
42
49
|
// add fallback
|
|
43
50
|
const fallbackLocale = fallbackMap[locale];
|
|
@@ -47,18 +54,24 @@ export function generateMessageModules(compiledBundles, settings, fallbackMap, c
|
|
|
47
54
|
}
|
|
48
55
|
else {
|
|
49
56
|
// fallback to just the bundle id
|
|
50
|
-
file += `\nexport const ${id} = () => '${escapeForSingleQuoteString(compiledBundle.bundle.node.id)}'`;
|
|
57
|
+
file += `\n/** @type {(inputs?: Record<string, never>) => string} */\nexport const ${id} = () => '${escapeForSingleQuoteString(compiledBundle.bundle.node.id)}'`;
|
|
51
58
|
}
|
|
52
59
|
}
|
|
53
60
|
else {
|
|
54
61
|
file += `\n${compiledMessage.code}`;
|
|
55
62
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
63
|
+
if (output[`messages/${bundleFileId}/${locale}.js`]) {
|
|
64
|
+
// message file already exists, need to append to it
|
|
65
|
+
output[`messages/${bundleFileId}/${locale}.js`] += file;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
// Add the registry import to the message file
|
|
69
|
+
// if registry is used
|
|
70
|
+
if (file.includes("registry.")) {
|
|
71
|
+
file = `import * as registry from '../../registry.js'\n` + file;
|
|
72
|
+
}
|
|
73
|
+
output[`messages/${bundleFileId}/${locale}.js`] = file;
|
|
60
74
|
}
|
|
61
|
-
output[`messages/${compiledBundle.bundle.node.id}/${locale}.js`] = file;
|
|
62
75
|
}
|
|
63
76
|
}
|
|
64
77
|
return output;
|