mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-06-21 15:26:32 +03:00
build web with optional ui languages
This commit is contained in:
@@ -46,6 +46,38 @@ ${fileInfo.map((f) => `${INDENT}{"${f.uri}", "${f.mimeType}", ${f.variable}, ${f
|
||||
static constexpr size_t WWW_ASSETS_COUNT = sizeof(WWW_ASSETS) / sizeof(WWW_ASSETS[0]);
|
||||
`;
|
||||
|
||||
// Optional locale allow-list, shared with the Vite build via VITE_APP_LOCALES
|
||||
// (e.g. "en,de,nl"). When set, locale chunks outside the list are NOT embedded
|
||||
// into firmware flash. `en` is always kept as the fallback. Unset => embed all.
|
||||
const ALL_LOCALES = [
|
||||
'cz',
|
||||
'de',
|
||||
'en',
|
||||
'fr',
|
||||
'it',
|
||||
'nl',
|
||||
'no',
|
||||
'pl',
|
||||
'sk',
|
||||
'sv',
|
||||
'tr'
|
||||
];
|
||||
const localeAllowList = (process.env.VITE_APP_LOCALES || '')
|
||||
.split(',')
|
||||
.map((locale) => locale.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
const isExcludedLocaleChunk = (relativeFilePath) => {
|
||||
if (localeAllowList.length === 0) return false;
|
||||
const base = relativeFilePath.split(sep).pop();
|
||||
const match = /^([a-z]{2})-[A-Za-z0-9_-]+\.js$/.exec(base);
|
||||
if (!match) return false;
|
||||
const code = match[1];
|
||||
// Only treat known locale codes as locale chunks; never drop the en fallback.
|
||||
if (!ALL_LOCALES.includes(code) || code === 'en') return false;
|
||||
return !localeAllowList.includes(code);
|
||||
};
|
||||
|
||||
const getFilesSync = (dir, files = []) => {
|
||||
readdirSync(dir, { withFileTypes: true }).forEach((entry) => {
|
||||
const entryPath = resolve(dir, entry.name);
|
||||
@@ -116,7 +148,12 @@ writeStream.write(ARDUINO_INCLUDES);
|
||||
|
||||
const buildPath = resolve(sourcePath);
|
||||
for (const filePath of getFilesSync(buildPath)) {
|
||||
writeFile(relative(buildPath, filePath), readFileSync(filePath));
|
||||
const relativeFilePath = relative(buildPath, filePath);
|
||||
if (isExcludedLocaleChunk(relativeFilePath)) {
|
||||
console.log(`Skipping locale (not in VITE_APP_LOCALES): ${relativeFilePath}`);
|
||||
continue;
|
||||
}
|
||||
writeFile(relativeFilePath, readFileSync(filePath));
|
||||
}
|
||||
|
||||
writeStream.write(generateWWWClass());
|
||||
|
||||
@@ -9,7 +9,7 @@ import type { Locales } from 'i18n/i18n-types';
|
||||
import { loadLocaleAsync } from 'i18n/i18n-util.async';
|
||||
import { detectLocale, navigatorDetector } from 'typesafe-i18n/detectors';
|
||||
|
||||
const AVAILABLE_LOCALES = [
|
||||
const ALL_LOCALES = [
|
||||
'de',
|
||||
'en',
|
||||
'it',
|
||||
@@ -23,6 +23,20 @@ const AVAILABLE_LOCALES = [
|
||||
'cz'
|
||||
] as Locales[];
|
||||
|
||||
// Optional build-time allow-list (e.g. VITE_APP_LOCALES="en,de,nl"). When unset,
|
||||
// every locale is available. `en` is always kept as the fallback locale, and the
|
||||
// progmem generator embeds the matching subset into firmware flash.
|
||||
const localeAllowList = (import.meta.env.VITE_APP_LOCALES ?? '')
|
||||
.split(',')
|
||||
.map((locale) => locale.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
const AVAILABLE_LOCALES: Locales[] = localeAllowList.length
|
||||
? ALL_LOCALES.filter(
|
||||
(locale) => locale === 'en' || localeAllowList.includes(locale)
|
||||
)
|
||||
: ALL_LOCALES;
|
||||
|
||||
const App = memo(() => {
|
||||
const [wasLoaded, setWasLoaded] = useState(false);
|
||||
const [locale, setLocale] = useState<Locales>('en');
|
||||
@@ -30,7 +44,12 @@ const App = memo(() => {
|
||||
useEffect(() => {
|
||||
const initializeLocale = async () => {
|
||||
const browserLocale = detectLocale('en', AVAILABLE_LOCALES, navigatorDetector);
|
||||
const newLocale = (localStorage.getItem('lang') || browserLocale) as Locales;
|
||||
const stored = localStorage.getItem('lang');
|
||||
// Ignore a stored locale that isn't available (e.g. trimmed from this build).
|
||||
const newLocale =
|
||||
stored && AVAILABLE_LOCALES.includes(stored as Locales)
|
||||
? (stored as Locales)
|
||||
: browserLocale;
|
||||
localStorage.setItem('lang', newLocale);
|
||||
setLocale(newLocale);
|
||||
await loadLocaleAsync(newLocale);
|
||||
|
||||
12
interface/src/vite-env.d.ts
vendored
12
interface/src/vite-env.d.ts
vendored
@@ -1 +1,13 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
interface ImportMetaEnv {
|
||||
// Optional comma-separated allow-list of locales to ship (e.g. "en,de,nl").
|
||||
// Unset => all locales are bundled and embedded. `en` is always kept as the
|
||||
// fallback. Consumed by App.tsx (UI language list) and progmem-generator.js
|
||||
// (which locale chunks get embedded into firmware flash).
|
||||
readonly VITE_APP_LOCALES?: string;
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user