better code: moved language logic server-side
Massimo Melina committed
Apr 5, 2023 at 10:46 UTC
83252315f6bb57ca8b168ab7670751789f4c431b
4 files changed
+31
-38
frontend/src/i18n.ts
+2
-9
@@ -14,16 +14,9 @@ export function useI18N() {
14
}
15
16
export function I18Nprovider({ embedded='en', ...props }) {
17
- const langs = urlParams.lang?.split(',') || navigator.languages
17
+ loaded = getHFS().lang
18
state.embedded = embedded
19
- let all = useApi(!getHFS().lang && langs[0] !== embedded && 'load_lang', { embedded, lang: langs }, { noModal: true })
20
- ?? getHFS().lang
21
- useEffect(() => {
22
- if (all instanceof Error)
23
- all = undefined
24
- state.langs = Object.keys(all||{})
25
- loaded = all
26
- }, [all])
19
+ state.langs = Object.keys(loaded||{})
20
return h(Fragment, props)
21
}
22
src/api.lang.ts
+25
-3
@@ -5,12 +5,14 @@ import _ from 'lodash'
5
import glob from 'fast-glob'
6
import { readFile, rm, writeFile } from 'fs/promises'
7
import { HTTP_BAD_REQUEST, HTTP_NOT_ACCEPTABLE, HTTP_SERVER_ERROR } from './const'
8
-import { tryJson } from './misc'
8
+import { tryJson, wantArray } from './misc'
9
import { defineConfig } from './config'
10
import { watchLoad } from './watchLoad'
11
+import Koa from 'koa'
12
13
const PREFIX = 'hfs-lang-'
14
const SUFFIX = '.json'
15
+const EMBEDDED = 'en'
16
17
const apis: ApiHandlers = {
18
@@ -69,8 +71,28 @@ function validateCode(code: string) {
71
throw new ApiError(HTTP_BAD_REQUEST, 'bad code/filename')
72
}
73
72
-export function getForceLangData() {
73
- return forceLangData
74
+export async function getLangData(ctx: Koa.Context) {
75
+ if (forceLangData)
76
+ return forceLangData
77
+ const ret: any = {}
78
+ const csv = String(ctx.query.lang||'') || ctx.get('Accept-Language') || ''
79
+ const langs = wantArray(csv.split(',').map(x => x.toLowerCase()))
80
+ let i = 0
81
+ while (i < langs.length) {
82
+ let k = langs[i] || '' // shut up ts
83
+ if (!k || k === EMBEDDED) break
84
+ try { ret[k!] = JSON.parse(await readFile(`hfs-lang-${k}.json`, 'utf8')) }
85
+ catch {
86
+ do { k = k.substring(0, k.lastIndexOf('-'))
87
+ } while (k && langs.includes(k))
88
+ if (k) {
89
+ langs[i] = k // overwrite and retry
90
+ continue
91
+ }
92
+ }
93
+ i++
94
+ }
95
+ return ret
96
}
97
98
let forceLangData: any
src/frontEndApis.ts
+1
-23
@@ -16,9 +16,8 @@ import {
16
HTTP_UNAUTHORIZED
17
} from './const'
18
import { hasPermission, urlToNode } from './vfs'
19
-import { mkdir, readFile, rm } from 'fs/promises'
19
+import { mkdir, rm } from 'fs/promises'
20
import { join } from 'path'
21
-import { wantArray } from './misc'
21
22
export const customHeader = defineConfig('custom_header', '')
23
@@ -73,27 +72,6 @@ export const frontEndApis: ApiHandlers = {
72
}
73
},
74
76
- async load_lang({ lang, embedded }) {
77
- const ret: any = {}
78
- const langs = wantArray(lang).map(x => x.toLowerCase())
79
- let i = 0
80
- while (i < langs.length) {
81
- let x = langs[i]
82
- if (x === embedded) break
83
- try { ret[x] = JSON.parse(await readFile(`hfs-lang-${x}.json`, 'utf8')) }
84
- catch {
85
- do { x = x.substring(0, x.lastIndexOf('-'))
86
- } while (x && langs.includes(x))
87
- if (x) {
88
- langs[i] = x // overwrite and retry
89
- continue
90
- }
91
- }
92
- i++
93
- }
94
- return ret
95
- }
96
-
75
}
76
77
export function notifyClient(ctx: Koa.Context, name: string, data: any) {
src/serveGuiFiles.ts
+3
-3
@@ -23,8 +23,7 @@ import { subscribe } from 'valtio'
23
import { customHtmlState, getSection } from './customHtml'
24
import _ from 'lodash'
25
import { defineConfig } from './config'
26
-import { watchLoad } from './watchLoad'
27
-import { getForceLangData } from './api.lang'
26
+import { getLangData } from './api.lang'
27
28
// in case of dev env we have our static files within the 'dist' folder'
29
const DEV_STATIC = process.env.DEV ? 'dist/' : ''
@@ -90,6 +89,7 @@ async function treatIndex(ctx: Koa.Context, filesUri: string, body: string) {
89
configs = getPluginInfo(name).onFrontendConfig?.(configs) || configs
90
return !_.isEmpty(configs) && [name, configs]
91
})))
92
+ const lang = await getLangData(ctx)
93
let ret = body
94
.replace(/((?:src|href) *= *['"])\/?(?![a-z]+:\/\/)/g, '$1' + ctx.state.revProxyPath + filesUri)
95
.replace('</head>', () => `
@@ -108,7 +108,7 @@ async function treatIndex(ctx: Koa.Context, filesUri: string, body: string) {
108
customHtml: _.omit(Object.fromEntries(customHtmlState.sections),
109
['top','bottom']), // excluding sections we apply in this phase
110
fileMenuOnLink: fileMenuOnLink.get(),
111
- lang: getForceLangData()
111
+ lang
112
}, null, 4)
113
.replace(/<(\/script)/g, '<"+"$1') /*avoid breaking our script container*/}
114
document.documentElement.setAttribute('ver', '${VERSION.split('-')[0] /*for style selectors*/}')