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
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:
@@ -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."
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user