@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.
Files changed (96) hide show
  1. package/README.md +286 -0
  2. package/dist/browser.cjs +7669 -0
  3. package/dist/browser.cjs.map +1 -0
  4. package/dist/browser.d.cts +50 -0
  5. package/dist/browser.d.ts +50 -0
  6. package/dist/browser.js +7592 -0
  7. package/dist/browser.js.map +1 -0
  8. package/dist/hyperfixi-i18n.min.js +2 -0
  9. package/dist/hyperfixi-i18n.min.js.map +1 -0
  10. package/dist/hyperfixi-i18n.mjs +8558 -0
  11. package/dist/hyperfixi-i18n.mjs.map +1 -0
  12. package/dist/index.cjs +14205 -0
  13. package/dist/index.cjs.map +1 -0
  14. package/dist/index.d.cts +947 -0
  15. package/dist/index.d.ts +947 -0
  16. package/dist/index.js +14095 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/transformer-Ckask-yw.d.cts +1041 -0
  19. package/dist/transformer-Ckask-yw.d.ts +1041 -0
  20. package/package.json +84 -0
  21. package/src/browser.ts +122 -0
  22. package/src/compatibility/browser-tests/grammar-demo.spec.ts +169 -0
  23. package/src/constants.ts +366 -0
  24. package/src/dictionaries/ar.ts +233 -0
  25. package/src/dictionaries/bn.ts +156 -0
  26. package/src/dictionaries/de.ts +233 -0
  27. package/src/dictionaries/derive.ts +515 -0
  28. package/src/dictionaries/en.ts +237 -0
  29. package/src/dictionaries/es.ts +233 -0
  30. package/src/dictionaries/fr.ts +233 -0
  31. package/src/dictionaries/hi.ts +270 -0
  32. package/src/dictionaries/id.ts +233 -0
  33. package/src/dictionaries/index.ts +238 -0
  34. package/src/dictionaries/it.ts +233 -0
  35. package/src/dictionaries/ja.ts +233 -0
  36. package/src/dictionaries/ko.ts +233 -0
  37. package/src/dictionaries/ms.ts +276 -0
  38. package/src/dictionaries/pl.ts +239 -0
  39. package/src/dictionaries/pt.ts +237 -0
  40. package/src/dictionaries/qu.ts +233 -0
  41. package/src/dictionaries/ru.ts +270 -0
  42. package/src/dictionaries/sw.ts +233 -0
  43. package/src/dictionaries/th.ts +156 -0
  44. package/src/dictionaries/tl.ts +276 -0
  45. package/src/dictionaries/tr.ts +233 -0
  46. package/src/dictionaries/uk.ts +270 -0
  47. package/src/dictionaries/vi.ts +210 -0
  48. package/src/dictionaries/zh.ts +233 -0
  49. package/src/enhanced-i18n.test.ts +454 -0
  50. package/src/enhanced-i18n.ts +713 -0
  51. package/src/examples/new-languages.ts +326 -0
  52. package/src/formatting.test.ts +213 -0
  53. package/src/formatting.ts +416 -0
  54. package/src/grammar/direct-mappings.ts +353 -0
  55. package/src/grammar/grammar.test.ts +1053 -0
  56. package/src/grammar/index.ts +59 -0
  57. package/src/grammar/profiles/index.ts +860 -0
  58. package/src/grammar/transformer.ts +1318 -0
  59. package/src/grammar/types.ts +630 -0
  60. package/src/index.ts +202 -0
  61. package/src/new-languages.test.ts +389 -0
  62. package/src/parser/analyze-conflicts.test.ts +229 -0
  63. package/src/parser/ar.ts +40 -0
  64. package/src/parser/create-provider.ts +309 -0
  65. package/src/parser/de.ts +36 -0
  66. package/src/parser/es.ts +31 -0
  67. package/src/parser/fr.ts +31 -0
  68. package/src/parser/id.ts +34 -0
  69. package/src/parser/index.ts +50 -0
  70. package/src/parser/ja.ts +36 -0
  71. package/src/parser/ko.ts +37 -0
  72. package/src/parser/locale-manager.test.ts +198 -0
  73. package/src/parser/locale-manager.ts +197 -0
  74. package/src/parser/parser-integration.test.ts +439 -0
  75. package/src/parser/pt.ts +37 -0
  76. package/src/parser/qu.ts +37 -0
  77. package/src/parser/sw.ts +37 -0
  78. package/src/parser/tr.ts +38 -0
  79. package/src/parser/types.ts +113 -0
  80. package/src/parser/zh.ts +38 -0
  81. package/src/plugins/vite.ts +224 -0
  82. package/src/plugins/webpack.ts +124 -0
  83. package/src/pluralization.test.ts +197 -0
  84. package/src/pluralization.ts +393 -0
  85. package/src/runtime.ts +441 -0
  86. package/src/ssr-integration.ts +225 -0
  87. package/src/test-setup.ts +195 -0
  88. package/src/translation-validation.test.ts +171 -0
  89. package/src/translator.test.ts +252 -0
  90. package/src/translator.ts +297 -0
  91. package/src/types.ts +209 -0
  92. package/src/utils/locale.ts +190 -0
  93. package/src/utils/tokenizer-adapter.ts +469 -0
  94. package/src/utils/tokenizer.ts +19 -0
  95. package/src/validators/index.ts +174 -0
  96. package/src/validators/schema.ts +129 -0
package/src/index.ts ADDED
@@ -0,0 +1,202 @@
1
+ // packages/i18n/src/index.ts
2
+
3
+ // =============================================================================
4
+ // Type Exports
5
+ // =============================================================================
6
+
7
+ export type {
8
+ DictionaryCategory,
9
+ Dictionary,
10
+ I18nConfig,
11
+ TranslationOptions,
12
+ ValidationResult,
13
+ ValidationError,
14
+ ValidationWarning,
15
+ LocaleMetadata,
16
+ TranslationContext,
17
+ TokenType,
18
+ Token,
19
+ TranslationResult,
20
+ } from './types';
21
+
22
+ export {
23
+ DICTIONARY_CATEGORIES,
24
+ isDictionaryCategory,
25
+ getDictionaryCategory,
26
+ forEachCategory,
27
+ findInDictionary,
28
+ translateFromEnglish,
29
+ } from './types';
30
+
31
+ // =============================================================================
32
+ // Translator Exports
33
+ // =============================================================================
34
+
35
+ export { HyperscriptTranslator } from './translator';
36
+
37
+ // =============================================================================
38
+ // Dictionary Exports
39
+ // =============================================================================
40
+
41
+ export {
42
+ dictionaries,
43
+ en,
44
+ es,
45
+ ko,
46
+ zh,
47
+ fr,
48
+ de,
49
+ ja,
50
+ ar,
51
+ tr,
52
+ id,
53
+ qu,
54
+ sw,
55
+ pt,
56
+ supportedLocales,
57
+ isLocaleSupported,
58
+ getDictionary,
59
+ } from './dictionaries';
60
+
61
+ // =============================================================================
62
+ // Parser Integration Exports
63
+ // =============================================================================
64
+
65
+ export type { KeywordProvider, KeywordProviderOptions } from './parser';
66
+
67
+ export {
68
+ createKeywordProvider,
69
+ createEnglishProvider,
70
+ ENGLISH_COMMANDS,
71
+ ENGLISH_KEYWORDS,
72
+ UNIVERSAL_ENGLISH_KEYWORDS,
73
+ // Locale packs
74
+ esKeywords,
75
+ esDictionary,
76
+ jaKeywords,
77
+ jaDictionary,
78
+ frKeywords,
79
+ frDictionary,
80
+ deKeywords,
81
+ deDictionary,
82
+ arKeywords,
83
+ arDictionary,
84
+ koKeywords,
85
+ koDictionary,
86
+ zhKeywords,
87
+ zhDictionary,
88
+ trKeywords,
89
+ trDictionary,
90
+ idKeywords,
91
+ idDictionary,
92
+ quKeywords,
93
+ quDictionary,
94
+ swKeywords,
95
+ swDictionary,
96
+ ptKeywords,
97
+ ptDictionary,
98
+ // Locale management
99
+ LocaleManager,
100
+ detectBrowserLocale,
101
+ } from './parser';
102
+
103
+ // Re-export key utilities
104
+ export { detectLocale, getBrowserLocales, isRTL } from './utils/locale';
105
+ export { tokenize } from './utils/tokenizer';
106
+ export { validate } from './validators';
107
+
108
+ // Plugin exports
109
+ export { hyperscriptI18nVitePlugin } from './plugins/vite';
110
+ export { HyperscriptI18nWebpackPlugin } from './plugins/webpack';
111
+
112
+ // SSR integration
113
+ export { SSRLocaleManager, createExpressI18nMiddleware, withI18n } from './ssr-integration';
114
+ export type { SSRLocaleContext, SSRLocaleOptions } from './ssr-integration';
115
+
116
+ // Pluralization
117
+ export {
118
+ pluralRules,
119
+ getPlural,
120
+ PluralAwareTranslator,
121
+ pluralTimeExpressions,
122
+ } from './pluralization';
123
+ export type { PluralRule, PluralForms } from './pluralization';
124
+
125
+ // Formatting
126
+ export {
127
+ NumberFormatter,
128
+ DateFormatter,
129
+ LocaleFormatter,
130
+ getFormatter,
131
+ formatForLocale,
132
+ } from './formatting';
133
+ export type {
134
+ NumberFormatOptions,
135
+ DateFormatOptions,
136
+ RelativeTimeFormatOptions,
137
+ } from './formatting';
138
+
139
+ // Runtime i18n
140
+ export { RuntimeI18nManager, initializeI18n, getI18n, runtimeI18n } from './runtime';
141
+ export type { RuntimeI18nOptions } from './runtime';
142
+
143
+ // Create and export default translator instance
144
+ import { HyperscriptTranslator } from './translator';
145
+ export const defaultTranslator = new HyperscriptTranslator({ locale: 'en' });
146
+
147
+ // Create and export default runtime instance for browser usage
148
+ import { RuntimeI18nManager } from './runtime';
149
+ export const defaultRuntime = new RuntimeI18nManager({ locale: 'en' });
150
+
151
+ // Enhanced I18n Implementation (following enhanced pattern)
152
+ export {
153
+ TypedI18nContextImplementation,
154
+ createI18nContext,
155
+ createEnhancedI18n,
156
+ enhancedI18nImplementation,
157
+ EnhancedI18nInputSchema,
158
+ EnhancedI18nOutputSchema,
159
+ } from './enhanced-i18n';
160
+ export type { EnhancedI18nInput, EnhancedI18nOutput } from './enhanced-i18n';
161
+
162
+ // Grammar-aware transformation system (Phase 2)
163
+ export {
164
+ // Types
165
+ type SemanticRole,
166
+ type WordOrder,
167
+ type AdpositionType,
168
+ type MorphologyType,
169
+ type GrammaticalMarker,
170
+ type LanguageProfile,
171
+ type GrammarRule,
172
+ type PatternMatcher,
173
+ type PatternTransform,
174
+ type ParsedStatement,
175
+ type ParsedElement,
176
+ UNIVERSAL_PATTERNS,
177
+ LANGUAGE_FAMILY_DEFAULTS,
178
+ reorderRoles,
179
+ insertMarkers,
180
+ transformStatement,
181
+ // Profiles
182
+ profiles,
183
+ getProfile,
184
+ getSupportedLocales,
185
+ englishProfile,
186
+ japaneseProfile,
187
+ koreanProfile,
188
+ chineseProfile,
189
+ arabicProfile,
190
+ turkishProfile,
191
+ spanishProfile,
192
+ indonesianProfile,
193
+ quechuaProfile,
194
+ swahiliProfile,
195
+ // Transformer
196
+ GrammarTransformer,
197
+ parseStatement,
198
+ toLocale,
199
+ toEnglish,
200
+ translate,
201
+ examples as grammarExamples,
202
+ } from './grammar';
@@ -0,0 +1,389 @@
1
+ /**
2
+ * Tests for newly added language support
3
+ * Turkish, Indonesian, Quechua, and Swahili
4
+ */
5
+
6
+ import { describe, it, expect } from 'vitest';
7
+ import { HyperscriptTranslator } from './translator';
8
+ import { dictionaries } from './dictionaries';
9
+ import { PluralAwareTranslator, pluralRules } from './pluralization';
10
+
11
+ describe('New Language Support', () => {
12
+ const translator = new HyperscriptTranslator({ locale: 'en' });
13
+
14
+ describe('Turkish (tr)', () => {
15
+ it('should have complete dictionary coverage', () => {
16
+ expect(dictionaries.tr).toBeDefined();
17
+ expect(dictionaries.tr.commands.on).toBe('üzerinde');
18
+ expect(dictionaries.tr.commands.add).toBe('ekle');
19
+ expect(dictionaries.tr.commands.if).toBe('eğer');
20
+ expect(dictionaries.tr.logical.and).toBe('ve');
21
+ expect(dictionaries.tr.events.click).toBe('tıklama');
22
+ });
23
+
24
+ it('should translate basic commands', () => {
25
+ const result = translator.translate('on click add .active to me', { from: 'en', to: 'tr' });
26
+ // TODO: Once grammar transformation is implemented, test for native word order: 'tıklama üzerinde'
27
+ // Current word-by-word translation preserves English order
28
+ expect(result).toContain('tıklama'); // click → tıklama
29
+ expect(result).toContain('üzerinde'); // on → üzerinde
30
+ expect(result).toContain('ekle'); // add → ekle
31
+ });
32
+
33
+ it('should handle conditional logic', () => {
34
+ const result = translator.translate('if my value is empty then hide me else show me', {
35
+ from: 'en',
36
+ to: 'tr',
37
+ });
38
+ expect(result).toContain('eğer');
39
+ expect(result).toContain('yoksa');
40
+ });
41
+
42
+ it('should translate time expressions', () => {
43
+ const result = translator.translate('wait 3 seconds then continue', { from: 'en', to: 'tr' });
44
+ expect(result).toContain('bekle');
45
+ expect(result).toContain('saniye');
46
+ });
47
+
48
+ it('should handle events properly', () => {
49
+ const result = translator.translate('on mouseenter add .hover', { from: 'en', to: 'tr' });
50
+ expect(result).toContain('fare_gir');
51
+ expect(result).toContain('ekle');
52
+ });
53
+
54
+ it('should support pluralization', () => {
55
+ expect(pluralRules.tr).toBeDefined();
56
+ expect(pluralRules.tr(1)).toBe('one');
57
+ expect(pluralRules.tr(5)).toBe('other');
58
+ });
59
+
60
+ it('should handle plural time expressions', () => {
61
+ const singular = PluralAwareTranslator.translateTimeExpression(1, 'second', 'tr');
62
+ const plural = PluralAwareTranslator.translateTimeExpression(5, 'second', 'tr');
63
+ expect(singular).toBe('1 saniye');
64
+ expect(plural).toBe('5 saniye');
65
+ });
66
+ });
67
+
68
+ describe('Indonesian (id)', () => {
69
+ it('should have complete dictionary coverage', () => {
70
+ expect(dictionaries.id).toBeDefined();
71
+ expect(dictionaries.id.commands.on).toBe('pada');
72
+ expect(dictionaries.id.commands.add).toBe('tambah');
73
+ expect(dictionaries.id.commands.if).toBe('jika');
74
+ expect(dictionaries.id.logical.and).toBe('dan');
75
+ expect(dictionaries.id.events.click).toBe('klik');
76
+ });
77
+
78
+ it('should translate basic commands', () => {
79
+ const result = translator.translate('on click toggle .selected', { from: 'en', to: 'id' });
80
+ // TODO: Once grammar transformation is implemented, test for native word order
81
+ expect(result).toContain('klik'); // click → klik
82
+ expect(result).toContain('pada'); // on → pada
83
+ expect(result).toContain('ganti'); // toggle → ganti
84
+ });
85
+
86
+ it('should handle form interactions', () => {
87
+ const result = translator.translate('on submit take form data then send it', {
88
+ from: 'en',
89
+ to: 'id',
90
+ });
91
+ // TODO: Test expects Swahili-like translations - verify Indonesian dictionary values
92
+ expect(result).toContain('kirim'); // submit/send → kirim
93
+ expect(result).toContain('ambil'); // take → ambil
94
+ });
95
+
96
+ it('should translate async operations', () => {
97
+ const result = translator.translate('fetch /api/data then put result into #content', {
98
+ from: 'en',
99
+ to: 'id',
100
+ });
101
+ expect(result).toContain('ambil'); // fetch → ambil
102
+ expect(result).toContain('taruh'); // put → taruh
103
+ expect(result).toContain('hasil'); // result → hasil
104
+ });
105
+
106
+ it('should support simple pluralization (no actual plural forms)', () => {
107
+ expect(pluralRules.id).toBeDefined();
108
+ expect(pluralRules.id(1)).toBe('other');
109
+ expect(pluralRules.id(5)).toBe('other');
110
+ });
111
+
112
+ it('should handle time expressions without pluralization', () => {
113
+ const singular = PluralAwareTranslator.translateTimeExpression(1, 'minute', 'id');
114
+ const plural = PluralAwareTranslator.translateTimeExpression(5, 'minute', 'id');
115
+ expect(singular).toBe('1 menit');
116
+ expect(plural).toBe('5 menit');
117
+ });
118
+ });
119
+
120
+ describe('Quechua (qu)', () => {
121
+ it('should have complete dictionary coverage', () => {
122
+ expect(dictionaries.qu).toBeDefined();
123
+ expect(dictionaries.qu.commands.on).toBe('kaqpi');
124
+ expect(dictionaries.qu.commands.add).toBe('yapay');
125
+ expect(dictionaries.qu.commands.if).toBe('sichus');
126
+ expect(dictionaries.qu.logical.and).toBe('chaymanta');
127
+ expect(dictionaries.qu.events.click).toBe('ñitiy');
128
+ });
129
+
130
+ it('should translate basic commands', () => {
131
+ const result = translator.translate('on click put "Allin p\'unchaw" into #greeting', {
132
+ from: 'en',
133
+ to: 'qu',
134
+ });
135
+ // TODO: Once grammar transformation is implemented, test for native SOV word order
136
+ expect(result).toContain('ñitiy'); // click → ñitiy
137
+ expect(result).toContain('kaqpi'); // on → kaqpi
138
+ expect(result).toContain('churay'); // put → churay
139
+ });
140
+
141
+ it('should handle complex expressions', () => {
142
+ const result = translator.translate('if target matches .button then add .pressed', {
143
+ from: 'en',
144
+ to: 'qu',
145
+ });
146
+ expect(result).toContain('sichus'); // if → sichus
147
+ expect(result).toContain('tupan'); // matches → tupan
148
+ expect(result).toContain('yapay'); // add → yapay
149
+ });
150
+
151
+ it('should translate element references', () => {
152
+ const result = translator.translate('tell closest .card to add .highlight', {
153
+ from: 'en',
154
+ to: 'qu',
155
+ });
156
+ expect(result).toContain('niy'); // tell → niy
157
+ expect(result).toContain('aswan_kaylla'); // closest → aswan_kaylla
158
+ });
159
+
160
+ it('should support pluralization', () => {
161
+ expect(pluralRules.qu).toBeDefined();
162
+ expect(pluralRules.qu(1)).toBe('one');
163
+ expect(pluralRules.qu(5)).toBe('other');
164
+ });
165
+
166
+ it('should handle plural time expressions', () => {
167
+ const singular = PluralAwareTranslator.translateTimeExpression(1, 'hour', 'qu');
168
+ const plural = PluralAwareTranslator.translateTimeExpression(3, 'hour', 'qu');
169
+ expect(singular).toBe('1 hora');
170
+ expect(plural).toBe('3 horakuna');
171
+ });
172
+ });
173
+
174
+ describe('Swahili (sw)', () => {
175
+ it('should have complete dictionary coverage', () => {
176
+ expect(dictionaries.sw).toBeDefined();
177
+ expect(dictionaries.sw.commands.on).toBe('kwenye');
178
+ expect(dictionaries.sw.commands.add).toBe('ongeza');
179
+ expect(dictionaries.sw.commands.if).toBe('kama');
180
+ expect(dictionaries.sw.logical.and).toBe('na');
181
+ expect(dictionaries.sw.events.click).toBe('bonyeza');
182
+ });
183
+
184
+ it('should translate basic commands', () => {
185
+ const result = translator.translate('on click put "Habari za asubuhi" into .message', {
186
+ from: 'en',
187
+ to: 'sw',
188
+ });
189
+ // TODO: Once grammar transformation is implemented, test for native word order
190
+ expect(result).toContain('bonyeza'); // click → bonyeza
191
+ expect(result).toContain('kwenye'); // on → kwenye
192
+ expect(result).toContain('weka'); // put → weka
193
+ });
194
+
195
+ it('should handle double-click events', () => {
196
+ const result = translator.translate('on dblclick focus on me', { from: 'en', to: 'sw' });
197
+ expect(result).toContain('bonyeza_mara_mbili'); // dblclick → bonyeza_mara_mbili
198
+ expect(result).toContain('zingatia'); // focus → zingatia
199
+ });
200
+
201
+ it('should translate navigation commands', () => {
202
+ const result = translator.translate('go to next .panel with transition', {
203
+ from: 'en',
204
+ to: 'sw',
205
+ });
206
+ expect(result).toContain('nenda'); // go → nenda
207
+ expect(result).toContain('ijayo'); // next → ijayo
208
+ });
209
+
210
+ it('should support pluralization', () => {
211
+ expect(pluralRules.sw).toBeDefined();
212
+ expect(pluralRules.sw(1)).toBe('one');
213
+ expect(pluralRules.sw(5)).toBe('other');
214
+ });
215
+
216
+ it('should handle time expressions with special plural for hours', () => {
217
+ const singularHour = PluralAwareTranslator.translateTimeExpression(1, 'hour', 'sw');
218
+ const pluralHours = PluralAwareTranslator.translateTimeExpression(5, 'hour', 'sw');
219
+ expect(singularHour).toBe('1 saa');
220
+ expect(pluralHours).toBe('5 masaa');
221
+ });
222
+ });
223
+
224
+ describe('Cross-language consistency', () => {
225
+ const testExpressions = [
226
+ 'on click add .active',
227
+ 'if my value exists then show me',
228
+ 'wait 2 seconds then hide me',
229
+ 'on mouseenter tell closest .parent to add .hover',
230
+ 'fetch /api/data then put result into #content',
231
+ ];
232
+
233
+ const newLanguages = ['tr', 'id', 'qu', 'sw'];
234
+
235
+ it('should translate all test expressions in all new languages', () => {
236
+ for (const lang of newLanguages) {
237
+ for (const expr of testExpressions) {
238
+ expect(() => {
239
+ const result = translator.translate(expr, { from: 'en', to: lang });
240
+ expect(result).toBeTruthy();
241
+ expect(result.length).toBeGreaterThan(0);
242
+ }).not.toThrow();
243
+ }
244
+ }
245
+ });
246
+
247
+ it('should maintain consistent command translations', () => {
248
+ const commands = ['add', 'remove', 'show', 'hide', 'wait', 'put'];
249
+
250
+ for (const lang of newLanguages) {
251
+ const dict = dictionaries[lang];
252
+ for (const cmd of commands) {
253
+ expect(dict.commands[cmd]).toBeTruthy();
254
+ expect(dict.commands[cmd].length).toBeGreaterThan(0);
255
+ }
256
+ }
257
+ });
258
+
259
+ it('should have consistent event translations', () => {
260
+ const events = ['click', 'mouseenter', 'mouseleave', 'focus', 'blur', 'submit'];
261
+
262
+ for (const lang of newLanguages) {
263
+ const dict = dictionaries[lang];
264
+ for (const event of events) {
265
+ expect(dict.events[event]).toBeTruthy();
266
+ expect(dict.events[event].length).toBeGreaterThan(0);
267
+ }
268
+ }
269
+ });
270
+
271
+ it('should support ordinal numbers in all new languages', () => {
272
+ for (const lang of newLanguages) {
273
+ const first = PluralAwareTranslator.getOrdinal(1, lang);
274
+ const second = PluralAwareTranslator.getOrdinal(2, lang);
275
+ const third = PluralAwareTranslator.getOrdinal(3, lang);
276
+
277
+ expect(first).toBeTruthy();
278
+ expect(second).toBeTruthy();
279
+ expect(third).toBeTruthy();
280
+ expect(first).not.toBe(second);
281
+ }
282
+ });
283
+ });
284
+
285
+ describe('Cultural and linguistic accuracy', () => {
286
+ it('should use appropriate Turkish agglutination patterns', () => {
287
+ const dict = dictionaries.tr;
288
+ // Turkish typically uses suffixes, our translations should reflect this
289
+ expect(dict.modifiers.to).toBe('e');
290
+ expect(dict.modifiers.from).toBe('den');
291
+ expect(dict.modifiers.in).toBe('içinde');
292
+ });
293
+
294
+ it('should use appropriate Indonesian word order', () => {
295
+ const dict = dictionaries.id;
296
+ // Indonesian follows SVO order, similar to English
297
+ expect(dict.commands.if).toBe('jika');
298
+ expect(dict.logical.then).toBe('lalu');
299
+ expect(dict.logical.else).toBe('lainnya');
300
+ });
301
+
302
+ it('should reflect Quechua agglutinative nature', () => {
303
+ const dict = dictionaries.qu;
304
+ // Quechua uses complex suffixation
305
+ expect(dict.modifiers.to).toBe('man');
306
+ expect(dict.modifiers.from).toBe('manta');
307
+ expect(dict.expressions.children).toBe('wawakuna'); // -kuna is plural marker
308
+ });
309
+
310
+ it('should use appropriate Swahili noun class system hints', () => {
311
+ const dict = dictionaries.sw;
312
+ // Swahili has noun classes, reflected in some translations
313
+ expect(dict.expressions.children).toBe('watoto'); // wa- prefix for people
314
+ expect(dict.values.window).toBe('dirisha'); // appropriate class
315
+ });
316
+ });
317
+
318
+ describe('Real-world usage scenarios', () => {
319
+ it('should handle e-commerce interactions in Turkish', () => {
320
+ const expr =
321
+ 'on click if stock exists then add product to cart else show out-of-stock message';
322
+ const result = translator.translate(expr, { from: 'en', to: 'tr' });
323
+ // TODO: Test native word order once grammar transformation is implemented
324
+ expect(result).toContain('tıklama'); // click
325
+ expect(result).toContain('üzerinde'); // on
326
+ expect(result).toContain('eğer'); // if
327
+ expect(result).toContain('yoksa'); // else
328
+ });
329
+
330
+ it('should handle form validation in Indonesian', () => {
331
+ const expr = 'on blur if my value is empty then add .error to closest .field';
332
+ const result = translator.translate(expr, { from: 'en', to: 'id' });
333
+ expect(result).toContain('blur'); // blur (event name preserved or translated)
334
+ expect(result).toContain('jika'); // if
335
+ });
336
+
337
+ it('should handle social interactions in Quechua', () => {
338
+ const expr = 'on click toggle .liked then send like-count to /api/likes';
339
+ const result = translator.translate(expr, { from: 'en', to: 'qu' });
340
+ expect(result).toContain('ñitiy'); // click
341
+ expect(result).toContain('kaqpi'); // on
342
+ expect(result).toContain('tikray'); // toggle
343
+ expect(result).toContain('kachay'); // send
344
+ });
345
+
346
+ it('should handle dashboard updates in Swahili', () => {
347
+ const expr = 'on load fetch /api/dashboard then for each item put item into next .widget';
348
+ const result = translator.translate(expr, { from: 'en', to: 'sw' });
349
+ expect(result).toContain('pakia'); // load
350
+ expect(result).toContain('kwenye'); // on
351
+ expect(result).toContain('leta'); // fetch
352
+ });
353
+ });
354
+
355
+ describe('Performance and edge cases', () => {
356
+ const testLanguages = ['tr', 'id', 'qu', 'sw'];
357
+
358
+ it('should handle very long expressions efficiently', () => {
359
+ const longExpr =
360
+ 'on click if my value matches /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$/ then add .valid to closest .form-group then remove .invalid from closest .form-group then put "Valid email" into next .feedback else add .invalid to closest .form-group then remove .valid from closest .form-group then put "Invalid email format" into next .feedback';
361
+
362
+ for (const lang of testLanguages) {
363
+ expect(() => {
364
+ const result = translator.translate(longExpr, { from: 'en', to: lang });
365
+ expect(result.length).toBeGreaterThan(0);
366
+ }).not.toThrow();
367
+ }
368
+ });
369
+
370
+ it('should handle expressions with mixed content', () => {
371
+ const mixedExpr = 'on click put "Hello مرحبا Hola" into #multilingual-content';
372
+
373
+ for (const lang of testLanguages) {
374
+ const result = translator.translate(mixedExpr, { from: 'en', to: lang });
375
+ expect(result).toContain('"Hello مرحبا Hola"'); // String literals should be preserved
376
+ }
377
+ });
378
+
379
+ it('should handle numeric expressions correctly', () => {
380
+ const numericExpr = 'wait 1.5 seconds then set my opacity to 0.5';
381
+
382
+ for (const lang of testLanguages) {
383
+ const result = translator.translate(numericExpr, { from: 'en', to: lang });
384
+ expect(result).toContain('1.5');
385
+ expect(result).toContain('0.5');
386
+ }
387
+ });
388
+ });
389
+ });