Files
GuidoandClaude Opus 5 09ec2dc5fd feat: Bildschirmsperre mit Face ID und PIN
Beim ersten Start fuehrt kein Weg an einer sechsstelligen PIN vorbei. Danach
sperrt die App beim Kaltstart und beim Wegschalten; kommt man binnen einer
Minute zurueck, geht sie ohne Nachfrage wieder auf. Face ID zuerst, die PIN
als Rueckfallweg und als einziger Weg ohne Biometrie. Nach fuenf falschen
PINs meldet die App ab.

Gesperrt wird schon bei inactive, nicht erst im Hintergrund - sonst stuenden
die Kontostaende im App-Umschalter.

Von der PIN liegt nur ein gesalzener SHA-256 im Schluesselbund. Die
Gerätemarke selbst bleibt wie bisher abgelegt: Die Sperre verdeckt die
Oberflaeche, sie verschluesselt nichts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-24 18:09:05 +02:00

378 lines
17 KiB
Plaintext
Raw Permalink 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.
/* Certain for iOS – English
Keys mirror de.lproj line for line. Keep them that way: in the web app
de.json and en.json are the same length, and that is why nothing is ever
missing there. */
/* --- General --- */
"allgemein.nochmal" = "Try again";
"allgemein.abbrechen" = "Cancel";
"allgemein.abmelden" = "Sign out";
"allgemein.unbekannt" = "Unknown";
"allgemein.sichern" = "Save";
"allgemein.ok" = "OK";
"allgemein.fertig" = "Done";
"allgemein.bearbeiten" = "Edit";
"allgemein.loeschen" = "Delete";
/* --- Tabs --- */
"reiter.dashboard" = "Overview";
"reiter.budget" = "Budget";
"reiter.buchungen" = "Transactions";
"reiter.abos" = "Subscriptions";
"reiter.arbeitsliste" = "Inbox";
"reiter.konten" = "Accounts";
"reiter.einstellungen" = "Settings";
/* --- Errors --- */
"fehler.titel" = "That did not work";
"fehler.unbekannt" = "Unknown error.";
"fehler.keineVerbindung" = "Cannot reach the server: %@";
"fehler.keinCertainServer" = "Something answers at this address, but it is not Certain.";
"fehler.nichtAngemeldet" = "This device is no longer signed in. It was probably revoked on the desktop.";
"fehler.passwortWechseln" = "The password has to be changed before anything else.";
"fehler.zweiterFaktor" = "This account needs a second factor.";
"fehler.nichtGefunden" = "Does not exist.";
"fehler.server" = "The server reports an error (%d).";
"fehler.antwortUnlesbar" = "The server's answer does not match what the app expects: %@";
/* --- Offline --- */
"stand.hinweis" = "As of %@ – the server cannot be reached right now.";
/* --- Server address --- */
"server.titel" = "Connect to Certain";
"server.ueberschrift" = "Address";
"server.platzhalter" = "budget.example.com";
"server.erklaerung" = "The same address you open Certain with in your browser. Leaving off https is fine.";
"server.verbinden" = "Connect";
"server.keineAdresse" = "That does not look like an address.";
/* --- Sign in --- */
"anmeldung.titel" = "Sign in";
"anmeldung.benutzer" = "Username";
"anmeldung.passwort" = "Password";
"anmeldung.anmelden" = "Sign in";
"anmeldung.erklaerung" = "Just this once. Afterwards the device keeps a key of its own, and your password is stored nowhere.";
"anmeldung.andererServer" = "Choose a different server";
"anmeldung.aktuellerServer" = "Connected to %@";
"anmeldung.markeOhneSchluessel" = "The server returned no key. Please try again.";
/* --- Second factor --- */
"zweifaktor.titel" = "Second factor";
"zweifaktor.ueberschrift" = "Code";
"zweifaktor.platzhalterCode" = "123456";
"zweifaktor.platzhalterWiederherstellung" = "ABCDE-FGHIJ";
"zweifaktor.erklaerungCode" = "The six digits from your authenticator app.";
"zweifaktor.erklaerungWiederherstellung" = "One of the codes you got when setting this up. Each works once.";
"zweifaktor.bestaetigen" = "Confirm";
"zweifaktor.dochWiederherstellung" = "Use a recovery code instead";
"zweifaktor.dochCode" = "Use the code from the app instead";
"zweifaktor.abbrechen" = "Cancel sign-in";
"zweifaktor.verbraucht" = "Too many wrong attempts. Please start over.";
/* --- Second factor missing --- */
"zweifaktorEinrichten.titel" = "Second factor required";
"zweifaktorEinrichten.erklaerung" = "The policy requires a second factor for this account. Setting one up still only works in the browser; the app will get it later.";
"zweifaktorEinrichten.imBrowser" = "Open in browser";
/* --- Password change --- */
"passwort.titel" = "Change password";
"passwort.bisher" = "Current password";
"passwort.neu" = "New password";
"passwort.wiederholen" = "Once more";
"passwort.erklaerung" = "This account has to change its password. The server allows nothing else until then.";
"passwort.stimmtNichtUeberein" = "These two do not match.";
"passwort.speichern" = "Change password";
/* --- Accounts --- */
"konten.titel" = "Accounts";
"konten.leerTitel" = "No accounts yet";
"konten.leerErklaerung" = "Create your first account in the browser; the app will get this in a later stage.";
"konten.archivierteZeigen" = "Show archived";
"konten.archiviert" = "archived";
"konten.gebunden" = "Money set aside";
"konten.gebundenSumme" = "Of which set aside";
"konten.verfuegbar" = "Available";
"konten.bankWeichtAb" = "The bank reports a different balance";
/* --- Account types --- */
"kontoart.girokonto" = "Current account";
"kontoart.sparkonto" = "Savings account";
"kontoart.bargeld" = "Cash";
"kontoart.kreditkarte" = "Credit card";
"kontoart.depot" = "Securities account";
"kontoart.sonstiges" = "Other";
/* --- Settings --- */
"einstellungen.zugang" = "Access";
"einstellungen.angemeldetAls" = "Signed in as";
"einstellungen.server" = "Server";
"einstellungen.markeErklaerung" = "This device holds a key of its own. You can revoke it any time on the desktop under Settings → Device keys; the app signs out immediately.";
"einstellungen.ausDemServer" = "From the server";
"einstellungen.hauptwaehrung" = "Main currency";
"einstellungen.budgetStarttag" = "Budget starts on";
"einstellungen.abmeldenFrage" = "Sign out on this device?";
"einstellungen.abmeldenErklaerung" = "Signing out also removes this device's key on the server.";
/* --- Dashboard --- */
"dashboard.bilanz" = "This month";
"dashboard.einnahmen" = "Income";
"dashboard.ausgaben" = "Expenses";
"dashboard.budgetfortschritt" = "Budget";
"dashboard.keinBudget" = "Nothing planned for this month yet.";
"dashboard.kontostaende" = "Accounts";
"dashboard.letzteBuchungen" = "Recent";
/* --- Budget --- */
"budget.einnahmen" = "Planned income";
"budget.uebrig" = "left";
"budget.vonGeplant" = "%1$@ of %2$@ spent";
"budget.vonBetrag" = "of %@";
"budget.angepasst" = "adjusted";
"budget.vorigerMonat" = "Previous month";
"budget.naechsterMonat" = "Next month";
"budget.ausVertraegenHinweis" = "%1$d subscriptions: %2$@";
"budget.ausVertraegenBerechnet" = "Calculated from %1$d subscriptions: %2$@";
"budget.vertraegeOhneKategorie" = "%1$d subscriptions without a category (%2$@) are missing from these totals.";
"budget.ohneKurs" = "No exchange rate for %@ – those amounts are missing from the totals.";
/* --- Transactions --- */
"buchungen.suchen" = "Payee, description, note";
"buchungen.konto" = "Account";
"buchungen.alleKonten" = "All accounts";
"buchungen.art" = "Type";
"buchungen.alleArten" = "All types";
"buchungen.leerTitel" = "No transactions";
"buchungen.leerErklaerung" = "Once something is booked, it shows up here.";
"buchungen.leerGefiltert" = "Nothing matches this search. Try different filters?";
"buchung.ohneBezeichnung" = "Untitled";
"buchung.ohneKategorie" = "No category";
"buchung.uebertrag" = "Transfer";
/* --- Transaction types --- */
"buchungsart.ausgabe" = "Expense";
"buchungsart.einnahme" = "Income";
"buchungsart.uebertrag" = "Transfer";
/* --- Subscriptions --- */
"abos.leerTitel" = "No subscriptions";
"abos.leerErklaerung" = "Subscriptions and contracts show up here once you add them.";
"abos.beendeteZeigen" = "Show cancelled";
"abos.beendet" = "cancelled";
"abos.jaehrlichUndAnzahl" = "%1$@ per year · %2$d active";
"abos.ohneKurs" = "No exchange rate for %@ – those subscriptions are missing from the total.";
"abo.monatlich" = "monthly";
"abo.vierteljaehrlich" = "quarterly";
"abo.halbjaehrlich" = "twice a year";
"abo.jaehrlich" = "yearly";
"abo.alleNMonate" = "every %d months";
"abo.proMonat" = "%@ per month";
"abo.naechste" = "next on %@";
"abo.inTagen" = "due in %d days";
/* --- Edit transaction --- */
"buchung.neu" = "New transaction";
"buchung.aendern" = "Edit transaction";
"buchung.datum" = "Date";
"buchung.betrag" = "Amount";
"buchung.konto" = "Account";
"buchung.konto.keines" = "No account";
"buchung.zielkonto" = "To account";
"buchung.kategorie" = "Category";
"buchung.empfaenger" = "Payee";
"buchung.verwendungszweck" = "Description";
"buchung.notiz" = "Note";
"buchung.schlagwoerter" = "Tags";
"buchung.keineSchlagwoerter" = "No tags yet. You can add them on the desktop.";
"buchung.uebertragErklaerung" = "A transfer moves money between your own accounts. It counts in no report and therefore needs no category.";
"buchung.loeschen" = "Delete transaction";
"buchung.loeschenFrage" = "Delete this transaction?";
/* --- Edit budget --- */
"budget.geplant" = "Planned";
"budget.zuschlag" = "Extra";
"budget.ausVertraegen" = "From subscriptions";
"budget.ergibt" = "Totals";
"budget.monatSetzen" = "This month only";
"budget.vorlageSetzen" = "Default budget";
"budget.vorlage" = "Template";
"budget.ausVertraegenRechnen" = "Calculate from subscriptions";
"budget.berechnetErklaerung" = "The planned amount comes from this category's subscriptions plus the extra. Change a subscription and the budget follows.";
"budget.festErklaerung" = "A fixed amount you set yourself.";
"budget.vorlageHolen" = "Load template into this month";
"budget.alsVorlageSetzen" = "Make this month the default";
"budget.zuruecksetzen" = "Reset month";
"budget.zuruecksetzenFrage" = "Reset this month?";
"budget.zuruecksetzenErklaerung" = "All adjustments to this month are dropped. The default budget applies again.";
/* --- Edit subscription --- */
"abo.neu" = "New subscription";
"abo.aendern" = "Edit subscription";
"abo.name" = "Name";
"abo.betrag" = "Amount per payment";
"abo.rhythmus" = "Billed";
"abo.konto" = "Charged to";
"abo.kategorieErklaerung" = "The category decides which budget line this subscription counts towards.";
"abo.faelligkeitKennen" = "Next payment known";
"abo.naechsteZahlung" = "Next payment";
"abo.erkennungstext" = "Match text";
"abo.erkennungErklaerung" = "How the matcher recognises this subscription in a transaction - usually part of the payee name.";
"abo.laeuftNoch" = "Still running";
"abo.beendenStattLoeschen" = "Cancelling keeps the record of what it cost. Deleting removes it entirely.";
"abo.loeschen" = "Delete subscription";
"abo.loeschenFrage" = "Delete this subscription?";
"abo.loeschenErklaerung" = "The linked transactions stay; they only lose the label.";
/* --- Edit account --- */
"konto.neu" = "New account";
"konto.aendern" = "Edit account";
"konto.name" = "Name";
"konto.art" = "Type";
"konto.waehrung" = "Currency";
"konto.anfangssaldo" = "Opening balance";
"konto.stichtagKennen" = "Set an opening date";
"konto.stichtag" = "Opening date";
"konto.anfangssaldoErklaerung" = "The balance to start from. Without a date it applies from the beginning; with one, only transactions from that day count on top.";
"konto.kreditrahmenKennen" = "Set a credit limit";
"konto.kreditrahmen" = "Credit limit";
"konto.kreditrahmenErklaerung" = "What the card may spend - not a balance.";
"konto.gebunden" = "Locked money";
"konto.gebundenErklaerung" = "Money you cannot reach, such as a pension account. It does not count as available.";
"konto.archiviert" = "Archived";
"konto.archivierenStattLoeschen" = "Archiving hides the account and keeps its transactions. Deleting only works while none are attached.";
"konto.loeschen" = "Delete account";
"konto.loeschenFrage" = "Delete this account?";
"konto.loeschenErklaerung" = "Only possible while no transaction is attached. Archive it otherwise.";
/* --- Inbox / work list --- */
"arbeit.leerTitel" = "Nothing to do";
"arbeit.leerErklaerung" = "No pending entries, no transfer suggestions, no duplicates. Just as it should be.";
"arbeit.eingang" = "To book";
"arbeit.uebertraege" = "Might be transfers";
"arbeit.ohneKategorie" = "Without a category";
"arbeit.dubletten" = "Looks duplicated";
"arbeit.dublettenErklaerung" = "Same account, same day, same amount. Only you know whether it really is the same payment - different reference numbers mean the bank reported them as separate.";
"arbeit.buchen" = "Book";
"arbeit.alleBuchen" = "Book all that have an account";
"arbeit.alsUebertrag" = "Transfer";
"arbeit.verwerfen" = "Discard";
"arbeit.verbinden" = "Link";
"arbeit.keinUebertrag" = "Not a transfer";
"arbeit.istRichtigSo" = "That is correct";
"arbeit.unklarHinweis" = "The matcher was unsure - have a look first.";
"arbeit.hatKategorie" = "One of the two has a category. Linking takes it out of the budget.";
"arbeit.ohneKonto" = "no account";
"arbeit.rueckfrage" = "Are you sure?";
"arbeit.trotzdem" = "Do it anyway";
"arbeit.zielkontoErklaerung" = "This creates one transaction moving the money from one account to the other. It counts in both balances and in no report.";
/* --- Inbox: source and status --- */
"eingang.quelle.kurzbefehl" = "Shortcut";
"eingang.quelle.postfach" = "Mailbox";
"eingang.quelle.bank" = "Bank";
"eingang.stand.gebucht" = "booked";
"eingang.stand.offen" = "pending";
"eingang.stand.unklar" = "unclear";
"eingang.stand.verworfen" = "discarded";
/* --- Manage --- */
"nebenraeume.titel" = "Manage";
"nebenraeume.kategorien" = "Categories";
"nebenraeume.tags" = "Tags";
"nebenraeume.bank" = "Bank connection";
/* --- Categories --- */
"kategorien.leer" = "No categories yet.";
"kategorien.neu" = "New category";
"kategorien.aendern" = "Edit category";
"kategorien.neueGruppe" = "New group";
"kategorien.gruppe" = "Group";
"kategorien.art" = "Kind";
"kategorien.ausgaben" = "Expenses";
"kategorien.einnahmen" = "Income";
"kategorien.archivierteZeigen" = "Show archived";
"kategorien.sparen" = "saving";
"kategorien.ohneAuswertung" = "not counted";
"kategorien.istSparen" = "Spending that is not a loss";
"kategorien.istSparenErklaerung" = "For savings and reserves. Spending more than planned is no warning here - it is good news.";
"kategorien.ohneAuswertungSchalter" = "Keep out of reports";
"kategorien.ohneAuswertungErklaerung" = "For pass-through items. The transactions stay but count in no chart and no total.";
"kategorien.loeschen" = "Delete category";
"kategorien.loeschenFrage" = "Delete this category?";
"kategorien.loeschenErklaerung" = "Only possible while no transaction is attached.";
"kategorien.archivierenStattLoeschen" = "Archiving hides the category and keeps its transactions. Deleting only works while none are attached.";
"kategorien.gruppeLoeschen" = "Delete group";
"kategorien.gruppeLoeschenFrage" = "Delete this group?";
"kategorien.gruppeLoeschenErklaerung" = "Only possible while no category is left in it.";
"kategorien.erkennungswoerter" = "Match words";
"kategorien.wortHinzufuegen" = "Add a word";
"kategorien.erkennungErklaerung" = "If one of these words appears in the payee or description, the importer assigns this category. The longest word wins. Applies to future imports only - existing transactions stay as they are.";
"kategorien.markiertTitel" = "Words that get corrected a lot";
"kategorien.markiertErklaerung" = "These words often assign the wrong category. Keep them if those were one-offs - remove them if the word does not work.";
"kategorien.markiertZaehler" = "applied %1$d times, corrected %2$d times";
"kategorien.behalten" = "Keep";
"kategorien.entfernen" = "Remove";
/* --- Tags --- */
"tags.neu" = "New tag";
"tags.erklaerung" = "Tags sit across categories: one transaction can carry several. Good for everything that does not fit a category - Iceland trip, tax deductible, to be reimbursed.";
/* --- Settings --- */
"einstellungen.erscheinungsbild" = "Appearance";
"einstellungen.system" = "System";
"einstellungen.hell" = "Light";
"einstellungen.dunkel" = "Dark";
"einstellungen.serverweitErklaerung" = "These settings belong to your account, not just this device - the browser follows them too.";
/* --- Two-factor setup --- */
"zweifaktor.stand" = "Two-factor";
"zweifaktor.aktiv" = "Active";
"zweifaktor.inaktiv" = "Not set up";
"zweifaktor.aktivErklaerung" = "Signing in through the browser asks for a code as well. Turning it off only works on the desktop - it needs your password, and this app deliberately stores none.";
"zweifaktor.inaktivErklaerung" = "A second factor protects your account even if someone knows your password.";
"zweifaktor.einrichten" = "Set up";
"zweifaktor.schrittEins" = "Step 1: add it to your authenticator app";
"zweifaktor.schrittZwei" = "Step 2: confirm with a code";
"zweifaktor.inAppOeffnen" = "Open in authenticator app";
"zweifaktor.geheimnis" = "Secret";
"zweifaktor.geheimnisErklaerung" = "The button opens the app directly. If that does not work, type the secret in by hand.";
"zweifaktor.code" = "Six-digit code";
"zweifaktor.aktivieren" = "Turn on";
"zweifaktor.rettungscodes" = "Recovery codes";
"zweifaktor.rettungscodesErklaerung" = "Each code works once instead of an app code. They appear here and nowhere else - save them now.";
"zweifaktor.codesSichern" = "Save codes";
"zweifaktor.codesNotiert" = "I have saved them";
/* --- Bank --- */
"bank.leerTitel" = "No bank connection";
"bank.leerErklaerung" = "Connecting a bank only works on the desktop - the bank redirects there. You can fetch from here afterwards.";
"bank.land" = "Country";
"bank.zuletzt" = "Last fetched";
"bank.nie" = "never";
"bank.gueltigBis" = "Valid until";
"bank.takt" = "Automatically";
"bank.alleNMinuten" = "every %d minutes";
"bank.abrufen" = "Fetch now";
"bank.saldenAuffrischen" = "Refresh balances only";
"bank.saldenAufgefrischt" = "Balances refreshed.";
"bank.abrufFertig" = "Fetch complete";
"bank.abrufErgebnis" = "Fetched %1$d transactions, %2$d of them new.";
"bank.ohneZuordnung" = "This connection has no account assigned yet. That is done on the desktop.";
/* Screen lock */
"sperre.titel" = "Certain is locked";
"sperre.pin" = "PIN";
"sperre.faceid" = "Unlock with Face ID";
"sperre.touchid" = "Unlock with Touch ID";
"sperre.grund" = "Unlocks Certain without typing your PIN.";
"sperre.falsch" = "Wrong PIN. %d attempts left, then the app signs out.";
"sperre.abmelden" = "Forgot your PIN? Sign out";
"pin.einrichtenTitel" = "Set a PIN";
"pin.erklaerung" = "Six digits. You need them when Face ID does not work – and on every start.";
"pin.neu" = "New PIN";
"pin.wiederholen" = "Again";
"pin.zuKurz" = "The PIN must be six digits.";
"pin.ungleich" = "The two entries differ.";
"pin.sichern" = "Set PIN";
"pin.aendern" = "Change PIN";