release: v2.6.2-beta English and French interface
This commit is contained in:
1 parent
721311a643
commit
2c8f39273c
4 files changed
+39
-3
No files matched your search
@@ -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.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.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.0-beta` | v2.6.0-beta - Signed updates and browser restart |
|
||||||
|
| `v2.6.2-beta` | v2.6.2-beta - English and French interface |
|
||||||
@@ -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.
|
||||||
@@ -199,6 +199,8 @@ describe('Switch language without losing work', () => {
|
|||||||
.find((button) => button.textContent?.trim() === 'Retry')!
|
.find((button) => button.textContent?.trim() === 'Retry')!
|
||||||
.click()
|
.click()
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 250))
|
||||||
|
await flushPromises()
|
||||||
await captureBothWays(
|
await captureBothWays(
|
||||||
'2 images were deleted. kitchen-before.webp is still in your library. Try again.',
|
'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.',
|
'2 images ont été supprimées. kitchen-before.webp est toujours dans votre bibliothèque. Réessayez.',
|
||||||
|
|||||||
@@ -100,6 +100,8 @@ let opener: HTMLElement | null = null
|
|||||||
let skipFocusRestore = false
|
let skipFocusRestore = false
|
||||||
let pendingSelectId: number | null = null
|
let pendingSelectId: number | null = null
|
||||||
let bulkDeletedTotal = 0
|
let bulkDeletedTotal = 0
|
||||||
|
let bulkFailureRevision = 0
|
||||||
|
let bulkFailureToastId = BULK_FAILED_TOAST_ID
|
||||||
let failureToastShown = false
|
let failureToastShown = false
|
||||||
|
|
||||||
const activeItem = computed(
|
const activeItem = computed(
|
||||||
@@ -645,17 +647,17 @@ function bulkFailedToast(failed: MediaItem[]) {
|
|||||||
],
|
],
|
||||||
}
|
}
|
||||||
if (failureToastShown) {
|
if (failureToastShown) {
|
||||||
toast.update(BULK_FAILED_TOAST_ID, () => content)
|
toast.update(bulkFailureToastId, () => content)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
failureToastShown = true
|
failureToastShown = true
|
||||||
toast.add(() => ({ id: BULK_FAILED_TOAST_ID, ...content }))
|
toast.add(() => ({ id: bulkFailureToastId, ...content }))
|
||||||
}
|
}
|
||||||
|
|
||||||
function dismissBulkFailedToast() {
|
function dismissBulkFailedToast() {
|
||||||
if (failureToastShown) {
|
if (failureToastShown) {
|
||||||
failureToastShown = false
|
failureToastShown = false
|
||||||
toast.remove(BULK_FAILED_TOAST_ID)
|
toast.remove(bulkFailureToastId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -708,6 +710,8 @@ async function bulkDeleteAction() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function retryBulkDelete(failed: MediaItem[]) {
|
async function retryBulkDelete(failed: MediaItem[]) {
|
||||||
|
dismissBulkFailedToast()
|
||||||
|
bulkFailureToastId = `${BULK_FAILED_TOAST_ID}-${++bulkFailureRevision}`
|
||||||
const firstIndex = firstIndexOf(failed)
|
const firstIndex = firstIndexOf(failed)
|
||||||
const result = await media.deleteMany(failed)
|
const result = await media.deleteMany(failed)
|
||||||
if (result.handled) {
|
if (result.handled) {
|
||||||
|
|||||||
Reference in new issue
Block a user