@intlayer/docs 9.0.0-canary.7 → 9.0.0-canary.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/generated/docs.entry.cjs +0 -20
- package/dist/cjs/generated/docs.entry.cjs.map +1 -1
- package/dist/esm/generated/docs.entry.mjs +0 -20
- package/dist/esm/generated/docs.entry.mjs.map +1 -1
- package/dist/types/generated/docs.entry.d.ts +0 -1
- package/dist/types/generated/docs.entry.d.ts.map +1 -1
- package/docs/ar/dynamic_dictionaries/index.md +24 -18
- package/docs/ar/dynamic_dictionaries/variants.md +280 -22
- package/docs/ar/plugins/sync-json.md +0 -1
- package/docs/ar/releases/v9.md +35 -12
- package/docs/de/dynamic_dictionaries/index.md +22 -22
- package/docs/de/dynamic_dictionaries/variants.md +272 -14
- package/docs/de/plugins/sync-json.md +0 -1
- package/docs/de/releases/v9.md +35 -12
- package/docs/en/dynamic_dictionaries/index.md +20 -14
- package/docs/en/dynamic_dictionaries/variants.md +266 -8
- package/docs/en/plugins/sync-json.md +0 -1
- package/docs/en/releases/v9.md +35 -12
- package/docs/en-GB/dynamic_dictionaries/index.md +21 -15
- package/docs/en-GB/dynamic_dictionaries/variants.md +268 -10
- package/docs/en-GB/plugins/sync-json.md +0 -1
- package/docs/en-GB/releases/v9.md +35 -12
- package/docs/es/dynamic_dictionaries/index.md +25 -19
- package/docs/es/dynamic_dictionaries/variants.md +275 -17
- package/docs/es/plugins/sync-json.md +0 -1
- package/docs/es/releases/v9.md +35 -12
- package/docs/fr/dynamic_dictionaries/index.md +26 -20
- package/docs/fr/dynamic_dictionaries/variants.md +273 -15
- package/docs/fr/plugins/sync-json.md +0 -1
- package/docs/fr/releases/v9.md +35 -12
- package/docs/hi/dynamic_dictionaries/index.md +28 -22
- package/docs/hi/dynamic_dictionaries/variants.md +282 -24
- package/docs/hi/plugins/sync-json.md +0 -1
- package/docs/hi/releases/v9.md +35 -12
- package/docs/id/dynamic_dictionaries/index.md +25 -19
- package/docs/id/dynamic_dictionaries/variants.md +274 -16
- package/docs/id/plugins/sync-json.md +0 -1
- package/docs/id/releases/v9.md +35 -12
- package/docs/it/dynamic_dictionaries/index.md +26 -20
- package/docs/it/dynamic_dictionaries/variants.md +273 -15
- package/docs/it/plugins/sync-json.md +0 -1
- package/docs/it/releases/v9.md +35 -12
- package/docs/ja/dynamic_dictionaries/index.md +27 -21
- package/docs/ja/dynamic_dictionaries/variants.md +276 -18
- package/docs/ja/plugins/sync-json.md +0 -1
- package/docs/ja/releases/v9.md +35 -12
- package/docs/ko/dynamic_dictionaries/index.md +23 -17
- package/docs/ko/dynamic_dictionaries/variants.md +273 -15
- package/docs/ko/plugins/sync-json.md +0 -1
- package/docs/ko/releases/v9.md +35 -12
- package/docs/pl/dynamic_dictionaries/index.md +26 -20
- package/docs/pl/dynamic_dictionaries/variants.md +275 -17
- package/docs/pl/plugins/sync-json.md +0 -1
- package/docs/pl/releases/v9.md +35 -12
- package/docs/pt/dynamic_dictionaries/index.md +25 -19
- package/docs/pt/dynamic_dictionaries/variants.md +276 -18
- package/docs/pt/plugins/sync-json.md +0 -1
- package/docs/pt/releases/v9.md +35 -12
- package/docs/ru/dynamic_dictionaries/index.md +25 -19
- package/docs/ru/dynamic_dictionaries/variants.md +277 -19
- package/docs/ru/plugins/sync-json.md +0 -1
- package/docs/ru/releases/v9.md +35 -12
- package/docs/tr/dynamic_dictionaries/index.md +27 -21
- package/docs/tr/dynamic_dictionaries/variants.md +274 -16
- package/docs/tr/plugins/sync-json.md +0 -1
- package/docs/tr/releases/v9.md +35 -12
- package/docs/uk/dynamic_dictionaries/index.md +25 -19
- package/docs/uk/dynamic_dictionaries/variants.md +277 -19
- package/docs/uk/plugins/sync-json.md +0 -1
- package/docs/uk/releases/v9.md +35 -12
- package/docs/vi/dynamic_dictionaries/index.md +28 -22
- package/docs/vi/dynamic_dictionaries/variants.md +278 -20
- package/docs/vi/plugins/sync-json.md +0 -1
- package/docs/vi/releases/v9.md +35 -12
- package/docs/zh/dynamic_dictionaries/index.md +24 -18
- package/docs/zh/dynamic_dictionaries/variants.md +274 -16
- package/docs/zh/plugins/sync-json.md +0 -1
- package/docs/zh/releases/v9.md +35 -12
- package/package.json +6 -6
- package/src/generated/docs.entry.ts +0 -20
- package/docs/ar/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/de/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/en/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/en-GB/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/es/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/fr/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/hi/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/id/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/it/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/ja/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/ko/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/pl/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/pt/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/ru/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/tr/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/uk/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/vi/dynamic_dictionaries/dynamic_content.md +0 -271
- package/docs/zh/dynamic_dictionaries/dynamic_content.md +0 -271
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2026-06-12
|
|
3
|
-
updatedAt: 2026-06-
|
|
3
|
+
updatedAt: 2026-06-26
|
|
4
4
|
title: 변형
|
|
5
|
-
description:
|
|
5
|
+
description: Intlayer 콘텐츠 파일에서 variant 메타데이터 필드를 사용하여 이름이 지정되었거나 구조화된 콘텐츠 대안 — A/B 테스트, 시즌 배너, 기능 플래그 텍스트, CMS 레코드, 사용자별 콘텐츠 — 을 선언하고 코드 변경 없이 런타임에 전환합니다.
|
|
6
6
|
keywords:
|
|
7
7
|
- 변형
|
|
8
8
|
- A/B 테스트
|
|
9
9
|
- 기능 플래그
|
|
10
10
|
- 동적 콘텐츠
|
|
11
|
+
- 동적 레코드
|
|
12
|
+
- CMS
|
|
11
13
|
- Intlayer
|
|
12
14
|
- 국제화
|
|
13
15
|
slugs:
|
|
@@ -17,17 +19,27 @@ slugs:
|
|
|
17
19
|
history:
|
|
18
20
|
- version: 9.0.0
|
|
19
21
|
date: 2026-06-12
|
|
20
|
-
changes: "변형
|
|
22
|
+
changes: "변형 기능 출시"
|
|
23
|
+
- version: 9.1.0
|
|
24
|
+
date: 2026-06-26
|
|
25
|
+
changes: "이제 `variant`는 문자열 또는 객체를 허용합니다 — 이전의 `meta` / 동적 레코드는 객체 변형으로 선언됩니다"
|
|
21
26
|
author: aymericzip
|
|
22
27
|
---
|
|
23
28
|
|
|
24
29
|
# 변형
|
|
25
30
|
|
|
26
|
-
|
|
31
|
+
**변형**은 동일한 사전 `key`를 공유하지만 각각 다른 `variant` 값을 갖는 콘텐츠 파일의 집합입니다. Intlayer는 `useIntlayer`에 전달된 셀렉터에 따라 적절한 파일을 제공합니다.
|
|
27
32
|
|
|
28
|
-
|
|
33
|
+
`variant` 값은 **두 가지 형태**를 가질 수 있습니다:
|
|
29
34
|
|
|
30
|
-
|
|
35
|
+
- **문자열** — 단일 이름 지정 대안(A/B 테스트, 시즌 배너, 기능 플래그).
|
|
36
|
+
- **객체** — 필드 집합으로 주소가 지정되는 구조화된 판별자(CMS 레코드, 사용자별 콘텐츠, 불투명한 ID로 키가 지정된 모든 콘텐츠). 객체 전체가 정체성입니다. 항목을 해결하려면 셀렉터가 **동일한** 객체를 제공해야 합니다.
|
|
37
|
+
|
|
38
|
+
> 객체 형태는 이전의 `meta` 필드를 대체합니다. 이전에 `meta: { id, … }`를 작성했던 모든 곳에서 `variant: { id, … }`를 작성하고 `{ variant: { id, … } }`로 선택하세요.
|
|
39
|
+
|
|
40
|
+
## 이름 지정(문자열) 변형
|
|
41
|
+
|
|
42
|
+
각 파일은 하나의 이름 지정 대안을 나타냅니다. `variant`를 생략하거나(`"default"`로 설정하면) 폴백으로 표시됩니다.
|
|
31
43
|
|
|
32
44
|
```ts fileName="hero-banner.content.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
33
45
|
import { t, type Dictionary } from "intlayer";
|
|
@@ -65,9 +77,9 @@ const dictionary = {
|
|
|
65
77
|
export default dictionary;
|
|
66
78
|
```
|
|
67
79
|
|
|
68
|
-
|
|
80
|
+
### 이름 지정 변형 사용
|
|
69
81
|
|
|
70
|
-
|
|
82
|
+
#### 기본 변형
|
|
71
83
|
|
|
72
84
|
<Tabs group="framework">
|
|
73
85
|
<Tab label="React" value="react">
|
|
@@ -209,7 +221,7 @@ export default dictionary;
|
|
|
209
221
|
</Tab>
|
|
210
222
|
</Tabs>
|
|
211
223
|
|
|
212
|
-
|
|
224
|
+
#### 이름 지정 변형
|
|
213
225
|
|
|
214
226
|
```tsx
|
|
215
227
|
const { headline, cta } = useIntlayer("hero-banner", {
|
|
@@ -217,18 +229,264 @@ const { headline, cta } = useIntlayer("hero-banner", {
|
|
|
217
229
|
});
|
|
218
230
|
```
|
|
219
231
|
|
|
220
|
-
|
|
232
|
+
#### 명시적 로케일이 있는 이름 지정 변형
|
|
221
233
|
|
|
222
234
|
```tsx
|
|
223
235
|
const content = useIntlayer("hero-banner", {
|
|
224
236
|
variant: "black_friday",
|
|
225
|
-
locale: "
|
|
237
|
+
locale: "fr",
|
|
226
238
|
});
|
|
227
239
|
```
|
|
228
240
|
|
|
241
|
+
## 객체(구조화) 변형
|
|
242
|
+
|
|
243
|
+
객체 변형은 `variant` 필드에 선언된 임의의 키-값 쌍 집합으로 콘텐츠의 주소를 지정합니다 — 이를 통해 CMS 레코드, 사용자별 콘텐츠, 또는 키가 불투명한 ID인 모든 콘텐츠를 모델링할 수 있습니다. **객체 전체**가 정체성입니다. 항목이 해결되려면 셀렉터가 동일한 객체를 제공해야 합니다.
|
|
244
|
+
|
|
245
|
+
```ts fileName="product.abc.content.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
246
|
+
import { t, type Dictionary } from "intlayer";
|
|
247
|
+
|
|
248
|
+
const dictionary = {
|
|
249
|
+
key: "product",
|
|
250
|
+
variant: { id: "prod_abc", userId: "user_123" },
|
|
251
|
+
content: {
|
|
252
|
+
name: t({ en: "Widget Pro", fr: "Widget Pro" }),
|
|
253
|
+
description: t({ en: "The best widget.", fr: "Le meilleur widget." }),
|
|
254
|
+
},
|
|
255
|
+
} satisfies Dictionary;
|
|
256
|
+
|
|
257
|
+
export default dictionary;
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
```ts fileName="product.abcd.content.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
261
|
+
import { t, type Dictionary } from "intlayer";
|
|
262
|
+
|
|
263
|
+
const dictionary = {
|
|
264
|
+
key: "product",
|
|
265
|
+
variant: { id: "prod_abcd", userId: "user_123" },
|
|
266
|
+
content: {
|
|
267
|
+
name: t({ en: "Widget Lite", fr: "Widget Lite" }),
|
|
268
|
+
description: t({ en: "A lighter option.", fr: "Une option plus légère." }),
|
|
269
|
+
},
|
|
270
|
+
} satisfies Dictionary;
|
|
271
|
+
|
|
272
|
+
export default dictionary;
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### 객체 변형 사용
|
|
276
|
+
|
|
277
|
+
일치하는 객체를 `variant`에 전달하세요. 사전에 선언된 모든 필드를 제공해야 하며 동일해야 합니다. 그렇지 않으면 결과는 `null`입니다. 필드 순서는 중요하지 않습니다.
|
|
278
|
+
|
|
279
|
+
<Tabs group="framework">
|
|
280
|
+
<Tab label="React" value="react">
|
|
281
|
+
```tsx fileName="Product.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
282
|
+
import { useIntlayer } from "react-intlayer";
|
|
283
|
+
|
|
284
|
+
export const Product = ({
|
|
285
|
+
productId,
|
|
286
|
+
userId,
|
|
287
|
+
}: {
|
|
288
|
+
productId: string;
|
|
289
|
+
userId: string;
|
|
290
|
+
}) => {
|
|
291
|
+
const content = useIntlayer("product", {
|
|
292
|
+
variant: { id: productId, userId },
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
if (!content) return null;
|
|
296
|
+
|
|
297
|
+
return <p>{content.description}</p>;
|
|
298
|
+
};
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
</Tab>
|
|
302
|
+
<Tab label="Next.js" value="nextjs">
|
|
303
|
+
```tsx fileName="Product.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
304
|
+
import { useIntlayer } from "next-intlayer";
|
|
305
|
+
|
|
306
|
+
export const Product = ({
|
|
307
|
+
productId,
|
|
308
|
+
userId,
|
|
309
|
+
}: {
|
|
310
|
+
productId: string;
|
|
311
|
+
userId: string;
|
|
312
|
+
}) => {
|
|
313
|
+
const content = useIntlayer("product", {
|
|
314
|
+
variant: { id: productId, userId },
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
if (!content) return null;
|
|
318
|
+
|
|
319
|
+
return <p>{content.description}</p>;
|
|
320
|
+
};
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
</Tab>
|
|
324
|
+
<Tab label="Vue" value="vue">
|
|
325
|
+
```vue fileName="Product.vue" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
326
|
+
<script setup>
|
|
327
|
+
import { useIntlayer } from "vue-intlayer";
|
|
328
|
+
|
|
329
|
+
const props = defineProps({
|
|
330
|
+
productId: String,
|
|
331
|
+
userId: String,
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
const content = useIntlayer("product", {
|
|
335
|
+
variant: { id: props.productId, userId: props.userId },
|
|
336
|
+
});
|
|
337
|
+
</script>
|
|
338
|
+
|
|
339
|
+
<template>
|
|
340
|
+
<p v-if="content">{{ content.description }}</p>
|
|
341
|
+
</template>
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
</Tab>
|
|
345
|
+
<Tab label="Svelte" value="svelte">
|
|
346
|
+
```svelte fileName="Product.svelte" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
347
|
+
<script lang="ts">
|
|
348
|
+
import { useIntlayer } from "svelte-intlayer";
|
|
349
|
+
|
|
350
|
+
export let productId: string;
|
|
351
|
+
export let userId: string;
|
|
352
|
+
|
|
353
|
+
const content = useIntlayer("product", {
|
|
354
|
+
variant: { id: productId, userId },
|
|
355
|
+
});
|
|
356
|
+
</script>
|
|
357
|
+
|
|
358
|
+
{#if $content}
|
|
359
|
+
<p>{$content.description}</p>
|
|
360
|
+
{/if}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
</Tab>
|
|
364
|
+
<Tab label="Preact" value="preact">
|
|
365
|
+
```tsx fileName="Product.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
366
|
+
import { useIntlayer } from "preact-intlayer";
|
|
367
|
+
|
|
368
|
+
export const Product = ({
|
|
369
|
+
productId,
|
|
370
|
+
userId,
|
|
371
|
+
}: {
|
|
372
|
+
productId: string;
|
|
373
|
+
userId: string;
|
|
374
|
+
}) => {
|
|
375
|
+
const content = useIntlayer("product", {
|
|
376
|
+
variant: { id: productId, userId },
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
if (!content) return null;
|
|
380
|
+
|
|
381
|
+
return <p>{content.description}</p>;
|
|
382
|
+
};
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
</Tab>
|
|
386
|
+
<Tab label="Solid" value="solid">
|
|
387
|
+
```tsx fileName="Product.tsx" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
388
|
+
import { useIntlayer } from "solid-intlayer";
|
|
389
|
+
|
|
390
|
+
export const Product = (props: {
|
|
391
|
+
productId: string;
|
|
392
|
+
userId: string;
|
|
393
|
+
}) => {
|
|
394
|
+
const content = useIntlayer("product", {
|
|
395
|
+
variant: { id: props.productId, userId: props.userId },
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
return (
|
|
399
|
+
<>
|
|
400
|
+
{content() && <p>{content().description}</p>}
|
|
401
|
+
</>
|
|
402
|
+
);
|
|
403
|
+
};
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
</Tab>
|
|
407
|
+
<Tab label="Angular" value="angular">
|
|
408
|
+
```typescript fileName="product.component.ts" contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
409
|
+
import { Component, Input, OnInit } from "@angular/core";
|
|
410
|
+
import { useIntlayer } from "angular-intlayer";
|
|
411
|
+
|
|
412
|
+
@Component({
|
|
413
|
+
selector: "app-product",
|
|
414
|
+
template: `
|
|
415
|
+
@if (content()) {
|
|
416
|
+
<p>{{ content().description }}</p>
|
|
417
|
+
}
|
|
418
|
+
`,
|
|
419
|
+
})
|
|
420
|
+
export class ProductComponent implements OnInit {
|
|
421
|
+
@Input() productId!: string;
|
|
422
|
+
@Input() userId!: string;
|
|
423
|
+
|
|
424
|
+
content: any;
|
|
425
|
+
|
|
426
|
+
ngOnInit() {
|
|
427
|
+
this.content = useIntlayer("product", {
|
|
428
|
+
variant: { id: this.productId, userId: this.userId },
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
</Tab>
|
|
435
|
+
<Tab label="Vanilla JS" value="vanilla">
|
|
436
|
+
```javascript fileName="product.js"
|
|
437
|
+
import { useIntlayer } from "vanilla-intlayer";
|
|
438
|
+
|
|
439
|
+
const content = useIntlayer("product", {
|
|
440
|
+
variant: { id: "prod_abcd", userId: "user_123" },
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
if (content) {
|
|
444
|
+
document.body.innerHTML = `<p>${content.description}</p>`;
|
|
445
|
+
}
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
</Tab>
|
|
449
|
+
</Tabs>
|
|
450
|
+
|
|
451
|
+
#### 명시적 로케일과 함께
|
|
452
|
+
|
|
453
|
+
```tsx
|
|
454
|
+
const content = useIntlayer("product", {
|
|
455
|
+
variant: { id: "prod_abc", userId: "user_123" },
|
|
456
|
+
locale: "fr",
|
|
457
|
+
});
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
#### 누락된 필드 — 일치 없음
|
|
461
|
+
|
|
462
|
+
```ts
|
|
463
|
+
// null 반환: `userId`가 누락되어 객체가 선언된 변형과 일치하지 않습니다
|
|
464
|
+
const content = useIntlayer("product", { variant: { id: "prod_abc" } });
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
## 로딩 모드
|
|
468
|
+
|
|
469
|
+
객체 변형은 종종 지연 로드됩니다. 이를 제어하려면 사전에 `importMode`를 설정하세요:
|
|
470
|
+
|
|
471
|
+
```ts contentDeclarationFormat={["typescript", "esm", "commonjs"]}
|
|
472
|
+
const dictionary = {
|
|
473
|
+
key: "product",
|
|
474
|
+
importMode: "fetch", // or "dynamic"
|
|
475
|
+
variant: { id: "prod_abc", userId: "user_123" },
|
|
476
|
+
content: { … },
|
|
477
|
+
} satisfies Dictionary;
|
|
478
|
+
|
|
479
|
+
export default dictionary;
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
`static`, `dynamic`, `fetch` 모드에 대한 자세한 내용은 [번들 최적화](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ko/bundle_optimization.md)를 참조하세요.
|
|
483
|
+
|
|
229
484
|
## 일반적인 사용 사례
|
|
230
485
|
|
|
231
|
-
- 실험
|
|
232
|
-
-
|
|
233
|
-
- 기능 플래그
|
|
234
|
-
-
|
|
486
|
+
- 실험 키로 구동되는 A/B 카피 테스트
|
|
487
|
+
- 시즌 또는 프로모션 배너
|
|
488
|
+
- 기능 플래그 메시지
|
|
489
|
+
- 로케일별 마케팅 캠페인
|
|
490
|
+
- CMS에서 관리되는 제품별 마케팅 카피
|
|
491
|
+
- 사용자별 또는 계정별 콘텐츠
|
|
492
|
+
- 런타임에 불투명한 ID로 키가 지정된 모든 콘텐츠
|
package/docs/ko/releases/v9.md
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2026-06-14
|
|
3
|
-
updatedAt: 2026-06-
|
|
3
|
+
updatedAt: 2026-06-26
|
|
4
4
|
title: 새로운 Intlayer v9 - 무엇이 달라졌나요?
|
|
5
|
-
description: Intlayer v9의 새로운 기능을 알아보세요. 인기 있는 i18n 라이브러리를 위한 드롭인 호환성 패키지와 컬렉션(Collections), 베리언트(Variants)
|
|
5
|
+
description: Intlayer v9의 새로운 기능을 알아보세요. 인기 있는 i18n 라이브러리를 위한 드롭인 호환성 패키지와 컬렉션(Collections), 베리언트(Variants) 지원을 소개합니다.
|
|
6
6
|
keywords:
|
|
7
7
|
- Intlayer
|
|
8
8
|
- 호환성
|
|
9
9
|
- 마이그레이션
|
|
10
10
|
- 컬렉션
|
|
11
11
|
- 베리언트
|
|
12
|
-
- 동적 레코드
|
|
13
12
|
- i18next
|
|
14
13
|
- next-intl
|
|
15
14
|
- vue-i18n
|
|
@@ -22,7 +21,7 @@ author: aymericzip
|
|
|
22
21
|
|
|
23
22
|
# 새로운 Intlayer v9 - 무엇이 달라졌나요?
|
|
24
23
|
|
|
25
|
-
Intlayer v9에 오신 것을 환영합니다! 이번 메이저 릴리스는 주요 i18n 라이브러리(`react-i18next`, `next-intl`, `vue-i18n` 등)를 위한 **호환 어댑터 패키지(Compat Adapter Packages)**를 통해 Intlayer로의 마이그레이션 경로를 획기적으로 단순화하고, **컬렉션(Collections)
|
|
24
|
+
Intlayer v9에 오신 것을 환영합니다! 이번 메이저 릴리스는 주요 i18n 라이브러리(`react-i18next`, `next-intl`, `vue-i18n` 등)를 위한 **호환 어댑터 패키지(Compat Adapter Packages)**를 통해 Intlayer로의 마이그레이션 경로를 획기적으로 단순화하고, **컬렉션(Collections)** 및 **베리언트(Variants)**와 같은 풍부한 콘텐츠 구조 지원을 추가하는 큰 이정표를 세웠습니다.
|
|
26
25
|
|
|
27
26
|
## 목차
|
|
28
27
|
|
|
@@ -41,8 +40,10 @@ Intlayer v9에 오신 것을 환영합니다! 이번 메이저 릴리스는 주
|
|
|
41
40
|
- `@intlayer/i18next`
|
|
42
41
|
- `@intlayer/react-i18next`
|
|
43
42
|
- `@intlayer/next-intl`
|
|
43
|
+
- `@intlayer/react-intl`
|
|
44
44
|
- `@intlayer/next-i18next`
|
|
45
45
|
- `@intlayer/vue-i18n`
|
|
46
|
+
- `@intlayer/lingui`
|
|
46
47
|
|
|
47
48
|
예를 들어, 다음과 같이 간단히 변경하면 됩니다:
|
|
48
49
|
|
|
@@ -100,7 +101,7 @@ export default defineConfig({
|
|
|
100
101
|
|
|
101
102
|
---
|
|
102
103
|
|
|
103
|
-
## 기능 사양:
|
|
104
|
+
## 기능 사양: 컬렉션 및 베리언트
|
|
104
105
|
|
|
105
106
|
Intlayer v9은 정적인 키-값 객체를 넘어, 딕셔너리가 처음부터 끝까지 완전히 타입 지정된 동적 레이아웃 구조를 선언할 수 있도록 확장되었습니다.
|
|
106
107
|
|
|
@@ -144,6 +145,8 @@ const faq = useIntlayer("faq", { item: 1 }); // -> { question: string, answer: s
|
|
|
144
145
|
|
|
145
146
|
A/B 테스트, 시즌별 헤더, 피처 플래그(feature flags) 또는 커스텀 랜딩 페이지를 제공합니다:
|
|
146
147
|
|
|
148
|
+
#### 문자열 베리언트 (예: A/B 테스트)
|
|
149
|
+
|
|
147
150
|
```ts fileName="hero.content.ts"
|
|
148
151
|
import { t, type Dictionary } from "intlayer";
|
|
149
152
|
|
|
@@ -167,16 +170,14 @@ export default {
|
|
|
167
170
|
const banner = useIntlayer("hero-banner", { variant: "black_friday" });
|
|
168
171
|
```
|
|
169
172
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
쿼리 ID를 통해 런타임에 동적으로 로드되는 항목을 가진 딕셔너리를 정의합니다:
|
|
173
|
+
#### 객체 베리언트 (예: 동적 레코드)
|
|
173
174
|
|
|
174
175
|
```ts fileName="product.content.ts"
|
|
175
176
|
import { t, type Dictionary } from "intlayer";
|
|
176
177
|
|
|
177
178
|
export default {
|
|
178
179
|
key: "product-copy",
|
|
179
|
-
|
|
180
|
+
variant: {
|
|
180
181
|
id: "prod_123",
|
|
181
182
|
category: "books",
|
|
182
183
|
},
|
|
@@ -229,7 +230,7 @@ export default defineConfig({
|
|
|
229
230
|
});
|
|
230
231
|
```
|
|
231
232
|
|
|
232
|
-
- **Compiler**: `compiler.enabled`가 설정되고 `compiler.output` 경로가 구성되면 자동으로 활성화됩니다. 더 이상 `intlayerCompiler()`를 별도로 등록할 필요가 없습니다.
|
|
233
|
+
- **Compiler**: `compiler.enabled`가 `true`로 설정되고 `compiler.output` 경로가 구성되면 자동으로 활성화됩니다. 더 이상 `intlayerCompiler()`를 별도로 등록할 필요가 없습니다.
|
|
233
234
|
- **Proxy**: 새로운 `routing.enableProxy` 옵션(`기본값: true`)을 기반으로 자동으로 활성화됩니다. 개발, 미리보기 및 프로덕션 SSR에서 로케일 감지 / 리다이렉트 / 재작성 미들웨어를 연결합니다. 더 이상 `intlayerProxy()`를 별도로 등록할 필요가 없습니다.
|
|
234
235
|
|
|
235
236
|
### `routing.enableProxy` 옵션
|
|
@@ -252,6 +253,27 @@ export default config;
|
|
|
252
253
|
|
|
253
254
|
---
|
|
254
255
|
|
|
256
|
+
## 컴파일러는 기본적으로 비활성화
|
|
257
|
+
|
|
258
|
+
Intlayer v9부터 **컴파일러는 기본적으로 비활성화됩니다**(`compiler.enabled`의 기본값이 이제 `false`입니다). `.content.ts` 파일의 빌드 타임 추출을 활성화하려면 구성에서 `compiler.enabled: true`를 설정하세요:
|
|
259
|
+
|
|
260
|
+
```ts fileName="intlayer.config.ts"
|
|
261
|
+
import type { IntlayerConfig } from "intlayer";
|
|
262
|
+
|
|
263
|
+
const config: IntlayerConfig = {
|
|
264
|
+
compiler: {
|
|
265
|
+
enabled: true, // 기본값: false — v9부터 컴파일러를 활성화하는 데 필요
|
|
266
|
+
output: ({ fileName }) => `./${fileName}.content.ts`,
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
export default config;
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
컴파일러가 비활성화되면 Intlayer는 빌드 타임 추출 단계를 건너뛰고 이미 선언한 딕셔너리에 의존합니다. 번들러 플러그인(`@intlayer/swc`, `@intlayer/babel` 또는 `intlayer()` Vite 플러그인)이 콘텐츠를 자동으로 추출하기를 원할 때만 활성화하세요.
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
255
277
|
## React Native: 단일 패키지 임포트
|
|
256
278
|
|
|
257
279
|
React Native 또는 Expo 앱에서는 더 이상 `react-intlayer`와 `react-native-intlayer`를 번갈아 사용할 필요가 없습니다. `react-native-intlayer` 패키지는 이제 **`react-intlayer`의 전체 API를 다시 내보내며** (훅, 유틸리티 및 `/format`, `/html`, `/markdown` 하위 경로), `IntlayerProvider`는 React Native 폴리필을 자동으로 적용합니다.
|
|
@@ -278,13 +300,14 @@ npm install intlayer react-native-intlayer
|
|
|
278
300
|
|
|
279
301
|
v8에서 업그레이드하는 경우, v9에는 하위 호환성을 깨뜨리는 변경 사항(breaking changes)이 포함되어 있지 않습니다. 하지만 다음과 같은 주요 변경 사항이 있습니다:
|
|
280
302
|
|
|
303
|
+
- **컴파일러는 기본적으로 비활성화**: `compiler.enabled`의 기본값이 이제 `false`입니다. `.content.ts` 파일의 빌드 타임 추출에 의존하는 경우 `intlayer.config.ts`에서 `compiler.enabled: true`를 설정하세요.
|
|
281
304
|
- **로케일 및 다이얼렉트 (Locales & Dialects)**: 외부 i18n 의존성을 사용하는 경우, 설정 또는 번들러 구성에 해당 호환 어댑터 플러그인을 추가하여 임포트를 자동으로 변환하세요.
|
|
282
|
-
- **커스텀 셀렉터 (Custom Selectors)**: `useIntlayer`를 호출할 때 두 번째 매개변수는 이제 `{ locale, item, variant
|
|
305
|
+
- **커스텀 셀렉터 (Custom Selectors)**: `useIntlayer`를 호출할 때 두 번째 매개변수는 이제 `{ locale, item, variant }`를 포함하는 옵션 객체 전용으로 예약됩니다. 이전에 로케일 문자열을 직접 전달했다면 여전히 그렇게 사용할 수 있지만, 고급 선택을 위해서는 옵션 객체를 사용하는 것을 권장합니다.
|
|
283
306
|
|
|
284
307
|
---
|
|
285
308
|
|
|
286
309
|
## 유용한 링크
|
|
287
310
|
|
|
288
311
|
- [호환 어댑터 패키지 가이드](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ko/compat/index.md)
|
|
289
|
-
- [동적 딕셔너리 -
|
|
312
|
+
- [동적 딕셔너리 - 컬렉션 및 베리언트](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ko/dynamic_dictionaries/index.md)
|
|
290
313
|
- [설정 레퍼런스](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ko/configuration.md)
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2026-06-12
|
|
3
|
-
updatedAt: 2026-06-
|
|
4
|
-
title: Słowniki
|
|
5
|
-
description:
|
|
3
|
+
updatedAt: 2026-06-26
|
|
4
|
+
title: Słowniki dynamiczne
|
|
5
|
+
description: Przegląd funkcji słowników dynamicznych Intlayer — kolekcji i wariantów — do tworzenia elastycznej, sterowanej w czasie wykonywania treści i18n.
|
|
6
6
|
keywords:
|
|
7
|
-
- Słowniki
|
|
7
|
+
- Słowniki dynamiczne
|
|
8
8
|
- Kolekcje
|
|
9
9
|
- Warianty
|
|
10
|
-
- Rekordy Dynamiczne
|
|
11
10
|
- Intlayer
|
|
12
|
-
-
|
|
11
|
+
- Internacjonalizacja
|
|
13
12
|
slugs:
|
|
14
13
|
- doc
|
|
15
14
|
- concept
|
|
@@ -18,31 +17,38 @@ history:
|
|
|
18
17
|
- version: 9.0.0
|
|
19
18
|
date: 2026-06-12
|
|
20
19
|
changes: "Wydanie funkcji słowników dynamicznych"
|
|
20
|
+
- version: 9.1.0
|
|
21
|
+
date: 2026-06-26
|
|
22
|
+
changes: "Scalono rekordy dynamiczne z wariantami — `variant` przyjmuje teraz ciąg znaków lub obiekt"
|
|
21
23
|
author: aymericzip
|
|
22
24
|
---
|
|
23
25
|
|
|
24
|
-
# Słowniki
|
|
26
|
+
# Słowniki dynamiczne
|
|
25
27
|
|
|
26
|
-
Intlayer obsługuje
|
|
28
|
+
Intlayer obsługuje dwa mechanizmy wyrażania treści wykraczającej poza pojedynczy statyczny słownik na klucz. Każdy jest deklarowany przez **pole metadanych najwyższego poziomu** w pliku treści; nie jest potrzebna żadna funkcja opakowująca.
|
|
27
29
|
|
|
28
|
-
| Funkcja
|
|
29
|
-
|
|
|
30
|
-
| [Kolekcje](https://github.com/aymericzip/intlayer/blob/main/docs/docs/pl/dynamic_dictionaries/collections.md)
|
|
31
|
-
| [Warianty](https://github.com/aymericzip/intlayer/blob/main/docs/docs/pl/dynamic_dictionaries/variants.md)
|
|
32
|
-
| [Rekordy Dynamiczne](https://github.com/aymericzip/intlayer/blob/main/docs/docs/pl/dynamic_dictionaries/dynamic_content.md) | `meta: { id, … }` | `{ id, … }` |
|
|
30
|
+
| Funkcja | Pole metadanych | Selektor w `useIntlayer` |
|
|
31
|
+
| ------------------------------------------------------------------------------------------------------------- | ---------------------------------------- | ------------------------------------------------ |
|
|
32
|
+
| [Kolekcje](https://github.com/aymericzip/intlayer/blob/main/docs/docs/pl/dynamic_dictionaries/collections.md) | `item: N` | `{ item: N }` |
|
|
33
|
+
| [Warianty](https://github.com/aymericzip/intlayer/blob/main/docs/docs/pl/dynamic_dictionaries/variants.md) | `variant: "name"` _lub_ `variant: { … }` | `{ variant: "name" }` _lub_ `{ variant: { … } }` |
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
Oba łączą się z argumentem locale i obsługują selektywne / leniwe ładowanie przez `importMode`.
|
|
35
36
|
|
|
36
|
-
## Kiedy używać
|
|
37
|
+
## Kiedy czego używać
|
|
37
38
|
|
|
38
39
|
- **Kolekcje** — uporządkowana lista elementów zarządzanych w osobnych plikach (wpisy FAQ, posty na blogu, produkty).
|
|
39
|
-
- **Warianty** — nazwane
|
|
40
|
-
-
|
|
40
|
+
- **Warianty** — nazwane lub strukturalne alternatywy treści:
|
|
41
|
+
- wariant **tekstowy** do testów A/B, banerów sezonowych lub feature flag;
|
|
42
|
+
- wariant **obiektowy** dla rekordów CMS, treści zależnej od użytkownika lub dowolnej treści adresowanej zestawem pól (dawne „rekordy dynamiczne").
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
> Wcześniejsze wersje udostępniały osobne pole `meta` dla treści indeksowanej rekordami. Zostało scalone z `variant`: przekaż do `variant` **obiekt** zamiast używać `meta`.
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
## Ujednoznacznianie selektora
|
|
47
|
+
|
|
48
|
+
Klucz może deklarować obydwa wymiary jednocześnie (np. kolekcja, której elementy mają wariant). Są one rozwiązywane w kolejności:
|
|
45
49
|
|
|
46
50
|
```
|
|
47
|
-
variant →
|
|
51
|
+
variant → item
|
|
48
52
|
```
|
|
53
|
+
|
|
54
|
+
Zatem `{ variant: "promo" }` dla klucza variant × item zwraca wszystkie elementy promo jako tablicę, a dodanie `{ item: 2 }` zawęża wynik do pojedynczego wpisu.
|