fix(dev): veralteten PWA-Cache bereinigen, damit i18n-Labels laden
Stale Service-Worker-Precache konnte Vite-Module und Locale-Bundles überlagern, sodass Kompass-Dial-Texte als Roh-i18n-Keys erschienen. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -48,7 +48,7 @@ export function usePwaUpdate() {
|
||||
needRefresh: [needRefresh, setNeedRefresh],
|
||||
updateServiceWorker
|
||||
} = useRegisterSW({
|
||||
immediate: true,
|
||||
immediate: !import.meta.env.DEV,
|
||||
onNeedReload() {
|
||||
clearUpdateSuppression()
|
||||
setNeedRefresh(false)
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import deJson from './locales/de.json'
|
||||
import enJson from './locales/en.json'
|
||||
|
||||
const resources = {
|
||||
de: { translation: deJson.translation },
|
||||
en: { translation: enJson.translation }
|
||||
}
|
||||
|
||||
describe('course dial i18n keys', () => {
|
||||
it.each([
|
||||
'logs.event_course_section',
|
||||
'logs.course_tab_mgk',
|
||||
'logs.course_tab_rwk',
|
||||
'logs.course_dial_hint',
|
||||
'logs.course_step_fine',
|
||||
'logs.wind_mode_cardinal'
|
||||
])('resolves %s in de and en bundles', async (key) => {
|
||||
const { default: i18n } = await import('i18next')
|
||||
await i18n.init({ lng: 'de', resources, defaultNS: 'translation' })
|
||||
expect(i18n.t(key)).not.toBe(key)
|
||||
await i18n.changeLanguage('en')
|
||||
expect(i18n.t(key)).not.toBe(key)
|
||||
})
|
||||
})
|
||||
@@ -1,19 +1,26 @@
|
||||
import i18n from 'i18next'
|
||||
import { initReactI18next } from 'react-i18next'
|
||||
import LanguageDetector from 'i18next-browser-languagedetector'
|
||||
import enTranslation from './locales/en.json'
|
||||
import deTranslation from './locales/de.json'
|
||||
import enJson from './locales/en.json'
|
||||
import deJson from './locales/de.json'
|
||||
import { initSeo } from '../utils/seo.js'
|
||||
|
||||
/** JSON files wrap strings in `translation` — register that namespace explicitly. */
|
||||
const resources = {
|
||||
en: { translation: enJson.translation },
|
||||
de: { translation: deJson.translation }
|
||||
}
|
||||
|
||||
i18n
|
||||
.use(LanguageDetector)
|
||||
.use(initReactI18next)
|
||||
.init({
|
||||
resources: {
|
||||
en: enTranslation,
|
||||
de: deTranslation
|
||||
},
|
||||
resources,
|
||||
defaultNS: 'translation',
|
||||
fallbackLng: 'en',
|
||||
supportedLngs: ['de', 'en'],
|
||||
nonExplicitSupportedLngs: true,
|
||||
load: 'languageOnly',
|
||||
interpolation: {
|
||||
escapeValue: false // React already escapes values (prevents XSS)
|
||||
},
|
||||
|
||||
+18
-3
@@ -3,14 +3,29 @@ import { createRoot } from 'react-dom/client'
|
||||
import 'leaflet/dist/leaflet.css'
|
||||
import './themes.css'
|
||||
import './index.css'
|
||||
import App from './App.tsx'
|
||||
import './i18n'
|
||||
import { applyAppearanceToDocument } from './services/appearance.ts'
|
||||
|
||||
applyAppearanceToDocument()
|
||||
/** Stale PWA precache on localhost can shadow Vite dev modules and old locale bundles. */
|
||||
async function clearDevServiceWorkerCaches(): Promise<void> {
|
||||
if (!import.meta.env.DEV || !('serviceWorker' in navigator)) return
|
||||
const regs = await navigator.serviceWorker.getRegistrations()
|
||||
await Promise.all(regs.map((r) => r.unregister()))
|
||||
if ('caches' in window) {
|
||||
const keys = await caches.keys()
|
||||
await Promise.all(keys.map((k) => caches.delete(k)))
|
||||
}
|
||||
}
|
||||
|
||||
async function bootstrap(): Promise<void> {
|
||||
await clearDevServiceWorkerCaches()
|
||||
await import('./i18n')
|
||||
const { default: App } = await import('./App.tsx')
|
||||
applyAppearanceToDocument()
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</StrictMode>,
|
||||
)
|
||||
}
|
||||
|
||||
void bootstrap()
|
||||
|
||||
@@ -47,6 +47,9 @@ export default defineConfig({
|
||||
srcDir: 'src',
|
||||
filename: 'sw.ts',
|
||||
registerType: 'prompt',
|
||||
devOptions: {
|
||||
enabled: false
|
||||
},
|
||||
includeAssets: ['favicon.ico', 'logo.png'],
|
||||
injectManifest: {
|
||||
globPatterns: ['**/*.{js,css,html,ico,png,svg,woff2,webmanifest}']
|
||||
|
||||
Reference in New Issue
Block a user