@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,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
|
+
}
|