release: v2.6.2-beta English and French interface

This commit is contained in:
fsylvain committed 2026-10-03 02:08:52 +02:00
1 parent 721311a643
commit 2c8f39273c
4 files changed
+39 -3

No files matched your search

+1
View File
@@ -28,3 +28,4 @@ Each body lives in `docs/releases/<tag>.md`. Publish with `tea releases create -
| `v2.4.0-beta` | v2.4.0-beta - Owner role, invite management & Settings page |
| `v2.5.0-beta` | v2.5.0-beta - Media library & image picker |
| `v2.6.0-beta` | v2.6.0-beta - Signed updates and browser restart |
| `v2.6.2-beta` | v2.6.2-beta - English and French interface |
+29
View File
@@ -0,0 +1,29 @@
This release adds English and French throughout the SPA, with an instant language switch and a preference remembered on this browser.
## New
**English and French interface**
- Choose English or Français from the Language control in the desktop or mobile profile submenu.
- Switch interface language immediately while keeping your current page and unsaved work.
- Keep your selected language after navigation, reload and logout, including on authentication screens.
- See translated forms, validation, notifications, dialogs and accessibility labels, with localized dates, numbers and counts.
## Improvements and fixes
- Keep partial bulk-delete failure notifications available after retrying, including when switching languages.
## Under the hood
- Add translation catalog parity, fallback, persistence and SPA interaction tests.
## Upgrading
- Install the signed update through Settings on a prepared Linux/systemd installation, or replace the binary and restart the service.
- No database migration or new environment variable is required.
- English remains the default until a language is selected; the preference is stored locally in the browser.
- User content, API data and transactional emails retain their existing language.
## Known limitations
- Visual parity checks for this feature were skipped under the accepted slice waiver.
+2
View File
@@ -199,6 +199,8 @@ describe('Switch language without losing work', () => {
.find((button) => button.textContent?.trim() === 'Retry')!
.click()
await flushPromises()
await new Promise((resolve) => setTimeout(resolve, 250))
await flushPromises()
await captureBothWays(
'2 images were deleted. kitchen-before.webp is still in your library. Try again.',
'2 images ont été supprimées. kitchen-before.webp est toujours dans votre bibliothèque. Réessayez.',
+7 -3
View File
@@ -100,6 +100,8 @@ let opener: HTMLElement | null = null
let skipFocusRestore = false
let pendingSelectId: number | null = null
let bulkDeletedTotal = 0
let bulkFailureRevision = 0
let bulkFailureToastId = BULK_FAILED_TOAST_ID
let failureToastShown = false
const activeItem = computed(
@@ -645,17 +647,17 @@ function bulkFailedToast(failed: MediaItem[]) {
],
}
if (failureToastShown) {
toast.update(BULK_FAILED_TOAST_ID, () => content)
toast.update(bulkFailureToastId, () => content)
return
}
failureToastShown = true
toast.add(() => ({ id: BULK_FAILED_TOAST_ID, ...content }))
toast.add(() => ({ id: bulkFailureToastId, ...content }))
}
function dismissBulkFailedToast() {
if (failureToastShown) {
failureToastShown = false
toast.remove(BULK_FAILED_TOAST_ID)
toast.remove(bulkFailureToastId)
}
}
@@ -708,6 +710,8 @@ async function bulkDeleteAction() {
}
async function retryBulkDelete(failed: MediaItem[]) {
dismissBulkFailedToast()
bulkFailureToastId = `${BULK_FAILED_TOAST_ID}-${++bulkFailureRevision}`
const firstIndex = firstIndexOf(failed)
const result = await media.deleteMany(failed)
if (result.handled) {