@lokascript/i18n 2.9.4 → 2.11.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 +56 -0
- 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 +56 -0
- package/dist/browser.js.map +1 -1
- package/dist/index.cjs +56 -0
- 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 +56 -0
- 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 +94 -0
- package/dist/lokascript-i18n.mjs.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 +3 -3
- 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
|
@@ -10105,6 +10105,50 @@ function restoreCaretScopes(input, scopes) {
|
|
|
10105
10105
|
return input.replace(new RegExp(`${CARET_SCOPE_OPEN}(\\d+)${CARET_SCOPE_CLOSE}`, 'g'), (_m, n) => scopes[Number(n)] ?? '');
|
|
10106
10106
|
}
|
|
10107
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
|
+
// =============================================================================
|
|
10108
10152
|
// Main Transformer
|
|
10109
10153
|
// =============================================================================
|
|
10110
10154
|
class GrammarTransformer {
|
|
@@ -10133,6 +10177,16 @@ class GrammarTransformer {
|
|
|
10133
10177
|
return this.targetProfile.code === 'he' ? repairHebrewFrontedAccusative(out) : out;
|
|
10134
10178
|
}
|
|
10135
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
|
+
}
|
|
10136
10190
|
// Caret-scoped variable reads (`^name on <selector>`) carry a second,
|
|
10137
10191
|
// overloaded `on` that the splitter/event-parser would mistake for an event
|
|
10138
10192
|
// or command boundary \u2014 mangling `put ^count on #host into me`. Mask the
|
|
@@ -10221,6 +10275,17 @@ class GrammarTransformer {
|
|
|
10221
10275
|
if (setScope !== null) {
|
|
10222
10276
|
return setScope;
|
|
10223
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
|
+
}
|
|
10224
10289
|
// 1. Parse into semantic roles
|
|
10225
10290
|
const parsed = parseStatement(input, this.sourceProfile.code);
|
|
10226
10291
|
if (!parsed) {
|
|
@@ -10251,6 +10316,35 @@ class GrammarTransformer {
|
|
|
10251
10316
|
// 7. Join without markers (still use joinTokens for consistency)
|
|
10252
10317
|
return joinTokens(reordered.map(e => e.translated || e.value));
|
|
10253
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
|
+
}
|
|
10254
10348
|
/**
|
|
10255
10349
|
* `<command \u2026> end` fragments: transform the command without its stranded
|
|
10256
10350
|
* terminator, then re-append the translated terminator as a standalone
|