embedded languages

Massimo Melina committed Apr 5, 2023 at 15:29 UTC e5c067b51302d6a1eadd04c93dc12a829694d838
11 files changed +41 -19
README.md
+4 -7
@@ -84,15 +84,12 @@ If you want to run HFS as a service
84 ## Internationalization
85
86 It is possible to show the Front-end in other languages.
87 -In the Languages section of the Admin-panel you'll be able to install lang files.
88 -You can find some of these files at https://github.com/rejetto/hfs/tree/main/langs
89 -Files are named `hfs-lang-CODE.json`, where `CODE` is the ISO code for your language (e.g. pt-br for Brazilian).
90 -To download a file: open it, right-click on the "Raw" button, Save.
87 +Translation for some languages is already provided. If you find an error, consider reporting it
88 +or [editing the source file](https://github.com/rejetto/hfs/tree/main/src/langs).
89
92 -If your language is missing, please consider [translating yourself](https://github.com/rejetto/hfs/wiki/Translation).
90 +In the Languages section of the Admin-panel you can install additional language files.
91
94 -Translation is applied automatically based on the configuration of the visitor's browser.
95 -[Check the language configuration of your browser](https://gtranslate.io/detect-browser-language).
92 +If your language is missing, please consider [translating yourself](https://github.com/rejetto/hfs/wiki/Translation).
93
94 ## Plug-ins
95
admin/src/LangPage.ts
+6 -2
@@ -22,7 +22,7 @@ export default function LangPage() {
22 h(Box, { mb: 1, display: 'flex' },
23 h(Button, { variant: 'contained', startIcon: h(Upload), onClick: add }, "Add"),
24 h(Box, { flex: 1 }),
25 - h(ForceLang, { langs: list.map(x => x.code) }),
25 + h(ForceLang, { langs: _.uniq(list.map(x => x.code)) }),
26 ),
27 h(DataGrid, {
28 loading: connecting,
@@ -38,6 +38,10 @@ export default function LangPage() {
38 field: 'version',
39 width: 80,
40 },
41 + {
42 + field: 'hfs_version',
43 + headerName: "HFS version",
44 + },
45 {
46 field: 'author',
47 flex: 1,
@@ -49,7 +53,7 @@ export default function LangPage() {
53 hideSortIcons: true,
54 disableColumnMenu: true,
55 renderCell({ row }) {
52 - return h('div', {},
56 + return row.embedded ? "Embedded" : h('div', {},
57 h(IconBtn, {
58 icon: Delete,
59 title: "Delete",
src/api.lang.ts
+3 -1
@@ -6,7 +6,7 @@ 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'
9 -import { code2file, file2code } from './lang'
9 +import { code2file, EMBEDDED_TRANSLATIONS, file2code } from './lang'
10
11 const apis: ApiHandlers = {
12
@@ -22,6 +22,8 @@ const apis: ApiHandlers = {
22 }
23 catch {}
24 }
25 + for (const [code, data] of Object.entries(EMBEDDED_TRANSLATIONS))
26 + list.add({ code, embedded: true, ..._.omit(data, 'translate') })
27 list.close()
28 }
29 })
src/lang.ts
+26 -7
@@ -6,7 +6,7 @@ import { watchLoad } from './watchLoad'
6
7 const PREFIX = 'hfs-lang-'
8 const SUFFIX = '.json'
9 -const EMBEDDED = 'en'
9 +const EMBEDDED_LANGUAGE = 'en'
10
11 export function code2file(code: string) {
12 return PREFIX + code.toLowerCase() + SUFFIX
@@ -25,14 +25,18 @@ export async function getLangData(ctx: Koa.Context) {
25 let i = 0
26 while (i < langs.length) {
27 let k = langs[i] || '' // shut up ts
28 - if (!k || k === EMBEDDED) break
28 + if (!k || k === EMBEDDED_LANGUAGE) break
29 try { ret[k!] = JSON.parse(await readFile(`hfs-lang-${k}.json`, 'utf8')) }
30 catch {
31 - do { k = k.substring(0, k.lastIndexOf('-'))
32 - } while (k && langs.includes(k))
33 - if (k) {
34 - langs[i] = k // overwrite and retry
35 - continue
31 + if (k in EMBEDDED_TRANSLATIONS)
32 + ret[k] = EMBEDDED_TRANSLATIONS[k as keyof typeof EMBEDDED_TRANSLATIONS]
33 + else {
34 + do { k = k.substring(0, k.lastIndexOf('-'))
35 + } while (k && langs.includes(k))
36 + if (k) {
37 + langs[i] = k // overwrite and retry
38 + continue
39 + }
40 }
41 }
42 i++
@@ -52,3 +56,18 @@ defineConfig('force_lang', '', v => {
56 undo = res.unwatch
57 })
58
59 +
60 +import lang_it from './langs/hfs-lang-it.json'
61 +import lang_zh from './langs/hfs-lang-zh.json'
62 +import lang_ru from './langs/hfs-lang-ru.json'
63 +import lang_sr from './langs/hfs-lang-sr.json'
64 +import lang_ko from './langs/hfs-lang-ko.json'
65 +
66 +export const EMBEDDED_TRANSLATIONS = {
67 + it: lang_it,
68 + zh: lang_zh,
69 + ru: lang_ru,
70 + sr: lang_sr,
71 + ko: lang_ko,
72 +}
73 +
src/langs/hfs-lang-en.json renamed
src/langs/hfs-lang-it.json renamed
src/langs/hfs-lang-ko.json renamed
+1 -1
@@ -4,7 +4,7 @@
4 "hfs_version": "0.42.3",
5 "translate": {
6 "Select": "선택",
7 - "n_files": "{n,개의 파일,{# file} other{# files}}",
7 + "n_files": "{n,plural,one{1개의 파일} =2 =3{파일 #개} other{#개 파일}}",
8 "n_folders": "{n,개의 폴더,{# folder} other{# folders}}",
9 "filter_count": "{n,개, {# filtered} other{# filtered}}",
10 "select_count": "{n,개, {# selected} other{# selected}}",
src/langs/hfs-lang-ru.json renamed
src/langs/hfs-lang-sr.json renamed
src/langs/hfs-lang-zh.json renamed
tsconfig.json
+1 -1
@@ -34,7 +34,7 @@
34 // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
35 // "types": [], /* Specify type package names to be included without being referenced in a source file. */
36 // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
37 - // "resolveJsonModule": true, /* Enable importing .json files */
37 + "resolveJsonModule": true, /* Enable importing .json files */
38 // "noResolve": true, /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
39
40 /* JavaScript Support */