@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.
@@ -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