@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.
Files changed (40) hide show
  1. package/dist/browser.cjs +74 -10
  2. package/dist/browser.cjs.map +1 -1
  3. package/dist/browser.d.cts +2 -2
  4. package/dist/browser.d.ts +2 -2
  5. package/dist/browser.js +74 -10
  6. package/dist/browser.js.map +1 -1
  7. package/dist/dictionaries/index.cjs +18 -10
  8. package/dist/dictionaries/index.cjs.map +1 -1
  9. package/dist/dictionaries/index.js +18 -10
  10. package/dist/dictionaries/index.js.map +1 -1
  11. package/dist/index.cjs +74 -10
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.d.cts +1 -1
  14. package/dist/index.d.ts +1 -1
  15. package/dist/index.js +74 -10
  16. package/dist/index.js.map +1 -1
  17. package/dist/lokascript-i18n.min.js +1 -1
  18. package/dist/lokascript-i18n.min.js.map +1 -1
  19. package/dist/lokascript-i18n.mjs +110 -10
  20. package/dist/lokascript-i18n.mjs.map +1 -1
  21. package/dist/plugins/vite.cjs +18 -10
  22. package/dist/plugins/vite.cjs.map +1 -1
  23. package/dist/plugins/vite.js +18 -10
  24. package/dist/plugins/vite.js.map +1 -1
  25. package/dist/plugins/webpack.cjs +18 -10
  26. package/dist/plugins/webpack.cjs.map +1 -1
  27. package/dist/plugins/webpack.js +18 -10
  28. package/dist/plugins/webpack.js.map +1 -1
  29. package/dist/{transformer--W46PGaW.d.cts → transformer-CsOeqayN.d.cts} +18 -1
  30. package/dist/{transformer-FU06J6kG.d.ts → transformer-DWCTG1DQ.d.ts} +18 -1
  31. package/package.json +4 -4
  32. package/src/dictionaries/de.ts +3 -1
  33. package/src/dictionaries/es.ts +2 -2
  34. package/src/dictionaries/pl.ts +2 -1
  35. package/src/dictionaries/pt.ts +5 -2
  36. package/src/dictionaries/ru.ts +2 -2
  37. package/src/dictionaries/uk.ts +2 -2
  38. package/src/grammar/grammar.test.ts +87 -0
  39. package/src/grammar/transformer.ts +106 -0
  40. package/src/grammar/types.ts +4 -0
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { I as I18nConfig, T as TranslationOptions, a as TranslationResult, D as Dictionary, V as ValidationResult$1, b as Token } from './types-BYtpqGq3.cjs';
2
2
  export { c as DICTIONARY_CATEGORIES, d as DictionaryCategory, L as LocaleMetadata, e as TokenType, f as TranslationContext, g as ValidationError, h as ValidationWarning, i as findInDictionary, j as forEachCategory, k as getDictionaryCategory, l as isDictionaryCategory, t as translateFromEnglish } from './types-BYtpqGq3.cjs';
3
3
  export { ar, bn, de, dictionaries, en, es, fr, getDictionary, hi, id, isLocaleSupported, it, ja, ko, ms, pl, pt, qu, ru, supportedLocales, sw, th, tl, tr, uk, vi, zh } from './dictionaries/index.cjs';
4
- export { A as AdpositionType, E as ENGLISH_COMMANDS, a as ENGLISH_KEYWORDS, G as GrammarRule, b as GrammarTransformer, c as GrammaticalMarker, K as KeywordProvider, d as KeywordProviderOptions, L as LANGUAGE_FAMILY_DEFAULTS, e as LanguageProfile, f as LocaleManager, M as MorphologyType, P as ParsedElement, g as ParsedStatement, h as PatternMatcher, i as PatternTransform, S as SemanticRole, U as UNIVERSAL_ENGLISH_KEYWORDS, j as UNIVERSAL_PATTERNS, W as WordOrder, k as arDictionary, l as arKeywords, m as arabicProfile, n as bnDictionary, o as bnKeywords, p as chineseProfile, q as createEnglishProvider, r as createKeywordProvider, s as deDictionary, t as deKeywords, u as detectBrowserLocale, v as englishProfile, w as esDictionary, x as esKeywords, y as frDictionary, z as frKeywords, D as getProfile, F as getSupportedLocales, H as grammarExamples, J as hiDictionary, N as hiKeywords, O as idDictionary, Q as idKeywords, R as indonesianProfile, T as insertMarkers, V as itDictionary, X as itKeywords, Y as jaDictionary, Z as jaKeywords, _ as japaneseProfile, a0 as koDictionary, a1 as koKeywords, a2 as koreanProfile, a3 as malayProfile, a4 as msDictionary, a5 as msKeywords, a6 as parseStatement, a7 as plDictionary, a8 as plKeywords, aa as profiles, ab as ptDictionary, ac as ptKeywords, ad as quDictionary, ae as quKeywords, af as quechuaProfile, ag as reorderRoles, ah as ruDictionary, ai as ruKeywords, aj as spanishProfile, ak as swDictionary, al as swKeywords, am as swahiliProfile, an as thDictionary, ao as thKeywords, ap as tlDictionary, aq as tlKeywords, ar as toEnglish, as as toLocale, at as trDictionary, au as trKeywords, av as transformStatement, aw as translate, ax as turkishProfile, ay as ukDictionary, az as ukKeywords, aA as viDictionary, aB as viKeywords, aC as zhDictionary, aD as zhKeywords } from './transformer--W46PGaW.cjs';
4
+ export { A as AdpositionType, E as ENGLISH_COMMANDS, a as ENGLISH_KEYWORDS, G as GrammarRule, b as GrammarTransformer, c as GrammaticalMarker, K as KeywordProvider, d as KeywordProviderOptions, L as LANGUAGE_FAMILY_DEFAULTS, e as LanguageProfile, f as LocaleManager, M as MorphologyType, P as ParsedElement, g as ParsedStatement, h as PatternMatcher, i as PatternTransform, S as SemanticRole, U as UNIVERSAL_ENGLISH_KEYWORDS, j as UNIVERSAL_PATTERNS, W as WordOrder, k as arDictionary, l as arKeywords, m as arabicProfile, n as bnDictionary, o as bnKeywords, p as chineseProfile, q as createEnglishProvider, r as createKeywordProvider, s as deDictionary, t as deKeywords, u as detectBrowserLocale, v as englishProfile, w as esDictionary, x as esKeywords, y as frDictionary, z as frKeywords, D as getProfile, F as getSupportedLocales, H as grammarExamples, J as hiDictionary, N as hiKeywords, O as idDictionary, Q as idKeywords, R as indonesianProfile, T as insertMarkers, V as itDictionary, X as itKeywords, Y as jaDictionary, Z as jaKeywords, _ as japaneseProfile, a0 as koDictionary, a1 as koKeywords, a2 as koreanProfile, a3 as malayProfile, a4 as msDictionary, a5 as msKeywords, a6 as parseStatement, a7 as plDictionary, a8 as plKeywords, aa as profiles, ab as ptDictionary, ac as ptKeywords, ad as quDictionary, ae as quKeywords, af as quechuaProfile, ag as reorderRoles, ah as ruDictionary, ai as ruKeywords, aj as spanishProfile, ak as swDictionary, al as swKeywords, am as swahiliProfile, an as thDictionary, ao as thKeywords, ap as tlDictionary, aq as tlKeywords, ar as toEnglish, as as toLocale, at as trDictionary, au as trKeywords, av as transformStatement, aw as translate, ax as turkishProfile, ay as ukDictionary, az as ukKeywords, aA as viDictionary, aB as viKeywords, aC as zhDictionary, aD as zhKeywords } from './transformer-CsOeqayN.cjs';
5
5
  export { hyperscriptI18nVitePlugin } from './plugins/vite.cjs';
6
6
  export { HyperscriptI18nWebpackPlugin } from './plugins/webpack.cjs';
7
7
  import { z } from 'zod';
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { I as I18nConfig, T as TranslationOptions, a as TranslationResult, D as Dictionary, V as ValidationResult$1, b as Token } from './types-BYtpqGq3.js';
2
2
  export { c as DICTIONARY_CATEGORIES, d as DictionaryCategory, L as LocaleMetadata, e as TokenType, f as TranslationContext, g as ValidationError, h as ValidationWarning, i as findInDictionary, j as forEachCategory, k as getDictionaryCategory, l as isDictionaryCategory, t as translateFromEnglish } from './types-BYtpqGq3.js';
3
3
  export { ar, bn, de, dictionaries, en, es, fr, getDictionary, hi, id, isLocaleSupported, it, ja, ko, ms, pl, pt, qu, ru, supportedLocales, sw, th, tl, tr, uk, vi, zh } from './dictionaries/index.js';
4
- export { A as AdpositionType, E as ENGLISH_COMMANDS, a as ENGLISH_KEYWORDS, G as GrammarRule, b as GrammarTransformer, c as GrammaticalMarker, K as KeywordProvider, d as KeywordProviderOptions, L as LANGUAGE_FAMILY_DEFAULTS, e as LanguageProfile, f as LocaleManager, M as MorphologyType, P as ParsedElement, g as ParsedStatement, h as PatternMatcher, i as PatternTransform, S as SemanticRole, U as UNIVERSAL_ENGLISH_KEYWORDS, j as UNIVERSAL_PATTERNS, W as WordOrder, k as arDictionary, l as arKeywords, m as arabicProfile, n as bnDictionary, o as bnKeywords, p as chineseProfile, q as createEnglishProvider, r as createKeywordProvider, s as deDictionary, t as deKeywords, u as detectBrowserLocale, v as englishProfile, w as esDictionary, x as esKeywords, y as frDictionary, z as frKeywords, D as getProfile, F as getSupportedLocales, H as grammarExamples, J as hiDictionary, N as hiKeywords, O as idDictionary, Q as idKeywords, R as indonesianProfile, T as insertMarkers, V as itDictionary, X as itKeywords, Y as jaDictionary, Z as jaKeywords, _ as japaneseProfile, a0 as koDictionary, a1 as koKeywords, a2 as koreanProfile, a3 as malayProfile, a4 as msDictionary, a5 as msKeywords, a6 as parseStatement, a7 as plDictionary, a8 as plKeywords, aa as profiles, ab as ptDictionary, ac as ptKeywords, ad as quDictionary, ae as quKeywords, af as quechuaProfile, ag as reorderRoles, ah as ruDictionary, ai as ruKeywords, aj as spanishProfile, ak as swDictionary, al as swKeywords, am as swahiliProfile, an as thDictionary, ao as thKeywords, ap as tlDictionary, aq as tlKeywords, ar as toEnglish, as as toLocale, at as trDictionary, au as trKeywords, av as transformStatement, aw as translate, ax as turkishProfile, ay as ukDictionary, az as ukKeywords, aA as viDictionary, aB as viKeywords, aC as zhDictionary, aD as zhKeywords } from './transformer-FU06J6kG.js';
4
+ export { A as AdpositionType, E as ENGLISH_COMMANDS, a as ENGLISH_KEYWORDS, G as GrammarRule, b as GrammarTransformer, c as GrammaticalMarker, K as KeywordProvider, d as KeywordProviderOptions, L as LANGUAGE_FAMILY_DEFAULTS, e as LanguageProfile, f as LocaleManager, M as MorphologyType, P as ParsedElement, g as ParsedStatement, h as PatternMatcher, i as PatternTransform, S as SemanticRole, U as UNIVERSAL_ENGLISH_KEYWORDS, j as UNIVERSAL_PATTERNS, W as WordOrder, k as arDictionary, l as arKeywords, m as arabicProfile, n as bnDictionary, o as bnKeywords, p as chineseProfile, q as createEnglishProvider, r as createKeywordProvider, s as deDictionary, t as deKeywords, u as detectBrowserLocale, v as englishProfile, w as esDictionary, x as esKeywords, y as frDictionary, z as frKeywords, D as getProfile, F as getSupportedLocales, H as grammarExamples, J as hiDictionary, N as hiKeywords, O as idDictionary, Q as idKeywords, R as indonesianProfile, T as insertMarkers, V as itDictionary, X as itKeywords, Y as jaDictionary, Z as jaKeywords, _ as japaneseProfile, a0 as koDictionary, a1 as koKeywords, a2 as koreanProfile, a3 as malayProfile, a4 as msDictionary, a5 as msKeywords, a6 as parseStatement, a7 as plDictionary, a8 as plKeywords, aa as profiles, ab as ptDictionary, ac as ptKeywords, ad as quDictionary, ae as quKeywords, af as quechuaProfile, ag as reorderRoles, ah as ruDictionary, ai as ruKeywords, aj as spanishProfile, ak as swDictionary, al as swKeywords, am as swahiliProfile, an as thDictionary, ao as thKeywords, ap as tlDictionary, aq as tlKeywords, ar as toEnglish, as as toLocale, at as trDictionary, au as trKeywords, av as transformStatement, aw as translate, ax as turkishProfile, ay as ukDictionary, az as ukKeywords, aA as viDictionary, aB as viKeywords, aC as zhDictionary, aD as zhKeywords } from './transformer-DWCTG1DQ.js';
5
5
  export { hyperscriptI18nVitePlugin } from './plugins/vite.js';
6
6
  export { HyperscriptI18nWebpackPlugin } from './plugins/webpack.js';
7
7
  import { z } from 'zod';
package/dist/index.js CHANGED
@@ -377,12 +377,12 @@ var es = {
377
377
  events: {
378
378
  click: "clic",
379
379
  dblclick: "dobleclic",
380
- mousedown: "rat\xF3nabajo",
381
- mouseup: "rat\xF3narriba",
382
380
  mouseenter: "rat\xF3nentrar",
383
381
  mouseleave: "rat\xF3nsalir",
384
382
  // V3 Batch 2: fused forms split to the S5b/tokenizer-known forms (the fused
385
383
  // spellings captured event=expression:undefined — broken listeners)
384
+ mousedown: "rat\xF3n abajo",
385
+ mouseup: "rat\xF3n arriba",
386
386
  mouseover: "rat\xF3n encima",
387
387
  mouseout: "rat\xF3n fuera",
388
388
  mousemove: "rat\xF3nmover",
@@ -1273,7 +1273,9 @@ var de = {
1273
1273
  reset: "zur\xFCcksetzen",
1274
1274
  load: "laden",
1275
1275
  unload: "entladen",
1276
- resize: "gr\xF6\xDFe\xE4ndern",
1276
+ // 'größeändern' was a malformed compound: German either separates the verb
1277
+ // phrase ('Größe ändern') or compounds with the linking -n- ('Größenänderung').
1278
+ resize: "gr\xF6\xDFen\xE4nderung",
1277
1279
  scroll: "scrollen",
1278
1280
  touchstart: "ber\xFChrungstart",
1279
1281
  touchend: "ber\xFChrungend",
@@ -2850,12 +2852,15 @@ var pt = {
2850
2852
  events: {
2851
2853
  click: "clique",
2852
2854
  dblclick: "duploClique",
2853
- mousedown: "mouseBaixo",
2854
- mouseup: "mouseCima",
2855
2855
  mouseenter: "mouseEntrar",
2856
2856
  mouseleave: "mouseSair",
2857
2857
  // V3 Batch 2: camelCase forms split to the S5b/tokenizer-known forms (the
2858
2858
  // fused spellings captured event=expression:undefined — broken listeners)
2859
+ // pt-BR idiom is "pressionado"/"solto", not the spatial baixo/cima calque —
2860
+ // cf. MDN pt-BR ("um botão ... é pressionado") and Scratch pt-BR
2861
+ // ("mouse pressionado?"). The calques stay as profile parse alternatives.
2862
+ mousedown: "mouse pressionado",
2863
+ mouseup: "mouse solto",
2859
2864
  mouseover: "mouse sobre",
2860
2865
  mouseout: "mouse fora",
2861
2866
  mousemove: "mouseMover",
@@ -3518,7 +3523,8 @@ var pl = {
3518
3523
  // Batch 3: resetuj captured on.event as expression (broken listener) — profile word round-trips
3519
3524
  load: "za\u0142aduj",
3520
3525
  unload: "wy\u0142aduj",
3521
- resize: "zmie\u0144rozmiar",
3526
+ // 'zmieńrozmiar' was a fused two-word phrase; Polish writes 'zmiana rozmiaru'.
3527
+ resize: "zmiana rozmiaru",
3522
3528
  scroll: "przewi\u0144",
3523
3529
  touchstart: "dotykstart",
3524
3530
  touchend: "dotykkoniec",
@@ -3677,7 +3683,7 @@ var russianDictionary = {
3677
3683
  morph: "\u0442\u0440\u0430\u043D\u0441\u0444\u043E\u0440\u043C\u0438\u0440\u043E\u0432\u0430\u0442\u044C",
3678
3684
  settle: "\u0441\u0442\u0430\u0431\u0438\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u0442\u044C",
3679
3685
  append: "\u0434\u043E\u043F\u0438\u0441\u0430\u0442\u044C",
3680
- // profile alternative; the compound splits and добавить parses as add
3686
+ // matches the ru profile primary
3681
3687
  exit: "\u0432\u044B\u0439\u0442\u0438",
3682
3688
  else: "\u0438\u043D\u0430\u0447\u0435",
3683
3689
  install: "\u0438\u043D\u0441\u0442\u0430\u043B\u043B\u0438\u0440\u043E\u0432\u0430\u0442\u044C",
@@ -3687,7 +3693,8 @@ var russianDictionary = {
3687
3693
  focus: "\u0441\u0444\u043E\u043A\u0443\u0441\u0438\u0440\u043E\u0432\u0430\u0442\u044C",
3688
3694
  blur: "\u0440\u0430\u0437\u043C\u044B\u0442\u044C",
3689
3695
  clone: "\u043A\u043B\u043E\u043D\u0438\u0440\u043E\u0432\u0430\u0442\u044C",
3690
- prepend: "\u0434\u043E\u0431\u0430\u0432\u0438\u0442\u044C_\u0432_\u043D\u0430\u0447\u0430\u043B\u043E",
3696
+ prepend: "\u0434\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0432 \u043D\u0430\u0447\u0430\u043B\u043E",
3697
+ // natural form; the underscore compound was never natural Russian
3691
3698
  breakpoint: "\u0442\u043E\u0447\u043A\u0430-\u043E\u0441\u0442\u0430\u043D\u043E\u0432\u0430",
3692
3699
  clear: "\u043E\u0447\u0438\u0441\u0442\u0438\u0442\u044C",
3693
3700
  close: "\u0437\u0430\u043A\u0440\u044B\u0442\u044C",
@@ -3919,7 +3926,7 @@ var ukrainianDictionary = {
3919
3926
  morph: "\u0442\u0440\u0430\u043D\u0441\u0444\u043E\u0440\u043C\u0443\u0432\u0430\u0442\u0438",
3920
3927
  settle: "\u0441\u0442\u0430\u0431\u0456\u043B\u0456\u0437\u0443\u0432\u0430\u0442\u0438",
3921
3928
  append: "\u0434\u043E\u043F\u0438\u0441\u0430\u0442\u0438",
3922
- // profile alternative; the compound splits and додати parses as add
3929
+ // matches the uk profile primary
3923
3930
  exit: "\u0432\u0438\u0439\u0442\u0438",
3924
3931
  else: "\u0456\u043D\u0430\u043A\u0448\u0435",
3925
3932
  install: "\u0456\u043D\u0441\u0442\u0430\u043B\u044E\u0432\u0430\u0442\u0438",
@@ -3929,7 +3936,8 @@ var ukrainianDictionary = {
3929
3936
  focus: "\u0441\u0444\u043E\u043A\u0443\u0441\u0443\u0432\u0430\u0442\u0438",
3930
3937
  blur: "\u0440\u043E\u0437\u0444\u043E\u043A\u0443\u0441\u0443\u0432\u0430\u0442\u0438",
3931
3938
  clone: "\u043A\u043B\u043E\u043D\u0443\u0432\u0430\u0442\u0438",
3932
- prepend: "\u0434\u043E\u0434\u0430\u0442\u0438_\u043D\u0430_\u043F\u043E\u0447\u0430\u0442\u043E\u043A",
3939
+ prepend: "\u0434\u043E\u0434\u0430\u0442\u0438 \u043D\u0430 \u043F\u043E\u0447\u0430\u0442\u043E\u043A",
3940
+ // natural form; see ru.ts
3933
3941
  breakpoint: "\u0442\u043E\u0447\u043A\u0430-\u0437\u0443\u043F\u0438\u043D\u043A\u0438",
3934
3942
  clear: "\u043E\u0447\u0438\u0441\u0442\u0438\u0442\u0438",
3935
3943
  close: "\u0437\u0430\u043A\u0440\u0438\u0442\u0438",
@@ -15327,6 +15335,25 @@ function restoreCaretScopes(input, scopes) {
15327
15335
  (_m, n) => scopes[Number(n)] ?? ""
15328
15336
  );
15329
15337
  }
15338
+ var VIEW_TAIL_OPEN = "\uE002";
15339
+ var VIEW_TAIL_CLOSE = "\uE003";
15340
+ var VIEW_TAIL_RE = /\busing\s+view\b(?:\s+(?!then\b)[A-Za-z][\w-]*)?/gi;
15341
+ var VIEW_TAIL_TOKEN_RE = new RegExp(`^${VIEW_TAIL_OPEN}(\\d+)${VIEW_TAIL_CLOSE}$`);
15342
+ function maskViewTransitionTails(input) {
15343
+ const tails = [];
15344
+ const masked = input.replace(VIEW_TAIL_RE, (match) => {
15345
+ const idx = tails.length;
15346
+ tails.push(match);
15347
+ return `${VIEW_TAIL_OPEN}${idx}${VIEW_TAIL_CLOSE}`;
15348
+ });
15349
+ return tails.length > 0 ? { masked, tails } : null;
15350
+ }
15351
+ function restoreViewTransitionTails(input, tails) {
15352
+ return input.replace(
15353
+ new RegExp(`${VIEW_TAIL_OPEN}(\\d+)${VIEW_TAIL_CLOSE}`, "g"),
15354
+ (_m, n) => tails[Number(n)] ?? ""
15355
+ );
15356
+ }
15330
15357
  var GrammarTransformer = class {
15331
15358
  constructor(sourceLocale = "en", targetLocale) {
15332
15359
  const source = getProfile(sourceLocale);
@@ -15348,6 +15375,10 @@ var GrammarTransformer = class {
15348
15375
  return this.targetProfile.code === "he" ? repairHebrewFrontedAccusative(out) : out;
15349
15376
  }
15350
15377
  transformInternal(input) {
15378
+ const viewTails = maskViewTransitionTails(input);
15379
+ if (viewTails) {
15380
+ return restoreViewTransitionTails(this.transformInternal(viewTails.masked), viewTails.tails);
15381
+ }
15351
15382
  const caret = maskCaretScopes(input);
15352
15383
  if (caret) {
15353
15384
  return restoreCaretScopes(this.transform(caret.masked), caret.scopes);
@@ -15400,6 +15431,10 @@ var GrammarTransformer = class {
15400
15431
  if (setScope !== null) {
15401
15432
  return setScope;
15402
15433
  }
15434
+ const viewTail = this.transformWithViewTransitionTail(input);
15435
+ if (viewTail !== null) {
15436
+ return viewTail;
15437
+ }
15403
15438
  const parsed = parseStatement(input, this.sourceProfile.code);
15404
15439
  if (!parsed) {
15405
15440
  return input;
@@ -15423,6 +15458,35 @@ var GrammarTransformer = class {
15423
15458
  }
15424
15459
  return joinTokens(reordered.map((e) => e.translated || e.value));
15425
15460
  }
15461
+ /**
15462
+ * Clause carrying a masked `using view transition` tail: strip the opaque
15463
+ * token, transform the clause alone, and re-append the token at the very end.
15464
+ *
15465
+ * The tail is a clause-final modifier in every word order the corpus emits:
15466
+ * the semantic side matches it as the literal `using view` marker plus a value
15467
+ * word, and the SOV/VSO event-handler patterns admit it as an optional
15468
+ * TRAILING group (after the with-marked operand). So the target position is
15469
+ * "end of the transformed clause" for all 24 languages — no per-profile
15470
+ * placement decision, which is what makes this a passthrough rather than a
15471
+ * role.
15472
+ *
15473
+ * Returns null when the clause carries no masked tail, or when the token is
15474
+ * not clause-final (nothing to reposition — leaving it in place still restores
15475
+ * verbatim English).
15476
+ */
15477
+ transformWithViewTransitionTail(input) {
15478
+ const trimmed = input.trim();
15479
+ const tokens = trimmed.split(/\s+/);
15480
+ if (tokens.length < 2) {
15481
+ return null;
15482
+ }
15483
+ if (!VIEW_TAIL_TOKEN_RE.test(tokens[tokens.length - 1])) {
15484
+ return null;
15485
+ }
15486
+ const tail = tokens[tokens.length - 1];
15487
+ const head = tokens.slice(0, -1).join(" ");
15488
+ return `${this.transformSingle(head)} ${tail}`;
15489
+ }
15426
15490
  /**
15427
15491
  * `<command …> end` fragments: transform the command without its stranded
15428
15492
  * terminator, then re-append the translated terminator as a standalone