mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
Replace the semantic keys with the English source text, so code reads as the
UI does and English needs no catalog: t('Save keys'), tn(count, one, other)
for plurals, msg() for text stored in data, and bare data-i18n* markup that
translates the element's own English. Other languages are one flat JSON each.
- Simplify src/i18n: drop namespaces, the configurable locale pair
(GEV_DEFAULT_LOCALE / GEV_SECONDARY_LOCALE) and its build defines. Locale
comes from ?lang=, the stored choice, then browser languages.
- Add scripts/i18n.mjs (npm run i18n): extracts every message from t/tn/msg
and markup, and fails on missing, unused, placeholder-mismatched or
wrongly-shaped plural entries. npm test runs it via catalog.test.mjs.
- Add Russian (src/i18n/locales/ru.json, 833 messages), started from the
community catalog in #312 and reviewed against the current English.
- Fix data-i18n placed on parents that would wipe their children (cockpit
LEVEL and local weather cells, first-run EXPLORE MANUALLY tile), and a
doubled degree sign in the TRACK ACQUIRED signal.
- Rewrite docs/TRANSLATORS.md for the new workflow; drop sections the earlier
merge resurrected in docs/CURRENT-STATE.md.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
127 lines
4.1 KiB
JavaScript
127 lines
4.1 KiB
JavaScript
import { t } from '../i18n/index.js';
|
|
import { shouldExpandGlobalContextPanel } from '../rightRailPolicy.js';
|
|
|
|
export function _initGlobalContextPanel() {
|
|
const contextTabs = [
|
|
this._globalContextFlightsBtn,
|
|
this._globalContextMissionsBtn,
|
|
].filter(Boolean);
|
|
contextTabs.forEach((tab, index) =>
|
|
this.listen(tab, 'keydown', (event) => {
|
|
let nextIndex = null;
|
|
if (event.key === 'ArrowRight')
|
|
nextIndex = (index + 1) % contextTabs.length;
|
|
else if (event.key === 'ArrowLeft')
|
|
nextIndex = (index - 1 + contextTabs.length) % contextTabs.length;
|
|
else if (event.key === 'Home') nextIndex = 0;
|
|
else if (event.key === 'End') nextIndex = contextTabs.length - 1;
|
|
if (nextIndex === null) return;
|
|
event.preventDefault();
|
|
contextTabs[nextIndex].focus({ preventScroll: true });
|
|
contextTabs[nextIndex].click();
|
|
}),
|
|
);
|
|
this.listen(this._globalContextFlightsBtn, 'click', () => {
|
|
if (
|
|
this.destroyed ||
|
|
this._contextModeChanging ||
|
|
this._clearSelectedLayersPromise
|
|
)
|
|
return;
|
|
const nextMode = this._contextMode === 'flights' ? null : 'flights';
|
|
this._claimContextVisualAuthority();
|
|
void this._runUserFacingContextAction(
|
|
(notificationToken) =>
|
|
this._selectContextMode(nextMode, { notificationToken }),
|
|
t('Contacts could not complete the requested transition; try again'),
|
|
).then((succeeded) => {
|
|
if (
|
|
!this.destroyed &&
|
|
nextMode &&
|
|
shouldExpandGlobalContextPanel({
|
|
action: 'contacts',
|
|
explicitUserAction: true,
|
|
succeeded: succeeded === true,
|
|
})
|
|
)
|
|
this.actions.setPanelCollapsed('global-context-panel', false, {
|
|
explicit: true,
|
|
});
|
|
});
|
|
});
|
|
this.listen(this._globalContextMissionsBtn, 'click', () => {
|
|
if (
|
|
this.destroyed ||
|
|
this._contextModeChanging ||
|
|
this._clearSelectedLayersPromise
|
|
)
|
|
return;
|
|
const nextMode =
|
|
this._contextMode === 'space-missions' ? null : 'space-missions';
|
|
this._claimContextVisualAuthority();
|
|
void this._runUserFacingContextAction(
|
|
(notificationToken) =>
|
|
this._selectContextMode(nextMode, { notificationToken }),
|
|
t(
|
|
'Space Missions could not complete the requested transition; try again',
|
|
),
|
|
).then((succeeded) => {
|
|
if (
|
|
!this.destroyed &&
|
|
nextMode &&
|
|
shouldExpandGlobalContextPanel({
|
|
action: 'space-missions',
|
|
explicitUserAction: true,
|
|
succeeded: succeeded === true,
|
|
})
|
|
)
|
|
this.actions.setPanelCollapsed('global-context-panel', false, {
|
|
explicit: true,
|
|
});
|
|
});
|
|
});
|
|
this.listen(this._installationsSearchBtn, 'click', () => {
|
|
if (
|
|
this.destroyed ||
|
|
!this._dataManager?.layers?.has('military-installations')
|
|
)
|
|
return;
|
|
const button = this._installationsSearchBtn;
|
|
if (button.getAttribute('aria-busy') === 'true') return;
|
|
button.setAttribute('aria-disabled', 'true');
|
|
button.setAttribute('aria-busy', 'true');
|
|
void this._runUserFacingContextAction(async (notificationToken) => {
|
|
const enabled = await this._dataManager.setEnabled(
|
|
'military-installations',
|
|
true,
|
|
{
|
|
origin: 'user',
|
|
notificationToken,
|
|
},
|
|
);
|
|
if (
|
|
this.destroyed ||
|
|
enabled === false ||
|
|
!this._dataManager.isEnabled('military-installations')
|
|
)
|
|
return false;
|
|
const searched = await this.installations.searchNearby?.();
|
|
if (this.destroyed || searched === false) return false;
|
|
const stats = this.installations.getStats?.();
|
|
this.showToast(
|
|
stats?.statusMessage ||
|
|
(stats?.status === 'zoom-in'
|
|
? t('Zoom in to search mapped installations')
|
|
: t('Nearby installations refreshed')),
|
|
);
|
|
return true;
|
|
}, t('Nearby installations could not be refreshed; try again')).finally(
|
|
() => {
|
|
if (this.destroyed) return;
|
|
button.setAttribute('aria-disabled', 'false');
|
|
button.setAttribute('aria-busy', 'false');
|
|
},
|
|
);
|
|
});
|
|
}
|