mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
i18n: fix review findings and polish ru/es strings
Fixes the 51 P0–P2 findings from the full review of the i18n branch and the issues found while checking every new string on screen in ru and es. - Translate errors and statuses that still reached ru/es in English: feed and tile errors, provider statuses, the ALPR chip, the traffic mode chip, voice plan step labels, fire feed values, receiver bands, scene save reasons and the Cesium attribution link. - Show preset city names in the UI language (src/ui/placeNames.js); data and everything sent to the model stay English. - Share layer names between the layer panel, HUD and voice card (src/ui/layerNames.js). - Keep long ru/es strings whole: voice card error lines, analyst titles, the voice tier status, the Nepal evidence button, the ALPR retry chip. English layout is unchanged. - Ask before a language switch drops unsaved work. - Catalog fixes: glossary terms (пуск, пресет), gender agreement and consistent "peticiones" in es, fewer calques in both languages. - Fix English text that was itself wrong (e.g. "Exit cockpit to fly to a weather", raw tool ids in voice plan steps). Catalogs: es/ru 2535 messages each, complete. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
8029747b7e
commit
00704ddc89
212 files changed
+9871
-909
No files matched your search
@@ -4,6 +4,8 @@ const STATUS_URL = 'https://www.nhc.noaa.gov/CurrentStorms.json';
|
||||
const GIS =
|
||||
'https://mapservices.weather.noaa.gov/tropical/rest/services/tropical/NHC_tropical_weather_summary/MapServer';
|
||||
const HOUR = 3600_000;
|
||||
// Data, not UI copy: src/layers/cyclones/index.js keeps the same English in
|
||||
// msg() and translates it when shown (likewise 'Cyclone data unavailable').
|
||||
const COVERAGE =
|
||||
'Atlantic and eastern/central North Pacific; not worldwide cyclone coverage.';
|
||||
const LAYERS = [
|
||||
|
||||
@@ -3,6 +3,10 @@ import { fetchIfsWind } from './wind/ifs.js';
|
||||
import { decodeWindGribMessage } from './wind/decode.js';
|
||||
import { weatherScalarMetadata, weatherScalarError } from './wind/grid.js';
|
||||
|
||||
// Data, not UI copy: the client (src/layers/wind/index.js) marks this exact
|
||||
// English with msg() and translates it when shown, so keep the two in sync.
|
||||
const UPSTREAM_UNAVAILABLE = 'Wind upstream unavailable';
|
||||
|
||||
/** Serve bounded, single-flight, per-model/overlay forecast snapshots from fixed providers. */
|
||||
export function windProxy({
|
||||
fetchImpl = fetch,
|
||||
@@ -25,7 +29,7 @@ export function windProxy({
|
||||
...(overlay === 'none' ? {} : { overlay }),
|
||||
unavailable: true,
|
||||
stale: true,
|
||||
reason: 'Wind upstream unavailable',
|
||||
reason: UPSTREAM_UNAVAILABLE,
|
||||
},
|
||||
});
|
||||
const sendJson = (res, value, status = 200) => {
|
||||
@@ -139,7 +143,7 @@ export function windProxy({
|
||||
old.manifest = {
|
||||
...old.manifest,
|
||||
stale: true,
|
||||
reason: 'Wind upstream unavailable',
|
||||
reason: UPSTREAM_UNAVAILABLE,
|
||||
};
|
||||
return old;
|
||||
}
|
||||
|
||||
@@ -134,6 +134,9 @@ function keySetupEndpoint({ sourceRoot = defaultSourceRoot } = {}) {
|
||||
};
|
||||
// The gate itself is pure and unit-tested (admitKeySetupRequest in
|
||||
// src/keySetupCore.mjs) — this just feeds it the request.
|
||||
// A refusal as the panel reads it: `code` (and `params`) pick its localized
|
||||
// sentence in src/keySetup.js; `error` is the English for logs and scripts.
|
||||
const refusal = ({ error, code, params }) => ({ error, code, params });
|
||||
const admit = (req) =>
|
||||
admitKeySetupRequest({
|
||||
method: req.method,
|
||||
@@ -247,18 +250,24 @@ function keySetupEndpoint({ sourceRoot = defaultSourceRoot } = {}) {
|
||||
configureServer(server) {
|
||||
server.middlewares.use('/api/setup/status', (req, res) => {
|
||||
if (req.method !== 'GET')
|
||||
return respond(res, 405, { error: 'Method not allowed' });
|
||||
return respond(res, 405, {
|
||||
error: 'Method not allowed',
|
||||
code: 'method',
|
||||
});
|
||||
const admission = admit(req);
|
||||
if (!admission.ok)
|
||||
return respond(res, admission.status, { error: admission.error });
|
||||
return respond(res, admission.status, refusal(admission));
|
||||
respond(res, 200, providerStatus());
|
||||
});
|
||||
server.middlewares.use('/api/setup/keys', (req, res) => {
|
||||
if (req.method !== 'POST')
|
||||
return respond(res, 405, { error: 'Method not allowed' });
|
||||
return respond(res, 405, {
|
||||
error: 'Method not allowed',
|
||||
code: 'method',
|
||||
});
|
||||
const admission = admit(req);
|
||||
if (!admission.ok)
|
||||
return respond(res, admission.status, { error: admission.error });
|
||||
return respond(res, admission.status, refusal(admission));
|
||||
let body = '';
|
||||
let overflowed = false;
|
||||
req.on('data', (chunk) => {
|
||||
@@ -270,15 +279,21 @@ function keySetupEndpoint({ sourceRoot = defaultSourceRoot } = {}) {
|
||||
});
|
||||
req.on('end', () => {
|
||||
if (overflowed)
|
||||
return respond(res, 413, { error: 'Request too large' });
|
||||
return respond(res, 413, {
|
||||
error: 'Request too large',
|
||||
code: 'too-large',
|
||||
});
|
||||
let parsed;
|
||||
try {
|
||||
parsed = JSON.parse(body || '{}');
|
||||
} catch {
|
||||
return respond(res, 400, { error: 'Invalid JSON' });
|
||||
return respond(res, 400, {
|
||||
error: 'Invalid JSON',
|
||||
code: 'invalid-json',
|
||||
});
|
||||
}
|
||||
const verdict = validateKeySetupUpdates(parsed);
|
||||
if (!verdict.ok) return respond(res, 400, { error: verdict.error });
|
||||
if (!verdict.ok) return respond(res, 400, refusal(verdict));
|
||||
// Neither a replace NOR a removal may touch an externally-supplied
|
||||
// credential (shell env, Keychain, another workflow). This backs the
|
||||
// UI's read-only "configured externally" state with a real contract —
|
||||
@@ -289,6 +304,8 @@ function keySetupEndpoint({ sourceRoot = defaultSourceRoot } = {}) {
|
||||
if (isExternallyManaged(name, inStore)) {
|
||||
return respond(res, 409, {
|
||||
error: `${name} is configured outside Provider Settings and can only be changed where it was set`,
|
||||
code: 'external',
|
||||
params: { name },
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -305,10 +322,16 @@ function keySetupEndpoint({ sourceRoot = defaultSourceRoot } = {}) {
|
||||
) {
|
||||
return respond(res, 500, {
|
||||
error: `The key was not saved: ${error.message}`,
|
||||
code:
|
||||
error.code === 'GEV_HARDEN_FAILED'
|
||||
? 'harden-failed'
|
||||
: 'store-unreadable',
|
||||
});
|
||||
}
|
||||
return respond(res, 500, {
|
||||
error: `Could not write the ${storeName()} store`,
|
||||
code: 'write-failed',
|
||||
params: { store: storeName() },
|
||||
});
|
||||
}
|
||||
// Live for the server-side proxies immediately; the restart below is
|
||||
|
||||
Reference in new issue
Block a user