Skip to content

Commit 9267dca

Browse files
Merge pull request #3779 from opral/declaration-files
Add an opt-in `emitTsDeclarations` compiler flag
2 parents ffc6e1d + 19e6625 commit 9267dca

File tree

9 files changed

+269
-19
lines changed

9 files changed

+269
-19
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
"@inlang/paraglide-js": minor
3+
---
4+
5+
Add an opt-in `emitTsDeclarations` compiler flag to generate fresh `.d.ts` files (incl. `m` re-export and locale fallbacks) for locale-modules so IDEs stop reporting stale/missing message keys.
6+
7+
Closes https://github.com/opral/inlang-paraglide-js/issues/566
8+
Closes https://github.com/opral/inlang-paraglide-js/issues/238
9+
Closes https://github.com/opral/inlang-paraglide-js/issues/160
10+
11+
Example output (locale-modules):
12+
13+
```diff
14+
src/paraglide/
15+
messages/
16+
_index.js
17+
+ _index.d.ts
18+
de.js
19+
+ de.d.ts
20+
en.js
21+
+ en.d.ts
22+
messages.js
23+
+ messages.d.ts
24+
```

inlang/packages/paraglide/paraglide-js/docs-api/compiler-options.md

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22

33
> **CompilerOptions** = `object`
44
5-
Defined in: [compiler-options.ts:19](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
5+
Defined in: [compiler-options.ts:20](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
66

77
### Properties
88

99
#### additionalFiles?
1010

1111
> `optional` **additionalFiles**: `Record`\<`string`, `string`\>
1212
13-
Defined in: [compiler-options.ts:154](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
13+
Defined in: [compiler-options.ts:155](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
1414

1515
The `additionalFiles` option is an array of paths to additional files that should be copied to the output directory.
1616

@@ -40,7 +40,7 @@ The output will look like this:
4040

4141
> `optional` **cleanOutdir**: `boolean`
4242
43-
Defined in: [compiler-options.ts:260](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
43+
Defined in: [compiler-options.ts:280](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
4444

4545
Whether to clean the output directory before writing the new files.
4646

@@ -54,7 +54,7 @@ true
5454

5555
> `optional` **cookieDomain**: `string`
5656
57-
Defined in: [compiler-options.ts:128](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
57+
Defined in: [compiler-options.ts:129](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
5858

5959
The host to which the cookie will be sent.
6060
If undefined or empty, the domain attribute is omitted from the cookie, scoping it to the exact current domain only (no subdomains).
@@ -83,7 +83,7 @@ cookieDomain: "example.com" // Cookie: "PARAGLIDE_LOCALE=en; path=/; max-age=345
8383

8484
> `optional` **cookieMaxAge**: `number`
8585
86-
Defined in: [compiler-options.ts:108](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
86+
Defined in: [compiler-options.ts:109](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
8787

8888
The max-age in seconds of the cookie until it expires.
8989

@@ -97,7 +97,7 @@ The max-age in seconds of the cookie until it expires.
9797

9898
> `optional` **cookieName**: `string`
9999
100-
Defined in: [compiler-options.ts:102](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
100+
Defined in: [compiler-options.ts:103](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
101101

102102
The name of the cookie to use for the cookie strategy.
103103

@@ -111,7 +111,7 @@ The name of the cookie to use for the cookie strategy.
111111

112112
> `optional` **disableAsyncLocalStorage**: `boolean`
113113
114-
Defined in: [compiler-options.ts:189](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
114+
Defined in: [compiler-options.ts:209](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
115115

116116
Replaces AsyncLocalStorage with a synchronous implementation.
117117

@@ -126,7 +126,7 @@ leak into another concurrent request.
126126

127127
> `optional` **emitGitIgnore**: `boolean`
128128
129-
Defined in: [compiler-options.ts:203](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
129+
Defined in: [compiler-options.ts:223](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
130130

131131
If `emitGitIgnore` is set to `true` a `.gitignore` file will be emitted in the output directory. Defaults to `true`.
132132

@@ -148,7 +148,7 @@ true
148148

149149
> `optional` **emitPrettierIgnore**: `boolean`
150150
151-
Defined in: [compiler-options.ts:168](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
151+
Defined in: [compiler-options.ts:169](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
152152

153153
If `emitPrettierIgnore` is set to `true` a `.prettierignore` file will be emitted in the output directory. Defaults to `true`.
154154

@@ -166,11 +166,39 @@ If `emitPrettierIgnore` is set to `true` a `.prettierignore` file will be emitte
166166
true
167167
```
168168

169+
#### emitTsDeclarations?
170+
171+
> `optional` **emitTsDeclarations**: `boolean`
172+
173+
Defined in: [compiler-options.ts:188](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
174+
175+
Emit `.d.ts` files for the generated output using the TypeScript compiler.
176+
177+
Enable this to give IDEs fresh, explicit typings for generated message modules
178+
(useful when using `locale-modules` during development). Requires `typescript`
179+
to be resolvable in your toolchain.
180+
181+
##### Example
182+
183+
```ts
184+
await compile({
185+
project: "./project.inlang",
186+
outdir: "./src/paraglide",
187+
emitTsDeclarations: true,
188+
});
189+
```
190+
191+
##### Default
192+
193+
```ts
194+
false
195+
```
196+
169197
#### experimentalMiddlewareLocaleSplitting?
170198

171199
> `optional` **experimentalMiddlewareLocaleSplitting**: `boolean`
172200
173-
Defined in: [compiler-options.ts:77](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
201+
Defined in: [compiler-options.ts:78](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
174202

175203
Whether or not to use experimental middleware locale splitting.
176204

@@ -194,7 +222,7 @@ false
194222

195223
> `optional` **fs**: `any`
196224
197-
Defined in: [compiler-options.ts:267](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
225+
Defined in: [compiler-options.ts:287](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
198226

199227
The file system to use. Defaults to `await import('node:fs')`.
200228

@@ -204,7 +232,7 @@ Useful for testing the paraglide compiler by mocking the fs.
204232

205233
> `optional` **includeEslintDisableComment**: `boolean`
206234
207-
Defined in: [compiler-options.ts:178](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
235+
Defined in: [compiler-options.ts:198](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
208236

209237
Whether to include an eslint-disable comment at the top of each .js file.
210238

@@ -218,7 +246,7 @@ true
218246

219247
> `optional` **isServer**: `string`
220248
221-
Defined in: [compiler-options.ts:96](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
249+
Defined in: [compiler-options.ts:97](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
222250

223251
Tree-shaking flag if the code is running on the server.
224252

@@ -242,7 +270,7 @@ typeof window === "undefined"
242270

243271
> `optional` **localStorageKey**: `string`
244272
245-
Defined in: [compiler-options.ts:83](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
273+
Defined in: [compiler-options.ts:84](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
246274

247275
The name of the localStorage key to use for the localStorage strategy.
248276

@@ -256,7 +284,7 @@ The name of the localStorage key to use for the localStorage strategy.
256284

257285
> **outdir**: `string`
258286
259-
Defined in: [compiler-options.ts:43](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
287+
Defined in: [compiler-options.ts:44](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
260288

261289
The path to the output directory.
262290

@@ -273,7 +301,7 @@ await compile({
273301

274302
> `optional` **outputStructure**: `"locale-modules"` \| `"message-modules"`
275303
276-
Defined in: [compiler-options.ts:254](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
304+
Defined in: [compiler-options.ts:274](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
277305

278306
The `outputStructure` defines how modules are structured in the output.
279307

@@ -332,7 +360,7 @@ The benefit are substantially fewer files which is needed in large projects.
332360

333361
> **project**: `string`
334362
335-
Defined in: [compiler-options.ts:31](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
363+
Defined in: [compiler-options.ts:32](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
336364

337365
The path to the inlang project.
338366

@@ -349,7 +377,7 @@ await compile({
349377

350378
> `optional` **strategy**: [`Runtime`](runtime/type/README.md#runtime)\[`"strategy"`\]
351379
352-
Defined in: [compiler-options.ts:61](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
380+
Defined in: [compiler-options.ts:62](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
353381

354382
The strategy to use for getting the locale.
355383

@@ -375,7 +403,7 @@ Custom strategies with the pattern `custom-[A-Za-z0-9]+` are supported.
375403

376404
> `optional` **urlPatterns**: [`Runtime`](runtime/type/README.md#runtime)\[`"urlPatterns"`\]
377405
378-
Defined in: [compiler-options.ts:172](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
406+
Defined in: [compiler-options.ts:192](https://github.com/opral/monorepo/tree/main/inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts)
379407

380408
https://inlang.com/m/gerre34r/library-inlang-paraglideJs/strategy#url
381409

@@ -417,6 +445,10 @@ Defined in: [compiler-options.ts:3](https://github.com/opral/monorepo/tree/main/
417445

418446
> `readonly` **emitPrettierIgnore**: `true` = `true`
419447
448+
#### emitTsDeclarations
449+
450+
> `readonly` **emitTsDeclarations**: `false` = `false`
451+
420452
#### experimentalMiddlewareLocaleSplitting
421453

422454
> `readonly` **experimentalMiddlewareLocaleSplitting**: `false` = `false`

inlang/packages/paraglide/paraglide-js/examples/vite/vite.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export default defineConfig({
99
// forcing locale modules to detect problems during CI/CD
1010
// (all other projects use message-modules)
1111
outputStructure: "locale-modules",
12+
emitTsDeclarations: true,
1213
}),
1314
],
1415
build: {

inlang/packages/paraglide/paraglide-js/src/cli/commands/compile/command.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,18 @@ export const compileCommand = new Command()
3131
].join("\n")
3232
)
3333
.requiredOption("--silent", "Only log errors to the console", false)
34+
.option(
35+
"--emit-ts-declarations",
36+
"Emit .d.ts files for the generated output (requires the typescript package)",
37+
defaultCompilerOptions.emitTsDeclarations
38+
)
3439
.action(
3540
async (options: {
3641
silent: boolean;
3742
project: string;
3843
outdir: string;
3944
strategy?: CompilerOptions["strategy"];
45+
emitTsDeclarations?: CompilerOptions["emitTsDeclarations"];
4046
}) => {
4147
const logger = new Logger({ silent: options.silent, prefix: true });
4248
const path = resolve(process.cwd(), options.project);
@@ -48,6 +54,9 @@ export const compileCommand = new Command()
4854
project: path,
4955
outdir: options.outdir,
5056
strategy: options.strategy ?? defaultCompilerOptions.strategy,
57+
emitTsDeclarations:
58+
options.emitTsDeclarations ??
59+
defaultCompilerOptions.emitTsDeclarations,
5160
});
5261
} catch (e) {
5362
logger.error("Error while compiling inlang project.");

inlang/packages/paraglide/paraglide-js/src/compiler/compile-project.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,20 @@ test("emitPrettierIgnore", async () => {
8787
expect(_false).not.toHaveProperty(".prettierignore");
8888
});
8989

90+
test("emitTsDeclarations generates declaration files", async () => {
91+
const output = await compileProject({
92+
project,
93+
compilerOptions: {
94+
emitTsDeclarations: true,
95+
outputStructure: "locale-modules",
96+
},
97+
});
98+
99+
expect(output).toHaveProperty("messages/_index.d.ts");
100+
expect(output).toHaveProperty("messages.d.ts");
101+
expect(output["messages/_index.d.ts"]).toContain("sad_penguin_bundle");
102+
});
103+
90104
test("handles message bundles with a : in the id", async () => {
91105
const project = await loadProjectInMemory({
92106
blob: await newProject({

inlang/packages/paraglide/paraglide-js/src/compiler/compile-project.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
import { createRuntimeFile } from "./runtime/create-runtime.js";
1111
import { createServerFile } from "./server/create-server-file.js";
1212
import { createRegistry } from "./registry.js";
13+
import { emitTsDeclarations } from "./emit-ts-declarations.js";
1314

1415
const outputStructures = {
1516
"locale-modules": localeModules,
@@ -99,6 +100,11 @@ export const compileProject = async (args: {
99100
}
100101
}
101102

103+
if (optionsWithDefaults.emitTsDeclarations) {
104+
const declarations = await emitTsDeclarations(output);
105+
Object.assign(output, declarations);
106+
}
107+
102108
return output;
103109
};
104110

inlang/packages/paraglide/paraglide-js/src/compiler/compiler-options.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export const defaultCompilerOptions = {
55
emitGitIgnore: true,
66
includeEslintDisableComment: true,
77
emitPrettierIgnore: true,
8+
emitTsDeclarations: false,
89
cleanOutdir: true,
910
disableAsyncLocalStorage: false,
1011
experimentalMiddlewareLocaleSplitting: false,
@@ -166,6 +167,25 @@ export type CompilerOptions = {
166167
* @default true
167168
*/
168169
emitPrettierIgnore?: boolean;
170+
/**
171+
* Emit `.d.ts` files for the generated output using the TypeScript compiler.
172+
*
173+
* Enable this to give IDEs fresh, explicit typings for generated message modules
174+
* (useful when using `locale-modules` during development). Requires `typescript`
175+
* to be resolvable in your toolchain.
176+
*
177+
* @example
178+
* ```ts
179+
* await compile({
180+
* project: "./project.inlang",
181+
* outdir: "./src/paraglide",
182+
* emitTsDeclarations: true,
183+
* });
184+
* ```
185+
*
186+
* @default false
187+
*/
188+
emitTsDeclarations?: boolean;
169189
/**
170190
* https://inlang.com/m/gerre34r/library-inlang-paraglideJs/strategy#url
171191
*/

0 commit comments

Comments
 (0)