v0.254.0 — the saved notes follow the language, and the switch becomes a globe (R-557 slice 2 release C; SLICE 2 CLOSED)
gates / gates (push) Successful in 23s

The notes a background run SAVES — last night's backup line, the last error, the proof
result, the restore outcome — are written in the BOX's language at the moment they are
written. A household that switches sees the previous run's note in the old language until
the next run rewrites it: the operator's §16 option 1, stated rather than hidden.
EndRestoreOp no longer receives a Hungarian literal from anywhere.

The language switch is a globe. Two text links wrapped in the sidebar footer and asked the
reader to recognise "Magyar"/"English" as links; a globe is the one symbol every web user
already reads as "language", so nobody has to read Hungarian to escape Hungarian. It is
<details>/<summary> — a menu with no script, drawn inline because the icon sprite lives
only in layout.html and the visitor pages have their own shell.

Those visitor pages get the same globe, and a visitor's choice stays theirs: a display-only
felhom_lang cookie that langFor reads ONLY when there is no session. A signed-in household
can never inherit a language a previous visitor picked in the same browser. POST /lang is
CSRF-exempt for a narrow reason written at the exemption — its only achievable effect is the
language of the page the victim's own browser shows them — and safeBackPath refuses
//evil.example as well as https://, because "starts with /" alone is not the test. §16 taken:
a successful claim carries the cookie into the household's setting.

TWO PARITY EXCEPTIONS, MEASURED: 106 fixtures compared with a real diff — exactly two change
shapes (the dashboard footer, the globe in the shells) and 5 byte-identical, which are the
three pages that must not change.

I INTRODUCED A DEADLOCK AND THE SUITE CAUGHT IT BY HANGING. UpdateOffboxStatus holds the
settings write lock while running its callback; boxLang() wants the read lock; sync.RWMutex
is not reentrant. On a real box an off-site run would have hung forever HOLDING the settings
lock. Fixed by resolving the language before the callback, and guarded by a test that names
the file and line in a second instead of hanging for 25 minutes.

MinAgent: 0.131.0 (unchanged). No hub release needed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-09-18 14:19:31 +02:00
parent eb6aa58aa7
commit 48f3336956
142 changed files with 2199 additions and 318 deletions
+72 -1
View File
@@ -2196,5 +2196,76 @@
"err.integrations.onlyoffice_no_subdomain": "the OnlyOffice subdomain is not known",
"err.integrations.occ_failed": "the occ command failed (%s): %s (output: %s)",
"err.integrations.occ_disable_failed": "occ app:disable failed: %s (output: %s)",
"err.notify.hub_error": "hub error (%d): %s"
"err.notify.hub_error": "hub error (%d): %s",
"note.offsite.fail_quota": "The remote backup did not fit inside its storage limit",
"note.offsite.fail_orphaned": "The remote store was made with an earlier key that is no longer available",
"note.offsite.fail_no_repo": "There is no backup store at the remote target",
"note.offsite.fail_no_units": "There was nothing to back up: none of the selected apps has a backup",
"note.offsite.fail_transport": "The remote store cannot be reached (network or sign-in)",
"note.offsite.fail_unknown": "The remote backup failed for an unknown reason",
"note.offsite.fail_head": "The remote backup failed",
"note.offsite.whole_unit_gap": "(the whole app — it has no local backup unit)",
"note.offsite.no_local_unit": "These apps did NOT go into the remote backup, because they have no local backup unit yet: %s. The next backup usually makes one — if they are still listed after the second run, tell your operator.",
"note.offsite.not_installed": "These apps are selected for remote backup but are not installed, so they cannot be backed up: %s. If you no longer need them, clear their selection on the Remote backup page.",
"note.offsite.quota_partial": "Warning: because of the storage limit, %d apps got only a settings and database backup: %s.",
"note.offsite.quota_usage": "The remote backup uses %d%% of its limit (%d/%d GB).",
"note.tier2.reason_manual": "your own choice",
"note.tier2.reason_other_drive": "another data drive",
"note.tier2.label_internal_ssd": "internal SSD (system)",
"note.tier2.reason_no_second": "no second data drive — only the database and settings fit on the internal SSD; large files need a second drive",
"note.tier2.same_disk": "the target you picked is on the same physical disk",
"note.tier2.ssd_partial": "Only the settings, the database and the required data fit on the internal SSD — the optional content was not copied.",
"note.tier2.no_space_ssd": "not enough space on the internal SSD — backing large files off the drive needs a second drive (or remote storage)",
"note.tier2.no_other_drive": "there is no second physical drive — the second backup needs one",
"note.tier2.unit_preserved": "The data package on the main drive was incomplete, so the complete one already in the second copy was kept. The copy's data package is therefore older than this backup.",
"note.restore.interrupted": "The restore was interrupted (the box restarted) — start it again.",
"note.undo.present": "the earlier state is backed up: %s",
"note.undo.partial": "the earlier state is only PARTLY backed up — present: %s; MISSING: %s",
"note.undo.absent": "the backup of the earlier state is NOT where it should be (%s)",
"note.undo.none": "no restorable copy of the earlier state was made",
"note.reconstitute.copy_latest": "latest",
"note.reconstitute.held": "restoring the data of %s stopped at %s, and the earlier state could not be put back either. The app stays stopped, for safety, so your data cannot be damaged further. Get in touch with us",
"layout.nyelv": "Language",
"note.restore.failed": "The restore failed: %s",
"note.restore.full_failed": "The full restore failed: %s",
"note.restore.recover_failed": "The recovery failed: %s",
"note.restore.shares_failed": "Restoring the shares failed: %s",
"note.restore.shares_recover_failed": "Recovering the shares failed: %s",
"note.restore.unit_failed": "Restore failed: %s",
"note.restore.file_failed": "File restore failed: %s",
"note.restore.full_unit_failed": "Full restore failed: %s",
"note.restore.recovered_files": "The missing files of %s are back among your live data.",
"note.restore.shares_prepared": "The shares are restored — you can now put them back among your live data.",
"note.restore.at_scratch": " into the check folder",
"note.restore.at_scratch_named": " into the check folder: %s",
"note.restore.scratch_full": "The full backup of %s is restored%s — together with your own files. Your existing data is unchanged.",
"note.restore.scratch_state": "The settings and the database of %s are restored%s. Your own files (documents, pictures, uploads) did NOT come back — this check restore brings back only the app's settings and database. If you need your files, start “Prepare a full restore” on this page. Your existing data is unchanged.",
"note.restore.files_count": "%d files",
"note.restore.and_volumes": " and %d data volumes",
"note.restore.and_database": " and the database",
"note.restore.volumes_count": "%d data volumes",
"note.restore.the_database": "the database",
"note.restore.dumps_at": " (backup: %s)",
"note.restore.reconstituted": "%s: %s restored%s — the app has restarted.",
"note.restore.no_db_in_backup": " WARNING: this app HAS a database, but the backup held no database dump, so the database did NOT come back. The state from before the restore is backed up: %s",
"note.restore.no_db_at_all": " This app has no database.",
"note.restore.all_files_present": "Every file that was checked is in place.",
"note.restore.files_from_second": "%s: %d files restored from the second copy.",
"note.restore.scratch_incomplete": "The restore copy is incomplete — the last download did not finish. Start “Prepare a full restore” again.",
"note.unit_restore_data": "%s: %s restored — the app has restarted.",
"note.unit_restore_settings_only": "%s: the settings are back — the app has restarted. WARNING: this backup held only the settings, no data. The app's data did NOT come back from this backup.",
"note.unit_restore_counts_unknown": "The restore of %s ran — the app has restarted. This backup has no backup unit, so we cannot tell you what came back from it. Check inside the app that your data is there.",
"note.unit_restore_none_returned": "%s: WARNING — the backup lists %d data volumes and %d database dumps, but none of them came back. Your data is unchanged. Ask for help before you try again.",
"note.tier2_no_coverage": "This app's data cannot be restored from this copy — the app was not stopped. Use the Start restore button on the Backup → Restore page.",
"note.tier2_unit_available": "This app's data is not in files but in the app's own database and volumes — the app was not stopped. You can bring those back from the same copy with the “Full restore from the copy” button beside this one. Careful: that action OVERWRITES the current data, while this button only fills in the missing files.",
"note.tier2_unit_not_covered": "The app's database and internal volumes are not part of this restore.",
"note.tier2_unit_restore_source": "The restore came from the copy on the second drive (%s).",
"note.tier2_unit_restore_source_unproven": "The restore came from the copy on the second drive (%s — that is the time of the last backup ATTEMPT; we cannot prove it succeeded).",
"note.tier2_unit_action_label": "Full restore from the copy",
"note.tier2_unit_confirm_base": "This action OVERWRITES the app's current data – its database and its internal volumes too – with the copy on the second drive. Anything made since the copy is lost.",
"note.tier2_unit_confirm_date_fmt": " The copy is from: %s.",
"note.tier2_unit_confirm_date_unproven_fmt": " The copy is from: %s – that is the time of the last backup attempt; we cannot prove it succeeded.",
"note.tier2_unit_confirm_contrast": " The “Restore files” button beside it only fills in the missing files and overwrites nothing. The app stops while either one runs.",
"note.tier2_unit_stale_clause": " WARNING: this copy's data package is older than the latest backup — the package on the main drive was incomplete, so the complete one was kept. The restore uses the package named above.",
"note.tier2_unit_stale_notice_fmt": "The copy's data package is older than the latest backup (%s): the package on the main drive was incomplete, so the complete one already there was kept."
}
+72 -1
View File
@@ -2185,5 +2185,76 @@
"err.integrations.onlyoffice_no_subdomain": "OnlyOffice aldomain nem ismert",
"err.integrations.occ_failed": "occ parancs sikertelen (%s): %s (kimenet: %s)",
"err.integrations.occ_disable_failed": "occ app:disable sikertelen: %s (kimenet: %s)",
"err.notify.hub_error": "hub hiba (%d): %s"
"err.notify.hub_error": "hub hiba (%d): %s",
"note.offsite.fail_quota": "A távoli mentés nem fért el a tárhelykereten belül",
"note.offsite.fail_orphaned": "A távoli tárhely egy korábbi, már nem elérhető kulccsal készült",
"note.offsite.fail_no_repo": "A távoli tárhelyen nincs mentési adattár",
"note.offsite.fail_no_units": "Nem volt mit menteni: egyetlen kijelölt alkalmazásnak sem található mentése",
"note.offsite.fail_transport": "A távoli tárhely nem érhető el (hálózat vagy bejelentkezés)",
"note.offsite.fail_unknown": "A távoli mentés ismeretlen okból nem sikerült",
"note.offsite.fail_head": "A távoli mentés nem sikerült",
"note.offsite.whole_unit_gap": "(a teljes alkalmazás — nincs helyi mentési egysége)",
"note.offsite.no_local_unit": "Ezek az alkalmazások NEM kerültek be a távoli mentésbe, mert még nincs helyi mentési egységük: %s. A következő mentés általában már elkészíti — ha a második futás után is itt szerepelnek, szólj az üzemeltetőnek.",
"note.offsite.not_installed": "Ezek az alkalmazások ki vannak jelölve távoli mentésre, de nincsenek telepítve, ezért nem menthetők: %s. Ha már nincs rájuk szükséged, vedd ki a kijelölésüket a Távoli mentés oldalon.",
"note.offsite.quota_partial": "Figyelmeztetés: a tárhelykeret miatt %d alkalmazásnál csak konfiguráció- és adatbázis-mentés készült: %s.",
"note.offsite.quota_usage": "A távoli mentés a keret %d%%-át használja (%d/%d GB).",
"note.tier2.reason_manual": "kézi választás",
"note.tier2.reason_other_drive": "másik adatmeghajtó",
"note.tier2.label_internal_ssd": "belső SSD (rendszer)",
"note.tier2.reason_no_second": "nincs 2. adatmeghajtó — csak az adatbázis/konfiguráció fér a belső SSD-re; a nagy fájlokhoz 2. meghajtó kell",
"note.tier2.same_disk": "a kiválasztott cél ugyanazon a fizikai lemezen van",
"note.tier2.ssd_partial": "A belső SSD-n csak a konfiguráció, adatbázis és a kötelező adatok férnek el — a választható tartalom nem került másolásra.",
"note.tier2.no_space_ssd": "nincs elég hely a belső SSD-n — a nagy fájlok off-drive mentéséhez 2. meghajtó (vagy távoli tárhely) szükséges",
"note.tier2.no_other_drive": "nincs másik fizikai meghajtó — a 2. mentéshez 2. meghajtó szükséges",
"note.tier2.unit_preserved": "A fő meghajtón lévő adatcsomag hiányos volt, ezért a másodlagos másolatban meglévő, teljes csomagot megőriztük. A másolat adatcsomagja ezért régebbi, mint ez a mentés.",
"note.restore.interrupted": "A visszaállítás megszakadt (a doboz újraindult) — indítsd el újra.",
"note.undo.present": "a korábbi állapot mentése megvan: %s",
"note.undo.partial": "a korábbi állapot mentése RÉSZBEN van meg — megvan: %s; HIÁNYZIK: %s",
"note.undo.absent": "a korábbi állapot mentését NEM találjuk a helyén (%s)",
"note.undo.none": "a korábbi állapotról nem készült menthető másolat",
"note.reconstitute.copy_latest": "legutóbbi",
"note.reconstitute.held": "a(z) %s adatainak visszaállítása %s-kor megszakadt, és a korábbi állapotot sem sikerült visszatölteni. Az alkalmazás biztonsági okból leállítva marad, hogy az adatai ne sérüljenek tovább. Vedd fel velünk a kapcsolatot",
"layout.nyelv": "Nyelv",
"note.restore.failed": "A visszaállítás sikertelen: %s",
"note.restore.full_failed": "A teljes visszaállítás sikertelen: %s",
"note.restore.recover_failed": "A helyreállítás sikertelen: %s",
"note.restore.shares_failed": "A megosztások visszaállítása sikertelen: %s",
"note.restore.shares_recover_failed": "A megosztások helyreállítása sikertelen: %s",
"note.restore.unit_failed": "Visszaállítás sikertelen: %s",
"note.restore.file_failed": "Fájl-visszaállítás sikertelen: %s",
"note.restore.full_unit_failed": "Teljes visszaállítás sikertelen: %s",
"note.restore.recovered_files": "A(z) %s hiányzó fájljai helyreállítva az élő adatok közé.",
"note.restore.shares_prepared": "A megosztások visszaállítása elkészült — most helyreállíthatod az élő adatok közé.",
"note.restore.at_scratch": " ellenőrző mappába",
"note.restore.at_scratch_named": " ellenőrző mappába: %s",
"note.restore.scratch_full": "A(z) %s teljes mentése visszaállítva%s — a saját fájljaiddal együtt. A meglévő adatok változatlanok.",
"note.restore.scratch_state": "A(z) %s beállításai és adatbázisa visszaállítva%s. A saját fájljaid (dokumentumok, képek, feltöltések) NEM kerültek vissza — ez az ellenőrző visszaállítás csak az alkalmazás beállításait és adatbázisát hozza vissza. Ha a fájljaidra van szükséged, indítsd el a „Teljes visszaállítás előkészítése” lépést ezen az oldalon. A meglévő adatok változatlanok.",
"note.restore.files_count": "%d fájl",
"note.restore.and_volumes": " és %d adatkötet",
"note.restore.and_database": " és az adatbázis",
"note.restore.volumes_count": "%d adatkötet",
"note.restore.the_database": "az adatbázis",
"note.restore.dumps_at": " (mentés: %s)",
"note.restore.reconstituted": "A(z) %s: %s visszaállítva%s — az alkalmazás újraindult.",
"note.restore.no_db_in_backup": " FIGYELEM: ennek az alkalmazásnak VAN adatbázisa, de a mentés nem tartalmazott adatbázis-mentést, ezért az adatbázis NEM állt vissza. A visszaállítás előtti állapot mentése megvan: %s",
"note.restore.no_db_at_all": " Ennek az alkalmazásnak nincs adatbázisa.",
"note.restore.all_files_present": "Minden vizsgált fájl megvan a helyén.",
"note.restore.files_from_second": "%s: %d fájl visszaállítva a másodlagos másolatból.",
"note.restore.scratch_incomplete": "A visszaállítási másolat nem teljes — a legutóbbi letöltés nem fejeződött be. Indítsd újra a teljes visszaállítás előkészítését.",
"note.unit_restore_data": "A(z) %s: %s visszaállítva — az alkalmazás újraindult.",
"note.unit_restore_settings_only": "A(z) %s: a beállítások visszaálltak — az alkalmazás újraindult. FIGYELEM: ez a mentés csak a beállításokat tartalmazta, adatot nem. Az alkalmazás adatai NEM álltak vissza ebből a mentésből.",
"note.unit_restore_counts_unknown": "A(z) %s visszaállítása lefutott — az alkalmazás újraindult. Ehhez a mentéshez nem tartozik mentési egység, ezért nem tudjuk megmondani, mi állt vissza belőle. Ellenőrizd az alkalmazásban, hogy megvannak-e az adataid.",
"note.unit_restore_none_returned": "A(z) %s: FIGYELEM — a mentés %d adatkötetet és %d adatbázis-mentést sorol fel, de egyik sem állt vissza. Az adataid változatlanok maradtak. Kérj segítséget, mielőtt újra próbálod.",
"note.tier2_no_coverage": "Ennek az alkalmazásnak az adatai nem ebből a másolatból állíthatók vissza — az alkalmazás nem állt le. Használd a Visszaállítás indítása gombot a Biztonsági mentés → Visszaállítás oldalon.",
"note.tier2_unit_available": "Ennek az alkalmazásnak az adatai nem fájlokban, hanem az alkalmazás saját adatbázisában és köteteiben vannak — az alkalmazás nem állt le. Ezeket a mellette lévő „Teljes visszaállítás a másolatból” gombbal tudod visszahozni ugyanerről a másolatról. Figyelem: az a művelet FELÜLÍRJA a jelenlegi adatokat, míg ez a gomb csak a hiányzó fájlokat pótolja.",
"note.tier2_unit_not_covered": "Az alkalmazás adatbázisa és belső kötetei nem tartoznak ebbe a visszaállításba.",
"note.tier2_unit_restore_source": "A visszaállítás forrása a második meghajtón lévő másolat volt (%s).",
"note.tier2_unit_restore_source_unproven": "A visszaállítás forrása a második meghajtón lévő másolat volt (%s — ez az utolsó mentési kísérlet ideje; azt nem tudjuk igazolni, hogy az sikeres volt).",
"note.tier2_unit_action_label": "Teljes visszaállítás a másolatból",
"note.tier2_unit_confirm_base": "Ez a művelet FELÜLÍRJA az alkalmazás jelenlegi adatait – az adatbázisát és a belső köteteit is – a második meghajtón lévő másolattal. Ami a másolat óta keletkezett, elveszik.",
"note.tier2_unit_confirm_date_fmt": " A másolat kelte: %s.",
"note.tier2_unit_confirm_date_unproven_fmt": " A másolat kelte: %s – ez az utolsó mentési kísérlet ideje, azt nem tudjuk igazolni, hogy sikeres volt.",
"note.tier2_unit_confirm_contrast": " A mellette lévő „Fájlok visszaállítása” ezzel szemben csak a hiányzó fájlokat pótolja, és semmit nem ír felül. Az alkalmazás a művelet idejére leáll.",
"note.tier2_unit_stale_clause": " FIGYELEM: ennek a másolatnak az adatcsomagja régebbi, mint a legutóbbi mentés — a fő meghajtón lévő csomag hiányos volt, ezért a meglévő, teljes másolatot megőriztük. A visszaállítás a fent megadott csomagot használja.",
"note.tier2_unit_stale_notice_fmt": "A másolat adatcsomagja régebbi, mint a legutóbbi mentés (%s): a fő meghajtón lévő csomag hiányos volt, ezért a meglévő, teljes másolatot megőriztük."
}