@hua-labs/i18n-core 1.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.
Files changed (58) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +636 -0
  3. package/dist/components/MissingKeyOverlay.d.ts +33 -0
  4. package/dist/components/MissingKeyOverlay.d.ts.map +1 -0
  5. package/dist/components/MissingKeyOverlay.js +138 -0
  6. package/dist/components/MissingKeyOverlay.js.map +1 -0
  7. package/dist/core/debug-tools.d.ts +37 -0
  8. package/dist/core/debug-tools.d.ts.map +1 -0
  9. package/dist/core/debug-tools.js +241 -0
  10. package/dist/core/debug-tools.js.map +1 -0
  11. package/dist/core/i18n-resource.d.ts +59 -0
  12. package/dist/core/i18n-resource.d.ts.map +1 -0
  13. package/dist/core/i18n-resource.js +153 -0
  14. package/dist/core/i18n-resource.js.map +1 -0
  15. package/dist/core/lazy-loader.d.ts +82 -0
  16. package/dist/core/lazy-loader.d.ts.map +1 -0
  17. package/dist/core/lazy-loader.js +193 -0
  18. package/dist/core/lazy-loader.js.map +1 -0
  19. package/dist/core/translator-factory.d.ts +50 -0
  20. package/dist/core/translator-factory.d.ts.map +1 -0
  21. package/dist/core/translator-factory.js +117 -0
  22. package/dist/core/translator-factory.js.map +1 -0
  23. package/dist/core/translator.d.ts +202 -0
  24. package/dist/core/translator.d.ts.map +1 -0
  25. package/dist/core/translator.js +912 -0
  26. package/dist/core/translator.js.map +1 -0
  27. package/dist/hooks/useI18n.d.ts +39 -0
  28. package/dist/hooks/useI18n.d.ts.map +1 -0
  29. package/dist/hooks/useI18n.js +531 -0
  30. package/dist/hooks/useI18n.js.map +1 -0
  31. package/dist/hooks/useTranslation.d.ts +55 -0
  32. package/dist/hooks/useTranslation.d.ts.map +1 -0
  33. package/dist/hooks/useTranslation.js +58 -0
  34. package/dist/hooks/useTranslation.js.map +1 -0
  35. package/dist/index.d.ts +162 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +191 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/types/index.d.ts +162 -0
  40. package/dist/types/index.d.ts.map +1 -0
  41. package/dist/types/index.js +191 -0
  42. package/dist/types/index.js.map +1 -0
  43. package/dist/utils/default-translations.d.ts +20 -0
  44. package/dist/utils/default-translations.d.ts.map +1 -0
  45. package/dist/utils/default-translations.js +123 -0
  46. package/dist/utils/default-translations.js.map +1 -0
  47. package/package.json +60 -0
  48. package/src/components/MissingKeyOverlay.tsx +223 -0
  49. package/src/core/debug-tools.ts +298 -0
  50. package/src/core/i18n-resource.ts +180 -0
  51. package/src/core/lazy-loader.ts +255 -0
  52. package/src/core/translator-factory.ts +137 -0
  53. package/src/core/translator.tsx +1194 -0
  54. package/src/hooks/useI18n.tsx +595 -0
  55. package/src/hooks/useTranslation.tsx +62 -0
  56. package/src/index.ts +298 -0
  57. package/src/types/index.ts +443 -0
  58. package/src/utils/default-translations.ts +129 -0
@@ -0,0 +1,138 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useState } from 'react';
3
+ /**
4
+ * 개발 모드에서 누락된 번역 키를 화면에 표시하는 오버레이
5
+ * Lingui 스타일의 디버그 모드
6
+ */
7
+ export const MissingKeyOverlay = ({ enabled = process.env.NODE_ENV === 'development', position = 'top-right', style }) => {
8
+ const [missingKeys, setMissingKeys] = useState([]);
9
+ const [isVisible, setIsVisible] = useState(false);
10
+ useEffect(() => {
11
+ if (!enabled)
12
+ return;
13
+ // 누락된 키 이벤트 리스너
14
+ const handleMissingKey = (event) => {
15
+ setMissingKeys(prev => [...prev, event.detail]);
16
+ setIsVisible(true);
17
+ };
18
+ // 전역 이벤트 리스너 등록
19
+ window.addEventListener('i18n:missing-key', handleMissingKey);
20
+ return () => {
21
+ window.removeEventListener('i18n:missing-key', handleMissingKey);
22
+ };
23
+ }, [enabled]);
24
+ if (!enabled || !isVisible)
25
+ return null;
26
+ const positionStyles = {
27
+ 'top-right': { top: 20, right: 20 },
28
+ 'top-left': { top: 20, left: 20 },
29
+ 'bottom-right': { bottom: 20, right: 20 },
30
+ 'bottom-left': { bottom: 20, left: 20 }
31
+ };
32
+ const overlayStyle = {
33
+ position: 'fixed',
34
+ zIndex: 9999,
35
+ backgroundColor: 'rgba(255, 0, 0, 0.9)',
36
+ color: 'white',
37
+ padding: '12px 16px',
38
+ borderRadius: '8px',
39
+ fontFamily: 'monospace',
40
+ fontSize: '12px',
41
+ maxWidth: '400px',
42
+ maxHeight: '300px',
43
+ overflow: 'auto',
44
+ boxShadow: '0 4px 12px rgba(0, 0, 0, 0.3)',
45
+ border: '2px solid #ff4444',
46
+ ...positionStyles[position],
47
+ ...style
48
+ };
49
+ const keyStyle = {
50
+ marginBottom: '8px',
51
+ padding: '4px 8px',
52
+ backgroundColor: 'rgba(255, 255, 255, 0.1)',
53
+ borderRadius: '4px',
54
+ borderLeft: '3px solid #ff8888'
55
+ };
56
+ const headerStyle = {
57
+ display: 'flex',
58
+ justifyContent: 'space-between',
59
+ alignItems: 'center',
60
+ marginBottom: '12px',
61
+ paddingBottom: '8px',
62
+ borderBottom: '1px solid rgba(255, 255, 255, 0.3)'
63
+ };
64
+ const closeButtonStyle = {
65
+ background: 'none',
66
+ border: 'none',
67
+ color: 'white',
68
+ cursor: 'pointer',
69
+ fontSize: '16px',
70
+ padding: '0',
71
+ width: '20px',
72
+ height: '20px',
73
+ display: 'flex',
74
+ alignItems: 'center',
75
+ justifyContent: 'center'
76
+ };
77
+ const clearButtonStyle = {
78
+ background: 'rgba(255, 255, 255, 0.2)',
79
+ border: 'none',
80
+ color: 'white',
81
+ cursor: 'pointer',
82
+ padding: '4px 8px',
83
+ borderRadius: '4px',
84
+ fontSize: '10px',
85
+ marginLeft: '8px'
86
+ };
87
+ const handleClose = () => {
88
+ setIsVisible(false);
89
+ };
90
+ const handleClear = () => {
91
+ setMissingKeys([]);
92
+ };
93
+ const formatTime = (timestamp) => {
94
+ return new Date(timestamp).toLocaleTimeString();
95
+ };
96
+ return (_jsxs("div", { style: overlayStyle, children: [_jsxs("div", { style: headerStyle, children: [_jsxs("div", { children: [_jsx("strong", { children: "\uD83D\uDEA8 Missing Translation Keys" }), _jsxs("span", { style: { fontSize: '10px', marginLeft: '8px' }, children: ["(", missingKeys.length, ")"] })] }), _jsxs("div", { children: [_jsx("button", { style: clearButtonStyle, onClick: handleClear, children: "Clear" }), _jsx("button", { style: closeButtonStyle, onClick: handleClose, children: "\u00D7" })] })] }), _jsxs("div", { children: [missingKeys.slice(-10).reverse().map((key, index) => (_jsxs("div", { style: keyStyle, children: [_jsx("div", { style: { fontWeight: 'bold', color: '#ffcccc' }, children: key.key }), _jsxs("div", { style: { fontSize: '10px', marginTop: '2px' }, children: [_jsxs("span", { children: ["Lang: ", key.language] }), key.namespace && _jsxs("span", { style: { marginLeft: '8px' }, children: ["NS: ", key.namespace] }), _jsxs("span", { style: { marginLeft: '8px' }, children: ["Time: ", formatTime(key.timestamp)] })] }), key.component && (_jsxs("div", { style: { fontSize: '10px', color: '#ffaaaa', marginTop: '2px' }, children: ["Component: ", key.component] }))] }, `${key.key}-${key.timestamp}`))), missingKeys.length > 10 && (_jsxs("div", { style: { fontSize: '10px', textAlign: 'center', marginTop: '8px' }, children: ["... and ", missingKeys.length - 10, " more"] }))] })] }));
97
+ };
98
+ /**
99
+ * 누락된 키를 오버레이에 표시하는 유틸리티 함수
100
+ */
101
+ export const reportMissingKey = (key, options) => {
102
+ if (process.env.NODE_ENV === 'development') {
103
+ const missingKey = {
104
+ key,
105
+ namespace: options.namespace,
106
+ language: options.language,
107
+ timestamp: Date.now(),
108
+ component: options.component
109
+ };
110
+ // 커스텀 이벤트 발생
111
+ window.dispatchEvent(new CustomEvent('i18n:missing-key', {
112
+ detail: missingKey
113
+ }));
114
+ // 콘솔에도 로그
115
+ console.warn(`Missing translation key: ${key}`, {
116
+ namespace: options.namespace,
117
+ language: options.language,
118
+ component: options.component
119
+ });
120
+ }
121
+ };
122
+ /**
123
+ * 누락된 키 오버레이를 자동으로 활성화하는 훅
124
+ */
125
+ export const useMissingKeyOverlay = (enabled = true) => {
126
+ const [showOverlay, setShowOverlay] = useState(enabled);
127
+ useEffect(() => {
128
+ if (enabled && process.env.NODE_ENV === 'development') {
129
+ setShowOverlay(true);
130
+ }
131
+ }, [enabled]);
132
+ return {
133
+ showOverlay,
134
+ setShowOverlay,
135
+ reportMissingKey
136
+ };
137
+ };
138
+ //# sourceMappingURL=MissingKeyOverlay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MissingKeyOverlay.js","sourceRoot":"","sources":["../../src/components/MissingKeyOverlay.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * 조건부 디버깅 도구 - 개발 환경에서만 로드
3
+ * 번들 크기 최적화를 위해 조건부 로딩
4
+ */
5
+ export interface DebugTools {
6
+ highlightMissingKeys: (container: HTMLElement) => void;
7
+ showTranslationKeys: (container: HTMLElement) => void;
8
+ performanceMetrics: {
9
+ translationCount: number;
10
+ cacheHits: number;
11
+ cacheMisses: number;
12
+ loadTimes: number[];
13
+ };
14
+ devTools: {
15
+ open: () => void;
16
+ close: () => void;
17
+ isOpen: boolean;
18
+ };
19
+ validateTranslations: (translations: Record<string, unknown>) => {
20
+ missingKeys: string[];
21
+ duplicateKeys: string[];
22
+ invalidKeys: string[];
23
+ };
24
+ }
25
+ /**
26
+ * 디버깅 도구 팩토리 - 조건부 로딩
27
+ */
28
+ export declare function createDebugTools(): DebugTools | null;
29
+ /**
30
+ * 디버깅 도구 활성화 (전역 함수)
31
+ */
32
+ export declare function enableDebugTools(): void;
33
+ /**
34
+ * 디버깅 도구 비활성화
35
+ */
36
+ export declare function disableDebugTools(): void;
37
+ //# sourceMappingURL=debug-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug-tools.d.ts","sourceRoot":"","sources":["../../src/core/debug-tools.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,UAAU;IAEzB,oBAAoB,EAAE,CAAC,SAAS,EAAE,WAAW,KAAK,IAAI,CAAC;IACvD,mBAAmB,EAAE,CAAC,SAAS,EAAE,WAAW,KAAK,IAAI,CAAC;IAGtD,kBAAkB,EAAE;QAClB,gBAAgB,EAAE,MAAM,CAAC;QACzB,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;IAGF,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,IAAI,CAAC;QACjB,KAAK,EAAE,MAAM,IAAI,CAAC;QAClB,MAAM,EAAE,OAAO,CAAC;KACjB,CAAC;IAGF,oBAAoB,EAAE,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK;QAC/D,WAAW,EAAE,MAAM,EAAE,CAAC;QACtB,aAAa,EAAE,MAAM,EAAE,CAAC;QACxB,WAAW,EAAE,MAAM,EAAE,CAAC;KACvB,CAAC;CACH;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,UAAU,GAAG,IAAI,CAiIpD;AAsGD;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAgBvC;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAMxC"}
@@ -0,0 +1,241 @@
1
+ /**
2
+ * 조건부 디버깅 도구 - 개발 환경에서만 로드
3
+ * 번들 크기 최적화를 위해 조건부 로딩
4
+ */
5
+ /**
6
+ * 디버깅 도구 팩토리 - 조건부 로딩
7
+ */
8
+ export function createDebugTools() {
9
+ // 프로덕션에서는 디버깅 도구 비활성화
10
+ if (process.env.NODE_ENV === 'production') {
11
+ return null;
12
+ }
13
+ // 개발 환경에서만 로드
14
+ return {
15
+ highlightMissingKeys: (container) => {
16
+ const elements = container.querySelectorAll('[data-i18n-key]');
17
+ elements.forEach((element) => {
18
+ const key = element.getAttribute('data-i18n-key');
19
+ const text = element.textContent;
20
+ // 번역 키가 텍스트와 다른 경우 하이라이트
21
+ if (key && text === key) {
22
+ element.style.backgroundColor = '#ffeb3b';
23
+ element.style.border = '2px solid #f57c00';
24
+ element.title = `Missing translation: ${key}`;
25
+ }
26
+ });
27
+ },
28
+ showTranslationKeys: (container) => {
29
+ const elements = container.querySelectorAll('[data-i18n-key]');
30
+ elements.forEach((element) => {
31
+ const key = element.getAttribute('data-i18n-key');
32
+ if (key) {
33
+ const tooltip = document.createElement('div');
34
+ tooltip.style.cssText = `
35
+ position: absolute;
36
+ background: #333;
37
+ color: white;
38
+ padding: 4px 8px;
39
+ border-radius: 4px;
40
+ font-size: 12px;
41
+ z-index: 10000;
42
+ pointer-events: none;
43
+ opacity: 0;
44
+ transition: opacity 0.2s;
45
+ `;
46
+ tooltip.textContent = `Key: ${key}`;
47
+ element.addEventListener('mouseenter', () => {
48
+ const rect = element.getBoundingClientRect();
49
+ tooltip.style.left = `${rect.left}px`;
50
+ tooltip.style.top = `${rect.bottom + 5}px`;
51
+ tooltip.style.opacity = '1';
52
+ document.body.appendChild(tooltip);
53
+ });
54
+ element.addEventListener('mouseleave', () => {
55
+ tooltip.style.opacity = '0';
56
+ setTimeout(() => {
57
+ if (tooltip.parentNode) {
58
+ tooltip.parentNode.removeChild(tooltip);
59
+ }
60
+ }, 200);
61
+ });
62
+ }
63
+ });
64
+ },
65
+ performanceMetrics: {
66
+ translationCount: 0,
67
+ cacheHits: 0,
68
+ cacheMisses: 0,
69
+ loadTimes: [],
70
+ },
71
+ devTools: {
72
+ isOpen: false,
73
+ open: () => {
74
+ const devTools = createDevToolsPanel();
75
+ document.body.appendChild(devTools);
76
+ devTools.isOpen = true;
77
+ },
78
+ close: () => {
79
+ const existingPanel = document.getElementById('hua-i18n-devtools');
80
+ if (existingPanel) {
81
+ existingPanel.remove();
82
+ }
83
+ // devTools 변수는 이 스코프에서 접근할 수 없으므로 전역에서 관리
84
+ const globalDebugTools = window.__HUA_I18N_DEBUG__;
85
+ if (globalDebugTools) {
86
+ globalDebugTools.devTools.isOpen = false;
87
+ }
88
+ },
89
+ },
90
+ validateTranslations: (translations) => {
91
+ const missingKeys = [];
92
+ const duplicateKeys = [];
93
+ const invalidKeys = [];
94
+ const seenKeys = new Set();
95
+ const traverse = (obj, path = '') => {
96
+ if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
97
+ return;
98
+ }
99
+ for (const [key, value] of Object.entries(obj)) {
100
+ const currentPath = path ? `${path}.${key}` : key;
101
+ // 키 유효성 검사
102
+ if (typeof key !== 'string' || key.trim() === '') {
103
+ invalidKeys.push(currentPath);
104
+ }
105
+ // 중복 키 검사
106
+ if (seenKeys.has(currentPath)) {
107
+ duplicateKeys.push(currentPath);
108
+ }
109
+ else {
110
+ seenKeys.add(currentPath);
111
+ }
112
+ // 값 검사
113
+ if (value === null || value === undefined) {
114
+ missingKeys.push(currentPath);
115
+ }
116
+ else if (typeof value === 'object' && !Array.isArray(value)) {
117
+ traverse(value, currentPath);
118
+ }
119
+ }
120
+ };
121
+ traverse(translations);
122
+ return { missingKeys, duplicateKeys, invalidKeys };
123
+ },
124
+ };
125
+ }
126
+ /**
127
+ * 개발자 도구 패널 생성
128
+ */
129
+ function createDevToolsPanel() {
130
+ const panel = document.createElement('div');
131
+ panel.id = 'hua-i18n-devtools';
132
+ panel.style.cssText = `
133
+ position: fixed;
134
+ top: 20px;
135
+ right: 20px;
136
+ width: 300px;
137
+ max-height: 500px;
138
+ background: #1e1e1e;
139
+ color: #fff;
140
+ border-radius: 8px;
141
+ box-shadow: 0 4px 20px rgba(0,0,0,0.3);
142
+ z-index: 10000;
143
+ font-family: 'Monaco', 'Menlo', monospace;
144
+ font-size: 12px;
145
+ overflow: hidden;
146
+ `;
147
+ const header = document.createElement('div');
148
+ header.style.cssText = `
149
+ background: #2d2d2d;
150
+ padding: 12px;
151
+ border-bottom: 1px solid #444;
152
+ display: flex;
153
+ justify-content: space-between;
154
+ align-items: center;
155
+ `;
156
+ header.innerHTML = `
157
+ <span style="font-weight: bold;">HUA i18n Debug</span>
158
+ <button id="close-devtools" style="background: none; border: none; color: #fff; cursor: pointer; font-size: 16px;">×</button>
159
+ `;
160
+ const content = document.createElement('div');
161
+ content.style.cssText = `
162
+ padding: 12px;
163
+ max-height: 400px;
164
+ overflow-y: auto;
165
+ `;
166
+ // 성능 메트릭
167
+ const metricsSection = document.createElement('div');
168
+ metricsSection.innerHTML = `
169
+ <h4 style="margin: 0 0 8px 0; color: #4fc3f7;">Performance</h4>
170
+ <div>Translations: <span id="translation-count">0</span></div>
171
+ <div>Cache Hits: <span id="cache-hits">0</span></div>
172
+ <div>Cache Misses: <span id="cache-misses">0</span></div>
173
+ <div>Hit Rate: <span id="hit-rate">0%</span></div>
174
+ `;
175
+ // 현재 언어 정보
176
+ const languageSection = document.createElement('div');
177
+ languageSection.style.marginTop = '16px';
178
+ languageSection.innerHTML = `
179
+ <h4 style="margin: 0 0 8px 0; color: #4fc3f7;">Current Language</h4>
180
+ <div>Language: <span id="current-language">ko</span></div>
181
+ <div>Fallback: <span id="fallback-language">en</span></div>
182
+ `;
183
+ // 액션 버튼들
184
+ const actionsSection = document.createElement('div');
185
+ actionsSection.style.marginTop = '16px';
186
+ actionsSection.innerHTML = `
187
+ <h4 style="margin: 0 0 8px 0; color: #4fc3f7;">Actions</h4>
188
+ <button id="highlight-missing" style="background: #4fc3f7; border: none; color: #000; padding: 4px 8px; border-radius: 4px; cursor: pointer; margin-right: 8px;">Highlight Missing</button>
189
+ <button id="show-keys" style="background: #4fc3f7; border: none; color: #000; padding: 4px 8px; border-radius: 4px; cursor: pointer;">Show Keys</button>
190
+ `;
191
+ content.appendChild(metricsSection);
192
+ content.appendChild(languageSection);
193
+ content.appendChild(actionsSection);
194
+ panel.appendChild(header);
195
+ panel.appendChild(content);
196
+ // 이벤트 리스너
197
+ panel.querySelector('#close-devtools')?.addEventListener('click', () => {
198
+ panel.remove();
199
+ });
200
+ panel.querySelector('#highlight-missing')?.addEventListener('click', () => {
201
+ const debugTools = createDebugTools();
202
+ if (debugTools) {
203
+ debugTools.highlightMissingKeys(document.body);
204
+ }
205
+ });
206
+ panel.querySelector('#show-keys')?.addEventListener('click', () => {
207
+ const debugTools = createDebugTools();
208
+ if (debugTools) {
209
+ debugTools.showTranslationKeys(document.body);
210
+ }
211
+ });
212
+ return panel;
213
+ }
214
+ /**
215
+ * 디버깅 도구 활성화 (전역 함수)
216
+ */
217
+ export function enableDebugTools() {
218
+ if (process.env.NODE_ENV === 'production') {
219
+ console.warn('Debug tools are not available in production');
220
+ return;
221
+ }
222
+ const debugTools = createDebugTools();
223
+ if (!debugTools)
224
+ return;
225
+ // 전역 객체에 추가
226
+ window.__HUA_I18N_DEBUG__ = debugTools;
227
+ // 개발자 도구 열기
228
+ debugTools.devTools.open();
229
+ console.log('HUA i18n debug tools enabled. Use window.__HUA_I18N_DEBUG__ to access.');
230
+ }
231
+ /**
232
+ * 디버깅 도구 비활성화
233
+ */
234
+ export function disableDebugTools() {
235
+ const debugTools = window.__HUA_I18N_DEBUG__;
236
+ if (debugTools) {
237
+ debugTools.devTools.close();
238
+ delete window.__HUA_I18N_DEBUG__;
239
+ }
240
+ }
241
+ //# sourceMappingURL=debug-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug-tools.js","sourceRoot":"","sources":["../../src/core/debug-tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ import { TranslationNamespace } from '../types';
2
+ /**
3
+ * i18n 리소스 관리자
4
+ * SSR 환경에서 동일 번역 요청 중복 방지 및 전역 캐시 관리
5
+ */
6
+ export declare class I18nResourceManager {
7
+ private static instance;
8
+ private globalCache;
9
+ private loadingPromises;
10
+ private cacheStats;
11
+ private constructor();
12
+ static getInstance(): I18nResourceManager;
13
+ /**
14
+ * 전역 캐시에서 번역 데이터 가져오기
15
+ */
16
+ getCachedTranslations(language: string, namespace: string, loader: (lang: string, ns: string) => Promise<TranslationNamespace>): Promise<TranslationNamespace>;
17
+ /**
18
+ * 캐시된 번역 데이터 직접 접근
19
+ */
20
+ getCachedTranslationsSync(language: string, namespace: string): TranslationNamespace | null;
21
+ /**
22
+ * 특정 언어의 모든 네임스페이스 가져오기
23
+ */
24
+ getAllTranslationsForLanguage(language: string): Record<string, TranslationNamespace>;
25
+ /**
26
+ * 모든 캐시된 번역 데이터 가져오기
27
+ */
28
+ getAllCachedTranslations(): Record<string, Record<string, TranslationNamespace>>;
29
+ /**
30
+ * 캐시 통계 가져오기
31
+ */
32
+ getCacheStats(): {
33
+ hitRate: number;
34
+ hits: number;
35
+ misses: number;
36
+ size: number;
37
+ };
38
+ /**
39
+ * 캐시 무효화
40
+ */
41
+ invalidateCache(language?: string, namespace?: string): void;
42
+ /**
43
+ * 캐시 크기 제한 설정
44
+ */
45
+ setCacheLimit(maxSize: number): void;
46
+ /**
47
+ * SSR 환경에서 하이드레이션
48
+ */
49
+ hydrateFromSSR(translations: Record<string, Record<string, TranslationNamespace>>): void;
50
+ /**
51
+ * 메모리 사용량 최적화
52
+ */
53
+ optimizeMemory(): void;
54
+ }
55
+ /**
56
+ * 전역 리소스 매니저 인스턴스
57
+ */
58
+ export declare const i18nResourceManager: I18nResourceManager;
59
+ //# sourceMappingURL=i18n-resource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i18n-resource.d.ts","sourceRoot":"","sources":["../../src/core/i18n-resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAmB,MAAM,UAAU,CAAC;AAEjE;;;GAGG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAsB;IAC7C,OAAO,CAAC,WAAW,CAA2C;IAC9D,OAAO,CAAC,eAAe,CAAoD;IAC3E,OAAO,CAAC,UAAU,CAIhB;IAEF,OAAO;IAEP,MAAM,CAAC,WAAW,IAAI,mBAAmB;IAOzC;;OAEG;IACG,qBAAqB,CACzB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,oBAAoB,CAAC,GAClE,OAAO,CAAC,oBAAoB,CAAC;IA2BhC;;OAEG;IACH,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,oBAAoB,GAAG,IAAI;IAK3F;;OAEG;IACH,6BAA6B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC;IAarF;;OAEG;IACH,wBAAwB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IAchF;;OAEG;IACH,aAAa;;;;;;IAOb;;OAEG;IACH,eAAe,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI;IAuB5D;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAcpC;;OAEG;IACH,cAAc,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC,GAAG,IAAI;IAWxF;;OAEG;IACH,cAAc,IAAI,IAAI;CAIvB;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,qBAAoC,CAAC"}
@@ -0,0 +1,153 @@
1
+ /**
2
+ * i18n 리소스 관리자
3
+ * SSR 환경에서 동일 번역 요청 중복 방지 및 전역 캐시 관리
4
+ */
5
+ export class I18nResourceManager {
6
+ constructor() {
7
+ this.globalCache = new Map();
8
+ this.loadingPromises = new Map();
9
+ this.cacheStats = {
10
+ hits: 0,
11
+ misses: 0,
12
+ size: 0
13
+ };
14
+ }
15
+ static getInstance() {
16
+ if (!I18nResourceManager.instance) {
17
+ I18nResourceManager.instance = new I18nResourceManager();
18
+ }
19
+ return I18nResourceManager.instance;
20
+ }
21
+ /**
22
+ * 전역 캐시에서 번역 데이터 가져오기
23
+ */
24
+ async getCachedTranslations(language, namespace, loader) {
25
+ const cacheKey = `${language}:${namespace}`;
26
+ // 캐시에 있으면 반환
27
+ if (this.globalCache.has(cacheKey)) {
28
+ this.cacheStats.hits++;
29
+ return this.globalCache.get(cacheKey);
30
+ }
31
+ // 이미 로딩 중이면 기존 Promise 반환
32
+ if (this.loadingPromises.has(cacheKey)) {
33
+ return this.loadingPromises.get(cacheKey);
34
+ }
35
+ // 새로 로딩
36
+ this.cacheStats.misses++;
37
+ const loadPromise = loader(language, namespace).then(data => {
38
+ this.globalCache.set(cacheKey, data);
39
+ this.cacheStats.size = this.globalCache.size;
40
+ this.loadingPromises.delete(cacheKey);
41
+ return data;
42
+ });
43
+ this.loadingPromises.set(cacheKey, loadPromise);
44
+ return loadPromise;
45
+ }
46
+ /**
47
+ * 캐시된 번역 데이터 직접 접근
48
+ */
49
+ getCachedTranslationsSync(language, namespace) {
50
+ const cacheKey = `${language}:${namespace}`;
51
+ return this.globalCache.get(cacheKey) || null;
52
+ }
53
+ /**
54
+ * 특정 언어의 모든 네임스페이스 가져오기
55
+ */
56
+ getAllTranslationsForLanguage(language) {
57
+ const result = {};
58
+ for (const [key, data] of this.globalCache.entries()) {
59
+ if (key.startsWith(`${language}:`)) {
60
+ const namespace = key.split(':')[1];
61
+ result[namespace] = data;
62
+ }
63
+ }
64
+ return result;
65
+ }
66
+ /**
67
+ * 모든 캐시된 번역 데이터 가져오기
68
+ */
69
+ getAllCachedTranslations() {
70
+ const result = {};
71
+ for (const [key, data] of this.globalCache.entries()) {
72
+ const [language, namespace] = key.split(':');
73
+ if (!result[language]) {
74
+ result[language] = {};
75
+ }
76
+ result[language][namespace] = data;
77
+ }
78
+ return result;
79
+ }
80
+ /**
81
+ * 캐시 통계 가져오기
82
+ */
83
+ getCacheStats() {
84
+ return {
85
+ ...this.cacheStats,
86
+ hitRate: this.cacheStats.hits / (this.cacheStats.hits + this.cacheStats.misses)
87
+ };
88
+ }
89
+ /**
90
+ * 캐시 무효화
91
+ */
92
+ invalidateCache(language, namespace) {
93
+ if (language && namespace) {
94
+ // 특정 언어/네임스페이스만 무효화
95
+ const cacheKey = `${language}:${namespace}`;
96
+ this.globalCache.delete(cacheKey);
97
+ this.loadingPromises.delete(cacheKey);
98
+ }
99
+ else if (language) {
100
+ // 특정 언어의 모든 네임스페이스 무효화
101
+ for (const key of this.globalCache.keys()) {
102
+ if (key.startsWith(`${language}:`)) {
103
+ this.globalCache.delete(key);
104
+ this.loadingPromises.delete(key);
105
+ }
106
+ }
107
+ }
108
+ else {
109
+ // 전체 캐시 무효화
110
+ this.globalCache.clear();
111
+ this.loadingPromises.clear();
112
+ }
113
+ this.cacheStats.size = this.globalCache.size;
114
+ }
115
+ /**
116
+ * 캐시 크기 제한 설정
117
+ */
118
+ setCacheLimit(maxSize) {
119
+ if (this.globalCache.size > maxSize) {
120
+ // LRU 방식으로 오래된 항목 제거
121
+ const entries = Array.from(this.globalCache.entries());
122
+ const toRemove = entries.slice(0, this.globalCache.size - maxSize);
123
+ for (const [key] of toRemove) {
124
+ this.globalCache.delete(key);
125
+ }
126
+ this.cacheStats.size = this.globalCache.size;
127
+ }
128
+ }
129
+ /**
130
+ * SSR 환경에서 하이드레이션
131
+ */
132
+ hydrateFromSSR(translations) {
133
+ for (const [language, namespaces] of Object.entries(translations)) {
134
+ for (const [namespace, data] of Object.entries(namespaces)) {
135
+ const cacheKey = `${language}:${namespace}`;
136
+ this.globalCache.set(cacheKey, data);
137
+ }
138
+ }
139
+ this.cacheStats.size = this.globalCache.size;
140
+ }
141
+ /**
142
+ * 메모리 사용량 최적화
143
+ */
144
+ optimizeMemory() {
145
+ // 사용되지 않는 번역 데이터 정리
146
+ // 실제 구현에서는 사용 통계를 기반으로 정리
147
+ }
148
+ }
149
+ /**
150
+ * 전역 리소스 매니저 인스턴스
151
+ */
152
+ export const i18nResourceManager = I18nResourceManager.getInstance();
153
+ //# sourceMappingURL=i18n-resource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i18n-resource.js","sourceRoot":"","sources":["../../src/core/i18n-resource.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,OAAO,mBAAmB;IAU9B;QARQ,gBAAW,GAAG,IAAI,GAAG,EAAgC,CAAC;QACtD,oBAAe,GAAG,IAAI,GAAG,EAAyC,CAAC;QACnE,eAAU,GAAG;YACnB,IAAI,EAAE,CAAC;YACP,MAAM,EAAE,CAAC;YACT,IAAI,EAAE,CAAC;SACR,CAAC;IAEqB,CAAC;IAExB,MAAM,CAAC,WAAW;QAChB,IAAI,CAAC,mBAAmB,CAAC,QAAQ,EAAE,CAAC;YAClC,mBAAmB,CAAC,QAAQ,GAAG,IAAI,mBAAmB,EAAE,CAAC;QAC3D,CAAC;QACD,OAAO,mBAAmB,CAAC,QAAQ,CAAC;IACtC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,qBAAqB,CACzB,QAAgB,EAChB,SAAiB,EACjB,MAAmE;QAEnE,MAAM,QAAQ,GAAG,GAAG,QAAQ,IAAI,SAAS,EAAE,CAAC;QAE5C,aAAa;QACb,IAAI,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YACnC,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAE,CAAC;QACzC,CAAC;QAED,0BAA0B;QAC1B,IAAI,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YACvC,OAAO,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAE,CAAC;QAC7C,CAAC;QAED,QAAQ;QACR,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;QACzB,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YAC1D,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YACrC,IAAI,CAAC,UAAU,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;YAC7C,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YACtC,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QAChD,OAAO,WAAW,CAAC;IACrB,CAAC;IAED;;OAEG;IACH,yBAAyB,CAAC,QAAgB,EAAE,SAAiB;QAC3D,MAAM,QAAQ,GAAG,GAAG,QAAQ,IAAI,SAAS,EAAE,CAAC;QAC5C,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC;IAChD,CAAC;IAED;;OAEG;IACH,6BAA6B,CAAC,QAAgB;QAC5C,MAAM,MAAM,GAAyC,EAAE,CAAC;QAExD,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC;YACrD,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,QAAQ,GAAG,CAAC,EAAE,CAAC;gBACnC,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;gBACpC,MAAM,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;YAC3B,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACH,wBAAwB;QACtB,MAAM,MAAM,GAAyD,EAAE,CAAC;QAExE,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC;YACrD,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC7C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACtB,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC;YACxB,CAAC;YACD,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;QACrC,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED;;OAEG;IACH,aAAa;QACX,OAAO;YACL,GAAG,IAAI,CAAC,UAAU;YAClB,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;SAChF,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,eAAe,CAAC,QAAiB,EAAE,SAAkB;QACnD,IAAI,QAAQ,IAAI,SAAS,EAAE,CAAC;YAC1B,oBAAoB;YACpB,MAAM,QAAQ,GAAG,GAAG,QAAQ,IAAI,SAAS,EAAE,CAAC;YAC5C,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAClC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACxC,CAAC;aAAM,IAAI,QAAQ,EAAE,CAAC;YACpB,uBAAuB;YACvB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC;gBAC1C,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,QAAQ,GAAG,CAAC,EAAE,CAAC;oBACnC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;oBAC7B,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACnC,CAAC;YACH,CAAC;QACH,CAAC;aAAM,CAAC;YACN,YAAY;YACZ,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;QAC/B,CAAC;QAED,IAAI,CAAC,UAAU,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;IAC/C,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,OAAe;QAC3B,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,GAAG,OAAO,EAAE,CAAC;YACpC,qBAAqB;YACrB,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC;YACvD,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;YAEnE,KAAK,MAAM,CAAC,GAAG,CAAC,IAAI,QAAQ,EAAE,CAAC;gBAC7B,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC/B,CAAC;YAED,IAAI,CAAC,UAAU,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;QAC/C,CAAC;IACH,CAAC;IAED;;OAEG;IACH,cAAc,CAAC,YAAkE;QAC/E,KAAK,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;YAClE,KAAK,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC3D,MAAM,QAAQ,GAAG,GAAG,QAAQ,IAAI,SAAS,EAAE,CAAC;gBAC5C,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YACvC,CAAC;QACH,CAAC;QAED,IAAI,CAAC,UAAU,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;IAC/C,CAAC;IAED;;OAEG;IACH,cAAc;QACZ,oBAAoB;QACpB,0BAA0B;IAC5B,CAAC;CACF;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,mBAAmB,CAAC,WAAW,EAAE,CAAC"}