plugins: HFS.customizeText
Massimo Melina committed
Dec 7, 2025 at 15:26 UTC
5197e5d83cf57c6ad2dcef5c21f1461b627aca6c
4 files changed
+21
-6
dev-plugins.md
+6
-1
@@ -456,6 +456,9 @@ In frontend you will have access to the `HFS` object of the global scope, which
456
- `markVideoComponent(Component): Component` if you replace the show-video component with yours, wrap it with this function.
457
- `isAudioComponent(Component): boolean` tell if the component is used by show for audio files.
458
- `markAudioComponent(Component): Component` if you replace the show-audio component with yours, wrap it with this function.
459
+- `customizeText(changes: { [key]: string }, languageCode?: string)` customize text. Find text keys to change, and assign new text.
460
+ If you don't specify a languageCode, the change will apply to all languages (and has precedence).
461
+ Find they keys in this file https://github.com/rejetto/hfs/blob/main/src/langs/hfs-lang-en.json (english language).
462
463
- The following properties are accessible only immediately at top-level; don't call it later in a callback.
464
- `getPluginConfig()` returns object of all config keys that are declared frontend-accessible by this plugin.
@@ -1111,4 +1114,6 @@ If you want to override a text regardless of the language, use the special langu
1114
- HFS.userBelongsTo now supports array of usernames
1115
- 12.96 (v0.57.27)
1116
- frontend events: loginOk, loginFailed
1114
- - api.normalizeFilename
\ No newline at end of file
1117
+ - api.normalizeFilename
1118
+- 12.97 (v0.57.28)
1119
+ - HFS.customizeText
\ No newline at end of file
frontend/src/misc.ts
+8
-1
@@ -16,6 +16,7 @@ import { logout } from './login'
16
import { subscribeKey } from 'valtio/utils'
17
import { uploadState } from './uploadQueue'
18
import { fileShow, Video, Audio, getShowComponent } from './show'
19
+import { ANY_LANGUAGE } from '../../src/i18n'
20
import { debounceAsync } from '../../src/debounceAsync'
21
export * from '@hfs/shared'
22
import i18n from './i18n'
@@ -102,7 +103,7 @@ export function formatTimestamp(x: number | string | Date, options?: Intl.DateTi
103
import * as thisModule from './misc'
104
Object.assign(getHFS(), {
105
h, React, state, t, _, dialogLib, apiCall, useApi, reloadList, logout, Icon, hIcon, iconBtn, useBatch, fileShow,
105
- toast, domOn, getNotifications, debounceAsync, useSnapState, DirEntry, Btn,
106
+ toast, domOn, getNotifications, debounceAsync, useSnapState, DirEntry, Btn, i18n,
107
fileShowComponents: { Video, Audio },
108
isVideoComponent, markVideoComponent, isAudioComponent, markAudioComponent,
109
isShowSupported: getShowComponent,
@@ -127,6 +128,12 @@ Object.assign(getHFS(), {
128
try { return _.find(state.list, { uri: new URL(a.href).pathname }) }
129
catch {}
130
},
131
+ customizeText(mods: Dict<string>, lang=ANY_LANGUAGE) {
132
+ const o = i18n.state.translations
133
+ if (lang === ANY_LANGUAGE || lang === cross.EMBEDDED_LANGUAGE) // these are missing at the start, but we need them if we want to customize content
134
+ o[lang] ??= { translate: {} }
135
+ Object.assign(o[lang]?.translate || {}, mods)
136
+ }
137
})
138
139
markVideoComponent(Video)
src/const.ts
+1
-1
@@ -9,7 +9,7 @@ import { formatTimestamp } from './cross'
9
import { argv } from './argv'
10
export * from './cross-const'
11
12
-export const API_VERSION = 12.96
12
+export const API_VERSION = 12.97
13
export const COMPATIBLE_API_VERSION = 1 // while changes in the api are not breaking, this number stays the same, otherwise it is made equal to API_VERSION
14
15
// you can add arguments with this file, currently used for the update process on mac/linux
src/i18n.ts
+6
-3
@@ -3,6 +3,9 @@
3
import { proxy, useSnapshot } from 'valtio'
4
import { watch } from 'valtio/utils'
5
6
+export const ANY_LANGUAGE = 'all'
7
+
8
+// this code is in the backend to give the chance to plugins to translate http's body
9
export function i18nFromTranslations(translations: Record<string, any>, embedded='en') {
10
const state = proxy({
11
embedded,
@@ -11,8 +14,8 @@ export function i18nFromTranslations(translations: Record<string, any>, embedded
14
})
15
const searchLangs: string[] = []
16
watch(get => {
14
- const snapshot = get(state)
15
- searchLangs.splice(0, Infinity, 'all', ...Object.keys(snapshot.translations), snapshot.embedded) // replace completely
17
+ const snap = get(state)
18
+ searchLangs.splice(0, Infinity, ANY_LANGUAGE, ...snap.disabled ? [] : Object.keys(snap.translations), snap.embedded) // replace the array completely
19
})
20
21
const warns = new Set() // avoid duplicates
@@ -36,7 +39,7 @@ export function i18nFromTranslations(translations: Record<string, any>, embedded
39
let selectedLang = '' // keep track of where we find the translation
40
const { embedded } = state
41
const langs = Object.keys(state.translations)
39
- if (!state.disabled) for (const key of keys) {
42
+ for (const key of keys) {
43
for (const lang of searchLangs)
44
if (found = state.translations[selectedLang=lang]?.translate?.[key]) break
45
if (found) break