Public Access
fix(ui): stop old translations and page shrink on Android
The translation files get a content version in their URL, so a browser that cached an old file loads the new one. On touch screens the scroll lock of menus and selects no longer adds a right margin: Android Chrome reported one and the whole page became narrower.
This commit is contained in:
1 parent
6edb53162e
commit
25d2f0d0bd
4 files changed
+49
-1
No files matched your search
+2
-1
@@ -9,7 +9,8 @@ i18n.use(HttpBackend)
|
|||||||
lng: 'de',
|
lng: 'de',
|
||||||
fallbackLng: 'en',
|
fallbackLng: 'en',
|
||||||
backend: {
|
backend: {
|
||||||
loadPath: '/i18n/{{lng}}.json',
|
// A browser kept an old file without its Cache-Control and showed raw keys; a new URL per version avoids that.
|
||||||
|
loadPath: `/i18n/{{lng}}.json?v=${__TRANSLATIONS_VERSION__}`,
|
||||||
},
|
},
|
||||||
interpolation: {
|
interpolation: {
|
||||||
escapeValue: false
|
escapeValue: false
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import {createHash} from 'node:crypto';
|
||||||
|
import {readdirSync, readFileSync} from 'node:fs';
|
||||||
|
import path from 'node:path';
|
||||||
|
import {describe, expect, it, vi} from 'vitest';
|
||||||
|
|
||||||
|
vi.mock('i18next-http-backend', () => ({
|
||||||
|
default: {type: 'backend', init() {}, read(language, namespace, callback) { callback(null, {}); }},
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('translation files', () => {
|
||||||
|
it('are loaded under a URL that changes with their content, so no browser keeps an old copy', async () => {
|
||||||
|
const {default: i18n} = await import('./i18n.js');
|
||||||
|
const loadPath = i18n.options.backend.loadPath;
|
||||||
|
|
||||||
|
const dir = path.resolve(import.meta.dirname, '../public/i18n');
|
||||||
|
const hash = createHash('sha256');
|
||||||
|
for (const file of readdirSync(dir).filter((name) => name.endsWith('.json')).sort()) {
|
||||||
|
hash.update(readFileSync(path.join(dir, file)));
|
||||||
|
}
|
||||||
|
expect(loadPath).toBe(`/i18n/{{lng}}.json?v=${hash.digest('hex').slice(0, 12)}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -191,3 +191,12 @@
|
|||||||
@apply bg-background text-foreground antialiased;
|
@apply bg-background text-foreground antialiased;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Radix menus and selects lock the page scroll and add a right margin as wide as the scrollbar, measured as
|
||||||
|
innerWidth minus the page width. Android Chrome can report a larger innerWidth, and then the whole page shrinks.
|
||||||
|
Touch screens have no scrollbar to make room for. */
|
||||||
|
@media (pointer: coarse) {
|
||||||
|
html body[data-scroll-locked] {
|
||||||
|
margin-right: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,29 @@
|
|||||||
|
import {createHash} from 'node:crypto';
|
||||||
|
import {readdirSync, readFileSync} from 'node:fs';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
import react from '@vitejs/plugin-react';
|
import react from '@vitejs/plugin-react';
|
||||||
import tailwindcss from '@tailwindcss/vite';
|
import tailwindcss from '@tailwindcss/vite';
|
||||||
|
|
||||||
|
const translationsDir = path.resolve(import.meta.dirname, 'public/i18n');
|
||||||
|
|
||||||
|
// Changes whenever a translation changes, so the browser loads the new file under a new URL.
|
||||||
|
const translationsVersion = () => {
|
||||||
|
const hash = createHash('sha256');
|
||||||
|
for (const file of readdirSync(translationsDir).filter((name) => name.endsWith('.json')).sort()) {
|
||||||
|
hash.update(readFileSync(path.join(translationsDir, file)));
|
||||||
|
}
|
||||||
|
return hash.digest('hex').slice(0, 12);
|
||||||
|
};
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [
|
plugins: [
|
||||||
react(),
|
react(),
|
||||||
tailwindcss(),
|
tailwindcss(),
|
||||||
],
|
],
|
||||||
|
define: {
|
||||||
|
__TRANSLATIONS_VERSION__: JSON.stringify(translationsVersion()),
|
||||||
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'@': path.resolve(import.meta.dirname, './src'),
|
'@': path.resolve(import.meta.dirname, './src'),
|
||||||
|
|||||||
Reference in new issue
Block a user