@lokascript/i18n 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.
- package/README.md +286 -0
- package/dist/browser.cjs +7669 -0
- package/dist/browser.cjs.map +1 -0
- package/dist/browser.d.cts +50 -0
- package/dist/browser.d.ts +50 -0
- package/dist/browser.js +7592 -0
- package/dist/browser.js.map +1 -0
- package/dist/hyperfixi-i18n.min.js +2 -0
- package/dist/hyperfixi-i18n.min.js.map +1 -0
- package/dist/hyperfixi-i18n.mjs +8558 -0
- package/dist/hyperfixi-i18n.mjs.map +1 -0
- package/dist/index.cjs +14205 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +947 -0
- package/dist/index.d.ts +947 -0
- package/dist/index.js +14095 -0
- package/dist/index.js.map +1 -0
- package/dist/transformer-Ckask-yw.d.cts +1041 -0
- package/dist/transformer-Ckask-yw.d.ts +1041 -0
- package/package.json +84 -0
- package/src/browser.ts +122 -0
- package/src/compatibility/browser-tests/grammar-demo.spec.ts +169 -0
- package/src/constants.ts +366 -0
- package/src/dictionaries/ar.ts +233 -0
- package/src/dictionaries/bn.ts +156 -0
- package/src/dictionaries/de.ts +233 -0
- package/src/dictionaries/derive.ts +515 -0
- package/src/dictionaries/en.ts +237 -0
- package/src/dictionaries/es.ts +233 -0
- package/src/dictionaries/fr.ts +233 -0
- package/src/dictionaries/hi.ts +270 -0
- package/src/dictionaries/id.ts +233 -0
- package/src/dictionaries/index.ts +238 -0
- package/src/dictionaries/it.ts +233 -0
- package/src/dictionaries/ja.ts +233 -0
- package/src/dictionaries/ko.ts +233 -0
- package/src/dictionaries/ms.ts +276 -0
- package/src/dictionaries/pl.ts +239 -0
- package/src/dictionaries/pt.ts +237 -0
- package/src/dictionaries/qu.ts +233 -0
- package/src/dictionaries/ru.ts +270 -0
- package/src/dictionaries/sw.ts +233 -0
- package/src/dictionaries/th.ts +156 -0
- package/src/dictionaries/tl.ts +276 -0
- package/src/dictionaries/tr.ts +233 -0
- package/src/dictionaries/uk.ts +270 -0
- package/src/dictionaries/vi.ts +210 -0
- package/src/dictionaries/zh.ts +233 -0
- package/src/enhanced-i18n.test.ts +454 -0
- package/src/enhanced-i18n.ts +713 -0
- package/src/examples/new-languages.ts +326 -0
- package/src/formatting.test.ts +213 -0
- package/src/formatting.ts +416 -0
- package/src/grammar/direct-mappings.ts +353 -0
- package/src/grammar/grammar.test.ts +1053 -0
- package/src/grammar/index.ts +59 -0
- package/src/grammar/profiles/index.ts +860 -0
- package/src/grammar/transformer.ts +1318 -0
- package/src/grammar/types.ts +630 -0
- package/src/index.ts +202 -0
- package/src/new-languages.test.ts +389 -0
- package/src/parser/analyze-conflicts.test.ts +229 -0
- package/src/parser/ar.ts +40 -0
- package/src/parser/create-provider.ts +309 -0
- package/src/parser/de.ts +36 -0
- package/src/parser/es.ts +31 -0
- package/src/parser/fr.ts +31 -0
- package/src/parser/id.ts +34 -0
- package/src/parser/index.ts +50 -0
- package/src/parser/ja.ts +36 -0
- package/src/parser/ko.ts +37 -0
- package/src/parser/locale-manager.test.ts +198 -0
- package/src/parser/locale-manager.ts +197 -0
- package/src/parser/parser-integration.test.ts +439 -0
- package/src/parser/pt.ts +37 -0
- package/src/parser/qu.ts +37 -0
- package/src/parser/sw.ts +37 -0
- package/src/parser/tr.ts +38 -0
- package/src/parser/types.ts +113 -0
- package/src/parser/zh.ts +38 -0
- package/src/plugins/vite.ts +224 -0
- package/src/plugins/webpack.ts +124 -0
- package/src/pluralization.test.ts +197 -0
- package/src/pluralization.ts +393 -0
- package/src/runtime.ts +441 -0
- package/src/ssr-integration.ts +225 -0
- package/src/test-setup.ts +195 -0
- package/src/translation-validation.test.ts +171 -0
- package/src/translator.test.ts +252 -0
- package/src/translator.ts +297 -0
- package/src/types.ts +209 -0
- package/src/utils/locale.ts +190 -0
- package/src/utils/tokenizer-adapter.ts +469 -0
- package/src/utils/tokenizer.ts +19 -0
- package/src/validators/index.ts +174 -0
- package/src/validators/schema.ts +129 -0
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enhanced I18n Implementation Tests
|
|
3
|
+
* Comprehensive testing following enhanced pattern validation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
7
|
+
import {
|
|
8
|
+
TypedI18nContextImplementation,
|
|
9
|
+
createI18nContext,
|
|
10
|
+
createEnhancedI18n,
|
|
11
|
+
enhancedI18nImplementation,
|
|
12
|
+
type EnhancedI18nInput,
|
|
13
|
+
type EnhancedI18nOutput,
|
|
14
|
+
} from './enhanced-i18n.js';
|
|
15
|
+
|
|
16
|
+
describe('Enhanced I18n Implementation', () => {
|
|
17
|
+
let i18nContext: TypedI18nContextImplementation;
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
i18nContext = createI18nContext();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe('Context Initialization', () => {
|
|
24
|
+
it('should initialize with minimal configuration', async () => {
|
|
25
|
+
const input: EnhancedI18nInput = {
|
|
26
|
+
locale: 'en',
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const result = await i18nContext.initialize(input);
|
|
30
|
+
|
|
31
|
+
expect(result.success).toBe(true);
|
|
32
|
+
expect(result.value).toBeDefined();
|
|
33
|
+
|
|
34
|
+
if (result.success && result.value) {
|
|
35
|
+
expect(result.value.locale.current).toBe('en');
|
|
36
|
+
expect(result.value.category).toBe('Universal');
|
|
37
|
+
expect(result.value.capabilities).toContain('translation');
|
|
38
|
+
expect(result.value.capabilities).toContain('locale-management');
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should initialize with comprehensive configuration', async () => {
|
|
43
|
+
const spanishDict = {
|
|
44
|
+
commands: { click: 'clic', add: 'agregar', remove: 'quitar' },
|
|
45
|
+
modifiers: { to: 'a', from: 'de', with: 'con' },
|
|
46
|
+
events: { click: 'clic', hover: 'hover', focus: 'foco' },
|
|
47
|
+
logical: { and: 'y', or: 'o', not: 'no' },
|
|
48
|
+
temporal: { then: 'luego', wait: 'esperar', after: 'después' },
|
|
49
|
+
values: { true: 'verdadero', false: 'falso', null: 'nulo' },
|
|
50
|
+
attributes: { class: 'clase', id: 'id', style: 'estilo' },
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const input: EnhancedI18nInput = {
|
|
54
|
+
locale: 'es',
|
|
55
|
+
fallbackLocale: 'en',
|
|
56
|
+
dictionaries: {
|
|
57
|
+
es: spanishDict,
|
|
58
|
+
},
|
|
59
|
+
options: {
|
|
60
|
+
detectLocale: true,
|
|
61
|
+
rtlLocales: ['ar', 'he'],
|
|
62
|
+
validate: true,
|
|
63
|
+
},
|
|
64
|
+
environment: 'frontend',
|
|
65
|
+
debug: true,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const result = await i18nContext.initialize(input);
|
|
69
|
+
|
|
70
|
+
expect(result.success).toBe(true);
|
|
71
|
+
|
|
72
|
+
if (result.success && result.value) {
|
|
73
|
+
expect(result.value.locale.current).toBe('es');
|
|
74
|
+
expect(result.value.locale.fallback).toBe('en');
|
|
75
|
+
expect(result.value.locale.direction).toBe('ltr');
|
|
76
|
+
expect(result.value.locale.available).toContain('es');
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should handle RTL languages correctly', async () => {
|
|
81
|
+
const arabicDict = {
|
|
82
|
+
commands: { click: 'انقر', add: 'أضف', remove: 'احذف' },
|
|
83
|
+
modifiers: { to: 'إلى', from: 'من', with: 'مع' },
|
|
84
|
+
events: { click: 'انقر', hover: 'تحوم', focus: 'التركيز' },
|
|
85
|
+
logical: { and: 'و', or: 'أو', not: 'ليس' },
|
|
86
|
+
temporal: { then: 'ثم', wait: 'انتظر', after: 'بعد' },
|
|
87
|
+
values: { true: 'صحيح', false: 'خطأ', null: 'فارغ' },
|
|
88
|
+
attributes: { class: 'فئة', id: 'معرف', style: 'نمط' },
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const input: EnhancedI18nInput = {
|
|
92
|
+
locale: 'ar',
|
|
93
|
+
dictionaries: { ar: arabicDict },
|
|
94
|
+
options: {
|
|
95
|
+
rtlLocales: ['ar', 'he', 'fa', 'ur'],
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const result = await i18nContext.initialize(input);
|
|
100
|
+
|
|
101
|
+
expect(result.success).toBe(true);
|
|
102
|
+
|
|
103
|
+
if (result.success && result.value) {
|
|
104
|
+
expect(result.value.locale.direction).toBe('rtl');
|
|
105
|
+
expect(result.value.capabilities).toContain('rtl-support');
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
describe('Translation Capabilities', () => {
|
|
111
|
+
it('should translate individual terms', async () => {
|
|
112
|
+
const frenchDict = {
|
|
113
|
+
commands: { click: 'cliquer', add: 'ajouter', remove: 'supprimer' },
|
|
114
|
+
modifiers: { to: 'à', from: 'de', with: 'avec' },
|
|
115
|
+
events: { click: 'clic', hover: 'survol', focus: 'focus' },
|
|
116
|
+
logical: { and: 'et', or: 'ou', not: 'non' },
|
|
117
|
+
temporal: { then: 'puis', wait: 'attendre', after: 'après' },
|
|
118
|
+
values: { true: 'vrai', false: 'faux', null: 'nul' },
|
|
119
|
+
attributes: { class: 'classe', id: 'id', style: 'style' },
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const result = await i18nContext.initialize({
|
|
123
|
+
locale: 'fr',
|
|
124
|
+
dictionaries: { fr: frenchDict },
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
expect(result.success).toBe(true);
|
|
128
|
+
|
|
129
|
+
if (result.success && result.value) {
|
|
130
|
+
const translate = result.value.translate;
|
|
131
|
+
|
|
132
|
+
expect(translate('click', 'commands')).toBe('cliquer');
|
|
133
|
+
expect(translate('to', 'modifiers')).toBe('à');
|
|
134
|
+
expect(translate('and', 'logical')).toBe('et');
|
|
135
|
+
expect(translate('nonexistent', 'commands')).toBe('nonexistent'); // Fallback
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should translate hyperscript expressions', async () => {
|
|
140
|
+
const germanDict = {
|
|
141
|
+
commands: { click: 'klicken', add: 'hinzufügen', remove: 'entfernen' },
|
|
142
|
+
modifiers: { to: 'zu', from: 'von', with: 'mit' },
|
|
143
|
+
events: { click: 'klick', hover: 'schweben', focus: 'fokus' },
|
|
144
|
+
logical: { and: 'und', or: 'oder', not: 'nicht' },
|
|
145
|
+
temporal: { then: 'dann', wait: 'warten', after: 'nach' },
|
|
146
|
+
values: { true: 'wahr', false: 'falsch', null: 'null' },
|
|
147
|
+
attributes: { class: 'klasse', id: 'id', style: 'stil' },
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const result = await i18nContext.initialize({
|
|
151
|
+
locale: 'de',
|
|
152
|
+
dictionaries: { de: germanDict },
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
expect(result.success).toBe(true);
|
|
156
|
+
|
|
157
|
+
if (result.success && result.value) {
|
|
158
|
+
const translateHyperscript = result.value.translateHyperscript;
|
|
159
|
+
|
|
160
|
+
const translated = translateHyperscript('on click add .highlight');
|
|
161
|
+
expect(translated).toContain('klick'); // Event should be translated
|
|
162
|
+
expect(translated).toContain('hinzufügen'); // Command should be translated
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
describe('Dictionary Management', () => {
|
|
168
|
+
it('should provide dictionary access methods', async () => {
|
|
169
|
+
const japaneseDict = {
|
|
170
|
+
commands: { click: 'クリック', add: '追加', remove: '削除' },
|
|
171
|
+
modifiers: { to: 'に', from: 'から', with: 'と' },
|
|
172
|
+
events: { click: 'クリック', hover: 'ホバー', focus: 'フォーカス' },
|
|
173
|
+
logical: { and: 'かつ', or: 'または', not: 'ではない' },
|
|
174
|
+
temporal: { then: 'そして', wait: '待つ', after: '後' },
|
|
175
|
+
values: { true: '真', false: '偽', null: 'null' },
|
|
176
|
+
attributes: { class: 'クラス', id: 'ID', style: 'スタイル' },
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const result = await i18nContext.initialize({
|
|
180
|
+
locale: 'ja',
|
|
181
|
+
dictionaries: { ja: japaneseDict },
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
expect(result.success).toBe(true);
|
|
185
|
+
|
|
186
|
+
if (result.success && result.value) {
|
|
187
|
+
const { dictionary } = result.value;
|
|
188
|
+
|
|
189
|
+
// Test dictionary access
|
|
190
|
+
expect(dictionary.get('commands.click')).toBe('クリック');
|
|
191
|
+
expect(dictionary.has('commands.click')).toBe(true);
|
|
192
|
+
expect(dictionary.has('commands.nonexistent')).toBe(false);
|
|
193
|
+
|
|
194
|
+
// Test dictionary keys
|
|
195
|
+
const keys = dictionary.keys();
|
|
196
|
+
expect(keys).toContain('commands.click');
|
|
197
|
+
expect(keys).toContain('modifiers.to');
|
|
198
|
+
|
|
199
|
+
// Test setting new values
|
|
200
|
+
dictionary.set('commands.test', 'テスト');
|
|
201
|
+
expect(dictionary.get('commands.test')).toBe('テスト');
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
describe('Formatting Utilities', () => {
|
|
207
|
+
it('should provide locale-aware number formatting', async () => {
|
|
208
|
+
const result = await i18nContext.initialize({
|
|
209
|
+
locale: 'de-DE',
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
expect(result.success).toBe(true);
|
|
213
|
+
|
|
214
|
+
if (result.success && result.value) {
|
|
215
|
+
const { format } = result.value;
|
|
216
|
+
|
|
217
|
+
// Number formatting (format may vary by environment)
|
|
218
|
+
const formatted = format.number(1234.56);
|
|
219
|
+
expect(typeof formatted).toBe('string');
|
|
220
|
+
expect(formatted).toMatch(/1[,\s]?234/); // May have comma or space separator
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it('should provide locale-aware date formatting', async () => {
|
|
225
|
+
const result = await i18nContext.initialize({
|
|
226
|
+
locale: 'fr-FR',
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
expect(result.success).toBe(true);
|
|
230
|
+
|
|
231
|
+
if (result.success && result.value) {
|
|
232
|
+
const { format } = result.value;
|
|
233
|
+
|
|
234
|
+
const testDate = new Date('2024-01-15');
|
|
235
|
+
const formatted = format.date(testDate, {
|
|
236
|
+
year: 'numeric',
|
|
237
|
+
month: 'long',
|
|
238
|
+
day: 'numeric',
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
expect(typeof formatted).toBe('string');
|
|
242
|
+
expect(formatted).toBeTruthy(); // Date formatting succeeds
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it('should provide currency formatting', async () => {
|
|
247
|
+
const result = await i18nContext.initialize({
|
|
248
|
+
locale: 'en-US',
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
expect(result.success).toBe(true);
|
|
252
|
+
|
|
253
|
+
if (result.success && result.value) {
|
|
254
|
+
const { format } = result.value;
|
|
255
|
+
|
|
256
|
+
const formatted = format.currency(1234.56, 'USD');
|
|
257
|
+
expect(typeof formatted).toBe('string');
|
|
258
|
+
expect(formatted).toMatch(/1[,\s]?234/); // Contains the number part with possible separators
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
it('should provide relative time formatting', async () => {
|
|
263
|
+
const result = await i18nContext.initialize({
|
|
264
|
+
locale: 'en',
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
expect(result.success).toBe(true);
|
|
268
|
+
|
|
269
|
+
if (result.success && result.value) {
|
|
270
|
+
const { format } = result.value;
|
|
271
|
+
|
|
272
|
+
const relative = format.relative(-1, 'day');
|
|
273
|
+
expect(relative).toMatch(/yesterday|1 day ago/);
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
describe('Validation and Error Handling', () => {
|
|
279
|
+
it('should validate locale format', () => {
|
|
280
|
+
const validationResult = i18nContext.validate({
|
|
281
|
+
locale: 'invalid-locale',
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
expect(validationResult.isValid).toBe(false);
|
|
285
|
+
expect(validationResult.errors).toHaveLength(1);
|
|
286
|
+
expect(validationResult.errors[0].type).toBe('invalid-locale');
|
|
287
|
+
expect(validationResult.suggestions).toContain(
|
|
288
|
+
'Use standard locale codes like "en", "es", "fr", "de", "ja", "zh"'
|
|
289
|
+
);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it('should validate dictionary completeness', () => {
|
|
293
|
+
const incompleteDict = {
|
|
294
|
+
commands: { click: 'clic' },
|
|
295
|
+
// Missing other required categories
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
const validationResult = i18nContext.validate({
|
|
299
|
+
locale: 'es',
|
|
300
|
+
dictionaries: {
|
|
301
|
+
es: incompleteDict,
|
|
302
|
+
},
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
expect(validationResult.isValid).toBe(false);
|
|
306
|
+
expect(validationResult.errors.length).toBeGreaterThan(0);
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it('should handle initialization failures gracefully', async () => {
|
|
310
|
+
const result = await i18nContext.initialize({
|
|
311
|
+
locale: '', // Invalid empty locale
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
expect(result.success).toBe(false);
|
|
315
|
+
expect(result.errors).toBeDefined();
|
|
316
|
+
expect(result.suggestions).toBeDefined();
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
describe('Performance Tracking', () => {
|
|
321
|
+
it('should track performance metrics', async () => {
|
|
322
|
+
// Initialize multiple times to build performance history
|
|
323
|
+
for (let i = 0; i < 3; i++) {
|
|
324
|
+
await i18nContext.initialize({
|
|
325
|
+
locale: 'en',
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const metrics = i18nContext.getPerformanceMetrics();
|
|
330
|
+
|
|
331
|
+
expect(metrics.totalInitializations).toBeGreaterThanOrEqual(3);
|
|
332
|
+
expect(typeof metrics.successRate).toBe('number');
|
|
333
|
+
expect(typeof metrics.averageDuration).toBe('number');
|
|
334
|
+
expect(metrics.evaluationHistory).toBeDefined();
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
describe('Factory Functions', () => {
|
|
339
|
+
it('should create context through factory function', () => {
|
|
340
|
+
const context = createI18nContext();
|
|
341
|
+
expect(context).toBeInstanceOf(TypedI18nContextImplementation);
|
|
342
|
+
expect(context.name).toBe('i18nContext');
|
|
343
|
+
expect(context.category).toBe('Universal');
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
it('should create enhanced i18n through convenience function', async () => {
|
|
347
|
+
const result = await createEnhancedI18n('zh-CN', {
|
|
348
|
+
fallbackLocale: 'en',
|
|
349
|
+
environment: 'frontend',
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
expect(result).toBeDefined();
|
|
353
|
+
expect(typeof result.success).toBe('boolean');
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
describe('Enhanced Pattern Compliance', () => {
|
|
358
|
+
it('should have required enhanced pattern properties', () => {
|
|
359
|
+
expect(i18nContext.name).toBe('i18nContext');
|
|
360
|
+
expect(i18nContext.category).toBe('Universal');
|
|
361
|
+
expect(i18nContext.description).toBeDefined();
|
|
362
|
+
expect(i18nContext.inputSchema).toBeDefined();
|
|
363
|
+
expect(i18nContext.outputType).toBe('Context');
|
|
364
|
+
expect(i18nContext.metadata).toBeDefined();
|
|
365
|
+
expect(i18nContext.documentation).toBeDefined();
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
it('should have comprehensive metadata', () => {
|
|
369
|
+
const { metadata } = i18nContext;
|
|
370
|
+
|
|
371
|
+
expect(metadata.category).toBe('Universal');
|
|
372
|
+
expect(metadata.complexity).toBe('moderate');
|
|
373
|
+
expect(Array.isArray(metadata.sideEffects)).toBe(true);
|
|
374
|
+
expect(Array.isArray(metadata.dependencies)).toBe(true);
|
|
375
|
+
expect(Array.isArray(metadata.examples)).toBe(true);
|
|
376
|
+
expect(metadata.examples.length).toBeGreaterThan(0);
|
|
377
|
+
expect(metadata.environmentRequirements).toBeDefined();
|
|
378
|
+
expect(metadata.performance).toBeDefined();
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
it('should have LLM-compatible documentation', () => {
|
|
382
|
+
const { documentation } = i18nContext;
|
|
383
|
+
|
|
384
|
+
expect(documentation.summary).toBeDefined();
|
|
385
|
+
expect(Array.isArray(documentation.parameters)).toBe(true);
|
|
386
|
+
expect(documentation.returns).toBeDefined();
|
|
387
|
+
expect(Array.isArray(documentation.examples)).toBe(true);
|
|
388
|
+
expect(documentation.examples.length).toBeGreaterThan(0);
|
|
389
|
+
expect(Array.isArray(documentation.tags)).toBe(true);
|
|
390
|
+
expect(documentation.tags).toContain('i18n');
|
|
391
|
+
expect(documentation.tags).toContain('enhanced-pattern');
|
|
392
|
+
});
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
describe('Integration with Indigenous Languages', () => {
|
|
396
|
+
it('should support Quechua language', async () => {
|
|
397
|
+
const quechuaDict = {
|
|
398
|
+
commands: { click: "ñit'iy", add: 'yapay', remove: 'qichuy' },
|
|
399
|
+
modifiers: { to: 'man', from: 'manta', with: 'wan' },
|
|
400
|
+
events: { click: "ñit'iy", hover: 'puray', focus: 'qhaway' },
|
|
401
|
+
logical: { and: 'chaymanta', or: 'utaq', not: 'mana' },
|
|
402
|
+
temporal: { then: 'chayqa', wait: 'suyay', after: 'qhipaman' },
|
|
403
|
+
values: { true: 'cheqaq', false: 'mana cheqaq', null: 'mana ima' },
|
|
404
|
+
attributes: { class: 'kaq', id: 'riqsichiq', style: "rikch'ay" },
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
const result = await i18nContext.initialize({
|
|
408
|
+
locale: 'qu',
|
|
409
|
+
dictionaries: { qu: quechuaDict },
|
|
410
|
+
environment: 'universal',
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
expect(result.success).toBe(true);
|
|
414
|
+
|
|
415
|
+
if (result.success && result.value) {
|
|
416
|
+
const translate = result.value.translate;
|
|
417
|
+
expect(translate('click', 'commands')).toBe("ñit'iy");
|
|
418
|
+
expect(translate('add', 'commands')).toBe('yapay');
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
it('should support Swahili language', async () => {
|
|
423
|
+
const swahiliDict = {
|
|
424
|
+
commands: { click: 'bonyeza', add: 'ongeza', remove: 'ondoa' },
|
|
425
|
+
modifiers: { to: 'kwa', from: 'kutoka', with: 'na' },
|
|
426
|
+
events: { click: 'bonyeza', hover: 'ruka', focus: 'lenga' },
|
|
427
|
+
logical: { and: 'na', or: 'au', not: 'si' },
|
|
428
|
+
temporal: { then: 'kisha', wait: 'ngoja', after: 'baada' },
|
|
429
|
+
values: { true: 'kweli', false: 'uongo', null: 'tupu' },
|
|
430
|
+
attributes: { class: 'darasa', id: 'kitambulisho', style: 'mtindo' },
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
const result = await i18nContext.initialize({
|
|
434
|
+
locale: 'sw',
|
|
435
|
+
dictionaries: { sw: swahiliDict },
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
expect(result.success).toBe(true);
|
|
439
|
+
|
|
440
|
+
if (result.success && result.value) {
|
|
441
|
+
const translate = result.value.translate;
|
|
442
|
+
expect(translate('click', 'commands')).toBe('bonyeza');
|
|
443
|
+
expect(translate('add', 'commands')).toBe('ongeza');
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
});
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
describe('Enhanced I18n Export', () => {
|
|
450
|
+
it('should export singleton implementation', () => {
|
|
451
|
+
expect(enhancedI18nImplementation).toBeInstanceOf(TypedI18nContextImplementation);
|
|
452
|
+
expect(enhancedI18nImplementation.name).toBe('i18nContext');
|
|
453
|
+
});
|
|
454
|
+
});
|