@yuneta/gobj-ui 7.26.34 → 7.26.35
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/README.md +223 -53
- package/dist/gobj-ui.cjs.js +1035 -141
- package/dist/gobj-ui.es.js +1035 -141
- package/package.json +2 -2
- package/scripts/validate-locales.mjs +672 -96
- package/src/c_yui_form.js +186 -9
- package/src/c_yui_gclass.js +2 -0
- package/src/c_yui_gobj_tree_js.js +2 -0
- package/src/c_yui_json.js +2 -0
- package/src/c_yui_json_graph.js +2 -0
- package/src/c_yui_nav.js +23 -5
- package/src/c_yui_shell.css +16 -0
- package/src/c_yui_shell.js +282 -26
- package/src/c_yui_treedb_graph.js +26 -8
- package/src/c_yui_treedb_topic_with_form.js +40 -18
- package/src/c_yui_treedb_topics.js +34 -11
- package/src/c_yui_window.js +132 -32
- package/src/c_yui_window_manager.js +156 -44
- package/src/form_json_editor_names.js +448 -0
- package/src/form_json_editor_names.wiring.test.js +595 -0
- package/src/form_label_i18n.wiring.test.js +169 -0
- package/src/i18n_key_functions.js +14 -6
- package/src/i18n_key_functions.test.js +124 -2
- package/src/lib_maplibre.js +26 -2
- package/src/lib_maplibre_relocalize.test.js +78 -0
- package/src/named_controls.wiring.test.js +468 -0
- package/src/nav_cards_helpers.js +9 -1
- package/src/nav_item_badge.wiring.test.js +182 -1
- package/src/shell_route_map.js +25 -8
- package/src/table_editor_name.wiring.test.js +201 -0
- package/src/treedb_column_title.wiring.test.js +151 -0
- package/src/treedb_json_drill.wiring.test.js +41 -1
- package/src/window_layer.wiring.test.js +308 -43
- package/src/window_show.wiring.test.js +6 -2
- package/src/window_stacking.wiring.test.js +334 -0
- package/src/yui_badge.js +58 -13
- package/src/yui_badge.test.js +40 -3
- package/src/yui_dev.js +2 -1
- package/src/yui_file_field.js +2 -0
- package/src/yui_frontend_view.js +2 -1
- package/src/yui_gclass_view.js +9 -6
- package/src/yui_tabulator_i18n.js +42 -0
- package/src/yui_tabulator_i18n.test.js +48 -1
package/README.md
CHANGED
|
@@ -79,14 +79,50 @@ Published as `@yuneta/gobj-ui`. Built on top of [`@yuneta/gobj-js`](https://gith
|
|
|
79
79
|
> the title bar in place) and its `is-shaded` CSS are **removed**; an app that
|
|
80
80
|
> relied on shading needs to register a manager.
|
|
81
81
|
>
|
|
82
|
-
> **Where a window lives (7.26.31):** a `C_YUI_WINDOW` whose host
|
|
83
|
-
> `$parent` mounts in the **
|
|
84
|
-
>
|
|
85
|
-
>
|
|
86
|
-
>
|
|
87
|
-
>
|
|
88
|
-
>
|
|
89
|
-
>
|
|
82
|
+
> **Where a window lives (7.26.31, 7.26.35):** a `C_YUI_WINDOW` whose host
|
|
83
|
+
> names no `$parent` mounts in the **window layer of the shell**
|
|
84
|
+
> (`yui_shell_window_layer()`), a stacking context of its own inside the
|
|
85
|
+
> overlay layer -- above the content, below the drawer, the toolbar's
|
|
86
|
+
> dropdowns, the dialogs and the toasts -- and on `document.body` only while
|
|
87
|
+
> there is no shell. It used to be the body always, and since `.yui-shell` is
|
|
88
|
+
> `position: fixed` (a stacking context of its own) a window at z-index 11
|
|
89
|
+
> covered the WHOLE shell, modal layer included: the confirmation of a
|
|
90
|
+
> window's own close opened under it, out of reach. A `$parent` the host names
|
|
91
|
+
> still wins.
|
|
92
|
+
>
|
|
93
|
+
> **Every window of the library lives there, in ONE z-order** (7.26.35). The
|
|
94
|
+
> site map, the raw json of the treedb graph and topics, the gclass viewer and
|
|
95
|
+
> the json of a treedb topic form used to name the shell's POPUP layer: above
|
|
96
|
+
> the drawer, in the way of the toolbar's dropdowns (which opened behind them
|
|
97
|
+
> where they met). And there were two orders: the dock raised its windows to a
|
|
98
|
+
> counter of its own, a window without a dock sat at 3 -- so a window opened
|
|
99
|
+
> later without a dock opened UNDER any docked one, and no click brought it up.
|
|
100
|
+
> Now one number orders every window (`yui_shell_raise_window()`): a window
|
|
101
|
+
> opens on top, a press brings it up (a docked one through the dock's
|
|
102
|
+
> `EV_FOCUS_WINDOW`, one without a dock through its own `EV_SHOW`), and nothing
|
|
103
|
+
> a window takes can reach the drawer or the layers above.
|
|
104
|
+
>
|
|
105
|
+
> **The place follows the shell.** A window parented to the app (the
|
|
106
|
+
> developer window, a device window) outlives a logout that destroys the
|
|
107
|
+
> shell: it goes to the body with it, and the next shell takes it in again.
|
|
108
|
+
> Each shell built or destroyed sends `EV_SHELL_CHANGED` to every gobj that
|
|
109
|
+
> asked with `yui_shell_watch_changes()` -- every `C_YUI_WINDOW` and the dock
|
|
110
|
+
> do -- and each places itself again in its own action. A window its host
|
|
111
|
+
> placed stays where it was put, unless that element was inside the shell
|
|
112
|
+
> that went. From 7.26.31 to 7.26.34 such a window stayed in the destroyed
|
|
113
|
+
> shell's layer: alive, detached, invisible, and the first click on its menu
|
|
114
|
+
> entry closed the invisible one. Its Back entry goes with the shell that held
|
|
115
|
+
> it: after a re-login Back no longer closes it, its ✕ does.
|
|
116
|
+
>
|
|
117
|
+
> **The dock** (`C_YUI_WINDOW_MANAGER`, floating) lives in the shell's popup
|
|
118
|
+
> layer, at the top of it: above every window, below the dialogs and the
|
|
119
|
+
> toasts. It was `document.body` at z-index 1000000, above the whole shell --
|
|
120
|
+
> clickable over a dialog's backdrop. Inline, it moves to the next shell's zone
|
|
121
|
+
> after a logout, and floats in the body between them. A **chip** of the dock
|
|
122
|
+
> is no control itself (7.26.35): it holds two sibling buttons, the toggle
|
|
123
|
+
> (minimise / bring back, named by the window's title, through the FSM:
|
|
124
|
+
> `EV_TOGGLE_WINDOW`) and its ✕ (`close`). It was a `role="button"` holding
|
|
125
|
+
> the ✕ button -- one control inside another.
|
|
90
126
|
|
|
91
127
|
## Two maintained lines
|
|
92
128
|
|
|
@@ -3207,14 +3243,35 @@ all for the same reason (a badge that lies costs more than no badge):
|
|
|
3207
3243
|
the default look, so a call with three arguments works as it always did.
|
|
3208
3244
|
- **Unknown item id is a silent no-op**, so an app whose toolbar or menu has no
|
|
3209
3245
|
such item does not log an error on every tick of whatever feeds the number.
|
|
3210
|
-
- Writing the **same** value again touches no DOM
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3246
|
+
- Writing the **same** value again touches no DOM.
|
|
3247
|
+
|
|
3248
|
+
**What a screen reader gets** (since `7.26.35`). The button or link carries an
|
|
3249
|
+
explicit `aria-label`, and an explicit label **replaces** an element's content
|
|
3250
|
+
for a reader -- inside a `<button>` (the toolbar, an accordion head) the badge
|
|
3251
|
+
is not even in the tree. So:
|
|
3252
|
+
|
|
3253
|
+
- **The count is part of the control's NAME.** The control is labelled by
|
|
3254
|
+
itself and by its badge (`aria-labelledby="<control> <badge>"`,
|
|
3255
|
+
`name_control_with_badge()` in `yui_badge.js`): the self-reference reads its
|
|
3256
|
+
`aria-label`, which `refresh_language()` re-translates, and the badge adds its
|
|
3257
|
+
text -- *"Alarms 3"*, or *"Alarms"* while there is none. Nothing is composed
|
|
3258
|
+
in javascript, so a language switch keeps it right.
|
|
3259
|
+
- **A change is SAID, with the name of what it counts**: *"Alarms, 3"*, in one
|
|
3260
|
+
live region of the shell (`.SHELL_BADGE_STATUS`, `role="status"`,
|
|
3261
|
+
visually hidden), which is always in the tree -- never hidden, never inside a
|
|
3262
|
+
control. `yui_shell_set_nav_item_badge()` and
|
|
3263
|
+
`yui_shell_set_toolbar_item_badge()` say it when the text a reader would see
|
|
3264
|
+
CHANGES and is not empty: the same count is no news, a count going away is
|
|
3265
|
+
not either, one coming back is. A menu entry drawn by three navs is said
|
|
3266
|
+
once. The phrase is a key of its own, `"{{name}}, {{n}}"`, so a language
|
|
3267
|
+
orders and punctuates it its way; it goes through the translator the app gave
|
|
3268
|
+
the shell (`yui_shell_set_translator`).
|
|
3269
|
+
|
|
3270
|
+
Up to `7.26.34` the badge was its own `role="status"`: it said *"3"* with no
|
|
3271
|
+
word of what has three, it was `hidden` while empty -- so the first count was
|
|
3272
|
+
most likely never said -- and inside a `<button>` it was not there at all. A
|
|
3273
|
+
`C_YUI_NAV` used without a shell names its counts the same way, but says
|
|
3274
|
+
nothing when one changes: the live region is the shell's.
|
|
3218
3275
|
|
|
3219
3276
|
**The menu entry's badge reaches every instance of the id.** A menu hosted by
|
|
3220
3277
|
two zones (a rail on desktop, an icon bar on a phone) draws the same entry
|
|
@@ -3599,7 +3656,8 @@ export default { plugins: [ yunetaHtmlPlugin({ defaultTitle: "My App" }) ] };
|
|
|
3599
3656
|
|
|
3600
3657
|
`npm run build && npm test`, then `npm publish`. A published version reaches
|
|
3601
3658
|
an app only through **`npm run deploy-round`**: it waits for the registry to
|
|
3602
|
-
serve the version, then per app raises the range
|
|
3659
|
+
serve the version, then per app raises the range (and the app's own version,
|
|
3660
|
+
its third number, in the same edit), installs, builds, deploys
|
|
3603
3661
|
and reads back the bundle each host serves (`--check` only reads back,
|
|
3604
3662
|
`--only <name>` does one app, `--no-wait` skips the registry). The private
|
|
3605
3663
|
consumers are listed in `~/.yuneta/gobj-ui-consumers.json` (see
|
|
@@ -3654,7 +3712,7 @@ one. All four attributes are written where the control is built:
|
|
|
3654
3712
|
```
|
|
3655
3713
|
|
|
3656
3714
|
It is a floor, not a preference. The ecosystem was swept against it — the
|
|
3657
|
-
deployed page of
|
|
3715
|
+
deployed page of every SPA, read control by control — and the target is **zero
|
|
3658
3716
|
controls without a name**. Three things it exists to stop, each of which
|
|
3659
3717
|
shipped:
|
|
3660
3718
|
|
|
@@ -3703,7 +3761,30 @@ DOM is a race with the next one:
|
|
|
3703
3761
|
row-selection checkbox (`yui_tabulator_name_filters` /
|
|
3704
3762
|
`yui_tabulator_name_row_selects`, hung off `columnsLoaded` and
|
|
3705
3763
|
`renderComplete`), Tom Select's box in front of the `<select>` it hides
|
|
3706
|
-
(`name_form_control`).
|
|
3764
|
+
(`name_form_control`). Since `7.26.35` also:
|
|
3765
|
+
- the box Tabulator draws in a cell being **edited**, named after its
|
|
3766
|
+
column by `yui_tabulator_name_editor(column_def, name_of)` -- asked at
|
|
3767
|
+
the moment of editing (Tabulator takes `editorParams` as a function of
|
|
3768
|
+
the cell, and its built-in editors write the `elementAttributes` it
|
|
3769
|
+
answers), so the name is in the language of that moment with nothing to
|
|
3770
|
+
re-apply;
|
|
3771
|
+
- the ✕ of a selected option of a Tom Select (its `remove_button`
|
|
3772
|
+
plugin's `html`): `remove this option`, reachable and pressed by a key;
|
|
3773
|
+
- the menu of the json editor of a form (vanilla-jsoneditor), known by
|
|
3774
|
+
the class it gives each button (`form_json_editor_names.js`): its titles
|
|
3775
|
+
and the text of its mode buttons through `onRenderMenu`, its aria-labels
|
|
3776
|
+
and `aria-pressed` after each render (`EV_NAME_JSON_EDITORS`), and drawn
|
|
3777
|
+
again on the shell's `EV_LANGUAGE_CHANGED`. Its CONTEXT menu too
|
|
3778
|
+
(`onRenderContextMenu`): its items carry no class, so each is known by
|
|
3779
|
+
the icon it is drawn with, the column it stands in, its place in a
|
|
3780
|
+
dropdown and the editor's mode -- never by its words -- and an item the
|
|
3781
|
+
module does not know stays in English rather than mislabelled; the arrow
|
|
3782
|
+
that opens a dropdown, which the editor names not at all, is `more
|
|
3783
|
+
options`. **A documented limit:** what the editor draws with no hook --
|
|
3784
|
+
its search box, its repair messages, the tip at the foot of the context
|
|
3785
|
+
menu, its sort and transform modals -- stays in its English;
|
|
3786
|
+
- maplibre's canvas and default markers, whose `aria-label` maplibre writes
|
|
3787
|
+
once from its locale: `yui_maplibre_relocalize()` rewrites them.
|
|
3707
3788
|
- **An `<option>`**, which is text like any other: it carries `data-i18n`,
|
|
3708
3789
|
with `value` kept explicit — a translated option with no value tells the FSM
|
|
3709
3790
|
to enter a mode that does not exist.
|
|
@@ -3846,14 +3927,30 @@ call of t()?" (since `7.26.32`; up to `7.26.31` it was a call NAMED `t` or
|
|
|
3846
3927
|
`tr`): a name `t` or `tr` (whatever binds it), a member `.t` / `.tr`
|
|
3847
3928
|
(`i18next.t`), i18next's `t` imported under any name (`import {t as tt} from
|
|
3848
3929
|
"i18next"`), or an alias of one -- a const (`const translate = t`), a
|
|
3849
|
-
`.bind()` (`i18next.t.bind(i18next)`), a
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
`t(
|
|
3853
|
-
|
|
3854
|
-
`
|
|
3930
|
+
`.bind()` (`i18next.t.bind(i18next)`), a destructuring (since `7.26.35`:
|
|
3931
|
+
`const {t: tt} = i18next`, a parameter `{t: tt}`), a re-export of a module the
|
|
3932
|
+
reader reads --, called as `t(k)`, `t?.(k)`, `t.call(x, k)` or
|
|
3933
|
+
`t.apply(x, [k])`. An ARRAY given to it is i18next's list of fallback keys, and
|
|
3934
|
+
each one is a key: `t([specific, "generic"])` asks for "generic". The places,
|
|
3935
|
+
since `7.26.32`, also include `el.dataset.i18nTitle = k` (`dataset.i18nX` IS
|
|
3936
|
+
the attribute `data-i18n-x`), and an attribute or property NAMED by a const:
|
|
3855
3937
|
`el.setAttribute(ATTR, k)`, `{[ATTR]: k}`, `x[ATTR] = k`, with `const ATTR =
|
|
3856
|
-
"data-i18n-title"
|
|
3938
|
+
"data-i18n-title"`; and since `7.26.35` `el.setAttributeNS(ns, ATTR, k)`, and a
|
|
3939
|
+
translator handed as a CALLBACK:
|
|
3940
|
+
|
|
3941
|
+
- `keys.map(t)`, `.forEach(t)` (and `flatMap`, `filter`, `find`, `findLast`,
|
|
3942
|
+
`some`, `every`), `Array.from(keys, t)`: each ELEMENT is a key, read like any
|
|
3943
|
+
other -- a const array, a published list, an import of one are followed;
|
|
3944
|
+
- `promise.then(t)`, `.catch(t)`: what the promise settles with is a key no
|
|
3945
|
+
source writes.
|
|
3946
|
+
|
|
3947
|
+
Both are held to the rule per call (below): an array the reader cannot follow,
|
|
3948
|
+
and any promise, fails unless the call is marked
|
|
3949
|
+
(`/* i18n: data */ rows.map(t)`; or before the translator,
|
|
3950
|
+
`load().then(/* i18n: data */ t)`). A translator handed to a FUNCTION is not
|
|
3951
|
+
one of these: `{t: t}`, `yui_tabulator_lang(t)`, `refresh_language($el, t)` --
|
|
3952
|
+
it is how gobj-ui receives one, and the function calls it with keys of its
|
|
3953
|
+
own. What is followed:
|
|
3857
3954
|
|
|
3858
3955
|
- a string literal, a template with no `${}`, and every branch of `?:`, `||`
|
|
3859
3956
|
and `??` (the right one of `&&`), so
|
|
@@ -3903,13 +4000,39 @@ function pick(ok) {
|
|
|
3903
4000
|
t(pick(answer)); // asks for both
|
|
3904
4001
|
```
|
|
3905
4002
|
|
|
3906
|
-
What it cannot follow cannot be known: a `let
|
|
3907
|
-
function, a call it does not read, a concatenation, data
|
|
3908
|
-
that arrives that way is PUBLISHED by its module (below),
|
|
3909
|
-
read is MARKED; a marked `let` -- or a marked member or
|
|
3910
|
-
one
|
|
4003
|
+
What it cannot follow cannot be known: a `let` given anything but literals, a
|
|
4004
|
+
parameter of an app's function, a call it does not read, a concatenation, data
|
|
4005
|
+
from a backend. A key that arrives that way is PUBLISHED by its module (below),
|
|
4006
|
+
and the place it is read is MARKED; a marked `let` -- or a marked member or
|
|
4007
|
+
element of one -- is followed (below). A source file that cannot be parsed
|
|
3911
4008
|
fails the build, because its keys would go unchecked.
|
|
3912
4009
|
|
|
4010
|
+
**An UNMARKED `let` that is only ever given literals IS followed** (since
|
|
4011
|
+
`7.26.35`), where `t()`, an `i18n` / `code` value or a `data-i18n*` attribute
|
|
4012
|
+
reads a key: when every value it is given in its scope -- its initializer, every
|
|
4013
|
+
`=`, `||=`, `??=`, `&&=` -- is WRITTEN as a string literal, a const bound to one
|
|
4014
|
+
(of the module, or imported), `null` / `undefined`, another such `let`, or a
|
|
4015
|
+
`?:` / `||` / `??` of those (the right one of `&&`), the variable can only ever
|
|
4016
|
+
hold those literals, and each is a key asked for. It is exact, not a guess, so
|
|
4017
|
+
it fails nothing new: a key missing from the locales fails as any key does.
|
|
4018
|
+
|
|
4019
|
+
```js
|
|
4020
|
+
let state_key = (st === "ST_MONITORING")? "monitor monitoring" : "monitor disconnected";
|
|
4021
|
+
if(connecting) {
|
|
4022
|
+
state_key = "monitor connecting";
|
|
4023
|
+
}
|
|
4024
|
+
$state.setAttribute("data-i18n", state_key); // asks for all three
|
|
4025
|
+
$state.textContent = t(state_key);
|
|
4026
|
+
```
|
|
4027
|
+
|
|
4028
|
+
A `let` given anything else is not followed and stays invisible: a property of
|
|
4029
|
+
a table (`let m = MONTHS[i]`: the reader would read every value of the table,
|
|
4030
|
+
which is enough for a marker that names lists, and too much to ask the locales
|
|
4031
|
+
for), a call (`let k = busy_key(gobj)`), a parameter, data, or a write it cannot
|
|
4032
|
+
read (`k += "!"`, a `for...of` over it, a destructuring). At a key position of a
|
|
4033
|
+
key function nothing changes: a `let` there is still a violation of the rule per
|
|
4034
|
+
call (below), which wants a const or a marker.
|
|
4035
|
+
|
|
3913
4036
|
**A key handed to a FUNCTION is read where it is handed.**
|
|
3914
4037
|
`yui_shell_show_error(shell, "some records were gone before the delete")` asks
|
|
3915
4038
|
`t()` for its key INSIDE the function, where no scan of `t("...")` sees it, and
|
|
@@ -4054,7 +4177,9 @@ write it as a literal or a `const` where it is read, and the reader sees it.
|
|
|
4054
4177
|
`const key = maximized ? "restore" : "maximize"; t(key);` asks for both keys,
|
|
4055
4178
|
and so do the pager's ✕, the camera's anchor button, the nav's landmark, the
|
|
4056
4179
|
selection bar's clear button and the treedb form's title, which are written
|
|
4057
|
-
that way. The same code with a `let` asks for
|
|
4180
|
+
that way. The same code with a `let` asks for both too at `t()` (since
|
|
4181
|
+
`7.26.35`: a `let` only ever given literals is followed), but at a key position
|
|
4182
|
+
of a key function it fails the rule per call, which wants the const.
|
|
4058
4183
|
|
|
4059
4184
|
```js
|
|
4060
4185
|
export const MY_VIEW_I18N_KEYS = ['shape', 'radius', 'apply to'];
|
|
@@ -4088,9 +4213,11 @@ list in silence, and a key holding `]` dropped the whole array; up to
|
|
|
4088
4213
|
WRITTEN, so a key it is given later is asked for by nobody. `X.push(k)`,
|
|
4089
4214
|
`X.splice(i, 0, k)`, `X.unshift(k)`, `X.fill(k)`, `X[i] = k`, `X.length = n`,
|
|
4090
4215
|
`Object.assign(X, ...)` and `delete X[i]` fail the build, in the module that
|
|
4091
|
-
publishes the list and in every module that imports it (under any name
|
|
4092
|
-
|
|
4093
|
-
|
|
4216
|
+
publishes the list and in every module that imports it (under any name; since
|
|
4217
|
+
`7.26.35` also as a member of a namespace import, `M.X_I18N_KEYS.push(k)`, and
|
|
4218
|
+
through an ALIAS: `const a = X_I18N_KEYS; a.push(k)`, or a `let` given nothing
|
|
4219
|
+
else). Up to `7.26.31` an `export let` list was read and could be pushed into,
|
|
4220
|
+
and the pushed keys went unasked:
|
|
4094
4221
|
|
|
4095
4222
|
```js
|
|
4096
4223
|
export let MY_VIEW_I18N_KEYS = ["shape"]; // fails: a published list is an export const
|
|
@@ -4117,12 +4244,24 @@ confirm_then(gobj, /* i18n: C_YUI_FORM_I18N_KEYS */ kw.warning || "all changes w
|
|
|
4117
4244
|
follow must be in them: a marker is a claim, and it is checked. A key BUILT
|
|
4118
4245
|
at run time is published that way and marked with its list -- gui_agent's
|
|
4119
4246
|
monitor names a control's label `monitor ${control}`, and publishes the six
|
|
4120
|
-
keys that template builds in `C_AGENT_MONITOR_I18N_KEYS
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4247
|
+
keys that template builds in `C_AGENT_MONITOR_I18N_KEYS` (and the questions,
|
|
4248
|
+
`monitor confirm ${control}`, in `C_AGENT_MONITOR_CONFIRM_I18N_KEYS`). A
|
|
4249
|
+
template with `${}` under a list marker must have the SHAPE of some key of
|
|
4250
|
+
the lists (since `7.26.32`): `monitor ${control}` is checked against
|
|
4251
|
+
`^monitor .*$`, so a marker naming the wrong list fails. And (since
|
|
4252
|
+
`7.26.35`) a key of that shape that a NARROWER marked template builds -- one
|
|
4253
|
+
whose shape lies inside it, `monitor confirm ${control}` -- is that
|
|
4254
|
+
template's: up to `7.26.34` `monitor ${control}` marked with the list of the
|
|
4255
|
+
questions passed, because "monitor confirm start" matches `^monitor .*$`;
|
|
4256
|
+
now it fails, naming the narrower template. (The wider template builds such
|
|
4257
|
+
a key only when what fills its `${}` carries the narrower one's literal --
|
|
4258
|
+
"confirm start" for a control --, which code that writes both does not do.)
|
|
4259
|
+
Every key of a published list is asked for, so a control whose key the list
|
|
4260
|
+
LACKS is the one thing the validator cannot see: what a template builds is
|
|
4261
|
+
data. The app holds such a list to its source with a test of its own --
|
|
4262
|
+
gui_agent's `monitor_i18n_keys.test.js` derives every control from
|
|
4263
|
+
`SCENARIO_ACTIONS` and `scenario_controls()`, and fails until both lists
|
|
4264
|
+
hold exactly their keys.
|
|
4126
4265
|
|
|
4127
4266
|
**A `data` marker is a claim too** (since `7.26.29`). On what the reader
|
|
4128
4267
|
follows to keys and nothing else -- a literal, a template with no `${}`, a
|
|
@@ -4189,7 +4328,9 @@ t(/* i18n: C_YUI_WINDOW_I18N_KEYS */ key);
|
|
|
4189
4328
|
```
|
|
4190
4329
|
|
|
4191
4330
|
The rule is the same under `i18n: data`: the literals of a marked variable are
|
|
4192
|
-
read, and one that holds nothing else fails.
|
|
4331
|
+
read, and one that holds nothing else fails. (Unmarked, such a variable fails
|
|
4332
|
+
nothing: since `7.26.35` its literals are simply asked for, above. The marker
|
|
4333
|
+
is what makes it a claim to check.)
|
|
4193
4334
|
|
|
4194
4335
|
**A `let` that holds a TABLE is held the same way** (since the same round:
|
|
4195
4336
|
up to then a marked member of one passed unread). When what is marked is read
|
|
@@ -4271,7 +4412,13 @@ so it never changes language. Hand it the key. A translated text is the value
|
|
|
4271
4412
|
of any TRANSLATOR (since `7.26.32`; up to `7.26.31` only a call named `t`, so
|
|
4272
4413
|
`tr("save")`, an alias of t, `t?.()` or `t.call()` passed marked -- and an
|
|
4273
4414
|
unmarked `tr()` failed with *"cannot follow"*, whose advice was the marker that
|
|
4274
|
-
then let it pass):
|
|
4415
|
+
then let it pass), and (since `7.26.35`) a string BUILT from one: a
|
|
4416
|
+
concatenation or a template holding one (`t("k") + ":"`, `` `${t("k")}:` ``),
|
|
4417
|
+
a method called on one (`t("k").toUpperCase()`, `[t("a"), name].join(" ")`);
|
|
4418
|
+
DOM built with one (`createElement2(["p", {}, t("k")])`) is DOM. No marker
|
|
4419
|
+
excuses such a text anywhere a key is read -- `t(/* i18n: data */ t("k") +
|
|
4420
|
+
"!")` and `{i18n: /* i18n: data */ t("k").trim()}` fail too, with *"hand the
|
|
4421
|
+
key, not t(key)"*:
|
|
4275
4422
|
|
|
4276
4423
|
```js
|
|
4277
4424
|
yui_install_ask_once(shell, {t: t, message: t("install this app")}); // fails
|
|
@@ -4354,8 +4501,10 @@ it asks for or carries with the list.
|
|
|
4354
4501
|
reading the page in another language:
|
|
4355
4502
|
|
|
4356
4503
|
- a key handed to a translator, an `i18n` or a `data-i18n*` value by an
|
|
4357
|
-
UNMARKED `let
|
|
4358
|
-
|
|
4504
|
+
UNMARKED `let` given anything but literals (a property of a table, a call, a
|
|
4505
|
+
parameter, data, a `+=`: one only ever given literals is followed, above), a
|
|
4506
|
+
call the reader does not follow (a recursion, one whose returns mix keys and
|
|
4507
|
+
data, a function of a package) or a computed string:
|
|
4359
4508
|
a translator is not a key function, and only the positions of
|
|
4360
4509
|
`I18N_KEY_FUNCTIONS` are held to the per-call rule -- in the library and in
|
|
4361
4510
|
an app alike. (A PARAMETER is not, in the library: the forwarder test puts
|
|
@@ -4363,7 +4512,18 @@ reading the page in another language:
|
|
|
4363
4512
|
name it.);
|
|
4364
4513
|
- a translator the reader does not know as one: a name other than `t` / `tr`
|
|
4365
4514
|
that no const or import makes an alias of -- a parameter `translate`, a
|
|
4366
|
-
`let` alias, `opts.translate(k)`, `i18next.getFixedT()
|
|
4515
|
+
`let` alias, `opts.translate(k)`, `i18next.getFixedT()` --, or one called
|
|
4516
|
+
through what is no name of it: `(0, t)(k)`, `[t][0](k)`,
|
|
4517
|
+
`Reflect.apply(t, x, [k])`, `Function.prototype.call.call(t, x, k)`;
|
|
4518
|
+
- a key BOUND with the translator, `t.bind(null, k)` (`.bind()` is read as an
|
|
4519
|
+
alias of the translator, and the key it binds is not read);
|
|
4520
|
+
- a translator handed to a FUNCTION (`{t: t}`, `yui_tabulator_lang(t)`,
|
|
4521
|
+
`run(t)`): only the iteration methods, `Array.from()` and `.then()` /
|
|
4522
|
+
`.catch()` are read as calling it with what they walk or settle with;
|
|
4523
|
+
- a translated text held in a marked `let` (`let label = t(k);` ...
|
|
4524
|
+
`/* i18n: data */ label`): the marker reads the literals of the `let`, not
|
|
4525
|
+
its translations -- only a translated text written right under the marker
|
|
4526
|
+
fails;
|
|
4367
4527
|
- a key function reached through a parameter (`apply(fn)` calling
|
|
4368
4528
|
`fn(shell, "k")`), a `let` given more than one function, a map in a `let`,
|
|
4369
4529
|
a computed member (`API[name](...)`), or `.apply()` of an array the source
|
|
@@ -4378,13 +4538,20 @@ reading the page in another language:
|
|
|
4378
4538
|
- what a module of a package exports (gobj-js, i18next), and an exported
|
|
4379
4539
|
`let`;
|
|
4380
4540
|
- in the library's forwarder search, a key stored in a heap object or a DOM
|
|
4381
|
-
node and read back somewhere else (`$b._yui_label` was one),
|
|
4382
|
-
|
|
4541
|
+
node and read back somewhere else (`$b._yui_label` was one), a parameter a
|
|
4542
|
+
CLOSURE returns (`const inner = () => key; t(inner())`), and what a caller
|
|
4543
|
+
puts in a gobj's attrs (a window's `title` given at `gobj_create()`);
|
|
4544
|
+
- a published list mutated through a function it is handed to
|
|
4545
|
+
(`function add(list) { list.push(k); } add(X_I18N_KEYS)`), or by
|
|
4546
|
+
`Array.prototype.push.call(X_I18N_KEYS, k)`;
|
|
4383
4547
|
- in an app, a key its callers hand a wrapper of its own reaches the locales
|
|
4384
4548
|
only through a list the module publishes: the wrapper's hand-off must be
|
|
4385
4549
|
marked (the rule per call), and nothing ties its callers' literals to the
|
|
4386
4550
|
list -- nor a key built at run time (a template) to the list its marker
|
|
4387
|
-
names, beyond the shape of the template
|
|
4551
|
+
names, beyond the shape of the template (the app's own test does:
|
|
4552
|
+
gui_agent's `monitor_i18n_keys.test.js`); a marker over a parameter of such
|
|
4553
|
+
a wrapper (`title: /* i18n: L_I18N_KEYS */ title_key`) checks nothing at
|
|
4554
|
+
all, since what its callers hand it is not read.
|
|
4388
4555
|
|
|
4389
4556
|
**What fails the build, besides a key no locale defines:**
|
|
4390
4557
|
|
|
@@ -4396,14 +4563,17 @@ reading the page in another language:
|
|
|
4396
4563
|
`translation` dict;
|
|
4397
4564
|
- a source file that cannot be parsed;
|
|
4398
4565
|
- a published list no consumer can read (above), declared with `let` or
|
|
4399
|
-
`var`, or mutated;
|
|
4566
|
+
`var`, or mutated (also through an alias or a namespace member);
|
|
4400
4567
|
- a marker that is wrong (above): a `data` marker on what the reader follows
|
|
4401
4568
|
to keys, or on what would hide a key (a call mixing keys and data, an array
|
|
4402
|
-
of string literals),
|
|
4403
|
-
list has
|
|
4569
|
+
of string literals), any marker on a translated text, a list marker on a
|
|
4570
|
+
template whose shape no key of the list has -- or whose every key of that
|
|
4571
|
+
shape a narrower marked template builds;
|
|
4404
4572
|
- a key position of a key function, in the app's own code, given what the
|
|
4405
4573
|
reader cannot follow and unmarked, or given a translated text (the rule per
|
|
4406
|
-
call, above)
|
|
4574
|
+
call, above); and so a translator handed as a callback to `.map()`,
|
|
4575
|
+
`.forEach()`, ... over an array the reader cannot follow, or to `.then()` /
|
|
4576
|
+
`.catch()`, unmarked.
|
|
4407
4577
|
|
|
4408
4578
|
Up to `7.26.27` the locale cases were "skipped" with an OK: one language less
|
|
4409
4579
|
validated, and nobody told. A file of the locales directory with a locale's
|