@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,439 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration tests for the i18n parser integration.
|
|
3
|
+
*
|
|
4
|
+
* Tests the actual esKeywords and jaKeywords providers
|
|
5
|
+
* work correctly with the core parser.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, it, expect } from 'vitest';
|
|
9
|
+
import { esKeywords } from './es';
|
|
10
|
+
import { jaKeywords } from './ja';
|
|
11
|
+
import { frKeywords } from './fr';
|
|
12
|
+
import { deKeywords } from './de';
|
|
13
|
+
import { arKeywords } from './ar';
|
|
14
|
+
import { koKeywords } from './ko';
|
|
15
|
+
import { zhKeywords } from './zh';
|
|
16
|
+
import { trKeywords } from './tr';
|
|
17
|
+
import { createKeywordProvider, createEnglishProvider } from './create-provider';
|
|
18
|
+
import { es } from '../dictionaries/es';
|
|
19
|
+
import { ja } from '../dictionaries/ja';
|
|
20
|
+
|
|
21
|
+
describe('KeywordProvider Integration', () => {
|
|
22
|
+
describe('Spanish Provider (esKeywords)', () => {
|
|
23
|
+
it('should resolve Spanish commands to English', () => {
|
|
24
|
+
expect(esKeywords.resolve('alternar')).toBe('toggle');
|
|
25
|
+
expect(esKeywords.resolve('poner')).toBe('put');
|
|
26
|
+
expect(esKeywords.resolve('establecer')).toBe('set');
|
|
27
|
+
expect(esKeywords.resolve('mostrar')).toBe('show');
|
|
28
|
+
expect(esKeywords.resolve('ocultar')).toBe('hide');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should resolve Spanish keywords with priority (commands over modifiers)', () => {
|
|
32
|
+
// Note: Spanish 'en' maps to multiple English words:
|
|
33
|
+
// - commands.on = 'en' (for event handlers)
|
|
34
|
+
// - modifiers.in = 'en' (for prepositions)
|
|
35
|
+
// - modifiers.into = 'en'
|
|
36
|
+
// The resolver prioritizes commands, so 'en' → 'on'
|
|
37
|
+
expect(esKeywords.resolve('en')).toBe('on');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should resolve Spanish events', () => {
|
|
41
|
+
expect(esKeywords.resolve('clic')).toBe('click');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should resolve Spanish modifiers', () => {
|
|
45
|
+
expect(esKeywords.resolve('a')).toBe('to');
|
|
46
|
+
// Note: 'de' maps to both 'from' and 'of' in Spanish dictionary
|
|
47
|
+
// Since modifiers are processed together, the last one wins
|
|
48
|
+
// But commands/logical have priority, so 'de' → 'of' (modifiers.of = 'de')
|
|
49
|
+
expect(esKeywords.resolve('con')).toBe('with');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should resolve Spanish logical operators', () => {
|
|
53
|
+
expect(esKeywords.resolve('y')).toBe('and');
|
|
54
|
+
expect(esKeywords.resolve('o')).toBe('or');
|
|
55
|
+
expect(esKeywords.resolve('no')).toBe('not');
|
|
56
|
+
expect(esKeywords.resolve('entonces')).toBe('then');
|
|
57
|
+
expect(esKeywords.resolve('sino')).toBe('else');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should allow English fallback', () => {
|
|
61
|
+
// English keywords should resolve to themselves
|
|
62
|
+
expect(esKeywords.resolve('toggle')).toBe('toggle');
|
|
63
|
+
expect(esKeywords.resolve('on')).toBe('on');
|
|
64
|
+
expect(esKeywords.resolve('click')).toBe('click');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should correctly identify commands', () => {
|
|
68
|
+
// Spanish commands
|
|
69
|
+
expect(esKeywords.isCommand('alternar')).toBe(true);
|
|
70
|
+
expect(esKeywords.isCommand('poner')).toBe(true);
|
|
71
|
+
// English commands (fallback)
|
|
72
|
+
expect(esKeywords.isCommand('toggle')).toBe(true);
|
|
73
|
+
expect(esKeywords.isCommand('put')).toBe(true);
|
|
74
|
+
// Non-commands
|
|
75
|
+
expect(esKeywords.isCommand('unknown')).toBe(false);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should return locale code', () => {
|
|
79
|
+
expect(esKeywords.locale).toBe('es');
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('should provide completions list', () => {
|
|
83
|
+
const commands = esKeywords.getCommands();
|
|
84
|
+
expect(commands.length).toBeGreaterThan(0);
|
|
85
|
+
expect(commands).toContain('alternar');
|
|
86
|
+
// Should also contain English fallbacks
|
|
87
|
+
expect(commands).toContain('toggle');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should translate English to locale', () => {
|
|
91
|
+
expect(esKeywords.toLocale('toggle')).toBe('alternar');
|
|
92
|
+
expect(esKeywords.toLocale('put')).toBe('poner');
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe('Japanese Provider (jaKeywords)', () => {
|
|
97
|
+
it('should resolve Japanese commands to English', () => {
|
|
98
|
+
expect(jaKeywords.resolve('切り替え')).toBe('toggle');
|
|
99
|
+
expect(jaKeywords.resolve('置く')).toBe('put');
|
|
100
|
+
expect(jaKeywords.resolve('設定')).toBe('set');
|
|
101
|
+
expect(jaKeywords.resolve('表示')).toBe('show');
|
|
102
|
+
expect(jaKeywords.resolve('隠す')).toBe('hide');
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should resolve Japanese keywords based on dictionary', () => {
|
|
106
|
+
// Note: Japanese 'で' maps to both 'on' (commands) and 'at' (modifiers)
|
|
107
|
+
// With priority, commands win, so 'で' → 'on'
|
|
108
|
+
expect(jaKeywords.resolve('で')).toBe('on');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should resolve Japanese events', () => {
|
|
112
|
+
expect(jaKeywords.resolve('クリック')).toBe('click');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should resolve Japanese modifiers', () => {
|
|
116
|
+
expect(jaKeywords.resolve('に')).toBe('to');
|
|
117
|
+
expect(jaKeywords.resolve('から')).toBe('from');
|
|
118
|
+
expect(jaKeywords.resolve('と')).toBe('with');
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should resolve Japanese logical operators', () => {
|
|
122
|
+
expect(jaKeywords.resolve('そして')).toBe('and');
|
|
123
|
+
expect(jaKeywords.resolve('または')).toBe('or');
|
|
124
|
+
expect(jaKeywords.resolve('ではない')).toBe('not');
|
|
125
|
+
expect(jaKeywords.resolve('それから')).toBe('then');
|
|
126
|
+
// Note: Japanese dictionary has 'そうでなければ' for 'otherwise', not 'else'
|
|
127
|
+
expect(jaKeywords.resolve('そうでなければ')).toBe('otherwise');
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should allow English fallback', () => {
|
|
131
|
+
expect(jaKeywords.resolve('toggle')).toBe('toggle');
|
|
132
|
+
expect(jaKeywords.resolve('on')).toBe('on');
|
|
133
|
+
expect(jaKeywords.resolve('click')).toBe('click');
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('should return locale code', () => {
|
|
137
|
+
expect(jaKeywords.locale).toBe('ja');
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
describe('French Provider (frKeywords)', () => {
|
|
142
|
+
it('should resolve French commands to English', () => {
|
|
143
|
+
expect(frKeywords.resolve('basculer')).toBe('toggle');
|
|
144
|
+
expect(frKeywords.resolve('mettre')).toBe('put');
|
|
145
|
+
expect(frKeywords.resolve('définir')).toBe('set');
|
|
146
|
+
expect(frKeywords.resolve('montrer')).toBe('show');
|
|
147
|
+
expect(frKeywords.resolve('cacher')).toBe('hide');
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('should resolve French events', () => {
|
|
151
|
+
expect(frKeywords.resolve('clic')).toBe('click');
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('should resolve French modifiers', () => {
|
|
155
|
+
expect(frKeywords.resolve('à')).toBe('to');
|
|
156
|
+
expect(frKeywords.resolve('avec')).toBe('with');
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('should resolve French logical operators', () => {
|
|
160
|
+
expect(frKeywords.resolve('et')).toBe('and');
|
|
161
|
+
expect(frKeywords.resolve('ou')).toBe('or');
|
|
162
|
+
expect(frKeywords.resolve('non')).toBe('not');
|
|
163
|
+
expect(frKeywords.resolve('alors')).toBe('then');
|
|
164
|
+
expect(frKeywords.resolve('sinon')).toBe('else');
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('should allow English fallback', () => {
|
|
168
|
+
expect(frKeywords.resolve('toggle')).toBe('toggle');
|
|
169
|
+
expect(frKeywords.resolve('on')).toBe('on');
|
|
170
|
+
expect(frKeywords.resolve('click')).toBe('click');
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('should return locale code', () => {
|
|
174
|
+
expect(frKeywords.locale).toBe('fr');
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('should translate English to locale', () => {
|
|
178
|
+
expect(frKeywords.toLocale('toggle')).toBe('basculer');
|
|
179
|
+
expect(frKeywords.toLocale('put')).toBe('mettre');
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
describe('German Provider (deKeywords)', () => {
|
|
184
|
+
it('should resolve German commands to English', () => {
|
|
185
|
+
expect(deKeywords.resolve('umschalten')).toBe('toggle');
|
|
186
|
+
expect(deKeywords.resolve('setzen')).toBe('put');
|
|
187
|
+
expect(deKeywords.resolve('festlegen')).toBe('set');
|
|
188
|
+
expect(deKeywords.resolve('zeigen')).toBe('show');
|
|
189
|
+
expect(deKeywords.resolve('verstecken')).toBe('hide');
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('should resolve German events', () => {
|
|
193
|
+
expect(deKeywords.resolve('klick')).toBe('click');
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it('should resolve German modifiers', () => {
|
|
197
|
+
expect(deKeywords.resolve('zu')).toBe('to');
|
|
198
|
+
expect(deKeywords.resolve('mit')).toBe('with');
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('should resolve German logical operators', () => {
|
|
202
|
+
expect(deKeywords.resolve('und')).toBe('and');
|
|
203
|
+
expect(deKeywords.resolve('oder')).toBe('or');
|
|
204
|
+
expect(deKeywords.resolve('nicht')).toBe('not');
|
|
205
|
+
expect(deKeywords.resolve('dann')).toBe('then');
|
|
206
|
+
expect(deKeywords.resolve('sonst')).toBe('else');
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('should allow English fallback', () => {
|
|
210
|
+
expect(deKeywords.resolve('toggle')).toBe('toggle');
|
|
211
|
+
expect(deKeywords.resolve('on')).toBe('on');
|
|
212
|
+
expect(deKeywords.resolve('click')).toBe('click');
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('should return locale code', () => {
|
|
216
|
+
expect(deKeywords.locale).toBe('de');
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('should translate English to locale', () => {
|
|
220
|
+
expect(deKeywords.toLocale('toggle')).toBe('umschalten');
|
|
221
|
+
expect(deKeywords.toLocale('put')).toBe('setzen');
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
describe('Arabic Provider (arKeywords)', () => {
|
|
226
|
+
it('should resolve Arabic commands to English', () => {
|
|
227
|
+
expect(arKeywords.resolve('بدل')).toBe('toggle');
|
|
228
|
+
expect(arKeywords.resolve('ضع')).toBe('put');
|
|
229
|
+
expect(arKeywords.resolve('اضبط')).toBe('set');
|
|
230
|
+
expect(arKeywords.resolve('اظهر')).toBe('show');
|
|
231
|
+
expect(arKeywords.resolve('اخف')).toBe('hide');
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('should resolve Arabic events', () => {
|
|
235
|
+
expect(arKeywords.resolve('نقر')).toBe('click');
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it('should resolve Arabic modifiers', () => {
|
|
239
|
+
expect(arKeywords.resolve('إلى')).toBe('to');
|
|
240
|
+
expect(arKeywords.resolve('مع')).toBe('with');
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it('should resolve Arabic logical operators', () => {
|
|
244
|
+
expect(arKeywords.resolve('و')).toBe('and');
|
|
245
|
+
expect(arKeywords.resolve('أو')).toBe('or');
|
|
246
|
+
expect(arKeywords.resolve('ليس')).toBe('not');
|
|
247
|
+
expect(arKeywords.resolve('ثم')).toBe('then');
|
|
248
|
+
expect(arKeywords.resolve('وإلا')).toBe('else');
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it('should allow English fallback', () => {
|
|
252
|
+
expect(arKeywords.resolve('toggle')).toBe('toggle');
|
|
253
|
+
expect(arKeywords.resolve('on')).toBe('on');
|
|
254
|
+
expect(arKeywords.resolve('click')).toBe('click');
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it('should return locale code', () => {
|
|
258
|
+
expect(arKeywords.locale).toBe('ar');
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it('should handle RTL text correctly (Arabic script)', () => {
|
|
262
|
+
// Arabic uses right-to-left script, but the parser works on tokens
|
|
263
|
+
// which are separated by whitespace/operators, so direction doesn't matter
|
|
264
|
+
expect(arKeywords.resolve('على')).toBe('on');
|
|
265
|
+
expect(arKeywords.resolve('بدل')).toBe('toggle');
|
|
266
|
+
// Verify round-trip works for commands
|
|
267
|
+
expect(arKeywords.toLocale('toggle')).toBe('بدل');
|
|
268
|
+
expect(arKeywords.toLocale('on')).toBe('على');
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it('should translate English to locale', () => {
|
|
272
|
+
expect(arKeywords.toLocale('toggle')).toBe('بدل');
|
|
273
|
+
expect(arKeywords.toLocale('put')).toBe('ضع');
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
describe('Korean Provider (koKeywords)', () => {
|
|
278
|
+
it('should resolve Korean commands to English', () => {
|
|
279
|
+
expect(koKeywords.resolve('토글')).toBe('toggle');
|
|
280
|
+
expect(koKeywords.resolve('넣다')).toBe('put');
|
|
281
|
+
expect(koKeywords.resolve('설정')).toBe('set');
|
|
282
|
+
expect(koKeywords.resolve('보이다')).toBe('show');
|
|
283
|
+
expect(koKeywords.resolve('숨기다')).toBe('hide');
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
it('should resolve Korean modifiers', () => {
|
|
287
|
+
// Note: '에' is a conflict (used for both 'on' and 'to')
|
|
288
|
+
// Commands have priority, so '에' → 'on'
|
|
289
|
+
expect(koKeywords.resolve('와')).toBe('with');
|
|
290
|
+
expect(koKeywords.resolve('에서')).toBe('from');
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it('should resolve Korean logical operators', () => {
|
|
294
|
+
expect(koKeywords.resolve('그리고')).toBe('and');
|
|
295
|
+
expect(koKeywords.resolve('또는')).toBe('or');
|
|
296
|
+
expect(koKeywords.resolve('아니')).toBe('not'); // dictionary uses '아니'
|
|
297
|
+
expect(koKeywords.resolve('그러면')).toBe('then');
|
|
298
|
+
// Note: '아니면' is used for both 'unless' (command) and 'else' (logical)
|
|
299
|
+
// Both commands and logical have priority=true, so logical overwrites commands
|
|
300
|
+
expect(koKeywords.resolve('아니면')).toBe('else');
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
it('should allow English fallback', () => {
|
|
304
|
+
expect(koKeywords.resolve('toggle')).toBe('toggle');
|
|
305
|
+
expect(koKeywords.resolve('on')).toBe('on');
|
|
306
|
+
expect(koKeywords.resolve('click')).toBe('click');
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it('should return locale code', () => {
|
|
310
|
+
expect(koKeywords.locale).toBe('ko');
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it('should handle Hangul script correctly', () => {
|
|
314
|
+
// Korean uses syllabic blocks (Hangul)
|
|
315
|
+
expect(koKeywords.resolve('에')).toBe('on'); // commands.on has priority
|
|
316
|
+
expect(koKeywords.resolve('토글')).toBe('toggle');
|
|
317
|
+
// Verify round-trip
|
|
318
|
+
expect(koKeywords.toLocale('toggle')).toBe('토글');
|
|
319
|
+
expect(koKeywords.toLocale('on')).toBe('에');
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
describe('Chinese Provider (zhKeywords)', () => {
|
|
324
|
+
it('should resolve Chinese commands to English', () => {
|
|
325
|
+
expect(zhKeywords.resolve('切换')).toBe('toggle');
|
|
326
|
+
expect(zhKeywords.resolve('放置')).toBe('put');
|
|
327
|
+
expect(zhKeywords.resolve('设置')).toBe('set');
|
|
328
|
+
expect(zhKeywords.resolve('显示')).toBe('show');
|
|
329
|
+
expect(zhKeywords.resolve('隐藏')).toBe('hide');
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
it('should resolve Chinese modifiers', () => {
|
|
333
|
+
expect(zhKeywords.resolve('到')).toBe('to');
|
|
334
|
+
expect(zhKeywords.resolve('与')).toBe('with'); // dictionary uses '与' not '用'
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
it('should resolve Chinese logical operators', () => {
|
|
338
|
+
expect(zhKeywords.resolve('和')).toBe('and');
|
|
339
|
+
expect(zhKeywords.resolve('或')).toBe('or');
|
|
340
|
+
expect(zhKeywords.resolve('非')).toBe('not');
|
|
341
|
+
expect(zhKeywords.resolve('那么')).toBe('then');
|
|
342
|
+
expect(zhKeywords.resolve('否则')).toBe('else');
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it('should allow English fallback', () => {
|
|
346
|
+
expect(zhKeywords.resolve('toggle')).toBe('toggle');
|
|
347
|
+
expect(zhKeywords.resolve('on')).toBe('on');
|
|
348
|
+
expect(zhKeywords.resolve('click')).toBe('click');
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
it('should return locale code', () => {
|
|
352
|
+
expect(zhKeywords.locale).toBe('zh');
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
it('should handle Chinese characters correctly', () => {
|
|
356
|
+
// Chinese uses logographic characters
|
|
357
|
+
// Note: '当' (dāng) is used for 'when' (logical), 'while' (commands), and 'on' (commands)
|
|
358
|
+
// Since 'when' appears last in dictionary iteration, '当' → 'when'
|
|
359
|
+
expect(zhKeywords.resolve('当')).toBe('when');
|
|
360
|
+
expect(zhKeywords.resolve('切换')).toBe('toggle');
|
|
361
|
+
// Round-trip for toggle
|
|
362
|
+
expect(zhKeywords.toLocale('toggle')).toBe('切换');
|
|
363
|
+
// Note: toLocale('on') still returns '当' (forward map), even though reverse is 'when'
|
|
364
|
+
expect(zhKeywords.toLocale('on')).toBe('当');
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
describe('Turkish Provider (trKeywords)', () => {
|
|
369
|
+
it('should resolve Turkish commands to English', () => {
|
|
370
|
+
expect(trKeywords.resolve('değiştir')).toBe('toggle');
|
|
371
|
+
expect(trKeywords.resolve('koy')).toBe('put');
|
|
372
|
+
expect(trKeywords.resolve('ayarla')).toBe('set');
|
|
373
|
+
expect(trKeywords.resolve('göster')).toBe('show');
|
|
374
|
+
expect(trKeywords.resolve('gizle')).toBe('hide');
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
it('should resolve Turkish modifiers', () => {
|
|
378
|
+
// Note: 'için' is commands.for, 'e' is modifiers.to
|
|
379
|
+
expect(trKeywords.resolve('e')).toBe('to');
|
|
380
|
+
expect(trKeywords.resolve('ile')).toBe('with');
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
it('should resolve Turkish logical operators', () => {
|
|
384
|
+
expect(trKeywords.resolve('ve')).toBe('and');
|
|
385
|
+
expect(trKeywords.resolve('veya')).toBe('or');
|
|
386
|
+
expect(trKeywords.resolve('değil')).toBe('not');
|
|
387
|
+
expect(trKeywords.resolve('sonra')).toBe('then'); // dictionary uses 'sonra'
|
|
388
|
+
expect(trKeywords.resolve('yoksa')).toBe('else');
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
it('should allow English fallback', () => {
|
|
392
|
+
expect(trKeywords.resolve('toggle')).toBe('toggle');
|
|
393
|
+
expect(trKeywords.resolve('on')).toBe('on');
|
|
394
|
+
expect(trKeywords.resolve('click')).toBe('click');
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
it('should return locale code', () => {
|
|
398
|
+
expect(trKeywords.locale).toBe('tr');
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
it('should handle Turkish special characters correctly', () => {
|
|
402
|
+
// Turkish uses extended Latin with special chars: ı, ğ, ş, ç, ö, ü
|
|
403
|
+
expect(trKeywords.resolve('üzerinde')).toBe('on');
|
|
404
|
+
expect(trKeywords.resolve('değiştir')).toBe('toggle');
|
|
405
|
+
// Verify round-trip
|
|
406
|
+
expect(trKeywords.toLocale('toggle')).toBe('değiştir');
|
|
407
|
+
expect(trKeywords.toLocale('on')).toBe('üzerinde');
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
describe('createKeywordProvider factory', () => {
|
|
412
|
+
it('should create provider from dictionary', () => {
|
|
413
|
+
const provider = createKeywordProvider(es, 'es');
|
|
414
|
+
expect(provider.locale).toBe('es');
|
|
415
|
+
expect(provider.resolve('alternar')).toBe('toggle');
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
it('should support disabling English fallback', () => {
|
|
419
|
+
const provider = createKeywordProvider(es, 'es', {
|
|
420
|
+
allowEnglishFallback: false,
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
// Spanish should still work
|
|
424
|
+
expect(provider.resolve('alternar')).toBe('toggle');
|
|
425
|
+
// English should NOT work (no fallback)
|
|
426
|
+
expect(provider.resolve('toggle')).toBeUndefined();
|
|
427
|
+
});
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
describe('createEnglishProvider', () => {
|
|
431
|
+
it('should create English-only provider', () => {
|
|
432
|
+
const provider = createEnglishProvider();
|
|
433
|
+
expect(provider.locale).toBe('en');
|
|
434
|
+
expect(provider.resolve('toggle')).toBe('toggle');
|
|
435
|
+
expect(provider.resolve('on')).toBe('on');
|
|
436
|
+
expect(provider.resolve('alternar')).toBeUndefined();
|
|
437
|
+
});
|
|
438
|
+
});
|
|
439
|
+
});
|
package/src/parser/pt.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// packages/i18n/src/parser/pt.ts
|
|
2
|
+
|
|
3
|
+
import { pt } from '../dictionaries/pt';
|
|
4
|
+
import { createKeywordProvider } from './create-provider';
|
|
5
|
+
import type { KeywordProvider } from './types';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Portuguese (Português) keyword provider for the hyperscript parser.
|
|
9
|
+
*
|
|
10
|
+
* Enables parsing hyperscript written in Portuguese:
|
|
11
|
+
* - `em clique alternar .active` → parses as `on click toggle .active`
|
|
12
|
+
* - `se verdadeiro então registrar "Olá"` → parses as `if true then log "Hello"`
|
|
13
|
+
*
|
|
14
|
+
* Portuguese is an SVO language with:
|
|
15
|
+
* - High mutual intelligibility with Spanish
|
|
16
|
+
* - Prepositions (like English and Spanish)
|
|
17
|
+
* - Gender agreement (simplified for hyperscript)
|
|
18
|
+
* - Fusional morphology
|
|
19
|
+
*
|
|
20
|
+
* Direct translation is supported between Portuguese and Spanish,
|
|
21
|
+
* avoiding the English pivot for more natural translations.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* import { ptKeywords } from '@lokascript/i18n/parser/pt';
|
|
26
|
+
* import { Parser } from '@lokascript/core';
|
|
27
|
+
*
|
|
28
|
+
* const parser = new Parser({ keywords: ptKeywords });
|
|
29
|
+
* parser.parse('em clique alternar .active');
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export const ptKeywords: KeywordProvider = createKeywordProvider(pt, 'pt', {
|
|
33
|
+
allowEnglishFallback: true,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Re-export for convenience
|
|
37
|
+
export { pt as ptDictionary } from '../dictionaries/pt';
|
package/src/parser/qu.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// packages/i18n/src/parser/qu.ts
|
|
2
|
+
|
|
3
|
+
import { qu } from '../dictionaries/qu';
|
|
4
|
+
import { createKeywordProvider } from './create-provider';
|
|
5
|
+
import type { KeywordProvider } from './types';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Quechua (Runasimi) keyword provider for the hyperscript parser.
|
|
9
|
+
*
|
|
10
|
+
* Enables parsing hyperscript written in Quechua:
|
|
11
|
+
* - `ñitiy-pi yapay #count-ta` → parses as `on click increment #count`
|
|
12
|
+
*
|
|
13
|
+
* Quechua is an SOV language with:
|
|
14
|
+
* - Agglutinative/polysynthetic morphology
|
|
15
|
+
* - Extensive suffix system (case markers: -ta, -man, -pi, -manta, -wan)
|
|
16
|
+
* - Postpositions (unlike Spanish which uses prepositions)
|
|
17
|
+
* - Object-Verb word order
|
|
18
|
+
* - Evidentiality markers (not used in hyperscript)
|
|
19
|
+
*
|
|
20
|
+
* The grammar transformer handles suffix joining via hyphen notation
|
|
21
|
+
* (e.g., "#count-ta" attaches the accusative marker).
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* import { quKeywords } from '@lokascript/i18n/parser/qu';
|
|
26
|
+
* import { Parser } from '@lokascript/core';
|
|
27
|
+
*
|
|
28
|
+
* const parser = new Parser({ keywords: quKeywords });
|
|
29
|
+
* parser.parse('ñitiy-pi yapay #count-ta');
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export const quKeywords: KeywordProvider = createKeywordProvider(qu, 'qu', {
|
|
33
|
+
allowEnglishFallback: true,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Re-export for convenience
|
|
37
|
+
export { qu as quDictionary } from '../dictionaries/qu';
|
package/src/parser/sw.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// packages/i18n/src/parser/sw.ts
|
|
2
|
+
|
|
3
|
+
import { sw } from '../dictionaries/sw';
|
|
4
|
+
import { createKeywordProvider } from './create-provider';
|
|
5
|
+
import type { KeywordProvider } from './types';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Swahili (Kiswahili) keyword provider for the hyperscript parser.
|
|
9
|
+
*
|
|
10
|
+
* Enables parsing hyperscript written in Swahili:
|
|
11
|
+
* - `kwenye bonyeza badilisha .active` → parses as `on click toggle .active`
|
|
12
|
+
* - `kama kweli basi andika "Habari"` → parses as `if true then log "Hello"`
|
|
13
|
+
*
|
|
14
|
+
* Swahili is an SVO Bantu language with:
|
|
15
|
+
* - Agglutinative verb morphology
|
|
16
|
+
* - Noun class system (simplified for hyperscript keywords)
|
|
17
|
+
* - Prepositions (unlike many other African languages)
|
|
18
|
+
* - Subject-verb agreement (not relevant for hyperscript)
|
|
19
|
+
*
|
|
20
|
+
* Swahili is widely spoken in East Africa and serves as a lingua franca
|
|
21
|
+
* for millions of speakers.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* import { swKeywords } from '@lokascript/i18n/parser/sw';
|
|
26
|
+
* import { Parser } from '@lokascript/core';
|
|
27
|
+
*
|
|
28
|
+
* const parser = new Parser({ keywords: swKeywords });
|
|
29
|
+
* parser.parse('kwenye bonyeza badilisha .active');
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export const swKeywords: KeywordProvider = createKeywordProvider(sw, 'sw', {
|
|
33
|
+
allowEnglishFallback: true,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Re-export for convenience
|
|
37
|
+
export { sw as swDictionary } from '../dictionaries/sw';
|
package/src/parser/tr.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// packages/i18n/src/parser/tr.ts
|
|
2
|
+
|
|
3
|
+
import { tr } from '../dictionaries/tr';
|
|
4
|
+
import { createKeywordProvider } from './create-provider';
|
|
5
|
+
import type { KeywordProvider } from './types';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Turkish keyword provider for the hyperscript parser.
|
|
9
|
+
*
|
|
10
|
+
* Enables parsing hyperscript written in Turkish:
|
|
11
|
+
* - `üzerinde tıklama değiştir .active` → parses as `on click toggle .active`
|
|
12
|
+
* - `eğer doğru ise kaydet "merhaba"` → parses as `if true then log "hello"`
|
|
13
|
+
*
|
|
14
|
+
* English keywords are also accepted (mixed mode), so:
|
|
15
|
+
* - `üzerinde click değiştir .active` also works (Turkish `üzerinde` + English `click`)
|
|
16
|
+
*
|
|
17
|
+
* Turkish is a useful test case because:
|
|
18
|
+
* - SOV word order (Subject-Object-Verb)
|
|
19
|
+
* - Agglutinative morphology with suffixes
|
|
20
|
+
* - Vowel harmony rules
|
|
21
|
+
* - Latin script with special characters (ı, ğ, ş, ç, ö, ü)
|
|
22
|
+
* - Tests parser's handling of extended Latin characters
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* import { trKeywords } from '@lokascript/i18n/parser/tr';
|
|
27
|
+
* import { Parser } from '@lokascript/core';
|
|
28
|
+
*
|
|
29
|
+
* const parser = new Parser({ keywords: trKeywords });
|
|
30
|
+
* parser.parse('üzerinde tıklama değiştir .active');
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export const trKeywords: KeywordProvider = createKeywordProvider(tr, 'tr', {
|
|
34
|
+
allowEnglishFallback: true,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Re-export for convenience
|
|
38
|
+
export { tr as trDictionary } from '../dictionaries/tr';
|