Skip to content

Commit 783622f

Browse files
authored
release(v3.1.0): default language + portal i18n + ffmpeg path config (closes #88, closes #89)
- Admin: add “Default language” setting (used when a user has not chosen a language yet) - Admin: add optional FFmpeg binary path setting (env FR_FFMPEG_PATH overrides / locks) - Thumbnails: resolve ffmpeg path from env first, then admin config, then PATH - Portals: add language selector + apply defaultLanguage from siteConfig on first run - Portals: fix button styling (accent-aware) + refresh button color (fixes #88) - i18n: split locales into separate files and add Polish/Russian/Japanese; refresh German strings (fixes #89) - UI: replace hardcoded upload/login alerts/toasts with i18n keys for better translation coverage Closes #88 Closes #89
1 parent 7d84ee9 commit 783622f

30 files changed

Lines changed: 6548 additions & 1394 deletions

CHANGELOG.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,66 @@
11
# Changelog
22

3+
## Changes 01/16/2026 (v3.1.0)
4+
5+
`release(v3.1.0): default language + portal i18n + ffmpeg path config (closes #88, closes #89)`
6+
7+
**Commit message**
8+
9+
```text
10+
release(v3.1.0): default language + portal i18n + ffmpeg path config (closes #88, closes #89)
11+
12+
- Admin: add “Default language” setting (used when a user has not chosen a language yet)
13+
- Admin: add optional FFmpeg binary path setting (env FR_FFMPEG_PATH overrides / locks)
14+
- Thumbnails: resolve ffmpeg path from env first, then admin config, then PATH
15+
- Portals: add language selector + apply defaultLanguage from siteConfig on first run
16+
- Portals: fix button styling (accent-aware) + refresh button color (fixes #88)
17+
- i18n: split locales into separate files and add Polish/Russian/Japanese; refresh German strings (fixes #89)
18+
- UI: replace hardcoded upload/login alerts/toasts with i18n keys for better translation coverage
19+
20+
Closes #88
21+
Closes #89
22+
```
23+
24+
**Added**
25+
26+
- **Admin setting: Default language**
27+
- New `display.defaultLanguage` config surfaced in Admin → Header/File List/Language section.
28+
- Used automatically when a user has not chosen a language yet.
29+
- **Admin setting: FFmpeg binary path (optional)**
30+
- New `ffmpegPath` config for video thumbnail generation.
31+
- `FR_FFMPEG_PATH` remains the source of truth when set (admin field becomes read-only).
32+
- **New locales shipped**
33+
- **Polish (pl)**, **Russian (ru)**, **Japanese (ja)**, plus **Simplified Chinese (zh-CN)** locale file.
34+
- **Portal language selector**
35+
- Added a language dropdown to both **portal.html** and **portal-login.html**.
36+
37+
**Changed**
38+
39+
- **FFmpeg resolution order for thumbnails**
40+
- `FR_FFMPEG_PATH` → admin `ffmpegPath` → fallback to `ffmpeg` from PATH (and standard locations).
41+
- This keeps the Docker image lean while still supporting thumbnails when ffmpeg exists on the host/container.
42+
- **Portals now inherit default language**
43+
- If `localStorage.language` is missing, portals fetch `/api/siteConfig.php` and apply `display.defaultLanguage`.
44+
- **Translations architecture**
45+
- Locales are now maintained in dedicated files under `public/js/i18n/locales/` lazy load instead of a giant embedded map.
46+
- Added missing i18n keys for upload flows and admin/pro toasts to reduce English-only strings.
47+
48+
**Fixed**
49+
50+
- **Portal button styling / colors** (fixes #88)
51+
- Portal buttons now use accent-aware classes (`portal-btn-primary` / `portal-btn-outline`) and render correctly across themes.
52+
- **German translation gaps** (fixes #89)
53+
- German strings were refreshed and missing UI keys were added/normalized.
54+
- **More consistent i18n coverage**
55+
- Upload-related toasts and some boot/login alerts now use translation keys instead of hardcoded English.
56+
57+
**Notes**
58+
59+
- There are still parts of the Admin Panel and some edge UI strings that may fall back to English. This release fixes the reported German issues and adds new locales, but translation coverage will continue to improve over time.
60+
- If you want video thumbnails in Docker without bundling ffmpeg, mount a host ffmpeg binary or install it in your own derived image and set `FR_FFMPEG_PATH` (or set the path in Admin).
61+
62+
---
63+
364
## Changes 01/15/2026 (v3.0.2)
465

566
`release(v3.0.2): ffmpeg-backed video thumbnails (Docker) + new thumbnail API (closes #79)`

Dockerfile

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,29 @@ ENV DEBIAN_FRONTEND=noninteractive \
3232
PERSISTENT_TOKENS_KEY=default_please_change_this_key \
3333
PUID=99 PGID=100
3434

35+
ARG INSTALL_FFMPEG=0
36+
ARG INSTALL_CLAMAV=1
37+
ARG INSTALL_7ZIP=1
38+
ARG INSTALL_UNAR=1
39+
ARG INSTALL_SMBCLIENT=1
40+
3541
# Install Apache, PHP, and required extensions
3642
RUN if [ -f /etc/apt/sources.list.d/ubuntu.sources ]; then \
3743
sed -i 's/^Components: .*/Components: main universe/' /etc/apt/sources.list.d/ubuntu.sources; \
3844
fi && \
3945
apt-get update && \
40-
apt-get upgrade -y && \
46+
set -eux; \
47+
extra_pkgs=""; \
48+
if [ "${INSTALL_FFMPEG}" = "1" ]; then extra_pkgs="${extra_pkgs} ffmpeg"; fi; \
49+
if [ "${INSTALL_CLAMAV}" = "1" ]; then extra_pkgs="${extra_pkgs} clamav clamav-freshclam"; fi; \
50+
if [ "${INSTALL_7ZIP}" = "1" ]; then extra_pkgs="${extra_pkgs} 7zip"; fi; \
51+
if [ "${INSTALL_UNAR}" = "1" ]; then extra_pkgs="${extra_pkgs} unar"; fi; \
52+
if [ "${INSTALL_SMBCLIENT}" = "1" ]; then extra_pkgs="${extra_pkgs} smbclient"; fi; \
4153
apt-get install -y --no-install-recommends \
4254
apache2 \
4355
php php-json php-curl php-zip php-mbstring php-gd php-xml \
44-
ffmpeg \
45-
ca-certificates curl git openssl \
46-
smbclient \
47-
7zip \
48-
unar \
49-
clamav clamav-freshclam \
56+
ca-certificates curl openssl \
57+
${extra_pkgs} \
5058
&& apt-get clean && rm -rf /var/lib/apt/lists/*
5159

5260
# Remap www-data to the PUID/PGID provided for safe bind mounts

public/js/adminFolderAccess.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1610,7 +1610,7 @@ async function loadUserGroupsList(useCacheOnly) {
16101610
const nameInput = card.querySelector('input[data-group-field="name"]');
16111611
const name = (nameInput && nameInput.value || '').trim();
16121612
if (!name) {
1613-
showToast('Enter a group name first.');
1613+
showToast(t('admin_group_name_required'));
16141614
return;
16151615
}
16161616
await openGroupAclEditor(name);
@@ -1673,7 +1673,7 @@ async function saveUserGroupsFromUI() {
16731673
try {
16741674
const res = await saveAllGroups(groups);
16751675
if (!res.success) {
1676-
showToast(res.error || 'Error saving groups');
1676+
showToast(res.error || t('admin_groups_save_error'));
16771677
if (status) {
16781678
status.textContent = 'Error saving groups.';
16791679
status.className = 'small text-danger';
@@ -1686,14 +1686,14 @@ async function saveUserGroupsFromUI() {
16861686
status.textContent = 'Groups saved.';
16871687
status.className = 'small text-success';
16881688
}
1689-
showToast('Groups saved.');
1689+
showToast(t('admin_groups_saved'));
16901690
} catch (e) {
16911691
console.error(e);
16921692
if (status) {
16931693
status.textContent = 'Error saving groups.';
16941694
status.className = 'small text-danger';
16951695
}
1696-
showToast('Error saving groups', 'error');
1696+
showToast(t('admin_groups_save_error'), 'error');
16971697
}
16981698
}
16991699

@@ -1791,7 +1791,7 @@ function saveGroupAclFromUI() {
17911791
}
17921792
__groupsCache[groupName].grants = grants;
17931793

1794-
showToast('Group folder access updated. Remember to Save groups.');
1794+
showToast(t('admin_group_access_updated'));
17951795
modal.style.display = 'none';
17961796
}
17971797

public/js/adminOnlyOffice.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -424,18 +424,18 @@ function attachOnlyOfficeCspHelper(container) {
424424
const txt = (cspPre.textContent || '').trim();
425425
const ok = await copyToClipboard(txt);
426426
if (ok) {
427-
showToast('CSP line copied.');
427+
showToast(t('admin_onlyoffice_csp_copied'));
428428
} else {
429429
try { selectElementContents(cspPre); } catch (e) { /* ignore */ }
430-
const reason = window.isSecureContext ? '' : ' (page is not HTTPS or localhost)';
431-
showToast('Copy failed' + reason + '. Press Ctrl/Cmd+C to copy.');
430+
const reason = window.isSecureContext ? '' : t('admin_onlyoffice_copy_failed_reason_insecure');
431+
showToast(t('admin_onlyoffice_copy_failed', { reason }));
432432
}
433433
});
434434

435435
document.getElementById('selectOoCsp')?.addEventListener('click', () => {
436436
try {
437437
selectElementContents(cspPre);
438-
showToast('Selected — press Ctrl/Cmd+C');
438+
showToast(t('admin_onlyoffice_select_prompt'));
439439
} catch (e) {
440440
/* ignore */
441441
}
@@ -535,4 +535,4 @@ export function collectOnlyOfficeSettingsForSave(payload) {
535535

536536
payload.onlyoffice = onlyoffice;
537537
return payload;
538-
}
538+
}

0 commit comments

Comments
 (0)