@hua-labs/i18n-core 2.1.0 → 2.2.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.
@@ -0,0 +1,249 @@
1
+ import React$1 from 'react';
2
+ import * as react_jsx_runtime from 'react/jsx-runtime';
3
+ import { I as I18nConfig, a as I18nContextType, L as LanguageConfig, R as ResolveStringKey, T as TranslationParams, b as ResolvePluralKey, c as ResolveArrayKey, d as TranslationError } from './server-DgpyR0RE.js';
4
+ export { e as I18nPlatformAdapter, P as PluralCategory, f as PluralValue, g as Translator, h as TypedTranslationKeys, i as headlessPlatformAdapter, s as serverTranslate, j as ssrTranslate, w as webPlatformAdapter } from './server-DgpyR0RE.js';
5
+
6
+ /**
7
+ * I18n Provider 컴포넌트
8
+ */
9
+ declare function I18nProvider({ config, children }: {
10
+ config: I18nConfig & {
11
+ autoLanguageSync?: boolean;
12
+ };
13
+ children: React.ReactNode;
14
+ }): react_jsx_runtime.JSX.Element;
15
+ /**
16
+ * I18n 훅
17
+ */
18
+ declare function useI18n(): I18nContextType;
19
+
20
+ /**
21
+ * 간단한 번역 훅 (원본 SDK와 호환)
22
+ *
23
+ * @example
24
+ * ```tsx
25
+ * import { useTranslation } from '@hua-labs/i18n-core';
26
+ *
27
+ * function MyComponent() {
28
+ * const { t, currentLanguage, setLanguage, isLoading, error } = useTranslation();
29
+ *
30
+ * return (
31
+ * <div>
32
+ * <h1>{t('welcome')}</h1>
33
+ * <p>Current language: {currentLanguage}</p>
34
+ * <button onClick={() => setLanguage('en')}>Switch to English</button>
35
+ * </div>
36
+ * );
37
+ * }
38
+ * ```
39
+ */
40
+ declare function useTranslation(): {
41
+ t: (key: ResolveStringKey, paramsOrLang?: TranslationParams | string, language?: string) => string;
42
+ tPlural: (key: ResolvePluralKey, count: number, params?: Record<string, unknown>, language?: string) => string;
43
+ tArray: (key: ResolveArrayKey, language?: string) => string[];
44
+ currentLanguage: string;
45
+ setLanguage: (language: string) => void | Promise<void>;
46
+ getRawValue: <T = unknown>(key: string, language?: string) => T | undefined;
47
+ isLoading: boolean;
48
+ error: TranslationError | null;
49
+ supportedLanguages: LanguageConfig[];
50
+ debug: {
51
+ getCurrentLanguage: () => string;
52
+ getSupportedLanguages: () => string[];
53
+ getLoadedNamespaces: () => string[];
54
+ getAllTranslations: () => Record<string, Record<string, unknown>>;
55
+ isReady: () => boolean;
56
+ getInitializationError: () => TranslationError | null;
57
+ clearCache: () => void;
58
+ reloadTranslations: () => Promise<void>;
59
+ getCacheStats: () => {
60
+ size: number;
61
+ hits: number;
62
+ misses: number;
63
+ };
64
+ };
65
+ isInitialized: boolean;
66
+ };
67
+ /**
68
+ * 언어 변경 전용 훅
69
+ */
70
+ declare function useLanguageChange(): {
71
+ currentLanguage: string;
72
+ changeLanguage: (language: string) => void;
73
+ supportedLanguages: LanguageConfig[];
74
+ };
75
+
76
+ /**
77
+ * @hua-labs/i18n-core - 핵심 기능 전용 엔트리포인트
78
+ *
79
+ * 이 모듈은 기본적인 번역 기능만 필요한 경우 사용합니다.
80
+ * 플러그인, 고급 기능, 디버깅 도구 없이 순수한 번역 기능만 제공합니다.
81
+ */
82
+
83
+ declare global {
84
+ interface Window {
85
+ __I18N_DEBUG_MODE__?: boolean;
86
+ __I18N_DEBUG_MISSING_KEYS__?: Record<string, string[]>;
87
+ __I18N_DEBUG_ERRORS__?: Array<{
88
+ timestamp: string;
89
+ language: string;
90
+ namespace: string;
91
+ error: string;
92
+ stack?: string;
93
+ }>;
94
+ __I18N_PERFORMANCE_DATA__?: Record<string, number[]>;
95
+ __I18N_PERFORMANCE_ALERTS__?: Array<{
96
+ id: string;
97
+ type: 'warning' | 'error' | 'info';
98
+ severity: 'low' | 'medium' | 'high' | 'critical';
99
+ message: string;
100
+ metric: string;
101
+ value: number;
102
+ threshold: number;
103
+ timestamp: number;
104
+ resolved: boolean;
105
+ }>;
106
+ __I18N_ANALYTICS_DATA__?: {
107
+ missingKeys?: Set<string> | string[];
108
+ performance?: {
109
+ totalTime: number;
110
+ averageTime: number;
111
+ calls: number;
112
+ };
113
+ usage?: {
114
+ keys?: Map<string, number> | Record<string, number>;
115
+ languages?: Map<string, number> | Record<string, number>;
116
+ namespaces?: Map<string, number> | Record<string, number>;
117
+ };
118
+ errors?: Array<{
119
+ timestamp: number;
120
+ error: string;
121
+ context: string;
122
+ }>;
123
+ };
124
+ }
125
+ }
126
+ /**
127
+ * 핵심 기능용 설정 함수
128
+ *
129
+ * @example
130
+ * ```tsx
131
+ * // app/layout.tsx (Next.js App Router)
132
+ * import { createCoreI18n } from '@hua-labs/i18n-core';
133
+ *
134
+ * export default function RootLayout({ children }) {
135
+ * return (
136
+ * <html>
137
+ * <body>
138
+ * {createCoreI18n({
139
+ * defaultLanguage: 'ko',
140
+ * fallbackLanguage: 'en',
141
+ * namespaces: ['common', 'auth']
142
+ * })({ children })}
143
+ * </body>
144
+ * </html>
145
+ * );
146
+ * }
147
+ * ```
148
+ */
149
+ declare function createCoreI18n(options?: {
150
+ defaultLanguage?: string;
151
+ fallbackLanguage?: string;
152
+ namespaces?: string[];
153
+ debug?: boolean;
154
+ loadTranslations?: (language: string, namespace: string) => Promise<Record<string, string>>;
155
+ /**
156
+ * 번역 파일 로딩 방식 설정
157
+ * - 'api': API route를 통해 동적 로드 (기본값, 권장)
158
+ * - 'static': 정적 파일 경로에서 로드
159
+ * - 'custom': loadTranslations 함수 사용
160
+ */
161
+ translationLoader?: 'api' | 'static' | 'custom';
162
+ /**
163
+ * API route 경로 (translationLoader가 'api'일 때 사용)
164
+ * 기본값: '/api/translations'
165
+ */
166
+ translationApiPath?: string;
167
+ /**
168
+ * SSR에서 전달된 초기 번역 데이터 (네트워크 요청 없이 사용)
169
+ * 형식: { [language]: { [namespace]: { [key]: value } } }
170
+ */
171
+ initialTranslations?: Record<string, Record<string, Record<string, string>>>;
172
+ /**
173
+ * 지원 언어 목록 (LanguageConfig 배열 또는 언어 코드 문자열 배열)
174
+ * 기본값: ['ko', 'en']
175
+ */
176
+ supportedLanguages?: Array<{
177
+ code: string;
178
+ name: string;
179
+ nativeName: string;
180
+ }> | string[];
181
+ /**
182
+ * 자동 언어 동기화 활성화 여부
183
+ * 기본값: false (Zustand 어댑터 등 외부에서 직접 처리하는 경우)
184
+ */
185
+ autoLanguageSync?: boolean;
186
+ /**
187
+ * 서버사이드 렌더링 시 사용할 기본 URL
188
+ * 환경 변수보다 우선 적용됨
189
+ */
190
+ baseUrl?: string;
191
+ /**
192
+ * 로컬 개발 환경 fallback URL
193
+ * 기본값: 'http://localhost:3010'
194
+ */
195
+ localFallbackBaseUrl?: string;
196
+ }): ({ children }: {
197
+ children: React$1.ReactNode;
198
+ }) => React$1.FunctionComponentElement<{
199
+ config: I18nConfig & {
200
+ autoLanguageSync?: boolean;
201
+ };
202
+ children: React$1.ReactNode;
203
+ }>;
204
+ /**
205
+ * 가장 기본적인 Provider (최소한의 설정)
206
+ */
207
+ declare function CoreProvider({ children }: {
208
+ children: React$1.ReactNode;
209
+ }): React$1.FunctionComponentElement<{
210
+ config: I18nConfig & {
211
+ autoLanguageSync?: boolean;
212
+ };
213
+ children: React$1.ReactNode;
214
+ }>;
215
+ /**
216
+ * 언어별 Provider (언어만 지정)
217
+ */
218
+ declare function createLanguageProvider(language: string): ({ children }: {
219
+ children: React$1.ReactNode;
220
+ }) => React$1.FunctionComponentElement<{
221
+ config: I18nConfig & {
222
+ autoLanguageSync?: boolean;
223
+ };
224
+ children: React$1.ReactNode;
225
+ }>;
226
+ /**
227
+ * 네임스페이스별 Provider (네임스페이스만 지정)
228
+ */
229
+ declare function createNamespaceProvider(namespaces: string[]): ({ children }: {
230
+ children: React$1.ReactNode;
231
+ }) => React$1.FunctionComponentElement<{
232
+ config: I18nConfig & {
233
+ autoLanguageSync?: boolean;
234
+ };
235
+ children: React$1.ReactNode;
236
+ }>;
237
+ /**
238
+ * 커스텀 로더 Provider (사용자 정의 번역 로더 사용)
239
+ */
240
+ declare function createCustomLoaderProvider(loadTranslations: (language: string, namespace: string) => Promise<Record<string, string>>): ({ children }: {
241
+ children: React$1.ReactNode;
242
+ }) => React$1.FunctionComponentElement<{
243
+ config: I18nConfig & {
244
+ autoLanguageSync?: boolean;
245
+ };
246
+ children: React$1.ReactNode;
247
+ }>;
248
+
249
+ export { CoreProvider, I18nConfig, I18nContextType, I18nProvider, ResolveArrayKey, ResolvePluralKey, ResolveStringKey, TranslationParams, createCoreI18n, createCustomLoaderProvider, createLanguageProvider, createNamespaceProvider, useI18n, useLanguageChange, useTranslation };
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { validateI18nConfig, Translator } from './chunk-EZL5TNH5.mjs';
2
- export { Translator, serverTranslate, ssrTranslate } from './chunk-EZL5TNH5.mjs';
1
+ import { validateI18nConfig, webPlatformAdapter, Translator } from './chunk-7ZYOSEMW.mjs';
2
+ export { Translator, headlessPlatformAdapter, serverTranslate, ssrTranslate, webPlatformAdapter } from './chunk-7ZYOSEMW.mjs';
3
3
  import React, { createContext, useState, useEffect, useMemo, useCallback, useContext } from 'react';
4
4
  import { jsx } from 'react/jsx-runtime';
5
5
 
@@ -208,11 +208,12 @@ function resolveInitialLanguage(config) {
208
208
  if (config.defaultLanguage) {
209
209
  return config.defaultLanguage;
210
210
  }
211
- if (typeof window !== "undefined" && navigator?.language) {
212
- const browserLang = navigator.language.slice(0, 2).toLowerCase();
211
+ const adapter = config.platformAdapter ?? webPlatformAdapter;
212
+ const deviceLang = adapter.getDeviceLanguage();
213
+ if (deviceLang) {
213
214
  const supportedCodes = config.supportedLanguages?.map((l) => l.code) ?? [];
214
- if (supportedCodes.includes(browserLang)) {
215
- return browserLang;
215
+ if (supportedCodes.includes(deviceLang)) {
216
+ return deviceLang;
216
217
  }
217
218
  }
218
219
  return config.supportedLanguages?.[0]?.code ?? "ko";
@@ -310,25 +311,19 @@ function I18nProvider({
310
311
  return unsubscribe;
311
312
  }, [translator, isInitialized, currentLanguage, config.debug]);
312
313
  useEffect(() => {
313
- if (!config.autoLanguageSync || typeof window === "undefined") {
314
+ if (!config.autoLanguageSync) {
314
315
  return;
315
316
  }
316
- const handleLanguageChange = (event) => {
317
- const newLanguage = event.detail;
318
- if (typeof newLanguage === "string" && newLanguage !== currentLanguage) {
317
+ const adapter = config.platformAdapter ?? webPlatformAdapter;
318
+ return adapter.onLanguageChange((newLanguage) => {
319
+ if (newLanguage !== currentLanguage) {
319
320
  if (config.debug) {
320
321
  console.log("\u{1F310} Auto language sync:", newLanguage);
321
322
  }
322
323
  setLanguage(newLanguage);
323
324
  }
324
- };
325
- window.addEventListener("huaI18nLanguageChange", handleLanguageChange);
326
- window.addEventListener("i18nLanguageChanged", handleLanguageChange);
327
- return () => {
328
- window.removeEventListener("huaI18nLanguageChange", handleLanguageChange);
329
- window.removeEventListener("i18nLanguageChanged", handleLanguageChange);
330
- };
331
- }, [config.autoLanguageSync, currentLanguage]);
325
+ });
326
+ }, [config.autoLanguageSync, config.platformAdapter, currentLanguage]);
332
327
  const setLanguage = useCallback(async (language) => {
333
328
  if (!translator) {
334
329
  return;