mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 10:53:59 +00:00
feat(i18n): presentation extraction — t() call sites, data-i18n templates, locale selector
Route every application-owned presentation string through the i18n core: t() call sites across the app/layers/ui/data/voice surfaces, data-i18n* attributes in the src/ui/templates/*.html markup (applied at boot by applyDocumentTranslations from src/standalone/application.js), and the dock locale selector (runtime-rendered from the offered pair — a single EN button while only English ships). Rebased onto current main, where the extraction follows the module splits: the shell wiring now lands in the owner modules (panelChrome, visualSettings, locationNavigation, shareRestoration, shellFeedback, applicationShell) and the voice status corpus in the realtime* modules; scene status lives in director.js + playbackAdapter.js. Modules shared with the node runtime (loadingFeedback, installationFeedback, regionalModel, keySetupCore, vessels ingestion) stay environment-neutral English and localize at their browser render sites (chip maps in shellFeedback/installations controls, the weather table in cockpitBriefing, keySetupRequirementEnvVars compositions), so the package-boundary graph stays clean; the browser boundary groups now own the i18n modules they reach (scripts/package-boundaries.json).
This commit is contained in:
1 parent
bde1e430ef
commit
284c4d4601
98 files changed
+3474
-1625
No files matched your search
+38
-19
@@ -16,12 +16,20 @@ import { createSurfaceKeyboard } from './ui/surfaceKeyboard.js';
|
||||
* the chip and the dialog are removed outright.
|
||||
*/
|
||||
|
||||
/** Chip label — pure, exported for tests. */
|
||||
import { t, hasMessage } from './i18n/index.js';
|
||||
|
||||
/**
|
||||
* Chip label — pure, exported for tests. The exact English values are pinned
|
||||
* by keySetup.test.mjs; t() resolves them from the catalog, so the default
|
||||
* locale renders byte-identical text and 'es' localizes at the same site.
|
||||
* @param {{total?: number, setCount?: number}|null} status
|
||||
* @returns {string}
|
||||
*/
|
||||
export function keySetupChipLabel(status) {
|
||||
const missing = Math.max(0, (status?.total || 0) - (status?.setCount || 0));
|
||||
return missing > 0
|
||||
? `POWER UP · ${missing} ${missing === 1 ? 'KEY' : 'KEYS'} WAITING`
|
||||
: 'POWERED UP';
|
||||
? t('setup.keySetup.chipWaiting', { count: missing })
|
||||
: t('setup.keySetup.chipReady');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,7 +121,10 @@ function buildRow(documentRef, key) {
|
||||
|
||||
const unlocks = documentRef.createElement('p');
|
||||
unlocks.className = 'key-setup-unlocks';
|
||||
unlocks.textContent = key.unlocks;
|
||||
// The registry `unlocks` text localizes per registry id; an id missing from
|
||||
// the catalog falls back to the server-provided English copy.
|
||||
const unlocksKey = `setup.keySetup.unlocks.${key.id}`;
|
||||
unlocks.textContent = hasMessage(unlocksKey) ? t(unlocksKey) : key.unlocks;
|
||||
|
||||
row.append(head, unlocks);
|
||||
if (!external) {
|
||||
@@ -138,8 +149,8 @@ function buildRow(documentRef, key) {
|
||||
remove.type = 'button';
|
||||
remove.className = 'key-setup-remove';
|
||||
remove.dataset.keySetupRemove = JSON.stringify(key.envVars);
|
||||
remove.textContent = 'REMOVE';
|
||||
remove.title = `Remove ${key.title} from this app's saved keys`;
|
||||
remove.textContent = t('setup.keySetup.row.remove');
|
||||
remove.title = t('setup.keySetup.row.removeTitle', { title: key.title });
|
||||
fields.append(remove);
|
||||
}
|
||||
row.append(fields);
|
||||
@@ -284,17 +295,19 @@ export async function initKeySetup({
|
||||
|
||||
const storeLabel = () =>
|
||||
status?.store === 'pinokio-environment'
|
||||
? 'your app configuration'
|
||||
: 'your local .env';
|
||||
? t('setup.keySetup.store.pinokio')
|
||||
: t('setup.keySetup.store.env');
|
||||
|
||||
const submitUpdates = async (updates, doneVerb) => {
|
||||
// doneMessageKey names the whole saved/removed sentence; the storage
|
||||
// destination is interpolated so the {store} phrase stays one spelling.
|
||||
const submitUpdates = async (updates, doneMessageKey) => {
|
||||
if (disposed || busy) return;
|
||||
const googleWasUnset = !status?.keys?.find(
|
||||
(key) => key.id === 'google-maps',
|
||||
)?.set;
|
||||
busy = true;
|
||||
applyButton?.setAttribute('aria-disabled', 'true');
|
||||
say('Saving…');
|
||||
say(t('setup.keySetup.status.saving'));
|
||||
try {
|
||||
const response = await doFetch('/api/setup/keys', {
|
||||
method: 'POST',
|
||||
@@ -305,7 +318,11 @@ export async function initKeySetup({
|
||||
const payload = await response.json().catch(() => ({}));
|
||||
if (disposed) return;
|
||||
if (!response.ok || !payload.ok) {
|
||||
say(payload.error || `Save failed (${response.status}).`);
|
||||
// payload.error is a server-authored message (API value) — shown as-is.
|
||||
say(
|
||||
payload.error ||
|
||||
t('setup.keySetup.status.saveFailed', { status: response.status }),
|
||||
);
|
||||
return;
|
||||
}
|
||||
for (const input of root.querySelectorAll('input[data-env-var]'))
|
||||
@@ -331,11 +348,13 @@ export async function initKeySetup({
|
||||
signal: lifetime.signal,
|
||||
});
|
||||
}
|
||||
say(
|
||||
`${doneVerb} ${storeLabel()}. Restarting — this page reloads itself.`,
|
||||
);
|
||||
say(t(doneMessageKey, { store: storeLabel() }));
|
||||
} catch (error) {
|
||||
say(`Save failed: ${error?.message || error}`);
|
||||
say(
|
||||
t('setup.keySetup.status.saveFailedDetail', {
|
||||
detail: error?.message || error,
|
||||
}),
|
||||
);
|
||||
} finally {
|
||||
busy = false;
|
||||
applyButton?.setAttribute('aria-disabled', 'false');
|
||||
@@ -352,10 +371,10 @@ export async function initKeySetup({
|
||||
})),
|
||||
);
|
||||
if (!Object.keys(updates).length) {
|
||||
say('Paste at least one key first.');
|
||||
say(t('setup.keySetup.status.pasteFirst'));
|
||||
return;
|
||||
}
|
||||
await submitUpdates(updates, 'Saved to');
|
||||
await submitUpdates(updates, 'setup.keySetup.status.saved');
|
||||
};
|
||||
|
||||
chip.addEventListener('click', openDialog);
|
||||
@@ -377,11 +396,11 @@ export async function initKeySetup({
|
||||
// a deliberate two-step the lure cannot pre-satisfy.
|
||||
const ok =
|
||||
typeof globalThis.confirm !== 'function' ||
|
||||
globalThis.confirm('Remove this key from your saved configuration?');
|
||||
globalThis.confirm(t('setup.keySetup.confirm.remove'));
|
||||
if (!ok) return;
|
||||
void submitUpdates(
|
||||
Object.fromEntries(envVars.map((name) => [name, null])),
|
||||
'Removed from',
|
||||
'setup.keySetup.status.removed',
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user