config: optional defaults.lang to pin a default UI language
When set (and the user hasn't explicitly chosen one), it overrides browser detection after the runtime config loads. Omitted = auto-detect as before.
This commit is contained in:
parent
ed2744ef8c
commit
5d5b54cfc4
4 changed files with 17 additions and 2 deletions
|
|
@ -1,7 +1,7 @@
|
|||
// Tchatou service worker — installable PWA + offline app shell.
|
||||
// Scope: /app/. Only handles same-origin /app/ GETs; the IRC websocket and all
|
||||
// API calls (cloudflare, change_password, upload) pass straight through.
|
||||
const CACHE = 'tchatou-v50';
|
||||
const CACHE = 'tchatou-v51';
|
||||
const SHELL = ['/app/', '/app/index.html', '/app/favicon.svg', '/app/orbit-icon.svg', '/app/manifest.webmanifest'];
|
||||
|
||||
self.addEventListener('install', (e) => {
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ export interface AppConfig {
|
|||
sound: boolean; // blip on mention / PM
|
||||
hideJoinQuit: boolean; // hide join/part/quit noise
|
||||
clock24: boolean; // 24h timestamps
|
||||
lang?: string; // force a default UI language (e.g. 'en'); omit to auto-detect from the browser
|
||||
};
|
||||
/** Feature switches — turn whole features off for a deployment. */
|
||||
features: {
|
||||
|
|
|
|||
|
|
@ -65,6 +65,18 @@ void i18n.use(initReactI18next).init({
|
|||
|
||||
document.documentElement.lang = i18n.language;
|
||||
|
||||
// Apply a deployment's default UI language (config.defaults.lang) — but only for
|
||||
// users who haven't explicitly picked one (setLang writes KEY). Called after the
|
||||
// runtime config loads, so it can override the browser-detected language.
|
||||
export function applyConfigDefaultLang(code?: string): void {
|
||||
if (!code) return;
|
||||
if (localStorage.getItem(KEY)) return; // explicit user choice — honour it
|
||||
if (!CODES.includes(code)) return; // unknown language — ignore
|
||||
if (i18n.language === code) return;
|
||||
void i18n.changeLanguage(code);
|
||||
document.documentElement.lang = code;
|
||||
}
|
||||
|
||||
export function getLang(): string {
|
||||
return i18n.language;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ import { StrictMode } from 'react'
|
|||
import { createRoot } from 'react-dom/client'
|
||||
import { applyTheme, getTheme } from './ui/theme.ts'
|
||||
import './i18n'
|
||||
import { applyConfigDefaultLang } from './i18n'
|
||||
import './index.css'
|
||||
import { initViewport } from './ui/viewport.ts'
|
||||
import { loadConfig } from './config.ts'
|
||||
import { loadConfig, getConfig } from './config.ts'
|
||||
|
||||
// Track the visual viewport so the layout shrinks above the on-screen keyboard.
|
||||
initViewport()
|
||||
|
|
@ -14,6 +15,7 @@ initViewport()
|
|||
// a rebuild.
|
||||
loadConfig().then(async () => {
|
||||
applyTheme(getTheme()) // re-apply now that config (default theme) is loaded
|
||||
applyConfigDefaultLang(getConfig().defaults.lang) // honour a config-pinned default language
|
||||
const { default: App } = await import('./App.tsx') // also creates the store
|
||||
// Plugin subsystem: publish window.Orbit, bridge app/IRC events onto the bus,
|
||||
// then load operator-listed plugins from config. After the store exists,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue