@intlayer/engine 9.5.11 → 9.6.0
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/assets/installSkills/skills/bundle-optimization.md +123 -0
- package/dist/assets/installSkills/skills/cli.md +28 -1
- package/dist/assets/installSkills/skills/compat.md +1 -5
- package/dist/assets/installSkills/skills/content.md +8 -2
- package/dist/assets/installSkills/skills/dev-tools.md +8 -6
- package/dist/assets/installSkills/skills/next-js.md +2 -2
- package/dist/assets/installSkills/skills/usage.md +1 -1
- package/dist/cjs/build.cjs +5 -0
- package/dist/cjs/cli.cjs +3 -0
- package/dist/cjs/init/index.cjs +14 -14
- package/dist/cjs/init/index.cjs.map +1 -1
- package/dist/cjs/init/utils/backendPackages.cjs +15 -0
- package/dist/cjs/init/utils/backendPackages.cjs.map +1 -0
- package/dist/cjs/init/utils/index.cjs +2 -3
- package/dist/cjs/init/utils/packageManager.cjs +1 -1
- package/dist/cjs/init/utils/packageManager.cjs.map +1 -1
- package/dist/cjs/installMCP/installMCP.cjs +35 -25
- package/dist/cjs/installMCP/installMCP.cjs.map +1 -1
- package/dist/cjs/installSkills/index.cjs +28 -1
- package/dist/cjs/installSkills/index.cjs.map +1 -1
- package/dist/cjs/listGitFiles.cjs +3 -5
- package/dist/cjs/listGitFiles.cjs.map +1 -1
- package/dist/cjs/listProjects.cjs +1 -2
- package/dist/cjs/listProjects.cjs.map +1 -1
- package/dist/cjs/loadDictionaries/loadDictionaries.cjs +9 -8
- package/dist/cjs/loadDictionaries/loadDictionaries.cjs.map +1 -1
- package/dist/cjs/loadDictionaries/loadRemoteDictionaries.cjs +3 -5
- package/dist/cjs/loadDictionaries/loadRemoteDictionaries.cjs.map +1 -1
- package/dist/cjs/loadDictionaries/remoteDictionaryClient.cjs +18 -0
- package/dist/cjs/loadDictionaries/remoteDictionaryClient.cjs.map +1 -0
- package/dist/cjs/prepareIntlayerServer.cjs +132 -0
- package/dist/cjs/prepareIntlayerServer.cjs.map +1 -0
- package/dist/cjs/utils/getProcessChainCommands.cjs +117 -0
- package/dist/cjs/utils/getProcessChainCommands.cjs.map +1 -0
- package/dist/cjs/utils/index.cjs +2 -0
- package/dist/cjs/utils/startContentWatcher.cjs +99 -0
- package/dist/cjs/utils/startContentWatcher.cjs.map +1 -0
- package/dist/cjs/watcher.cjs +2 -2
- package/dist/cjs/watcher.cjs.map +1 -1
- package/dist/cjs/writeJsonIfChanged.cjs.map +1 -1
- package/dist/esm/build.mjs +2 -1
- package/dist/esm/cli.mjs +4 -4
- package/dist/esm/init/index.mjs +13 -13
- package/dist/esm/init/index.mjs.map +1 -1
- package/dist/esm/init/utils/backendPackages.mjs +14 -0
- package/dist/esm/init/utils/backendPackages.mjs.map +1 -0
- package/dist/esm/init/utils/index.mjs +2 -2
- package/dist/esm/init/utils/packageManager.mjs +1 -1
- package/dist/esm/init/utils/packageManager.mjs.map +1 -1
- package/dist/esm/installMCP/installMCP.mjs +35 -25
- package/dist/esm/installMCP/installMCP.mjs.map +1 -1
- package/dist/esm/installSkills/index.mjs +29 -3
- package/dist/esm/installSkills/index.mjs.map +1 -1
- package/dist/esm/listGitFiles.mjs +1 -1
- package/dist/esm/listGitFiles.mjs.map +1 -1
- package/dist/esm/listProjects.mjs +1 -1
- package/dist/esm/listProjects.mjs.map +1 -1
- package/dist/esm/loadDictionaries/loadDictionaries.mjs +9 -8
- package/dist/esm/loadDictionaries/loadDictionaries.mjs.map +1 -1
- package/dist/esm/loadDictionaries/loadRemoteDictionaries.mjs +2 -4
- package/dist/esm/loadDictionaries/loadRemoteDictionaries.mjs.map +1 -1
- package/dist/esm/loadDictionaries/remoteDictionaryClient.mjs +16 -0
- package/dist/esm/loadDictionaries/remoteDictionaryClient.mjs.map +1 -0
- package/dist/esm/prepareIntlayerServer.mjs +128 -0
- package/dist/esm/prepareIntlayerServer.mjs.map +1 -0
- package/dist/esm/utils/getProcessChainCommands.mjs +115 -0
- package/dist/esm/utils/getProcessChainCommands.mjs.map +1 -0
- package/dist/esm/utils/index.mjs +2 -1
- package/dist/esm/utils/runParallel/pidTree.mjs +3 -3
- package/dist/esm/utils/runParallel/pidTree.mjs.map +1 -1
- package/dist/esm/utils/runParallel/ps.mjs +2 -2
- package/dist/esm/utils/runParallel/ps.mjs.map +1 -1
- package/dist/esm/utils/runParallel/wmic.mjs +2 -2
- package/dist/esm/utils/runParallel/wmic.mjs.map +1 -1
- package/dist/esm/utils/startContentWatcher.mjs +98 -0
- package/dist/esm/utils/startContentWatcher.mjs.map +1 -0
- package/dist/esm/watcher.mjs +1 -1
- package/dist/esm/watcher.mjs.map +1 -1
- package/dist/esm/writeJsonIfChanged.mjs +1 -1
- package/dist/esm/writeJsonIfChanged.mjs.map +1 -1
- package/dist/types/build.d.ts +2 -1
- package/dist/types/cli.d.ts +4 -4
- package/dist/types/init/index.d.ts +1 -1
- package/dist/types/init/index.d.ts.map +1 -1
- package/dist/types/init/utils/backendPackages.d.ts +5 -0
- package/dist/types/init/utils/backendPackages.d.ts.map +1 -0
- package/dist/types/init/utils/index.d.ts +2 -2
- package/dist/types/init/utils/packageManager.d.ts +5 -0
- package/dist/types/init/utils/packageManager.d.ts.map +1 -1
- package/dist/types/installMCP/installMCP.d.ts +4 -0
- package/dist/types/installMCP/installMCP.d.ts.map +1 -1
- package/dist/types/installSkills/index.d.ts +7 -0
- package/dist/types/installSkills/index.d.ts.map +1 -1
- package/dist/types/loadDictionaries/loadRemoteDictionaries.d.ts.map +1 -1
- package/dist/types/loadDictionaries/remoteDictionaryClient.d.ts +14 -0
- package/dist/types/loadDictionaries/remoteDictionaryClient.d.ts.map +1 -0
- package/dist/types/prepareIntlayerServer.d.ts +67 -0
- package/dist/types/prepareIntlayerServer.d.ts.map +1 -0
- package/dist/types/utils/getProcessChainCommands.d.ts +35 -0
- package/dist/types/utils/getProcessChainCommands.d.ts.map +1 -0
- package/dist/types/utils/index.d.ts +2 -1
- package/dist/types/utils/startContentWatcher.d.ts +40 -0
- package/dist/types/utils/startContentWatcher.d.ts.map +1 -0
- package/dist/types/watcher.d.ts.map +1 -1
- package/package.json +9 -9
- package/dist/cjs/init/utils/devScript.cjs +0 -57
- package/dist/cjs/init/utils/devScript.cjs.map +0 -1
- package/dist/esm/init/utils/devScript.mjs +0 -55
- package/dist/esm/init/utils/devScript.mjs.map +0 -1
- package/dist/types/init/utils/devScript.d.ts +0 -48
- package/dist/types/init/utils/devScript.d.ts.map +0 -1
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: intlayer-bundle-optimization
|
|
3
|
+
description: Keeps Intlayer dictionaries small in production bundles (purge, minify, import modes). Use when the user asks to "reduce bundle size", "optimize dictionaries", fix "cannot be purged or minified" / "Opaque field" build warnings, or configure `build.optimize`, `build.purge`, `build.minify` or `importMode`.
|
|
4
|
+
metadata:
|
|
5
|
+
author: Intlayer
|
|
6
|
+
url: https://intlayer.org
|
|
7
|
+
license: Apache-2.0
|
|
8
|
+
category: productivity
|
|
9
|
+
tags: [i18n, performance, bundle]
|
|
10
|
+
documentation: https://intlayer.org/doc/concept/bundle-optimization
|
|
11
|
+
support: contact@intlayer.org
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Intlayer Bundle Optimization
|
|
15
|
+
|
|
16
|
+
[Doc](https://intlayer.org/doc/concept/bundle-optimization.md)
|
|
17
|
+
|
|
18
|
+
## Configuration
|
|
19
|
+
|
|
20
|
+
```typescript fileName="intlayer.config.ts"
|
|
21
|
+
import type { IntlayerConfig } from "intlayer";
|
|
22
|
+
|
|
23
|
+
const config: IntlayerConfig = {
|
|
24
|
+
dictionary: {
|
|
25
|
+
importMode: "dynamic", // 'static' (default) | 'dynamic' | 'fetch'
|
|
26
|
+
},
|
|
27
|
+
build: {
|
|
28
|
+
optimize: undefined, // auto: enabled in production builds only
|
|
29
|
+
purge: true, // drop fields never read in source code
|
|
30
|
+
minify: true, // rename field keys to short aliases (title → a)
|
|
31
|
+
chunkGrouping: true, // dynamic mode: one dictionary chunk per split boundary
|
|
32
|
+
dictionariesPreload: true, // dynamic mode: fetch content with its chunk
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export default config;
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
- `purge` and `minify` do nothing when `optimize` is `false`.
|
|
40
|
+
- `minify` skips key renaming while `editor.enabled` is `true`, and for `importMode: 'fetch'` dictionaries.
|
|
41
|
+
- `importMode: 'dynamic'` ships only the current locale's JSON; it can also be set per dictionary.
|
|
42
|
+
|
|
43
|
+
## Dictionaries Follow Their Chunk
|
|
44
|
+
|
|
45
|
+
The build optimization rewrites each `useIntlayer('key')` / `getIntlayer('key')` into a direct import of that dictionary, then empties the global dictionary registry:
|
|
46
|
+
|
|
47
|
+
- A dictionary is bundled with the component that reads it, so a lazy-loaded route only ships its own content.
|
|
48
|
+
|
|
49
|
+
With `importMode: 'dynamic'`, `vite-intlayer` adds two more build plugins (build only, not in dev):
|
|
50
|
+
|
|
51
|
+
- `intlayerChunk` (`build.chunkGrouping`, default `true`) merges the per-dictionary, per-locale chunks by the code-split boundary that uses them (`React.lazy`, split route). Each boundary loads its content in one request per locale. Dictionaries used by several boundaries go to a shared chunk.
|
|
52
|
+
- `intlayerPreload` (`build.dictionariesPreload`, default `true`) starts the dictionary fetch when its chunk is loaded, instead of when the component renders, so navigation does not flash a loading state.
|
|
53
|
+
|
|
54
|
+
Keep dictionaries scoped to their component or page. A dictionary read from many routes ends up in a shared chunk.
|
|
55
|
+
|
|
56
|
+
## Write Code the Analyzer Can Follow
|
|
57
|
+
|
|
58
|
+
Purge and minify rely on a static analysis of every `useIntlayer` / `getIntlayer` call. When a read cannot be followed, the build keeps the whole field or dictionary and warns:
|
|
59
|
+
|
|
60
|
+
- `Dictionary <key> cannot be purged or minified`: the content object escapes.
|
|
61
|
+
- `Dictionary <key> partially minified. Opaque field: '<path>'`: a field is read with a dynamic key.
|
|
62
|
+
|
|
63
|
+
### Read fields by name
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
// ✅ Destructure or use dot access
|
|
67
|
+
const { title, description } = useIntlayer("post");
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Use `select()` instead of dynamic keys
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
// ❌ Opaque field: 'statuses' is kept whole, keys not minified
|
|
74
|
+
const { statuses } = useIntlayer("post");
|
|
75
|
+
<p>{statuses[post.status]}</p>;
|
|
76
|
+
|
|
77
|
+
// ✅ post.content.ts: publishStatus: select({ draft: "…", published: "…" })
|
|
78
|
+
const { publishStatus } = useIntlayer("post");
|
|
79
|
+
<p>{publishStatus(post.status)}</p>;
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Same for numbers (`enu()`), booleans (`cond()`) and genders (`gender()`).
|
|
83
|
+
|
|
84
|
+
### Call `useIntlayer` in each component
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
// ❌ Passing content as a prop: the whole dictionary is kept
|
|
88
|
+
const Post = () => {
|
|
89
|
+
const content = useIntlayer("post");
|
|
90
|
+
return <PostFooter content={content} />;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// ✅ Each component reads its own fields; the dictionary is loaded once
|
|
94
|
+
const PostFooter = () => {
|
|
95
|
+
const { footer } = useIntlayer("post");
|
|
96
|
+
return <footer>{footer}</footer>;
|
|
97
|
+
};
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Don't let the content object escape
|
|
101
|
+
|
|
102
|
+
Spreading (`{ ...content }`), iterating (`Object.entries(content)`) or passing it to a helper (`format(content)`) keeps the whole dictionary.
|
|
103
|
+
|
|
104
|
+
## Accepted Exceptions
|
|
105
|
+
|
|
106
|
+
Some framework APIs need the content as a value, for example a TanStack Start route that loads it in `loader` and reads it in `head`:
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
loader: async ({ params }) => ({
|
|
110
|
+
content: await getIntlayerAsync("admin-metadata", params.locale),
|
|
111
|
+
}),
|
|
112
|
+
head: ({ loaderData }) => ({
|
|
113
|
+
meta: [{ title: loaderData?.content.title }],
|
|
114
|
+
}),
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
The analyzer cannot follow `loaderData`, so this dictionary stays whole and the warning is expected. Keep such dictionaries dedicated and small (e.g. a `*-metadata` dictionary holding only the page metadata) so the rest of the content is still optimized.
|
|
118
|
+
|
|
119
|
+
## References
|
|
120
|
+
|
|
121
|
+
- [Bundle Optimization](https://intlayer.org/doc/concept/bundle-optimization.md)
|
|
122
|
+
- [Select](https://intlayer.org/doc/concept/content/select.md)
|
|
123
|
+
- [Configuration](https://intlayer.org/doc/concept/configuration.md)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: intlayer-cli
|
|
3
|
-
description:
|
|
3
|
+
description: Sets up Intlayer and manages its dictionaries and configuration via the Command Line Interface. Use when the user asks to "set up Intlayer", "audit translations", "build dictionaries", "sync content", or run "intlayer" commands.
|
|
4
4
|
metadata:
|
|
5
5
|
author: Intlayer
|
|
6
6
|
url: https://intlayer.org
|
|
@@ -22,6 +22,33 @@ The `intlayer-cli` package provides a set of commands to manage Intlayer diction
|
|
|
22
22
|
npm install intlayer-cli
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
## Set Up Intlayer
|
|
26
|
+
|
|
27
|
+
`npx intlayer init` installs the Intlayer packages and sets up the framework (config file, tsconfig, bundler plugin, middleware/proxy, providers). Every other setup step is opt-in, through its own sub-command:
|
|
28
|
+
|
|
29
|
+
| Command | Sets up |
|
|
30
|
+
| --------------------------------------------------------- | --------------------------------------------------------- |
|
|
31
|
+
| `npx intlayer init packages` | Missing Intlayer packages, and upgrades the outdated ones |
|
|
32
|
+
| `npx intlayer init project --routing <routing>` | The framework only (no install) |
|
|
33
|
+
| `npx intlayer init github-actions` | The `fill` and `test` GitHub Actions workflows |
|
|
34
|
+
| `npx intlayer init vscode-extension` | The VS Code extension recommendation |
|
|
35
|
+
| `npx intlayer init lsp` | The language server settings |
|
|
36
|
+
| `npx intlayer init eslint` | The lint rules, when the project already lints |
|
|
37
|
+
| `npx intlayer init skills --platform <p> --skills <s…>` | The Intlayer skills for an AI agent |
|
|
38
|
+
| `npx intlayer init mcp --platform <p> --transport stdio` | The Intlayer MCP server, inside the project |
|
|
39
|
+
| `npx intlayer init extension --browser chrome` | Opens the browser extension store page |
|
|
40
|
+
| `npx intlayer init cms` | CMS login through the browser (needs a person) |
|
|
41
|
+
| `npx intlayer init infra --mode <desktop/docker/compose>` | Desktop app or self-hosted stack |
|
|
42
|
+
|
|
43
|
+
`--routing` accepts `prefix-no-default` (default), `prefix-all`, `no-prefix`, `search-params` or `none`.
|
|
44
|
+
|
|
45
|
+
### As an AI agent
|
|
46
|
+
|
|
47
|
+
- Never run `npx intlayer init --interactive`: its checklist needs a terminal. Without one it exits with code 1 and lists the sub-commands above.
|
|
48
|
+
- Run `npx intlayer init`, then only the sub-commands the user asked for.
|
|
49
|
+
- Pass the values as flags so nothing is prompted. When omitted without a terminal: `--skills` defaults to the project stack, `--platform` to the detected agent (e.g. `Claude` for Claude Code), `--transport` to `stdio`; `init infra` requires `--mode`.
|
|
50
|
+
- Leave `init cms` and `init extension` to the user: both finish in their browser.
|
|
51
|
+
|
|
25
52
|
## Main CLI Commands
|
|
26
53
|
|
|
27
54
|
| Command | Description |
|
|
@@ -18,7 +18,7 @@ Compat adapters expose the **exact same public API** as an existing i18n library
|
|
|
18
18
|
|
|
19
19
|
## How it works
|
|
20
20
|
|
|
21
|
-
1. Run `npx intlayer init
|
|
21
|
+
1. Run `npx intlayer init`: it creates `intlayer.config.ts`, installs the adapter and can keep existing JSON catalogs as the source of truth via a sync plugin.
|
|
22
22
|
2. Register the adapter's bundler plugin (`<adapter>/plugin`). It aliases the original imports to the adapter at build time, so no import is rewritten by hand.
|
|
23
23
|
|
|
24
24
|
## Adapters
|
|
@@ -80,8 +80,4 @@ Once the app runs on Intlayer, components can be moved progressively to the nati
|
|
|
80
80
|
- [Lingui](https://intlayer.org/doc/compatibility/lingui.md)
|
|
81
81
|
- [NuxtJS I18n](https://intlayer.org/doc/compatibility/nuxtjs-i18n.md)
|
|
82
82
|
- [NGX Translate](https://intlayer.org/doc/compatibility/ngx-translate.md)
|
|
83
|
-
- [Transloco](https://intlayer.org/doc/compatibility/transloco.md)
|
|
84
83
|
- [Svelte I18n](https://intlayer.org/doc/compatibility/svelte-i18n.md)
|
|
85
|
-
- [Next Translate](https://intlayer.org/doc/compatibility/next-translate.md)
|
|
86
|
-
- [Polyglot.js](https://intlayer.org/doc/compatibility/polyglot.md)
|
|
87
|
-
- [i18n-js](https://intlayer.org/doc/compatibility/i18n-js.md)
|
|
@@ -210,7 +210,7 @@ const publishStatus = select({
|
|
|
210
210
|
// Usage: publishStatus(post.status)
|
|
211
211
|
```
|
|
212
212
|
|
|
213
|
-
> Prefer `select()` over indexing a plain object (`content[status]`): dynamic property access prevents the compiler from pruning and minifying the content
|
|
213
|
+
> Prefer `select()` over indexing a plain object (`content.statuses[status]`): dynamic property access prevents the compiler from pruning and minifying the content, and the build warns `Opaque field`.
|
|
214
214
|
|
|
215
215
|
### Choosing a node by discriminant
|
|
216
216
|
|
|
@@ -304,6 +304,7 @@ import {
|
|
|
304
304
|
html,
|
|
305
305
|
md,
|
|
306
306
|
nest,
|
|
307
|
+
select,
|
|
307
308
|
t,
|
|
308
309
|
type Dictionary,
|
|
309
310
|
} from "intlayer";
|
|
@@ -312,7 +313,7 @@ const content = {
|
|
|
312
313
|
key: "test",
|
|
313
314
|
title: "Test component content",
|
|
314
315
|
description:
|
|
315
|
-
"Content declarations for the Test component, including examples of plurals, conditions, gender-specific messages, dynamic insertions, markdown, file-based content and nested dictionaries used for demonstration and testing purposes.",
|
|
316
|
+
"Content declarations for the Test component, including examples of plurals, conditions, gender-specific messages, string-based selections, dynamic insertions, markdown, file-based content and nested dictionaries used for demonstration and testing purposes.",
|
|
316
317
|
content: {
|
|
317
318
|
baseContent: "Intlayer", // Content that no need to be i18n
|
|
318
319
|
welcomeMessage: t({
|
|
@@ -342,6 +343,11 @@ const content = {
|
|
|
342
343
|
female: "my content for female users",
|
|
343
344
|
fallback: "my content when gender is not specified", // Optional but avoid undefined type
|
|
344
345
|
}),
|
|
346
|
+
mySelect: select({
|
|
347
|
+
draft: "my content when the status is draft",
|
|
348
|
+
published: "my content when the status is published",
|
|
349
|
+
fallback: "my content for any other status", // Optional but avoid undefined type
|
|
350
|
+
}),
|
|
345
351
|
myInsertion: insert(
|
|
346
352
|
"Hello, my name is {{name}} and I am {{age}} years old!"
|
|
347
353
|
),
|
|
@@ -22,7 +22,7 @@ metadata:
|
|
|
22
22
|
npm install --save-dev eslint-plugin-intlayer
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
Then spread `intlayer.configs.recommended` in your `eslint.config.mjs` (oxlint is also supported).
|
|
25
|
+
Then spread `intlayer.configs.recommended` in your `eslint.config.mjs` (oxlint is also supported). `npx intlayer init eslint` installs the plugin and wires the oxlint config for you (for an ESLint flat config, it prints the snippet to add).
|
|
26
26
|
|
|
27
27
|
| Config | `no-raw-text` | `static-dictionary-key` | `no-dynamic-field-access` |
|
|
28
28
|
| --------------- | ------------- | ----------------------- | ------------------------- |
|
|
@@ -38,25 +38,27 @@ Then spread `intlayer.configs.recommended` in your `eslint.config.mjs` (oxlint i
|
|
|
38
38
|
npm install --save-dev @intlayer/lsp
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
+
`npx intlayer init lsp` writes the language server settings to `.vscode/settings.json`.
|
|
42
|
+
|
|
41
43
|
## VS Code Extension
|
|
42
44
|
|
|
43
|
-
Jump from a dictionary key to its content file, extract content from a component, and run build, fill, test, push and pull from the command palette.
|
|
45
|
+
Jump from a dictionary key to its content file, extract content from a component, and run build, fill, test, push and pull from the command palette. `npx intlayer init vscode-extension` recommends it in `.vscode/extensions.json`.
|
|
44
46
|
|
|
45
47
|
## MCP Server
|
|
46
48
|
|
|
47
49
|
Gives AI assistants access to the Intlayer documentation and CLI.
|
|
48
50
|
|
|
49
51
|
```bash
|
|
50
|
-
npx intlayer init mcp
|
|
52
|
+
npx intlayer init mcp --platform Claude --transport stdio
|
|
51
53
|
```
|
|
52
54
|
|
|
53
|
-
This writes the MCP configuration for your IDE (local `@intlayer/mcp` over stdio
|
|
55
|
+
This writes the MCP configuration inside the project for your IDE or agent (`.mcp.json` for Claude Code, `.cursor/mcp.json`, `.vscode/mcp.json`, …), using the local `@intlayer/mcp` over stdio or the hosted `https://mcp.intlayer.org` over SSE. Both flags are optional: without them the platform is detected and the transport is prompted for, or defaults to `stdio` when there is no terminal.
|
|
54
56
|
|
|
55
57
|
A WebMCP is also available for the main website and documentation at `https://intlayer.org`.
|
|
56
58
|
|
|
57
59
|
## CI/CD
|
|
58
60
|
|
|
59
|
-
Fill missing translations with AI on each change, and fail the build on missing ones:
|
|
61
|
+
Fill missing translations with AI on each change, and fail the build on missing ones. `npx intlayer init github-actions` scaffolds both workflows:
|
|
60
62
|
|
|
61
63
|
```bash
|
|
62
64
|
npx intlayer fill --git-diff --mode complete
|
|
@@ -65,7 +67,7 @@ npx intlayer test
|
|
|
65
67
|
|
|
66
68
|
## Chrome Extension
|
|
67
69
|
|
|
68
|
-
Inspect the i18n setup of any website: framework, i18n library, locales, hreflang and SEO tags.
|
|
70
|
+
Inspect the i18n setup of any website: framework, i18n library, locales, hreflang and SEO tags. `npx intlayer init extension --browser chrome` opens its store page.
|
|
69
71
|
|
|
70
72
|
## References
|
|
71
73
|
|
|
@@ -90,8 +90,8 @@ The [Intlayer Compiler](https://intlayer.org/doc/compiler.md) can extract all yo
|
|
|
90
90
|
- [Next.js 14](https://intlayer.org/doc/environment/nextjs/14.md)
|
|
91
91
|
- [Next.js 15](https://intlayer.org/doc/environment/nextjs/15.md)
|
|
92
92
|
- [Next.js with Page Router](https://intlayer.org/doc/environment/nextjs/next-with-page-router.md)
|
|
93
|
-
- [Intlayer with next-intl](https://intlayer.org/doc/next-intl.md)
|
|
94
|
-
- [Intlayer with next-i18next](https://intlayer.org/doc/next-i18next.md)
|
|
93
|
+
- [Intlayer with next-intl](https://intlayer.org/doc/migration/next-intl.md)
|
|
94
|
+
- [Intlayer with next-i18next](https://intlayer.org/doc/migration/next-i18next.md)
|
|
95
95
|
|
|
96
96
|
### Concepts
|
|
97
97
|
|
|
@@ -19,7 +19,7 @@ To use Intlayer effectively:
|
|
|
19
19
|
1. **Retrieve Locales**: Check `intlayer.config.{ts,js,json,json5,jsonc,cjs,mjs}`, `.intlayerrc` to see the configured locales.
|
|
20
20
|
|
|
21
21
|
2. **Declare Content**:
|
|
22
|
-
We recommend creating one content declaration file per component, located alongside the component file. This keeps translations close to the code.
|
|
22
|
+
We recommend creating one content declaration file per component or per section of your application, located alongside the component file. This keeps translations close to the code.
|
|
23
23
|
|
|
24
24
|
3. **Consume Content**: Use the provided hooks and functions to access your content.
|
|
25
25
|
- [Intlayer Exports](https://intlayer.org/doc/packages/intlayer/exports.md)
|
package/dist/cjs/build.cjs
CHANGED
|
@@ -19,11 +19,13 @@ const require_loadDictionaries_loadDictionaries = require('./loadDictionaries/lo
|
|
|
19
19
|
const require_loadDictionaries_loadLocalDictionaries = require('./loadDictionaries/loadLocalDictionaries.cjs');
|
|
20
20
|
const require_writeConfiguration_index = require('./writeConfiguration/index.cjs');
|
|
21
21
|
const require_prepareIntlayer = require('./prepareIntlayer.cjs');
|
|
22
|
+
const require_prepareIntlayerServer = require('./prepareIntlayerServer.cjs');
|
|
22
23
|
const require_writeContentDeclaration_detectExportedComponentName = require('./writeContentDeclaration/detectExportedComponentName.cjs');
|
|
23
24
|
const require_writeContentDeclaration_transformJSFile = require('./writeContentDeclaration/transformJSFile.cjs');
|
|
24
25
|
const require_writeContentDeclaration_writeJSFile = require('./writeContentDeclaration/writeJSFile.cjs');
|
|
25
26
|
const require_writeContentDeclaration_writeContentDeclaration = require('./writeContentDeclaration/writeContentDeclaration.cjs');
|
|
26
27
|
|
|
28
|
+
exports.INTLAYER_WATCH_ENV_VAR = require_prepareIntlayerServer.INTLAYER_WATCH_ENV_VAR;
|
|
27
29
|
exports.buildDictionary = require_buildIntlayerDictionary_buildIntlayerDictionary.buildDictionary;
|
|
28
30
|
exports.cleanOutputDir = require_cleanOutputDir.cleanOutputDir;
|
|
29
31
|
exports.createDictionaryEntryPoint = require_createDictionaryEntryPoint_createDictionaryEntryPoint.createDictionaryEntryPoint;
|
|
@@ -46,6 +48,8 @@ exports.getBuiltDynamicDictionariesPath = require_createDictionaryEntryPoint_get
|
|
|
46
48
|
exports.getBuiltFetchDictionariesPath = require_createDictionaryEntryPoint_getBuiltFetchDictionariesPath.getBuiltFetchDictionariesPath;
|
|
47
49
|
exports.getBuiltRemoteDictionariesPath = require_createDictionaryEntryPoint_getBuiltRemoteDictionariesPath.getBuiltRemoteDictionariesPath;
|
|
48
50
|
exports.getBuiltUnmergedDictionariesPath = require_createDictionaryEntryPoint_getBuiltUnmergedDictionariesPath.getBuiltUnmergedDictionariesPath;
|
|
51
|
+
exports.getIsDevWatcherCommand = require_prepareIntlayerServer.getIsDevWatcherCommand;
|
|
52
|
+
exports.getIsServerDevelopment = require_prepareIntlayerServer.getIsServerDevelopment;
|
|
49
53
|
exports.getTypeName = require_createType_createModuleAugmentation.getTypeName;
|
|
50
54
|
exports.isCachedConfigurationUpToDate = require_writeConfiguration_index.isCachedConfigurationUpToDate;
|
|
51
55
|
exports.loadContentDeclaration = require_loadDictionaries_loadContentDeclaration.loadContentDeclaration;
|
|
@@ -54,6 +58,7 @@ exports.loadDictionaries = require_loadDictionaries_loadDictionaries.loadDiction
|
|
|
54
58
|
exports.loadLocalDictionaries = require_loadDictionaries_loadLocalDictionaries.loadLocalDictionaries;
|
|
55
59
|
exports.loadRemoteDictionaries = require_loadDictionaries_loadRemoteDictionaries.loadRemoteDictionaries;
|
|
56
60
|
exports.prepareIntlayer = require_prepareIntlayer.prepareIntlayer;
|
|
61
|
+
exports.prepareIntlayerServer = require_prepareIntlayerServer.prepareIntlayerServer;
|
|
57
62
|
exports.processContentDeclaration = require_buildIntlayerDictionary_processContentDeclaration.processContentDeclaration;
|
|
58
63
|
exports.readDictionariesFromDisk = require_utils_readDictionariesFromDisk.readDictionariesFromDisk;
|
|
59
64
|
exports.transformJSFile = require_writeContentDeclaration_transformJSFile.transformJSFile;
|
package/dist/cjs/cli.cjs
CHANGED
|
@@ -23,6 +23,7 @@ const require_listGitFiles = require('./listGitFiles.cjs');
|
|
|
23
23
|
|
|
24
24
|
exports.COMPAT_I18N_LIBRARIES = require_init_utils_packageManager.COMPAT_I18N_LIBRARIES;
|
|
25
25
|
exports.DocumentationRouter = require_init_documentationRouter.DocumentationRouter;
|
|
26
|
+
exports.MCP_TRANSPORTS = require_installMCP_installMCP.MCP_TRANSPORTS;
|
|
26
27
|
exports.NEXT_INTLAYER_BABEL_CONFIG_CONTENT = require_init_utils_nextCompilerBabel.NEXT_INTLAYER_BABEL_CONFIG_CONTENT;
|
|
27
28
|
exports.PLATFORMS = require_installSkills_index.PLATFORMS;
|
|
28
29
|
exports.PLATFORMS_METADATA = require_installSkills_index.PLATFORMS_METADATA;
|
|
@@ -32,7 +33,9 @@ exports.detectCompatI18nLibraries = require_init_utils_packageManager.detectComp
|
|
|
32
33
|
exports.detectExportedComponentName = require_writeContentDeclaration_detectExportedComponentName.detectExportedComponentName;
|
|
33
34
|
exports.detectFormatCommand = require_detectFormatCommand.detectFormatCommand;
|
|
34
35
|
exports.detectPackageManager = require_init_utils_packageManager.detectPackageManager;
|
|
36
|
+
exports.detectPlatform = require_installSkills_index.detectPlatform;
|
|
35
37
|
exports.enableEditorInConfig = require_init_cms.enableEditorInConfig;
|
|
38
|
+
exports.findLockFileDir = require_init_utils_packageManager.findLockFileDir;
|
|
36
39
|
exports.getContentDeclarationFileTemplate = require_getContentDeclarationFileTemplate_getContentDeclarationFileTemplate.getContentDeclarationFileTemplate;
|
|
37
40
|
exports.getDefaultApplicationURL = require_init_index.getDefaultApplicationURL;
|
|
38
41
|
exports.getDocumentationUrl = require_init_documentationRouter.getDocumentationUrl;
|
package/dist/cjs/init/index.cjs
CHANGED
|
@@ -6,7 +6,7 @@ const require_init_cms = require('./cms.cjs');
|
|
|
6
6
|
const require_initConfig_index = require('../initConfig/index.cjs');
|
|
7
7
|
const require_init_documentationRouter = require('./documentationRouter.cjs');
|
|
8
8
|
const require_init_frameworkSetup_index = require('./frameworkSetup/index.cjs');
|
|
9
|
-
const
|
|
9
|
+
const require_init_utils_backendPackages = require('./utils/backendPackages.cjs');
|
|
10
10
|
const require_init_utils_packageManager = require('./utils/packageManager.cjs');
|
|
11
11
|
const require_init_utils_githubActions = require('./utils/githubActions.cjs');
|
|
12
12
|
const require_init_utils_jsonParser = require('./utils/jsonParser.cjs');
|
|
@@ -63,7 +63,7 @@ const initIntlayer = async (rootDir, options) => {
|
|
|
63
63
|
...packageJson.dependencies ?? {},
|
|
64
64
|
...packageJson.devDependencies ?? {}
|
|
65
65
|
};
|
|
66
|
-
const movedPackages = require_init_utils_packageManager.moveCompatPackagesToDevDependencies(packageJson);
|
|
66
|
+
const movedPackages = options?.noInstallPackages ? [] : require_init_utils_packageManager.moveCompatPackagesToDevDependencies(packageJson);
|
|
67
67
|
if (movedPackages.length > 0) {
|
|
68
68
|
const indentation = packageJsonContent.match(/^[ \t]+(?=")/m)?.[0] ?? 2;
|
|
69
69
|
const trailingNewline = packageJsonContent.endsWith("\n") ? "\n" : "";
|
|
@@ -77,7 +77,8 @@ const initIntlayer = async (rootDir, options) => {
|
|
|
77
77
|
const { packagesToInstall, devPackagesToInstall, compatSyncConfig, compatVitePluginConfig, pendingCompatAdapters } = require_init_utils_packageManager.detectMissingIntlayerPackages(allDeps, {
|
|
78
78
|
linguiCatalogFormat,
|
|
79
79
|
dependencies: packageJson.dependencies,
|
|
80
|
-
devDependencies: packageJson.devDependencies
|
|
80
|
+
devDependencies: packageJson.devDependencies,
|
|
81
|
+
skipLintPlugin: options?.noEslint
|
|
81
82
|
});
|
|
82
83
|
/** Whether the compat adapter for a library is not released yet. */
|
|
83
84
|
const isCompatAdapterPending = (adapterPackage) => pendingCompatAdapters.includes(adapterPackage);
|
|
@@ -175,6 +176,15 @@ const initIntlayer = async (rootDir, options) => {
|
|
|
175
176
|
}
|
|
176
177
|
if (!options?.noEslint && require_init_utils_packageManager.hasLegacyEslint(allDeps)) (0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.x} ${(0, _intlayer_config_logger.colorize)(require_init_utils_lintConfig.LINT_PLUGIN_PACKAGE_NAME, _intlayer_config_colors.MAGENTA)} needs ESLint ${9}+ (flat config) — skipped the Intlayer lint rules. Upgrade ESLint to enable them: ${(0, _intlayer_config_logger.colorizePath)(require_init_documentationRouter.DocumentationRouter.ESLint)}`, { level: "warn" });
|
|
177
178
|
if (!options?.noEslint && require_init_utils_packageManager.hasLintTooling(allDeps)) {
|
|
179
|
+
if (options?.noInstallPackages && !allDeps["eslint-plugin-intlayer"]) {
|
|
180
|
+
const lintPluginSpecifier = options.upgradeToVersion ? `${require_init_utils_lintConfig.LINT_PLUGIN_PACKAGE_NAME}@${options.upgradeToVersion}` : require_init_utils_lintConfig.LINT_PLUGIN_PACKAGE_NAME;
|
|
181
|
+
try {
|
|
182
|
+
require_init_utils_packageManager.installPackages(rootDir, [lintPluginSpecifier], packageManager, true);
|
|
183
|
+
(0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.v} Installed: ${(0, _intlayer_config_logger.colorize)(require_init_utils_lintConfig.LINT_PLUGIN_PACKAGE_NAME, _intlayer_config_colors.MAGENTA)}`);
|
|
184
|
+
} catch {
|
|
185
|
+
(0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.x} Failed to install ${require_init_utils_lintConfig.LINT_PLUGIN_PACKAGE_NAME}. Please install it manually.`, { level: "warn" });
|
|
186
|
+
}
|
|
187
|
+
}
|
|
178
188
|
const oxlintConfigPath = ".oxlintrc.json";
|
|
179
189
|
const hasOxlintConfig = await require_init_utils_fileSystem.exists(rootDir, oxlintConfigPath);
|
|
180
190
|
const shouldCreateOxlintConfig = !hasOxlintConfig && Boolean(allDeps.oxlint) && !allDeps.eslint;
|
|
@@ -398,16 +408,6 @@ const initIntlayer = async (rootDir, options) => {
|
|
|
398
408
|
(0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.v} Created ${(0, _intlayer_config_logger.colorizePath)(newMetroConfigFile)} with the Intlayer Metro plugin`);
|
|
399
409
|
}
|
|
400
410
|
}
|
|
401
|
-
const newDevScript = require_init_utils_devScript.resolveDevScript({
|
|
402
|
-
devScript: packageJson.scripts?.dev,
|
|
403
|
-
allDeps,
|
|
404
|
-
isNextJsProject
|
|
405
|
-
});
|
|
406
|
-
if (newDevScript) {
|
|
407
|
-
packageJson.scripts.dev = newDevScript;
|
|
408
|
-
await require_init_utils_fileSystem.writeFileToRoot(rootDir, packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
409
|
-
(0, _intlayer_config_logger.logger)(`${_intlayer_config_logger.v} Updated ${(0, _intlayer_config_logger.colorizePath)("package.json")} dev script to run intlayer watch`);
|
|
410
|
-
}
|
|
411
411
|
for (const file of [
|
|
412
412
|
"webpack.config.js",
|
|
413
413
|
"webpack.config.ts",
|
|
@@ -424,7 +424,7 @@ const initIntlayer = async (rootDir, options) => {
|
|
|
424
424
|
"@adonisjs/core",
|
|
425
425
|
"hono",
|
|
426
426
|
"elysia",
|
|
427
|
-
...
|
|
427
|
+
...require_init_utils_backendPackages.BACKEND_INTLAYER_PACKAGES
|
|
428
428
|
].some((pkg) => allDeps[pkg])) hasAliasConfiguration = true;
|
|
429
429
|
if (!hasAliasConfiguration) {
|
|
430
430
|
const configuration = (0, _intlayer_config_node.getConfiguration)({ baseDir: rootDir });
|