@lokascript/i18n 2.5.1 → 2.6.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 +1274 -154
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +3 -3
- package/dist/browser.d.ts +3 -3
- package/dist/browser.js +1274 -155
- package/dist/browser.js.map +1 -1
- package/dist/dictionaries/index.cjs +364 -133
- package/dist/dictionaries/index.cjs.map +1 -1
- package/dist/dictionaries/index.d.cts +1 -1
- package/dist/dictionaries/index.d.ts +1 -1
- package/dist/dictionaries/index.js +364 -133
- package/dist/dictionaries/index.js.map +1 -1
- package/dist/index.cjs +8860 -7740
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -37
- package/dist/index.d.ts +37 -37
- package/dist/index.js +8860 -7741
- 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 +1697 -146
- package/dist/lokascript-i18n.mjs.map +1 -1
- package/dist/plugins/vite.cjs +359 -132
- package/dist/plugins/vite.cjs.map +1 -1
- package/dist/plugins/vite.js +359 -132
- package/dist/plugins/vite.js.map +1 -1
- package/dist/plugins/webpack.cjs +359 -132
- package/dist/plugins/webpack.cjs.map +1 -1
- package/dist/plugins/webpack.js +359 -132
- package/dist/plugins/webpack.js.map +1 -1
- package/dist/{transformer-BLv389qz.d.ts → transformer-BA8YX9u1.d.ts} +120 -2
- package/dist/{transformer-PFsYELrc.d.cts → transformer-DM7iplCU.d.cts} +120 -2
- package/dist/{types-BcALAO6h.d.cts → types-BYtpqGq3.d.cts} +1 -1
- package/dist/{types-BcALAO6h.d.ts → types-BYtpqGq3.d.ts} +1 -1
- package/package.json +6 -6
- package/src/browser.ts +1 -0
- package/src/command-primary-roles.test.ts +59 -0
- package/src/constants.ts +51 -0
- package/src/dictionaries/ar.ts +8 -3
- package/src/dictionaries/bn.ts +3 -1
- package/src/dictionaries/de.ts +19 -4
- package/src/dictionaries/derive.ts +4 -0
- package/src/dictionaries/en.ts +9 -0
- package/src/dictionaries/es.ts +2 -2
- package/src/dictionaries/fr.ts +6 -2
- package/src/dictionaries/he.ts +7 -1
- package/src/dictionaries/hi.ts +17 -10
- package/src/dictionaries/id.ts +15 -8
- package/src/dictionaries/it.ts +6 -3
- package/src/dictionaries/ja.ts +10 -4
- package/src/dictionaries/ko.ts +9 -4
- package/src/dictionaries/ms.ts +2 -1
- package/src/dictionaries/pl.ts +11 -3
- package/src/dictionaries/pt.ts +10 -4
- package/src/dictionaries/qu.ts +46 -22
- package/src/dictionaries/ru.ts +14 -7
- package/src/dictionaries/sw.ts +37 -10
- package/src/dictionaries/th.ts +3 -1
- package/src/dictionaries/tl.ts +14 -7
- package/src/dictionaries/tr.ts +22 -9
- package/src/dictionaries/uk.ts +13 -7
- package/src/dictionaries/vi.ts +3 -3
- package/src/dictionaries/zh.ts +10 -2
- package/src/examples/new-languages.ts +1 -1
- package/src/grammar/grammar.test.ts +1242 -1
- package/src/grammar/index.ts +1 -0
- package/src/grammar/profiles/index.ts +358 -12
- package/src/grammar/transformer.ts +1053 -16
- package/src/grammar/types.ts +22 -1
- package/src/index.ts +1 -0
- package/src/new-languages.test.ts +7 -3
- package/src/parser/parser-integration.test.ts +5 -1
- package/src/positional-keyword-drift.test.ts +138 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { D as Dictionary } from './types-BYtpqGq3.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* KeywordProvider interface for locale-aware parsing.
|
|
@@ -869,6 +869,7 @@ declare const germanProfile: LanguageProfile;
|
|
|
869
869
|
declare const frenchProfile: LanguageProfile;
|
|
870
870
|
declare const portugueseProfile: LanguageProfile;
|
|
871
871
|
declare const indonesianProfile: LanguageProfile;
|
|
872
|
+
declare const malayProfile: LanguageProfile;
|
|
872
873
|
declare const quechuaProfile: LanguageProfile;
|
|
873
874
|
declare const swahiliProfile: LanguageProfile;
|
|
874
875
|
declare const hebrewProfile: LanguageProfile;
|
|
@@ -901,10 +902,127 @@ declare class GrammarTransformer {
|
|
|
901
902
|
* For multi-line input, preserves line structure (indentation, blank lines).
|
|
902
903
|
*/
|
|
903
904
|
transform(input: string): string;
|
|
905
|
+
private transformInternal;
|
|
904
906
|
/**
|
|
905
907
|
* Transform a single hyperscript statement (no compound "then" chains).
|
|
906
908
|
*/
|
|
907
909
|
private transformSingle;
|
|
910
|
+
/**
|
|
911
|
+
* Detect and transform an inline JS block (`[on <event>] js <raw js> end`).
|
|
912
|
+
*
|
|
913
|
+
* The `js ... end` body is raw JavaScript: it must not be tokenized,
|
|
914
|
+
* translated, or word-order reordered. We mask the whole block with a single
|
|
915
|
+
* opaque placeholder, run the surrounding statement (the event-handler head,
|
|
916
|
+
* if any) through the normal reorder pipeline so the placeholder lands in the
|
|
917
|
+
* correct action position, then substitute the translated `js`/`end` keywords
|
|
918
|
+
* around the verbatim body.
|
|
919
|
+
*
|
|
920
|
+
* Returns `null` (fall through to the normal path) when there is no js block,
|
|
921
|
+
* no matching `end`, or trailing content after `end` (kept tight on purpose).
|
|
922
|
+
*/
|
|
923
|
+
private tryTransformJsBlock;
|
|
924
|
+
/**
|
|
925
|
+
* Transform an event handler whose body is a block command
|
|
926
|
+
* (`on <event> [from <src>] {if|repeat|unless|while|for} … end`).
|
|
927
|
+
*
|
|
928
|
+
* `parseEventHandler` would treat the block keyword as the action and sweep the
|
|
929
|
+
* condition/body into role values, then reorder them — shredding the block
|
|
930
|
+
* (`if event.shiftKey call submitAndContinue() end` → scattered tokens). Instead
|
|
931
|
+
* we mask the whole block as an opaque action placeholder, reorder the event
|
|
932
|
+
* head normally, transform the block as a self-contained unit, and restitch.
|
|
933
|
+
*
|
|
934
|
+
* Returns `null` (fall through) when the input isn't an event handler, has no
|
|
935
|
+
* block-keyword body, or has no closing `end`.
|
|
936
|
+
*/
|
|
937
|
+
private tryTransformEventWithBlockBody;
|
|
938
|
+
/**
|
|
939
|
+
* Transform an event handler whose body is an inline `unless` guard with NO
|
|
940
|
+
* `end` (`on <event> unless <cond> <body>` — the `unless-condition` shape).
|
|
941
|
+
*
|
|
942
|
+
* Object-marking SVO targets (he, zh). `parseEventHandler` reads `unless` as the
|
|
943
|
+
* action and sweeps the whole `<cond> <body>` tail into a single `patient` blob;
|
|
944
|
+
* the target then prefixes that blob with its object marker — Hebrew's accusative
|
|
945
|
+
* את (`… אלא את I match .disabled מתג .selected`) or Chinese's BA particle 把
|
|
946
|
+
* (`… 除非 把 I match .disabled 切换 .selected`) — and the inner toggle loses its
|
|
947
|
+
* own marker. The semantic parser can't recover the guard from that: the marker
|
|
948
|
+
* ahead of the condition blocks the `unless` pattern AND the now-markerless body
|
|
949
|
+
* command fails its object-marked toggle pattern, so the body collapses (`unless`
|
|
950
|
+
* dropped). Marker-less languages (de/it/ar/pl) tolerate the same role-blob and
|
|
951
|
+
* stay faithful, so this is an object-marker artifact, not a general parse gap.
|
|
952
|
+
*
|
|
953
|
+
* The standalone `unless <cond> <body>` path already produces the correct shape
|
|
954
|
+
* (`extractBlockStructure` → `transformBlock`: condition kept marker-free, body
|
|
955
|
+
* command keeps its marker — he `אלא I match .disabled מתג את .selected`, zh
|
|
956
|
+
* `除非 I match .disabled 切换 把 .selected`). So we split the event head off,
|
|
957
|
+
* transform the guard through that path, and emit the event clause first (he and
|
|
958
|
+
* zh are both SVO — event leads). Returns `null` (fall through) when the input
|
|
959
|
+
* isn't an object-marking event handler with an un-terminated inline `unless`
|
|
960
|
+
* guard.
|
|
961
|
+
*/
|
|
962
|
+
private tryTransformEventWithUnlessGuard;
|
|
963
|
+
/**
|
|
964
|
+
* Transform an event handler whose body leads with a command-modifier
|
|
965
|
+
* (`on <event> [from <src>] {async|once|debounced [at N]|throttled [at N]} <body>`).
|
|
966
|
+
*
|
|
967
|
+
* `parseEventHandler` reads the first token after the event as the **action**, so
|
|
968
|
+
* a leading modifier is mistaken for the verb and the real verb (`fetch`/`add`) is
|
|
969
|
+
* swept into the patient. For SOV targets the reorder then surfaces that verb
|
|
970
|
+
* **first** (`取得 /api/data を クリック …`), and the semantic parser matches the
|
|
971
|
+
* leading `<verb> <patient>` with the low-priority `*-generated-verb-first`
|
|
972
|
+
* command pattern — returning a bare command and discarding the event + the rest
|
|
973
|
+
* of the body (degenerate parse).
|
|
974
|
+
*
|
|
975
|
+
* Instead, lift the modifier out, transform the modifier-free handler through the
|
|
976
|
+
* normal path (which keeps the body in canonical patient-first SOV order so the
|
|
977
|
+
* event sits mid-stream and the existing SOV event-extraction recovers it), then
|
|
978
|
+
* re-emit the modifier as a **leading English literal**. The semantic parser
|
|
979
|
+
* strips a leading `once`/`debounced`/`throttled` (`extractStandaloneModifiers`)
|
|
980
|
+
* and an `async` anywhere (`stripAsyncModifier`) before parsing, so the modifier
|
|
981
|
+
* is consumed as handler metadata rather than shadowing the body.
|
|
982
|
+
*
|
|
983
|
+
* Returns `null` (fall through) when the input isn't an event handler or the body
|
|
984
|
+
* doesn't lead with a modifier — leaving simple/Mode-B handlers byte-identical.
|
|
985
|
+
*/
|
|
986
|
+
private tryTransformEventWithModifierBody;
|
|
987
|
+
/**
|
|
988
|
+
* Transform a `set <stuff> on <scope>` clause (S1 tabs-aria). The trailing
|
|
989
|
+
* `on <scope>` is the element(s) the attribute is set on — kept attached by
|
|
990
|
+
* splitOnCommandBoundaries. The semantic parser captures it as a `scope` role
|
|
991
|
+
* via the passthrough literal `on` (setSchema's scope markerOverride is `on`
|
|
992
|
+
* in every language), so `on` is emitted verbatim and only the scope *value*
|
|
993
|
+
* is translated (selectors pass through; `me`/`it`/`you` translate to the
|
|
994
|
+
* native reference, which the parser also accepts).
|
|
995
|
+
*
|
|
996
|
+
* Positioning matches where the set patterns expect the scope: at the clause
|
|
997
|
+
* end for verb-first orders (SVO/VSO), and immediately before the clause-final
|
|
998
|
+
* verb for SOV (the generated SOV pattern is `{dest} {patient} on {scope}
|
|
999
|
+
* {verb}`). Returns null (fall through) when there is no trailing `on <scope>`.
|
|
1000
|
+
*
|
|
1001
|
+
* Source is English in the sync-translations pipeline, so the `set` verb and
|
|
1002
|
+
* `on` marker are matched as English literals.
|
|
1003
|
+
*/
|
|
1004
|
+
private transformSetWithScope;
|
|
1005
|
+
/**
|
|
1006
|
+
* Transform a self-contained block command (`{head} {clause?} {body} {end}`),
|
|
1007
|
+
* where head ∈ {if, repeat, unless, …}. The clause (condition / `until event …`)
|
|
1008
|
+
* runs up to the first command verb and is translated word-by-word; the body is
|
|
1009
|
+
* recursively transformed (so its inner commands reorder for the target); the
|
|
1010
|
+
* head/tail keywords are translated. The block is never word-order reordered as
|
|
1011
|
+
* a whole — delimiters stay at the edges regardless of target word order.
|
|
1012
|
+
*/
|
|
1013
|
+
private transformBlockBody;
|
|
1014
|
+
/**
|
|
1015
|
+
* Transform an `if`/`unless` block body, splitting it at a top-level `else` into
|
|
1016
|
+
* a then-branch and an else-branch so each is reordered as a self-contained unit
|
|
1017
|
+
* and the `else` keyword itself is translated. Without this, the body is reordered
|
|
1018
|
+
* as one stream: `else` rides along glued to the preceding clause (and, when that
|
|
1019
|
+
* clause begins with a selector, is marked a selector and left *untranslated*),
|
|
1020
|
+
* and a spurious `then` is inserted around it — both of which break the target
|
|
1021
|
+
* text and the downstream parse. The split is depth-aware so an `else` belonging
|
|
1022
|
+
* to a nested block is not mistaken for this block's separator. Bodies without an
|
|
1023
|
+
* `else` transform exactly as before.
|
|
1024
|
+
*/
|
|
1025
|
+
private transformConditionalBody;
|
|
908
1026
|
/**
|
|
909
1027
|
* Translate a reactive block by translating the head/tail/connector
|
|
910
1028
|
* via the dictionary, recursively transforming the body through the
|
|
@@ -965,4 +1083,4 @@ declare const examples: {
|
|
|
965
1083
|
};
|
|
966
1084
|
};
|
|
967
1085
|
|
|
968
|
-
export { joinTokens as $, type AdpositionType as A,
|
|
1086
|
+
export { joinTokens as $, type AdpositionType as A, frenchProfile as B, germanProfile as C, getProfile as D, ENGLISH_COMMANDS as E, getSupportedLocales as F, type GrammarRule as G, examples as H, hebrewProfile as I, hindiDictionary as J, type KeywordProvider as K, LANGUAGE_FAMILY_DEFAULTS as L, type MorphologyType as M, hiKeywords as N, id as O, type ParsedElement as P, idKeywords as Q, indonesianProfile as R, type SemanticRole as S, insertMarkers as T, UNIVERSAL_ENGLISH_KEYWORDS as U, it as V, type WordOrder as W, itKeywords as X, ja as Y, jaKeywords as Z, japaneseProfile as _, ENGLISH_KEYWORDS as a, ko as a0, koKeywords as a1, koreanProfile as a2, malayProfile as a3, ms as a4, msKeywords as a5, parseStatement as a6, pl as a7, plKeywords as a8, portugueseProfile as a9, vi as aA, viKeywords as aB, zh as aC, zhKeywords as aD, profiles as aa, pt as ab, ptKeywords as ac, qu as ad, quKeywords as ae, quechuaProfile as af, reorderRoles as ag, russianDictionary as ah, ruKeywords as ai, spanishProfile as aj, sw as ak, swKeywords as al, swahiliProfile as am, th as an, thKeywords as ao, tl as ap, tlKeywords as aq, toEnglish as ar, toLocale as as, tr as at, trKeywords as au, transformStatement as av, translate as aw, turkishProfile as ax, ukrainianDictionary as ay, ukKeywords as az, GrammarTransformer as b, type GrammaticalMarker as c, type KeywordProviderOptions as d, type LanguageProfile as e, LocaleManager as f, type ParsedStatement as g, type PatternMatcher as h, type PatternTransform as i, UNIVERSAL_PATTERNS as j, ar as k, arKeywords as l, arabicProfile as m, bn as n, bnKeywords as o, chineseProfile as p, createEnglishProvider as q, createKeywordProvider as r, de as s, deKeywords as t, detectBrowserLocale as u, englishProfile as v, es as w, esKeywords as x, fr as y, frKeywords as z };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { D as Dictionary } from './types-BYtpqGq3.cjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* KeywordProvider interface for locale-aware parsing.
|
|
@@ -869,6 +869,7 @@ declare const germanProfile: LanguageProfile;
|
|
|
869
869
|
declare const frenchProfile: LanguageProfile;
|
|
870
870
|
declare const portugueseProfile: LanguageProfile;
|
|
871
871
|
declare const indonesianProfile: LanguageProfile;
|
|
872
|
+
declare const malayProfile: LanguageProfile;
|
|
872
873
|
declare const quechuaProfile: LanguageProfile;
|
|
873
874
|
declare const swahiliProfile: LanguageProfile;
|
|
874
875
|
declare const hebrewProfile: LanguageProfile;
|
|
@@ -901,10 +902,127 @@ declare class GrammarTransformer {
|
|
|
901
902
|
* For multi-line input, preserves line structure (indentation, blank lines).
|
|
902
903
|
*/
|
|
903
904
|
transform(input: string): string;
|
|
905
|
+
private transformInternal;
|
|
904
906
|
/**
|
|
905
907
|
* Transform a single hyperscript statement (no compound "then" chains).
|
|
906
908
|
*/
|
|
907
909
|
private transformSingle;
|
|
910
|
+
/**
|
|
911
|
+
* Detect and transform an inline JS block (`[on <event>] js <raw js> end`).
|
|
912
|
+
*
|
|
913
|
+
* The `js ... end` body is raw JavaScript: it must not be tokenized,
|
|
914
|
+
* translated, or word-order reordered. We mask the whole block with a single
|
|
915
|
+
* opaque placeholder, run the surrounding statement (the event-handler head,
|
|
916
|
+
* if any) through the normal reorder pipeline so the placeholder lands in the
|
|
917
|
+
* correct action position, then substitute the translated `js`/`end` keywords
|
|
918
|
+
* around the verbatim body.
|
|
919
|
+
*
|
|
920
|
+
* Returns `null` (fall through to the normal path) when there is no js block,
|
|
921
|
+
* no matching `end`, or trailing content after `end` (kept tight on purpose).
|
|
922
|
+
*/
|
|
923
|
+
private tryTransformJsBlock;
|
|
924
|
+
/**
|
|
925
|
+
* Transform an event handler whose body is a block command
|
|
926
|
+
* (`on <event> [from <src>] {if|repeat|unless|while|for} … end`).
|
|
927
|
+
*
|
|
928
|
+
* `parseEventHandler` would treat the block keyword as the action and sweep the
|
|
929
|
+
* condition/body into role values, then reorder them — shredding the block
|
|
930
|
+
* (`if event.shiftKey call submitAndContinue() end` → scattered tokens). Instead
|
|
931
|
+
* we mask the whole block as an opaque action placeholder, reorder the event
|
|
932
|
+
* head normally, transform the block as a self-contained unit, and restitch.
|
|
933
|
+
*
|
|
934
|
+
* Returns `null` (fall through) when the input isn't an event handler, has no
|
|
935
|
+
* block-keyword body, or has no closing `end`.
|
|
936
|
+
*/
|
|
937
|
+
private tryTransformEventWithBlockBody;
|
|
938
|
+
/**
|
|
939
|
+
* Transform an event handler whose body is an inline `unless` guard with NO
|
|
940
|
+
* `end` (`on <event> unless <cond> <body>` — the `unless-condition` shape).
|
|
941
|
+
*
|
|
942
|
+
* Object-marking SVO targets (he, zh). `parseEventHandler` reads `unless` as the
|
|
943
|
+
* action and sweeps the whole `<cond> <body>` tail into a single `patient` blob;
|
|
944
|
+
* the target then prefixes that blob with its object marker — Hebrew's accusative
|
|
945
|
+
* את (`… אלא את I match .disabled מתג .selected`) or Chinese's BA particle 把
|
|
946
|
+
* (`… 除非 把 I match .disabled 切换 .selected`) — and the inner toggle loses its
|
|
947
|
+
* own marker. The semantic parser can't recover the guard from that: the marker
|
|
948
|
+
* ahead of the condition blocks the `unless` pattern AND the now-markerless body
|
|
949
|
+
* command fails its object-marked toggle pattern, so the body collapses (`unless`
|
|
950
|
+
* dropped). Marker-less languages (de/it/ar/pl) tolerate the same role-blob and
|
|
951
|
+
* stay faithful, so this is an object-marker artifact, not a general parse gap.
|
|
952
|
+
*
|
|
953
|
+
* The standalone `unless <cond> <body>` path already produces the correct shape
|
|
954
|
+
* (`extractBlockStructure` → `transformBlock`: condition kept marker-free, body
|
|
955
|
+
* command keeps its marker — he `אלא I match .disabled מתג את .selected`, zh
|
|
956
|
+
* `除非 I match .disabled 切换 把 .selected`). So we split the event head off,
|
|
957
|
+
* transform the guard through that path, and emit the event clause first (he and
|
|
958
|
+
* zh are both SVO — event leads). Returns `null` (fall through) when the input
|
|
959
|
+
* isn't an object-marking event handler with an un-terminated inline `unless`
|
|
960
|
+
* guard.
|
|
961
|
+
*/
|
|
962
|
+
private tryTransformEventWithUnlessGuard;
|
|
963
|
+
/**
|
|
964
|
+
* Transform an event handler whose body leads with a command-modifier
|
|
965
|
+
* (`on <event> [from <src>] {async|once|debounced [at N]|throttled [at N]} <body>`).
|
|
966
|
+
*
|
|
967
|
+
* `parseEventHandler` reads the first token after the event as the **action**, so
|
|
968
|
+
* a leading modifier is mistaken for the verb and the real verb (`fetch`/`add`) is
|
|
969
|
+
* swept into the patient. For SOV targets the reorder then surfaces that verb
|
|
970
|
+
* **first** (`取得 /api/data を クリック …`), and the semantic parser matches the
|
|
971
|
+
* leading `<verb> <patient>` with the low-priority `*-generated-verb-first`
|
|
972
|
+
* command pattern — returning a bare command and discarding the event + the rest
|
|
973
|
+
* of the body (degenerate parse).
|
|
974
|
+
*
|
|
975
|
+
* Instead, lift the modifier out, transform the modifier-free handler through the
|
|
976
|
+
* normal path (which keeps the body in canonical patient-first SOV order so the
|
|
977
|
+
* event sits mid-stream and the existing SOV event-extraction recovers it), then
|
|
978
|
+
* re-emit the modifier as a **leading English literal**. The semantic parser
|
|
979
|
+
* strips a leading `once`/`debounced`/`throttled` (`extractStandaloneModifiers`)
|
|
980
|
+
* and an `async` anywhere (`stripAsyncModifier`) before parsing, so the modifier
|
|
981
|
+
* is consumed as handler metadata rather than shadowing the body.
|
|
982
|
+
*
|
|
983
|
+
* Returns `null` (fall through) when the input isn't an event handler or the body
|
|
984
|
+
* doesn't lead with a modifier — leaving simple/Mode-B handlers byte-identical.
|
|
985
|
+
*/
|
|
986
|
+
private tryTransformEventWithModifierBody;
|
|
987
|
+
/**
|
|
988
|
+
* Transform a `set <stuff> on <scope>` clause (S1 tabs-aria). The trailing
|
|
989
|
+
* `on <scope>` is the element(s) the attribute is set on — kept attached by
|
|
990
|
+
* splitOnCommandBoundaries. The semantic parser captures it as a `scope` role
|
|
991
|
+
* via the passthrough literal `on` (setSchema's scope markerOverride is `on`
|
|
992
|
+
* in every language), so `on` is emitted verbatim and only the scope *value*
|
|
993
|
+
* is translated (selectors pass through; `me`/`it`/`you` translate to the
|
|
994
|
+
* native reference, which the parser also accepts).
|
|
995
|
+
*
|
|
996
|
+
* Positioning matches where the set patterns expect the scope: at the clause
|
|
997
|
+
* end for verb-first orders (SVO/VSO), and immediately before the clause-final
|
|
998
|
+
* verb for SOV (the generated SOV pattern is `{dest} {patient} on {scope}
|
|
999
|
+
* {verb}`). Returns null (fall through) when there is no trailing `on <scope>`.
|
|
1000
|
+
*
|
|
1001
|
+
* Source is English in the sync-translations pipeline, so the `set` verb and
|
|
1002
|
+
* `on` marker are matched as English literals.
|
|
1003
|
+
*/
|
|
1004
|
+
private transformSetWithScope;
|
|
1005
|
+
/**
|
|
1006
|
+
* Transform a self-contained block command (`{head} {clause?} {body} {end}`),
|
|
1007
|
+
* where head ∈ {if, repeat, unless, …}. The clause (condition / `until event …`)
|
|
1008
|
+
* runs up to the first command verb and is translated word-by-word; the body is
|
|
1009
|
+
* recursively transformed (so its inner commands reorder for the target); the
|
|
1010
|
+
* head/tail keywords are translated. The block is never word-order reordered as
|
|
1011
|
+
* a whole — delimiters stay at the edges regardless of target word order.
|
|
1012
|
+
*/
|
|
1013
|
+
private transformBlockBody;
|
|
1014
|
+
/**
|
|
1015
|
+
* Transform an `if`/`unless` block body, splitting it at a top-level `else` into
|
|
1016
|
+
* a then-branch and an else-branch so each is reordered as a self-contained unit
|
|
1017
|
+
* and the `else` keyword itself is translated. Without this, the body is reordered
|
|
1018
|
+
* as one stream: `else` rides along glued to the preceding clause (and, when that
|
|
1019
|
+
* clause begins with a selector, is marked a selector and left *untranslated*),
|
|
1020
|
+
* and a spurious `then` is inserted around it — both of which break the target
|
|
1021
|
+
* text and the downstream parse. The split is depth-aware so an `else` belonging
|
|
1022
|
+
* to a nested block is not mistaken for this block's separator. Bodies without an
|
|
1023
|
+
* `else` transform exactly as before.
|
|
1024
|
+
*/
|
|
1025
|
+
private transformConditionalBody;
|
|
908
1026
|
/**
|
|
909
1027
|
* Translate a reactive block by translating the head/tail/connector
|
|
910
1028
|
* via the dictionary, recursively transforming the body through the
|
|
@@ -965,4 +1083,4 @@ declare const examples: {
|
|
|
965
1083
|
};
|
|
966
1084
|
};
|
|
967
1085
|
|
|
968
|
-
export { joinTokens as $, type AdpositionType as A,
|
|
1086
|
+
export { joinTokens as $, type AdpositionType as A, frenchProfile as B, germanProfile as C, getProfile as D, ENGLISH_COMMANDS as E, getSupportedLocales as F, type GrammarRule as G, examples as H, hebrewProfile as I, hindiDictionary as J, type KeywordProvider as K, LANGUAGE_FAMILY_DEFAULTS as L, type MorphologyType as M, hiKeywords as N, id as O, type ParsedElement as P, idKeywords as Q, indonesianProfile as R, type SemanticRole as S, insertMarkers as T, UNIVERSAL_ENGLISH_KEYWORDS as U, it as V, type WordOrder as W, itKeywords as X, ja as Y, jaKeywords as Z, japaneseProfile as _, ENGLISH_KEYWORDS as a, ko as a0, koKeywords as a1, koreanProfile as a2, malayProfile as a3, ms as a4, msKeywords as a5, parseStatement as a6, pl as a7, plKeywords as a8, portugueseProfile as a9, vi as aA, viKeywords as aB, zh as aC, zhKeywords as aD, profiles as aa, pt as ab, ptKeywords as ac, qu as ad, quKeywords as ae, quechuaProfile as af, reorderRoles as ag, russianDictionary as ah, ruKeywords as ai, spanishProfile as aj, sw as ak, swKeywords as al, swahiliProfile as am, th as an, thKeywords as ao, tl as ap, tlKeywords as aq, toEnglish as ar, toLocale as as, tr as at, trKeywords as au, transformStatement as av, translate as aw, turkishProfile as ax, ukrainianDictionary as ay, ukKeywords as az, GrammarTransformer as b, type GrammaticalMarker as c, type KeywordProviderOptions as d, type LanguageProfile as e, LocaleManager as f, type ParsedStatement as g, type PatternMatcher as h, type PatternTransform as i, UNIVERSAL_PATTERNS as j, ar as k, arKeywords as l, arabicProfile as m, bn as n, bnKeywords as o, chineseProfile as p, createEnglishProvider as q, createKeywordProvider as r, de as s, deKeywords as t, detectBrowserLocale as u, englishProfile as v, es as w, esKeywords as x, fr as y, frKeywords as z };
|
|
@@ -119,4 +119,4 @@ interface TranslationResult {
|
|
|
119
119
|
warnings?: string[];
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
export {
|
|
122
|
+
export { type Dictionary as D, type I18nConfig as I, type LocaleMetadata as L, type TranslationOptions as T, type ValidationResult as V, type TranslationResult as a, type Token as b, DICTIONARY_CATEGORIES as c, type DictionaryCategory as d, type TokenType as e, type TranslationContext as f, type ValidationError as g, type ValidationWarning as h, findInDictionary as i, forEachCategory as j, getDictionaryCategory as k, isDictionaryCategory as l, translateFromEnglish as t };
|
|
@@ -119,4 +119,4 @@ interface TranslationResult {
|
|
|
119
119
|
warnings?: string[];
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
export {
|
|
122
|
+
export { type Dictionary as D, type I18nConfig as I, type LocaleMetadata as L, type TranslationOptions as T, type ValidationResult as V, type TranslationResult as a, type Token as b, DICTIONARY_CATEGORIES as c, type DictionaryCategory as d, type TokenType as e, type TranslationContext as f, type ValidationError as g, type ValidationWarning as h, findInDictionary as i, forEachCategory as j, getDictionaryCategory as k, isDictionaryCategory as l, translateFromEnglish as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lokascript/i18n",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "Grammar transformation and keyword translation for hyperscript",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -37,9 +37,9 @@
|
|
|
37
37
|
"build": "tsup && npm run build:browser",
|
|
38
38
|
"build:browser": "rollup -c rollup.config.mjs",
|
|
39
39
|
"dev": "tsup --watch",
|
|
40
|
-
"test": "vitest",
|
|
41
|
-
"test:check": "vitest
|
|
42
|
-
"test:coverage": "vitest
|
|
40
|
+
"test": "bash ../../scripts/vitest-run.sh",
|
|
41
|
+
"test:check": "VITEST_QUIET=1 bash ../../scripts/vitest-run.sh --reporter=dot",
|
|
42
|
+
"test:coverage": "bash ../../scripts/vitest-run.sh --coverage",
|
|
43
43
|
"typecheck": "tsc --noEmit",
|
|
44
44
|
"lint": "eslint src --ext ts,tsx",
|
|
45
45
|
"validate-dictionaries": "node scripts/validate-dictionaries.js"
|
|
@@ -65,8 +65,8 @@
|
|
|
65
65
|
},
|
|
66
66
|
"homepage": "https://github.com/codetalcott/hyperfixi/tree/main/packages/i18n#readme",
|
|
67
67
|
"dependencies": {
|
|
68
|
-
"@hyperfixi/core": "^2.
|
|
69
|
-
"@lokascript/semantic": "^2.
|
|
68
|
+
"@hyperfixi/core": "^2.6.0",
|
|
69
|
+
"@lokascript/semantic": "^2.6.0",
|
|
70
70
|
"esbuild": "^0.28.0",
|
|
71
71
|
"happy-dom": "^20.8.9",
|
|
72
72
|
"vite": "^7.1.12"
|
package/src/browser.ts
CHANGED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* COMMAND_PRIMARY_ROLES ↔ semantic schema alignment
|
|
3
|
+
*
|
|
4
|
+
* `COMMAND_PRIMARY_ROLES` (constants.ts) is a local mirror of the `primaryRole`
|
|
5
|
+
* field on each `CommandSchema` exported by `@lokascript/semantic`. It's kept
|
|
6
|
+
* local — rather than importing the schemas into the transformer — so the i18n
|
|
7
|
+
* browser bundle doesn't have to pull in the whole semantic graph just to read a
|
|
8
|
+
* handful of role labels.
|
|
9
|
+
*
|
|
10
|
+
* This test guarantees the local copy can't silently drift from the source of
|
|
11
|
+
* truth: every non-`patient` primary role in the schemas must be present (and
|
|
12
|
+
* identical) here, and every entry here must match a schema. The test imports
|
|
13
|
+
* the schemas, but tests don't ship in the bundle.
|
|
14
|
+
*
|
|
15
|
+
* @see packages/i18n/src/constants.ts
|
|
16
|
+
* @see docs-internal/ZH_BLOCK_BODY_SCOPE.md (#1 — transformer role model)
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { describe, it, expect } from 'vitest';
|
|
20
|
+
import { commandSchemas } from '@lokascript/semantic';
|
|
21
|
+
import { COMMAND_PRIMARY_ROLES } from './constants';
|
|
22
|
+
|
|
23
|
+
describe('COMMAND_PRIMARY_ROLES ↔ semantic schema alignment', () => {
|
|
24
|
+
const schemaEntries = Object.entries(commandSchemas) as Array<[string, { primaryRole: string }]>;
|
|
25
|
+
|
|
26
|
+
it('every non-patient schema primaryRole is mirrored locally with the same value', () => {
|
|
27
|
+
const missingOrWrong: string[] = [];
|
|
28
|
+
for (const [action, schema] of schemaEntries) {
|
|
29
|
+
if (schema.primaryRole === 'patient') continue;
|
|
30
|
+
if (COMMAND_PRIMARY_ROLES[action] !== schema.primaryRole) {
|
|
31
|
+
missingOrWrong.push(
|
|
32
|
+
`${action}: schema=${schema.primaryRole} local=${COMMAND_PRIMARY_ROLES[action] ?? '(missing)'}`
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
expect(
|
|
37
|
+
missingOrWrong,
|
|
38
|
+
`COMMAND_PRIMARY_ROLES (packages/i18n/src/constants.ts) drifted from @lokascript/semantic command schemas:\n ${missingOrWrong.join('\n ')}\nUpdate the local map to match.`
|
|
39
|
+
).toEqual([]);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('every local entry matches a schema primaryRole (no stale/patient entries)', () => {
|
|
43
|
+
const stale: string[] = [];
|
|
44
|
+
for (const [action, role] of Object.entries(COMMAND_PRIMARY_ROLES)) {
|
|
45
|
+
const schema = commandSchemas[action as keyof typeof commandSchemas];
|
|
46
|
+
if (!schema) {
|
|
47
|
+
stale.push(`${action}: no such command schema`);
|
|
48
|
+
} else if (schema.primaryRole === 'patient') {
|
|
49
|
+
stale.push(`${action}: schema primaryRole is 'patient' (the default) — drop it`);
|
|
50
|
+
} else if (schema.primaryRole !== role) {
|
|
51
|
+
stale.push(`${action}: local=${role} schema=${schema.primaryRole}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
expect(
|
|
55
|
+
stale,
|
|
56
|
+
`COMMAND_PRIMARY_ROLES contains stale entries vs @lokascript/semantic:\n ${stale.join('\n ')}`
|
|
57
|
+
).toEqual([]);
|
|
58
|
+
});
|
|
59
|
+
});
|
package/src/constants.ts
CHANGED
|
@@ -29,6 +29,50 @@ export const ENGLISH_MODIFIER_ROLES: Readonly<Record<string, SemanticRole>> = {
|
|
|
29
29
|
for: 'duration',
|
|
30
30
|
} as const;
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Maps a command verb to its **primary** semantic role — the role of the
|
|
34
|
+
* command's first/leading argument when no explicit modifier keyword marks it.
|
|
35
|
+
*
|
|
36
|
+
* The generic argument parser in the transformer defaults the first unmarked
|
|
37
|
+
* argument to `patient`, which is correct for the majority of commands
|
|
38
|
+
* (`toggle .x`, `add .x`, …) but wrong for commands whose leading argument is a
|
|
39
|
+
* non-patient — e.g. `wait <duration>`. Marking a duration as a patient emits a
|
|
40
|
+
* spurious object-marker in the target language (Chinese `等待 把 1s`, ungrammatical;
|
|
41
|
+
* Japanese `1s を 待つ`; Korean `1s 를 대기`), which the semantic parser then fails to
|
|
42
|
+
* match — dropping the command.
|
|
43
|
+
*
|
|
44
|
+
* Only commands whose primary role is **not** `patient` are listed here (the
|
|
45
|
+
* `patient` default already covers the rest). Mirrors the `primaryRole` field of
|
|
46
|
+
* the semantic package's command schemas (`@lokascript/semantic`); kept in sync by
|
|
47
|
+
* `schema-alignment.test.ts` so this local copy can't drift without the bundle
|
|
48
|
+
* having to pull in the whole semantic graph.
|
|
49
|
+
*
|
|
50
|
+
* @see packages/i18n/src/schema-alignment.test.ts
|
|
51
|
+
* @see docs-internal/ZH_BLOCK_BODY_SCOPE.md (#1 — transformer role model)
|
|
52
|
+
*/
|
|
53
|
+
export const COMMAND_PRIMARY_ROLES: Readonly<Record<string, SemanticRole>> = {
|
|
54
|
+
set: 'destination',
|
|
55
|
+
on: 'event',
|
|
56
|
+
trigger: 'event',
|
|
57
|
+
send: 'event',
|
|
58
|
+
wait: 'duration',
|
|
59
|
+
fetch: 'source',
|
|
60
|
+
get: 'source',
|
|
61
|
+
if: 'condition',
|
|
62
|
+
unless: 'condition',
|
|
63
|
+
while: 'condition',
|
|
64
|
+
repeat: 'loopType',
|
|
65
|
+
go: 'destination',
|
|
66
|
+
scroll: 'destination',
|
|
67
|
+
tell: 'destination',
|
|
68
|
+
default: 'destination',
|
|
69
|
+
swap: 'destination',
|
|
70
|
+
// morph deliberately absent: its schema primaryRole is `patient` (the
|
|
71
|
+
// element being morphed — aligned with the transformer's patient marking
|
|
72
|
+
// in the session-9 role-layout swap), and patient is the default.
|
|
73
|
+
bind: 'destination',
|
|
74
|
+
} as const;
|
|
75
|
+
|
|
32
76
|
/**
|
|
33
77
|
* English modifier keywords (derived from ENGLISH_MODIFIER_ROLES)
|
|
34
78
|
*/
|
|
@@ -110,6 +154,13 @@ export const ENGLISH_COMMANDS: Set<string> = new Set([
|
|
|
110
154
|
'trigger',
|
|
111
155
|
'unless',
|
|
112
156
|
'wait',
|
|
157
|
+
// v2.x reactive + realtime + service-worker DSL commands
|
|
158
|
+
'live',
|
|
159
|
+
'bind',
|
|
160
|
+
'eventsource',
|
|
161
|
+
'socket',
|
|
162
|
+
'worker',
|
|
163
|
+
'intercept',
|
|
113
164
|
]);
|
|
114
165
|
|
|
115
166
|
// =============================================================================
|
package/src/dictionaries/ar.ts
CHANGED
|
@@ -19,7 +19,10 @@ export const ar: Dictionary = {
|
|
|
19
19
|
hide: 'اخف',
|
|
20
20
|
show: 'اظهر',
|
|
21
21
|
if: 'إذا',
|
|
22
|
-
|
|
22
|
+
// Single-token form: the semantic ar tokenizer splits the two-word `إلا إذا`
|
|
23
|
+
// into `إلا` + `إذا`(if), which derails the `unless` block. `إلا` alone is the
|
|
24
|
+
// conventional Arabic shorthand and matches the ar profile's unless keyword.
|
|
25
|
+
unless: 'إلا',
|
|
23
26
|
repeat: 'كرر',
|
|
24
27
|
for: 'لكل',
|
|
25
28
|
while: 'بينما',
|
|
@@ -49,19 +52,20 @@ export const ar: Dictionary = {
|
|
|
49
52
|
js: 'جافاسكربت',
|
|
50
53
|
async: 'متزامن',
|
|
51
54
|
render: 'ارسم',
|
|
52
|
-
swap: 'بدّل'
|
|
55
|
+
swap: 'استبدل', // profile primary; 'بدّل' is toggle's word (parsed as toggle)
|
|
53
56
|
morph: 'حوّل',
|
|
54
57
|
settle: 'استقر',
|
|
55
58
|
append: 'ألحق',
|
|
56
59
|
exit: 'اخرج',
|
|
57
60
|
install: 'ثبّت',
|
|
58
61
|
breakpoint: 'نقطة-توقف',
|
|
59
|
-
clear: '
|
|
62
|
+
clear: 'نظّف', // امسح is a remove alternative in the profile
|
|
60
63
|
close: 'أغلق',
|
|
61
64
|
open: 'افتح',
|
|
62
65
|
select: 'اختر',
|
|
63
66
|
clone: 'استنسخ',
|
|
64
67
|
prepend: 'سبق',
|
|
68
|
+
socket: 'مقبس',
|
|
65
69
|
},
|
|
66
70
|
|
|
67
71
|
modifiers: {
|
|
@@ -131,6 +135,7 @@ export const ar: Dictionary = {
|
|
|
131
135
|
otherwise: 'خلاف ذلك',
|
|
132
136
|
end: 'النهاية',
|
|
133
137
|
live: 'حي',
|
|
138
|
+
bind: 'اربط',
|
|
134
139
|
changes: 'يتغير',
|
|
135
140
|
},
|
|
136
141
|
|
package/src/dictionaries/bn.ts
CHANGED
|
@@ -34,7 +34,7 @@ export const bengaliDictionary: Dictionary = {
|
|
|
34
34
|
throw: 'নিক্ষেপ',
|
|
35
35
|
continue: 'চালিয়ে যান',
|
|
36
36
|
make: 'তৈরি করুন',
|
|
37
|
-
append: '
|
|
37
|
+
append: 'জুড়ুন',
|
|
38
38
|
prepend: 'শুরুতে যোগ',
|
|
39
39
|
focus: 'ফোকাস',
|
|
40
40
|
blur: 'ঝাপসা',
|
|
@@ -63,6 +63,7 @@ export const bengaliDictionary: Dictionary = {
|
|
|
63
63
|
close: 'বন্ধ',
|
|
64
64
|
open: 'খুলুন',
|
|
65
65
|
select: 'নির্বাচন',
|
|
66
|
+
socket: 'সকেট',
|
|
66
67
|
},
|
|
67
68
|
|
|
68
69
|
modifiers: {
|
|
@@ -124,6 +125,7 @@ export const bengaliDictionary: Dictionary = {
|
|
|
124
125
|
end: 'শেষ',
|
|
125
126
|
then: 'তারপর',
|
|
126
127
|
live: 'লাইভ',
|
|
128
|
+
bind: 'বাইন্ড',
|
|
127
129
|
changes: 'পরিবর্তিত হলে',
|
|
128
130
|
},
|
|
129
131
|
|
package/src/dictionaries/de.ts
CHANGED
|
@@ -16,9 +16,17 @@ export const de: Dictionary = {
|
|
|
16
16
|
add: 'hinzufügen',
|
|
17
17
|
remove: 'entfernen',
|
|
18
18
|
toggle: 'umschalten',
|
|
19
|
+
// command blur (the events section has the blur EVENT word; without this
|
|
20
|
+
// entry the transformer fell back to it and no profile read it as the verb)
|
|
21
|
+
blur: 'defokussieren',
|
|
19
22
|
hide: 'verstecken',
|
|
20
23
|
show: 'zeigen',
|
|
21
|
-
if
|
|
24
|
+
// Align with the semantic German profile's `if` primary (`falls`). The previous
|
|
25
|
+
// `wenn` collides with the profile's `when` keyword (German `wenn` = both
|
|
26
|
+
// "if" and "when"), so a transformed `if` resolved to `when` and the conditional
|
|
27
|
+
// wrapper never formed (`if`/`put` dropped). Same dict↔profile alignment as id
|
|
28
|
+
// `toggle` / get-value. `when` is unaffected (separate dict entry).
|
|
29
|
+
if: 'falls',
|
|
22
30
|
unless: 'wennnicht',
|
|
23
31
|
repeat: 'wiederholen',
|
|
24
32
|
for: 'für',
|
|
@@ -28,7 +36,7 @@ export const de: Dictionary = {
|
|
|
28
36
|
break: 'unterbrechen',
|
|
29
37
|
halt: 'anhalten',
|
|
30
38
|
wait: 'warten',
|
|
31
|
-
fetch: '
|
|
39
|
+
fetch: 'abrufen',
|
|
32
40
|
call: 'aufrufen',
|
|
33
41
|
return: 'zurückgeben',
|
|
34
42
|
make: 'erstellen',
|
|
@@ -56,12 +64,13 @@ export const de: Dictionary = {
|
|
|
56
64
|
exit: 'beenden',
|
|
57
65
|
install: 'installieren',
|
|
58
66
|
breakpoint: 'haltepunkt',
|
|
59
|
-
clear: '
|
|
67
|
+
clear: 'bereinigen', // löschen is a remove alternative in the profile
|
|
60
68
|
close: 'schließen',
|
|
61
69
|
open: 'öffnen',
|
|
62
70
|
select: 'auswählen',
|
|
63
71
|
clone: 'klonen',
|
|
64
72
|
prepend: 'voranstellen',
|
|
73
|
+
focus: 'fokussieren',
|
|
65
74
|
},
|
|
66
75
|
|
|
67
76
|
modifiers: {
|
|
@@ -192,7 +201,13 @@ export const de: Dictionary = {
|
|
|
192
201
|
prev: 'vorh',
|
|
193
202
|
at: 'bei',
|
|
194
203
|
random: 'zufällig',
|
|
195
|
-
|
|
204
|
+
// `nächste` already serves `next` (line above). German `nächste` is
|
|
205
|
+
// genuinely ambiguous (next/nearest), so emitting it for `closest` too
|
|
206
|
+
// collided: the semantic tokenizer normalizes `nächste`→next (a deliberate
|
|
207
|
+
// last-wins choice — see german.ts), and a closest reading is impossible to
|
|
208
|
+
// recover. Use the unambiguous `nächstgelegene` ("nearest-located") for
|
|
209
|
+
// closest so the two readings stay distinct end-to-end.
|
|
210
|
+
closest: 'nächstgelegene',
|
|
196
211
|
parent: 'elternteil',
|
|
197
212
|
children: 'kinder',
|
|
198
213
|
within: 'innerhalb',
|
package/src/dictionaries/en.ts
CHANGED
|
@@ -55,6 +55,15 @@ export const en: Dictionary = {
|
|
|
55
55
|
decrement: 'decrement',
|
|
56
56
|
default: 'default',
|
|
57
57
|
|
|
58
|
+
// Reactivity Commands
|
|
59
|
+
bind: 'bind',
|
|
60
|
+
|
|
61
|
+
// Realtime / service-worker Commands
|
|
62
|
+
eventsource: 'eventsource',
|
|
63
|
+
socket: 'socket',
|
|
64
|
+
worker: 'worker',
|
|
65
|
+
intercept: 'intercept',
|
|
66
|
+
|
|
58
67
|
// Navigation Commands
|
|
59
68
|
go: 'go',
|
|
60
69
|
pushUrl: 'pushUrl',
|