91 leaves refined after a native-Italian style pass.
## Categories of fixes
- Grammar / gender agreement — e.g. `logs.table.headers.lastSeenAt`
"Ultima visto il" → "Visto l'ultima volta"; heap gauge subject
agreement in `logs.diagnostics.gauges.allocatedPercentage`.
- Awkward phrasing / calques — `notFound.subtitle` drops stilted
"ad esso"; `incidents.fallback.title` "in salute" → "funzionano
correttamente" (was reading as if for a person, not systems);
`settings.form.removeMonitors.title` "Reset del sistema" →
"Reimposta il sistema"; "con successo" → "correttamente" on
status-page delete confirmations.
- Consistency — paused monitor status unified on "In pausa" across
`common.labels.paused`, monitor status labels, status-bar keys, and
the `bulkPause.*_one/other` copies. Button verbs
"Sospendi"/"Riprendi" kept for brevity; status noun stays "In pausa".
- Mistranslations — `buttons.testNotifications` "Testa" → "Prova";
`buttons.toggleTheme` "Cambia" → "Alterna"; Twilio "Auth token" now
translated; Mongoose `readyState` clarified to "Stato di connessione".
- Register — trimmed "Ancora" from several empty-state titles so they
read like natural Italian empty states.
## Verification
874 leaves in EN and IT, 0 missing / 0 extra, all placeholders and
inline tags preserved, no empty values.
## Changes
- Add `client/src/locales/it.json` — Italian translation of all 874 UI
keys, structure mirrors `en.json` exactly. Placeholders (`{{value}}`,
etc.) and inline tag tokens (`<settingsLink>`, `<highlight>`, ...)
are preserved. Product/brand names, technical abbreviations, and
placeholder-style examples (e.g. `you@example.com`) are kept in
English. 116 leaves are intentionally kept verbatim in English
(brand names, protocol names, sample values, port numbers, regex).
- Register `it: "Italiano"` in `LanguageSelector`'s `languageNames`
map so the dropdown shows the localised name; the selector already
picks up any locale present in the i18n resources.
- Fill in the two "How do I..." sections that CONTRIBUTING.md's table
of contents already links to but did not have bodies:
- "Improve the documentation?" — short guidance on doc PRs and
keeping README translations in sync.
- "Help with translations?" — describes the current per-language
JSON workflow (source of truth: `en.json`; improve an existing
language by editing its JSON; add a new one by adding a JSON file
and registering the display name in `LanguageSelector`). Notes
that the older PoEditor sync workflow is no longer authoritative.
## Benefits
- Italian speakers can now use Checkmate in Italian.
- Contributors who follow the "Help with translations?" link from
the CONTRIBUTING TOC land on real, current guidance instead of a
broken anchor.
- Translation quality can be improved incrementally by anyone
editing `it.json` directly; no external tooling required.
The notice now triggers on interface names (loopback / container-bridge
only), not on zero traffic. Update the variable, i18n key, and English
copy to match:
- showNoTrafficNotice -> showLoopbackOnlyNotice
- pages.infrastructure.charts.labels.netNoTraffic ->
pages.infrastructure.charts.labels.loopbackOnlyNotice
- English string rewritten to describe the loopback-only condition
rather than "zero traffic on every interface"
Other locales still hold the old string under the old key and will fall
back to English until the translation pipeline picks up the new key.
Tracked separately.
The notice at the top of the network charts was firing whenever the aggregated
per-second delta was zero across all interfaces. That is a false positive when
Capture is running on a real host but the polling interval is >= 1 minute and
the aggregation bucket is also 1 minute — first == last in the bucket, delta
is zero, but the interface has plenty of real traffic in its cumulative
counters.
Base the notice on interface names instead: only show it when the ONLY
interfaces Capture reports are loopback / container-bridge names (lo, lo0,
docker0). Real NICs (enp0s6, eth0, wlan0, tunN, vethN, brN, etc.) keep the
notice hidden even when the aggregation currently reports zero throughput.
The underlying zero-throughput bug (single-sample buckets producing zero
deltas) is tracked separately.
The customCSS field on status pages was persisted and validated
end-to-end but never rendered on the public page, so operator-supplied
styles had no effect.
Inject the string as a <style> tag on the public route (which the
admin preview iframe also renders), reusing the existing
cssReferencesExternalResource check so external-resource CSS
(@import, url(http…), //…) is dropped defensively on the client.
The admin preview iframe already points at the public URL, so this
one insertion covers both the live page and the in-app preview.
The preview framed the page public URL, which for a custom domain is cross
origin and blocked by the admin document CSP frame-src. Point the iframe at the
same-origin public path while the frame chrome still shows the public URL.
The form only enforced the length cap, so CSS with an external url() or @import
passed client validation and was rejected by the server. Add the same tokenizer
based check with the same error message so it is caught inline before submit.
- Add standard custom HTTP status codes (Cloudflare, AWS ELB, etc.) to both frontend and backend allowlists.
- Enforce strict validation of custom status codes using Zod sets on both sides, ensuring they match perfectly.
The preview previously rendered the themed status page inline in the
admin document, so document-global concerns leaked in both directions:
custom CSS spilled into the admin UI and the theme body painting never
showed. Pointing the BrowserFrame at the real public URL in an iframe
isolates the CSS completely and makes the preview pixel-identical to
what visitors see. Auth for unpublished pages keeps working because the
same-origin iframe shares localStorage and the API client reads the
token from the rehydrated store.
Bound customCSS to 100000 characters on both the client schema and the
server body validation (the server is the enforcement boundary; multer's
1MB field cap was the only limit), regenerate the OpenAPI spec, and add
a validation test suite covering acceptance, clearing, the length cap,
and type rejection.
The customCSS field existed on the model, types, and form schema but was
never editable, sent to the API, or rendered. Wire it end to end:
- Accept customCSS in the create/update status page body validation and
regenerate the OpenAPI spec
- Add a Custom CSS editor (multiline field) to the status page form and
include the value in the submitted form data
- Support multiline mode in the shared TextInput component
- Inject the saved CSS via a style tag when rendering the status page