Files
pl_mail/translations/messages.en.yaml
T
Paul LütznerandClaude Opus 5 ea43b1fe30 fix(compose): the schedule that went nowhere, and eight other things a person hit
Scheduled send did nothing when a time was picked by hand, and it did it
silently. ScheduledSendResolver refuses anything closer than MIN_SECONDS (60s);
the picker only checked whether a time had PASSED, so the entire band between
now and a minute from now sailed through the browser. The server then reported
the refusal with $form->addError() — a ROOT error — and _window.html.twig
rendered only form.toAddresses's errors, so the message went nowhere at all.
Turbo replaced the compose frame with a re-render identical to what was already
on screen: menu closed, composer unchanged, no toast, one request in the
profiler, console clean.

Which is exactly the click a person makes to test the feature — they type the
next whole minute. Every green test used a PRESET; the custom picker appeared
in one test that drives it to a refusal, so "pick a time and have it actually
schedule" was asserted nowhere.

  * the picker mirrors MIN_SECONDS and refuses below it, locally and in words
    that are true of the time chosen ("past" and "too soon" are now two
    different things to be told, in three catalogues)
  * root-level form errors have somewhere to render, so no refusal from
    schedule() can be swallowed again
  * the spec drives the custom picker to a real schedule, all the way to a
    persisted badge in Drafts — and pins the floor case as a local refusal
    with no round trip at all

And the rest of the pass:

  * the signature no longer eats the first paragraph. Clicking the empty space
    BELOW it put the caret at the end of the sign-off, so typing welded onto
    it; those clicks now land in the writing space above. The emptiness check
    counted the signature as not-the-user's-writing unconditionally, so text
    that had landed inside it was subtracted before the count and Send claimed
    a visibly full message had none — the block is skipped only while it is
    untouched.
  * the subject/body confirmations are the in-app panel the plain-text switch
    already uses, not window.confirm(), which froze a test session three times.
    Both reasons are one question asked once, and the retry goes back through
    the same submitter so a scheduled send stays scheduled.
  * the To field: the refusal clears when a recipient is added, names the
    invalid address rather than blaming the count, and keeps what was typed
    (Tom Select wiped the box on blur before submit ever saw it). The
    suggestion panel no longer reopens over the Subject row on every focus.
  * aria-invalid and aria-describedby tie the refusal to the input; the From
    select and the Tom Select original are named; the picker's refusal is a
    role="alert".
  * a subject typed on its own is worth autosaving — the threshold counted the
    body alone, so "TEST-RELOAD halbfertig" was lost on reload with no warning
    and nothing in Drafts. Below the threshold, beforeunload interrupts.
  * the emoji panel is capped against the compose WINDOW rather than the
    viewport (its top edge sat 33px outside it), the grid's scrollbar is thin
    rather than a 15px native bar with arrows, and the skin-tone button is off
    the panel outline.
  * vergrößern, Schriftgröße, groß — the compose labels were the only corner
    of the UI spelling it the Swiss way, and a spec was asserting it.

phpunit OK (3427 tests, 8849 assertions); composer stan [OK] No errors;
120 compose e2e passed, plus 48 adjacent.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 12:56:29 +02:00

2570 lines
115 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
account:
add_title: Add account
added: Account added successfully
disabled: Account disabled
enabled: Account enabled
form:
email: Email address
encryption: Encryption
imap:
heading: Incoming — IMAP
host: Host
password: Password
port: Port
preset:
label: Provider
placeholder: Choose a provider…
smtp:
heading: Outgoing — SMTP
host: Host
username: Username
oauth:
google: Continue with Google
info: Sign in with your provider — no password stored.
microsoft: Continue with Microsoft
removed: Account removed
tabs:
imap: IMAP / SMTP
oauth: OAuth
test:
button: Test connection
imap: IMAP
smtp: SMTP
updated: Account updated
admin:
accounts:
account: 'Account'
heading: 'Accounts'
last_activity: 'Last activity'
messages: 'Messages'
threads: 'Threads'
ago: 'ago'
config_backup:
change:
absent: 'nothing set here yet'
differs: 'replaces a different value'
unchanged: 'already identical'
disposition:
applied: 'Written, and in force now.'
applied-on-restart: 'takes effect on next restart'
external: >-
plMail is a client of the system this belongs to, not its owner. The
database role was created with the password Postgres already holds, and
only an initdb reads a new one — so changing it here alone gives you an
installation that cannot connect to its own database. Change it in Postgres
first, then here.
kept-deliberately: >-
Kept as it is here, on purpose. The credentials out of this backup were
re-encrypted with this installation's key as they were written, so putting
the backup's key in place would make them — and everything else already
stored — unreadable at the next start. The line below is only for the case
where you are also restoring the old database, whose rows are encrypted
with it; then it has to go in before anything is stored.
not-writable: >-
This process could not write that path. Read-only secrets volume, wrong
uid, or a service that was never given the volume. The value is in the
backup you just uploaded — put it there yourself.
shadowed-by-compose: >-
Written, but something in the process environment sets this name too, and
the entrypoint lets an explicitly configured value win over the generated
one. Remove or update it in your compose file — or in the `.env` beside it
— and restart; the restored value is already waiting underneath.
error:
malformed-document: >-
The password opened that file, but what is inside is not a configuration
backup this plMail can read. Nothing has been changed.
not-a-backup: >-
That is not a plMail configuration backup. Nothing has been changed.
unsupported-version: >-
That backup was written by a newer plMail than this one, in a format this
version cannot read. Upgrade first, then import it.
wrong-password: >-
That password does not open this file — or the file has been altered since
it was written. Nothing has been changed.
export:
error:
mismatch: 'The two passwords did not match, so nothing was exported.'
too_short: 'That password is too short, so nothing was exported.'
heading: 'Export configuration'
intro: >-
Every setting and credential this installation runs on, in one
password-encrypted file: the environment values, the files in the secrets
volume, the provider and Firebase credentials from the database, and the
people — each with their password, their second factor, their mailboxes
and everything else they configured. No mail, no calendar entries and no
contacts; those are what `app:backup` is for.
generate: 'Generate one'
generated_copied: 'Copied to your clipboard — store it somewhere that outlives this machine.'
generated_shown: 'Your browser would not share its clipboard, so the password is shown above — store it now.'
password: 'Password'
password_help: >-
At least %length% characters. It is never stored anywhere, and there is no
way to open the file without it.
password_repeat: 'Repeat password'
submit: 'Download backup'
warning: >-
The file that comes out is every secret this installation has, protected by
nothing but the password you type here. Keep it the way you would keep the
encryption key itself.
import:
error:
no_file: 'No file arrived, or it was far larger than a configuration backup can be.'
no_password: 'Enter the password this backup was sealed with.'
file: 'Backup file'
heading: 'Import configuration'
intro: >-
Upload a backup and enter its password. Nothing is written until you have
seen what it would do and confirmed it.
password: 'Password'
submit: 'Review this backup'
review:
already_matching: '%count% more already match this environment, so there is nothing to do about them.'
apply: 'Apply this backup'
applied: 'What was written'
confirm_password: 'Password, once more'
exported_at: 'Exported'
from: 'From'
heading: 'Review this backup'
instructed: 'These are yours to do'
instructed_lead: >-
Everything else is in place. These few cannot be finished from here, and
each one says why — saying otherwise would be a lie an operator only
discovers on the day it matters.
kept_users: 'Already here — kept as they are'
kept_users_lead: >-
This installation already has these people, matched by email address.
Nothing about them was touched: not their password, not their second
factor, not their mailboxes or anything else they had set up. A backup is
a photograph of a moment that has passed, and writing it over a live
account is how somebody is locked out of their own mail without a word
anywhere.
notes: 'Worth knowing'
old_key_summary: 'Also restoring the old database? You will need its old encryption key.'
restart: >-
Most of this is read when the stack starts, so plMail writes it into the
generated secrets and it takes effect on the next restart. That is one
restart for the whole list, not one per value.
restart_applied: >-
Written. The values read at container start are in place but not yet in
force — restart the stack once and this installation comes up as the one
the backup was made from.
unknown_instance: 'not recorded'
written: 'plMail writes these'
written_applied: 'Written'
written_none: 'There is nothing in this backup for plMail to write.'
section:
database: 'Database'
env: 'Environment variables'
files: 'Files in the secrets volume'
users: 'People and everything they set up'
db:
active:
empty: 'No active queries right now.'
heading: 'Live activity'
cache_hit: 'Cache hit'
col:
calls: 'Calls'
hit: 'Cache'
max: 'Max ms'
mean: 'Mean ms'
query: 'Query'
rows: 'Rows'
total: 'Total'
connections: 'Connections'
deadlocks: 'Deadlocks'
extension_missing: 'pg_stat_statements is not enabled — slow-query aggregation is unavailable. Enable it once:'
extension_enable: "Enable it now"
extension_enable_hint: "Statistics start from the moment the extension is created, so earlier queries will not appear."
extension_enable_failed: "Could not enable the extension - the database role is not allowed to create it."
heavy_total:
heading: 'Heaviest queries (by total time)'
hint: 'Cumulative time across all calls — where the DB spends its time overall.'
reset: 'Reset stats'
reset_confirm: 'Reset all collected query statistics?'
rollback_ratio: 'Rollback ratio'
slow_mean:
empty: 'No statements above the threshold yet.'
heading: 'Slowest queries (by mean time)'
hint: 'Statements averaging ≥ 5ms, current database.'
failed:
delete: 'Delete'
delete_confirm: 'Permanently drop this failed message?'
empty: 'Failure transport is empty. 🎉'
heading: 'Failed messages'
purge: 'Purge all'
purge_confirm: 'Permanently drop every failed message? They cannot be retried afterwards.'
retry: 'Retry'
retry_all: 'Retry all'
retry_all_confirm: 'Re-dispatch every failed message?'
integrations:
base_url_per_user: 'Each user enters their own server address.'
base_url_pinned: 'pinned for all users'
clear_secret: 'Remove the stored client secret'
configure: 'Configure'
connected_users: '%count% connected'
connected_users_one: '1 connected'
copy_redirect_uri: 'Copy redirect URI'
inherit_toggle: 'Use these credentials for file storage too'
inherit_toggle_help: 'One Google project also covers Drive and Photos; one Microsoft app also covers OneDrive. Leave this on and there is nothing more to set up for them.'
field:
base_url: 'Server address'
base_url_help_saas: 'Leave empty. This service has one fixed address.'
base_url_help_selfhosted: 'Optional. Set this to pin every user to one server; leave it empty to let each user enter their own.'
client_id: 'Client ID'
client_secret: 'Client secret'
enabled: 'Offer this service to users'
enabled_help: 'When off, nobody can connect to it and it stays hidden from the compose and save-to menus.'
push_token: 'Push verification token'
push_token_help: 'Shared secret Google includes in every Pub/Sub push; the webhook rejects notifications without it. Leave empty to fall back to GMAIL_PUBSUB_VERIFICATION_TOKEN.'
pubsub_topic: 'Pub/Sub topic'
pubsub_topic_help: 'Full topic name Gmail publishes changes to. Without it, accounts stay on polling instead of push. Leave empty to fall back to GMAIL_PUBSUB_TOPIC.'
redirect_uri: 'Redirect URI'
tenant: 'Tenant'
tenant_help: 'Leave as common for personal and work accounts, organizations for work only, or a tenant ID to restrict to yours. It must match the app registration''s supported account types.'
redirect_uri_help: 'Paste this into the provider''s console exactly as shown. It cannot be changed later without breaking existing connections.'
inherit: 'Reuse %name% credentials'
inherit_help: 'Copies the client ID and secret across, server-side — the secret is never shown. It does not grant the extra permission the service needs; add that at the provider as the setup steps describe.'
inherited: 'Credentials copied'
mail:
calendar_heading: 'Calendar sync uses this same app'
calendar_google: >-
Nothing to set up here. Enable the Google Calendar API for this
project and add the .../auth/calendar scope to the consent
screen — users then get their calendars with the same sign-in
they already use for mail. Without it, mail keeps working and
calendars simply do not appear.
calendar_microsoft: >-
Nothing to set up here. Add the Calendars.ReadWrite delegated
permission to this app registration — users then get their
calendars with the same sign-in they already use for mail.
Without it, mail keeps working and calendars simply do not
appear.
env_note: 'Leaving these empty falls back to GOOGLE_OAUTH_* / MICROSOFT_OAUTH_* in the environment, so an installation already configured that way keeps working.'
from_env: 'From environment'
google: 'Gmail sign-in'
heading: 'Mail sign-in'
intro: 'The OAuth app users sign in through when they add a mail account. Google and Microsoft file integrations can reuse the same credentials.'
microsoft: 'Microsoft mail sign-in'
saved: 'Mail sign-in saved'
intro: 'Services users can attach files from and save attachments to. Every service is listed here, including the ones plMail cannot talk to yet.'
not_set: 'Not set'
saved: 'Integration settings saved'
secret_none: 'No secret stored'
secret_stored: 'Stored'
secret_unchanged: 'Leave blank to keep the stored secret'
status:
disabled: 'Disabled'
enabled: 'Enabled'
incomplete: 'Needs credentials'
unimplemented: 'Not available yet'
tutorial:
caldav:
intro: 'CalDAV authenticates with a per-user app password against the user''s own server, so there is nothing to register here.'
not_for_cloud_mail: 'Gmail and Outlook calendars do not come in this way. They ride the mail sign-in above, and need only the calendar permission ticked on that app registration.'
security: 'Users should create an app-specific password rather than use their login password: app passwords are individually revocable and work with two-factor authentication. iCloud and Fastmail accept nothing else.'
step_app_password: 'Each user creates an app password on their own server — Nextcloud under Settings → Security, iCloud at appleid.apple.com, Fastmail under Settings → Password & Security — and pastes it into their own calendar settings.'
step_base_url: 'Optionally pin the server address, for example https://cloud.example.com, if everyone here uses the same server.'
step_enable: 'Turn on "Offer this service to users" above.'
step_url: 'The address to enter is the CalDAV one, not the web interface: Nextcloud shows it under Calendar → Settings → "Copy primary CalDAV address", and it usually ends in /remote.php/dav. A bare domain works too — plMail asks it where its calendars live.'
dropbox:
intro: 'Dropbox needs an app registered in the Dropbox developer console.'
refresh_note: 'Choose the scoped access app type and request offline access, or connections will stop working after a few hours.'
step_app: 'Create an app at dropbox.com/developers/apps with scoped access to the full Dropbox.'
step_paste: 'Copy the app key and app secret into the fields above.'
step_permissions: 'Under Permissions, enable files.metadata.read, files.content.read and files.content.write.'
step_redirect: 'Under Settings, add the redirect URI shown above to the OAuth 2 redirect URIs.'
google:
separate_from_gmail: 'These credentials are separate from the Gmail ones in your environment file. You may reuse the same Cloud project, but the consent screen must list the extra scopes.'
step_consent: 'Configure the OAuth consent screen and add the scopes listed below.'
step_credentials: 'Create an OAuth 2.0 Client ID of type Web application.'
step_paste: 'Copy the client ID and client secret into the fields above.'
step_project: 'Open console.cloud.google.com and select or create a project.'
step_redirect: 'Add the redirect URI shown above to the authorised redirect URIs.'
google_drive:
intro: 'Google Drive uses OAuth, so plMail must be registered with Google before anyone can connect.'
scopes: 'Scope needed: the full drive scope. drive.file would be narrower, but it only ever sees files plMail itself created, so a browser would show an empty Drive — and share links need write access to the file being shared. This is a restricted scope: Google requires app verification before users outside your test list can consent.'
step_api: 'Enable the Google Drive API for the project.'
google_photos:
intro: 'Google Photos uses OAuth and its own API, separate from Drive.'
scope_warning: 'Google restricted the Photos read scopes in March 2025. A newly registered app is generally granted only appcreateddata, which sees nothing but media plMail itself uploaded — browsing an existing library needs the photoslibrary.readonly scope, which Google grants case by case. Saving attachments to Photos works either way; browsing may show an empty library until that scope is approved.'
step_api: 'Enable the Photos Library API for the project.'
immich:
intro: 'Immich authenticates with a per-user API key, so there is nothing to register here.'
no_share_links: 'Immich cannot create a public link for a single photo — sharing is album-level. Photos above the attachment size limit therefore cannot be attached at all.'
step_base_url: 'Optionally pin the server address, for example https://photos.example.com.'
step_enable: 'Turn on "Offer this service to users" above.'
step_key: 'Each user generates an API key in Immich under Account Settings → API Keys and pastes it into their own integration settings.'
nextcloud:
intro: 'Nextcloud authenticates with a per-user app password, so there is nothing to register here.'
security: 'Users should create an app password, not use their login password: app passwords are individually revocable and work with two-factor authentication.'
step_base_url: 'Optionally pin the server address, for example https://cloud.example.com.'
step_enable: 'Turn on "Offer this service to users" above.'
step_user: 'Each user creates an app password in Nextcloud under Settings → Security → Devices & sessions and pastes it into their own integration settings.'
one_drive:
intro: 'OneDrive uses Microsoft Graph, the same API as Microsoft mail accounts, but needs Files permissions that the mail registration does not grant.'
step_paste: 'Copy the application (client) ID and the secret value into the fields above.'
step_permissions: 'Under API permissions, add the delegated Microsoft Graph permissions Files.ReadWrite and offline_access.'
step_redirect: 'Under Authentication, add the redirect URI shown above as a Web platform redirect.'
step_register: 'Open the Azure portal and register an application under Microsoft Entra ID → App registrations.'
step_secret: 'Under Certificates & secrets, create a client secret and copy its value immediately — it is shown only once.'
tenant_note: 'Use the common tenant for personal Microsoft accounts, or your tenant ID to restrict access to your organisation.'
tutorial_heading: 'Setup'
unimplemented_notice: 'plMail cannot talk to this service yet. You can register the credentials now — they will be used as soon as support ships.'
loading: 'Loading…'
maintenance:
heading: Maintenance
heartbeats_help: 'Clears rows left behind by processes that died without shutting down cleanly.'
heartbeats_prune: 'Prune stale heartbeats'
heartbeats_title: 'Stale heartbeats'
restart: 'Restart workers'
restart_app: 'Restart now'
restart_app_help: >-
Ends the process serving this page so compose recreates it. Needed after
the generated secrets are rotated: the entrypoint exports them as
environment variables and the kernel boots once in worker mode, so a
running web container never picks up a new value. About two seconds of
downtime, and this page comes back on its own.
restart_app_title: 'Restart the web container'
restart_confirm: 'Restart the workers, scheduler and IMAP supervisor? In-flight work finishes first.'
restart_help: 'Stops the workers, scheduler and IMAP supervisor so their containers are recreated. Long-running processes cache database mappings for their whole lifetime, so they need this after a migration.'
restart_pending: 'Restart requested %seconds%s ago — processes finish their current work, then reappear here within a minute or two.'
restart_title: 'Restart long-running processes'
run_help: 'Queued for a worker, not run here. These are the same sweeps the scheduler runs unattended.'
run_title: 'Run a maintenance task now'
task:
mail_sync: 'Sync mail'
monitoring_prune: 'Prune monitoring data'
prune_blobs: 'Prune blobs'
push_renew: 'Renew push subscriptions'
logs:
all_channels: 'All channels'
clear: 'Clear'
clear_confirm: 'Delete the %count% log entries matching this filter?'
copied: 'Copied'
copy: 'Copy entry'
copy_failed: 'Copy blocked by the browser'
empty: 'Nothing logged at this level.'
entries: 'entries'
heading: 'Logs'
newer: 'Newer'
older: 'Older'
page: 'Page'
refresh: 'Refresh'
nav:
backup: Backup
database: Database
integrations: Integrations
logs: Logs
push: Push
reset: Reset
system: System
users: Users
processes:
empty: 'No heartbeats yet — processes report here after their first beat.'
heading: 'Processes'
key: 'Instance'
last_beat: 'Last beat'
pid: 'PID'
type: 'Type'
push:
calendar_domain_verification: >-
Google will not open a watch channel unless the callback domain is
verified in the Cloud project that owns the OAuth client: verify it
in Search Console, then add it under Domain verification in the
Cloud console. Microsoft needs no equivalent step.
calendar_routes: >-
Calendar push is delivered separately, to %google% and %graph%, and
needs no Pub/Sub topic.
calendar_without_public_address: >-
Without a public HTTPS address, connected calendars simply stay on
the fifteen-minute sweep.
deliveries:
all_outcomes: 'Any outcome'
all_transports: 'Both transports'
all_users: 'All users'
attempts: 'attempts'
empty_ever: >-
Nothing has been pushed yet. Either no device has completed the
verification handshake, or neither transport is configured —
the panel above says which.
empty_filter: 'No delivery matches this filter.'
heading: 'Recent deliveries'
newer: 'Newer'
older: 'Older'
outcome:
accepted: 'Accepted'
failed: 'Failed'
skipped: 'Skipped'
subscription-destroyed: 'Device dropped'
page: 'Page'
refresh: 'Refresh'
transport:
fcm: 'Firebase'
webpush: 'Web Push'
fcm:
android_package: 'Android package'
api_key: 'API key'
application_id: 'Application ID'
clear_key: 'Forget the stored key'
clear_key_help: 'Removes the service-account key and switches FCM off. Devices already registered stop receiving notifications until a new key is saved.'
client_email: 'Service account'
enable_without_client: 'There is no google-services.json on file — the Android app would have nothing to initialise Firebase with. Paste one below, or leave FCM switched off.'
enable_without_key: 'There is no service-account key on file — paste one below, or leave FCM switched off.'
field:
enabled: 'Deliver notifications over FCM'
enabled_help: 'Clients see this as "fcm" in the session capability, and only offer Firebase when it is on.'
google_services: 'google-services.json'
google_services_help: 'Firebase console → Project settings → Your apps → the Android app → google-services.json. The app is one build for every installation, so it initialises Firebase from these values at runtime — they are public and are published in the JMAP session.'
service_account: 'Firebase service-account key (JSON)'
service_account_help: 'Firebase console → Project settings → Service accounts → Generate new private key. Paste the whole file. It is stored encrypted and never shown again. It must belong to the same project as the google-services.json below.'
heading: 'Firebase Cloud Messaging'
intro: 'FCM is how a native Android app receives notifications in the background. It is optional — a device running a UnifiedPush distributor needs none of this, and neither does the browser app.'
paste_none: 'Paste the whole JSON file here'
paste_unchanged: 'One is on file — leave blank to keep it'
project: 'Firebase project'
save: 'Save'
saved: 'Firebase settings saved.'
sender_id: 'Sender ID'
status:
incomplete: 'Half configured'
key_only: 'Configured, switched off'
live: 'Live'
unconfigured: 'Not configured'
webpush_note: 'Web Push needs nothing here. Its VAPID keys are environment variables, generated once by app:push:generate-vapid-keys, and they serve browsers, the installed PWA and UnifiedPush distributors alike.'
queues:
due_in: 'due in %duration%'
empty: 'No pending messages.'
filter_placeholder: 'Filter the whole queue — handler, payload, queue name'
heading: 'Messenger queues'
in_flight: 'Running now'
loading: 'Loading…'
showing: '%shown% of %total%'
next_up: 'Waiting'
none_running: 'No worker is holding a message right now.'
oldest: 'Oldest waiting'
pending: 'Pending'
queue: 'Queue'
queued_for: 'queued %duration%'
retries: 'retry %count%'
running: 'Running'
running_for: 'for %duration%'
waiting_since: 'Waiting since'
refresh_hint: 'Live panels refresh every 10s'
# Shown in a card's header while it is collapsed — short enough to read at
# a glance, specific enough to be worth expanding for.
summary:
accounts: '%count% accounts'
active: '%count% active'
armed: '%active%/%total% armed'
down: '%count% down'
failed: '%count% failed'
failing: '%count% failing'
healthy: '%count% healthy'
idle: 'idle'
none: 'none'
ok: '%count% ok'
queries: '%count% queries'
queue: '%running% running · %waiting% waiting'
tables: '%count% tables'
reset:
button: 'Reset'
confirm_label: 'Type %name% to confirm'
confirm_mismatch: 'That is not %name%, so nothing was deleted. Type the instance name exactly as it is shown.'
done:
continue: 'Create the first administrator'
footnote: 'plMail is back to the state a fresh install starts in.'
heading: 'plMail has been reset'
lead: 'All %count% tables were emptied, along with the stored attachments, raw messages and uploads. There are no users left, so this session has been signed out.'
page_title: 'Reset complete'
restart_failed: 'The web container could NOT be restarted from here — run the command above yourself before using plMail.'
restart_sent: 'The web container was asked to restart and comes back on its own. Everything else in the stack still needs the command above.'
secrets_heading: 'The generated secrets were discarded'
tagline: 'Nothing left to sign in to'
workers_failed: 'The workers could not be signalled either, so they keep using the old encryption key until something restarts them.'
heading: 'Reset data'
intro: 'This permanently deletes synced data from the database. Each step deletes everything the step above it does, and more.'
monitoring_kept: 'Monitoring data is kept. Clear the aggregated logs from Logs, and stale heartbeats from Maintenance.'
postgres_password: >-
POSTGRES_PASSWORD is not rotated. Postgres was initialised with it and keeps
it in its own data directory, so regenerating it would leave plMail unable to
log in to the database it just reset. Changing that one means wiping the
database volume — docker compose down -v — which this cannot do.
restart_required: 'Restart the whole stack immediately afterwards, and before using plMail:'
self_restart: 'The web container asks itself to exit once this page has been sent, and compose brings it straight back. The workers are signalled too; the command above covers the rest of the stack.'
self_restart_unavailable: 'This process cannot restart itself here, so the command above is the only way. Nothing will happen automatically.'
stage:
accounts:
confirm: 'Delete the accounts as well? Every mailbox password and OAuth connection has to be entered again.'
deletes: 'The above, plus the accounts themselves, aliases included. Every mailbox password and OAuth connection has to be set up from scratch. Your own sign-in is untouched.'
title: 'Mail, structure, contacts and accounts'
contacts:
confirm: 'Delete every synced message, folder, label and harvested contact?'
deletes: 'The above, plus harvested contacts. They are collected again from mail as it arrives, so address autocomplete starts empty.'
title: 'Mail, structure and contacts'
full:
button: 'Erase this install'
deletes: >-
Everything, not just synced mail: every user (you included), every account
and its stored password, and the files on disk. The install goes back to
asking for its first administrator. You are signed out and cannot sign
back in.
title: 'Full reset'
full_secrets:
button: 'Erase this install and rotate secrets'
deletes: >-
Everything above, and the generated secrets. Every service is still
running with the old APP_ENCRYPTION_KEY in memory and keeps using it
until restarted, so anything saved before you restart the stack becomes
unreadable to half of it.
title: 'Full reset and new secrets'
structure:
confirm: 'Delete every synced message, thread, folder and label? The next sync rebuilds them.'
deletes: 'The above, plus the mailbox structure — folders and labels. The next sync rebuilds both.'
title: 'Mail and mailbox structure'
synced_mail:
confirm: 'Delete every synced message and thread? Accounts and folders stay, and the next sync fetches the mail again.'
deletes: 'Messages, threads, message parts and anything queued. Accounts, folders and labels stay; the sync cursors are cleared so the next sync fetches everything again.'
title: 'Synced mail'
unrecoverable:
heading: 'Cannot be undone'
lead: 'Neither of these is recoverable by resyncing: they delete the users, the stored mailbox passwords and the files on disk. Type the instance name to confirm — a click on its own is not enough.'
restarting:
back: 'Back to the admin panel'
heading: 'plMail is restarting'
lead: 'The web container was asked to exit and compose brings it straight back. This page reloads itself in a few seconds.'
page_title: 'Restarting'
unavailable_heading: 'Nothing was restarted'
unavailable_lead: 'This process is not the container''s main process, so it cannot end it. Run this instead:'
tables:
heading: 'Table sizes'
title: 'Admin'
tokens:
empty: 'No token refreshes recorded yet.'
heading: 'OAuth token health'
webhooks:
armed: 'Armed'
delivery:
endpoint: 'Push endpoint'
endpoint_hint: >-
The Cloud Pub/Sub push subscription must POST to exactly this
URL, token included. A mismatch is answered with 403 and shows
up below.
heading: 'Delivery path'
info_logs_off: >-
Successful deliveries are logged at info level and not stored.
Set APP_DB_LOG_LEVEL=info to see them here.
no_public_url: >-
APP_PUBLIC_URL is not an https:// address, so Pub/Sub cannot
reach this server.
no_token: >-
GMAIL_PUBSUB_VERIFICATION_TOKEN is not set. The endpoint fails
closed, so every notification is rejected with 403.
topic: 'Pub/Sub topic'
empty: 'No Gmail accounts with watch state.'
health: 'Health'
health_state:
active: 'delivering'
degraded: 'registered, not delivering'
inactive: 'off'
heading: 'Gmail webhooks'
history_id: 'History ID'
last_push: 'Last push'
never: 'never'
none: 'not registered'
resource: 'Resource'
state:
account_active: 'account active'
account_inactive: 'account disabled'
push_off: 'push off'
push_on: 'push on'
watch_expiry: 'Watch expiry'
users:
add: Add user
console_note: 'Passwords and two-factor recovery are handled from the server console, not here. An administrator who could change either would be a second way into every mailbox on this install.'
delete: Remove user
delete_confirm: 'Remove %name%? Their mail stays in the database but they can no longer sign in.'
edit: Edit user
field:
email: Email address
is_admin: Administrator
is_admin_help: 'Can reach this panel, manage users and configure providers. Cannot read anyone else''s mail.'
name_first: First name
name_last: Last name
password: Initial password
password_help: 'Set once, when the account is created. Change it later from the account itself, or reset it from the server console.'
heading: Users
last_login: 'Last seen %when%'
never_signed_in: Never signed in
no_password_edit: 'Passwords cannot be changed from here. Setting someone else''s password would make an admin session a way into their mailbox — the same reason removing a second factor is a console command.'
none: No users yet.
password_too_short: 'Use at least 12 characters — this password is being chosen for someone else.'
role:
admin: Admin
search: Search users…
two_factor_on: Two-factor authentication is on
two_factor_short: 2FA
version:
hint: The build this installation is running — the release, and the commit it was built from.
alias:
added: 'Address added.'
deleted: 'Address removed.'
duplicate: 'That address is already on this account.'
invalid: "That doesn't look like a valid email address."
primary_set: 'Primary address updated.'
refreshed: 'Refreshed from provider.'
status_blocked: "The primary address can't be disabled — make another primary first."
status_set: 'Address updated.'
app:
name: Mail
calendar:
default_name: Personal
alert:
mail:
subject: 'Reminder: %title%'
untitled: Untitled event
booking:
action:
delete: 'Delete the booking page "%name%"'
disable: 'Switch off the booking page "%name%"'
edit: 'Edit the booking page "%name%"'
enable: 'Switch on the booking page "%name%"'
regenerate: 'Give the booking page "%name%" a new address'
badge: Booked through your booking page
booked:
body: 'Your %name% is in the diary.'
mail: A confirmation with a calendar file is on its way to you.
title: That is booked
confirm: Confirm the booking
count: '{0}No booking pages|{1}1 booking page|]1,Inf[ %count% booking pages'
day_none: Nothing free
delete_confirm: 'Delete "%name%"? The appointments already booked through it go with it.'
disabled: 'Off'
duration: '{1} 1 minute|]1,Inf[ %count% minutes'
empty_list: No booking pages yet.
error:
no_calendar: Choose a calendar that accepts changes for bookings to land on.
taken: That time has just been taken. Please choose another.
too_many: >-
That is a lot of bookings from one place. Please wait a while
before trying again.
form:
add: New booking page
buffer_help: Quiet time left either side of anything already in the diary.
buffer_minutes: Buffer (minutes)
busy: Check these calendars for clashes
busy_help: >-
A time is only offered when nothing on these calendars overlaps
it. The calendar bookings land on is always checked, whether or
not it is ticked here.
calendar: Bookings land on
calendar_help: >-
Where the appointment is written. If that calendar syncs
somewhere, the booking goes with it.
day_end: Until
day_start: From
description: What this is about
edit: Edit booking page
horizon_days: Bookable up to (days ahead)
name: What the appointment is called
name_help: >-
Shown to whoever opens the link, and used as the title in your
calendar.
notice_minutes: Shortest notice (minutes)
slot_minutes: Appointment length (minutes)
time_zone: Your hours are in
time_zone_help: >-
The hours above are wall clock in this zone, so 09:00 stays nine
in the morning when the clocks change.
weekdays: Days you are bookable
lands_on: 'lands on %calendar%'
no_slots: There are no free times at the moment. Try again later.
no_slots_this_week: No free times this week. Try the week either side.
note: Anything else? (optional)
pick_a_time: Pick a time
toast:
created: Booking page created. Copy its address now — it is not shown again.
deleted: Booking page deleted.
disabled: Booking page switched off.
enabled: Booking page switched on.
regenerated: New address. The old one no longer works.
updated: Booking page updated.
weekday:
1: Mon
2: Tue
3: Wed
4: Thu
5: Fri
6: Sat
7: Sun
your_email: Your email
your_email_help: The confirmation and the calendar file go here.
your_name: Your name
zone: 'Times shown in %zone%'
chip:
on_calendars: 'On %calendars%'
delete_confirm: 'Delete "%name%" and every event on it? This cannot be undone.'
empty: Nothing coming up
error:
instance_create: >-
One occurrence cannot be added to a calendar on its own. Choose "All
events" to put this meeting on another calendar.
invalid_times: 'Those times do not work — the end has to come after the start.'
no_copies: 'Nothing was chosen, so nothing was changed. Tick at least one calendar.'
read_only: 'This event is only on calendars that do not accept changes, so it was left where it was.'
event:
alert:
action:
display: Notification
email: Email
amount:
days: '{1} 1 day|]1,Inf[ %count% days'
hours: '{1} 1 hour|]1,Inf[ %count% hours'
minutes: '{1} 1 minute|]1,Inf[ %count% minutes'
at_absolute: 'At %when%'
at_time: At the time of the event
custom: Something else, in minutes
custom_action: How the extra reminder arrives
day_1: 1 day before
hour_1: 1 hour before
legend: Reminders
minutes_10: 10 minutes before
minutes_30: 30 minutes before
minutes_5: 5 minutes before
relation:
after_end: '%amount% after the end'
after_start: '%amount% after the start'
before_end: '%amount% before the end'
before_start: '%amount% before the start'
series_note: >-
Reminders belong to the whole event, so the choice below does
not apply to them.
unreadable: Reminder set somewhere else
all_day: All day
cancel: Cancel
copies:
help: >-
Ticked calendars get this event and every change you save to it.
Unticking one does not remove it: that calendar keeps the copy it
has now and stops receiving updates, so it will show up as its own
entry once the two no longer match.
legend: Calendars
read_only: This calendar does not accept changes
delete: Delete
description: Description
dismiss: Not an event
dismiss_confirm: >-
Remove this event and stop it coming back? Later emails about the
same booking will not put it on the calendar again.
ends: Ends
error:
end_before_start: The end has to come after the start.
summary: This event could not be saved.
title_required: Give this event a title.
extracted_note: >-
This event was found in an email. Editing it stops later messages
about the same booking from overwriting your changes.
location: Location
new: New event
new_on: New event on %date%
repeat: Repeat
save: Save
scope:
instance: This event
instance_note: >-
"This event" changes only the occurrence you opened, so it cannot
add the meeting to a calendar it is not on yet.
legend: Apply to
series: All events
starts: Starts
title: Title
form:
add: New calendar
color: Colour
edit: Edit calendar
name: Name
time_zone: Time zone
time_zone_help: >-
The zone this calendar is read in, and the one an event that carries
no zone of its own is shown in.
grid:
all_day: All day
continues_after: Carries on into the next day
continues_before: Started the day before
keyboard_hint: >-
Hold Alt and use the arrow keys to move this event; add Shift to
change how long it lasts. Enter saves it, Escape puts it back.
pending: >-
Moved to %start% – %end%. Press Enter to save, or Escape to put it
back.
read_only: This calendar does not accept changes, so this event cannot be moved.
reverted: Left where it was.
ics:
error:
no_calendar: Choose a calendar to put the events on.
no_file: >-
Choose an .ics file. If you did choose one, it may be larger
than plMail will read.
no_url: Enter the address the calendar is published at.
export:
calendar: Download "%name%" as a calendar file
calendar_title: Download as .ics
event: Download .ics
import:
calendar: Add them to
dedup_note: >-
An event already on this calendar is updated rather than added
twice, and one already on another of your calendars — from an
invitation, or from a calendar you mirror — is left where it is.
file: Calendar file
file_help: An .ics file, up to %size% MB.
intro: >-
Reads an .ics file — an export from another calendar, or an
invitation somebody sent you — onto one of your calendars.
no_calendars: >-
None of your calendars accepts new events. A mirrored calendar
is a read-only copy; make one of your own first.
submit: Import
title: Import a calendar file
subscribe:
address: Calendar address
address_help: >-
The address a calendar is published at, ending in .ics. A
webcal:// link works too — it is the same address under another
name.
connect: Subscribe to an address
intro: >-
Follow a calendar somebody publishes: public holidays, a fixture
list, or the secret address your own Google or Outlook calendar
offers. plMail re-reads it in the background and shows it beside
your own calendars.
name: Name
name_help: What to call it here. Left empty, the calendar names itself.
read_only_note: >-
A subscribed calendar is read-only — it is a copy of a published
file, so changes made here could never reach it. Anyone who has
this address can read the calendar, so treat a secret one like a
password.
submit: Subscribe
title: Subscribe to a calendar address
toast:
import_empty: >-
That file holds no events plMail can read. Check that it is a
calendar export rather than something else.
import_nothing_new: >-
Nothing to add — every event in that file is already on your
calendars.
imported: '%added% added, %updated% updated, %skipped% skipped.'
subscribed: >-
Subscribed — the calendar will fill in within a minute.
invite:
action:
accepted: Yes
declined: 'No'
needs_action: No reply
tentative: Maybe
attendees: '%count% invited'
cancelled: This meeting has been called off.
organiser: Organised by %name%
organiser_tag: organiser
reply:
body: '%name% has responded %status% to this invitation.'
status:
accepted: Accepted
declined: Declined
needs_action: No reply
tentative: Maybe
toast:
not_sent: >-
Your answer was saved here, but the reply could not be sent to
the organiser.
sent: Your answer has been sent to the organiser.
kind:
call: Call
delivery: Delivery
dining: Reservation
event: Appointment
flight: Flight
lodging: Stay
meeting: Meeting
order: Order
rental: Rental
ticket: Ticket
train: Train
more_count: '%count% more'
nav:
next: Next
previous: Previous
pane:
mode:
calendar: Show the calendar full width
mail: Show the mail
split: Show the calendar beside the mail
resize: Resize the calendar
proposal:
action:
add: Add to calendar
dismiss: Not an event
explain: >-
Found in this message — nothing has been added to your calendar.
toast:
added: Added to your calendar.
dismissed: >-
Dismissed — this date will not be offered again, however often
this message is read.
no_calendar: >-
There is no calendar to add this to, so nothing was saved.
untitled: (no subject)
repeat:
daily: Every day
monthly: Every month
none: Does not repeat
weekly: Every week
yearly: Every year
share:
action:
delete: 'Delete the link "%name%"'
edit: 'Edit the link "%name%"'
regenerate: 'Give the link "%name%" a new address'
revoke: 'Revoke the link "%name%"'
all_day: All day
busy: Busy
busy_free_only: This link shows when the calendar is busy, and nothing else.
count: '{0}No shared links|{1}1 shared link|]1,Inf[ %count% shared links'
covers: '{0}no calendars|{1}1 calendar|]1,Inf[ %count% calendars'
day_free: Nothing on this day.
delete_confirm: 'Delete "%name%"? Anyone still holding its address loses it.'
detail:
description: Description
location: Location
participants: Who is coming
title: Titles
empty: Nothing in this window.
empty_list: No shared links yet.
footer: Shared calendar
form:
add: New shared link
calendars: Which calendars
days: days ahead
edit: Edit shared link
ends_on: Last day
name: What you call it
name_help: >-
Only you see this. It is how you find the link again to change or
revoke it.
reveals: What this link reveals
reveals_help: >-
With none of these ticked, the link shows only when the calendar
is busy. Each box adds one thing on top. An event marked private
stays a plain busy block whatever is ticked here.
rolling_days: Days ahead
starts_on: First day
token_note: >-
The address is shown once, when it is created. It is not stored,
so it cannot be shown again — if you lose it, give the link a new
one.
window: How far it reaches
heading: Shared calendar
minted:
heading: The address for this link
once: >-
Copy it now. It is not stored anywhere, so this is the only time
it can be shown.
not_shared: Not shared
outside_window: Days outside the shared window
page_title: Shared calendar
reveals: 'Reveals %details%'
reveals_busy_free: Busy/free only
revoked: Revoked
subscribe: Add to your calendar
toast:
created: Link created. Copy its address now — it is not shown again.
deleted: Link deleted.
regenerated: New address. The old one no longer works.
revoked: Link revoked.
updated: Link updated.
window:
fixed: Between two dates
rolling: A rolling window from today
window_label: '%from% – %to%'
zone: 'Times shown in %zone%'
soon:
empty: Nothing coming up
empty_hint: >-
Appointments in your calendar, and the flights, deliveries,
reservations and tickets found in your mail, appear here for the
next two weeks.
from: 'From %subject%'
open: What is happening soon
title: Happening soon
untitled: (no subject)
title: Calendar
toast:
created: Calendar created
default_set: New events will land here
deleted: Calendar deleted
disconnected: Server disconnected
disconnected_kept: >-
Server disconnected — %count% event(s) that came from mail rather
than from a calendar were moved to your default calendar.
hidden: Calendar hidden
shown: Calendar shown
subscriptions_saved: Subscriptions saved
subscriptions_saved_kept: >-
Subscriptions saved — %count% event(s) that came from mail rather
than from the calendar were moved to your default calendar.
subscriptions_unchanged: Nothing changed
sync_queued: Syncing now — this calendar will update in a moment.
updated: Calendar updated
today: Today
upcoming:
imminent: Starting within the hour
later: Coming up today
soon: Coming up in a few hours
view:
agenda: Agenda
day: Day
month: Month
week: Week
clipboard:
copied: Copied
copy_failed: Copy failed
compose:
no_account:
body: Add a mailbox first, and you can write from it right away.
cta: Add a mail account
heading: No mail account yet
font_family:
label: Typeface
monospace: Monospace
sans: Sans serif
serif: Serif
font_size:
huge: Huge
label: Text size
large: Large
normal: Normal
small: Small
align:
center: Align center
left: Align left
right: Align right
confirm:
no_body: This message has no text.
no_subject: This message has no subject.
send_anyway: Send it anyway?
plain_text: Switching to plain text removes all formatting from this message. Continue?
# Every label inside the emoji picker. The component ships its own English
# strings and takes a replacement object; this is that object, so the
# picker is as translated as the window around it.
emoji:
activities: Activities
animals_nature: Animals and nature
categories: Categories
custom: Custom
favorites: Frequently used
flags: Flags
food_drink: Food and drink
loading: "Loading…"
network_error: The emoji could not be loaded.
objects: Objects
people_body: People and body
region: Emoji picker
search: Search
search_description: When results appear, press up or down to select one and enter to choose it.
search_results: Search results
skin_tone: "Choose a skin tone (currently {skinTone})"
skin_tone_description: When expanded, press up or down to select one and enter to choose it.
skin_tones: Skin tones
smileys_emotion: Smileys and emoticons
symbols: Symbols
tone_dark: Dark
tone_default: Default
tone_light: Light
tone_medium: Medium
tone_medium_dark: Medium-dark
tone_medium_light: Medium-light
travel_places: Travel and places
unsupported: This browser cannot show colour emoji.
list:
ordered: Numbered list
unordered: Bullet list
priority:
high: High
label: Priority
low: Low
# Distinct from Normal on purpose: an untouched message says nothing
# about its urgency and carries no priority headers at all.
none: No priority
normal: Normal
quote:
hide: hide quoted text
show: show quoted text
schedule:
cancel: Cancel scheduled send
confirm: Schedule send
custom: Pick date & time
error:
past: That time has already passed.
too_far: Mail can be held for at most %days% days.
too_soon: Pick a time at least a minute from now.
unreadable: That is not a date and time.
heading: Send later
monday_morning: Monday morning
scheduled_for: Scheduled to send
timezone_hint: Times are in %zone%.
toast: Scheduled for %when%
# The toast's own action label. `cancel` is the menu's, where there is
# room to say which send is meant; in a toast beside the sentence that
# just named it, the long form pushes the message onto four lines.
toast_cancel: Cancel send
tomorrow_afternoon: Tomorrow afternoon
tomorrow_morning: Tomorrow morning
when: '%date%, %time%'
status:
pending_many: "%count% more characters to save"
pending_one: one more character to save
save_failed: Could not save the draft
saved: Draft saved
saving: "Saving…"
uploading: "Uploading…"
# Why an upload was refused. The compose window prints these as-is on its
# status line, so they are the whole of the explanation the user gets.
upload:
failed: Upload failed
images_only: Only images can be placed in the message body
over_limit: "File too large (max %limit% MB)"
post_too_large: Upload too large
too_large: File too large
add_bcc: Add Bcc recipients
add_cc: Add Cc recipients
attach: Attach files
attach_failed: Could not attach
attach_remove_failed: Could not remove attachment
attach_too_large: "%name% is over %limit% MB"
bcc: Bcc
bold: Bold
cc: Cc
click_to_cancel: click to cancel
continue_editing: Continue editing
discard: Delete draft
empty_draft: (empty draft)
encrypt: Encrypt message
# The whole of what the disabled encrypt button says for itself. It has to
# be a complete sentence: it is the only explanation anyone gets.
encrypt_unavailable: Encryption is not available yet.
expand: Expand
formatting: Formatting options
forward: Forward
from: From
image: Insert image
image_insert_failed: Could not place the image in the message
indent: Indent
insert_emoji: Insert emoji
insert_link: Insert link
invalid_address: "“%address%” is not a valid email address"
italic: Italic
# The insert-link popover, both of its faces. Nothing here is spelled in
# JavaScript: the controller reads the four strings it writes at runtime
# out of a data-…-i18n-value object Twig fills from these keys.
link:
add: Insert link
apply: Apply
cancel: Cancel
change: Change
dialog: Link
edit: Edit link
heading: Link
invalid: Enter a web address.
open: Open
remove: Remove link
text_label: Text to display
text_placeholder: The words that carry the link
unsafe: Only web, mail and telephone addresses can be linked.
url_label: Web address
url_placeholder: "example.com"
minimize: Minimize
more_options: More options
new_message: New Message
no_recipients: No recipients
outdent: Outdent
plain_text: Plain text mode
# The warning that used to be a browser confirm(). The question itself is
# still compose.confirm.plain_text — only the frame around it is new.
plain_warning:
cancel: Keep formatting
continue: Continue
title: Remove formatting?
pop_out: Open in compose window
send_warning:
cancel: Keep editing
continue: Send anyway
title: Send this message?
read_receipt: Request read receipt
recipient_required: Add at least one recipient before sending.
redo: Redo
reply: Reply
reply_all: Reply all
reply_placeholder: "Reply to %name%"
save_and_close: Save draft and close
send: Send
send_options: Send options
sending: "Sending…"
signature: Insert signature
signature_none: No signature set for this address
subject_label: Subj
subject_placeholder: Subject
text_color: Text colour
to: To
underline: Underline
undo: Undo
body_placeholder: "Write your message…"
attachment_remove: Remove attachment
drafts:
empty: No drafts.
heading: Drafts
errors:
access_denied: You do not have access to this resource.
not_found: The requested resource could not be found.
page:
back: Back to your mail
not_found:
body: The page you asked for is not here. The link may be mistyped, or what it pointed at may have been moved or deleted.
heading: Nothing at this address
title: Page not found
server:
body: Something went wrong at our end, not yours. The fault has been logged; trying again in a moment usually works.
heading: Something went wrong
title: Server error
form:
file:
choose: Choose an image…
hint: PNG, JPEG, GIF or WebP
select:
no_results: No matches
cancel: Cancel
submit: Save
header:
labels:
add: Create label
heading: Labels
none: No labels yet
search:
placeholder: Search mail…
user_menu:
account_attention: '%count% things about your accounts need attention'
admin: Admin
label: User menu for %email%
profile: Profile
rerun_setup: Run setup again
unseen_logs:
danger: '%count% new errors in the log'
warn: '%count% new warnings in the log'
settings: Settings
sign_out: Sign out
signed_in_as: Signed in as
inbox:
empty: No messages in this tab.
integration:
save_failed: 'Could not save: %reason%'
saved_to: 'Saved to %name%'
destination:
album_name: 'Album name'
choose_album: 'Choose an album for %file%'
choose_folder: 'Choose a folder for %file%'
create: Create
folder_name: 'Folder name'
library: 'Library (no album)'
new_album: 'New album'
new_folder: 'New folder'
no_albums: 'No albums yet.'
no_subfolders: 'No folders here.'
save_here: 'Save here'
start_over: 'Start over'
picker:
attach: Attach
attach_from: 'Attach from %name%'
attach_from_service: 'Attach from a service'
copy: Copy
empty: 'This folder is empty.'
link: Link
more: 'Show more'
no_results: 'Nothing found for “%query%”.'
search: Search
search_placeholder:
dropbox: 'Search Dropbox'
googleDrive: 'Search Drive'
googlePhotos: 'Search Photos'
immich: 'Describe a photo, e.g. beach at sunset'
nextcloud: 'Search Nextcloud'
oneDrive: 'Search OneDrive'
timeline: 'Jump to a date'
too_big: 'Too large to attach'
label:
all_accounts: All accounts
color:
amber: Amber
blue: Blue
gray: Gray
green: Green
orange: Orange
pink: Pink
red: Red
teal: Teal
violet: Violet
empty: No conversations with this label.
created: Label created.
delete_confirm: 'Delete the label "%name%"? Messages keep their other labels and are not deleted.'
delete_confirm_children: 'Delete "%name%" and its %count% nested label(s)? Messages are not deleted.'
deleted: Label deleted.
error:
duplicate: A label with this name already exists here.
form:
account: Account
color: Color
delete: Delete label
edit_title: Edit label
name: Name
no_color: '— none —'
no_parent: '— top level —'
parent: Nest under
menu:
create: Create new
empty: No labels yet.
updated: Label updated.
visibility:
hidden: Label is now hidden.
shown: Label is now visible.
list:
sort:
newest: Newest first
oldest: Oldest first
login:
form:
email: Email address
forgot_password: Forgot password?
forgot_password_hint: 'Password recovery runs from the server console: bin/console app:user:2fa-disable and a fresh password set by an administrator.'
password: Password
remember_me: Keep me logged in
submit: Sign in
page_title: Sign in
register:
coming_soon: Registration coming soon.
link: Create one
prompt: Don't have an account?
tagline: Sign in to your account
message:
actions:
archive: Archive
delete: Delete this message
expand: Expand or collapse this message
mark_unread: Mark as unread
more: More
print: Print
show_original: Show original
star: Star
unstar: Remove star
attachments: Attachments
back: Back
body_frame: Message content
details:
categorised:
correspondent: 'you have written to this sender'
default: 'nothing marked it as bulk mail'
forum: 'a mailing-list header: '
gmail: 'Gmail said so: '
promotion: 'a bulk-mail header: '
social: 'the sender domain '
update: 'an automated-mail signal: '
category: category
bcc: bcc
cc: cc
copy_address: 'Copy address %address%'
copy_headers: Copy headers
date: date
from: from
hide_all_headers: Hide all headers
label: Details
mailed_by: mailed-by
me: me
reply_to: reply-to
show_all_headers: Show all headers
signed_by: signed-by
subject: subject
to: "to %name%"
to_label: to
undisclosed: undisclosed recipients
draft: "Draft"
images:
always: 'Always show images from %sender%'
blocked: '{1}1 image was blocked to keep this read private|]1,Inf[ %count% images were blocked to keep this read private'
show_once: Show images
stop_trusting: Stop showing
trusted: 'Images are always shown for %sender%'
original:
copied: Copied
copy: Copy to clipboard
heading: Original message
quote:
hide: Hide quoted text
show: Show quoted text
read_receipt:
dismiss: 'No thanks'
mdn:
body: "Your message to %recipient% with the subject “%subject%” was displayed on %date%. This is no guarantee that it has been read or understood."
subject: 'Read: %subject%'
mismatch: 'The receipt was asked to go to %notifyTo%, which is not the address this message was sent from (%sender%).'
read_at: 'Read at %datetime%'
requested: '%sender% asked to be told when you read this message.'
send: 'Send receipt'
save_to: 'Save to'
security:
mismatch:
brand_in_name: "The name says “%claimed%”, but the message was sent from %actual%."
domain_in_name: "The name claims %claimed%, but the message was sent from %actual%."
title: "The sender's name does not match its address"
spam:
body: "This message was filed as spam. Its links and images are risky — treat anything it asks of you as a stranger's request."
title: This message is in Spam
mercure:
status:
connected: Live updates active
connecting: Reconnecting to live updates…
offline: Live updates unavailable — the inbox may be out of date
modal:
close: Close
loading: Loading…
oauth:
error:
generic: We couldn't connect that account. Please try again.
microsoft:
admin_consent_required: >-
Your organisation requires an administrator to approve plMail
before you can connect this account. Please ask your Microsoft
administrator to grant access.
app_not_found: >-
plMail isn't registered in your Microsoft organisation.
bad_credentials: >-
plMail's Microsoft credentials are invalid or expired. This is a
server configuration problem, not something you can fix.
blocked_by_policy: >-
A security policy in your organisation blocked this sign-in.
consent_declined: >-
Connection cancelled — plMail wasn't granted access.
tenant_mismatch: >-
This account type can't sign in to plMail with the current
configuration. Check the MICROSOFT_OAUTH_TENANT setting.
onboarding:
action:
back: Back
finish: Finish
next: Next
skip: Skip this step
skip_all: Skip setup
done:
body: >-
Anything you skipped is in Settings, and you can run this again from the
user menu whenever you like.
cta: Go to my mail
heading: You're all set
aside:
account:
body: >-
plMail needs the incoming (IMAP) and outgoing (SMTP) server addresses for
your provider. They are usually on your provider's help pages under
"IMAP settings".
heading: Where do I find these?
oauth: >-
For Gmail and Outlook, use the sign-in buttons under Settings → Mail
accounts instead — no server addresses needed.
admin_integrations:
body: Register plMail with the service, then paste the credentials it gives you.
heading: Setting this up
admin_mail:
google:
heading: Setting up Gmail sign-in
step1: Open console.cloud.google.com and create a project, or pick an existing one.
step2: 'Under APIs & Services → Library, enable the Gmail API.'
step3: 'Under OAuth consent screen, choose Internal if you have Workspace, otherwise External, and fill in the app name and support email.'
step4: 'Under Credentials, create an OAuth client ID of type "Web application".'
step5: Paste the redirect URI below into its "Authorised redirect URIs", then save.
step6: Copy the client ID and client secret it shows you into the fields on the left.
microsoft:
heading: Setting up Microsoft sign-in
step1: 'Open portal.azure.com and go to Microsoft Entra ID → App registrations → New registration.'
step2: 'Choose who can sign in. "Accounts in any organizational directory and personal Microsoft accounts" matches the default tenant setting of "common".'
step3: 'Set the redirect URI to Web, and paste the address below into it.'
step4: 'After registering, copy the Application (client) ID into the field on the left.'
step5: 'Under Certificates & secrets, create a new client secret and copy its Value — not its ID — straight away; it is only shown once.'
step6: 'Under API permissions, add these delegated Microsoft Graph permissions: Mail.ReadWrite, Mail.Send, MailboxSettings.ReadWrite, Calendars.ReadWrite, User.Read and offline_access. Leaving out MailboxSettings.ReadWrite or Calendars.ReadWrite still signs people in — they simply get no categories and no calendar, and a token already issued is not upgraded when you add the permission later.'
profile:
body: This is what recipients see in the From line. You can change it any time.
heading: Where this shows up
security:
body: >-
Think about what happens if someone gets your email password. They
don't just read your mail — they click "forgot password" on your
bank, your domain registrar, your cloud storage, and collect the
reset links as they arrive.
body_two: >-
A second factor is a code from your phone that changes every 30
seconds. A stolen password on its own stops being enough.
heading: Why this one matters most
account:
add: Add this account
or_manual: 'Or set it up by hand:'
sign_in_with: 'Sign in with %provider%'
add_another: Add another account
cancel: Cancel
integrations:
cancel: Cancel
connect: Connect
connected: Connected
progress: 'Step %index% of %total%'
security:
body: >-
Your mailbox is the key to every other account you have, because that
is where password resets arrive. Adding a code from your phone means a
stolen password is not enough on its own.
done_body: >-
You will be asked for a code from your app when you sign in. Keep the
recovery codes somewhere you can reach without your phone.
done_heading: Two-factor authentication is on
skip_hint: You can set this up later under Settings → Security.
switch_blocked: Nothing was switched — fix the fields below first, and what you entered will be kept.
step:
account:
lead: Connect the mailbox you actually read, and plMail starts syncing it.
title: Mail account
admin-integrations:
lead: Credentials for the services everyone here can attach files from.
title: Integration credentials
admin-mail:
lead: Sign-in credentials for Gmail and Outlook, set once for this whole install.
title: Mail providers
appearance:
lead: How plMail looks. None of this is permanent — change it whenever.
title: Appearance
integrations:
lead: Connect the services you keep files and photos in.
title: Your integrations
profile:
lead: The name that appears on the mail you send.
title: About you
security:
lead: The one account worth locking properly. This takes about a minute.
title: Protect your account
title: Set up plMail
profile:
avatar_current: Current picture
avatar_from:
empty: Nothing to show from this service.
heading: Or pick one from a connected service
avatar_wrong_type: Use a PNG, JPEG, GIF or WebP image.
field:
avatar: Picture
avatar_help: PNG, JPEG, GIF or WebP, up to 4 MB.
avatar_remove: Remove the current picture
name_first: First name
name_last: Last name
search:
empty:
or_keyword: or just type a keyword.
title: Search your mail
try: Try
heading:
results: Search results for
no_results:
hint: Try different keywords or remove some filters.
title: No results for "%query%"
pill:
after: After
attachment: attachment
before: Before
cc: Cc
from: From
has: Has
in: In
is: Is
label: Label
read: read
starred: starred
subject: Subject
to: To
unread: unread
results:
count: '%count% results'
count_one: 1 result
sort:
label: Sort by
recent: Most recent
relevance: Most relevant
title: Search
title_query: 'Search: %query%'
sent:
empty: No sent messages.
heading: Sent
setup:
install:
field:
email: Email address
email_help: This is the address you'll sign in with.
public_url: Public address
public_url_help: >-
Where people reach plMail from outside. Gmail and Outlook send push
notifications back to it, so it has to be reachable from the internet
and should be https. You can change it later.
locale: Language
name_first: First name
name_last: Last name
password: Password
password_repeat: Repeat password
footnote: You'll be able to add mailboxes, and anything else, once you're in.
heading: Create your account
lead: This is the first account on this plMail, so it gets full administrator rights.
page_title: Set up plMail
restore_link: Restore a configuration backup first.
restore_prompt: Moving from another plMail?
submit: Create account and sign in
tagline: Nobody has signed up yet — let's fix that
restore:
applied_lead: >-
The configuration is in place. This backup carried no user accounts, so this
installation still has none — create the administrator account to finish. If a
restart is noted above, it can wait until after that.
applied_lead_users: >-
The configuration and its people are in place — %count% restored, %admins%
among them. Sign in with the password you already had; nothing about it has
changed.
back: 'Back to creating the administrator'
continue: 'Continue — create the administrator'
footnote: >-
A configuration backup carries settings, credentials and the people who use
them — never mail, calendar entries or contacts.
heading: 'Restore a configuration backup'
lead: >-
Bring another plMail's settings, credentials and accounts here before you
create anything. Upload the file and type its password — plMail writes the
rest into this installation itself.
nothing_to_do: 'There is nothing left for you to do here.'
page_title: 'Restore configuration'
sign_in: 'Sign in'
submit: 'Open the backup'
settings:
accounts:
delete: Remove account
delete_confirm: 'Remove %account%? This permanently deletes all synced messages for this account and cannot be undone.'
disable: Disable account
edit: Edit account
empty: No accounts yet. Add one to start syncing mail.
enable: Enable account
heading: Mail accounts
password_help: Leave blank to keep the current password.
primary: Primary
push:
degraded_hint:
gmail: >-
Push is registered but nothing has arrived recently. The
Pub/Sub push subscription in Google Cloud may be missing or
pointing elsewhere. Mail is still syncing on a schedule.
microsoft: >-
The push subscription has lapsed and nothing is arriving.
Re-register it to resume instant delivery. Mail is still
syncing on a schedule.
failed:
gmail: >-
Push couldn't be enabled — Google rejected the watch
registration. Check that GMAIL_PUBSUB_TOPIC names an
existing Pub/Sub topic and that the topic grants
gmail-api-push@system.gserviceaccount.com the Pub/Sub Publisher
role. The account is still syncing on a schedule.
microsoft: >-
Push couldn't be enabled — Microsoft needs to reach this
server over HTTPS. Check your reverse proxy and
APP_PUBLIC_URL. The account is still syncing on a schedule.
health:
active: Push
degraded: Push (not delivering)
inactive: Scheduled
mode_pull: Scheduled
mode_push: Push
not_configured: >-
Push isn't available on this server — it needs a public HTTPS
address and, for Gmail, a Cloud Pub/Sub topic.
off_hint: Mail is checked on a schedule. Turn on push for instant delivery.
on_hint:
gmail: New mail arrives immediately via Gmail push notifications.
microsoft: New mail arrives immediately via Microsoft push notifications.
renews: Subscription renews before %date%.
reregister: Re-register push
title: Instant delivery
reorder: Drag to reorder
status:
active: Active
disabled: Disabled
subheading: Add, edit, enable, or remove the mailboxes you sync.
type:
imap: IMAP
oauth: '%provider% (OAuth)'
aliases:
add: 'Add'
add_placeholder: 'Add another address…'
delete: 'Remove'
disable: 'Disable'
empty: 'No addresses yet.'
enable: 'Enable'
heading: 'Email addresses'
make_primary: 'Make primary'
ms_sender_hint: 'Outlook sends as your account’s primary alias regardless of the address chosen here — change it in your'
ms_sender_hint_link: 'Microsoft account settings'
primary: 'Primary'
refresh: 'Refresh from provider'
subheading: 'Addresses this account sends and receives as.'
system: 'system'
clock:
heading: Clock
subheading: Whether times are written on a twelve- or twenty-four-hour clock. Nothing is stored differently — only the digits change.
label: Clock
follow_language: 'Follow your language (%sample%)'
option:
'12': '12-hour (%sample%)'
'24': '24-hour (%sample%)'
device_pairing:
pair_device: "Pair a device"
scan_title: "Scan this with the plMail app"
scan_hint: "The code works once and expires in two minutes. It doesn't contain your app password — the app exchanges it for a new one."
qr_alt: "Pairing code"
expires: "Expires at %time%."
open_in_app: "Open in the app"
app_passwords:
copy: Copy
copy_now: Here is your new app password
copy_now_hint: >-
Copy it now — it is not stored and cannot be shown again. If you
lose it, revoke it and generate another.
empty: No app passwords yet. Generate one to connect a mail app.
generate: Generate
heading: App passwords
last_used: 'Last used %date%'
name_placeholder: 'What is it for? e.g. iPhone — Sterna'
never_used: Never used
revoke: Revoke
revoke_confirm: 'Revoke "%name%"? Any app using it will be signed out immediately.'
setup_heading: Connecting an app
setup_hint: >-
Use your email address as the username and the app password as the
password. If the app asks for a server or JMAP URL, give it this —
not the /jmap/api address, which only accepts POST.
subheading: >-
Sign in to third-party mail apps that speak JMAP. Each app gets its
own password you can revoke on its own.
appearance:
accent:
heading: Accent colour
background:
heading: Background
theme: Theme default
upload: Upload image
density:
comfortable: Comfortable
compact: Compact
cosy: Cosy
heading: Density
export: Export theme
glass:
heading: Glass
paneAlpha: Opacity
paneBlur: Blur
radius: Corner radius
scrimAlpha: Background dimming
subheading: How much of the background shows through your panels.
import: Import theme
layout:
boxed: Boxed
flat: Flat
heading: Layout
subheading: How the interface is framed. Boxed floats every panel as a card; flat puts the top bar and sidebar straight on the background and keeps only the main pane boxed.
main:
default: Theme default
heading: Main pane
matchGlass: Match glass opacity
subheading: Tint and opacity for the main content area, independent of the sidebar.
tint: Background tint
reset: Reset to defaults
text:
autoDerive: Auto-derive
color: Text colour
default: Theme default
faint: Faint
heading: Text
muted: Muted
subheading: Adjust text colour for legibility against your background.
theme:
dark: Dark
dusk: Dusk
heading: Theme
light: Light
nord: Nord
paper: Paper
solar: Solar
subheading: Colour scheme for the whole interface.
system: System
back: Back to inbox
compose_defaults:
heading: 'Compose defaults'
invalid: 'That setting could not be saved.'
read_receipt:
for_alias: 'Read receipts for %alias%'
hint: 'When a sender asks to be told you have read their message.'
inherit: 'Account default (%mode%)'
label: 'Read receipts'
mode:
always: 'Always send'
ask: 'Ask each time'
never: 'Never send'
saved: 'Saved.'
subheading: 'What each of your addresses does by default when it sends and receives.'
filters:
account: Account
action:
applyLabel: Apply label
archive: Skip inbox
markRead: Mark as read
markSpam: Mark as spam
removeLabel: Remove label
saveToIntegration: Save attachments to
star: Star it
trash: Move to trash
add: New filter
add_action: Add action
add_condition: Add condition
add_group: Add group
all_accounts: All accounts
count: '%count% filters'
count_capped: 'Matches %count%+ existing messages'
count_error: Not a usable filter yet
# Pluralised in the browser, which is where the number changes —
# the builder swaps %count% in without another round trip, so the
# string has to carry both shapes. See rule_builder_controller.
count_exact: 'Matches %count% existing message|Matches %count% existing messages'
delete: Delete filter "%name%"
delete_confirm: 'Delete the filter "%name%"? Mail it already sorted stays where it is.'
delete_title: Delete filter
deleted: Filter deleted.
disable: Disable filter
disabled: Off
edit: 'Edit filter "%name%"'
edit_title: Edit filter
empty: No filters yet
empty_hint: Filters sort mail as it arrives — label it, skip the inbox, star it, or send it straight to the bin.
enable: Enable filter
error:
action_required: Add at least one action, or the filter would do nothing.
name_required: Give the filter a name.
field:
after: Received after
bcc: Bcc contains
before: Received before
body: Body contains
cc: Cc contains
filename: Attachment named
from: From contains
hasAttachment: Has an attachment
hasKeyword: Is
hasLabel: Has label
listId: Mailing list is
maxSize: Smaller than (bytes)
minSize: Larger than (bytes)
notKeyword: Is not
notLabel: Does not have label
subject: Subject contains
text: Anywhere in the message
to: To contains
heading: Filters
join:
and: and
none: 'none of: %list%'
or: or
keyword:
answered: replied to
draft: a draft
flagged: starred
seen: read
integration_missing: '(disconnected service)'
label_missing: '(deleted label)'
move_down: Move "%name%" later
move_up: Move "%name%" earlier
name: Name
name_placeholder: e.g. Invoices from Acme
new_title: New filter
no: No
no_actions: No actions yet
no_integrations: 'No services connected — set one up in Integrations first.'
of_the_following: of the following
op:
all: All
any: Any
none: None
placeholder:
date: Pick a date
number: 0
text: Type a value…
already_running: That filter is already running.
queued: Queued — applying to existing mail in the background.
ran: Filter applied to existing mail.
remove_action: Remove action
empty_group: 'This group is empty — it matches nothing until you add a condition.'
no_conditions: 'No conditions: this rule acts on every message it is scoped to.'
remove_condition: Remove condition
remove_group: Remove group
reorder: Drag to reorder
run: Apply to existing mail
run_state:
completed: 'Applied to %count% messages'
failed: 'Run stopped partway — %count% messages were done'
queued: 'Queued…'
running: 'Applying… %count% so far'
run_confirm: 'Apply "%name%" to mail you already have? This can move and relabel a lot of messages at once.'
saved: Filter saved.
stop: Stop after this filter
stop_help: Later filters are skipped for any message this one matches.
subheading: Sort mail automatically as it arrives.
summary:
every_message: 'this is any message'
# With an account chosen the scope IS the rule, so it is the
# subject of the sentence rather than a clause on the end.
every_message_in: 'this is any message in %account%'
in_account: '%conditions%, in %account%'
full: 'If %conditions% → %actions%'
no_actions: 'If %conditions% → (no actions yet)'
then: Then
when: When
yes: Yes
health:
awaiting:
calendar_resync: >-
Sync started. Waiting to hear how it went — this card will say
what happened as soon as it does.
confirm:
destructive: >-
This throws the waiting work away for good. Nothing is retried
and it cannot be brought back. Continue?
flash:
calendar_resync: >-
%calendar% has been asked to sync. It is running in the
background now, and the card below will say how it went.
queue_discarded: 'Discarded %count% abandoned jobs.'
queue_retried: 'Put %count% abandoned jobs back on the queue.'
heading: 'Account health'
healthy:
body: >-
Your accounts are signed in, your calendars are syncing and
nothing is waiting on you. If mail ever stops arriving, this is
the page that will say why.
title: 'Everything is working'
issue:
account_reconnect:
body: >-
New mail has stopped arriving for this account, and so has
everything that depends on it — calendar syncing, filters
that run on delivery, and sending from this address. The
mail already downloaded is safe and still here. This
happens when a password is changed, two-factor
authentication is switched on, or the sign-in is revoked
from the provider's security page.
title: '%account% needs you to sign in again'
calendar_sync_failing:
body: >-
This calendar has stopped picking up changes, so it is
showing what it knew the last time it worked. Events added
or moved elsewhere since then are not here yet, and changes
you make here are not being sent out.
title: '%calendar% has stopped syncing'
integration_reconnect:
body: >-
Saving attachments to %connection% and attaching files from
it will not work until it is connected again. Your mail is
unaffected — this is only the link to that service. Nothing
stored there has been touched.
title: '%connection% needs reconnecting'
push_degraded:
body: >-
Your mail is still arriving, just not the instant it is
sent — this account has fallen back to checking on a
schedule, so new messages can take a few minutes to show
up. Nothing is lost, and there is no rush to fix it.
title: 'Instant delivery is off for %account%'
queue_work_abandoned:
body: >-
%count% background jobs tried, failed repeatedly, and were
set aside so they would stop retrying. This is usually the
aftermath of one of the problems above rather than a
separate fault — fix that first, then put these back on the
queue.
title: '%count% background jobs were given up on'
outcome:
calendar_failed_again: >-
It failed again. What it said this time is below — the sync ran,
it just did not work.
calendar_still_waiting: >-
The sync was started, but nothing has come back yet. Try again,
or reload the page to see where it got to.
calendar_synced: 'Synced. This calendar is up to date again.'
pending:
calendar_resync: 'Starting sync…'
push_resubscribe: 'Turning it back on…'
queue_discard: 'Discarding…'
queue_retry: 'Putting them back…'
reconnect: 'Taking you to %provider%…'
reconnect_generic: 'Taking you to sign in…'
repair:
calendar_resync:
label: 'Try syncing now'
promise: >-
Asks this calendar to sync again right away, and puts it
back on the normal schedule. Nothing on it is deleted.
integration_reconnect:
label: 'Reconnect'
promise: >-
Sends you to sign in again, then restores the existing
connection. Your filters and saved destinations keep
working.
push_resubscribe:
label: 'Turn instant delivery back on'
promise: >-
Registers this account for instant delivery again. Your
mail keeps arriving either way while this is sorted out.
queue_discard:
label: 'Discard them'
promise: >-
Throws the abandoned jobs away without running them. There
is no undo, and anything they had not finished stays
unfinished.
queue_retry:
label: 'Put them back on the queue'
promise: >-
Tries the abandoned jobs once more. Safe to press — any
that fail again simply end up back here.
reconnect:
label: 'Reconnect this account'
promise: >-
Takes you to sign in again, then puts the new sign-in onto
this same account. Your mail, folders, labels, filters,
calendars and settings all stay exactly as they are —
nothing is downloaded again and nothing is deleted. You
must sign in as %account%; if you pick a different address
it will be refused rather than swapped in.
reconnect:
done: '%account% is connected again. Mail and calendar syncing will catch up over the next few minutes.'
wrong_account: >-
That signed you in as %actual%, but this account is %expected%.
Nothing has been changed. Sign out of %actual% with that
provider, then try again — swapping the address would have
mixed a different mailbox into this one.
subheading: >-
Anything that has stopped working, what it means for your mail, and
the smallest thing that fixes it.
technical_detail: 'Technical detail'
integrations:
ask_admin: 'Your administrator has not enabled this service.'
auth:
appPassword: 'app password'
oauth2: 'sign-in'
available_heading: 'Connect a service'
badge:
ask_admin: 'not enabled'
soon: 'coming soon'
checked: 'checked %date%'
connect: Connect
disabled: 'Connection paused'
disconnect: Disconnect
disconnect_confirm: 'Disconnect %name%? Files already attached to mail are unaffected.'
disconnected: 'Service disconnected'
edit: Edit
empty: 'No services connected yet.'
enabled: 'Connection resumed'
field:
base_url: 'Server address'
base_url_fixed: 'Connecting to %url%, set by your administrator.'
name: Name
name_help: 'Only shown to you, so you can tell two connections apart.'
secret:
dropbox: 'Access token'
googleDrive: 'Access token'
googlePhotos: 'Access token'
immich: 'API key'
nextcloud: 'App password'
oneDrive: 'Access token'
secret_help:
dropbox: ''
googleDrive: ''
googlePhotos: ''
immich: 'Create one in Immich under Account Settings → API Keys.'
nextcloud: 'Create one in Nextcloud under Settings → Security → Devices & sessions. Do not use your login password.'
oneDrive: ''
permissions:
immich: 'asset.read — see your photos and videos|asset.download — attach the original file|asset.view — show previews in the picker|asset.upload — save attachments into Immich|album.read — list and browse your albums|albumAsset.create — file saved attachments into an album'
permissions_heading: 'Permissions this key needs'
permissions_note: 'Granting the key all permissions also works, and is simpler if you would rather not tick boxes.'
secret_unchanged: 'Leave blank to keep the stored credential'
username: Username
heading: Integrations
not_implemented: 'plMail cannot talk to this service yet.'
oauth_no_code: 'The service did not return an authorisation code. Please try again.'
oauth_state_mismatch: 'That sign-in could not be verified. Please start again.'
not_oauth: 'This service does not use that sign-in method.'
pause: Pause
paused: paused
resume: Resume
save_tests: 'Saving checks the connection straight away.'
saved: 'Service connected'
saved_with_error: 'Saved, but the connection test failed'
subheading: 'Attach files from other services, and save attachments to them.'
test: Test
test_failed: 'Connection test failed'
test_ok: 'Connection is working'
unavailable_heading: 'Not available here'
calendars:
account_hint: Where events found in mail from %address% are filed.
caldav:
connect: Connect a CalDAV server
disconnect: Disconnect "%name%"
disconnect_confirm: >-
Disconnect "%name%"? Every calendar mirrored from it is removed
here. Anything on them that came from your mail rather than from
a calendar is moved to your default calendar first.
disconnect_title: Disconnect this server
field:
address: Server address
address_help: >-
The CalDAV address your server shows you, or just its domain
— plMail asks the domain where its calendars live before
giving up.
name: Name
name_help: What to call this connection in your settings.
reuse: Use the password from one of my mail accounts
reuse_account: Which account's password
reuse_account_none: Choose an account…
reuse_help: >-
Off by default, and worth leaving off: most servers want an
app-specific password, and ticking this sends a password you
gave plMail for your mailbox to the address above.
secret: App password
secret_help: >-
Create one on your server rather than using your login
password — iCloud and Fastmail accept nothing else.
username: Username
username_help: The account name your server knows you by.
intro: >-
Any CalDAV server: Nextcloud, Radicale, Baïkal, Fastmail,
iCloud, a box in a cupboard. Gmail and Outlook calendars do not
come in this way — they arrive with the mail account.
submit: Connect and find calendars
title: Connect a CalDAV server
count: '%count% calendars'
default: Default
delete: Delete calendar "%name%"
delete_title: Delete calendar
edit: Edit calendar "%name%"
empty: No calendars yet.
from: From %name%
heading: Calendars
hide: Hide calendar
last_synced: 'Last synced %when%'
make_default: Make "%name%" the calendar new events land on
make_default_title: Make default
mirrored: Mirrored
mirrored_hint: Kept in step with %name%.
never_synced: Not synced yet
read_only: Read-only
read_only_hint: This calendar does not accept changes from here.
show: Show calendar
sources:
empty: >-
No account or connection here carries calendars yet. Gmail and
Outlook accounts do; connect a CalDAV server for anything else.
find: Find calendars on %name%
heading: Where calendars come from
why_admin: >-
Your administrator may not have added calendar permissions to
the app registration plMail signs in with. Mail keeps working
without them; calendars do not.
why_consent: >-
Google's consent screen lets you untick calendar access while
allowing mail. Reconnect the account and leave the calendar box
ticked.
why_empty: No calendars appearing?
why_none: The account may simply have no calendars on it.
subheading: >-
Name, colour and time zone, which calendars the views show, and
where a new event lands.
subscribe:
default_locked: >-
New events land here, so this one stays. Make another calendar
the default first.
empty: There are no calendars on %name%.
intro: >-
Tick the calendars on %name% to keep in step with plMail. Events
appear within a minute of ticking one.
mirrored: Already mirrored
primary: Main
save: Save subscriptions
title: Find my calendars
unsubscribe_note: >-
Unticking a calendar deletes the copy held here. Anything on it
that came from your mail rather than from the calendar is moved
to your default calendar first.
sync_now: Sync "%name%" now
sync_now_title: Sync now
labels:
count: '%count% labels'
delete: Delete label "%name%"
edit: Edit label "%name%"
empty: No labels yet — create one, or they appear after the first sync.
heading: Labels
hide: Hide label
show: Show label
subheading: Create, rename and organise your labels, and choose which appear in the sidebar.
system: System
profile:
heading: Your profile
save: Save profile
subheading: The name and picture shown on the mail you send.
language:
heading: Language
subheading: The language plMail's interface is shown in. Your mail is left as it was written.
nav:
sharing: Sharing
accounts: Mail accounts
aliases: Aliases
app_passwords: App passwords
appearance: Appearance
calendars: Calendars
general: General
group:
access: Access
calendar: Calendar
mail: Mail
personal: Personal
health: 'Account health'
profile: Profile
filters: Filters
integrations: Integrations
labels: Labels
notifications: Notifications
security: Security
signature: Signatures
notifications:
devices:
empty: >-
No device is registered yet. Turning notifications on above
registers this browser; a phone app registers itself.
heading: 'Registered devices'
never_delivered: 'Nothing sent yet'
outcome:
accepted: 'Delivered'
failed: 'Failed'
skipped: 'Not sent'
subscription-destroyed: 'Dropped'
remove: 'Remove'
remove_confirm: >-
Remove %device%? Notifications stop being sent to it. Nothing is
uninstalled or turned off on the device itself, and if its app
still wants notifications it will register again the next time
it runs.
removed: >-
Device removed — nothing more is sent to it. It registers itself
again if its app still wants notifications.
transport:
fcm: 'Firebase'
webpush: 'Web Push'
unverified: 'Not verified'
verified: 'Verified'
heading: Notifications
ios_hint: >-
On iPhone and iPad, notifications only work once plMail is added to
the Home Screen: open it in Safari, tap Share, then "Add to Home
Screen", and enable notifications from there.
state_denied: >-
Blocked in your browser settings. Allow notifications for this site,
then try again.
state_error: Something went wrong. Try again.
state_off: 'Off — this device will not be notified.'
state_on: On — this device gets notified of new mail.
state_pending: Waiting for this device to confirm…
state_unconfigured: Push is not configured on this server.
state_unknown: Checking…
state_unsupported: >-
This browser cannot receive notifications. On iPhone and iPad, add
plMail to the Home Screen first.
state_working: Working…
subheading: >-
Get notified of new mail on this device, even when plMail is closed.
this_device: This device
toggle: Enable notifications
toggle_off: Disable notifications
unconfigured: >-
Push is not configured on this server — no VAPID keys are set.
Run "bin/console app:push:generate-vapid-keys".
security:
codes:
copy: Copy codes
copy_now: Save your recovery codes now
copy_now_hint: >-
This is the only time they are shown. Keep them somewhere you can
reach without your phone — a password manager, or paper in a
drawer. Each one works once.
heading: Recovery codes
hint: >-
Recovery codes get you back in if you lose your phone. Generating
a new set replaces the old one, so anything you wrote down before
stops working.
regenerate: Generate new codes
remaining: '%count% unused'
confirm_with_code: Code from your app
devices:
empty: No devices are remembered. You will be asked for a code every time you sign in.
expires: 'Expires %date%'
heading: Remembered devices
hint: >-
Devices that skip the code prompt for 30 days. Revoking one takes
effect immediately — it will ask for a code on its very next page
load.
last_used: 'Last used %date% from %ip%'
revoke: Revoke
revoke_all: Revoke every remembered device
revoke_all_confirm: >-
Every remembered device will be asked for a code next time,
including this one. Continue?
revoke_confirm: 'Stop trusting %name%? It will be asked for a code next time.'
this_device: this device
disable:
confirm: >-
Your account will be protected by your password alone. Continue?
heading: Turn off two-factor authentication
hint: >-
This deletes your recovery codes and stops trusting every
remembered device.
submit: Turn off
enable: Set up two-factor authentication
enrol:
cancel: Cancel
heading: Set up two-factor authentication
manual_copy: Copy setup key
manual_toggle: Can't scan? Enter a key instead
qr_alt: QR code for setting up your authenticator app
step_app: >-
Install an authenticator app if you don't have one — Google
Authenticator, Aegis, 1Password and Bitwarden all work.
step_confirm: Enter the six-digit code your app is showing now.
step_scan: Scan this with the app.
submit: Confirm
heading: Two-factor authentication
pitch: >-
Your account is the one worth protecting most: anyone who reaches it
can reset the password on everything else you own, because your mail
is where the reset links arrive. A second factor means a stolen
password is not enough on its own.
status:
off: Two-factor authentication is off
on: Two-factor authentication is on
on_since: 'Enabled %date%'
subheading: How you prove it is you when signing in.
sharing:
heading: Sharing
subheading: >-
Links that show part of your calendar to someone without an account,
and pages that let them book an hour of it.
signature:
for_alias: 'Signature for %alias%'
heading: Signatures
hint: 'Added to the bottom of every new message, above the quoted reply.'
label: Signature
overriding: 'That address has its own signature now — edit it below.'
per_address:
count: 'Addresses with a signature of their own: %number%'
disclosure: 'Use a different signature for some addresses'
inherits: 'Uses the account signature.'
override: 'Use a different one'
override_for: 'Give %alias% a signature of its own'
revert: 'Use the account signature'
revert_for: 'Go back to the account signature for %alias%'
signs_with_nothing: 'Empty, so this address signs with nothing.'
placeholder: 'No signature'
reverted: 'Back to the account signature.'
save: 'Save signature'
saved: 'Saved.'
subheading: 'What is added to the bottom of the messages you write.'
timezone:
heading: Time zone
subheading: The clock times and dates are shown in. Nothing is rewritten — the same instant is simply read on your own clock.
label: Time zone
follow_default: 'Server default (%timezone%)'
current_time: 'It is currently %time% in this zone.'
title: Settings
sidebar:
accounts:
add: Add account
heading: Accounts
loading: Loading…
none: No accounts yet
open: 'Open %account%'
toggle: 'Show or hide folders in %account%'
compose: Compose
labels:
add: Create label
heading: Labels
none: No labels yet
new_mail_here: 'New mail in %where%'
nav:
calendar: Calendar
archive: Archive
drafts: Drafts
inbox: Inbox
more: More
sent: Sent
snoozed: Snoozed
spam: Spam
starred: Starred
trash: Trash
toggle: Show or hide the sidebar
snooze:
later_today: Later today
next_week: Next week
pick_date: Pick a date and time
this_weekend: This weekend
tomorrow: Tomorrow
unsnooze: Unsnooze
snoozed:
empty: Nothing is snoozed.
heading: Snoozed
until: Comes back %when%
starred:
empty: No starred messages.
heading: Starred
tabs:
forums: Forums
primary: Primary
promotions: Promotions
social: Social
updates: Updates
thread:
no_subject: (no subject)
thread_row:
account: 'Received on %account%'
actions:
archive: Archive
cancel_schedule: Cancel scheduled send
delete: Delete
mark_read: Mark as read
mark_unread: Mark as unread
snooze: Snooze
has_attachment: Has attachment
me: me
message_count: "({ count })"
# The word in the badge, and the phrase a screen reader gets instead. The
# badge has room for one word; "New" alone, read out on the fortieth row of
# a list, does not say new what.
new: Not shown to you before
new_badge: New
no_recipient: (no recipient)
no_subject: (no subject)
scheduled: 'Scheduled %when%'
select: Select
star: Star this message
to: 'To: %recipients%'
unread: Unread
unstar: Unstar this message
toast:
dismiss: Dismiss
schedule_cancelled: Scheduled send cancelled.
send_cancelled: Send cancelled — back to your draft.
undo: Undo
error:
no_archive_mailbox: There is no archive mailbox.
toolbar:
actions:
archive: Archive
delete: Delete
label: Label as
mark_read: Mark as read
mark_unread: Mark as unread
snooze: Snooze
pagination:
next: Older
of: of
prev: Newer
select:
all: All
none: None
read: Read
starred: Starred
unread: Unread
select_all: Select all conversations
select_menu: More selection options
spam:
empty: No junk mail.
heading: Spam
trash:
empty: No deleted messages.
heading: Trash
two_factor:
cancel: Sign in as someone else
flash:
code_rejected: That code was not right. Check your app and try again.
codes_regenerated: New recovery codes generated. The old ones no longer work.
device_revoked: That device will be asked for a code next time.
devices_revoked: No devices are remembered any more.
disabled: Two-factor authentication is off.
enabled: Two-factor authentication is on.
form:
code: Authentication code
code_hint: >-
The six-digit code from your authenticator app, or one of your
recovery codes.
submit: Continue
submitting: Checking…
trust_device: Don't ask on this device again
trust_device_hint: For 30 days. You can revoke it any time from Settings → Security.
page_title: Two-factor authentication
recovery_hint: >-
Lost your phone? Use one of the recovery codes you saved when you set
this up.
tagline: One more step