@yuneta/gobj-ui 7.26.31 → 7.26.32
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 +237 -72
- package/dist/gobj-ui.cjs.js +22 -16
- package/dist/gobj-ui.es.js +22 -16
- package/package.json +1 -1
- package/scripts/validate-locales.mjs +1755 -328
- package/src/c_g6_nodes_tree.js +6 -4
- package/src/c_yui_form.js +5 -4
- package/src/c_yui_treedb_graph.js +6 -3
- package/src/c_yui_treedb_topics.js +6 -3
- package/src/i18n_key_functions.js +54 -31
- package/src/i18n_key_functions.test.js +461 -49
- package/src/yui_table_select.js +20 -13
package/README.md
CHANGED
|
@@ -95,8 +95,8 @@ consumers. They are independent snapshots (no shared git ancestry):
|
|
|
95
95
|
|
|
96
96
|
| Line | Branch | Latest tag | Layout | Consumed by | How | Status |
|
|
97
97
|
|------|--------|------------|--------|-------------|-----|--------|
|
|
98
|
-
| **v2** | `main` | `7.26.x` | `src/` subdir | **gui_agent**, **gui_treedb**, **wattyzer**, the **yunovatios** GUIs | published npm `@yuneta/gobj-ui` (dist-tag `latest`) | active development |
|
|
99
|
-
| **v1** | `v1` | `1.0.4` | `src/` subdir | **
|
|
98
|
+
| **v2** | `main` | `7.26.x` | `src/` subdir | **gui_agent**, **gui_treedb**, **wattyzer**, the **yunovatios** GUIs, **estadodelaire** (since 2026-10-13) | published npm `@yuneta/gobj-ui` (dist-tag `latest`) | active development |
|
|
99
|
+
| **v1** | `v1` | `1.0.4` | `src/` subdir | **hidraulia** | published npm `@yuneta/gobj-ui@^1.0.4` (dist-tag `legacy`) | frozen, maintenance-only |
|
|
100
100
|
|
|
101
101
|
- **v2 / `main`** is the active development line: the declarative shell
|
|
102
102
|
(legacy-stack-free since `3.0.0`). It is embedded as a git submodule in
|
|
@@ -109,9 +109,10 @@ consumers. They are independent snapshots (no shared git ancestry):
|
|
|
109
109
|
(`npm run deploy-round` does the round). `test-app/` is the one exception:
|
|
110
110
|
it consumes the working tree (`file:..`), which is what it is for.
|
|
111
111
|
- **v1 / `v1`** is the frozen legacy-only stack (the declarative shell is not on
|
|
112
|
-
this line). It is **published to npm**;
|
|
113
|
-
`@yuneta/gobj-ui@^1.0.4` from the registry
|
|
114
|
-
|
|
112
|
+
this line). It is **published to npm**; hidraulia depends on
|
|
113
|
+
`@yuneta/gobj-ui@^1.0.4` from the registry (estadodelaire left it for v2 on
|
|
114
|
+
2026-10-13, and hidraulia is next). Land only maintenance fixes here, then
|
|
115
|
+
`npm publish` a new `1.x`.
|
|
115
116
|
|
|
116
117
|
All new feature work lands on `main`/v2.
|
|
117
118
|
|
|
@@ -3835,28 +3836,57 @@ text is a key, `"configuración"` included.
|
|
|
3835
3836
|
dependency of this package since `7.26.29`: an app need not declare it). A
|
|
3836
3837
|
LOCALE is not a source: it is parsed, and then imported, so its top-level code
|
|
3837
3838
|
runs -- the app's own code, but code. Comments are not code. A key is read
|
|
3838
|
-
where it is WRITTEN -- given to
|
|
3839
|
-
an object literal, by `setAttribute()`, or (since `7.26.29`) written
|
|
3840
|
-
member, `attrs.i18n = "save"`, `attrs["data-i18n-title"] = "save"` -- and
|
|
3841
|
-
FOLLOWED where the source writes it out
|
|
3839
|
+
where it is WRITTEN -- given to a translator, as an `i18n` or `data-i18n*`
|
|
3840
|
+
value of an object literal, by `setAttribute()`, or (since `7.26.29`) written
|
|
3841
|
+
as a member, `attrs.i18n = "save"`, `attrs["data-i18n-title"] = "save"` -- and
|
|
3842
|
+
FOLLOWED where the source writes it out.
|
|
3843
|
+
|
|
3844
|
+
A **translator** is one notion, the same everywhere the reader asks "is this a
|
|
3845
|
+
call of t()?" (since `7.26.32`; up to `7.26.31` it was a call NAMED `t` or
|
|
3846
|
+
`tr`): a name `t` or `tr` (whatever binds it), a member `.t` / `.tr`
|
|
3847
|
+
(`i18next.t`), i18next's `t` imported under any name (`import {t as tt} from
|
|
3848
|
+
"i18next"`), or an alias of one -- a const (`const translate = t`), a
|
|
3849
|
+
`.bind()` (`i18next.t.bind(i18next)`), a re-export of a module the reader
|
|
3850
|
+
reads --, called as `t(k)`, `t?.(k)`, `t.call(x, k)` or `t.apply(x, [k])`. An
|
|
3851
|
+
ARRAY given to it is i18next's list of fallback keys, and each one is a key:
|
|
3852
|
+
`t([specific, "generic"])` asks for "generic". The places, since `7.26.32`, also
|
|
3853
|
+
include `el.dataset.i18nTitle = k` (`dataset.i18nX` IS the attribute
|
|
3854
|
+
`data-i18n-x`), and an attribute or property NAMED by a const:
|
|
3855
|
+
`el.setAttribute(ATTR, k)`, `{[ATTR]: k}`, `x[ATTR] = k`, with `const ATTR =
|
|
3856
|
+
"data-i18n-title"`. What is followed:
|
|
3842
3857
|
|
|
3843
3858
|
- a string literal, a template with no `${}`, and every branch of `?:`, `||`
|
|
3844
3859
|
and `??` (the right one of `&&`), so
|
|
3845
3860
|
`"data-i18n": pending ? "loading" : "click to load"` asks for both, and
|
|
3846
3861
|
`comment || "print-tranger failed"` for its fallback;
|
|
3847
3862
|
- a `const`, to its value, in the scope that declares it (a parameter or a
|
|
3848
|
-
`let` of the same name hides it)
|
|
3863
|
+
`let` of the same name hides it), and what a destructuring reads from it
|
|
3864
|
+
(since `7.26.32`: `const {title = "untitled"} = LABELS`);
|
|
3865
|
+
- an IMPORT of a const or of a function, into the module it names, when the
|
|
3866
|
+
reader reads that module -- a file of the app, a module of this library;
|
|
3867
|
+
re-exports are followed (since `7.26.32`). A package (gobj-js, i18next) is
|
|
3868
|
+
not read, and neither is the export of a `let`;
|
|
3849
3869
|
- a property of a const object literal: `DEFAULT_LABEL.ok`, and for a
|
|
3850
|
-
computed one, `NOTES[verdict]`, every value the object holds;
|
|
3870
|
+
computed one, `NOTES[verdict]`, every value the object holds; also of a
|
|
3871
|
+
COPY of one (since `7.26.32`): `{...BASE, title: "t"}`,
|
|
3872
|
+
`Object.assign({}, BASE)`;
|
|
3851
3873
|
- the element of a const array literal that a `.map()`, `.forEach()`, ...
|
|
3852
3874
|
callback or a `for...of` walks, and what a destructuring reads from it
|
|
3853
3875
|
(`for(const {key} of ROWS)`);
|
|
3854
3876
|
- `String(x)`, and a template that is only `${x}`, as `x` (since `7.26.29`);
|
|
3855
|
-
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3877
|
+
- a parameter, however it is read (since `7.26.32`): `opts.title`,
|
|
3878
|
+
`opts?.title`, `arguments[1]`, `rest[0]` of a rest parameter, a destructuring
|
|
3879
|
+
in the parameter or in the body; and its default, `function f(msg =
|
|
3880
|
+
"fallback")`, besides the parameter (since `7.26.29`);
|
|
3881
|
+
- a call of a function whose every `return` is one of these (since
|
|
3882
|
+
`7.26.29`): of the same module, or (since `7.26.32`) imported from a module
|
|
3883
|
+
the reader reads, called by `.call()` / `.apply()` too. One that returns
|
|
3884
|
+
anything else -- a parameter, a variable, a concatenation -- is not
|
|
3885
|
+
followed. What a function returns is read ONCE, and a RECURSION is not
|
|
3886
|
+
followed: a call of a function that is being read is a value the reader
|
|
3887
|
+
cannot follow. Up to `7.26.31` a function was read again at every call of
|
|
3888
|
+
it, so a helper that calls itself in two branches (`label_of(n)` walking
|
|
3889
|
+
up a tree) took more than two minutes, and in three it never ended.
|
|
3860
3890
|
|
|
3861
3891
|
```js
|
|
3862
3892
|
const KEY = "save";
|
|
@@ -3873,12 +3903,12 @@ function pick(ok) {
|
|
|
3873
3903
|
t(pick(answer)); // asks for both
|
|
3874
3904
|
```
|
|
3875
3905
|
|
|
3876
|
-
What it cannot follow cannot be known: a `let`, a parameter
|
|
3877
|
-
call, a concatenation, data from a backend. A key
|
|
3878
|
-
PUBLISHED by its module (below), and the place it is
|
|
3879
|
-
`let` -- or a marked member or element of one -- is the
|
|
3880
|
-
followed" (below). A source file that cannot be parsed
|
|
3881
|
-
its keys would go unchecked.
|
|
3906
|
+
What it cannot follow cannot be known: a `let`, a parameter of an app's
|
|
3907
|
+
function, a call it does not read, a concatenation, data from a backend. A key
|
|
3908
|
+
that arrives that way is PUBLISHED by its module (below), and the place it is
|
|
3909
|
+
read is MARKED; a marked `let` -- or a marked member or element of one -- is the
|
|
3910
|
+
one exception to "not followed" (below). A source file that cannot be parsed
|
|
3911
|
+
fails the build, because its keys would go unchecked.
|
|
3882
3912
|
|
|
3883
3913
|
**A key handed to a FUNCTION is read where it is handed.**
|
|
3884
3914
|
`yui_shell_show_error(shell, "some records were gone before the delete")` asks
|
|
@@ -3900,10 +3930,16 @@ A position is an argument (`"1"`), a property of the object given there
|
|
|
3900
3930
|
(`"2.title"`, also through `Object.assign()` or a spread of a const object),
|
|
3901
3931
|
or a property of each object of an array (`"1.actions[].label"`). What is
|
|
3902
3932
|
given at those positions is read like any other key (literals, consts,
|
|
3903
|
-
branches): in the app's own code, on a call
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3933
|
+
branches): in the app's own code, on a call that reaches that function of
|
|
3934
|
+
gobj-ui (an app function of the same name is not mistaken for it), and in
|
|
3935
|
+
every module the app mounts, where an entry with `exported: false` is a
|
|
3936
|
+
helper of its own module. A call reaches it however it names it (since
|
|
3937
|
+
`7.26.32`; up to `7.26.31` only an import by its own name, or a namespace
|
|
3938
|
+
member): an import under any name, a re-export from a file of the app
|
|
3939
|
+
(`export {yui_shell_show_info as say} from "@yuneta/gobj-ui/src/shell_modals.js"`),
|
|
3940
|
+
a const alias (`const show = yui_shell_show_info`), a map in a const
|
|
3941
|
+
(`const API = {info: yui_shell_show_info}; API.info(...)`, imported too),
|
|
3942
|
+
`.call(x, ...)` and `.apply(x, [...])`. A position may also hold
|
|
3907
3943
|
DOM, which is no key (since `7.26.29`): an array (a `createElement2` spec), a
|
|
3908
3944
|
call of `createElement2()`, `createOneHtml()` or `html_markup()` imported
|
|
3909
3945
|
from gobj-js, of `text_node()` from gobj-ui, of `document.createElement()`
|
|
@@ -3924,12 +3960,14 @@ gclass name, which titles it).
|
|
|
3924
3960
|
(since `7.26.29`: up to `7.26.28` the table lacked 39 of them, and 6 entries
|
|
3925
3961
|
lacked positions, so a literal handed to one went unasked -- REV-CLOUD
|
|
3926
3962
|
V21.4.1). `src/i18n_key_functions.test.js` reads every module and finds each
|
|
3927
|
-
function that hands one of its PARAMETERS on to a place a key is read --
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3963
|
+
function that hands one of its PARAMETERS on to a place a key is read -- a
|
|
3964
|
+
translator (any of the forms above), an `i18n`, `code` or `data-i18n*` value
|
|
3965
|
+
(`el.dataset.i18nTitle` included), a key position of a function of the table
|
|
3966
|
+
-- the parameter itself or what is read from it: `opts.title`, `opts?.title`,
|
|
3967
|
+
a destructured `{label}` in the parameter or in the body, each `items[].name`,
|
|
3968
|
+
`arguments[1]`, `rest[0]`, a copy (`{...opts}`, `Object.assign({}, opts)`),
|
|
3969
|
+
directly or through a `let` it is given to. The search runs to a fixpoint: a
|
|
3970
|
+
function that hands its parameter to one it found is one too.
|
|
3933
3971
|
|
|
3934
3972
|
- A function called by NAME -- in its module, or exported -- must be in the
|
|
3935
3973
|
table with that position, or the test fails, naming the entry to add:
|
|
@@ -3946,7 +3984,47 @@ to one it found is one too.
|
|
|
3946
3984
|
writes `i18n: /* i18n: data */ title_key`: the window's title is a key its
|
|
3947
3985
|
host chose.
|
|
3948
3986
|
- What a gobj keeps in its `priv` is its own state, not what a caller hands:
|
|
3949
|
-
a path through the `priv` of a parameter is no position.
|
|
3987
|
+
a path through the `priv` of a parameter is no position. So is what is
|
|
3988
|
+
read from a parameter `gobj` (the convention of every gclass function):
|
|
3989
|
+
its attrs, `gobj_read_attr(gobj, "title")`, were set by whoever created it.
|
|
3990
|
+
- A parameter handed on through what NO position can name fails too (since
|
|
3991
|
+
`7.26.32`), unless it is marked where it is handed: a key transformed
|
|
3992
|
+
(`t(k.toLowerCase())`, `"prefix " + k`, a template with `${}`, a call of a
|
|
3993
|
+
helper that does not return it as it is), an iteration of
|
|
3994
|
+
`Object.entries(opts)`, a rest parameter walked (`rest.forEach(...)`),
|
|
3995
|
+
`arguments[i]` by a computed index, a part of a parameter that an array
|
|
3996
|
+
pattern destructures. Its callers' keys reach no reader, so either the key
|
|
3997
|
+
is handed on as it arrives -- and the function goes in the table -- or the
|
|
3998
|
+
hand-off is marked `/* i18n: data */` (or a list). The test names the
|
|
3999
|
+
function, the parameter and the line:
|
|
4000
|
+
|
|
4001
|
+
```js
|
|
4002
|
+
function caption(gobj, k) { return t(k.toLowerCase()); }
|
|
4003
|
+
```
|
|
4004
|
+
|
|
4005
|
+
```
|
|
4006
|
+
x.js:1 caption() hands its parameter [1] to a place a key is read through `k.toLowerCase()`,
|
|
4007
|
+
which no position can name: hand the key on as it arrives (the function then goes in
|
|
4008
|
+
the table), or mark it where it hands it
|
|
4009
|
+
```
|
|
4010
|
+
|
|
4011
|
+
It found four in the library itself: the column labels of a form's
|
|
4012
|
+
template in `build_html_form()` and `template2columns()`
|
|
4013
|
+
(`Object.entries(template)`: the host's schema, marked data), a label's key
|
|
4014
|
+
read back from its DOM (`name_form_control()` of `c_g6_nodes_tree.js`,
|
|
4015
|
+
marked data), and the message of `mark_field_validity()`, which mixes a key
|
|
4016
|
+
with the json field's own error (marked with its lists).
|
|
4017
|
+
- **The table is CORRECT, not only complete** (since `7.26.32`): the same
|
|
4018
|
+
search, started from NO table, must find every entry, at every position,
|
|
4019
|
+
with the same `exported`. An entry nothing forwards to -- a wrong position,
|
|
4020
|
+
a function that no longer hands it on -- fails, and so does an `exported`
|
|
4021
|
+
that disagrees with the module (it hides the calls of other modules). Up to
|
|
4022
|
+
`7.26.31` an extra entry passed every test. The check found two: an
|
|
4023
|
+
`exported: false` on a function its module exports (`create_floating_icon`),
|
|
4024
|
+
and `yui_selection_bar`'s `1.actions[].label`, true but invisible to the
|
|
4025
|
+
search, because the label travelled through a DOM property
|
|
4026
|
+
(`$b._yui_label`); the function now paints each label from the actions
|
|
4027
|
+
themselves, where the reader follows it.
|
|
3950
4028
|
|
|
3951
4029
|
Naming a function moves the marker to where the value ENTERS: its callers give
|
|
3952
4030
|
it a literal, a const, a position of their own, or a marker. The nav's items
|
|
@@ -3982,11 +4060,11 @@ that way. The same code with a `let` asks for neither.
|
|
|
3982
4060
|
export const MY_VIEW_I18N_KEYS = ['shape', 'radius', 'apply to'];
|
|
3983
4061
|
```
|
|
3984
4062
|
|
|
3985
|
-
The list is read as DATA, never run: `export const
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
4063
|
+
The list is read as DATA, never run: `export const`, or `const X = [...];
|
|
4064
|
+
export {X}` (or `export {x as X_I18N_KEYS}`), wrapped in `Object.freeze()` or
|
|
4065
|
+
not, each element a string literal, a template with no `${}`, or (since
|
|
4066
|
+
`7.26.29`) a SPREAD of another array of the same module read the same way -- a
|
|
4067
|
+
top-level `const`, which a list the module publishes is:
|
|
3990
4068
|
|
|
3991
4069
|
```js
|
|
3992
4070
|
const COMMON_KEYS = ['shape', 'radius'];
|
|
@@ -3998,16 +4076,31 @@ Anything named `*_I18N_KEYS` (the name in any letter case) that no consumer
|
|
|
3998
4076
|
can read **fails the build**, naming the file and the list, in the app's own
|
|
3999
4077
|
code too: an export that is not such an array (an element that is a variable,
|
|
4000
4078
|
a call, a template with `${}`, a spread of an import or of a `let`), a list
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4079
|
+
declared with `let` or `var` (since `7.26.32`: it can be given other keys,
|
|
4080
|
+
which nobody reads), a list that is not exported, one declared inside a
|
|
4081
|
+
function or a block, one declared by destructuring (`export const
|
|
4082
|
+
{X_I18N_KEYS} = tables`), one exported under a name that does not end in
|
|
4083
|
+
`_I18N_KEYS`. Up to `7.26.27` the regex that read the lists dropped such a
|
|
4084
|
+
list in silence, and a key holding `]` dropped the whole array; up to
|
|
4085
|
+
`7.26.28` a spread of a const of the module was refused too.
|
|
4086
|
+
|
|
4087
|
+
**A published list is never MUTATED** (since `7.26.32`): it is read as it is
|
|
4088
|
+
WRITTEN, so a key it is given later is asked for by nobody. `X.push(k)`,
|
|
4089
|
+
`X.splice(i, 0, k)`, `X.unshift(k)`, `X.fill(k)`, `X[i] = k`, `X.length = n`,
|
|
4090
|
+
`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). Up
|
|
4092
|
+
to `7.26.31` an `export let` list was read and could be pushed into, and the
|
|
4093
|
+
pushed keys went unasked:
|
|
4094
|
+
|
|
4095
|
+
```js
|
|
4096
|
+
export let MY_VIEW_I18N_KEYS = ["shape"]; // fails: a published list is an export const
|
|
4097
|
+
MY_VIEW_I18N_KEYS.push("radius"); // fails: "radius" would be asked for by nobody
|
|
4098
|
+
```
|
|
4007
4099
|
|
|
4008
4100
|
**A MARKER says where the keys of a place come from.** It is a comment that
|
|
4009
|
-
stands right before the node it marks (only whitespace between
|
|
4010
|
-
a
|
|
4101
|
+
stands right before the node it marks (only whitespace between, and since
|
|
4102
|
+
`7.26.32` a parenthesis: `/* i18n: data */ (a || b)` marks `a || b`): an
|
|
4103
|
+
argument, a branch of one, a property value, or the whole call. Two kinds:
|
|
4011
4104
|
|
|
4012
4105
|
```js
|
|
4013
4106
|
yui_shell_show_error(shell, /* i18n: data */ comment || "print-tranger failed", {t: t});
|
|
@@ -4021,7 +4114,15 @@ confirm_then(gobj, /* i18n: C_YUI_FORM_I18N_KEYS */ kw.warning || "all changes w
|
|
|
4021
4114
|
above) are still read.
|
|
4022
4115
|
- `i18n: <NAME>_I18N_KEYS` (several by commas) -- the keys come from those
|
|
4023
4116
|
published lists. The keys of the marked expression that the reader CAN
|
|
4024
|
-
follow must be in them: a marker is a claim, and it is checked.
|
|
4117
|
+
follow must be in them: a marker is a claim, and it is checked. A key BUILT
|
|
4118
|
+
at run time is published that way and marked with its list -- gui_agent's
|
|
4119
|
+
monitor names a control's label `monitor ${control}`, and publishes the six
|
|
4120
|
+
keys that template builds in `C_AGENT_MONITOR_I18N_KEYS`. A template with
|
|
4121
|
+
`${}` under a list marker must have the SHAPE of some key of the lists
|
|
4122
|
+
(since `7.26.32`): `monitor ${control}` is checked against `^monitor .*$`,
|
|
4123
|
+
so a marker naming the wrong list fails. Every key of a published list is
|
|
4124
|
+
asked for, so a control whose key the list lacks is the one thing no check
|
|
4125
|
+
sees: the list sits next to the template, and a comment says so.
|
|
4025
4126
|
|
|
4026
4127
|
**A `data` marker is a claim too** (since `7.26.29`). On what the reader
|
|
4027
4128
|
follows to keys and nothing else -- a literal, a template with no `${}`, a
|
|
@@ -4042,6 +4143,31 @@ yui_shell_show_info(shell, /* i18n: data */ pick());
|
|
|
4042
4143
|
`/* i18n: data */ comment || "print-tranger failed"` stays legal: `comment` is
|
|
4043
4144
|
data, and the fallback is read anyway.
|
|
4044
4145
|
|
|
4146
|
+
Since `7.26.32` the claim is checked further:
|
|
4147
|
+
|
|
4148
|
+
- the call may be of a function IMPORTED from a module the reader reads (a
|
|
4149
|
+
file of the app, a module of the library), and the const may be imported:
|
|
4150
|
+
both are followed into their module, so `/* i18n: data */ pick()` fails
|
|
4151
|
+
there too;
|
|
4152
|
+
- a data marker on a call whose returns MIX keys with data fails: the reader
|
|
4153
|
+
does not read such a call (it reads a call only when it knows every
|
|
4154
|
+
return), so the marker would hide the key. Split the branches, so the key is
|
|
4155
|
+
handed where it is read and only the data is marked:
|
|
4156
|
+
|
|
4157
|
+
```js
|
|
4158
|
+
function label(kw) { return kw.ok? "accepted" : kw.comment; }
|
|
4159
|
+
yui_shell_show_info(shell, /* i18n: data */ label(kw)); // fails
|
|
4160
|
+
yui_shell_show_info(shell, /* i18n: data */ kw.comment || "accepted"); // the same, split
|
|
4161
|
+
```
|
|
4162
|
+
|
|
4163
|
+
The library had it twice: `refusal_text()` of the treedb views returned the
|
|
4164
|
+
backend's words or "print-tranger failed". It returns the words only now,
|
|
4165
|
+
and the call writes the fallback. Under a LIST marker such a call is
|
|
4166
|
+
checked, not refused: its keys are asked for and must be in the lists;
|
|
4167
|
+
- a data marker on an ARRAY OF STRING LITERALS fails: it is no DOM (a
|
|
4168
|
+
`createElement2` spec carries its attrs, an object, in its second slot), so
|
|
4169
|
+
the strings would be hidden.
|
|
4170
|
+
|
|
4045
4171
|
**A marked `let` (or `var`) is held to its marker.** A marker that names a list
|
|
4046
4172
|
used to let a `let` pass unread, whatever it held: a new literal branch on it
|
|
4047
4173
|
was neither asked for nor checked (REV-CLOUD V20). Now, when what a marker
|
|
@@ -4102,10 +4228,19 @@ would not carry what is pushed into it to the reader.
|
|
|
4102
4228
|
|
|
4103
4229
|
`validate-locales` checks every marker in what it scans, in an app's code too:
|
|
4104
4230
|
a comment that starts with `i18n:` and is no marker, a marker that stands
|
|
4105
|
-
before no place a key is read (a key position,
|
|
4231
|
+
before no place a key is read (a key position, a translator, an `i18n` or
|
|
4106
4232
|
`data-i18n*` value), a marker that names a list no module the app mounts
|
|
4107
|
-
publishes, a marked key that is not in the lists it names, a marked
|
|
4108
|
-
|
|
4233
|
+
publishes, a marked key that is not in the lists it names, a marked template
|
|
4234
|
+
with no key of its shape in them, a marked variable that only ever holds
|
|
4235
|
+
literals -- each one fails, with the file and the line. A marker that stands
|
|
4236
|
+
before no place says what it stands before, and why that is none (since
|
|
4237
|
+
`7.26.32`; it used to say only *"stands before no place a key is read"*):
|
|
4238
|
+
|
|
4239
|
+
```
|
|
4240
|
+
main.js:8: the i18n marker stands before `1;`, the value a variable is DECLARED with: mark it
|
|
4241
|
+
where the variable is handed to a place a key is read. A marker marks the value it stands
|
|
4242
|
+
right before, where a key is read: ...
|
|
4243
|
+
```
|
|
4109
4244
|
|
|
4110
4245
|
**The rule is per CALL, in the library and in the app.**
|
|
4111
4246
|
`src/i18n_key_functions.test.js` reads every module of the library with the
|
|
@@ -4132,7 +4267,11 @@ src/main.js:12: yui_shell_confirm_yesno() [2.title] is given opts, which the rea
|
|
|
4132
4267
|
|
|
4133
4268
|
A TRANSLATED text handed to a key position fails even when it is marked: the
|
|
4134
4269
|
function translates it again and marks it `data-i18n` with the translation,
|
|
4135
|
-
so it never changes language. Hand it the key
|
|
4270
|
+
so it never changes language. Hand it the key. A translated text is the value
|
|
4271
|
+
of any TRANSLATOR (since `7.26.32`; up to `7.26.31` only a call named `t`, so
|
|
4272
|
+
`tr("save")`, an alias of t, `t?.()` or `t.call()` passed marked -- and an
|
|
4273
|
+
unmarked `tr()` failed with *"cannot follow"*, whose advice was the marker that
|
|
4274
|
+
then let it pass):
|
|
4136
4275
|
|
|
4137
4276
|
```js
|
|
4138
4277
|
yui_install_ask_once(shell, {t: t, message: t("install this app")}); // fails
|
|
@@ -4142,7 +4281,7 @@ yui_install_ask_once(shell, {t: t, message: "install this app"}); // the ke
|
|
|
4142
4281
|
```
|
|
4143
4282
|
src/c_app.js:734 (call at line 732): yui_install_ask_once() [1.message] is given t("install this app"):
|
|
4144
4283
|
a TRANSLATED text where a KEY goes (translated again and marked data-i18n with the translation,
|
|
4145
|
-
it never changes language): hand
|
|
4284
|
+
it never changes language, and no marker excuses it): hand the key, not t(key)
|
|
4146
4285
|
```
|
|
4147
4286
|
|
|
4148
4287
|
In an app, what a wrapper of its own hands on is marked where it hands it:
|
|
@@ -4163,10 +4302,11 @@ module. The same test fails when a marker is not one
|
|
|
4163
4302
|
or stands nowhere; when a marker names a list that is not published by its
|
|
4164
4303
|
module or by one it imports (a consumer would not read it); when a marked key
|
|
4165
4304
|
the reader can follow is not in the list; when a marked variable only ever
|
|
4166
|
-
holds literals; when a list is not readable, holds a key that is
|
|
4167
|
-
lower-case ASCII, holds one twice, or holds one written nowhere else in
|
|
4168
|
-
module (stale); when an entry of the table names a function its module
|
|
4169
|
-
not declare.
|
|
4305
|
+
holds literals; when a list is not readable, is mutated, holds a key that is
|
|
4306
|
+
not lower-case ASCII, holds one twice, or holds one written nowhere else in
|
|
4307
|
+
its module (stale); when an entry of the table names a function its module
|
|
4308
|
+
does not declare, or (since `7.26.32`) a position the search for forwarders
|
|
4309
|
+
does not find.
|
|
4170
4310
|
|
|
4171
4311
|
**Every key of every list is PINNED**: dropping it from its list fails a test,
|
|
4172
4312
|
or loses nothing. For each key, one of these holds, or the test fails with
|
|
@@ -4210,19 +4350,41 @@ the node graph's key-taking helpers from its syntax tree, and
|
|
|
4210
4350
|
`yui_dev_controls.test.js` builds the Developer window and compares every key
|
|
4211
4351
|
it asks for or carries with the list.
|
|
4212
4352
|
|
|
4213
|
-
**What
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
`
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4353
|
+
**What stays INVISIBLE** -- read by no check, failing nothing; found only by
|
|
4354
|
+
reading the page in another language:
|
|
4355
|
+
|
|
4356
|
+
- a key handed to a translator, an `i18n` or a `data-i18n*` value by an
|
|
4357
|
+
UNMARKED `let`, a call the reader does not follow (a recursion, one whose
|
|
4358
|
+
returns mix keys and data, a function of a package) or a computed string:
|
|
4359
|
+
a translator is not a key function, and only the positions of
|
|
4360
|
+
`I18N_KEY_FUNCTIONS` are held to the per-call rule -- in the library and in
|
|
4361
|
+
an app alike. (A PARAMETER is not, in the library: the forwarder test puts
|
|
4362
|
+
its function in the table, or demands a marker, also when no position can
|
|
4363
|
+
name it.);
|
|
4364
|
+
- a translator the reader does not know as one: a name other than `t` / `tr`
|
|
4365
|
+
that no const or import makes an alias of -- a parameter `translate`, a
|
|
4366
|
+
`let` alias, `opts.translate(k)`, `i18next.getFixedT()`;
|
|
4367
|
+
- a key function reached through a parameter (`apply(fn)` calling
|
|
4368
|
+
`fn(shell, "k")`), a `let` given more than one function, a map in a `let`,
|
|
4369
|
+
a computed member (`API[name](...)`), or `.apply()` of an array the source
|
|
4370
|
+
does not write out;
|
|
4371
|
+
- a `data-i18n*` attribute written through an alias of `dataset`
|
|
4372
|
+
(`const ds = el.dataset; ds.i18nTitle = k`), by `Object.assign()` into it,
|
|
4373
|
+
or named by a `let`;
|
|
4374
|
+
- what is written INTO a `const` table after its declaration
|
|
4375
|
+
(`TABLE.k = "k"`): the reader follows a const to its value, and only a
|
|
4376
|
+
marked `let` is followed into what is written into it (a published list
|
|
4377
|
+
that is written into fails: above);
|
|
4378
|
+
- what a module of a package exports (gobj-js, i18next), and an exported
|
|
4379
|
+
`let`;
|
|
4380
|
+
- 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), and what a
|
|
4382
|
+
caller puts in a gobj's attrs (a window's `title` given at `gobj_create()`);
|
|
4383
|
+
- in an app, a key its callers hand a wrapper of its own reaches the locales
|
|
4384
|
+
only through a list the module publishes: the wrapper's hand-off must be
|
|
4385
|
+
marked (the rule per call), and nothing ties its callers' literals to the
|
|
4386
|
+
list -- nor a key built at run time (a template) to the list its marker
|
|
4387
|
+
names, beyond the shape of the template.
|
|
4226
4388
|
|
|
4227
4389
|
**What fails the build, besides a key no locale defines:**
|
|
4228
4390
|
|
|
@@ -4233,9 +4395,12 @@ callers' literals to the list.
|
|
|
4233
4395
|
- a locale that looks like one and exports no `{<code>}` with a
|
|
4234
4396
|
`translation` dict;
|
|
4235
4397
|
- a source file that cannot be parsed;
|
|
4236
|
-
- a published list no consumer can read (above)
|
|
4237
|
-
|
|
4238
|
-
|
|
4398
|
+
- a published list no consumer can read (above), declared with `let` or
|
|
4399
|
+
`var`, or mutated;
|
|
4400
|
+
- a marker that is wrong (above): a `data` marker on what the reader follows
|
|
4401
|
+
to keys, or on what would hide a key (a call mixing keys and data, an array
|
|
4402
|
+
of string literals), a list marker on a template whose shape no key of the
|
|
4403
|
+
list has;
|
|
4239
4404
|
- a key position of a key function, in the app's own code, given what the
|
|
4240
4405
|
reader cannot follow and unmarked, or given a translated text (the rule per
|
|
4241
4406
|
call, above).
|
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -27190,12 +27190,14 @@ function answer_print_tranger_refused$1(gobj, path, answer) {
|
|
|
27190
27190
|
}
|
|
27191
27191
|
/************************************************************
|
|
27192
27192
|
* The text of a transport's refusal: gobj_command() answers a string,
|
|
27193
|
-
* a command response or a number.
|
|
27193
|
+
* a command response or a number. Data only ("" when it says
|
|
27194
|
+
* nothing): the caller writes its own key as the fallback, where
|
|
27195
|
+
* validate-locales reads it.
|
|
27194
27196
|
************************************************************/
|
|
27195
27197
|
function refusal_text$1(ret) {
|
|
27196
27198
|
if (typeof ret === "string" && ret) return ret;
|
|
27197
27199
|
if (ret && typeof ret === "object" && typeof ret.comment === "string" && ret.comment) return ret.comment;
|
|
27198
|
-
return "
|
|
27200
|
+
return "";
|
|
27199
27201
|
}
|
|
27200
27202
|
/************************************************************
|
|
27201
27203
|
* The whole tranger, for the raw-json viewer.
|
|
@@ -27223,7 +27225,7 @@ function request_print_tranger$1(gobj, path) {
|
|
|
27223
27225
|
}, gobj);
|
|
27224
27226
|
if (ret) {
|
|
27225
27227
|
(0, _yuneta_gobj_js.log_error)(ret);
|
|
27226
|
-
answer_print_tranger_refused$1(gobj, path, { error: refusal_text$1(ret) });
|
|
27228
|
+
answer_print_tranger_refused$1(gobj, path, { error: refusal_text$1(ret) || "print-tranger failed" });
|
|
27227
27229
|
return;
|
|
27228
27230
|
}
|
|
27229
27231
|
if (path) priv.drills_in_flight.add(path);
|
|
@@ -28364,8 +28366,8 @@ function yui_clear_selection(tabulator) {
|
|
|
28364
28366
|
* through `refresh_language()`. Call it on EV_LANGUAGE_CHANGED.
|
|
28365
28367
|
***************************************************************/
|
|
28366
28368
|
function yui_selection_bar(t, opts) {
|
|
28367
|
-
|
|
28368
|
-
|
|
28369
|
+
const o = opts || {};
|
|
28370
|
+
const actions = Array.isArray(o.actions) ? o.actions : [];
|
|
28369
28371
|
let name = o.name || "TABLE";
|
|
28370
28372
|
let count = 0;
|
|
28371
28373
|
let $count = (0, _yuneta_gobj_js.createElement2)([
|
|
@@ -28392,7 +28394,6 @@ function yui_selection_bar(t, opts) {
|
|
|
28392
28394
|
]],
|
|
28393
28395
|
{ click: action.on_click }
|
|
28394
28396
|
]);
|
|
28395
|
-
$b._yui_label = action.label || "";
|
|
28396
28397
|
$buttons.push($b);
|
|
28397
28398
|
}
|
|
28398
28399
|
let $clear = (0, _yuneta_gobj_js.createElement2)([
|
|
@@ -28425,15 +28426,18 @@ function yui_selection_bar(t, opts) {
|
|
|
28425
28426
|
function label_of($b) {
|
|
28426
28427
|
return $b.querySelector("span.icon ~ span");
|
|
28427
28428
|
}
|
|
28429
|
+
function paint_label($b, key) {
|
|
28430
|
+
let $label = label_of($b);
|
|
28431
|
+
if ($label && key) $label.textContent = t(key);
|
|
28432
|
+
$b.title = key ? t(key) : "";
|
|
28433
|
+
$b.setAttribute("aria-label", $b.title);
|
|
28434
|
+
}
|
|
28428
28435
|
function refresh() {
|
|
28429
28436
|
$count.textContent = t("{{n}} selected", { n: count });
|
|
28430
|
-
|
|
28431
|
-
|
|
28432
|
-
|
|
28433
|
-
|
|
28434
|
-
$b.title = key ? t(key) : "";
|
|
28435
|
-
$b.setAttribute("aria-label", $b.title);
|
|
28436
|
-
}
|
|
28437
|
+
actions.forEach((action, i) => {
|
|
28438
|
+
paint_label($buttons[i], action.label || "");
|
|
28439
|
+
});
|
|
28440
|
+
paint_label($clear, "clear selection");
|
|
28437
28441
|
$el.classList.toggle("is-hidden", count <= 0);
|
|
28438
28442
|
}
|
|
28439
28443
|
function set_count(n) {
|
|
@@ -71278,12 +71282,14 @@ function answer_print_tranger_refused(gobj, path, answer) {
|
|
|
71278
71282
|
}
|
|
71279
71283
|
/************************************************************
|
|
71280
71284
|
* The text of a transport's refusal: gobj_command() answers a string,
|
|
71281
|
-
* a command response or a number.
|
|
71285
|
+
* a command response or a number. Data only ("" when it says
|
|
71286
|
+
* nothing): the caller writes its own key as the fallback, where
|
|
71287
|
+
* validate-locales reads it.
|
|
71282
71288
|
************************************************************/
|
|
71283
71289
|
function refusal_text(ret) {
|
|
71284
71290
|
if (typeof ret === "string" && ret) return ret;
|
|
71285
71291
|
if (ret && typeof ret === "object" && typeof ret.comment === "string" && ret.comment) return ret.comment;
|
|
71286
|
-
return "
|
|
71292
|
+
return "";
|
|
71287
71293
|
}
|
|
71288
71294
|
/************************************************************
|
|
71289
71295
|
* Fetch the treedb's raw tranger (or one subtree when `path` is set) as
|
|
@@ -71312,7 +71318,7 @@ function request_print_tranger(gobj, path) {
|
|
|
71312
71318
|
}, gobj);
|
|
71313
71319
|
if (ret) {
|
|
71314
71320
|
(0, _yuneta_gobj_js.log_error)(ret);
|
|
71315
|
-
answer_print_tranger_refused(gobj, path, { error: refusal_text(ret) });
|
|
71321
|
+
answer_print_tranger_refused(gobj, path, { error: refusal_text(ret) || "print-tranger failed" });
|
|
71316
71322
|
return;
|
|
71317
71323
|
}
|
|
71318
71324
|
if (path) priv.drills_in_flight.add(path);
|
package/dist/gobj-ui.es.js
CHANGED
|
@@ -27185,12 +27185,14 @@ function answer_print_tranger_refused$1(gobj, path, answer) {
|
|
|
27185
27185
|
}
|
|
27186
27186
|
/************************************************************
|
|
27187
27187
|
* The text of a transport's refusal: gobj_command() answers a string,
|
|
27188
|
-
* a command response or a number.
|
|
27188
|
+
* a command response or a number. Data only ("" when it says
|
|
27189
|
+
* nothing): the caller writes its own key as the fallback, where
|
|
27190
|
+
* validate-locales reads it.
|
|
27189
27191
|
************************************************************/
|
|
27190
27192
|
function refusal_text$1(ret) {
|
|
27191
27193
|
if (typeof ret === "string" && ret) return ret;
|
|
27192
27194
|
if (ret && typeof ret === "object" && typeof ret.comment === "string" && ret.comment) return ret.comment;
|
|
27193
|
-
return "
|
|
27195
|
+
return "";
|
|
27194
27196
|
}
|
|
27195
27197
|
/************************************************************
|
|
27196
27198
|
* The whole tranger, for the raw-json viewer.
|
|
@@ -27218,7 +27220,7 @@ function request_print_tranger$1(gobj, path) {
|
|
|
27218
27220
|
}, gobj);
|
|
27219
27221
|
if (ret) {
|
|
27220
27222
|
log_error(ret);
|
|
27221
|
-
answer_print_tranger_refused$1(gobj, path, { error: refusal_text$1(ret) });
|
|
27223
|
+
answer_print_tranger_refused$1(gobj, path, { error: refusal_text$1(ret) || "print-tranger failed" });
|
|
27222
27224
|
return;
|
|
27223
27225
|
}
|
|
27224
27226
|
if (path) priv.drills_in_flight.add(path);
|
|
@@ -28359,8 +28361,8 @@ function yui_clear_selection(tabulator) {
|
|
|
28359
28361
|
* through `refresh_language()`. Call it on EV_LANGUAGE_CHANGED.
|
|
28360
28362
|
***************************************************************/
|
|
28361
28363
|
function yui_selection_bar(t, opts) {
|
|
28362
|
-
|
|
28363
|
-
|
|
28364
|
+
const o = opts || {};
|
|
28365
|
+
const actions = Array.isArray(o.actions) ? o.actions : [];
|
|
28364
28366
|
let name = o.name || "TABLE";
|
|
28365
28367
|
let count = 0;
|
|
28366
28368
|
let $count = createElement2([
|
|
@@ -28387,7 +28389,6 @@ function yui_selection_bar(t, opts) {
|
|
|
28387
28389
|
]],
|
|
28388
28390
|
{ click: action.on_click }
|
|
28389
28391
|
]);
|
|
28390
|
-
$b._yui_label = action.label || "";
|
|
28391
28392
|
$buttons.push($b);
|
|
28392
28393
|
}
|
|
28393
28394
|
let $clear = createElement2([
|
|
@@ -28420,15 +28421,18 @@ function yui_selection_bar(t, opts) {
|
|
|
28420
28421
|
function label_of($b) {
|
|
28421
28422
|
return $b.querySelector("span.icon ~ span");
|
|
28422
28423
|
}
|
|
28424
|
+
function paint_label($b, key) {
|
|
28425
|
+
let $label = label_of($b);
|
|
28426
|
+
if ($label && key) $label.textContent = t(key);
|
|
28427
|
+
$b.title = key ? t(key) : "";
|
|
28428
|
+
$b.setAttribute("aria-label", $b.title);
|
|
28429
|
+
}
|
|
28423
28430
|
function refresh() {
|
|
28424
28431
|
$count.textContent = t("{{n}} selected", { n: count });
|
|
28425
|
-
|
|
28426
|
-
|
|
28427
|
-
|
|
28428
|
-
|
|
28429
|
-
$b.title = key ? t(key) : "";
|
|
28430
|
-
$b.setAttribute("aria-label", $b.title);
|
|
28431
|
-
}
|
|
28432
|
+
actions.forEach((action, i) => {
|
|
28433
|
+
paint_label($buttons[i], action.label || "");
|
|
28434
|
+
});
|
|
28435
|
+
paint_label($clear, "clear selection");
|
|
28432
28436
|
$el.classList.toggle("is-hidden", count <= 0);
|
|
28433
28437
|
}
|
|
28434
28438
|
function set_count(n) {
|
|
@@ -71273,12 +71277,14 @@ function answer_print_tranger_refused(gobj, path, answer) {
|
|
|
71273
71277
|
}
|
|
71274
71278
|
/************************************************************
|
|
71275
71279
|
* The text of a transport's refusal: gobj_command() answers a string,
|
|
71276
|
-
* a command response or a number.
|
|
71280
|
+
* a command response or a number. Data only ("" when it says
|
|
71281
|
+
* nothing): the caller writes its own key as the fallback, where
|
|
71282
|
+
* validate-locales reads it.
|
|
71277
71283
|
************************************************************/
|
|
71278
71284
|
function refusal_text(ret) {
|
|
71279
71285
|
if (typeof ret === "string" && ret) return ret;
|
|
71280
71286
|
if (ret && typeof ret === "object" && typeof ret.comment === "string" && ret.comment) return ret.comment;
|
|
71281
|
-
return "
|
|
71287
|
+
return "";
|
|
71282
71288
|
}
|
|
71283
71289
|
/************************************************************
|
|
71284
71290
|
* Fetch the treedb's raw tranger (or one subtree when `path` is set) as
|
|
@@ -71307,7 +71313,7 @@ function request_print_tranger(gobj, path) {
|
|
|
71307
71313
|
}, gobj);
|
|
71308
71314
|
if (ret) {
|
|
71309
71315
|
log_error(ret);
|
|
71310
|
-
answer_print_tranger_refused(gobj, path, { error: refusal_text(ret) });
|
|
71316
|
+
answer_print_tranger_refused(gobj, path, { error: refusal_text(ret) || "print-tranger failed" });
|
|
71311
71317
|
return;
|
|
71312
71318
|
}
|
|
71313
71319
|
if (path) priv.drills_in_flight.add(path);
|