langsys-js-react 0.6.6 → 0.7.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/CHANGELOG.md +43 -0
- package/README-SSR.md +144 -170
- package/README.md +339 -23
- package/dist/app-zQKL7-vo.d.mts +61 -0
- package/dist/app-zQKL7-vo.d.ts +61 -0
- package/dist/babel.d.mts +122 -0
- package/dist/babel.d.ts +122 -0
- package/dist/babel.js +547 -0
- package/dist/babel.js.map +1 -0
- package/dist/babel.mjs +545 -0
- package/dist/babel.mjs.map +1 -0
- package/dist/index.d.mts +164 -79
- package/dist/index.d.ts +164 -79
- package/dist/index.js +502 -97
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +423 -89
- package/dist/index.mjs.map +1 -1
- package/dist/next-loader.d.mts +8 -0
- package/dist/next-loader.d.ts +8 -0
- package/dist/next-loader.js +623 -0
- package/dist/next-loader.js.map +1 -0
- package/dist/next-loader.mjs +621 -0
- package/dist/next-loader.mjs.map +1 -0
- package/dist/next.d.mts +15 -0
- package/dist/next.d.ts +15 -0
- package/dist/next.js +41 -0
- package/dist/next.js.map +1 -0
- package/dist/next.mjs +37 -0
- package/dist/next.mjs.map +1 -0
- package/dist/server.d.mts +36 -0
- package/dist/server.d.ts +36 -0
- package/dist/server.js +57 -0
- package/dist/server.js.map +1 -0
- package/dist/server.mjs +25 -0
- package/dist/server.mjs.map +1 -0
- package/dist/vite.d.mts +14 -0
- package/dist/vite.d.ts +14 -0
- package/dist/vite.js +623 -0
- package/dist/vite.js.map +1 -0
- package/dist/vite.mjs +621 -0
- package/dist/vite.mjs.map +1 -0
- package/package.json +38 -3
package/dist/babel.d.mts
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { types, PluginObj, PluginPass } from '@babel/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* langsys-js-react/babel — the placeholder transform (spec VAR-6), as a Babel plugin.
|
|
5
|
+
*
|
|
6
|
+
* A value interpolated into translated text becomes a named placeholder, and the value travels as
|
|
7
|
+
* its param, so one sentence registers once however many users it is shown to (VAR-1):
|
|
8
|
+
*
|
|
9
|
+
* <Translate>Hello {user.name}</Translate>
|
|
10
|
+
* → <Translate params={{ name: user.name }}>Hello %name%</Translate>
|
|
11
|
+
*
|
|
12
|
+
* t(`You have ${items.length} items`)
|
|
13
|
+
* → t('You have {items_count} items', undefined, { items_count: items.length })
|
|
14
|
+
*
|
|
15
|
+
* A subtree the core shows as written — `<DontTranslate>`, a host element with `translate="no"` or
|
|
16
|
+
* `data-notrans`, or code and notation (`<template>`, `<noscript>`, `<math>`) — is never translated:
|
|
17
|
+
* a phrase keys it as one opaque element and restores its content, and a block keeps it in its
|
|
18
|
+
* stored content. A value there therefore stays where it is, in both components, and is marked as a
|
|
19
|
+
* value (VAR-3) rather than replaced, so the page shows the value and a block's stored content holds
|
|
20
|
+
* its placeholder; where no marker can stand (below) it is left as written instead. A `translate`
|
|
21
|
+
* or `data-notrans` whose value is an expression is known only at runtime. In a `<Translate>` a
|
|
22
|
+
* value under it is marked and passed as a param too, so excluded it shows as written, and
|
|
23
|
+
* translated the core reads the marker as its placeholder and fills it from the param, which wins
|
|
24
|
+
* over the marked text. In a `<Phrase>` it is a placeholder like any other: translated, the phrase
|
|
25
|
+
* fills it; excluded, the core keys the element as one empty pair and fills the caller's params into
|
|
26
|
+
* an author's exclusion. A `<Phrase>` holding a marker of its own in its text (inside a conditional
|
|
27
|
+
* or a component too) is served as its source until a translation exists, so its other values are
|
|
28
|
+
* marked too, and passed as params; one in its translated text where no marker can stand is left
|
|
29
|
+
* as written, and the phrase gets `data-ls-unnamed`. A name a marker already carries is taken, as an
|
|
30
|
+
* explicit `%name%` is. An opt-out passed through a spread is not seen. Where no marker element
|
|
31
|
+
* can stand — inside MathML and SVG an HTML `<span>` draws nothing, and `<textarea>`, `<title>` and
|
|
32
|
+
* `<option>` hold text only — a value in such a subtree is left as written, and a `<Translate>`,
|
|
33
|
+
* which would store it, gets `data-ls-unnamed` and registers nothing (VAR-7); a `<Phrase>` keys the
|
|
34
|
+
* subtree as one empty pair. `<script>`, `<style>` and `<plaintext>` hold raw text, which a block
|
|
35
|
+
* stores as written and a phrase keys as one empty pair: a value there is left as written, and a `<Translate>`
|
|
36
|
+
* holding one gets `data-ls-unnamed`.
|
|
37
|
+
*
|
|
38
|
+
* <Translate>Signed in as <DontTranslate>{user.email}</DontTranslate></Translate>
|
|
39
|
+
* → <Translate>Signed in as <DontTranslate><span data-ls-param="email">{user.email}</span></DontTranslate></Translate>
|
|
40
|
+
*
|
|
41
|
+
* A block's tokens begin with each element's attributes a translator reads (TOK-3: the core's
|
|
42
|
+
* `TRANSLATABLE_ATTRIBUTES`, and the value of a button or a submit or button input), so in a
|
|
43
|
+
* `<Translate>` a value in one is a placeholder too. A value only in attributes' text travels as the
|
|
44
|
+
* string JavaScript writes there; one that is the whole attribute, or also in the content, travels
|
|
45
|
+
* as given and fills its placeholder as a value fills text, and one React renders as nodes (a list,
|
|
46
|
+
* an object) is put back as a whole prop and fills an attribute's text as JavaScript writes it into a
|
|
47
|
+
* string (`withNodeParams`). On an element whose opt-out or input type is
|
|
48
|
+
* an expression, which only the page decides, the value is left as written and the `<Translate>`
|
|
49
|
+
* gets `data-ls-unnamed`. A `<Phrase>` keys none of its elements' attributes, so they are left as
|
|
50
|
+
* written there.
|
|
51
|
+
*
|
|
52
|
+
* <Translate><img alt={`Photo of ${user.name}`} /> Hi {user.name}</Translate>
|
|
53
|
+
* → <Translate params={{ name: user.name }}><img alt={"Photo of %name%"} /> Hi %name%</Translate>
|
|
54
|
+
*
|
|
55
|
+
* The core reads `%name%` left to right, so where the text before a value ends in a `%` and a name
|
|
56
|
+
* it has not closed (`%s{x}`), the placeholder's own `%` would close it; there the placeholder is
|
|
57
|
+
* written in the stored form, `{name}`, which the core reads the same way (`%s{x}`). The text is read
|
|
58
|
+
* as the core registers it (C0 control characters dropped) and as it renders it (kept).
|
|
59
|
+
*
|
|
60
|
+
* Only `<Translate>` and `<Phrase>` imported from `langsys-js-react` are rewritten, and only the
|
|
61
|
+
* children a host element, a fragment or `<DontTranslate>` renders as text: an expression inside a
|
|
62
|
+
* nested host element (`<b>{x}</b>`) is included; one that is itself JSX or holds JSX
|
|
63
|
+
* (`items.map((i) => <li>…`), a conditional, already marked (`data-ls-param`), or sits inside
|
|
64
|
+
* another component or a nested `<Translate>` / `<Phrase>` is left alone, since React renders nodes
|
|
65
|
+
* from it rather than a value's text. `{children}` (under any TypeScript cast) that is all the
|
|
66
|
+
* text of its run in translated text (what React renders between two elements) is content to
|
|
67
|
+
* translate and is left alone; beside text, or in a subtree that is not translated, it is a value. A value whose type only the page knows, an element held in a variable, is rewritten like
|
|
68
|
+
* any other, and `<Translate>` / `<Phrase>` render it in its placeholder's place
|
|
69
|
+
* (`withNodeParams`). String, number and plain template literals (`{' '}`, `{3}`) are static text,
|
|
70
|
+
* and a fragment (`<>…</>`, React's `Fragment`) is unwrapped, as React passes its children on. A
|
|
71
|
+
* children list the transform changes reaches React as a JSX compiler hands it over from the
|
|
72
|
+
* source, each run of text one string (JSX's whitespace rule applied, a comment dropped), so the
|
|
73
|
+
* runtime never takes a unit's own text for a value split from it (VAR-7); this holds in the JSX
|
|
74
|
+
* compiler's own Babel pass and when the output is compiled again. `t()` calls are rewritten where
|
|
75
|
+
* `t` is the binding a `useT()` call made (and `<Translate>` / `<Phrase>` matched by their import's
|
|
76
|
+
* binding), so another function named `t` is left alone. A `+` chain joins as JavaScript joins it:
|
|
77
|
+
* a sum before the first string, or in parentheses, is one value. A key built in the call (its own
|
|
78
|
+
* text has no space: `errors.${code}`, `status_${status}`) is left as it is, since legacy-key mode
|
|
79
|
+
* looks it up as built. A name the developer wrote (`%name%` anywhere in a unit, a key of a params
|
|
80
|
+
* literal, `{name}` in a `t()` text whose params the build cannot read into: a variable, a spread)
|
|
81
|
+
* is never given to a value. Names follow VAR-2 (`./naming`); an expression
|
|
82
|
+
* no name can be derived from is named `value`, `value_2`, … and reported in
|
|
83
|
+
* `file.metadata.langsys.warnings`, which the Vite plugin and the Next loader surface as build
|
|
84
|
+
* warnings.
|
|
85
|
+
*/
|
|
86
|
+
|
|
87
|
+
interface LangsysTransformMetadata {
|
|
88
|
+
/** One entry per unnameable expression: where it is, and the name it was given. */
|
|
89
|
+
warnings: Array<{
|
|
90
|
+
line: number | null;
|
|
91
|
+
column: number | null;
|
|
92
|
+
source: string;
|
|
93
|
+
name: string;
|
|
94
|
+
}>;
|
|
95
|
+
/** How many units were rewritten. */
|
|
96
|
+
rewritten: number;
|
|
97
|
+
}
|
|
98
|
+
interface State extends PluginPass {
|
|
99
|
+
targets: Set<string>;
|
|
100
|
+
/** Local names of `<Phrase>`, which keys code, notation and an author's exclusion as one empty pair. */
|
|
101
|
+
phrases: Set<string>;
|
|
102
|
+
verbatim: Set<string>;
|
|
103
|
+
/** Local names of React's `Fragment`, and of the `react` module itself (`React.Fragment`). */
|
|
104
|
+
fragments: Set<string>;
|
|
105
|
+
reactModules: Set<string>;
|
|
106
|
+
hooks: Set<string>;
|
|
107
|
+
/**
|
|
108
|
+
* The declaring identifiers of `<Translate>` / `<Phrase>` and `useT` imported from the package, and
|
|
109
|
+
* of each `t` a `useT()` call bound: a binding's identifier is the same node after another plugin
|
|
110
|
+
* in the pass crawls the scope again, where its `Binding` object is not.
|
|
111
|
+
*/
|
|
112
|
+
targetBindings: Set<types.Identifier>;
|
|
113
|
+
hookBindings: Set<types.Identifier>;
|
|
114
|
+
tBindings: Set<types.Identifier>;
|
|
115
|
+
meta: LangsysTransformMetadata;
|
|
116
|
+
}
|
|
117
|
+
type Babel = {
|
|
118
|
+
types: typeof types;
|
|
119
|
+
};
|
|
120
|
+
declare function langsysPlaceholders({ types: T }: Babel): PluginObj<State>;
|
|
121
|
+
|
|
122
|
+
export { type LangsysTransformMetadata, langsysPlaceholders as default };
|
package/dist/babel.d.ts
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { types, PluginObj, PluginPass } from '@babel/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* langsys-js-react/babel — the placeholder transform (spec VAR-6), as a Babel plugin.
|
|
5
|
+
*
|
|
6
|
+
* A value interpolated into translated text becomes a named placeholder, and the value travels as
|
|
7
|
+
* its param, so one sentence registers once however many users it is shown to (VAR-1):
|
|
8
|
+
*
|
|
9
|
+
* <Translate>Hello {user.name}</Translate>
|
|
10
|
+
* → <Translate params={{ name: user.name }}>Hello %name%</Translate>
|
|
11
|
+
*
|
|
12
|
+
* t(`You have ${items.length} items`)
|
|
13
|
+
* → t('You have {items_count} items', undefined, { items_count: items.length })
|
|
14
|
+
*
|
|
15
|
+
* A subtree the core shows as written — `<DontTranslate>`, a host element with `translate="no"` or
|
|
16
|
+
* `data-notrans`, or code and notation (`<template>`, `<noscript>`, `<math>`) — is never translated:
|
|
17
|
+
* a phrase keys it as one opaque element and restores its content, and a block keeps it in its
|
|
18
|
+
* stored content. A value there therefore stays where it is, in both components, and is marked as a
|
|
19
|
+
* value (VAR-3) rather than replaced, so the page shows the value and a block's stored content holds
|
|
20
|
+
* its placeholder; where no marker can stand (below) it is left as written instead. A `translate`
|
|
21
|
+
* or `data-notrans` whose value is an expression is known only at runtime. In a `<Translate>` a
|
|
22
|
+
* value under it is marked and passed as a param too, so excluded it shows as written, and
|
|
23
|
+
* translated the core reads the marker as its placeholder and fills it from the param, which wins
|
|
24
|
+
* over the marked text. In a `<Phrase>` it is a placeholder like any other: translated, the phrase
|
|
25
|
+
* fills it; excluded, the core keys the element as one empty pair and fills the caller's params into
|
|
26
|
+
* an author's exclusion. A `<Phrase>` holding a marker of its own in its text (inside a conditional
|
|
27
|
+
* or a component too) is served as its source until a translation exists, so its other values are
|
|
28
|
+
* marked too, and passed as params; one in its translated text where no marker can stand is left
|
|
29
|
+
* as written, and the phrase gets `data-ls-unnamed`. A name a marker already carries is taken, as an
|
|
30
|
+
* explicit `%name%` is. An opt-out passed through a spread is not seen. Where no marker element
|
|
31
|
+
* can stand — inside MathML and SVG an HTML `<span>` draws nothing, and `<textarea>`, `<title>` and
|
|
32
|
+
* `<option>` hold text only — a value in such a subtree is left as written, and a `<Translate>`,
|
|
33
|
+
* which would store it, gets `data-ls-unnamed` and registers nothing (VAR-7); a `<Phrase>` keys the
|
|
34
|
+
* subtree as one empty pair. `<script>`, `<style>` and `<plaintext>` hold raw text, which a block
|
|
35
|
+
* stores as written and a phrase keys as one empty pair: a value there is left as written, and a `<Translate>`
|
|
36
|
+
* holding one gets `data-ls-unnamed`.
|
|
37
|
+
*
|
|
38
|
+
* <Translate>Signed in as <DontTranslate>{user.email}</DontTranslate></Translate>
|
|
39
|
+
* → <Translate>Signed in as <DontTranslate><span data-ls-param="email">{user.email}</span></DontTranslate></Translate>
|
|
40
|
+
*
|
|
41
|
+
* A block's tokens begin with each element's attributes a translator reads (TOK-3: the core's
|
|
42
|
+
* `TRANSLATABLE_ATTRIBUTES`, and the value of a button or a submit or button input), so in a
|
|
43
|
+
* `<Translate>` a value in one is a placeholder too. A value only in attributes' text travels as the
|
|
44
|
+
* string JavaScript writes there; one that is the whole attribute, or also in the content, travels
|
|
45
|
+
* as given and fills its placeholder as a value fills text, and one React renders as nodes (a list,
|
|
46
|
+
* an object) is put back as a whole prop and fills an attribute's text as JavaScript writes it into a
|
|
47
|
+
* string (`withNodeParams`). On an element whose opt-out or input type is
|
|
48
|
+
* an expression, which only the page decides, the value is left as written and the `<Translate>`
|
|
49
|
+
* gets `data-ls-unnamed`. A `<Phrase>` keys none of its elements' attributes, so they are left as
|
|
50
|
+
* written there.
|
|
51
|
+
*
|
|
52
|
+
* <Translate><img alt={`Photo of ${user.name}`} /> Hi {user.name}</Translate>
|
|
53
|
+
* → <Translate params={{ name: user.name }}><img alt={"Photo of %name%"} /> Hi %name%</Translate>
|
|
54
|
+
*
|
|
55
|
+
* The core reads `%name%` left to right, so where the text before a value ends in a `%` and a name
|
|
56
|
+
* it has not closed (`%s{x}`), the placeholder's own `%` would close it; there the placeholder is
|
|
57
|
+
* written in the stored form, `{name}`, which the core reads the same way (`%s{x}`). The text is read
|
|
58
|
+
* as the core registers it (C0 control characters dropped) and as it renders it (kept).
|
|
59
|
+
*
|
|
60
|
+
* Only `<Translate>` and `<Phrase>` imported from `langsys-js-react` are rewritten, and only the
|
|
61
|
+
* children a host element, a fragment or `<DontTranslate>` renders as text: an expression inside a
|
|
62
|
+
* nested host element (`<b>{x}</b>`) is included; one that is itself JSX or holds JSX
|
|
63
|
+
* (`items.map((i) => <li>…`), a conditional, already marked (`data-ls-param`), or sits inside
|
|
64
|
+
* another component or a nested `<Translate>` / `<Phrase>` is left alone, since React renders nodes
|
|
65
|
+
* from it rather than a value's text. `{children}` (under any TypeScript cast) that is all the
|
|
66
|
+
* text of its run in translated text (what React renders between two elements) is content to
|
|
67
|
+
* translate and is left alone; beside text, or in a subtree that is not translated, it is a value. A value whose type only the page knows, an element held in a variable, is rewritten like
|
|
68
|
+
* any other, and `<Translate>` / `<Phrase>` render it in its placeholder's place
|
|
69
|
+
* (`withNodeParams`). String, number and plain template literals (`{' '}`, `{3}`) are static text,
|
|
70
|
+
* and a fragment (`<>…</>`, React's `Fragment`) is unwrapped, as React passes its children on. A
|
|
71
|
+
* children list the transform changes reaches React as a JSX compiler hands it over from the
|
|
72
|
+
* source, each run of text one string (JSX's whitespace rule applied, a comment dropped), so the
|
|
73
|
+
* runtime never takes a unit's own text for a value split from it (VAR-7); this holds in the JSX
|
|
74
|
+
* compiler's own Babel pass and when the output is compiled again. `t()` calls are rewritten where
|
|
75
|
+
* `t` is the binding a `useT()` call made (and `<Translate>` / `<Phrase>` matched by their import's
|
|
76
|
+
* binding), so another function named `t` is left alone. A `+` chain joins as JavaScript joins it:
|
|
77
|
+
* a sum before the first string, or in parentheses, is one value. A key built in the call (its own
|
|
78
|
+
* text has no space: `errors.${code}`, `status_${status}`) is left as it is, since legacy-key mode
|
|
79
|
+
* looks it up as built. A name the developer wrote (`%name%` anywhere in a unit, a key of a params
|
|
80
|
+
* literal, `{name}` in a `t()` text whose params the build cannot read into: a variable, a spread)
|
|
81
|
+
* is never given to a value. Names follow VAR-2 (`./naming`); an expression
|
|
82
|
+
* no name can be derived from is named `value`, `value_2`, … and reported in
|
|
83
|
+
* `file.metadata.langsys.warnings`, which the Vite plugin and the Next loader surface as build
|
|
84
|
+
* warnings.
|
|
85
|
+
*/
|
|
86
|
+
|
|
87
|
+
interface LangsysTransformMetadata {
|
|
88
|
+
/** One entry per unnameable expression: where it is, and the name it was given. */
|
|
89
|
+
warnings: Array<{
|
|
90
|
+
line: number | null;
|
|
91
|
+
column: number | null;
|
|
92
|
+
source: string;
|
|
93
|
+
name: string;
|
|
94
|
+
}>;
|
|
95
|
+
/** How many units were rewritten. */
|
|
96
|
+
rewritten: number;
|
|
97
|
+
}
|
|
98
|
+
interface State extends PluginPass {
|
|
99
|
+
targets: Set<string>;
|
|
100
|
+
/** Local names of `<Phrase>`, which keys code, notation and an author's exclusion as one empty pair. */
|
|
101
|
+
phrases: Set<string>;
|
|
102
|
+
verbatim: Set<string>;
|
|
103
|
+
/** Local names of React's `Fragment`, and of the `react` module itself (`React.Fragment`). */
|
|
104
|
+
fragments: Set<string>;
|
|
105
|
+
reactModules: Set<string>;
|
|
106
|
+
hooks: Set<string>;
|
|
107
|
+
/**
|
|
108
|
+
* The declaring identifiers of `<Translate>` / `<Phrase>` and `useT` imported from the package, and
|
|
109
|
+
* of each `t` a `useT()` call bound: a binding's identifier is the same node after another plugin
|
|
110
|
+
* in the pass crawls the scope again, where its `Binding` object is not.
|
|
111
|
+
*/
|
|
112
|
+
targetBindings: Set<types.Identifier>;
|
|
113
|
+
hookBindings: Set<types.Identifier>;
|
|
114
|
+
tBindings: Set<types.Identifier>;
|
|
115
|
+
meta: LangsysTransformMetadata;
|
|
116
|
+
}
|
|
117
|
+
type Babel = {
|
|
118
|
+
types: typeof types;
|
|
119
|
+
};
|
|
120
|
+
declare function langsysPlaceholders({ types: T }: Babel): PluginObj<State>;
|
|
121
|
+
|
|
122
|
+
export { type LangsysTransformMetadata, langsysPlaceholders as default };
|