@hua-labs/i18n-beginner 2.0.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/README.md ADDED
@@ -0,0 +1,830 @@
1
+ # @hua-labs/i18n-beginner
2
+
3
+ [한국어](#korean) | [English](./README_EN.md)
4
+
5
+ ## **이 SDK는 초보자용입니다!**
6
+
7
+ > 데모 보기 | 기여는 [SDK 레포](https://github.com/HUA-Labs/HUA-Labs-public)에서
8
+
9
+ > 고급 기능이 필요하시다면?
10
+ > - **초보자용**: `@hua-labs/i18n-beginner` (현재 패키지) - 간단하고 직관적
11
+ > - **고급자용**: `@hua-labs/i18n-sdk` - 완전한 기능, 플러그인, 고급 설정
12
+ > - **전문가용**: `@hua-labs/i18n-advanced` - 커스텀 로더, 성능 최적화, 엔터프라이즈 기능
13
+
14
+ **이 SDK는 "30초 만에 시작"을 목표로 만들어졌습니다!**
15
+
16
+ ---
17
+
18
+ ## English
19
+
20
+ **The simplest internationalization SDK for React beginners!**
21
+
22
+ A beginner-friendly i18n SDK that supports Korean and English out of the box, with easy support for additional languages.
23
+
24
+ ### Features
25
+ - **Zero Configuration**: Works out of the box with Korean and English
26
+ - **Easy Language Addition**: Add any language with simple functions
27
+ - **TypeScript Support**: Full type safety and IntelliSense
28
+ - **Next.js Compatible**: Works perfectly with App Router and Pages Router
29
+ - **No External Dependencies**: Lightweight and fast
30
+ - **80+ Built-in Translations**: Common UI elements pre-translated
31
+
32
+ ### Quick Start (30 seconds)
33
+ ```bash
34
+ npm install @hua-labs/i18n-beginner
35
+ ```
36
+
37
+ ```tsx
38
+ // app/layout.tsx
39
+ import { SimpleI18n } from '@hua-labs/i18n-beginner';
40
+
41
+ export default function RootLayout({ children }) {
42
+ return (
43
+ <html>
44
+ <body>
45
+ <SimpleI18n>
46
+ {children}
47
+ </SimpleI18n>
48
+ </body>
49
+ </html>
50
+ );
51
+ }
52
+ ```
53
+
54
+ ```tsx
55
+ // app/page.tsx
56
+ 'use client';
57
+ import { useSimpleI18n } from '@hua-labs/i18n-beginner';
58
+
59
+ export default function Home() {
60
+ const { t, toggleLanguage, languageButtonText } = useSimpleI18n();
61
+
62
+ return (
63
+ <div>
64
+ <h1>{t('welcome')}</h1>
65
+ <p>{t('hello')}</p>
66
+ <button onClick={toggleLanguage}>{languageButtonText}</button>
67
+ </div>
68
+ );
69
+ }
70
+ ```
71
+
72
+ ### Adding Other Languages
73
+ ```tsx
74
+ // Add Japanese
75
+ useEffect(() => {
76
+ addTranslation('ja', 'welcome', 'ようこそ');
77
+ addTranslation('ja', 'hello', 'こんにちは');
78
+ }, []);
79
+
80
+ // Or use TypeScript files
81
+ const japaneseTranslations = {
82
+ ja: {
83
+ welcome: "ようこそ",
84
+ hello: "こんにちは"
85
+ }
86
+ } as const;
87
+
88
+ useTranslationsFromFile(japaneseTranslations);
89
+ ```
90
+
91
+ ---
92
+
93
+ ## Korean
94
+
95
+ **React 초보자를 위한 가장 간단한 다국어 지원 SDK!**
96
+
97
+ 한국어와 영어를 기본으로 지원하며, 다른 언어도 쉽게 추가할 수 있는 초보자 친화적인 i18n SDK입니다.
98
+
99
+ ### 특징
100
+ - **설정 불필요**: 한국어/영어 즉시 사용 가능
101
+ - **언어 추가 쉬움**: 간단한 함수로 어떤 언어든 추가
102
+ - **TypeScript 지원**: 완전한 타입 안정성과 자동완성
103
+ - **Next.js 호환**: App Router와 Pages Router 완벽 지원
104
+ - **외부 의존성 없음**: 가볍고 빠름
105
+ - **80개+ 기본 번역**: 일반적인 UI 요소 미리 번역됨
106
+
107
+ ### 30초 만에 시작하기
108
+
109
+ #### 1단계: 설치하기
110
+ ```bash
111
+ npm install @hua-labs/i18n-beginner
112
+ ```
113
+
114
+ #### 2단계: 설정하기
115
+ ```tsx
116
+ // app/layout.tsx (또는 pages/_app.tsx)
117
+ import { SimpleI18n } from '@hua-labs/i18n-beginner';
118
+
119
+ export default function RootLayout({ children }) {
120
+ return (
121
+ <html>
122
+ <body>
123
+ <SimpleI18n>
124
+ {children}
125
+ </SimpleI18n>
126
+ </body>
127
+ </html>
128
+ );
129
+ }
130
+ ```
131
+
132
+ #### 3단계: 사용하기
133
+ ```tsx
134
+ // app/components/MyComponent.tsx
135
+ import { useSimpleI18n } from '@hua-labs/i18n-beginner';
136
+
137
+ export default function MyComponent() {
138
+ const { t, toggleLanguage, languageButtonText } = useSimpleI18n();
139
+
140
+ return (
141
+ <div>
142
+ <h1>{t('welcome')}</h1>
143
+ <p>{t('hello')}</p>
144
+ <button onClick={toggleLanguage}>{languageButtonText}</button>
145
+ </div>
146
+ );
147
+ }
148
+ ```
149
+
150
+ #### 4단계: TypeScript 파일로 번역 분리하기 (선택사항)
151
+ ```tsx
152
+ // translations/myTranslations.ts
153
+ export const myTranslations = {
154
+ ko: {
155
+ welcome_message: "환영합니다",
156
+ goodbye_message: "안녕히 가세요"
157
+ },
158
+ en: {
159
+ welcome_message: "Welcome",
160
+ goodbye_message: "Goodbye"
161
+ }
162
+ } as const;
163
+
164
+ // app/components/MyComponent.tsx
165
+ import { useSimpleI18n, useTranslationsFromFile } from '@hua-labs/i18n-beginner';
166
+ import { myTranslations } from '../translations/myTranslations';
167
+
168
+ export default function MyComponent() {
169
+ const { t, toggleLanguage, languageButtonText } = useSimpleI18n();
170
+
171
+ // TypeScript 파일에서 번역 자동 로드
172
+ useTranslationsFromFile(myTranslations);
173
+
174
+ return (
175
+ <div>
176
+ <h1>{t('welcome')}</h1>
177
+ <p>{t('welcome_message')}</p> {/* TypeScript 파일에서 로드된 번역 */}
178
+ <button onClick={toggleLanguage}>{languageButtonText}</button>
179
+ </div>
180
+ );
181
+ }
182
+ ```
183
+
184
+ **끝!** 이제 한국어/영어 자동 전환이 완성되었습니다!
185
+
186
+ ---
187
+
188
+ ## 다국어 지원 안내
189
+
190
+ ### 현재 지원 언어
191
+ - **한국어 (ko)**: 기본 지원
192
+ - **영어 (en)**: 기본 지원
193
+
194
+ ### 다른 언어 추가하기
195
+
196
+ 현재 SDK는 한국어와 영어만 기본으로 지원하지만, 다른 언어도 쉽게 추가할 수 있습니다!
197
+
198
+ #### 방법 1: 동적으로 언어 추가하기
199
+ ```tsx
200
+ import { useSimpleI18n } from '@hua-labs/i18n-beginner';
201
+
202
+ function MyComponent() {
203
+ const { addTranslation } = useSimpleI18n();
204
+
205
+ // 일본어 추가
206
+ useEffect(() => {
207
+ addTranslation('ja', 'welcome', 'ようこそ');
208
+ addTranslation('ja', 'hello', 'こんにちは');
209
+ addTranslation('ja', 'goodbye', 'さようなら');
210
+ }, []);
211
+
212
+ return <div>{t('welcome')}</div>;
213
+ }
214
+ ```
215
+
216
+ #### 방법 2: TypeScript 파일로 언어 추가하기
217
+ ```tsx
218
+ // translations/japanese.ts
219
+ export const japaneseTranslations = {
220
+ ja: {
221
+ welcome: "ようこそ",
222
+ hello: "こんにちは",
223
+ goodbye: "さようなら",
224
+ email: "メールアドレス",
225
+ password: "パスワード",
226
+ submit: "送信"
227
+ }
228
+ } as const;
229
+
230
+ // 컴포넌트에서 사용
231
+ import { useTranslationsFromFile } from '@hua-labs/i18n-beginner';
232
+ import { japaneseTranslations } from './translations/japanese';
233
+
234
+ function MyComponent() {
235
+ const { t } = useSimpleI18n();
236
+ useTranslationsFromFile(japaneseTranslations);
237
+
238
+ return <div>{t('welcome')}</div>;
239
+ }
240
+ ```
241
+
242
+ #### 방법 3: 언어별 파일로 분리하기
243
+ ```tsx
244
+ // translations/spanish.ts
245
+ export const spanishTranslations = {
246
+ es: {
247
+ welcome: "Bienvenido",
248
+ hello: "Hola",
249
+ goodbye: "Adiós"
250
+ }
251
+ } as const;
252
+
253
+ // translations/french.ts
254
+ export const frenchTranslations = {
255
+ fr: {
256
+ welcome: "Bienvenue",
257
+ hello: "Bonjour",
258
+ goodbye: "Au revoir"
259
+ }
260
+ } as const;
261
+
262
+ // translations/german.ts
263
+ export const germanTranslations = {
264
+ de: {
265
+ welcome: "Willkommen",
266
+ hello: "Hallo",
267
+ goodbye: "Auf Wiedersehen"
268
+ }
269
+ } as const;
270
+ ```
271
+
272
+ ### 언어 코드 참고
273
+
274
+ | 언어 | 코드 | 예시 |
275
+ |------|------|------|
276
+ | 한국어 | `ko` | 안녕하세요 |
277
+ | 영어 | `en` | Hello |
278
+ | 일본어 | `ja` | こんにちは |
279
+ | 중국어 (간체) | `zh-CN` | 你好 |
280
+ | 중국어 (번체) | `zh-TW` | 你好 |
281
+ | 스페인어 | `es` | Hola |
282
+ | 프랑스어 | `fr` | Bonjour |
283
+ | 독일어 | `de` | Hallo |
284
+ | 이탈리아어 | `it` | Ciao |
285
+ | 포르투갈어 | `pt` | Olá |
286
+ | 러시아어 | `ru` | Привет |
287
+ | 아랍어 | `ar` | مرحبا |
288
+
289
+ ### 언어 전환 기능 확장하기
290
+
291
+ 여러 언어를 지원하려면 언어 선택 UI를 만들어보세요:
292
+
293
+ ```tsx
294
+ function LanguageSelector() {
295
+ const { setLanguage, language } = useSimpleI18n();
296
+
297
+ const languages = [
298
+ { code: 'ko', name: '한국어', flag: '🇰🇷' },
299
+ { code: 'en', name: 'English', flag: '🇺🇸' },
300
+ { code: 'ja', name: '日本語', flag: '🇯🇵' },
301
+ { code: 'es', name: 'Español', flag: '🇪🇸' },
302
+ { code: 'fr', name: 'Français', flag: '🇫🇷' }
303
+ ];
304
+
305
+ return (
306
+ <select
307
+ value={language}
308
+ onChange={(e) => setLanguage(e.target.value)}
309
+ >
310
+ {languages.map(lang => (
311
+ <option key={lang.code} value={lang.code}>
312
+ {lang.flag} {lang.name}
313
+ </option>
314
+ ))}
315
+ </select>
316
+ );
317
+ }
318
+ ```
319
+
320
+ ### 📝 기여하기
321
+
322
+ 더 많은 언어를 기본으로 지원하고 싶다면:
323
+
324
+ 1. **GitHub Issues**에 언어 추가 요청
325
+ 2. **Pull Request**로 번역 파일 제출
326
+ 3. **커뮤니티 기여**로 SDK 발전에 참여
327
+
328
+ > 팁: 언어별 번역 파일을 만들어서 공유하면 다른 개발자들도 쉽게 사용할 수 있어요!
329
+
330
+ ---
331
+
332
+ ## 📋 완전 초보자용 체크리스트
333
+
334
+ ### 1단계: 설치 확인
335
+ ```bash
336
+ # 터미널에서 이 명령어를 실행했나요?
337
+ npm install @hua-labs/i18n-beginner
338
+ ```
339
+ > ❓ **확인 방법**: `package.json` 파일에 `"@hua-labs/i18n-beginner"`가 있는지 확인하세요.
340
+
341
+ ### 2단계: Provider 설정 확인
342
+ ```tsx
343
+ // 이 코드가 layout.tsx에 있나요?
344
+ import { SimpleI18n } from '@hua-labs/i18n-beginner';
345
+
346
+ <SimpleI18n>
347
+ {children}
348
+ </SimpleI18n>
349
+ ```
350
+ > ❓ **확인 방법**: 페이지가 로드될 때 오류가 없다면 성공이에요!
351
+
352
+ ### 3단계: 컴포넌트에서 사용 확인
353
+ ```tsx
354
+ // 이 코드가 컴포넌트에 있나요?
355
+ import { useSimpleI18n } from '@hua-labs/i18n-beginner';
356
+
357
+ const { t, toggleLanguage, languageButtonText } = useSimpleI18n();
358
+ ```
359
+ > ❓ **확인 방법**: 버튼을 클릭했을 때 언어가 바뀌나요?
360
+
361
+ ---
362
+
363
+ ## 🧪 실제 테스트 결과
364
+
365
+ ### 테스트 완료 항목들:
366
+ - [x] 한국어 → 영어 전환
367
+ - [x] 영어 → 한국어 전환
368
+ - [x] 페이지 새로고침 후 언어 유지
369
+ - [x] 기본 번역 키들 정상 작동
370
+ - [x] 커스텀 번역 추가 기능
371
+ - [x] TypeScript 파일 번역 로드
372
+ - [x] 하이드레이션 오류 없음
373
+ - [x] 무한 루프 오류 없음
374
+
375
+ ### 테스트 환경:
376
+ - **프레임워크**: Next.js 15
377
+ - **언어**: 한국어, 영어, TypeScript 파일 번역
378
+ - **브라우저**: Chrome, Firefox, Safari
379
+ - **기기**: 데스크톱, 모바일
380
+
381
+ ---
382
+
383
+ ## 기본 제공 번역 키들
384
+
385
+ ### 기본 인사말
386
+ ```tsx
387
+ t('welcome') // "환영합니다" / "Welcome"
388
+ t('hello') // "안녕하세요" / "Hello"
389
+ t('click_me') // "클릭하세요" / "Click me"
390
+ ```
391
+
392
+ ### 상태 메시지
393
+ ```tsx
394
+ t('loading') // "로딩 중..." / "Loading..."
395
+ t('error') // "오류가 발생했습니다" / "An error occurred"
396
+ t('success') // "성공했습니다" / "Success"
397
+ ```
398
+
399
+ ### 🎛️ 버튼 텍스트
400
+ ```tsx
401
+ t('cancel') // "취소" / "Cancel"
402
+ t('confirm') // "확인" / "Confirm"
403
+ t('save') // "저장" / "Save"
404
+ t('delete') // "삭제" / "Delete"
405
+ t('edit') // "편집" / "Edit"
406
+ t('add') // "추가" / "Add"
407
+ ```
408
+
409
+ ### 🔍 검색 및 네비게이션
410
+ ```tsx
411
+ t('search') // "검색" / "Search"
412
+ t('back') // "뒤로" / "Back"
413
+ t('next') // "다음" / "Next"
414
+ t('home') // "홈" / "Home"
415
+ t('about') // "소개" / "About"
416
+ t('contact') // "연락처" / "Contact"
417
+ ```
418
+
419
+ ### ⚙️ 설정 및 사용자
420
+ ```tsx
421
+ t('settings') // "설정" / "Settings"
422
+ t('profile') // "프로필" / "Profile"
423
+ t('logout') // "로그아웃" / "Logout"
424
+ t('login') // "로그인" / "Login"
425
+ t('register') // "회원가입" / "Register"
426
+ ```
427
+
428
+ ### 📝 폼 필드
429
+ ```tsx
430
+ t('email') // "이메일" / "Email"
431
+ t('password') // "비밀번호" / "Password"
432
+ t('name') // "이름" / "Name"
433
+ t('phone') // "전화번호" / "Phone"
434
+ t('address') // "주소" / "Address"
435
+ ```
436
+
437
+ ### 액션 버튼
438
+ ```tsx
439
+ t('submit') // "제출" / "Submit"
440
+ t('reset') // "초기화" / "Reset"
441
+ t('close') // "닫기" / "Close"
442
+ t('open') // "열기" / "Open"
443
+ t('yes') // "예" / "Yes"
444
+ t('no') // "아니오" / "No"
445
+ t('ok') // "확인" / "OK"
446
+ ```
447
+
448
+ ### 긴 메시지
449
+ ```tsx
450
+ t('loading_text') // "잠시만 기다려주세요..." / "Please wait..."
451
+ t('error_message') // "문제가 발생했습니다. 다시 시도해주세요." / "An error occurred. Please try again."
452
+ t('success_message') // "성공적으로 완료되었습니다!" / "Successfully completed!"
453
+ t('not_found') // "찾을 수 없습니다" / "Not found"
454
+ t('unauthorized') // "권한이 없습니다" / "Unauthorized"
455
+ t('forbidden') // "접근이 거부되었습니다" / "Forbidden"
456
+ t('server_error') // "서버 오류가 발생했습니다" / "Server error occurred"
457
+ ```
458
+
459
+ > 사용 팁:
460
+ > 이 키들을 그대로 복사해서 `t('키이름')` 형태로 사용하세요!
461
+ > 예: `t('welcome')` → "환영합니다" 또는 "Welcome"
462
+
463
+ ---
464
+
465
+ ## 📝 커스텀 번역 추가하기
466
+
467
+ 기본 번역 외에 추가 번역이 필요하다면 여러 가지 방법이 있어요!
468
+
469
+ ### 방법 1: 동적으로 번역 추가하기
470
+ ```tsx
471
+ import { useSimpleI18n } from '@hua-labs/i18n-beginner';
472
+
473
+ function MyComponent() {
474
+ const { t, toggleLanguage, languageButtonText, addTranslation } = useSimpleI18n();
475
+
476
+ // 번역 추가하기
477
+ const addCustomTranslations = () => {
478
+ addTranslation('ko', 'custom_message', '커스텀 메시지');
479
+ addTranslation('en', 'custom_message', 'Custom message');
480
+ };
481
+
482
+ return (
483
+ <div>
484
+ <h1>{t('welcome')}</h1>
485
+ <p>{t('hello')}</p>
486
+ <p>{t('custom_message')}</p> {/* 커스텀 번역 사용 */}
487
+ <button onClick={addCustomTranslations}>번역 추가</button>
488
+ <button onClick={toggleLanguage}>{languageButtonText}</button>
489
+ </div>
490
+ );
491
+ }
492
+ ```
493
+
494
+ ### 📁 방법 2: TypeScript 파일로 번역 분리하기 (추천!)
495
+
496
+ **1단계: 번역 파일 만들기**
497
+ ```tsx
498
+ // translations/myTranslations.ts
499
+ export const myTranslations = {
500
+ ko: {
501
+ welcome_message: "환영합니다",
502
+ goodbye_message: "안녕히 가세요",
503
+ custom_button: "커스텀 버튼",
504
+ about_us: "우리에 대해",
505
+ contact_info: "연락처 정보"
506
+ },
507
+ en: {
508
+ welcome_message: "Welcome",
509
+ goodbye_message: "Goodbye",
510
+ custom_button: "Custom Button",
511
+ about_us: "About Us",
512
+ contact_info: "Contact Information"
513
+ }
514
+ } as const;
515
+ ```
516
+
517
+ **2단계: 컴포넌트에서 사용하기**
518
+ ```tsx
519
+ import { useSimpleI18n, loadTranslationsFromFile } from '@hua-labs/i18n-beginner';
520
+ import { myTranslations } from './translations/myTranslations';
521
+
522
+ function MyComponent() {
523
+ const { t, addTranslation } = useSimpleI18n();
524
+
525
+ // 컴포넌트 마운트 시 번역 파일 로드
526
+ useEffect(() => {
527
+ loadTranslationsFromFile(myTranslations, addTranslation);
528
+ }, []);
529
+
530
+ return (
531
+ <div>
532
+ <h1>{t('welcome_message')}</h1>
533
+ <p>{t('about_us')}</p>
534
+ <button>{t('custom_button')}</button>
535
+ </div>
536
+ );
537
+ }
538
+ ```
539
+
540
+ ### 방법 3: 더 간단한 훅 사용하기
541
+ ```tsx
542
+ import { useSimpleI18n, useTranslationsFromFile } from '@hua-labs/i18n-beginner';
543
+ import { myTranslations } from './translations/myTranslations';
544
+
545
+ function MyComponent() {
546
+ const { t } = useSimpleI18n();
547
+
548
+ // 자동으로 번역 파일 로드
549
+ useTranslationsFromFile(myTranslations);
550
+
551
+ return (
552
+ <div>
553
+ <h1>{t('welcome_message')}</h1>
554
+ <p>{t('contact_info')}</p>
555
+ </div>
556
+ );
557
+ }
558
+ ```
559
+
560
+ > 이게 뭔가요?
561
+ > - **TypeScript 파일**: 번역을 별도 파일로 관리할 수 있어요
562
+ > - **`loadTranslationsFromFile`**: 번역 파일을 자동으로 로드해요
563
+ > - **`useTranslationsFromFile`**: 더 간단하게 사용할 수 있는 훅이에요
564
+
565
+ ### 번역 추가 규칙
566
+
567
+ - **언어 코드**: `ko` (한국어), `en` (영어)
568
+ - **키**: 문자열 (예: `'my_text'`)
569
+ - **값**: 문자열 (예: `'내 텍스트'`)
570
+ - **동적 추가**: `addTranslation(언어, 키, 값)`
571
+
572
+ > 추천하는 방법:
573
+ > - **초보자**: TypeScript 파일로 번역 분리하기
574
+ > - **간단한 경우**: 동적으로 번역 추가하기
575
+ > - **복잡한 프로젝트**: 여러 번역 파일로 나누기
576
+
577
+ > 주의사항:
578
+ > - 키는 따옴표로 감싸야 해요: `'my_text'` (O), `my_text` (X)
579
+ > - 값도 따옴표로 감싸야 해요: `'내 텍스트'` (O), `내 텍스트` (X)
580
+ > - TypeScript 파일 사용 시 `as const`를 붙이면 타입 안정성이 향상돼요!
581
+
582
+ 이렇게 하면 번역을 체계적으로 관리할 수 있습니다!
583
+
584
+ ---
585
+
586
+ ## 고급 사용법
587
+
588
+ ### 다양한 훅들
589
+
590
+ #### 1. `useSimpleI18n` (추천!)
591
+ ```tsx
592
+ const { t, toggleLanguage, languageButtonText, isClient, addTranslation } = useSimpleI18n();
593
+ ```
594
+ > 언제 사용? 대부분의 경우에 사용하세요. 가장 간단해요!
595
+
596
+ #### 2. `useTranslate` (번역만 필요할 때)
597
+ ```tsx
598
+ const t = useTranslate();
599
+ ```
600
+ > 언제 사용? 번역 함수만 필요할 때 사용하세요.
601
+
602
+ #### 3. `useLanguage` (언어 관련 기능만 필요할 때)
603
+ ```tsx
604
+ const { language, setLanguage, toggleLanguage, addTranslation } = useLanguage();
605
+ ```
606
+ > 언제 사용? 언어 변경 기능만 필요할 때 사용하세요.
607
+
608
+ #### 4. `useI18n` (모든 기능이 필요할 때)
609
+ ```tsx
610
+ const { t, language, setLanguage, toggleLanguage, addTranslation, isClient } = useI18n();
611
+ ```
612
+ > 언제 사용? 모든 기능이 필요할 때 사용하세요.
613
+
614
+ ### 언어 직접 설정하기
615
+
616
+ ```tsx
617
+ import { useLanguage } from '@hua-labs/i18n-beginner';
618
+
619
+ function LanguageSelector() {
620
+ const { setLanguage } = useLanguage();
621
+
622
+ return (
623
+ <div>
624
+ <button onClick={() => setLanguage('ko')}>한국어</button>
625
+ <button onClick={() => setLanguage('en')}>English</button>
626
+ </div>
627
+ );
628
+ }
629
+ ```
630
+
631
+ > 이게 뭔가요?
632
+ > `toggleLanguage()`는 한국어 ↔ 영어를 번갈아가며 바꾸고,
633
+ > `setLanguage('ko')`는 무조건 한국어로, `setLanguage('en')`은 무조건 영어로 바꿔요.
634
+
635
+ ---
636
+
637
+ ## 주의사항
638
+
639
+ ### 하이드레이션 문제 해결
640
+
641
+ Next.js에서 "hydration mismatch" 오류가 발생할 수 있어요. 이렇게 해결하세요:
642
+
643
+ ```tsx
644
+ import { useSimpleI18n } from '@hua-labs/i18n-beginner';
645
+
646
+ function MyComponent() {
647
+ const { t, toggleLanguage, languageButtonText, isClient } = useSimpleI18n();
648
+
649
+ // 하이드레이션 방지
650
+ if (!isClient) {
651
+ return (
652
+ <div>
653
+ <h1>환영합니다</h1>
654
+ <p>안녕하세요</p>
655
+ <button>English</button>
656
+ </div>
657
+ );
658
+ }
659
+
660
+ return (
661
+ <div>
662
+ <h1>{t('welcome')}</h1>
663
+ <p>{t('hello')}</p>
664
+ <button onClick={toggleLanguage}>{languageButtonText}</button>
665
+ </div>
666
+ );
667
+ }
668
+ ```
669
+
670
+ > 이게 뭔가요?
671
+ > - `isClient`: 브라우저에서 실행 중인지 확인하는 플래그
672
+ > - `!isClient`: 서버에서 실행 중일 때는 고정된 한국어 텍스트를 보여줌
673
+ > - 이렇게 하면 서버와 클라이언트의 내용이 일치해서 오류가 발생하지 않아요.
674
+
675
+ ### 무한 루프 방지
676
+
677
+ `useEffect`에서 `addTranslation`을 사용할 때는 의존성 배열을 비워야 해요:
678
+
679
+ ```tsx
680
+ // 올바른 방법
681
+ useEffect(() => {
682
+ addTranslation('ko', 'my_text', '내 텍스트');
683
+ addTranslation('en', 'my_text', 'My text');
684
+ }, []); // 빈 배열
685
+
686
+ // ❌ 잘못된 방법 (무한 루프 발생!)
687
+ useEffect(() => {
688
+ addTranslation('ko', 'my_text', '내 텍스트');
689
+ addTranslation('en', 'my_text', 'My text');
690
+ }, [addTranslation]); // addTranslation을 의존성에 포함
691
+ ```
692
+
693
+ > 이게 뭔가요?
694
+ > - 빈 배열 `[]`: 컴포넌트가 처음 로드될 때 한 번만 실행
695
+ > - `[addTranslation]`: `addTranslation` 함수가 바뀔 때마다 실행 (무한 루프!)
696
+
697
+ ---
698
+
699
+ ## ❓ 자주 묻는 질문
700
+
701
+ ### Q: 더 많은 언어를 지원하려면?
702
+ A: `addTranslation()` 함수를 사용해서 동적으로 추가할 수 있습니다.
703
+
704
+ ```tsx
705
+ addTranslation('ja', 'welcome', 'ようこそ'); // 일본어
706
+ addTranslation('fr', 'welcome', 'Bienvenue'); // 프랑스어
707
+ addTranslation('es', 'welcome', 'Bienvenido'); // 스페인어
708
+ ```
709
+
710
+ ### Q: 번역이 안 나오면?
711
+ A: 번역 키가 올바른지 확인해주세요. 기본 번역 키는 "기본 제공 번역 키들" 섹션을 참고하세요.
712
+
713
+ ### Q: 동적으로 번역을 추가할 수 있나요?
714
+ A: 네! `addTranslation()` 함수를 사용하면 런타임에 번역을 추가할 수 있습니다.
715
+
716
+ ### Q: 언어가 바뀌지 않아요
717
+ A: `SimpleI18n` Provider가 제대로 설정되어 있는지 확인해주세요.
718
+
719
+ ### Q: 하이드레이션 오류가 발생해요
720
+ A: "주의사항" 섹션의 하이드레이션 문제 해결 방법을 참고해주세요.
721
+
722
+ ### Q: 성능에 문제가 있나요?
723
+ A: 번역을 너무 많이 추가하면 성능에 영향을 줄 수 있습니다. 필요한 번역만 추가하세요.
724
+
725
+ ---
726
+
727
+ ## 성능 최적화
728
+
729
+ ### 불필요한 번역 키는 제거하세요
730
+ ```tsx
731
+ // 나쁜 예: 사용하지 않는 번역 추가
732
+ addTranslation('ko', 'unused_text', '사용하지 않는 텍스트');
733
+
734
+ // 좋은 예: 필요한 번역만 추가
735
+ addTranslation('ko', 'important_text', '중요한 텍스트');
736
+ ```
737
+
738
+ ### 불필요한 리렌더링을 방지하세요
739
+ ```tsx
740
+ import { useMemo } from 'react';
741
+
742
+ function MyComponent() {
743
+ const { t } = useSimpleI18n();
744
+
745
+ // 번역된 텍스트를 메모이제이션 (함수 자체는 메모이제이션 불필요)
746
+ const welcomeText = useMemo(() => t('welcome'), [t]);
747
+ const helloText = useMemo(() => t('hello'), [t]);
748
+
749
+ return (
750
+ <div>
751
+ <h1>{welcomeText}</h1>
752
+ <p>{helloText}</p>
753
+ </div>
754
+ );
755
+ }
756
+ ```
757
+
758
+ ### 동적 번역 추가는 필요한 시점에만 하세요
759
+ ```tsx
760
+ // 나쁜 예: 매번 렌더링할 때마다 추가
761
+ function MyComponent() {
762
+ const { addTranslation } = useSimpleI18n();
763
+
764
+ addTranslation('ko', 'text', '텍스트'); // 매번 실행됨!
765
+
766
+ return <div>...</div>;
767
+ }
768
+
769
+ // 좋은 예: 한 번만 추가
770
+ function MyComponent() {
771
+ const { addTranslation } = useSimpleI18n();
772
+
773
+ useEffect(() => {
774
+ addTranslation('ko', 'text', '텍스트'); // 한 번만 실행됨!
775
+ }, []);
776
+
777
+ return <div>...</div>;
778
+ }
779
+ ```
780
+
781
+ ---
782
+
783
+ ## 보안
784
+
785
+ ### 번역 키는 신뢰할 수 있는 소스에서만 가져오세요
786
+ ```tsx
787
+ // 나쁜 예: 사용자 입력을 그대로 사용
788
+ const userKey = userInput; // 위험!
789
+ t(userKey);
790
+
791
+ // 좋은 예: 허용된 키만 사용
792
+ const allowedKeys = ['welcome', 'hello', 'goodbye'];
793
+ if (allowedKeys.includes(userKey)) {
794
+ t(userKey);
795
+ }
796
+ ```
797
+
798
+ ---
799
+
800
+ ## 다음 단계
801
+
802
+ ### 더 많은 기능이 필요하다면:
803
+ - [HUA i18n SDK](https://github.com/hua-labs/hua-i18n-sdk): 고급 기능이 있는 완전한 i18n SDK
804
+ - [Next.js Internationalization](https://nextjs.org/docs/advanced-features/i18n-routing): Next.js 공식 다국어 지원
805
+
806
+ ### 커뮤니티:
807
+ - [GitHub Issues](https://github.com/hua-labs/hua-platform/issues): 버그 리포트 및 기능 요청
808
+ - [Discussions](https://github.com/hua-labs/hua-platform/discussions): 질문 및 토론
809
+
810
+ ---
811
+
812
+ ## 라이선스
813
+
814
+ MIT License - 자유롭게 사용하세요!
815
+
816
+ ---
817
+
818
+ ## 기여하기
819
+
820
+ 버그를 발견하거나 개선 아이디어가 있으시면 언제든지 기여해주세요!
821
+
822
+ 1. [Fork](https://github.com/hua-labs/hua-platform/fork) this repository
823
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
824
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
825
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
826
+ 5. Open a [Pull Request](https://github.com/hua-labs/hua-platform/pulls)
827
+
828
+ ---
829
+
830
+ **정말 한 줄로 시작하는 다국어 지원, 지금 바로 시작해보세요!**