mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
docs(i18n): translator's guide for the en-only foundation, current-state and changelog
docs/TRANSLATORS.md is rewritten for the foundation state: English shipped, and the locale-addition recipe front and center — the one-PR-per-locale procedure (catalogs, registration, CATALOG_LOCALES, pair behavior, parity gates). CURRENT-STATE.md documents the subsystem (file map, resolution order, selector, gates, deferrals) and the CHANGELOG records the foundation.
This commit is contained in:
1 parent
284c4d4601
commit
41378656c6
3 files changed
+340
-5
No files matched your search
+23
-5
@@ -76,6 +76,29 @@
|
||||
keeps frame time with ALPR on within a few percent of ALPR off, seats nearby
|
||||
badges on the rendered surface and says when no loaded camera is on screen.
|
||||
|
||||
## Internationalization foundation
|
||||
|
||||
- Add the locale core (`src/i18n/`): configurable locale pair
|
||||
(`GEV_DEFAULT_LOCALE` / `GEV_SECONDARY_LOCALE`, validated against the
|
||||
shipped catalogs), guarded preference storage, a one-shot `?lang=`
|
||||
override, and `<html lang>`/`<html dir>` metadata. English is the only
|
||||
shipped locale — the built-in pair degenerates to en-only and the dock
|
||||
language switch renders a single EN button — and English behavior is
|
||||
byte-identical to before.
|
||||
- Extract all application-owned presentation text into four English
|
||||
catalogs (`shell`/`cockpit`/`layers`/`setup`) consumed through `t()` call
|
||||
sites, `data-i18n*` template attributes, and the runtime locale selector;
|
||||
complete the duplicate `data-i18n` split on the first-run EXPLORE
|
||||
MANUALLY tile (the subcopy was wiped in every locale).
|
||||
- Enforce the parity gates every additional locale must pass (key /
|
||||
placeholder / plural-shape parity, markup coverage, repair-pass anchors).
|
||||
Additional locales ship as stacked follow-up PRs, one per locale, via the
|
||||
locale-addition recipe in `docs/TRANSLATORS.md` (Spanish is first).
|
||||
|
||||
- Let CLI tools, development launchers and the setup doctor use an explicit project directory while retaining their existing default paths.
|
||||
|
||||
- Split application scene, controls, catalog, tools and HTML into reusable components; configure application request services and sources without changing global fetch. Preserve standalone markup and voice behavior. Explicit annotation navigation may resolve a distant named target.
|
||||
|
||||
- CCTV cameras whose bearing is a guess now say so. Packs mark bearings derived
|
||||
from a hash of the camera id as `headingConfidence: 'low'`, but nothing read the
|
||||
flag, so roughly 70% of a default catalog rendered like surveyed facings. The HUD
|
||||
@@ -497,11 +520,6 @@ Analyst records for loaded satellites, datacenters and dams, with explicit bound
|
||||
- Separate navigation, share restoration, visual settings and panel state into focused UI owners with explicit dependencies and terminal cleanup.
|
||||
|
||||
- Separate layer lifecycle transactions from panel construction and render/detection reactions; retain existing transition and refresh behavior.
|
||||
|
||||
- Let CLI tools, development launchers and the setup doctor use an explicit project directory while retaining their existing default paths.
|
||||
|
||||
- Split application scene, controls, catalog, tools and HTML into reusable components; configure application request services and sources without changing global fetch. Preserve standalone markup and voice behavior. Explicit annotation navigation may resolve a distant named target.
|
||||
|
||||
## Satellite pass prediction
|
||||
|
||||
- Bisect pass rise/set to ~0.2 s and fit peak elevation with a parabola.
|
||||
|
||||
@@ -2806,6 +2806,125 @@ test:track` 43 tracking invariants · headless QA harnesses under
|
||||
> attribution 18/18). New modules: `src/data/{motionModel,aircraftMeta,aircraftClass,aircraftIcons,issPass,routePlausible,dataCredits}.js`.
|
||||
> The live runtime now declares 29 voice tools; the 17→20 count above is retained only as milestone history.
|
||||
|
||||
### Internationalization / catalog locales (September 2026)
|
||||
|
||||
The application-owned UI is fully extracted into message catalogs; **en**
|
||||
is the only shipped locale in this foundation state — additional locales
|
||||
land as stacked follow-up PRs, one per locale (Spanish first), each
|
||||
following the locale-addition recipe in
|
||||
[`docs/TRANSLATORS.md`](./TRANSLATORS.md). English is the default, the
|
||||
source catalog, and the fallback. The subsystem lives in `src/i18n/`:
|
||||
|
||||
- **File map.** `src/i18n/locale.js` owns locale resolution, guarded storage
|
||||
(`gev:locale:v1`), the one-shot `?lang=` override, and `<html lang>`/`<html
|
||||
dir>` metadata. `src/i18n/index.js` owns the catalog registry, `t()`
|
||||
(interpolation + `Intl.PluralRules` plural selection), `formatNumber` /
|
||||
`formatDate`, `applyDocumentTranslations()`, and
|
||||
`persistLocaleAndReload()`. The shipped catalog is four flat message maps
|
||||
— `src/i18n/locales/en/{shell,cockpit,layers,setup}.js`, 912 keys (shell
|
||||
34, cockpit 369, layers 388, setup 121). Plural entries are the en
|
||||
`{ one, other }` shape; a future locale may add only cardinal categories
|
||||
`Intl.PluralRules` reports valid for it, and an entry lacking the selected
|
||||
category degrades to `other` at runtime. Locale-code normalization
|
||||
(`es-MX`/`es_419` → `es`, plus fr/ru/uk and variants) ships ahead of the
|
||||
locales on purpose: knowing a code is hygiene, shipping is catalog-driven
|
||||
through `CATALOG_LOCALES`.
|
||||
- **Selector.** The command dock carries a compact locale switch: a static
|
||||
`.dock-locale-switch` group container in `index.html` whose buttons
|
||||
(`.dock-locale-btn`) are rendered at runtime by `src/ui/applicationShell.js`
|
||||
`_initLocaleSelector()` — one per locale in the configured pair; while
|
||||
only English ships that is a single EN button. A click persists the
|
||||
choice and reloads the page with the hash preserved, so no live re-apply
|
||||
of already-rendered dynamic panels is needed.
|
||||
- **Locale pair config.** `GEV_DEFAULT_LOCALE` and `GEV_SECONDARY_LOCALE` in
|
||||
`.env`, injected as `import.meta.env` defines by `vite.config.js`; both
|
||||
values are validated against the shipped catalogs (`CATALOG_LOCALES`),
|
||||
and the offered set is `dedup([default, secondary, 'en'])`. While English
|
||||
is the only shipped catalog the built-in pair is en-only, so every
|
||||
configuration degenerates to a single offered locale; an invalid,
|
||||
unshipped, or degenerate configured pair falls back to that built-in
|
||||
en-only shape (dev-only warn). The first secondary-locale PR restores the
|
||||
built-in en+es pair.
|
||||
- **Resolution order.** `?lang=<locale>` (search string only; never
|
||||
persisted, never written into share links; stripped by
|
||||
`persistLocaleAndReload`; accepted only for offered locales) → stored
|
||||
`gev:locale:v1` (re-checked against the pair) →
|
||||
`navigator.languages` (regional variants normalize to the primary tag:
|
||||
`es-MX`/`es_419` → `es`) → the CONFIGURED default locale. Unsupported
|
||||
values defer to the next
|
||||
step rather than forcing English.
|
||||
- **Gates** (all under `node --test src/i18n/`, 40 tests):
|
||||
`catalog.test.mjs` enforces per-locale key, placeholder-name, and
|
||||
plural-shape parity with the strict exact-parity flip ON
|
||||
(`REQUIRE_FULL_PARITY`; `GEV_I18N_REQUIRE_FULL_LOCALE_PARITY=0` opts out
|
||||
for staged work; the loops are vacuous while only en ships — each locale
|
||||
PR meets them from day one);
|
||||
`markupCoverage.test.mjs` requires every `data-i18n*` attribute in
|
||||
`index.html` to resolve in every shipped catalog and rejects unknown attribute
|
||||
spellings; `i18n.test.mjs` pins precedence, guards, fallback,
|
||||
interpolation, the plural-selection contract (synthetic missing-category
|
||||
degradation; real-catalog plural pins arrive with each locale PR), and
|
||||
DOM application; `repairPass.test.mjs` anchors en byte-identity for
|
||||
extracted literals and rejects a locale-scoped CCTV wrap rule shipping
|
||||
ahead of its locale (per-locale value anchors arrive with each locale
|
||||
PR).
|
||||
- **Accepted deferrals (do not "fix" silently):**
|
||||
- The military-awareness subject header literal `FLIGHT / VESSEL WINDOW`
|
||||
(`src/data/militaryAwareness.js`) stays English; the literal is
|
||||
test-pinned in `src/data/militaryAwareness.test.mjs`.
|
||||
- The visible cockpit-brief tab tokens `SIG` / `NEWS` / `LOCAL`
|
||||
(`index.html`) stay untranslated to match the runtime keys; their
|
||||
`aria-label`s ARE localized (`cockpit.brief.tab*AriaLabel`).
|
||||
- `src/voice/gevActions.js` tool-result confirmation strings stay English
|
||||
by contract (voice tool schemas and spoken confirmations are
|
||||
keep-English; see the Keep-English boundary in `docs/TRANSLATORS.md`).
|
||||
- Number formatting is still the pre-i18n `toLocaleString` policy at:
|
||||
`src/ui.js:1442`, `src/data/satellites.js:829`,
|
||||
`src/data/flights.js:436` (`'en-US'` pinned), and
|
||||
`src/data/rocketLaunches.js:2281/2299/2364/2371/2374`
|
||||
(default-locale). A locale-aware number-format policy is deferred; the
|
||||
`formatNumber` helper exists in `src/i18n/index.js` when that lands.
|
||||
|
||||
### Overpass proxy mirror rotation (September 2026)
|
||||
|
||||
- `/api/overpass` fans out across four public mirrors. `overpassPayloadIsData()` governs cache reads, writes, and stale fallback: only a 2xx that is neither rate-limited nor a body-level runtime error qualifies. Previously stored refusals are ignored on both fresh and stale reads, so upgrading does not require manually clearing the disk cache.
|
||||
- HTTP refusals such as 406 now rotate alongside the existing network, rate-limit, and runtime-error cases. A refusal from one mirror no longer prevents reaching healthy alternatives or persists under the seven-day road/month-long boundary cache TTLs. Concurrent identical queries share one mirror sequence; if it fails, both the initiating and joined callers can use the same last-good data.
|
||||
- A refusal every mirror agrees on is still reported with the first mirror's status and body, so a genuinely malformed query says what upstream said — but only after every mirror has had the chance to answer it. `fetchOverpassPayload` takes injectable endpoints and fetch so the rotation is tested without a live mirror (`src/overpassProxy.test.mjs`).
|
||||
|
||||
### Share-link v2 layer state (August 2026)
|
||||
|
||||
- Generated share links use a deterministic v2 hash. Existing camera, visual,
|
||||
HUD, detection, post-processing, celestial, scope, and map-stack fields remain,
|
||||
with compact fields for enabled layers, allowlisted layer options, panel state,
|
||||
and the active preset's allowlisted shader controls. An absent layer field uses
|
||||
deterministic defaults; an explicit empty field means no enabled layers.
|
||||
- The registry seals only after all 16 production layers register, and every
|
||||
layer has an explicit serialization disposition. Unknown enabled-layer tokens
|
||||
reject the layer payload; unknown option tokens are ignored. Restoration
|
||||
settles independently per layer so one failed or unavailable source cannot
|
||||
block its siblings.
|
||||
- Stable visible options are limited to aircraft 3D mode, selected civilian and
|
||||
military flight IDs, Satellite catalog and selection, CCTV coverage/projection/
|
||||
auto-hop, and Radio filter/volume. Playback and tuning, live-data health,
|
||||
calibration, caches, lifecycle state, temporary Context ownership, and derived
|
||||
effects are deliberately excluded. Radio restore never selects or plays a
|
||||
station.
|
||||
- Normal loads restore the last successful explicit UI, voice, or tool choice
|
||||
from versioned local storage. Any valid camera share wins for the current load
|
||||
without overwriting recipient preferences. Restore ownership is split by
|
||||
visibility, option/selection, camera, visual, map, and individual panel lane:
|
||||
a newer explicit action supersedes only the field it owns. In particular,
|
||||
navigation cannot turn unrelated layers off, and an option change cannot
|
||||
|
||||
#### Keep-English adjudications (post-merge catch-ups)
|
||||
|
||||
- `src/ui/visualPresets.js` `'ELASTIC'` — detection-allocation STRATEGY IDENTIFIER (persisted
|
||||
under `gev:detection-allocation`, compared via `dataset.allocation ===`), not display copy.
|
||||
- `src/ui/layerPanel.js` guidance meta — the `{source} · {statusMessage}` composition uses a
|
||||
locale-neutral interpunct; the statusMessage itself IS localized via `installationFeedback`.
|
||||
- `src/ui/mapSourceControls.js` `'...'` switching label and the orbit `'↻'` glyph —
|
||||
punctuation/glyphs, identical across locales.
|
||||
|
||||
## Canonical Docs Order
|
||||
|
||||
Use docs in this order when details conflict:
|
||||
|
||||
@@ -0,0 +1,198 @@
|
||||
# Translator's guide (i18n foundation — English shipped)
|
||||
|
||||
This is the working guide for translating God's Eye View. The i18n
|
||||
foundation ships **English only**: the locale core, the English
|
||||
catalogs, and the parity gates are in, and every additional locale lands
|
||||
as its own stacked PR, one locale at a time, following the
|
||||
[locale-addition recipe](#the-locale-addition-recipe) below. That recipe
|
||||
is the deliberate design artifact of this phase — a locale is not
|
||||
"translated into the app", it is *shipped* through the same gate every
|
||||
time.
|
||||
|
||||
## Which locale ships, and which pair is offered
|
||||
|
||||
One catalog ships: **en** (source of truth and unconditional fallback).
|
||||
Shipping is catalog-driven (`CATALOG_LOCALES` in `src/i18n/locale.js`):
|
||||
while only English ships, the built-in locale pair is en-only and the
|
||||
dock language switch renders a single EN button. Which pair the app
|
||||
*offers* is configuration, not code: `GEV_DEFAULT_LOCALE` and
|
||||
`GEV_SECONDARY_LOCALE` in `.env`, injected into the browser via vite
|
||||
defines. Both values are validated against the shipped catalogs — an
|
||||
invalid, unshipped, or degenerate pair (e.g. the same locale twice)
|
||||
degenerates to the built-in en-only shape with a dev-server-only
|
||||
`console.warn`. English is always resolvable — it is the fallback
|
||||
catalog — even when not part of the configured pair.
|
||||
|
||||
## How the catalog system works
|
||||
|
||||
All application-owned UI text lives in four flat message catalogs (en
|
||||
today; one directory per locale once shipped):
|
||||
|
||||
```text
|
||||
src/i18n/
|
||||
locale.js pair config + resolution + storage + <html lang>/<html dir>
|
||||
index.js catalog registry, t(), Intl formatters, DOM apply
|
||||
locales/en/{shell,cockpit,layers,setup}.js
|
||||
```
|
||||
|
||||
| Namespace | Surface |
|
||||
| --- | --- |
|
||||
| `shell.*` | Document chrome: title, dock actions, panels, global status chip, sync chips, toasts, locale selector |
|
||||
| `cockpit.*` | Cockpit HUD readouts, Context panel, CCTV scene summary, Display/panel chrome, visual presets, Radio utility |
|
||||
| `layers.*` | Data-layer presentation: layer names, feed-state labels, row meta, vessel/flight/satellite/mission/CCTV/Radio/awareness cards and readouts |
|
||||
| `setup.*` | First-run launcher, key setup (POWER UP), scenes/director status, map-stack chips |
|
||||
|
||||
Each catalog file exports `NAMESPACE` and a default map of
|
||||
namespace-relative keys; `mergeNamespace()` prefixes them (`cockpit.…`)
|
||||
and `buildCatalog()` rejects duplicates. English is the default and the
|
||||
fallback locale: a key missing in another locale renders its English
|
||||
value (dev-server-only `console.warn`). The en catalogs hold 912 keys
|
||||
(shell 34, cockpit 369, layers 388, setup 121).
|
||||
|
||||
## Key naming
|
||||
|
||||
- Markup surfaces: `<namespace>.<surface>.<element>` — e.g.
|
||||
`shell.panels.dataLayers`, `cockpit.readout.altitude`.
|
||||
- Runtime flows/states: `<namespace>.<flow>.<state>` — e.g.
|
||||
`shell.status.loadingLiveData`, `layers.missions.telemetry.km`.
|
||||
- Names are semantic and stable. Never rename, reorder, or renumber an
|
||||
existing key: `data-i18n` attributes and runtime `t()` call sites in other
|
||||
files reference them.
|
||||
|
||||
## The locale-addition recipe
|
||||
|
||||
Every locale PR follows the same steps, in this order. Nothing here is
|
||||
optional — the gates below fail the build if a step is skipped.
|
||||
|
||||
1. **Catalogs.** Copy `src/i18n/locales/en/` to
|
||||
`src/i18n/locales/<code>/` and translate all four files
|
||||
(`<code>` is the primary language tag: `es`, not `es-419`). Keep the
|
||||
en key order, keep key names byte-identical, and translate VALUES
|
||||
only. A locale may never carry a key en lacks.
|
||||
2. **Registration.** In `src/i18n/index.js`: add the four import lines
|
||||
and one `<CODE>_NAMESPACES` array, then one entry in the `CATALOGS`
|
||||
map. Registration is append-only; nothing else in the file changes.
|
||||
3. **Shipping.** Append `'<code>'` to `CATALOG_LOCALES` in
|
||||
`src/i18n/locale.js`. This single constant is what makes the locale
|
||||
normalizable-to-shipped: pair config, `?lang=`, storage, and the
|
||||
selector all read from it. Regional variants (`es-MX`, `es_419`)
|
||||
already normalize — locale-code hygiene is shipped ahead of the
|
||||
locales on purpose.
|
||||
4. **Selector labels.** Append
|
||||
`'locale.<code>.ariaLabel': 'Switch to <Language>'` to the `shell`
|
||||
catalog of EVERY shipped locale (en included — the en catalog names
|
||||
the new button; the new catalog names the English one).
|
||||
`markupCoverage.test.mjs` requires a label for every shipped code in
|
||||
every catalog, so this cannot be forgotten.
|
||||
5. **Plurals.** Plural entries are variant objects carrying a `{count}`
|
||||
placeholder, selected per active locale through `Intl.PluralRules`.
|
||||
English entries use `{ one, other }`. Your locale must keep every en
|
||||
variant and may add ONLY categories `Intl.PluralRules` reports valid
|
||||
for it (e.g. a Slavic locale adds `few`/`many`) —
|
||||
`catalog.test.mjs` enforces this shape against the live ICU data.
|
||||
Pin your locale's real-catalog plural agreement in
|
||||
`src/i18n/i18n.test.mjs` (one/few/many/other counts where relevant).
|
||||
6. **Layout.** Prefer concise glossary-approved copy over CSS surgery;
|
||||
fixed-width `nowrap` panels must be checked at narrow viewports. A
|
||||
locale-scoped wrap rule (`html[lang='<code>'] .cctv-controls {
|
||||
flex-wrap: wrap; }` in `src/ui/styles/cctv.css`) is added ONLY when
|
||||
the locale demonstrably clips, with a comment recording the measured
|
||||
widths — the English layout stays pixel-identical, and
|
||||
`repairPass.test.mjs` rejects a wrap rule shipping ahead of its
|
||||
locale.
|
||||
7. **Gates.** `node --test src/i18n/` must be green with the strict
|
||||
parity gate ON: exact key-set equality with en, identical
|
||||
placeholder names, plural-shape superset. While a new catalog is a
|
||||
staged untranslated seed, CI may run with
|
||||
`GEV_I18N_REQUIRE_FULL_LOCALE_PARITY=0` (subset mode) — record every
|
||||
such flip here, and record the flip back.
|
||||
8. **Docs.** Add the locale's section + glossary to this file, note it
|
||||
in `docs/CURRENT-STATE.md` (Internationalization) and `CHANGELOG.md`,
|
||||
and update the shipped-locales wording in `.env.example`.
|
||||
|
||||
## Append-only rules
|
||||
|
||||
- New keys are appended to the END of the namespace file in EVERY
|
||||
shipped locale directory in the same change. Never edit another
|
||||
namespace's files, and never touch the registration arrays in
|
||||
`src/i18n/index.js` without re-reading this guide first.
|
||||
- A fifth namespace is a last resort (prefer fitting one of the four); its
|
||||
registration recipe is the same append-only pattern as a locale (step 2
|
||||
of the recipe above), applied to every shipped locale at once.
|
||||
- Parity is enforced by tests, not goodwill: no locale may carry a key en
|
||||
lacks, and every shared key must keep identical placeholder names
|
||||
and a plural-variant set that includes every en variant plus only
|
||||
categories `Intl.PluralRules` reports for that locale
|
||||
(`src/i18n/catalog.test.mjs`).
|
||||
|
||||
## Placeholder, plural, and typography rules
|
||||
|
||||
- Interpolation uses named `{camelCase}` placeholders:
|
||||
`'Flying to {place}…'`. The **same placeholder names must exist in
|
||||
every locale** — the parity gate fails on a renamed `{name}` because
|
||||
it would break interpolation at runtime.
|
||||
- Locale-aware numbers, dates, and relative times go through the
|
||||
`formatNumber` / `formatDate` / `formatRelativeTime` helpers in
|
||||
`src/i18n/index.js` — do not hand-format in a catalog call site.
|
||||
- Style: the English catalog is ALL-CAPS for tactical labels, readouts,
|
||||
and status text; translations follow the same convention in their
|
||||
script's norms. The `·` separator used between metadata segments is
|
||||
part of the surface style and is reproduced in translations.
|
||||
- Instrument codes stay identical across languages; units (KTS, FT, km,
|
||||
km²) are never translated.
|
||||
- Romance languages run ~25% longer than English and Slavic languages
|
||||
compound that on multi-word tactical labels — plan string budgets and
|
||||
check fixed-width panels before review (see step 6 above).
|
||||
|
||||
## Keep-English boundary (summary)
|
||||
|
||||
Never catalog these — they are contracts, not copy:
|
||||
|
||||
- Internal layer IDs and registry keys (`military-installations`,
|
||||
`ais-live-vessels`, stack ids).
|
||||
- Status enums and machine values (`FEED_STATE_LABELS` keys, lifecycle
|
||||
states, detection/context modes) — translate only the final label at
|
||||
the presentation boundary.
|
||||
- URL/hash contracts: share-link parameters, `?welcome=`, `?lang=`,
|
||||
storage schemas.
|
||||
- API fields, voice tool names/schemas, `/api/setup/*` payloads.
|
||||
- Provider/dataset/product names, callsigns, vessel/satellite/place
|
||||
names from data, news headlines, license/source attributions.
|
||||
- Console diagnostics, QA pin scripts, and existing exact-English test
|
||||
expectations.
|
||||
- User-authored content (annotations, labels drawn from live data).
|
||||
|
||||
Adjudicated exceptions live in "Internationalization" in
|
||||
[`docs/CURRENT-STATE.md`](./CURRENT-STATE.md) (accepted deferrals — do not
|
||||
"fix" them silently).
|
||||
|
||||
## Glossary
|
||||
|
||||
Approved recurring terms per locale. Each locale PR appends its
|
||||
glossary here (English term · translation · catalog evidence) so later
|
||||
translators reuse approved copy verbatim. None yet — the first entry
|
||||
arrives with the first translated locale.
|
||||
|
||||
## Running the i18n test gates
|
||||
|
||||
```sh
|
||||
node --test src/i18n/ # 40 tests: core + pair config, catalog parity, markup coverage, repair-pass anchors
|
||||
npm test # full suite (see below for the known environmental caveat)
|
||||
```
|
||||
|
||||
- `src/i18n/i18n.test.mjs` — resolution precedence, guarded storage,
|
||||
fallback, interpolation, plural selection (contract + synthetic
|
||||
missing-category degradation; real-catalog plural pins arrive with
|
||||
each locale PR), DOM application.
|
||||
- `src/i18n/catalog.test.mjs` — key + placeholder + plural-shape parity for
|
||||
every shipped locale against en, strict `REQUIRE_FULL_PARITY` gate
|
||||
(vacuous while only en ships; each locale PR meets it from day one).
|
||||
- `src/i18n/markupCoverage.test.mjs` — every `data-i18n*` attribute in
|
||||
`index.html` must resolve in every shipped catalog; unknown attribute
|
||||
spellings fail loudly.
|
||||
- `src/i18n/repairPass.test.mjs` — byte-identity anchors for English
|
||||
literals; per-locale value anchors arrive with each locale PR.
|
||||
|
||||
Full-suite caveat: `src/devFreshDotenv.test.mjs`'s external-keys provenance
|
||||
test fails when a provider key (e.g. `OPENAI_API_KEY`) is exported in the
|
||||
running shell — an environmental false positive unrelated to i18n.
|
||||
Reference in new issue
Block a user