@lokascript/i18n 2.9.3 → 2.10.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/dist/browser.cjs +74 -10
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +2 -2
- package/dist/browser.d.ts +2 -2
- package/dist/browser.js +74 -10
- package/dist/browser.js.map +1 -1
- package/dist/dictionaries/index.cjs +18 -10
- package/dist/dictionaries/index.cjs.map +1 -1
- package/dist/dictionaries/index.js +18 -10
- package/dist/dictionaries/index.js.map +1 -1
- package/dist/index.cjs +74 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +74 -10
- package/dist/index.js.map +1 -1
- package/dist/lokascript-i18n.min.js +1 -1
- package/dist/lokascript-i18n.min.js.map +1 -1
- package/dist/lokascript-i18n.mjs +110 -10
- package/dist/lokascript-i18n.mjs.map +1 -1
- package/dist/plugins/vite.cjs +18 -10
- package/dist/plugins/vite.cjs.map +1 -1
- package/dist/plugins/vite.js +18 -10
- package/dist/plugins/vite.js.map +1 -1
- package/dist/plugins/webpack.cjs +18 -10
- package/dist/plugins/webpack.cjs.map +1 -1
- package/dist/plugins/webpack.js +18 -10
- package/dist/plugins/webpack.js.map +1 -1
- package/dist/{transformer--W46PGaW.d.cts → transformer-CsOeqayN.d.cts} +18 -1
- package/dist/{transformer-FU06J6kG.d.ts → transformer-DWCTG1DQ.d.ts} +18 -1
- package/package.json +4 -4
- package/src/dictionaries/de.ts +3 -1
- package/src/dictionaries/es.ts +2 -2
- package/src/dictionaries/pl.ts +2 -1
- package/src/dictionaries/pt.ts +5 -2
- package/src/dictionaries/ru.ts +2 -2
- package/src/dictionaries/uk.ts +2 -2
- package/src/grammar/grammar.test.ts +87 -0
- package/src/grammar/transformer.ts +106 -0
- package/src/grammar/types.ts +4 -0
package/dist/lokascript-i18n.mjs
CHANGED
|
@@ -704,12 +704,12 @@ const es$1 = {
|
|
|
704
704
|
events: {
|
|
705
705
|
click: 'clic',
|
|
706
706
|
dblclick: 'dobleclic',
|
|
707
|
-
mousedown: 'rat\u00f3nabajo',
|
|
708
|
-
mouseup: 'rat\u00f3narriba',
|
|
709
707
|
mouseenter: 'rat\u00f3nentrar',
|
|
710
708
|
mouseleave: 'rat\u00f3nsalir',
|
|
711
709
|
// V3 Batch 2: fused forms split to the S5b/tokenizer-known forms (the fused
|
|
712
710
|
// spellings captured event=expression:undefined \u2014 broken listeners)
|
|
711
|
+
mousedown: 'rat\u00f3n abajo',
|
|
712
|
+
mouseup: 'rat\u00f3n arriba',
|
|
713
713
|
mouseover: 'rat\u00f3n encima',
|
|
714
714
|
mouseout: 'rat\u00f3n fuera',
|
|
715
715
|
mousemove: 'rat\u00f3nmover',
|
|
@@ -1452,7 +1452,9 @@ const de$1 = {
|
|
|
1452
1452
|
reset: 'zur\u00fccksetzen',
|
|
1453
1453
|
load: 'laden',
|
|
1454
1454
|
unload: 'entladen',
|
|
1455
|
-
|
|
1455
|
+
// 'gr\u00f6\u00dfe\u00e4ndern' was a malformed compound: German either separates the verb
|
|
1456
|
+
// phrase ('Gr\u00f6\u00dfe \u00e4ndern') or compounds with the linking -n- ('Gr\u00f6\u00dfen\u00e4nderung').
|
|
1457
|
+
resize: 'gr\u00f6\u00dfen\u00e4nderung',
|
|
1456
1458
|
scroll: 'scrollen',
|
|
1457
1459
|
touchstart: 'ber\u00fchrungstart',
|
|
1458
1460
|
touchend: 'ber\u00fchrungend',
|
|
@@ -3461,12 +3463,15 @@ const pt$1 = {
|
|
|
3461
3463
|
events: {
|
|
3462
3464
|
click: 'clique',
|
|
3463
3465
|
dblclick: 'duploClique',
|
|
3464
|
-
mousedown: 'mouseBaixo',
|
|
3465
|
-
mouseup: 'mouseCima',
|
|
3466
3466
|
mouseenter: 'mouseEntrar',
|
|
3467
3467
|
mouseleave: 'mouseSair',
|
|
3468
3468
|
// V3 Batch 2: camelCase forms split to the S5b/tokenizer-known forms (the
|
|
3469
3469
|
// fused spellings captured event=expression:undefined \u2014 broken listeners)
|
|
3470
|
+
// pt-BR idiom is "pressionado"/"solto", not the spatial baixo/cima calque \u2014
|
|
3471
|
+
// cf. MDN pt-BR ("um bot\u00e3o ... \u00e9 pressionado") and Scratch pt-BR
|
|
3472
|
+
// ("mouse pressionado?"). The calques stay as profile parse alternatives.
|
|
3473
|
+
mousedown: 'mouse pressionado',
|
|
3474
|
+
mouseup: 'mouse solto',
|
|
3470
3475
|
mouseover: 'mouse sobre',
|
|
3471
3476
|
mouseout: 'mouse fora',
|
|
3472
3477
|
mousemove: 'mouseMover',
|
|
@@ -4155,7 +4160,8 @@ const pl$1 = {
|
|
|
4155
4160
|
reset: 'zresetuj', // Batch 3: resetuj captured on.event as expression (broken listener) \u2014 profile word round-trips
|
|
4156
4161
|
load: 'za\u0142aduj',
|
|
4157
4162
|
unload: 'wy\u0142aduj',
|
|
4158
|
-
|
|
4163
|
+
// 'zmie\u0144rozmiar' was a fused two-word phrase; Polish writes 'zmiana rozmiaru'.
|
|
4164
|
+
resize: 'zmiana rozmiaru',
|
|
4159
4165
|
scroll: 'przewi\u0144',
|
|
4160
4166
|
touchstart: 'dotykstart',
|
|
4161
4167
|
touchend: 'dotykkoniec',
|
|
@@ -4317,7 +4323,7 @@ const russianDictionary = {
|
|
|
4317
4323
|
swap: '\u043f\u043e\u043c\u0435\u043d\u044f\u0442\u044c',
|
|
4318
4324
|
morph: '\u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c',
|
|
4319
4325
|
settle: '\u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c',
|
|
4320
|
-
append: '\u0434\u043e\u043f\u0438\u0441\u0430\u0442\u044c', //
|
|
4326
|
+
append: '\u0434\u043e\u043f\u0438\u0441\u0430\u0442\u044c', // matches the ru profile primary
|
|
4321
4327
|
exit: '\u0432\u044b\u0439\u0442\u0438',
|
|
4322
4328
|
else: '\u0438\u043d\u0430\u0447\u0435',
|
|
4323
4329
|
install: '\u0438\u043d\u0441\u0442\u0430\u043b\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c', // loanword \u2014 `\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c` is `set` (homonym); see russian profile
|
|
@@ -4326,7 +4332,7 @@ const russianDictionary = {
|
|
|
4326
4332
|
focus: '\u0441\u0444\u043e\u043a\u0443\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c',
|
|
4327
4333
|
blur: '\u0440\u0430\u0437\u043c\u044b\u0442\u044c',
|
|
4328
4334
|
clone: '\u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c',
|
|
4329
|
-
prepend: '\u0434\u043e\u0431\u0430\u0432\u0438\u0442\
|
|
4335
|
+
prepend: '\u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043d\u0430\u0447\u0430\u043b\u043e', // natural form; the underscore compound was never natural Russian
|
|
4330
4336
|
breakpoint: '\u0442\u043e\u0447\u043a\u0430-\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0430',
|
|
4331
4337
|
clear: '\u043e\u0447\u0438\u0441\u0442\u0438\u0442\u044c',
|
|
4332
4338
|
close: '\u0437\u0430\u043a\u0440\u044b\u0442\u044c',
|
|
@@ -4558,7 +4564,7 @@ const ukrainianDictionary = {
|
|
|
4558
4564
|
swap: '\u043f\u043e\u043c\u0456\u043d\u044f\u0442\u0438',
|
|
4559
4565
|
morph: '\u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0443\u0432\u0430\u0442\u0438',
|
|
4560
4566
|
settle: '\u0441\u0442\u0430\u0431\u0456\u043b\u0456\u0437\u0443\u0432\u0430\u0442\u0438',
|
|
4561
|
-
append: '\u0434\u043e\u043f\u0438\u0441\u0430\u0442\u0438', //
|
|
4567
|
+
append: '\u0434\u043e\u043f\u0438\u0441\u0430\u0442\u0438', // matches the uk profile primary
|
|
4562
4568
|
exit: '\u0432\u0438\u0439\u0442\u0438',
|
|
4563
4569
|
else: '\u0456\u043d\u0430\u043a\u0448\u0435',
|
|
4564
4570
|
install: '\u0456\u043d\u0441\u0442\u0430\u043b\u044e\u0432\u0430\u0442\u0438', // loanword \u2014 `\u0432\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0438` is `set` (homonym); see ukrainian profile
|
|
@@ -4567,7 +4573,7 @@ const ukrainianDictionary = {
|
|
|
4567
4573
|
focus: '\u0441\u0444\u043e\u043a\u0443\u0441\u0443\u0432\u0430\u0442\u0438',
|
|
4568
4574
|
blur: '\u0440\u043e\u0437\u0444\u043e\u043a\u0443\u0441\u0443\u0432\u0430\u0442\u0438',
|
|
4569
4575
|
clone: '\u043a\u043b\u043e\u043d\u0443\u0432\u0430\u0442\u0438',
|
|
4570
|
-
prepend: '\u0434\u043e\u0434\u0430\u0442\
|
|
4576
|
+
prepend: '\u0434\u043e\u0434\u0430\u0442\u0438 \u043d\u0430 \u043f\u043e\u0447\u0430\u0442\u043e\u043a', // natural form; see ru.ts
|
|
4571
4577
|
breakpoint: '\u0442\u043e\u0447\u043a\u0430-\u0437\u0443\u043f\u0438\u043d\u043a\u0438',
|
|
4572
4578
|
clear: '\u043e\u0447\u0438\u0441\u0442\u0438\u0442\u0438',
|
|
4573
4579
|
close: '\u0437\u0430\u043a\u0440\u0438\u0442\u0438',
|
|
@@ -10099,6 +10105,50 @@ function restoreCaretScopes(input, scopes) {
|
|
|
10099
10105
|
return input.replace(new RegExp(`${CARET_SCOPE_OPEN}(\\d+)${CARET_SCOPE_CLOSE}`, 'g'), (_m, n) => scopes[Number(n)] ?? '');
|
|
10100
10106
|
}
|
|
10101
10107
|
// =============================================================================
|
|
10108
|
+
// View-transition tail masking (`using view transition`)
|
|
10109
|
+
// =============================================================================
|
|
10110
|
+
/** Private-use sentinels bracketing a masked view-transition-tail index. */
|
|
10111
|
+
const VIEW_TAIL_OPEN = '\uE002';
|
|
10112
|
+
const VIEW_TAIL_CLOSE = '\uE003';
|
|
10113
|
+
/**
|
|
10114
|
+
* Match `swap`/`process`'s trailing `using view transition` modifier.
|
|
10115
|
+
*
|
|
10116
|
+
* `using` is in no dictionary and in no role table, so it sweeps into whatever
|
|
10117
|
+
* role phrase is open; `transition` IS a translated command keyword in every
|
|
10118
|
+
* dictionary (es `transici\u00f3n`, de `\u00fcbergang`, ja `\u9077\u79fb`) and is in
|
|
10119
|
+
* `ENGLISH_COMMANDS`, so `splitOnCommandBoundaries` splits the clause there and
|
|
10120
|
+
* the rejoin plants a phantom translated `transition` COMMAND after the target's
|
|
10121
|
+
* `then`-connective (`intercambiar #a con #b using view entonces transici\u00f3n`).
|
|
10122
|
+
*
|
|
10123
|
+
* The phrase has no native form in any of the 24 languages \u2014 semantic's
|
|
10124
|
+
* `USING_VIEW_MARKER_ALL_LANGS` matches the literal English `using view` marker
|
|
10125
|
+
* everywhere \u2014 so it is a passthrough, matched on the English surface regardless
|
|
10126
|
+
* of source locale. The value word is optional so a bare `using view` still
|
|
10127
|
+
* masks rather than half-splitting; `then` is excluded so a clause boundary is
|
|
10128
|
+
* never swallowed into the tail.
|
|
10129
|
+
*/
|
|
10130
|
+
const VIEW_TAIL_RE = /\busing\s+view\b(?:\s+(?!then\b)[A-Za-z][\w-]*)?/gi;
|
|
10131
|
+
/** Whether a token is a masked view-transition tail. */
|
|
10132
|
+
const VIEW_TAIL_TOKEN_RE = new RegExp(`^${VIEW_TAIL_OPEN}(\\d+)${VIEW_TAIL_CLOSE}$`);
|
|
10133
|
+
/**
|
|
10134
|
+
* Mask every `using view <value>` tail behind an opaque token, so the phrase
|
|
10135
|
+
* never reaches the splitter, the word translator, or the role parser. Returns
|
|
10136
|
+
* null when there's nothing to mask.
|
|
10137
|
+
*/
|
|
10138
|
+
function maskViewTransitionTails(input) {
|
|
10139
|
+
const tails = [];
|
|
10140
|
+
const masked = input.replace(VIEW_TAIL_RE, match => {
|
|
10141
|
+
const idx = tails.length;
|
|
10142
|
+
tails.push(match);
|
|
10143
|
+
return `${VIEW_TAIL_OPEN}${idx}${VIEW_TAIL_CLOSE}`;
|
|
10144
|
+
});
|
|
10145
|
+
return tails.length > 0 ? { masked, tails } : null;
|
|
10146
|
+
}
|
|
10147
|
+
/** Restore masked view-transition tokens to their verbatim English phrase. */
|
|
10148
|
+
function restoreViewTransitionTails(input, tails) {
|
|
10149
|
+
return input.replace(new RegExp(`${VIEW_TAIL_OPEN}(\\d+)${VIEW_TAIL_CLOSE}`, 'g'), (_m, n) => tails[Number(n)] ?? '');
|
|
10150
|
+
}
|
|
10151
|
+
// =============================================================================
|
|
10102
10152
|
// Main Transformer
|
|
10103
10153
|
// =============================================================================
|
|
10104
10154
|
class GrammarTransformer {
|
|
@@ -10127,6 +10177,16 @@ class GrammarTransformer {
|
|
|
10127
10177
|
return this.targetProfile.code === 'he' ? repairHebrewFrontedAccusative(out) : out;
|
|
10128
10178
|
}
|
|
10129
10179
|
transformInternal(input) {
|
|
10180
|
+
// `using view transition` is a passthrough phrase, not translatable content:
|
|
10181
|
+
// `using` is in no dictionary and `transition` is a COMMAND keyword, so left
|
|
10182
|
+
// in place the splitter tears the clause apart there and the tail renders as
|
|
10183
|
+
// a phantom translated command. Mask it before any splitting/translation and
|
|
10184
|
+
// restore it verbatim; transformSingle re-appends the opaque token at the
|
|
10185
|
+
// clause tail so it lands after the reorder, not inside a role phrase.
|
|
10186
|
+
const viewTails = maskViewTransitionTails(input);
|
|
10187
|
+
if (viewTails) {
|
|
10188
|
+
return restoreViewTransitionTails(this.transformInternal(viewTails.masked), viewTails.tails);
|
|
10189
|
+
}
|
|
10130
10190
|
// Caret-scoped variable reads (`^name on <selector>`) carry a second,
|
|
10131
10191
|
// overloaded `on` that the splitter/event-parser would mistake for an event
|
|
10132
10192
|
// or command boundary \u2014 mangling `put ^count on #host into me`. Mask the
|
|
@@ -10215,6 +10275,17 @@ class GrammarTransformer {
|
|
|
10215
10275
|
if (setScope !== null) {
|
|
10216
10276
|
return setScope;
|
|
10217
10277
|
}
|
|
10278
|
+
// 0c. Masked `using view transition` tail (see maskViewTransitionTails):
|
|
10279
|
+
// strip the opaque token, transform the clause without it, and re-append
|
|
10280
|
+
// it at the clause tail. Left in the token stream it would be swept into
|
|
10281
|
+
// the open role's VALUE and rendered ahead of that role's marker
|
|
10282
|
+
// (ja `#b using view transition \u3067` instead of `#b \u3067 using view
|
|
10283
|
+
// transition`) \u2014 the same failure mode transformWithTrailingEnd fixes
|
|
10284
|
+
// for a stranded `end`.
|
|
10285
|
+
const viewTail = this.transformWithViewTransitionTail(input);
|
|
10286
|
+
if (viewTail !== null) {
|
|
10287
|
+
return viewTail;
|
|
10288
|
+
}
|
|
10218
10289
|
// 1. Parse into semantic roles
|
|
10219
10290
|
const parsed = parseStatement(input, this.sourceProfile.code);
|
|
10220
10291
|
if (!parsed) {
|
|
@@ -10245,6 +10316,35 @@ class GrammarTransformer {
|
|
|
10245
10316
|
// 7. Join without markers (still use joinTokens for consistency)
|
|
10246
10317
|
return joinTokens(reordered.map(e => e.translated || e.value));
|
|
10247
10318
|
}
|
|
10319
|
+
/**
|
|
10320
|
+
* Clause carrying a masked `using view transition` tail: strip the opaque
|
|
10321
|
+
* token, transform the clause alone, and re-append the token at the very end.
|
|
10322
|
+
*
|
|
10323
|
+
* The tail is a clause-final modifier in every word order the corpus emits:
|
|
10324
|
+
* the semantic side matches it as the literal `using view` marker plus a value
|
|
10325
|
+
* word, and the SOV/VSO event-handler patterns admit it as an optional
|
|
10326
|
+
* TRAILING group (after the with-marked operand). So the target position is
|
|
10327
|
+
* "end of the transformed clause" for all 24 languages \u2014 no per-profile
|
|
10328
|
+
* placement decision, which is what makes this a passthrough rather than a
|
|
10329
|
+
* role.
|
|
10330
|
+
*
|
|
10331
|
+
* Returns null when the clause carries no masked tail, or when the token is
|
|
10332
|
+
* not clause-final (nothing to reposition \u2014 leaving it in place still restores
|
|
10333
|
+
* verbatim English).
|
|
10334
|
+
*/
|
|
10335
|
+
transformWithViewTransitionTail(input) {
|
|
10336
|
+
const trimmed = input.trim();
|
|
10337
|
+
const tokens = trimmed.split(/\s+/);
|
|
10338
|
+
if (tokens.length < 2) {
|
|
10339
|
+
return null;
|
|
10340
|
+
}
|
|
10341
|
+
if (!VIEW_TAIL_TOKEN_RE.test(tokens[tokens.length - 1])) {
|
|
10342
|
+
return null;
|
|
10343
|
+
}
|
|
10344
|
+
const tail = tokens[tokens.length - 1];
|
|
10345
|
+
const head = tokens.slice(0, -1).join(' ');
|
|
10346
|
+
return `${this.transformSingle(head)} ${tail}`;
|
|
10347
|
+
}
|
|
10248
10348
|
/**
|
|
10249
10349
|
* `<command \u2026> end` fragments: transform the command without its stranded
|
|
10250
10350
|
* terminator, then re-append the translated terminator as a standalone
|