@yuneta/gobj-ui 7.26.28 → 7.26.30
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 +225 -62
- package/dist/gobj-ui.cjs.js +401 -122
- package/dist/gobj-ui.es.js +401 -123
- package/index.js +1 -0
- package/package.json +4 -2
- package/scripts/validate-locales.mjs +565 -177
- package/src/c_yui_form.js +5 -3
- package/src/c_yui_gobj_tree_js.js +1 -1
- package/src/c_yui_nav.js +164 -29
- package/src/c_yui_period.js +3 -3
- package/src/c_yui_schema_editor.js +22 -18
- package/src/c_yui_shell.css +84 -18
- package/src/c_yui_shell.js +149 -68
- package/src/c_yui_treedb_graph.js +3 -4
- package/src/c_yui_treedb_topic_with_form.js +15 -15
- package/src/c_yui_treedb_topics.js +8 -8
- package/src/c_yui_window_manager.js +5 -2
- package/src/i18n_key_functions.js +112 -23
- package/src/i18n_key_functions.test.js +329 -8
- package/src/nav_cards_helpers.js +21 -5
- package/src/nav_item_badge.wiring.test.js +564 -0
- package/src/shell_route_map.js +2 -2
- package/src/yui_badge.js +145 -0
- package/src/yui_badge.test.js +148 -0
- package/src/yui_gclass_view.js +1 -1
- package/src/yui_time.js +1 -1
package/README.md
CHANGED
|
@@ -3152,45 +3152,79 @@ at 38%, which is the whole graph and worth nothing.
|
|
|
3152
3152
|
> `ResizeObserver`, and its canvas keeps its birth size for the life of the
|
|
3153
3153
|
> window while everything resizes around it (fixed in 7.23.31).
|
|
3154
3154
|
|
|
3155
|
-
###
|
|
3155
|
+
### Badges — a count on a toolbar item or a menu entry
|
|
3156
3156
|
|
|
3157
3157
|
```js
|
|
3158
|
-
/* app_config.json —
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3158
|
+
/* app_config.json — a toolbar item and a menu entry; the fields seed the
|
|
3159
|
+
* FIRST paint only */
|
|
3160
|
+
"toolbar": {"items": [
|
|
3161
|
+
{ "id": "bell", "icon": "yi-triangle-exclamation", "align": "end",
|
|
3162
|
+
"aria_label": "alarms", "badge": 0,
|
|
3163
|
+
"action": {"type": "navigate", "route": "/alarms"} }
|
|
3164
|
+
]},
|
|
3165
|
+
"menu": {"primary": {"items": [
|
|
3166
|
+
{ "id": "alarms", "name": "alarms", "icon": "yi-triangle-exclamation", "route": "/alarms",
|
|
3167
|
+
"badge": 0, "badge_tone": "warning",
|
|
3168
|
+
"target": {"stage": "main", "gclass": "C_ALARMS"} }
|
|
3169
|
+
]}}
|
|
3162
3170
|
|
|
3163
3171
|
/* the interface that matters: a count is a RUNTIME fact */
|
|
3164
|
-
yui_shell_set_toolbar_item_badge(shell, "
|
|
3165
|
-
|
|
3172
|
+
yui_shell_set_toolbar_item_badge(shell, "bell", 3);
|
|
3173
|
+
yui_shell_set_nav_item_badge(shell, "alarms", 3);
|
|
3174
|
+
yui_shell_set_nav_item_badge(shell, "alarms", 3, "danger"); // with a tone
|
|
3175
|
+
yui_shell_set_nav_item_badge(shell, "alarms", 0); // clears it
|
|
3166
3176
|
```
|
|
3167
3177
|
|
|
3168
3178
|
An icon-only toolbar button is a link; the badge is what makes it a
|
|
3169
3179
|
**signal**. Without a number, an alarm bell cannot say whether anything needs
|
|
3170
|
-
you — which is the reason to look at it at all.
|
|
3180
|
+
you — which is the reason to look at it at all. The same goes for the menu
|
|
3181
|
+
entry that leads to the alarms.
|
|
3171
3182
|
|
|
3172
|
-
Rules baked in,
|
|
3173
|
-
badge):
|
|
3183
|
+
Rules baked in, the same for both (`src/yui_badge.js` draws and paints them),
|
|
3184
|
+
all for the same reason (a badge that lies costs more than no badge):
|
|
3174
3185
|
|
|
3175
3186
|
- **`0`, `""`, `null` and `false` all clear it.** A badge reading "0" is worse
|
|
3176
3187
|
than none: it draws the eye to say nothing.
|
|
3177
|
-
- **Over 99 renders `99+`.** The toolbar
|
|
3178
|
-
pill pushes its neighbours off a phone screen.
|
|
3188
|
+
- **Over 99 renders `99+`.** The toolbar and an icon bar are fixed-width rows
|
|
3189
|
+
and a four-digit pill pushes its neighbours off a phone screen.
|
|
3179
3190
|
- **A string passes through** for the states that are not counts (`"!"`, `"…"`).
|
|
3180
|
-
- **
|
|
3181
|
-
|
|
3191
|
+
- **A tone, optional:** `"danger"` (the default look), `"warning"`, `"info"`,
|
|
3192
|
+
`"success"`, `"primary"` or `"link"` — Bulma's `is-<tone>` on the badge, to
|
|
3193
|
+
say HOW BAD the count is (the alarms coloured by the worst state among
|
|
3194
|
+
them). A fill: the raw Bulma token under its `-invert` ink, the same pair in
|
|
3195
|
+
both themes. **An unknown tone is logged** (`log_error`) and drawn with the
|
|
3196
|
+
default look. Each call states the WHOLE badge: a call without a tone draws
|
|
3197
|
+
the default look, so a call with three arguments works as it always did.
|
|
3198
|
+
- **Unknown item id is a silent no-op**, so an app whose toolbar or menu has no
|
|
3199
|
+
such item does not log an error on every tick of whatever feeds the number.
|
|
3182
3200
|
- Writing the **same** value again touches no DOM: the badge is a
|
|
3183
3201
|
`role="status"` live region, and rewriting it would have a screen reader
|
|
3184
3202
|
announce the same number on every tick.
|
|
3185
3203
|
|
|
3186
|
-
`role="status"` and not `aria-hidden`, deliberately: the button
|
|
3187
|
-
explicit `aria-label`, and an explicit label **replaces** an
|
|
3188
|
-
for a screen reader — a badge inside it would otherwise be
|
|
3189
|
-
live region it is both read and announced when it changes.
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3204
|
+
`role="status"` and not `aria-hidden`, deliberately: the button or link
|
|
3205
|
+
carries an explicit `aria-label`, and an explicit label **replaces** an
|
|
3206
|
+
element's content for a screen reader — a badge inside it would otherwise be
|
|
3207
|
+
silent. As its own live region it is both read and announced when it changes.
|
|
3208
|
+
|
|
3209
|
+
**The menu entry's badge reaches every instance of the id.** A menu hosted by
|
|
3210
|
+
two zones (a rail on desktop, an icon bar on a phone) draws the same entry
|
|
3211
|
+
twice, and a drawer may repeat it: one `yui_shell_set_nav_item_badge()` call
|
|
3212
|
+
paints them all (it sends `EV_SET_ITEM_BADGE` to every `C_YUI_NAV` of the
|
|
3213
|
+
shell). And the value is KEPT — by each nav, in its `badges` attr, and by the
|
|
3214
|
+
shell, for the navs it creates later — so a rebuild draws it again: a
|
|
3215
|
+
`yui_shell_set_submenu()` with new item objects, a `submenu.index` landing
|
|
3216
|
+
mounted after the call. Once the call has spoken for an id, its value wins
|
|
3217
|
+
over the `badge` of any item with that id. It covers the entries of
|
|
3218
|
+
`app_config.json`'s menus and submenus and the items given to
|
|
3219
|
+
`yui_shell_set_submenu()`; the nodes of a `C_YUI_NODE` tree are not menu
|
|
3220
|
+
items, and carry none.
|
|
3221
|
+
|
|
3222
|
+
Where it sits: on the corner of the icon where the entry is an icon over its
|
|
3223
|
+
label (`icon-bar`, `cards`, a stacked item) or an icon alone; after the label
|
|
3224
|
+
elsewhere (`vertical`, `drawer`, `submenu`, `tabs`, an `accordion` head or
|
|
3225
|
+
leaf). A `breadcrumb` draws none, deliberately: a crumb names a step of the way
|
|
3226
|
+
in, and the count belongs to the entry that leads there. Logical class
|
|
3227
|
+
`NAV_ITEM_BADGE` (`TOOLBAR_ITEM_BADGE` in the toolbar), look `yui-badge`.
|
|
3194
3228
|
|
|
3195
3229
|
### Toasts — `yui_shell_show_info` / `_warning` / `_error`
|
|
3196
3230
|
|
|
@@ -3476,9 +3510,10 @@ text is in the yunetas `CLAUDE.md` ("JS GUI conventions"); in short:
|
|
|
3476
3510
|
1. Run the static check on the app's sources, from the published package
|
|
3477
3511
|
(7.26.11+ ships the script):
|
|
3478
3512
|
`node node_modules/@yuneta/gobj-ui/scripts/check-markup-strings.mjs src`
|
|
3479
|
-
— usually from the app's `prebuild`. It imports `acorn`,
|
|
3480
|
-
|
|
3481
|
-
|
|
3513
|
+
— usually from the app's `prebuild`. It imports `acorn`, a dependency
|
|
3514
|
+
of this package since `7.26.29`, so npm installs it with the package
|
|
3515
|
+
(up to `7.26.28` it was a devDependency here, and the APP had to
|
|
3516
|
+
declare it). It lists a markup string literal in a description
|
|
3482
3517
|
(`literal`, wrap it in `html_markup()`), markup built with values
|
|
3483
3518
|
(`built`: a template, `String.raw`, a `+` chain, `.concat()`, a
|
|
3484
3519
|
`[...].join()`, or a string method such as `.trim()` over one of those,
|
|
@@ -3667,9 +3702,9 @@ DOM is a race with the next one:
|
|
|
3667
3702
|
DEPLOYED DOM, resolve each control's name the way a reader does (`aria-label`
|
|
3668
3703
|
→ `label[for]` → a wrapping `<label>` → the text → `title` → `placeholder`),
|
|
3669
3704
|
then switch language and diff. A key that arrives as a VARIABLE — from a data
|
|
3670
|
-
table, a local alias of `t()`, a
|
|
3671
|
-
|
|
3672
|
-
|
|
3705
|
+
table, a local alias of `t()`, a wrapper of the app's own — is invisible to
|
|
3706
|
+
`validate-locales` unless its module publishes it (below), and shows up only
|
|
3707
|
+
there.
|
|
3673
3708
|
|
|
3674
3709
|
### i18n: a string must be able to CHANGE language, not just be translated once
|
|
3675
3710
|
|
|
@@ -3787,10 +3822,14 @@ declaration is a literal when it is the endonym of one of the app's locales
|
|
|
3787
3822
|
(the `name` its catalog exports: `"中文"`, `"español"`); any other lower-case
|
|
3788
3823
|
text is a key, `"configuración"` included.
|
|
3789
3824
|
|
|
3790
|
-
**The source is PARSED, never run** (since `7.26.28`, with `acorn`,
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3825
|
+
**The source is PARSED, never run** (since `7.26.28`, with `acorn`, a
|
|
3826
|
+
dependency of this package since `7.26.29`: an app need not declare it). A
|
|
3827
|
+
LOCALE is not a source: it is parsed, and then imported, so its top-level code
|
|
3828
|
+
runs -- the app's own code, but code. Comments are not code. A key is read
|
|
3829
|
+
where it is WRITTEN -- given to `t()`, as an `i18n` or `data-i18n*` value of
|
|
3830
|
+
an object literal, by `setAttribute()`, or (since `7.26.29`) written as a
|
|
3831
|
+
member, `attrs.i18n = "save"`, `attrs["data-i18n-title"] = "save"` -- and
|
|
3832
|
+
FOLLOWED where the source writes it out:
|
|
3794
3833
|
|
|
3795
3834
|
- a string literal, a template with no `${}`, and every branch of `?:`, `||`
|
|
3796
3835
|
and `??` (the right one of `&&`), so
|
|
@@ -3801,7 +3840,14 @@ it out:
|
|
|
3801
3840
|
- a property of a const object literal: `DEFAULT_LABEL.ok`, and for a
|
|
3802
3841
|
computed one, `NOTES[verdict]`, every value the object holds;
|
|
3803
3842
|
- the element of a const array literal that a `.map()`, `.forEach()`, ...
|
|
3804
|
-
callback or a `for...of` walks
|
|
3843
|
+
callback or a `for...of` walks, and what a destructuring reads from it
|
|
3844
|
+
(`for(const {key} of ROWS)`);
|
|
3845
|
+
- `String(x)`, and a template that is only `${x}`, as `x` (since `7.26.29`);
|
|
3846
|
+
- the default of a parameter, `function f(msg = "fallback")`, besides the
|
|
3847
|
+
parameter (since `7.26.29`);
|
|
3848
|
+
- a call of a function of the same module whose every `return` is one of
|
|
3849
|
+
these (since `7.26.29`). One that returns anything else -- a parameter, a
|
|
3850
|
+
variable, a concatenation -- is not followed.
|
|
3805
3851
|
|
|
3806
3852
|
```js
|
|
3807
3853
|
const KEY = "save";
|
|
@@ -3812,6 +3858,10 @@ for(const zone of ZONES) {
|
|
|
3812
3858
|
build_zone(gobj, zone); // ZONES[].key, at build_zone's key position
|
|
3813
3859
|
}
|
|
3814
3860
|
SHAPES.map((s) => ({value: s, i18n: s})); // every element of SHAPES
|
|
3861
|
+
function pick(ok) {
|
|
3862
|
+
return ok? "accepted" : "refused";
|
|
3863
|
+
}
|
|
3864
|
+
t(pick(answer)); // asks for both
|
|
3815
3865
|
```
|
|
3816
3866
|
|
|
3817
3867
|
What it cannot follow cannot be known: a `let`, a parameter, an import, a
|
|
@@ -3844,16 +3894,56 @@ given at those positions is read like any other key (literals, consts,
|
|
|
3844
3894
|
branches): in the app's own code, on a call bound to an import of that
|
|
3845
3895
|
function from gobj-ui (an app function of the same name is not mistaken for
|
|
3846
3896
|
it), and in every module the app mounts, where an entry with
|
|
3847
|
-
`exported: false` is a helper of its own module.
|
|
3848
|
-
|
|
3897
|
+
`exported: false` is a helper of its own module. A position may also hold
|
|
3898
|
+
DOM, which is no key (since `7.26.29`): an array (a `createElement2` spec), a
|
|
3899
|
+
call of `createElement2()`, `createOneHtml()` or `html_markup()` imported
|
|
3900
|
+
from gobj-js, of `text_node()` from gobj-ui, of `document.createElement()`
|
|
3901
|
+
and the like, a `const` bound to one, or a plain `let` that is only ever
|
|
3902
|
+
given one. DOM is known by where it comes from, never by the name of a
|
|
3903
|
+
variable: `$box` says nothing. The exported ones an app calls:
|
|
3904
|
+
`yui_shell_show_info` / `_warning` / `_error` (the message),
|
|
3849
3905
|
`yui_shell_show_modal` (a string content, `title`),
|
|
3850
3906
|
`yui_shell_confirm_ok` / `_yesno` / `_danger` / `_yesnocancel` (the message,
|
|
3851
3907
|
`title`, the `*_label`s), `yui_install_ask_once` (`message`, `yes_label`,
|
|
3852
3908
|
`no_label`), `yui_selection_bar` (each action's `label`), `yui_asset_missing`
|
|
3853
|
-
/ `yui_asset_element` (`key`), `hook_cell_spec` (the title key)
|
|
3854
|
-
`period_name` (a granularity id)
|
|
3855
|
-
|
|
3856
|
-
|
|
3909
|
+
/ `yui_asset_element` (`key`), `hook_cell_spec` (the title key),
|
|
3910
|
+
`period_name` (a granularity id), `card_descriptor` / `cards_grid_descriptor`
|
|
3911
|
+
(a nav item's `name`, `tooltip`, `aria_label`) and `open_gclass_view` (the
|
|
3912
|
+
gclass name, which titles it).
|
|
3913
|
+
|
|
3914
|
+
**Every function that forwards a key is in the table, and a test finds them**
|
|
3915
|
+
(since `7.26.29`: up to `7.26.28` the table lacked 39 of them, and 6 entries
|
|
3916
|
+
lacked positions, so a literal handed to one went unasked -- REV-CLOUD
|
|
3917
|
+
V21.4.1). `src/i18n_key_functions.test.js` reads every module and finds each
|
|
3918
|
+
function that hands one of its PARAMETERS on to a place a key is read --
|
|
3919
|
+
`t()`, an `i18n`, `code` or `data-i18n*` value, a key position of a function
|
|
3920
|
+
of the table -- the parameter itself or what is read from it (`opts.title`, a
|
|
3921
|
+
destructured `{label}`, each `items[].name`), directly or through a `let` it is
|
|
3922
|
+
given to. The search runs to a fixpoint: a function that hands its parameter
|
|
3923
|
+
to one it found is one too.
|
|
3924
|
+
|
|
3925
|
+
- A function called by NAME -- in its module, or exported -- must be in the
|
|
3926
|
+
table with that position, or the test fails, naming the entry to add:
|
|
3927
|
+
|
|
3928
|
+
```
|
|
3929
|
+
c_yui_nav.js:684 item_li() hands [1.name, 1.tooltip, 1.aria_label] to a place a key is read:
|
|
3930
|
+
name it in I18N_KEY_FUNCTIONS -- {module: "c_yui_nav.js", name: "item_li", exported: false, ...}
|
|
3931
|
+
```
|
|
3932
|
+
|
|
3933
|
+
- One that nothing calls by name -- an FSM action (the framework calls it
|
|
3934
|
+
with an event's kw), a callback, a method -- has no call a reader can
|
|
3935
|
+
read, so listing it would read nothing: what it hands on is MARKED where it
|
|
3936
|
+
hands it, or the test fails. `C_YUI_WINDOW_MANAGER`'s `ac_register_window`
|
|
3937
|
+
writes `i18n: /* i18n: data */ title_key`: the window's title is a key its
|
|
3938
|
+
host chose.
|
|
3939
|
+
- What a gobj keeps in its `priv` is its own state, not what a caller hands:
|
|
3940
|
+
a path through the `priv` of a parameter is no position.
|
|
3941
|
+
|
|
3942
|
+
Naming a function moves the marker to where the value ENTERS: its callers give
|
|
3943
|
+
it a literal, a const, a position of their own, or a marker. The nav's items
|
|
3944
|
+
and the shell's toolbar are marked once, where the library reads its config --
|
|
3945
|
+
`render_vertical(gobj, /* i18n: data */ items)`, the app's nav declaration,
|
|
3946
|
+
whose keys `validate-locales` reads in its `app_config.json`.
|
|
3857
3947
|
|
|
3858
3948
|
**A key the reader cannot follow is PUBLISHED by its module** (since
|
|
3859
3949
|
`7.26.27`): an exported `<NAME>_I18N_KEYS` array of string literals, which
|
|
@@ -3885,15 +3975,26 @@ export const MY_VIEW_I18N_KEYS = ['shape', 'radius', 'apply to'];
|
|
|
3885
3975
|
|
|
3886
3976
|
The list is read as DATA, never run: `export const` (or `let`, `var`),
|
|
3887
3977
|
`const X = [...]; export {X}` (or `export {x as X_I18N_KEYS}`), wrapped in
|
|
3888
|
-
`Object.freeze()` or not, each element a string literal
|
|
3889
|
-
`${}
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3978
|
+
`Object.freeze()` or not, each element a string literal, a template with no
|
|
3979
|
+
`${}`, or (since `7.26.29`) a SPREAD of another array of the same module read
|
|
3980
|
+
the same way -- a top-level `const`, or a list the module publishes:
|
|
3981
|
+
|
|
3982
|
+
```js
|
|
3983
|
+
const COMMON_KEYS = ['shape', 'radius'];
|
|
3984
|
+
export const MY_VIEW_I18N_KEYS = [...COMMON_KEYS, 'apply to'];
|
|
3985
|
+
export const MY_EDITOR_I18N_KEYS = [...MY_VIEW_I18N_KEYS, 'discard'];
|
|
3986
|
+
```
|
|
3987
|
+
|
|
3988
|
+
Anything named `*_I18N_KEYS` (the name in any letter case) that no consumer
|
|
3989
|
+
can read **fails the build**, naming the file and the list, in the app's own
|
|
3990
|
+
code too: an export that is not such an array (an element that is a variable,
|
|
3991
|
+
a call, a template with `${}`, a spread of an import or of a `let`), a list
|
|
3992
|
+
that is not exported, one declared inside a function or a block, one declared
|
|
3993
|
+
by destructuring (`export const {X_I18N_KEYS} = tables`), one exported under a
|
|
3994
|
+
name that does not end in `_I18N_KEYS`. Up to `7.26.27` the regex that read
|
|
3995
|
+
the lists dropped such a list in silence, and a key holding `]` dropped the
|
|
3996
|
+
whole array; up to `7.26.28` a spread of a const of the module was refused
|
|
3997
|
+
too.
|
|
3897
3998
|
|
|
3898
3999
|
**A MARKER says where the keys of a place come from.** It is a comment that
|
|
3899
4000
|
stands right before the node it marks (only whitespace between): an argument,
|
|
@@ -3913,6 +4014,25 @@ confirm_then(gobj, /* i18n: C_YUI_FORM_I18N_KEYS */ kw.warning || "all changes w
|
|
|
3913
4014
|
published lists. The keys of the marked expression that the reader CAN
|
|
3914
4015
|
follow must be in them: a marker is a claim, and it is checked.
|
|
3915
4016
|
|
|
4017
|
+
**A `data` marker is a claim too** (since `7.26.29`). On what the reader
|
|
4018
|
+
follows to keys and nothing else -- a literal, a template with no `${}`, a
|
|
4019
|
+
`const` bound to one, a `?:` / `||` / `??` branch that is one, a call of a
|
|
4020
|
+
function of the module whose returns are literals -- it claims data where the
|
|
4021
|
+
reader reads a key, and it fails. Up to `7.26.28` that is how the key behind
|
|
4022
|
+
a call went unread: the reader stopped at the call, and the marker excused it.
|
|
4023
|
+
|
|
4024
|
+
```js
|
|
4025
|
+
function pick() {
|
|
4026
|
+
return "accepted";
|
|
4027
|
+
}
|
|
4028
|
+
yui_shell_show_info(shell, /* i18n: data */ pick());
|
|
4029
|
+
// main.js:4: marked as data, but what it marks is the key "accepted", which the
|
|
4030
|
+
// reader follows: drop the marker (it is no data)
|
|
4031
|
+
```
|
|
4032
|
+
|
|
4033
|
+
`/* i18n: data */ comment || "print-tranger failed"` stays legal: `comment` is
|
|
4034
|
+
data, and the fallback is read anyway.
|
|
4035
|
+
|
|
3916
4036
|
**A marked `let` (or `var`) is held to its marker.** A marker that names a list
|
|
3917
4037
|
used to let a `let` pass unread, whatever it held: a new literal branch on it
|
|
3918
4038
|
was neither asked for nor checked (REV-CLOUD V20). Now, when what a marker
|
|
@@ -3978,20 +4098,55 @@ before no place a key is read (a key position, `t()`, an `i18n` or
|
|
|
3978
4098
|
publishes, a marked key that is not in the lists it names, a marked variable
|
|
3979
4099
|
that only ever holds literals -- each one fails, with the file and the line.
|
|
3980
4100
|
|
|
3981
|
-
**The
|
|
3982
|
-
reads every module
|
|
3983
|
-
|
|
4101
|
+
**The rule is per CALL, in the library and in the app.**
|
|
4102
|
+
`src/i18n_key_functions.test.js` reads every module of the library with the
|
|
4103
|
+
validator's own reader, and `validate-locales` reads the app's own code the
|
|
4104
|
+
same way (since `7.26.29`; up to `7.26.28` only the library was held to it, and
|
|
4105
|
+
a `let`, a wrapper or a concatenation in an app passed unread). Every value a
|
|
4106
|
+
key position of a key function can take must be:
|
|
3984
4107
|
|
|
3985
|
-
1. a string literal, a `?:` / `||` / `??` of them, or
|
|
3986
|
-
2. a const the reader follows to one of those
|
|
4108
|
+
1. a string literal, a `?:` / `||` / `??` of them, nothing, or DOM;
|
|
4109
|
+
2. a const the reader follows to one of those, or a plain `let` that is only
|
|
4110
|
+
ever given DOM;
|
|
3987
4111
|
3. a key position of the enclosing table function, handed on (`message`
|
|
3988
|
-
where `message` is a key parameter of the function the call is in)
|
|
4112
|
+
where `message` is a key parameter of the function the call is in) -- in
|
|
4113
|
+
the library only: a function of an app is in no table; or
|
|
3989
4114
|
4. MARKED, `/* i18n: data */` or `/* i18n: <NAME>_I18N_KEYS */`.
|
|
3990
4115
|
|
|
3991
4116
|
Anything else fails, naming the file, the line and the call:
|
|
3992
4117
|
|
|
3993
4118
|
```
|
|
3994
4119
|
c_yui_treedb_topics.js:860 (call at 859) card_action_anchor() [2]: table_key
|
|
4120
|
+
src/main.js:12: yui_shell_confirm_yesno() [2.title] is given opts, which the reader cannot follow:
|
|
4121
|
+
hand it a literal or a const, or mark it /* i18n: data */ or /* i18n: <NAME>_I18N_KEYS */
|
|
4122
|
+
```
|
|
4123
|
+
|
|
4124
|
+
A TRANSLATED text handed to a key position fails even when it is marked: the
|
|
4125
|
+
function translates it again and marks it `data-i18n` with the translation,
|
|
4126
|
+
so it never changes language. Hand it the key:
|
|
4127
|
+
|
|
4128
|
+
```js
|
|
4129
|
+
yui_install_ask_once(shell, {t: t, message: t("install this app")}); // fails
|
|
4130
|
+
yui_install_ask_once(shell, {t: t, message: "install this app"}); // the key
|
|
4131
|
+
```
|
|
4132
|
+
|
|
4133
|
+
```
|
|
4134
|
+
src/c_app.js:734 (call at line 732): yui_install_ask_once() [1.message] is given t("install this app"):
|
|
4135
|
+
a TRANSLATED text where a KEY goes (translated again and marked data-i18n with the translation,
|
|
4136
|
+
it never changes language): hand it the key
|
|
4137
|
+
```
|
|
4138
|
+
|
|
4139
|
+
In an app, what a wrapper of its own hands on is marked where it hands it:
|
|
4140
|
+
`/* i18n: data */` when it is data (a backend's comment, a key built from a
|
|
4141
|
+
name, the DOM its callers built). When its callers give it the module's own
|
|
4142
|
+
literal keys, the module PUBLISHES them and the marker names the list --
|
|
4143
|
+
wattyzer's `open_route_modal()` hands on the titles of `C_WZ_APP_I18N_KEYS`:
|
|
4144
|
+
|
|
4145
|
+
```js
|
|
4146
|
+
export const C_WZ_APP_I18N_KEYS = ["backend connection", "about wattyzer", "preferences"];
|
|
4147
|
+
...
|
|
4148
|
+
let handle = yui_shell_show_modal(priv.shell, /* i18n: data */ $content,
|
|
4149
|
+
/* i18n: C_WZ_APP_I18N_KEYS */ modal_opts);
|
|
3995
4150
|
```
|
|
3996
4151
|
|
|
3997
4152
|
Publishing a list does not exempt a module: the rule is per call, not per
|
|
@@ -4048,13 +4203,17 @@ it asks for or carries with the list.
|
|
|
4048
4203
|
|
|
4049
4204
|
**What is NOT pinned.** `t()` is not a key function, and only the positions of
|
|
4050
4205
|
`I18N_KEY_FUNCTIONS` are held to the per-call rule. So a key handed to `t()`,
|
|
4051
|
-
`i18n` or a `data-i18n*` value by an UNMARKED `let`, a
|
|
4052
|
-
concatenation is invisible to the validator and fails no test --
|
|
4053
|
-
library and in an app alike.
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4206
|
+
`i18n` or a `data-i18n*` value by an UNMARKED `let`, a call the reader does not
|
|
4207
|
+
follow or a concatenation is invisible to the validator and fails no test --
|
|
4208
|
+
in the library and in an app alike. (A PARAMETER is not, in the library: the
|
|
4209
|
+
forwarder test puts its function in the table, or demands a marker.) So is
|
|
4210
|
+
what is written INTO a `const` table after its declaration (`LIST.push("k")`,
|
|
4211
|
+
`TABLE.k = "k"`): the reader follows a const to its value, and only a marked
|
|
4212
|
+
`let` is followed into what is written into it. It is found only by reading
|
|
4213
|
+
the page in another language. In an app, a key its callers hand a wrapper of
|
|
4214
|
+
its own reaches the locales only through a list the module publishes: the
|
|
4215
|
+
wrapper's hand-off must be marked (the rule per call), and nothing ties its
|
|
4216
|
+
callers' literals to the list.
|
|
4058
4217
|
|
|
4059
4218
|
**What fails the build, besides a key no locale defines:**
|
|
4060
4219
|
|
|
@@ -4066,7 +4225,11 @@ function the table does not name.
|
|
|
4066
4225
|
`translation` dict;
|
|
4067
4226
|
- a source file that cannot be parsed;
|
|
4068
4227
|
- a published list no consumer can read (above);
|
|
4069
|
-
- a marker that is wrong (above)
|
|
4228
|
+
- a marker that is wrong (above), a `data` marker on what the reader follows
|
|
4229
|
+
to keys included;
|
|
4230
|
+
- a key position of a key function, in the app's own code, given what the
|
|
4231
|
+
reader cannot follow and unmarked, or given a translated text (the rule per
|
|
4232
|
+
call, above).
|
|
4070
4233
|
|
|
4071
4234
|
Up to `7.26.27` the locale cases were "skipped" with an OK: one language less
|
|
4072
4235
|
validated, and nobody told. A file of the locales directory with a locale's
|