halkyon/packages/halkyon_app/lib/l10n/halkyon_app_en.arb
Tizian 「ティツィアーン」 2a21672b43
fix(auth): every call with a code after the password takes the address
Whoever guessed codes decided whether the owner was mailed (the re-review's
fourth finding): the address a sign-in sent was optional, so a guesser left
it out and no mail went, and a wait begun without a mail used up the one
mail there was. Every call carrying a code after the password or the phrase
proved (signing in, the phrase's reset, a change of password, a new phrase,
deletion) now takes the account's address and the language of its mails,
and is refused (wrongCredentials, as anything wrong after the password)
before any code is checked when the address isn't the account's; every
wait mails the owner, not only the first. The app sends the address the
person typed, or for changes while signed in the one this device signed in
with, and says so where it doesn't know it (addressUnknown).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-23 14:12:47 +02:00

463 lines
19 KiB
Text

{
"@@locale": "en",
"tryAgain": "Try again",
"instanceWelcome": "Welcome to {app}",
"@instanceWelcome": {
"description": "Screen readers hear it for the wordmark on the first start.",
"placeholders": {
"app": {
"type": "String"
}
}
},
"instanceBuiltInTagline": "Comes with the app",
"instanceAnother": "Another instance",
"instanceAnotherTagline": "Enter its address",
"instanceAddress": "Instance address",
"instanceAddressInvalid": "This isn't an address.",
"instanceAddressRequired": "Enter the address of an instance.",
"instanceContinue": "Continue",
"instanceUnreachable": "No instance of {app} answers at {name}.",
"@instanceUnreachable": {
"placeholders": {
"app": {
"type": "String"
},
"name": {
"type": "String"
}
}
},
"instanceUseBuiltIn": "Use {name}",
"@instanceUseBuiltIn": {
"placeholders": {
"name": {
"type": "String"
}
}
},
"instanceOpenFailed": "Couldn't open the app on {name}.",
"@instanceOpenFailed": {
"placeholders": {
"name": {
"type": "String"
}
}
},
"instanceDataAndBackupsIn": "Data and backups: {place}",
"@instanceDataAndBackupsIn": {
"placeholders": {
"place": {
"type": "String"
}
}
},
"instanceDataIn": "Data: {place}",
"@instanceDataIn": {
"placeholders": {
"place": {
"type": "String"
}
}
},
"instanceBackupsIn": "Backups: {place}",
"@instanceBackupsIn": {
"placeholders": {
"place": {
"type": "String"
}
}
},
"instanceNoBackups": "No backups",
"instanceEuropeanUnion": "European Union",
"instanceCountryInEu": "{country} (EU)",
"@instanceCountryInEu": {
"description": "A country of the European Union, where an instance keeps data: Germany (EU).",
"placeholders": {
"country": {
"type": "String"
}
}
},
"instanceSubdivisionOf": "{subdivision}, {country}",
"@instanceSubdivisionOf": {
"description": "A state or region with its country, where an instance keeps data: California, United States.",
"placeholders": {
"subdivision": {
"type": "String"
},
"country": {
"type": "String"
}
}
},
"accountsTitle": "Accounts",
"accountAdd": "Add account",
"accountAddSubtitle": "Choose the instance for the account to add.",
"accountSignedIn": "Signed in",
"accountAnonymous": "Anonymous",
"accountRemoveTooltip": "Remove account",
"accountRemoveTitle": "Remove account?",
"accountRemoveMessage": "Removes the account on {name} from this device, with all the device holds of it. What it synced stays on {name}: sign in there again to have it. An anonymous account can't be signed into again.",
"@accountRemoveMessage": {
"placeholders": {
"name": {
"type": "String"
}
}
},
"accountRemoveConfirm": "Remove",
"accountSignedInOn": "Signed in on {instance}",
"@accountSignedInOn": {
"placeholders": {
"instance": {
"type": "String"
}
}
},
"accountAnonymousOn": "Anonymous on {instance}",
"@accountAnonymousOn": {
"placeholders": {
"instance": {
"type": "String"
}
}
},
"accountSwitch": "Switch account",
"accountSignOut": "Sign out",
"accountSignOutTitle": "Sign out?",
"accountDelete": "Delete account",
"accountDeleteTitle": "Delete your account?",
"aboutSourceCode": "The source of what this instance runs:",
"aboutSourceUnreachable": "Couldn't reach this instance to ask where its source is.",
"sessionUnreachable": "Couldn't reach the server.",
"personDataFailed": "Couldn't open this device's data.",
"startSignedOut": "Signed out",
"startOn": "Start on {instance}:",
"@startOn": {
"placeholders": {
"instance": {
"type": "String"
}
}
},
"startWithGitHub": "Sign in with GitHub",
"startWithoutAccount": "Start without an account",
"startAnonymous": "Progress is saved on this device. Sign in to keep it.",
"startGitHubFailed": "Couldn't sign in with GitHub.",
"startNoGitHubAccount": "No account here signs in with this GitHub account yet.",
"startOtherInstance": "Use another instance",
"syncTitle": "Sync",
"syncNow": "Sync now",
"syncStateSyncing": "Syncing…",
"syncStateSynced": "Everything synced",
"syncStateFailing": "Sync is failing",
"syncStateNotYet": "Not synced yet",
"syncStateMismatch": "This app can't sync with {server}",
"@syncStateMismatch": {
"placeholders": {
"server": {
"type": "String"
}
}
},
"syncMismatchDetail": "Update the app. If it is up to date, the server needs an update. What you do meanwhile stays on this device and syncs afterwards.",
"syncLastCompleted": "Last completed at {time}",
"@syncLastCompleted": {
"placeholders": {
"time": {
"type": "String"
}
}
},
"syncLastFailed": "Last attempt failed at {time}",
"@syncLastFailed": {
"placeholders": {
"time": {
"type": "String"
}
}
},
"syncNoRunYet": "No sync has completed since the app started",
"syncPending": "{count, plural, =1{1 change waits to sync} other{{count} changes wait to sync}}",
"@syncPending": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"syncTroubleLabel": "Sync needs attention",
"syncMismatchBanner": "This app can't sync with {server} any more. Update it to keep syncing.",
"@syncMismatchBanner": {
"placeholders": {
"server": {
"type": "String"
}
}
},
"syncMismatchMore": "More",
"startSignIn": "Sign in",
"startCreateAccount": "Create an account",
"startGitHubEnds": "Sign-in with GitHub ends on {date}.",
"@startGitHubEnds": {
"placeholders": {
"date": {
"type": "String"
}
}
},
"passwordAddress": "Email address",
"passwordPassword": "Password",
"passwordNewPassword": "New password",
"passwordCurrent": "Current password",
"passwordRepeat": "New password again",
"passwordsDiffer": "The two passwords differ.",
"passwordShow": "Show password",
"passwordHide": "Hide password",
"passwordContinue": "Continue",
"passwordBack": "Back",
"passwordDone": "Done",
"passwordCopy": "Copy",
"passwordCopied": "Copied.",
"passwordSave": "Save as a file",
"passwordQrCode": "QR code for your authenticator app",
"passwordMailCode": "Code from the email",
"passwordMailCodeSent": "We emailed a code to {address}. It's valid for 15 minutes.",
"@passwordMailCodeSent": {
"placeholders": {
"address": {
"type": "String"
}
}
},
"passwordResendCode": "Send a new code",
"passwordTotpCode": "Code from your authenticator app",
"passwordRecoveryCode": "Recovery code",
"passwordUseRecoveryCode": "Use a recovery code instead",
"passwordUseTotpCode": "Use your authenticator app instead",
"passwordUnlocking": "Unlocking your password on this device…",
"passwordMakingKeys": "Making your keys on this device…",
"passwordSignInTitle": "Sign in",
"passwordSignInAction": "Sign in",
"passwordSignInIntro": "With the email address and password of your account on {instance}.",
"@passwordSignInIntro": {
"placeholders": {
"instance": {
"type": "String"
}
}
},
"passwordSecondFactorIntro": "Enter the code your authenticator app shows for {instance}.",
"@passwordSecondFactorIntro": {
"placeholders": {
"instance": {
"type": "String"
}
}
},
"passwordRecoveryCodeIntro": "Enter one of the recovery codes you kept. Each signs in once.",
"passwordForgot": "Forgot your password?",
"passwordOtherPassword": "Change the address or password",
"passwordLostAuthenticator": "Lost your authenticator?",
"passwordLostAuthenticatorTitle": "Lost authenticator",
"passwordLostAuthenticatorIntro": "With a recovery code you sign in as usual. Without one, ask to reset your authenticators: it takes effect 72 hours later, and signing in with a code before then stops it.",
"passwordResetWithMail": "Reset with a code by email",
"passwordResetWithMailHint": "We email a code to {address}.",
"@passwordResetWithMailHint": {
"placeholders": {
"address": {
"type": "String"
}
}
},
"passwordResetWithPhrase": "Reset with your recovery phrase",
"passwordResetWithPhraseHint": "The 24 words you wrote down.",
"passwordSignInWithoutCode": "Sign in without a code",
"passwordSignInWithoutCodeHint": "Once a reset you asked for has taken effect.",
"passwordResetAction": "Reset",
"passwordAuthenticatorResetAt": "Your authenticators are reset on {date}. We emailed you: if it wasn't you, sign in with a code before then to stop it. After that, sign in with your password alone and set up a new authenticator.",
"@passwordAuthenticatorResetAt": {
"placeholders": {
"date": {
"type": "String"
}
}
},
"passwordUnfinishedIntro": "Your account was never finished. We emailed a code to {address}: with it, you sign in and set up an authenticator.",
"@passwordUnfinishedIntro": {
"placeholders": {
"address": {
"type": "String"
}
}
},
"passwordPhraseField": "Recovery phrase",
"passwordPhraseFieldHint": "The 24 words, with spaces between them",
"passwordPhraseFieldIntro": "Enter your recovery phrase: it proves the account is yours.",
"passwordAuthenticatorTitle": "Set up an authenticator",
"passwordAuthenticatorIntro": "Every sign-in takes a code from an authenticator app, such as Aegis, 2FAS or Proton Authenticator. Scan this code with it, or type in the key.",
"passwordAuthenticatorKey": "Key",
"passwordAuthenticatorOpen": "Open in your authenticator app",
"passwordAuthenticatorNoApp": "No app on this device opens it. Scan the code or type in the key.",
"passwordAuthenticatorCodeIntro": "Then enter the code it shows.",
"passwordExistingCode": "Code from an authenticator you added before",
"passwordRecoveryCodesTitle": "Recovery codes",
"passwordRecoveryCodesIntro": "Each signs in once in place of a code from your authenticator, should you lose it. Keep them where only you find them: they're shown only now.",
"passwordCodesKept": "I've kept them",
"passwordPhraseTitle": "Your recovery phrase",
"passwordPhraseIntro": "These 24 words open your account's keys should you forget your password: without them, what's encrypted is lost. Write them down in order, and keep them where only you find them. They're shown only now.",
"passwordPhraseWrittenDown": "I've written it down",
"passwordPhraseCheckTitle": "Check your recovery phrase",
"passwordPhraseCheckIntro": "Type the words asked for, from what you wrote down.",
"passwordPhraseWord": "Word {number}",
"@passwordPhraseWord": {
"placeholders": {
"number": {
"type": "int"
}
}
},
"passwordPhraseWrong": "These aren't the words. Look again at what you wrote down.",
"passwordPhraseShowAgain": "Show the phrase again",
"passwordCreateTitle": "Create an account",
"passwordCreateIntro": "On {instance}, with your email address, a password, and an authenticator app for the code every sign-in takes.",
"@passwordCreateIntro": {
"placeholders": {
"instance": {
"type": "String"
}
}
},
"passwordSetUpTitle": "Set up a password",
"passwordSetUpIntro": "Sign in with your email address, a password and an authenticator app, on this device and others. Everything you have stays.",
"passwordChooseIntro": "Choose a password. It never leaves this device: the instance can't read it, and can't reset it without what it protects being lost.",
"passwordFinishResetTitle": "Finish the reset",
"passwordFinishResetIntro": "72 hours after you asked to reset your account, finish it here with a new code by email.",
"passwordFinishResetHavePhrase": "I have my recovery phrase",
"passwordFinishResetKeepsKeys": "Your account keeps its keys: nothing encrypted is lost.",
"passwordFinishResetNewKeys": "Without your recovery phrase, your account gets new keys: what was encrypted with the old ones is lost.",
"passwordRecoveryTitle": "Get back into your account",
"passwordRecoveryWithPhrase": "I have my recovery phrase",
"passwordRecoveryWithPhraseHint": "Set a new password at once. Everything stays.",
"passwordRecoveryWithPhraseIntro": "Your recovery phrase opens your account's keys, which your new password then protects. A code from your authenticator, or a recovery code, confirms it.",
"passwordRecoveryNoCodeHint": "Lost your authenticator as well? Reset your account 72 hours later with your recovery phrase: it keeps everything.",
"passwordRecoveryWithoutPhrase": "Reset my account",
"passwordRecoveryWithoutPhraseHint": "Takes effect 72 hours later. Without your recovery phrase, what's encrypted is lost.",
"passwordRecoveryStartIntro": "We email a code to your address. Your account can then be reset 72 hours later; signing in with your password before then stops it.",
"passwordRecoveryFinish": "Finish a reset",
"passwordRecoveryFinishHint": "72 hours after you asked for it.",
"passwordResetStarted": "Your account can be reset from {date}. We emailed you: if it wasn't you, sign in with your password before then to stop it.",
"@passwordResetStarted": {
"placeholders": {
"date": {
"type": "String"
}
}
},
"passwordSectionTitle": "Password and authenticator",
"passwordSectionFailed": "Couldn't read how your account signs in.",
"passwordSectionGitHubEnds": "Sign-in with GitHub ends on {date}. Set up a password before then to keep your account.",
"@passwordSectionGitHubEnds": {
"placeholders": {
"date": {
"type": "String"
}
}
},
"passwordSectionSetUp": "Set up a password",
"passwordSectionSetUpHint": "Sign in with your email address, a password and an authenticator app.",
"passwordSectionUnfinished": "Finish setting up: add an authenticator",
"passwordSectionUnfinishedHint": "Your password signs in once an authenticator is set up.",
"passwordSectionChange": "Change password",
"passwordSectionKeysMissing": "Sign in on this device with your password to change it.",
"passwordSectionNotConfirmed": "Not set up yet",
"passwordSectionRemove": "Remove {name}?",
"@passwordSectionRemove": {
"placeholders": {
"name": {
"type": "String"
}
}
},
"passwordSectionRemoveIntro": "Enter a code from one of your authenticators to confirm.",
"passwordSectionRemoveAction": "Remove",
"passwordSectionAddAuthenticator": "Add an authenticator",
"passwordSectionRecoveryCodes": "New recovery codes",
"passwordSectionRecoveryCodesHint": "The old ones stop working.",
"passwordSectionNewPhrase": "New recovery phrase",
"passwordSectionPhraseHint": "Your old phrase stops working.",
"passwordChangeTitle": "Change password",
"passwordChangeIntro": "Your other devices are signed out. Your keys stay: nothing is lost.",
"passwordChangeAction": "Change password",
"passwordChanged": "Password changed. Your other devices are signed out.",
"passwordNewCodesIntro": "Enter a code from your authenticator app. Your old recovery codes stop working.",
"passwordNewPhraseIntro": "Your new recovery phrase. Write the 24 words down in order: once you confirm it, your old phrase opens nothing any more.",
"passwordPhraseKept": "New recovery phrase set. The old one no longer works.",
"passwordWrongCredentials": "The address, the password or the code isn't right.",
"passwordTooManyAttempts": "Too many attempts. Try again in an hour.",
"passwordSetupIncomplete": "Your account was never finished: set up an authenticator.",
"passwordNotDue": "This takes effect on {date}.",
"@passwordNotDue": {
"placeholders": {
"date": {
"type": "String"
}
}
},
"passwordNotDueYet": "This hasn't taken effect yet.",
"passwordNoReset": "No reset waits for this address.",
"passwordExists": "This address's account has a password already. Sign in with it, or get back in if you've forgotten it.",
"passwordAddressTaken": "This address belongs to another account.",
"passwordNoAddress": "Your account has no email address yet.",
"passwordNoPassword": "This account has no password.",
"passwordWrongCode": "This code isn't right. Enter the one your app shows now.",
"passwordWrongExistingCode": "The code from your other authenticator isn't right.",
"passwordLastAuthenticator": "Your last authenticator can't go: every sign-in needs one.",
"passwordTooManyAuthenticators": "Your account has as many authenticators as it may. Remove one first.",
"passwordUnknownAuthenticator": "This authenticator is gone.",
"passwordInvalidSetup": "The instance didn't accept what this device made. Update the app, or try again.",
"passwordChallengeExpired": "That took too long. Try again.",
"passwordUnavailable": "This instance offers no password sign-in.",
"passwordNotAnAddress": "This isn't an email address.",
"passwordTooManyCodes": "Too many codes asked for. Try again in an hour.",
"passwordWrongMailCode": "This code isn't right.",
"passwordTooManyMailTries": "Too many wrong codes. Ask for a new one.",
"passwordMailCodeExpired": "This code is no longer valid. Ask for a new one.",
"passwordMailFailed": "The instance couldn't send the email. Try again later.",
"passwordOtherAddressLinked": "Your account has another email address.",
"passwordNotAPhrase": "This isn't a recovery phrase: check every word and their number.",
"passwordPhraseDoesNotFit": "The address or the recovery phrase isn't right.",
"passwordUnusable": "This password can't be used: it's empty, or holds characters that aren't text.",
"passwordInstanceUnproven": "The instance couldn't prove it knows your password, so this device trusts nothing it says. Try again; if it happens again, the instance isn't the one it claims to be.",
"passwordKeysMissing": "Your account's keys aren't on this device. Sign out and in again with your password here.",
"passwordUnsafeCosts": "The instance asked for your password to be checked in a way no account uses, so nothing was sent. If it happens again, the instance isn't the one it claims to be.",
"passwordFailed": "Couldn't reach the instance. Check the connection and try again.",
"passwordMinLength": "At least {count} characters",
"@passwordMinLength": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"passwordTooShort": "A new password needs at least {count} characters: should the instance's database ever leak, a short one is guessed first.",
"@passwordTooShort": {
"placeholders": {
"count": {
"type": "int"
}
}
},
"passwordCodesWait": "Too many wrong codes in a row: no code is taken until {date}. If they weren't yours, someone knows your password: change it then.",
"@passwordCodesWait": {
"placeholders": {
"date": {
"type": "String"
}
}
},
"passwordDeleteIntro": "Your account goes with everything in it, in every service of this instance. To confirm, type your password and a code from your authenticator app.",
"passwordSessionEnded": "Too many wrong codes in a row from this device: it was signed out. Sign in again with your password and a code.",
"passwordAddressUnknown": "This device doesn't know your account's address, which this takes. Sign out, then sign in again with your address and password."
}