@intlayer/docs 9.3.1 → 9.3.2

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.
Files changed (60) hide show
  1. package/dist/cjs/generated/docs.entry.cjs +20 -0
  2. package/dist/cjs/generated/docs.entry.cjs.map +1 -1
  3. package/dist/esm/generated/docs.entry.mjs +20 -0
  4. package/dist/esm/generated/docs.entry.mjs.map +1 -1
  5. package/dist/types/generated/docs.entry.d.ts +1 -0
  6. package/dist/types/generated/docs.entry.d.ts.map +1 -1
  7. package/docs/ar/eslint.md +336 -0
  8. package/docs/ar/intlayer_with_react_router_v7_fs_routes.md +1 -1
  9. package/docs/bn/eslint.md +336 -0
  10. package/docs/cs/eslint.md +336 -0
  11. package/docs/de/eslint.md +336 -0
  12. package/docs/en/eslint.md +336 -0
  13. package/docs/en-GB/eslint.md +336 -0
  14. package/docs/en-GB/intlayer_with_create_react_app.md +32 -35
  15. package/docs/en-GB/intlayer_with_react_router_v7_fs_routes.md +1 -1
  16. package/docs/es/eslint.md +336 -0
  17. package/docs/fr/eslint.md +336 -0
  18. package/docs/hi/eslint.md +336 -0
  19. package/docs/hi/intlayer_with_react_router_v7_fs_routes.md +1 -1
  20. package/docs/hi/intlayer_with_vite+svelte.md +2 -2
  21. package/docs/id/eslint.md +336 -0
  22. package/docs/it/eslint.md +336 -0
  23. package/docs/ja/eslint.md +336 -0
  24. package/docs/ja/intlayer_with_react_router_v7.md +1 -146
  25. package/docs/ja/intlayer_with_vite+react.md +5 -1
  26. package/docs/ko/eslint.md +336 -0
  27. package/docs/ko/intlayer_with_lynx+react.md +4 -0
  28. package/docs/ko/intlayer_with_react_router_v7_fs_routes.md +1 -1
  29. package/docs/ko/intlayer_with_storybook.md +5 -5
  30. package/docs/nl/eslint.md +336 -0
  31. package/docs/pl/eslint.md +336 -0
  32. package/docs/pl/intlayer_with_astro.md +1 -114
  33. package/docs/pl/migration_from_i18next_to_intlayer.md +4 -0
  34. package/docs/pl/migration_from_next-i18next_to_intlayer.md +8 -4
  35. package/docs/pl/migration_from_next-intl_to_intlayer.md +11 -5
  36. package/docs/pl/migration_from_nuxtjs_i18n_to_intlayer.md +8 -4
  37. package/docs/pl/migration_from_react-i18next_to_intlayer.md +8 -4
  38. package/docs/pl/migration_from_vue-i18n_to_intlayer.md +4 -0
  39. package/docs/pt/eslint.md +336 -0
  40. package/docs/pt/intlayer_with_astro.md +1 -114
  41. package/docs/ru/eslint.md +336 -0
  42. package/docs/tr/eslint.md +336 -0
  43. package/docs/uk/eslint.md +336 -0
  44. package/docs/uk/packages/angular-intlayer/exports.md +2 -2
  45. package/docs/ur/eslint.md +336 -0
  46. package/docs/vi/eslint.md +336 -0
  47. package/docs/zh/eslint.md +336 -0
  48. package/docs/zh/intlayer_with_create_react_app.md +4 -0
  49. package/docs/zh/intlayer_with_lynx+react.md +4 -0
  50. package/docs/zh/intlayer_with_nextjs_14.md +0 -2
  51. package/docs/zh/intlayer_with_nextjs_15.md +0 -2
  52. package/docs/zh/intlayer_with_nextjs_page_router.md +0 -2
  53. package/docs/zh/intlayer_with_nuxt.md +1 -1
  54. package/docs/zh/intlayer_with_react_router_v7.md +4 -0
  55. package/docs/zh/intlayer_with_react_router_v7_fs_routes.md +4 -0
  56. package/docs/zh/intlayer_with_solid_start.md +1 -1
  57. package/docs/zh/intlayer_with_vite+vue.md +0 -2
  58. package/docs/zh-TW/eslint.md +336 -0
  59. package/package.json +6 -6
  60. package/src/generated/docs.entry.ts +20 -0
@@ -0,0 +1,336 @@
1
+ ---
2
+ createdAt: 2026-08-12
3
+ updatedAt: 2026-08-12
4
+ title: ESLint 플러그인 | Intlayer 린트 규칙
5
+ description: eslint-plugin-intlayer를 사용하여 하드코딩된 문자열, Intlayer 컴파일러가 최적화할 수 없는 동적 호출, 사용되지 않는 사전 콘텐츠를 감지하세요. React, Vue, Svelte, Angular 및 Astro 전반에서 ESLint 및 oxlint와 함께 작동합니다.
6
+ keywords:
7
+ - Intlayer
8
+ - ESLint
9
+ - oxlint
10
+ - 린팅
11
+ - i18n
12
+ - 국제화
13
+ - no-raw-text
14
+ - 하드코딩된 문자열
15
+ - 사용되지 않는 번역
16
+ - 미사용 콘텐츠
17
+ - React
18
+ - Vue
19
+ - Svelte
20
+ - Angular
21
+ slugs:
22
+ - doc
23
+ - eslint
24
+ history:
25
+ - version: 9.3.1
26
+ date: 2026-08-12
27
+ changes: "초기 히스토리"
28
+ author: aymericzip
29
+ ---
30
+
31
+ # ESLint x OXLint 플러그인
32
+
33
+ `eslint-plugin-intlayer`는 TypeScript가 감지하지 못하는 i18n 실수를 잡아냅니다:
34
+
35
+ 1. 사전에 등록되지 않은 **하드코딩된 텍스트**.
36
+ 2. 타입 검사를 통과하고 실행되지만 Intlayer 컴파일러가 최적화할 수 없는 **동적 호출**.
37
+ 3. **미사용 콘텐츠(Dead content)** — 프로젝트 내에서 아무 곳에서도 읽지 않는 사전 및 필드(선택 사항).
38
+
39
+ 알 수 없는 사전 키, 알 수 없는 필드 경로 및 누락된 로케일은 이미 컴파일 에러로 처리되므로 플러그인은 이를 중복 보고하지 않습니다.
40
+
41
+ ## 설치
42
+
43
+ ```bash packageManager="npm"
44
+ npm install --save-dev eslint-plugin-intlayer
45
+ ```
46
+
47
+ ```bash packageManager="pnpm"
48
+ pnpm add --save-dev eslint-plugin-intlayer
49
+ ```
50
+
51
+ ```bash packageManager="yarn"
52
+ yarn add --dev eslint-plugin-intlayer
53
+ ```
54
+
55
+ ESLint 9 이상(Flat config)이 필요합니다.
56
+
57
+ ## 사용법
58
+
59
+ 이 플러그인은 ESLint와 [oxlint](https://oxc.rs) 모두에서 동일한 규칙과 옵션으로 실행됩니다.
60
+
61
+ <Tabs defaultTab="eslint">
62
+ <Tab label="ESLint" value="eslint">
63
+
64
+ ```javascript fileName="eslint.config.mjs" codeFormat="esm"
65
+ import intlayer from "eslint-plugin-intlayer";
66
+
67
+ export default [...intlayer.configs.recommended];
68
+ ```
69
+
70
+ 또는 규칙을 하나씩 활성화할 수 있습니다:
71
+
72
+ ```javascript fileName="eslint.config.mjs" codeFormat="esm"
73
+ import intlayer from "eslint-plugin-intlayer";
74
+
75
+ export default [
76
+ {
77
+ plugins: { intlayer },
78
+ rules: {
79
+ "intlayer/no-raw-text": "warn",
80
+ "intlayer/static-dictionary-key": "error",
81
+ "intlayer/no-dynamic-field-access": "error",
82
+ "intlayer/enforce-adapter-import": "warn",
83
+ "intlayer/no-unused-content": "warn",
84
+ },
85
+ },
86
+ ];
87
+ ```
88
+
89
+ </Tab>
90
+ <Tab label="oxlint" value="oxlint">
91
+
92
+ ```json fileName=".oxlintrc.json"
93
+ {
94
+ "jsPlugins": ["eslint-plugin-intlayer"],
95
+ "rules": {
96
+ "intlayer/no-raw-text": "warn",
97
+ "intlayer/static-dictionary-key": "error",
98
+ "intlayer/no-dynamic-field-access": "error",
99
+ "intlayer/enforce-adapter-import": "warn"
100
+ }
101
+ }
102
+ ```
103
+
104
+ 두 가지 주의 사항: oxlint의 JS 플러그인 지원은 아직 알파 단계이며, 커스텀 파서를 지원하지 않으므로 `.vue`, `.svelte`, `.astro` 및 Angular 템플릿은 oxlint에서 린트되지 않습니다. JS/TS/JSX 파일에는 oxlint를 사용하고 나머지는 ESLint를 계속 사용하세요.
105
+
106
+ `no-unused-content`는 위에서 의도적으로 제외되었습니다. 이 규칙은 규칙 컨텍스트에서 작업 디렉터리와 린트 대상 파일 경로를 필요로 하지만, 알파 단계의 JS 플러그인 브리지에서는 이를 보장하지 못합니다. 이 규칙은 ESLint에서 실행하세요.
107
+
108
+ </Tab>
109
+ </Tabs>
110
+
111
+ ### 설정 (Configs)
112
+
113
+ | 설정 | `no-raw-text` | `static-dictionary-key` | `no-dynamic-field-access` | `enforce-adapter-import` | `no-unused-content` |
114
+ | --------------- | ----------------------- | ----------------------- | ------------------------- | ------------------------ | ------------------- |
115
+ | `recommended` | warn | error | error | off | off |
116
+ | `strict` | error (+ 비 JSX 리터럴) | error | error | error | off |
117
+ | `contract-only` | off | error | error | off | off |
118
+
119
+ `recommended`는 의도적으로 `no-raw-text`를 `warn`으로 유지합니다. 기존 코드베이스에 적용했을 때 번역되지 않은 모든 문자열이 한 번에 보고되어 첫날부터 빌드가 중단되는 것을 방지하기 위함입니다.
120
+
121
+ `enforce-adapter-import`는 기본적으로 꺼져 있습니다. 필요한 경우 명시적으로 활성화하세요.
122
+
123
+ `no-unused-content`는 `strict`를 포함한 모든 사전 설정에서 꺼져 있습니다. 이 규칙은 Intlayer 설정을 읽고 디스크의 소스 파일을 직접 순회하므로, 사전 설정에 의해 자동으로 켜지기보다는 신중한 선택에 따라 활성화해야 합니다.
124
+
125
+ ## 규칙
126
+
127
+ ### `no-raw-text`
128
+
129
+ 사전에 선언되지 않은 사용자 대면 텍스트를 보고합니다. `intlayer extract`와 동일한 감지 방식을 사용하므로 브랜드 이름, CSS 클래스 및 기술적 식별자는 무시됩니다.
130
+
131
+ ```jsx
132
+ // ✗ 보고됨
133
+ <h1>Welcome to our documentation</h1>
134
+ <input placeholder="Enter your email address" />
135
+
136
+ // ✓ 정상
137
+ const { title } = useIntlayer("home");
138
+ <h1>{title}</h1>
139
+ ```
140
+
141
+ 콘텐츠 선언 파일(`*.content.ts`, …)은 제외됩니다.
142
+
143
+ 파일 전체를 한 번에 수정하려면 `npx intlayer extract`를 실행하여 컴파일러가 문자열을 사전으로 이동하도록 하세요.
144
+
145
+ **옵션**
146
+
147
+ ```javascript fileName="eslint.config.mjs" codeFormat="esm"
148
+ {
149
+ "intlayer/no-raw-text": [
150
+ "warn",
151
+ {
152
+ // 사용자 대면 텍스트가 값인 속성
153
+ // 기본값: title, placeholder, alt, aria-label, label
154
+ attributes: ["title", "placeholder", "alt", "aria-label", "label"],
155
+
156
+ // 콘텐츠가 사용자 대면 텍스트가 아닌 요소
157
+ // 기본값: code, pre, script, style
158
+ ignoreElements: ["code", "pre", "script", "style"],
159
+
160
+ // 보고하지 않을 텍스트의 정규식
161
+ ignorePatterns: ["^Powered by"],
162
+
163
+ // 마크업 외부의 문자열 리터럴도 보고할지 여부. 기본값: false
164
+ includeStringLiterals: false,
165
+ },
166
+ ],
167
+ }
168
+ ```
169
+
170
+ ### `static-dictionary-key`
171
+
172
+ 사전 키가 반드시 문자열 리터럴이어야 합니다.
173
+
174
+ 컴파일러는 호출 위치에서 키를 직접 읽을 수 있을 때만 사전을 사전 로드(pre-load)할 수 있습니다. 계산된 키를 사용하면 최적화를 자동으로 건너뛰고 모든 사전을 번들에 포함합니다.
175
+
176
+ ```typescript
177
+ // ✗ 보고됨
178
+ useIntlayer(dictionaryKey);
179
+ useIntlayer(`home-${suffix}`);
180
+ getTranslations({ namespace: page });
181
+
182
+ // ✗ 변수는 리터럴이 아닙니다
183
+ const key = "home";
184
+ useIntlayer(key);
185
+
186
+ // ✓ 정상
187
+ useIntlayer("home");
188
+ getTranslations({ namespace: "home" });
189
+ ```
190
+
191
+ 이는 `useIntlayer`, `getIntlayer` 및 모든 호환 어댑터(`useTranslation`, `useTranslations`, `formatMessage`, `<FormattedMessage id>`, `<Trans i18nKey>`, …)에 적용됩니다.
192
+
193
+ ### `no-dynamic-field-access`
194
+
195
+ 사전에서 읽는 필드가 정적으로 알려져 있어야 합니다.
196
+
197
+ 컴파일러는 사용되지 않는 것으로 판단되는 필드를 제거합니다. 동적 접근은 컴파일러가 감지할 수 없으므로 런타임에 읽기 작업이 `undefined`를 반환할 수 있습니다.
198
+
199
+ ```typescript
200
+ // ✗ 보고됨
201
+ const content = useIntlayer("home");
202
+ content[fieldName];
203
+
204
+ const t = useTranslations("home");
205
+ t(messageKey);
206
+
207
+ // ✓ 정상
208
+ content.title;
209
+ content["title"];
210
+ content.items[0];
211
+ t("hero.title");
212
+ ```
213
+
214
+ ### `enforce-adapter-import`
215
+
216
+ 원본 패키지 대신 `@intlayer/*` 호환 어댑터의 사용을 권장합니다. 원본 패키지는 번들러 별칭이 설정된 경우에만 Intlayer로 확인되지만, 어댑터는 항상 확인됩니다. `--fix`로 자동 수정할 수 있습니다.
217
+
218
+ ```typescript
219
+ // ✗ 보고됨
220
+ import { useTranslation } from "react-i18next";
221
+ import { getTranslations } from "next-intl/server";
222
+
223
+ // ✓ 정상
224
+ import { useTranslation } from "@intlayer/react-i18next";
225
+ import { getTranslations } from "@intlayer/next-intl/server";
226
+ ```
227
+
228
+ ### `no-unused-content`
229
+
230
+ **기본적으로 꺼져 있습니다.** 프로젝트 내에서 아무 곳에서도 읽지 않는 콘텐츠와 여러 위치에서 선언된 사전 키를 보고합니다.
231
+
232
+ ```typescript fileName="src/home.content.ts"
233
+ export default {
234
+ key: "home", // ✗ 프로젝트 내 어떤 호출자도 "home"을 요청하지 않을 때 보고됨
235
+ content: {
236
+ title: t({ ko: "제목", en: "Title" }),
237
+
238
+ // ✗ `hero`를 읽는 곳이 없을 때 보고됨
239
+ hero: {
240
+ subtitle: t({ ko: "소제목", en: "Subtitle" }),
241
+ },
242
+ },
243
+ };
244
+ ```
245
+
246
+ 다른 규칙과 달리 이 규칙은 현재 파일 하나만으로 판단할 수 없습니다. 필드 사용 여부는 전체 프로젝트와의 관계에서만 파악할 수 있기 때문입니다. 린트 실행 시 첫 번째 콘텐츠 선언을 만났을 때 Intlayer 설정을 로드하고, 해당 설정에 선언된 소스 파일(`build.traversePattern`, `compiler.transformPattern`)을 수집한 후 `@intlayer/lsp` 및 VS Code 확장의 "미사용" 취소선을 지원하는 동일한 사용량 분석기를 실행합니다. 결과는 `cacheTtl` 밀리초 동안 캐시되므로 파일마다 검사하지 않고 1회 실행당 한 번만 검사를 수행합니다.
247
+
248
+ **옵션**
249
+
250
+ ```javascript fileName="eslint.config.mjs" codeFormat="esm"
251
+ {
252
+ "intlayer/no-unused-content": [
253
+ "warn",
254
+ {
255
+ // 아무 곳에서도 참조하지 않는 사전 키 보고. 기본값: true
256
+ reportUnusedDictionaries: true,
257
+
258
+ // 아무 곳에서도 읽지 않는 콘텐츠 필드 보고. 기본값: true
259
+ reportUnusedFields: true,
260
+
261
+ // 여러 위치에 선언된 중복 키 보고. 기본값: true
262
+ reportDuplicateKeys: true,
263
+
264
+ // 보고하지 않을 필드 경로의 정규식
265
+ ignoreFields: ["^meta"],
266
+
267
+ // 검사가 시작되는 프로젝트 루트. 기본값: ESLint 작업 디렉터리
268
+ baseDir: process.cwd(),
269
+
270
+ // 한 번의 프로젝트 검사 결과를 재사용하는 시간(ms). 기본값: 30000
271
+ cacheTtl: 30000,
272
+ },
273
+ ],
274
+ }
275
+ ```
276
+
277
+ 오랫동안 실행되는 에디터 서버에서 린트를 수행하며 변경 사항을 더 빨리 반영하고 싶을 때는 `cacheTtl`을 줄이세요. 모노레포에서 단일 린트 실행이 여러 Intlayer 프로젝트에 걸쳐 있을 때는 `baseDir`을 설정하세요.
278
+
279
+ > **침묵을 우선합니다.** 여기서 거짓 양성(false positive)이 발생하면 필요한 번역이 삭제될 수 있으므로, 분석기가 추적할 수 없는 방식으로 사전을 소비할 때는 아무것도 보고하지 않습니다: 콘텐츠 객체 전체를 그대로 전달, 객체에서 바인딩된 번역 함수(`const t = useTranslations("home")`), 직접 가져오기를 통한 선언 접근(`useDictionary(myDictionary)`), 다른 사전에서의 `nest()`, 또는 스프레드 연산자로 불완전해진 필드 목록 등입니다. 단일 파일 컴포넌트(`.vue`, `.svelte`, `.astro`)는 스크립트 블록이 여기서 파싱되지 않으므로 언급된 사전의 모든 필드를 사용하는 것으로 간주됩니다.
280
+
281
+ `reportDuplicateKeys`는 빌드 시 `.intlayer/`에 기록되는 병합되지 않은 사전을 읽으므로 프로젝트가 최소 한 번 빌드될 때까지는 동작하지 않습니다. 키를 공유하는 두 선언은 병합되며 이는 올바른 패턴입니다. 다만 양쪽에 정의된 필드가 조용히 둘 중 하나의 값만 유지하기 때문에 이 보고 기능이 제공됩니다.
282
+
283
+ 분석기는 ESM으로 제공되는 `@intlayer/lsp`에서 로드됩니다. 따라서 이 규칙은 ES 모듈을 `require()`할 수 있는 Node 버전(Node 20.19+ 또는 22.12+)이 필요합니다. 이전 버전에서는 린트 실행을 실패시키는 대신 아무것도 보고하지 않습니다.
284
+
285
+ ## 프레임워크
286
+
287
+ 모든 규칙은 Vue, Svelte 및 Angular 템플릿 내부를 포함하여 모든 Intlayer 통합 환경에서 작동합니다. ESLint에 각 파일 형식을 읽을 파서만 지정해 주면 됩니다.
288
+
289
+ | 프레임워크 | 파일 | 파서 |
290
+ | ------------------------- | ----------------- | --------------------------------- |
291
+ | React, Preact, Solid, Lit | `.jsx` `.tsx` | `typescript-eslint` |
292
+ | Next.js | `.jsx` `.tsx` | `typescript-eslint` |
293
+ | Vue, Nuxt | `.vue` | `vue-eslint-parser` |
294
+ | Svelte, SvelteKit | `.svelte` | `svelte-eslint-parser` |
295
+ | Angular | `.ts` | `typescript-eslint` |
296
+ | Angular 템플릿 | `.component.html` | `@angular-eslint/template-parser` |
297
+ | Astro | `.astro` | `astro-eslint-parser` |
298
+
299
+ ```javascript fileName="eslint.config.mjs" codeFormat="esm"
300
+ import intlayer from "eslint-plugin-intlayer";
301
+ import tseslint from "typescript-eslint";
302
+ import vueParser from "vue-eslint-parser";
303
+ import svelteParser from "svelte-eslint-parser";
304
+ import angularTemplateParser from "@angular-eslint/template-parser";
305
+
306
+ export default [
307
+ ...intlayer.configs.recommended,
308
+
309
+ {
310
+ files: ["**/*.{ts,tsx,jsx}"],
311
+ languageOptions: { parser: tseslint.parser },
312
+ },
313
+ {
314
+ files: ["**/*.vue"],
315
+ languageOptions: {
316
+ parser: vueParser,
317
+ parserOptions: { parser: tseslint.parser },
318
+ },
319
+ },
320
+ {
321
+ files: ["**/*.svelte"],
322
+ languageOptions: {
323
+ parser: svelteParser,
324
+ parserOptions: { parser: tseslint.parser },
325
+ },
326
+ },
327
+ {
328
+ files: ["**/*.component.html"],
329
+ languageOptions: { parser: angularTemplateParser },
330
+ },
331
+ ];
332
+ ```
333
+
334
+ 프로젝트에 필요한 파서만 설치하세요.
335
+
336
+ > **알려진 제한 사항.** Vue 및 Angular 템플릿에서 `{{ content[key] }}`와 같은 표현식은 `no-dynamic-field-access`에 의해 검사되지 않습니다. 스크립트 블록에 작성된 동적 읽기는 정상적으로 감지됩니다.
@@ -84,6 +84,10 @@ Intlayer는 단순한 i18n 솔루션 그 이상으로 관리에 도움이 되는
84
84
 
85
85
  ---
86
86
 
87
+ <Steps>
88
+
89
+ <Step number={1} title="의존성 설치">
90
+
87
91
  ### 패키지
88
92
 
89
93
  - **intlayer**
@@ -162,7 +162,7 @@ bun add vite-intlayer --dev
162
162
 
163
163
  </Step>
164
164
 
165
- </Steps>
165
+ <Step number={5} title="레이아웃 컴포넌트 생성">
166
166
 
167
167
  #### 파일 구조
168
168
 
@@ -266,10 +266,12 @@ export default preview;
266
266
 
267
267
  > `locale` 값은 `intlayer.config.ts`에 선언된 로케일과 일치해야 합니다.
268
268
 
269
+ </Step>
270
+ </Steps>
269
271
  </Tab>
270
272
  <Tab value="Webpack Setup">
271
273
 
272
- </Step>
274
+ <Steps>
273
275
 
274
276
  <Step number={1} title="종속성 설치">
275
277
 
@@ -391,15 +393,13 @@ const preview: Preview = {
391
393
  export default preview;
392
394
  ```
393
395
 
396
+ </Step>
397
+ </Steps>
394
398
  </Tab>
395
399
  </Tabs>
396
400
 
397
401
  ---
398
402
 
399
- </Step>
400
-
401
- </Steps>
402
-
403
403
  ## 콘텐츠 선언
404
404
 
405
405
  각 컴포넌트 옆에 `*.content.ts` 파일을 생성합니다. Intlayer는 컴파일 중에 이를 자동으로 감지합니다.