@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
@@ -0,0 +1,353 @@
1
+ /**
2
+ * Direct Language-Pair Mappings
3
+ *
4
+ * Enables translation between language pairs without English pivot.
5
+ * This reduces error compounding and provides more natural translations
6
+ * for closely related languages or those with shared vocabulary.
7
+ *
8
+ * Currently supported pairs:
9
+ * - Japanese ↔ Chinese (shared Kanji concepts)
10
+ * - Spanish ↔ Portuguese (Romance language mutual intelligibility)
11
+ * - Korean ↔ Japanese (SOV grammar similarity)
12
+ */
13
+
14
+ import type { Dictionary } from '../types';
15
+ import { ja } from '../dictionaries/ja';
16
+ import { zh } from '../dictionaries/zh';
17
+ import { ko } from '../dictionaries/ko';
18
+ // Note: es and pt use hand-crafted mappings for better quality
19
+
20
+ // =============================================================================
21
+ // Types
22
+ // =============================================================================
23
+
24
+ export interface DirectMapping {
25
+ /** Source language code */
26
+ source: string;
27
+ /** Target language code */
28
+ target: string;
29
+ /** Word mappings: source word -> target word */
30
+ words: Record<string, string>;
31
+ /** Category mappings for structured translation */
32
+ categories?: Record<string, Record<string, string>>;
33
+ }
34
+
35
+ // =============================================================================
36
+ // Utility Functions
37
+ // =============================================================================
38
+
39
+ /**
40
+ * Create reverse mapping from an existing mapping
41
+ */
42
+ function reverseMapping(mapping: DirectMapping): DirectMapping {
43
+ const reversedWords: Record<string, string> = {};
44
+ for (const [source, target] of Object.entries(mapping.words)) {
45
+ reversedWords[target] = source;
46
+ }
47
+
48
+ const reversedCategories: Record<string, Record<string, string>> = {};
49
+ if (mapping.categories) {
50
+ for (const [category, words] of Object.entries(mapping.categories)) {
51
+ reversedCategories[category] = {};
52
+ for (const [source, target] of Object.entries(words)) {
53
+ reversedCategories[category][target] = source;
54
+ }
55
+ }
56
+ }
57
+
58
+ const result: DirectMapping = {
59
+ source: mapping.target,
60
+ target: mapping.source,
61
+ words: reversedWords,
62
+ };
63
+
64
+ if (Object.keys(reversedCategories).length > 0) {
65
+ result.categories = reversedCategories;
66
+ }
67
+
68
+ return result;
69
+ }
70
+
71
+ /**
72
+ * Build direct mapping from two dictionaries via English keys
73
+ */
74
+ function buildMappingFromDictionaries(
75
+ sourceDict: Dictionary,
76
+ targetDict: Dictionary,
77
+ sourceCode: string,
78
+ targetCode: string
79
+ ): DirectMapping {
80
+ const words: Record<string, string> = {};
81
+ const categories: Record<string, Record<string, string>> = {};
82
+
83
+ // Map each category
84
+ for (const category of [
85
+ 'commands',
86
+ 'modifiers',
87
+ 'events',
88
+ 'logical',
89
+ 'temporal',
90
+ 'values',
91
+ 'attributes',
92
+ ] as const) {
93
+ const sourceCategory = sourceDict[category] as Record<string, string> | undefined;
94
+ const targetCategory = targetDict[category] as Record<string, string> | undefined;
95
+
96
+ if (sourceCategory && targetCategory) {
97
+ categories[category] = {};
98
+
99
+ for (const [englishKey, sourceWord] of Object.entries(sourceCategory)) {
100
+ const targetWord = targetCategory[englishKey];
101
+ if (targetWord && sourceWord !== targetWord) {
102
+ words[sourceWord] = targetWord;
103
+ categories[category][sourceWord] = targetWord;
104
+ }
105
+ }
106
+ }
107
+ }
108
+
109
+ return {
110
+ source: sourceCode,
111
+ target: targetCode,
112
+ words,
113
+ categories,
114
+ };
115
+ }
116
+
117
+ // =============================================================================
118
+ // Japanese ↔ Chinese Direct Mapping
119
+ // =============================================================================
120
+
121
+ /**
122
+ * Japanese to Chinese mapping
123
+ *
124
+ * These languages share many concepts through Kanji/Hanzi,
125
+ * making direct translation more accurate than pivot translation.
126
+ */
127
+ export const jaZhMapping: DirectMapping = buildMappingFromDictionaries(ja, zh, 'ja', 'zh');
128
+
129
+ /**
130
+ * Chinese to Japanese mapping (reverse of jaZh)
131
+ */
132
+ export const zhJaMapping: DirectMapping = reverseMapping(jaZhMapping);
133
+
134
+ // =============================================================================
135
+ // Korean ↔ Japanese Direct Mapping
136
+ // =============================================================================
137
+
138
+ /**
139
+ * Korean to Japanese mapping
140
+ *
141
+ * Both are SOV languages with postposition particles,
142
+ * sharing grammatical structure that enables more natural translation.
143
+ */
144
+ export const koJaMapping: DirectMapping = buildMappingFromDictionaries(ko, ja, 'ko', 'ja');
145
+
146
+ /**
147
+ * Japanese to Korean mapping (reverse of koJa)
148
+ */
149
+ export const jaKoMapping: DirectMapping = reverseMapping(koJaMapping);
150
+
151
+ // =============================================================================
152
+ // Spanish ↔ Portuguese Direct Mapping
153
+ // =============================================================================
154
+
155
+ /**
156
+ * Spanish to Portuguese mapping
157
+ *
158
+ * These Romance languages have high mutual intelligibility,
159
+ * with many cognates that translate directly.
160
+ */
161
+ export const esPtMapping: DirectMapping = {
162
+ source: 'es',
163
+ target: 'pt',
164
+ words: {
165
+ // Commands - many are cognates
166
+ en: 'em', // on (event)
167
+ decir: 'dizer', // tell
168
+ disparar: 'disparar', // trigger
169
+ enviar: 'enviar', // send
170
+ tomar: 'pegar', // take
171
+ poner: 'colocar', // put
172
+ establecer: 'definir', // set
173
+ obtener: 'obter', // get
174
+ agregar: 'adicionar', // add
175
+ quitar: 'remover', // remove
176
+ alternar: 'alternar', // toggle
177
+ ocultar: 'esconder', // hide
178
+ mostrar: 'mostrar', // show
179
+ si: 'se', // if
180
+ menos: 'a menos', // unless
181
+ repetir: 'repetir', // repeat
182
+ para: 'para', // for
183
+ mientras: 'enquanto', // while
184
+ hasta: 'até', // until
185
+ continuar: 'continuar', // continue
186
+ romper: 'parar', // break
187
+ detener: 'parar', // halt
188
+ esperar: 'esperar', // wait
189
+ buscar: 'buscar', // fetch
190
+ llamar: 'chamar', // call
191
+ retornar: 'retornar', // return
192
+ hacer: 'fazer', // make
193
+ registrar: 'registrar', // log
194
+ lanzar: 'lançar', // throw
195
+ atrapar: 'capturar', // catch
196
+ medir: 'medir', // measure
197
+ transición: 'transição', // transition
198
+ incrementar: 'incrementar', // increment
199
+ decrementar: 'decrementar', // decrement
200
+ vincular: 'vincular', // bind
201
+ predeterminar: 'padrão', // default
202
+ persistir: 'persistir', // persist
203
+ ir: 'ir', // go
204
+ copiar: 'copiar', // copy
205
+ escoger: 'escolher', // pick
206
+ intercambiar: 'trocar', // swap
207
+ transformar: 'transformar', // morph
208
+ añadir: 'anexar', // append
209
+ salir: 'sair', // exit
210
+
211
+ // Modifiers
212
+ a: 'para', // to
213
+ de: 'de', // from
214
+ dentro: 'em', // into
215
+ con: 'com', // with
216
+ como: 'como', // as
217
+ por: 'por', // by
218
+
219
+ // Events
220
+ clic: 'clique', // click
221
+ cambio: 'mudança', // change
222
+ entrada: 'entrada', // input
223
+ envío: 'envio', // submit
224
+ carga: 'carregar', // load
225
+ enfoque: 'foco', // focus
226
+ desenfoque: 'desfoque', // blur
227
+
228
+ // Logical
229
+ verdadero: 'verdadeiro', // true
230
+ falso: 'falso', // false
231
+ y: 'e', // and
232
+ o: 'ou', // or
233
+ no: 'não', // not
234
+ es: 'é', // is
235
+
236
+ // Temporal
237
+ segundos: 'segundos', // seconds
238
+ milisegundos: 'milissegundos', // milliseconds
239
+
240
+ // Values
241
+ nulo: 'nulo', // null
242
+ indefinido: 'indefinido', // undefined
243
+ vacío: 'vazio', // empty
244
+ },
245
+ categories: {
246
+ commands: {
247
+ en: 'em',
248
+ decir: 'dizer',
249
+ tomar: 'pegar',
250
+ poner: 'colocar',
251
+ establecer: 'definir',
252
+ obtener: 'obter',
253
+ agregar: 'adicionar',
254
+ quitar: 'remover',
255
+ ocultar: 'esconder',
256
+ si: 'se',
257
+ mientras: 'enquanto',
258
+ hasta: 'até',
259
+ romper: 'parar',
260
+ detener: 'parar',
261
+ llamar: 'chamar',
262
+ hacer: 'fazer',
263
+ lanzar: 'lançar',
264
+ atrapar: 'capturar',
265
+ escoger: 'escolher',
266
+ intercambiar: 'trocar',
267
+ añadir: 'anexar',
268
+ salir: 'sair',
269
+ },
270
+ events: {
271
+ clic: 'clique',
272
+ cambio: 'mudança',
273
+ carga: 'carregar',
274
+ enfoque: 'foco',
275
+ desenfoque: 'desfoque',
276
+ },
277
+ logical: {
278
+ verdadero: 'verdadeiro',
279
+ y: 'e',
280
+ o: 'ou',
281
+ no: 'não',
282
+ es: 'é',
283
+ },
284
+ },
285
+ };
286
+
287
+ /**
288
+ * Portuguese to Spanish mapping (reverse of esPt)
289
+ */
290
+ export const ptEsMapping: DirectMapping = reverseMapping(esPtMapping);
291
+
292
+ // =============================================================================
293
+ // Mapping Registry
294
+ // =============================================================================
295
+
296
+ /**
297
+ * Registry of direct translation pairs.
298
+ * Key format: "source->target" (e.g., "ja->zh")
299
+ */
300
+ export const directMappings: Map<string, DirectMapping> = new Map([
301
+ // Japanese ↔ Chinese
302
+ ['ja->zh', jaZhMapping],
303
+ ['zh->ja', zhJaMapping],
304
+
305
+ // Korean ↔ Japanese
306
+ ['ko->ja', koJaMapping],
307
+ ['ja->ko', jaKoMapping],
308
+
309
+ // Spanish ↔ Portuguese
310
+ ['es->pt', esPtMapping],
311
+ ['pt->es', ptEsMapping],
312
+ ]);
313
+
314
+ // =============================================================================
315
+ // Public API
316
+ // =============================================================================
317
+
318
+ /**
319
+ * Check if direct mapping exists for a language pair
320
+ */
321
+ export function hasDirectMapping(source: string, target: string): boolean {
322
+ return directMappings.has(`${source}->${target}`);
323
+ }
324
+
325
+ /**
326
+ * Get direct mapping for a language pair
327
+ */
328
+ export function getDirectMapping(source: string, target: string): DirectMapping | undefined {
329
+ return directMappings.get(`${source}->${target}`);
330
+ }
331
+
332
+ /**
333
+ * Translate a single word using direct mapping
334
+ */
335
+ export function translateWordDirect(
336
+ word: string,
337
+ source: string,
338
+ target: string
339
+ ): string | undefined {
340
+ const mapping = getDirectMapping(source, target);
341
+ if (!mapping) return undefined;
342
+ return mapping.words[word];
343
+ }
344
+
345
+ /**
346
+ * Get all supported direct translation pairs
347
+ */
348
+ export function getSupportedDirectPairs(): Array<{ source: string; target: string }> {
349
+ return Array.from(directMappings.keys()).map(key => {
350
+ const [source, target] = key.split('->');
351
+ return { source, target };
352
+ });
353
+ }