@intlayer/docs 7.3.14 → 7.4.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/blog/ar/intlayer_with_i18next.md +3 -0
- package/blog/ar/intlayer_with_next-i18next.md +3 -0
- package/blog/ar/intlayer_with_next-intl.md +3 -0
- package/blog/ar/intlayer_with_react-i18next.md +3 -0
- package/blog/ar/intlayer_with_react-intl.md +3 -0
- package/blog/ar/intlayer_with_vue-i18n.md +3 -0
- package/blog/de/intlayer_with_i18next.md +3 -0
- package/blog/de/intlayer_with_next-i18next.md +3 -0
- package/blog/de/intlayer_with_next-intl.md +3 -0
- package/blog/de/intlayer_with_react-i18next.md +3 -0
- package/blog/de/intlayer_with_react-intl.md +3 -0
- package/blog/de/intlayer_with_vue-i18n.md +3 -0
- package/blog/en/intlayer_with_i18next.md +7 -0
- package/blog/en/intlayer_with_next-i18next.md +3 -0
- package/blog/en/intlayer_with_next-intl.md +7 -0
- package/blog/en/intlayer_with_react-i18next.md +3 -0
- package/blog/en/intlayer_with_react-intl.md +3 -0
- package/blog/en/intlayer_with_vue-i18n.md +3 -0
- package/blog/en-GB/intlayer_with_i18next.md +3 -0
- package/blog/en-GB/intlayer_with_next-i18next.md +3 -0
- package/blog/en-GB/intlayer_with_next-intl.md +3 -0
- package/blog/en-GB/intlayer_with_react-i18next.md +3 -0
- package/blog/en-GB/intlayer_with_react-intl.md +3 -0
- package/blog/en-GB/intlayer_with_vue-i18n.md +3 -0
- package/blog/es/intlayer_with_i18next.md +3 -0
- package/blog/es/intlayer_with_next-i18next.md +3 -0
- package/blog/es/intlayer_with_next-intl.md +3 -0
- package/blog/es/intlayer_with_react-i18next.md +3 -0
- package/blog/es/intlayer_with_react-intl.md +3 -0
- package/blog/es/intlayer_with_vue-i18n.md +3 -0
- package/blog/fr/intlayer_with_i18next.md +3 -0
- package/blog/fr/intlayer_with_next-i18next.md +3 -0
- package/blog/fr/intlayer_with_next-intl.md +3 -0
- package/blog/fr/intlayer_with_react-i18next.md +3 -0
- package/blog/fr/intlayer_with_react-intl.md +3 -0
- package/blog/fr/intlayer_with_vue-i18n.md +3 -0
- package/blog/hi/intlayer_with_i18next.md +3 -0
- package/blog/hi/intlayer_with_next-i18next.md +3 -0
- package/blog/hi/intlayer_with_next-intl.md +3 -0
- package/blog/hi/intlayer_with_react-i18next.md +3 -0
- package/blog/hi/intlayer_with_react-intl.md +3 -0
- package/blog/hi/intlayer_with_vue-i18n.md +3 -0
- package/blog/id/intlayer_with_i18next.md +3 -0
- package/blog/id/intlayer_with_next-i18next.md +3 -0
- package/blog/id/intlayer_with_next-intl.md +3 -0
- package/blog/id/intlayer_with_react-i18next.md +3 -0
- package/blog/id/intlayer_with_react-intl.md +3 -0
- package/blog/id/intlayer_with_vue-i18n.md +3 -0
- package/blog/it/intlayer_with_i18next.md +3 -0
- package/blog/it/intlayer_with_next-i18next.md +3 -0
- package/blog/it/intlayer_with_next-intl.md +3 -0
- package/blog/it/intlayer_with_react-i18next.md +3 -0
- package/blog/it/intlayer_with_react-intl.md +3 -0
- package/blog/it/intlayer_with_vue-i18n.md +3 -0
- package/blog/ja/intlayer_with_i18next.md +3 -0
- package/blog/ja/intlayer_with_next-i18next.md +3 -0
- package/blog/ja/intlayer_with_next-intl.md +3 -0
- package/blog/ja/intlayer_with_react-i18next.md +3 -0
- package/blog/ja/intlayer_with_react-intl.md +3 -0
- package/blog/ja/intlayer_with_vue-i18n.md +3 -0
- package/blog/ko/intlayer_with_i18next.md +3 -0
- package/blog/ko/intlayer_with_next-i18next.md +3 -0
- package/blog/ko/intlayer_with_next-intl.md +3 -0
- package/blog/ko/intlayer_with_react-i18next.md +3 -0
- package/blog/ko/intlayer_with_react-intl.md +3 -0
- package/blog/ko/intlayer_with_vue-i18n.md +3 -0
- package/blog/pl/intlayer_with_i18next.md +3 -0
- package/blog/pl/intlayer_with_next-i18next.md +3 -0
- package/blog/pl/intlayer_with_next-intl.md +3 -0
- package/blog/pl/intlayer_with_react-i18next.md +3 -0
- package/blog/pl/intlayer_with_react-intl.md +3 -0
- package/blog/pl/intlayer_with_vue-i18n.md +3 -0
- package/blog/pt/intlayer_with_i18next.md +3 -0
- package/blog/pt/intlayer_with_next-i18next.md +3 -0
- package/blog/pt/intlayer_with_next-intl.md +3 -0
- package/blog/pt/intlayer_with_react-i18next.md +3 -0
- package/blog/pt/intlayer_with_react-intl.md +3 -0
- package/blog/pt/intlayer_with_vue-i18n.md +3 -0
- package/blog/ru/intlayer_with_i18next.md +3 -0
- package/blog/ru/intlayer_with_next-i18next.md +3 -0
- package/blog/ru/intlayer_with_next-intl.md +3 -0
- package/blog/ru/intlayer_with_react-i18next.md +3 -0
- package/blog/ru/intlayer_with_react-intl.md +3 -0
- package/blog/ru/intlayer_with_vue-i18n.md +3 -0
- package/blog/tr/intlayer_with_i18next.md +3 -0
- package/blog/tr/intlayer_with_next-i18next.md +3 -0
- package/blog/tr/intlayer_with_next-intl.md +3 -0
- package/blog/tr/intlayer_with_react-i18next.md +3 -0
- package/blog/tr/intlayer_with_vue-i18n.md +3 -0
- package/blog/vi/intlayer_with_i18next.md +3 -0
- package/blog/vi/intlayer_with_next-i18next.md +3 -0
- package/blog/vi/intlayer_with_next-intl.md +3 -0
- package/blog/vi/intlayer_with_react-i18next.md +3 -0
- package/blog/vi/intlayer_with_react-intl.md +3 -0
- package/blog/vi/intlayer_with_vue-i18n.md +3 -0
- package/blog/zh/intlayer_with_i18next.md +3 -0
- package/blog/zh/intlayer_with_next-i18next.md +3 -0
- package/blog/zh/intlayer_with_next-intl.md +3 -0
- package/blog/zh/intlayer_with_react-i18next.md +3 -0
- package/blog/zh/intlayer_with_react-intl.md +3 -0
- package/blog/zh/intlayer_with_vue-i18n.md +3 -0
- package/docs/ar/intlayer_with_lynx+react.md +1 -1
- package/docs/ar/intlayer_with_tanstack.md +132 -2
- package/docs/ar/intlayer_with_vite+react.md +99 -331
- package/docs/ar/plugins/sync-json.md +3 -0
- package/docs/de/intlayer_with_lynx+react.md +1 -1
- package/docs/de/intlayer_with_tanstack.md +132 -2
- package/docs/de/intlayer_with_vite+react.md +116 -380
- package/docs/de/plugins/sync-json.md +3 -0
- package/docs/en/intlayer_with_tanstack.md +131 -1
- package/docs/en/intlayer_with_vite+react.md +6 -10
- package/docs/en/plugins/sync-json.md +3 -0
- package/docs/en-GB/intlayer_with_tanstack.md +131 -1
- package/docs/en-GB/intlayer_with_vite+react.md +62 -74
- package/docs/en-GB/plugins/sync-json.md +3 -0
- package/docs/es/intlayer_with_tanstack.md +132 -2
- package/docs/es/intlayer_with_vite+react.md +101 -333
- package/docs/es/plugins/sync-json.md +3 -0
- package/docs/fr/intlayer_with_tanstack.md +132 -2
- package/docs/fr/intlayer_with_vite+react.md +101 -357
- package/docs/fr/plugins/sync-json.md +3 -0
- package/docs/hi/intlayer_with_tanstack.md +132 -2
- package/docs/hi/intlayer_with_vite+react.md +120 -333
- package/docs/hi/plugins/sync-json.md +3 -0
- package/docs/id/intlayer_with_tanstack.md +132 -2
- package/docs/id/intlayer_with_vite+react.md +7 -13
- package/docs/id/plugins/sync-json.md +3 -0
- package/docs/it/intlayer_with_lynx+react.md +1 -1
- package/docs/it/intlayer_with_tanstack.md +132 -2
- package/docs/it/intlayer_with_vite+react.md +121 -393
- package/docs/it/plugins/sync-json.md +3 -0
- package/docs/ja/intlayer_with_tanstack.md +132 -2
- package/docs/ja/intlayer_with_vite+react.md +106 -378
- package/docs/ja/plugins/sync-json.md +3 -0
- package/docs/ko/intlayer_with_lynx+react.md +1 -1
- package/docs/ko/intlayer_with_tanstack.md +132 -2
- package/docs/ko/intlayer_with_vite+react.md +90 -322
- package/docs/ko/plugins/sync-json.md +3 -0
- package/docs/pl/intlayer_with_tanstack.md +132 -2
- package/docs/pl/intlayer_with_vite+react.md +25 -21
- package/docs/pl/plugins/sync-json.md +3 -0
- package/docs/pt/intlayer_with_tanstack.md +132 -2
- package/docs/pt/intlayer_with_vite+react.md +96 -328
- package/docs/pt/plugins/sync-json.md +3 -0
- package/docs/ru/intlayer_with_lynx+react.md +1 -1
- package/docs/ru/intlayer_with_tanstack.md +132 -2
- package/docs/ru/intlayer_with_vite+react.md +109 -362
- package/docs/ru/plugins/sync-json.md +3 -0
- package/docs/tr/intlayer_with_tanstack.md +132 -2
- package/docs/tr/intlayer_with_vite+react.md +132 -366
- package/docs/tr/plugins/sync-json.md +3 -0
- package/docs/vi/intlayer_with_tanstack.md +132 -2
- package/docs/vi/intlayer_with_vite+react.md +16 -19
- package/docs/vi/plugins/sync-json.md +3 -0
- package/docs/zh/intlayer_with_tanstack.md +133 -3
- package/docs/zh/intlayer_with_vite+react.md +91 -374
- package/docs/zh/plugins/sync-json.md +3 -0
- package/frequent_questions/ar/customized_locale_list.md +1 -1
- package/frequent_questions/de/customized_locale_list.md +1 -1
- package/frequent_questions/en/customized_locale_list.md +1 -1
- package/frequent_questions/en-GB/customized_locale_list.md +1 -1
- package/frequent_questions/es/customized_locale_list.md +1 -1
- package/frequent_questions/fr/customized_locale_list.md +1 -1
- package/frequent_questions/hi/customized_locale_list.md +1 -1
- package/frequent_questions/id/customized_locale_list.md +1 -1
- package/frequent_questions/it/customized_locale_list.md +1 -1
- package/frequent_questions/ja/customized_locale_list.md +1 -1
- package/frequent_questions/ko/customized_locale_list.md +1 -1
- package/frequent_questions/pl/customized_locale_list.md +1 -1
- package/frequent_questions/pt/customized_locale_list.md +1 -1
- package/frequent_questions/ru/customized_locale_list.md +1 -1
- package/frequent_questions/tr/customized_locale_list.md +1 -1
- package/frequent_questions/vi/customized_locale_list.md +1 -1
- package/frequent_questions/zh/customized_locale_list.md +1 -1
- package/package.json +6 -6
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2024-03-07
|
|
3
|
-
updatedAt:
|
|
4
|
-
title: Vite
|
|
3
|
+
updatedAt: 2025-12-10
|
|
4
|
+
title: Vite 및 React 앱 번역하는 방법 – i18n 가이드 2025
|
|
5
5
|
description: Intlayer를 사용하여 Vite 및 React 애플리케이션에 국제화(i18n)를 추가하는 방법을 배우세요. 이 가이드를 따라 앱을 다국어로 만드세요.
|
|
6
6
|
keywords:
|
|
7
7
|
- 국제화
|
|
@@ -16,7 +16,7 @@ slugs:
|
|
|
16
16
|
- environment
|
|
17
17
|
- vite-and-react
|
|
18
18
|
applicationTemplate: https://github.com/aymericzip/intlayer-vite-react-template
|
|
19
|
-
youtubeVideo: https://www.youtube.com/watch?v=dS9L7uJeak4
|
|
19
|
+
youtubeVideo: https://www.youtube.com/watch?v=dS9L7uJeak4
|
|
20
20
|
history:
|
|
21
21
|
- version: 5.5.10
|
|
22
22
|
date: 2025-06-29
|
|
@@ -29,13 +29,9 @@ history:
|
|
|
29
29
|
|
|
30
30
|
<TOC/>
|
|
31
31
|
|
|
32
|
-
<iframe title="The best i18n solution for Vite and React? Discover Intlayer" class="m-auto aspect-[16/9] w-full overflow-hidden rounded-lg border-0" allow="autoplay; gyroscope;" loading="lazy" width="1080" height="auto" src="https://www.youtube.com/embed/dS9L7uJeak4?si=VaKmrYMmXjo3xpk2"/>
|
|
33
|
-
|
|
34
|
-
GitHub에서 [애플리케이션 템플릿](https://github.com/aymericzip/intlayer-vite-react-template)을 참조하세요.
|
|
35
|
-
|
|
36
32
|
## Intlayer란?
|
|
37
33
|
|
|
38
|
-
**Intlayer**는 최신 웹 애플리케이션에서 다국어 지원을 간소화하기 위해 설계된 혁신적이고 오픈
|
|
34
|
+
**Intlayer**는 최신 웹 애플리케이션에서 다국어 지원을 간소화하기 위해 설계된 혁신적이고 오픈 소스 국제화(i18n) 라이브러리입니다.
|
|
39
35
|
|
|
40
36
|
Intlayer를 사용하면 다음을 할 수 있습니다:
|
|
41
37
|
|
|
@@ -48,6 +44,27 @@ Intlayer를 사용하면 다음을 할 수 있습니다:
|
|
|
48
44
|
|
|
49
45
|
## Vite 및 React 애플리케이션에서 Intlayer 설정 단계별 가이드
|
|
50
46
|
|
|
47
|
+
<Tab defaultTab="video">
|
|
48
|
+
<TabItem label="비디오" value="video">
|
|
49
|
+
|
|
50
|
+
<iframe title="The best i18n solution for Vite and React? Discover Intlayer" class="m-auto aspect-[16/9] w-full overflow-hidden rounded-lg border-0" allow="autoplay; gyroscope;" loading="lazy" width="1080" height="auto" src="https://www.youtube.com/embed/dS9L7uJeak4?si=VaKmrYMmXjo3xpk2"/>
|
|
51
|
+
|
|
52
|
+
</TabItem>
|
|
53
|
+
<TabItem label="코드" value="code">
|
|
54
|
+
|
|
55
|
+
<iframe
|
|
56
|
+
src="https://stackblitz.com/github/aymericzip/intlayer-vite-react-template?embed=1&ctl=1&file=intlayer.config.ts"
|
|
57
|
+
className="m-auto overflow-hidden rounded-lg border-0 max-md:size-full max-md:h-[700px] md:aspect-16/9 md:w-full"
|
|
58
|
+
title="Demo CodeSandbox - Intlayer를 사용하여 애플리케이션을 국제화하는 방법"
|
|
59
|
+
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
|
|
60
|
+
loading="lazy"
|
|
61
|
+
/>
|
|
62
|
+
|
|
63
|
+
</TabItem>
|
|
64
|
+
</Tab>
|
|
65
|
+
|
|
66
|
+
GitHub에서 [Application Template](https://github.com/aymericzip/intlayer-vite-react-template)을 참조하세요.
|
|
67
|
+
|
|
51
68
|
### 1단계: 의존성 설치
|
|
52
69
|
|
|
53
70
|
npm을 사용하여 필요한 패키지를 설치하세요:
|
|
@@ -69,7 +86,7 @@ yarn add vite-intlayer --save-dev
|
|
|
69
86
|
|
|
70
87
|
- **intlayer**
|
|
71
88
|
|
|
72
|
-
|
|
89
|
+
구성 관리, 번역, [콘텐츠 선언](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ko/dictionary/content_file.md), 트랜스파일링 및 [CLI 명령어](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ko/cli/index.md)를 위한 국제화 도구를 제공하는 핵심 패키지입니다.
|
|
73
90
|
|
|
74
91
|
- **react-intlayer**
|
|
75
92
|
Intlayer를 React 애플리케이션과 통합하는 패키지로, React 국제화를 위한 컨텍스트 프로바이더와 훅을 제공합니다.
|
|
@@ -422,7 +439,7 @@ module.exports = appContent;
|
|
|
422
439
|
|
|
423
440
|
> 애플리케이션 내 어디에서든 `contentDir` 디렉토리(기본값: `./src`)에 포함되면 콘텐츠 선언을 정의할 수 있습니다. 그리고 콘텐츠 선언 파일 확장자(기본값: `.content.{json,ts,tsx,js,jsx,mjs,mjx,cjs,cjx}`)와 일치해야 합니다.
|
|
424
441
|
|
|
425
|
-
> 자세한 내용은 [콘텐츠 선언 문서](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ko/dictionary/
|
|
442
|
+
> 자세한 내용은 [콘텐츠 선언 문서](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ko/dictionary/content_file.md)를 참조하세요.
|
|
426
443
|
|
|
427
444
|
> 콘텐츠 파일에 TSX 코드가 포함된 경우, 콘텐츠 파일에 `import React from "react";`를 가져오는 것을 고려해야 합니다.
|
|
428
445
|
|
|
@@ -641,82 +658,10 @@ const LocaleSwitcher = () => {
|
|
|
641
658
|
애플리케이션에 지역화된 라우팅을 추가하려면, 애플리케이션의 라우트를 감싸고 로케일 기반 라우팅을 처리하는 `LocaleRouter` 컴포넌트를 생성할 수 있습니다. 다음은 [React Router](https://reactrouter.com/home)를 사용한 예제입니다:
|
|
642
659
|
|
|
643
660
|
```tsx fileName="src/components/LocaleRouter.tsx" codeFormat="typescript"
|
|
644
|
-
//
|
|
645
|
-
import { type Locales, configuration, getPathWithoutLocale } from "intlayer"; // 'intlayer'에서 제공하는 유틸리티 함수 및 타입
|
|
661
|
+
import { localeMap } from "intlayer"; // 'intlayer'에서 제공하는 유틸리티 함수 및 타입
|
|
646
662
|
import type { FC, PropsWithChildren } from "react"; // 함수형 컴포넌트 및 props 타입
|
|
647
663
|
import { IntlayerProvider } from "react-intlayer"; // 국제화 컨텍스트를 위한 프로바이더
|
|
648
|
-
import {
|
|
649
|
-
BrowserRouter,
|
|
650
|
-
Routes,
|
|
651
|
-
Route,
|
|
652
|
-
Navigate,
|
|
653
|
-
useLocation,
|
|
654
|
-
} from "react-router-dom"; // 네비게이션 관리를 위한 라우터 컴포넌트
|
|
655
|
-
|
|
656
|
-
// Intlayer에서 설정값 구조 분해 할당
|
|
657
|
-
const { internationalization, middleware } = configuration;
|
|
658
|
-
const { locales, defaultLocale } = internationalization;
|
|
659
|
-
|
|
660
|
-
/**
|
|
661
|
-
* 로컬라이제이션을 처리하고 자식 컴포넌트를 적절한 로케일 컨텍스트로 감싸는 컴포넌트입니다.
|
|
662
|
-
* URL 기반 로케일 감지 및 검증을 관리합니다.
|
|
663
|
-
*/
|
|
664
|
-
const AppLocalized: FC<PropsWithChildren<{ locale: Locales }>> = ({
|
|
665
|
-
children,
|
|
666
|
-
locale,
|
|
667
|
-
}) => {
|
|
668
|
-
const { pathname, search } = useLocation(); // 현재 URL 경로를 가져옵니다.
|
|
669
|
-
|
|
670
|
-
// 현재 로케일을 결정하며, 제공되지 않은 경우 기본 로케일로 대체합니다.
|
|
671
|
-
const currentLocale = locale ?? defaultLocale;
|
|
672
|
-
|
|
673
|
-
// 경로에서 로케일 접두사를 제거하여 기본 경로를 만듭니다.
|
|
674
|
-
const pathWithoutLocale = getPathWithoutLocale(
|
|
675
|
-
pathname // 현재 URL 경로
|
|
676
|
-
);
|
|
677
|
-
|
|
678
|
-
/**
|
|
679
|
-
* middleware.prefixDefault가 true인 경우, 기본 로케일은 항상 접두사로 붙어야 합니다.
|
|
680
|
-
*/
|
|
681
|
-
if (middleware.prefixDefault) {
|
|
682
|
-
// 로케일 유효성 검사
|
|
683
|
-
if (!locale || !locales.includes(locale)) {
|
|
684
|
-
// 업데이트된 경로와 함께 기본 로케일로 리다이렉트합니다.
|
|
685
|
-
return (
|
|
686
|
-
<Navigate
|
|
687
|
-
to={`/${defaultLocale}/${pathWithoutLocale}${search}`}
|
|
688
|
-
replace // 현재 기록 항목을 새 항목으로 교체합니다
|
|
689
|
-
/>
|
|
690
|
-
);
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
// 자식 컴포넌트를 IntlayerProvider로 감싸고 현재 로케일을 설정합니다
|
|
694
|
-
return (
|
|
695
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
696
|
-
);
|
|
697
|
-
} else {
|
|
698
|
-
/**
|
|
699
|
-
* middleware.prefixDefault가 false일 때, 기본 로케일은 접두사가 붙지 않습니다.
|
|
700
|
-
* 현재 로케일이 유효하며 기본 로케일이 아님을 확인합니다.
|
|
701
|
-
*/
|
|
702
|
-
if (
|
|
703
|
-
currentLocale.toString() !== defaultLocale.toString() &&
|
|
704
|
-
!locales
|
|
705
|
-
.filter(
|
|
706
|
-
(locale) => locale.toString() !== defaultLocale.toString() // 기본 로케일 제외
|
|
707
|
-
)
|
|
708
|
-
.includes(currentLocale) // 현재 로케일이 유효한 로케일 목록에 있는지 확인
|
|
709
|
-
) {
|
|
710
|
-
// 로케일 접두어가 없는 경로로 리디렉션
|
|
711
|
-
return <Navigate to={`${pathWithoutLocale}${search}`} replace />;
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
// IntlayerProvider로 자식 컴포넌트를 감싸고 현재 로케일 설정
|
|
715
|
-
return (
|
|
716
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
717
|
-
);
|
|
718
|
-
}
|
|
719
|
-
};
|
|
664
|
+
import { BrowserRouter, Route, Routes } from "react-router-dom"; // 네비게이션 관리를 위한 라우터 컴포넌트
|
|
720
665
|
|
|
721
666
|
/**
|
|
722
667
|
* 로케일별 경로를 설정하는 라우터 컴포넌트입니다.
|
|
@@ -725,257 +670,81 @@ const AppLocalized: FC<PropsWithChildren<{ locale: Locales }>> = ({
|
|
|
725
670
|
export const LocaleRouter: FC<PropsWithChildren> = ({ children }) => (
|
|
726
671
|
<BrowserRouter>
|
|
727
672
|
<Routes>
|
|
728
|
-
{
|
|
729
|
-
|
|
730
|
-
(
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
/>
|
|
739
|
-
))}
|
|
740
|
-
|
|
741
|
-
{
|
|
742
|
-
// 기본 로케일 접두어 사용이 비활성화된 경우, 루트 경로에서 직접 children을 렌더링
|
|
743
|
-
!middleware.prefixDefault && (
|
|
744
|
-
<Route
|
|
745
|
-
path="*"
|
|
746
|
-
element={
|
|
747
|
-
<AppLocalized locale={defaultLocale}>{children}</AppLocalized>
|
|
748
|
-
} // 로케일 관리를 위해 children을 래핑
|
|
749
|
-
/>
|
|
750
|
-
)
|
|
751
|
-
}
|
|
673
|
+
{localeMap(({ locale, urlPrefix }) => (
|
|
674
|
+
<Route
|
|
675
|
+
// 로케일을 캡처하는 경로 패턴 (예: /en/, /fr/) 및 이후 모든 경로와 매칭
|
|
676
|
+
path={`${urlPrefix}/*`}
|
|
677
|
+
key={locale}
|
|
678
|
+
element={
|
|
679
|
+
<IntlayerProvider locale={locale}>{children}</IntlayerProvider>
|
|
680
|
+
} // 로케일 관리를 위해 children을 래핑
|
|
681
|
+
/>
|
|
682
|
+
))}
|
|
752
683
|
</Routes>
|
|
753
684
|
</BrowserRouter>
|
|
754
685
|
);
|
|
755
686
|
```
|
|
756
687
|
|
|
757
688
|
```jsx fileName="src/components/LocaleRouter.mjx" codeFormat="esm"
|
|
758
|
-
//
|
|
759
|
-
import {
|
|
760
|
-
|
|
761
|
-
import {
|
|
762
|
-
import {
|
|
763
|
-
BrowserRouter,
|
|
764
|
-
Routes,
|
|
765
|
-
Route,
|
|
766
|
-
Navigate,
|
|
767
|
-
useLocation,
|
|
768
|
-
} from "react-router-dom"; // 네비게이션 관리를 위한 라우터 컴포넌트들
|
|
769
|
-
|
|
770
|
-
// Intlayer에서 설정을 구조 분해 할당합니다.
|
|
771
|
-
const { internationalization, middleware } = configuration;
|
|
772
|
-
const { locales, defaultLocale } = internationalization;
|
|
773
|
-
|
|
774
|
-
/**
|
|
775
|
-
* 로컬라이제이션을 처리하고 자식 컴포넌트를 적절한 로케일 컨텍스트로 감싸는 컴포넌트입니다.
|
|
776
|
-
/**
|
|
777
|
-
* URL 기반 로케일 감지 및 검증을 관리합니다.
|
|
778
|
-
*/
|
|
779
|
-
const AppLocalized = ({ children, locale }) => {
|
|
780
|
-
const { pathname, search } = useLocation(); // 현재 URL 경로를 가져옵니다.
|
|
781
|
-
|
|
782
|
-
// 현재 로케일을 결정하며, 제공되지 않은 경우 기본 로케일로 대체합니다.
|
|
783
|
-
const currentLocale = locale ?? defaultLocale;
|
|
784
|
-
|
|
785
|
-
// 경로에서 로케일 접두사를 제거하여 기본 경로를 구성합니다.
|
|
786
|
-
const pathWithoutLocale = getPathWithoutLocale(
|
|
787
|
-
pathname // 현재 URL 경로
|
|
788
|
-
);
|
|
789
|
-
|
|
790
|
-
/**
|
|
791
|
-
* middleware.prefixDefault가 true인 경우, 기본 로케일은 항상 접두사로 붙어야 합니다.
|
|
792
|
-
*/
|
|
793
|
-
if (middleware.prefixDefault) {
|
|
794
|
-
// 로케일을 검증합니다.
|
|
795
|
-
if (!locale || !locales.includes(locale)) {
|
|
796
|
-
// 업데이트된 경로와 함께 기본 로케일로 리다이렉트합니다.
|
|
797
|
-
return (
|
|
798
|
-
<Navigate
|
|
799
|
-
to={`/${defaultLocale}/${pathWithoutLocale}${search}`}
|
|
800
|
-
replace // 현재 기록 항목을 새 항목으로 교체합니다
|
|
801
|
-
/>
|
|
802
|
-
);
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
// 자식 컴포넌트를 IntlayerProvider로 감싸고 현재 로케일을 설정합니다
|
|
806
|
-
return (
|
|
807
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
808
|
-
);
|
|
809
|
-
} else {
|
|
810
|
-
/**
|
|
811
|
-
* middleware.prefixDefault가 false일 때, 기본 로케일은 접두사가 붙지 않습니다.
|
|
812
|
-
* 현재 로케일이 유효하며 기본 로케일이 아님을 확인합니다.
|
|
813
|
-
*/
|
|
814
|
-
if (
|
|
815
|
-
currentLocale.toString() !== defaultLocale.toString() &&
|
|
816
|
-
!locales
|
|
817
|
-
.filter(
|
|
818
|
-
(locale) => locale.toString() !== defaultLocale.toString() // 기본 로케일 제외
|
|
819
|
-
)
|
|
820
|
-
.includes(currentLocale) // 현재 로케일이 유효한 로케일 목록에 있는지 확인
|
|
821
|
-
) {
|
|
822
|
-
// 로케일 접두사가 없는 경로로 리디렉션
|
|
823
|
-
return <Navigate to={`${pathWithoutLocale}${search}`} replace />;
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
// IntlayerProvider로 자식 컴포넌트를 감싸고 현재 로케일 설정
|
|
827
|
-
return (
|
|
828
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
829
|
-
);
|
|
830
|
-
}
|
|
831
|
-
};
|
|
689
|
+
import { localeMap } from 'intlayer'; // 'intlayer'에서 제공하는 유틸리티 함수와 타입
|
|
690
|
+
import type { FC, PropsWithChildren } from 'react'; // 함수형 컴포넌트와 props 타입을 위한 React 타입
|
|
691
|
+
import { IntlayerProvider } from 'react-intlayer'; // 국제화 컨텍스트를 위한 프로바이더
|
|
692
|
+
import { BrowserRouter, Route, Routes } from 'react-router-dom'; // 네비게이션 관리를 위한 라우터 컴포넌트들
|
|
832
693
|
|
|
833
694
|
/**
|
|
834
695
|
* 로케일별 경로를 설정하는 라우터 컴포넌트입니다.
|
|
835
696
|
* React Router를 사용하여 내비게이션을 관리하고 로컬라이즈된 컴포넌트를 렌더링합니다.
|
|
836
697
|
*/
|
|
837
|
-
export const LocaleRouter = ({ children }) => (
|
|
698
|
+
export const LocaleRouter: FC<PropsWithChildren> = ({ children }) => (
|
|
838
699
|
<BrowserRouter>
|
|
839
700
|
<Routes>
|
|
840
|
-
{
|
|
841
|
-
|
|
842
|
-
(
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
/>
|
|
851
|
-
))}
|
|
852
|
-
|
|
853
|
-
{
|
|
854
|
-
// 기본 로케일 접두어 사용이 비활성화된 경우, 루트 경로에서 자식 컴포넌트를 직접 렌더링
|
|
855
|
-
!middleware.prefixDefault && (
|
|
856
|
-
<Route
|
|
857
|
-
path="*"
|
|
858
|
-
element={
|
|
859
|
-
<AppLocalized locale={defaultLocale}>{children}</AppLocalized>
|
|
860
|
-
} // 자식 컴포넌트를 로케일 관리로 감쌈
|
|
861
|
-
/>
|
|
862
|
-
)
|
|
863
|
-
}
|
|
701
|
+
{localeMap(({ locale, urlPrefix }) => (
|
|
702
|
+
<Route
|
|
703
|
+
// 로케일을 캡처하는 라우트 패턴 (예: /en/, /fr/) 및 이후 모든 경로와 매칭
|
|
704
|
+
path={`${urlPrefix}/*`}
|
|
705
|
+
key={locale}
|
|
706
|
+
element={
|
|
707
|
+
<IntlayerProvider locale={locale}>{children}</IntlayerProvider>
|
|
708
|
+
} // 자식 컴포넌트를 로케일 관리로 감쌈
|
|
709
|
+
/>
|
|
710
|
+
))}
|
|
864
711
|
</Routes>
|
|
865
712
|
</BrowserRouter>
|
|
866
713
|
);
|
|
867
714
|
```
|
|
868
715
|
|
|
869
716
|
```jsx fileName="src/components/LocaleRouter.cjx" codeFormat="commonjs"
|
|
870
|
-
//
|
|
871
|
-
const
|
|
872
|
-
const { IntlayerProvider
|
|
873
|
-
const {
|
|
874
|
-
BrowserRouter,
|
|
875
|
-
Routes,
|
|
876
|
-
Route,
|
|
877
|
-
Navigate,
|
|
878
|
-
useLocation,
|
|
879
|
-
} = require("react-router-dom"); // 내비게이션 관리를 위한 라우터 컴포넌트
|
|
880
|
-
|
|
881
|
-
// Intlayer에서 설정을 구조 분해 할당합니다.
|
|
882
|
-
const { internationalization, middleware } = configuration;
|
|
883
|
-
const { locales, defaultLocale } = internationalization;
|
|
884
|
-
|
|
885
|
-
/**
|
|
886
|
-
* 로컬라이제이션을 처리하고 자식 컴포넌트를 적절한 로케일 컨텍스트로 감싸는 컴포넌트입니다.
|
|
887
|
-
* URL 기반 로케일 감지 및 검증을 관리합니다.
|
|
888
|
-
*/
|
|
889
|
-
const AppLocalized = ({ children, locale }) => {
|
|
890
|
-
const { pathname, search } = useLocation(); // 현재 URL 경로를 가져옵니다.
|
|
891
|
-
|
|
892
|
-
// 현재 로케일을 결정하며, 제공되지 않은 경우 기본 로케일로 대체합니다.
|
|
893
|
-
const currentLocale = locale ?? defaultLocale;
|
|
894
|
-
|
|
895
|
-
// 경로에서 로케일 접두사를 제거하여 기본 경로를 만듭니다.
|
|
896
|
-
const pathWithoutLocale = getPathWithoutLocale(
|
|
897
|
-
pathname // 현재 URL 경로
|
|
898
|
-
);
|
|
899
|
-
|
|
900
|
-
/**
|
|
901
|
-
* middleware.prefixDefault가 true인 경우, 기본 로케일은 항상 접두사로 붙어야 합니다.
|
|
902
|
-
*/
|
|
903
|
-
if (middleware.prefixDefault) {
|
|
904
|
-
// 로케일을 검증합니다.
|
|
905
|
-
if (!locale || !locales.includes(locale)) {
|
|
906
|
-
// 업데이트된 경로와 함께 기본 로케일로 리다이렉트합니다.
|
|
907
|
-
return (
|
|
908
|
-
<Navigate
|
|
909
|
-
to={`/${defaultLocale}/${pathWithoutLocale}${search}`}
|
|
910
|
-
replace // 현재 기록 항목을 새 항목으로 교체
|
|
911
|
-
/>
|
|
912
|
-
);
|
|
913
|
-
}
|
|
914
|
-
|
|
915
|
-
// 자식 컴포넌트를 IntlayerProvider로 감싸고 현재 로케일을 설정
|
|
916
|
-
return (
|
|
917
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
918
|
-
);
|
|
919
|
-
} else {
|
|
920
|
-
/**
|
|
921
|
-
* middleware.prefixDefault가 false일 때, 기본 로케일은 접두사가 붙지 않습니다.
|
|
922
|
-
* 현재 로케일이 유효하며 기본 로케일이 아님을 확인합니다.
|
|
923
|
-
*/
|
|
924
|
-
if (
|
|
925
|
-
currentLocale.toString() !== defaultLocale.toString() &&
|
|
926
|
-
!locales
|
|
927
|
-
.filter(
|
|
928
|
-
(locale) => locale.toString() !== defaultLocale.toString() // 기본 로케일 제외
|
|
929
|
-
)
|
|
930
|
-
.includes(currentLocale) // 현재 로케일이 유효한 로케일 목록에 포함되어 있는지 확인
|
|
931
|
-
) {
|
|
932
|
-
// 로케일 접두사가 없는 경로로 리디렉션합니다.
|
|
933
|
-
return <Navigate to={`${pathWithoutLocale}${search}`} replace />;
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
// 자식 컴포넌트를 IntlayerProvider로 감싸고 현재 로케일을 설정합니다.
|
|
937
|
-
return (
|
|
938
|
-
<IntlayerProvider locale={currentLocale}>{children}</IntlayerProvider>
|
|
939
|
-
);
|
|
940
|
-
}
|
|
941
|
-
};
|
|
717
|
+
const { localeMap } = require("intlayer"); // 'intlayer'에서 제공하는 유틸리티 함수 및 타입
|
|
718
|
+
const React = require("react"); // React를 가져옵니다
|
|
719
|
+
const { IntlayerProvider } = require("react-intlayer"); // 국제화 컨텍스트를 위한 프로바이더
|
|
720
|
+
const { BrowserRouter, Route, Routes } = require("react-router-dom"); // 내비게이션 관리를 위한 라우터 컴포넌트
|
|
942
721
|
|
|
943
722
|
/**
|
|
944
723
|
* 로케일별 경로를 설정하는 라우터 컴포넌트입니다.
|
|
945
724
|
* React Router를 사용하여 내비게이션을 관리하고 로컬라이즈된 컴포넌트를 렌더링합니다.
|
|
946
725
|
*/
|
|
947
|
-
const LocaleRouter = ({ children }) =>
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
726
|
+
const LocaleRouter = ({ children }) =>
|
|
727
|
+
React.createElement(
|
|
728
|
+
BrowserRouter,
|
|
729
|
+
{},
|
|
730
|
+
React.createElement(
|
|
731
|
+
Routes,
|
|
732
|
+
{},
|
|
733
|
+
localeMap(({ locale, urlPrefix }) =>
|
|
734
|
+
React.createElement(Route, {
|
|
735
|
+
path: `${urlPrefix}/*`,
|
|
736
|
+
key: locale,
|
|
737
|
+
element: React.createElement(IntlayerProvider, { locale }, children),
|
|
738
|
+
})
|
|
739
|
+
)
|
|
740
|
+
)
|
|
741
|
+
);
|
|
962
742
|
|
|
963
|
-
|
|
964
|
-
// 기본 로케일 접두어 사용이 비활성화된 경우, 루트 경로에서 자식 컴포넌트를 직접 렌더링
|
|
965
|
-
!middleware.prefixDefault && (
|
|
966
|
-
<Route
|
|
967
|
-
path="*"
|
|
968
|
-
element={
|
|
969
|
-
<AppLocalized locale={defaultLocale}>{children}</AppLocalized>
|
|
970
|
-
} // 자식 컴포넌트를 로케일 관리로 감쌈
|
|
971
|
-
/>
|
|
972
|
-
)
|
|
973
|
-
}
|
|
974
|
-
</Routes>
|
|
975
|
-
</BrowserRouter>
|
|
976
|
-
);
|
|
743
|
+
exports.LocaleRouter = LocaleRouter;
|
|
977
744
|
```
|
|
978
745
|
|
|
746
|
+
> 참고: `routing.mode: 'no-prefix' | 'search-params'`를 사용하는 경우, 아마도 `localeMap` 함수를 사용할 필요가 없습니다.
|
|
747
|
+
|
|
979
748
|
그런 다음, 애플리케이션에서 `LocaleRouter` 컴포넌트를 사용할 수 있습니다:
|
|
980
749
|
|
|
981
750
|
```tsx fileName="src/App.tsx" codeFormat="typescript"
|
|
@@ -1015,7 +784,9 @@ const App = () => (
|
|
|
1015
784
|
);
|
|
1016
785
|
```
|
|
1017
786
|
|
|
1018
|
-
병행하여, `intlayerProxy
|
|
787
|
+
병행하여, `intlayerProxy`를 사용하여 애플리케이션에 서버 사이드 라우팅을 추가할 수도 있습니다. 이 플러그인은 URL을 기반으로 현재 로케일을 자동으로 감지하고 적절한 로케일 쿠키를 설정합니다. 로케일이 지정되지 않은 경우, 플러그인은 사용자의 브라우저 언어 설정을 기반으로 가장 적합한 로케일을 결정합니다. 로케일이 감지되지 않으면 기본 로케일로 리디렉션합니다.
|
|
788
|
+
|
|
789
|
+
- 프로덕션 환경에서 `intlayerProxy`를 사용하려면 `vite-intlayer` 패키지를 `devDependencies`에서 `dependencies`로 변경해야 합니다.
|
|
1019
790
|
|
|
1020
791
|
```typescript {3,7} fileName="vite.config.ts" codeFormat="typescript"
|
|
1021
792
|
import { defineConfig } from "vite";
|
|
@@ -1449,11 +1220,10 @@ import {
|
|
|
1449
1220
|
} from "react";
|
|
1450
1221
|
import { useLocale } from "react-intlayer";
|
|
1451
1222
|
|
|
1452
|
-
export interface LinkProps
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
> {}
|
|
1223
|
+
export interface LinkProps extends DetailedHTMLProps<
|
|
1224
|
+
AnchorHTMLAttributes<HTMLAnchorElement>,
|
|
1225
|
+
HTMLAnchorElement
|
|
1226
|
+
> {}
|
|
1457
1227
|
|
|
1458
1228
|
/**
|
|
1459
1229
|
* 주어진 URL이 외부 링크인지 확인하는 유틸리티 함수입니다.
|
|
@@ -1598,12 +1368,12 @@ TypeScript 구성에 자동 생성된 타입이 포함되어 있는지 확인하
|
|
|
1598
1368
|
|
|
1599
1369
|
### Git 설정
|
|
1600
1370
|
|
|
1601
|
-
Intlayer가 생성한 파일들은 Git 저장소에 커밋하지 않도록 무시하는 것이 권장됩니다.
|
|
1371
|
+
Intlayer가 생성한 파일들은 Git 저장소에 커밋하지 않도록 무시하는 것이 권장됩니다. 이렇게 하면 해당 파일들을 Git 저장소에 커밋하는 것을 방지할 수 있습니다.
|
|
1602
1372
|
|
|
1603
1373
|
이를 위해 `.gitignore` 파일에 다음 지침을 추가할 수 있습니다:
|
|
1604
1374
|
|
|
1605
|
-
```plaintext
|
|
1606
|
-
# Intlayer
|
|
1375
|
+
```plaintext fileName=".gitignore"
|
|
1376
|
+
# Intlayer에서 생성된 파일 무시하기
|
|
1607
1377
|
.intlayer
|
|
1608
1378
|
```
|
|
1609
1379
|
|
|
@@ -1616,9 +1386,9 @@ Intlayer와 함께 개발 경험을 향상시키기 위해 공식 **Intlayer VS
|
|
|
1616
1386
|
이 확장 프로그램은 다음 기능을 제공합니다:
|
|
1617
1387
|
|
|
1618
1388
|
- 번역 키에 대한 **자동 완성**.
|
|
1619
|
-
-
|
|
1620
|
-
-
|
|
1621
|
-
-
|
|
1389
|
+
- 누락된 번역에 대한 **실시간 오류 감지**.
|
|
1390
|
+
- 번역된 내용의 **인라인 미리보기**.
|
|
1391
|
+
- 번역을 쉽게 생성하고 업데이트할 수 있는 **빠른 작업**.
|
|
1622
1392
|
|
|
1623
1393
|
확장 기능 사용 방법에 대한 자세한 내용은 [Intlayer VS Code 확장 문서](https://intlayer.org/doc/vs-code-extension)를 참조하세요.
|
|
1624
1394
|
|
|
@@ -1627,5 +1397,3 @@ Intlayer와 함께 개발 경험을 향상시키기 위해 공식 **Intlayer VS
|
|
|
1627
1397
|
### 더 나아가기
|
|
1628
1398
|
|
|
1629
1399
|
더 나아가려면 [비주얼 에디터](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ko/intlayer_visual_editor.md)를 구현하거나 [CMS](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ko/intlayer_CMS.md)를 사용하여 콘텐츠를 외부화할 수 있습니다.
|
|
1630
|
-
|
|
1631
|
-
---
|
|
@@ -22,6 +22,7 @@ slugs:
|
|
|
22
22
|
- doc
|
|
23
23
|
- plugin
|
|
24
24
|
- sync-json
|
|
25
|
+
youtubeVideo: https://www.youtube.com/watch?v=MpGMxniDHNg
|
|
25
26
|
history:
|
|
26
27
|
- version: 6.1.6
|
|
27
28
|
date: 2025-10-05
|
|
@@ -30,6 +31,8 @@ history:
|
|
|
30
31
|
|
|
31
32
|
# Sync JSON (i18n 브리지)
|
|
32
33
|
|
|
34
|
+
<iframe title="Intlayer와 JSON 번역을 동기화 상태로 유지하는 방법" class="m-auto aspect-[16/9] w-full overflow-hidden rounded-lg border-0" allow="autoplay; gyroscope;" loading="lazy" width="1080" height="auto" src="https://www.youtube.com/embed/MpGMxniDHNg?autoplay=0&origin=http://intlayer.org&controls=0&rel=1"/>
|
|
35
|
+
|
|
33
36
|
기존 i18n 스택에 Intlayer를 애드온으로 사용하세요. 이 플러그인은 JSON 메시지를 Intlayer 사전과 동기화하여 다음을 할 수 있습니다:
|
|
34
37
|
|
|
35
38
|
- i18next, next-intl, react-intl, vue-i18n, next-translate, nuxt-i18n, Solid-i18next, svelte-i18n 등을 계속 사용할 수 있습니다.
|