From 71161e20f8610b989e7a0d803249e17362e10ddc Mon Sep 17 00:00:00 2001 From: Harsh Shandilya Date: Sun, 18 Aug 2024 13:40:12 +0530 Subject: [PATCH] fix: rework Crowdin integration (#3175) * chore: set up Crowdin configuration * fix(app): sync strings from Crowdin Closes #3174 * fix(ci): use crowdin/github-action instead of homebrew setup * fix(build): remove obsolete Crowdin plugin --- .github/workflows/sync_crowdin.yml | 40 ++- app/build.gradle.kts | 6 - app/src/main/res/values-de/strings.xml | 257 ++++++++++-------- app/src/main/res/values-fr/strings.xml | 1 - app/src/main/res/values-it/strings.xml | 1 - app/src/main/res/values-pt-rBR/strings.xml | 13 +- app/src/main/res/values-ru/strings.xml | 1 - app/src/main/res/values-zh-rCN/strings.xml | 1 - app/src/nonFree/res/values-ar/strings.xml | 8 + app/src/nonFree/res/values-es/strings.xml | 8 + app/src/nonFree/res/values-fi/strings.xml | 8 + app/src/nonFree/res/values-gl-rES/strings.xml | 8 + app/src/nonFree/res/values-hu/strings.xml | 8 + app/src/nonFree/res/values-ko/strings.xml | 8 + app/src/nonFree/res/values-pl/strings.xml | 8 + app/src/nonFree/res/values-uk/strings.xml | 3 +- build-logic/build.gradle.kts | 4 - .../kotlin/app/passwordstore/gradle/OkHttp.kt | 6 - .../gradle/crowdin/BuildOnApiTask.kt | 64 ----- .../gradle/crowdin/CrowdinExtension.kt | 22 -- .../gradle/crowdin/CrowdinPlugin.kt | 70 ----- .../gradle/crowdin/StringCleanupTask.kt | 66 ----- .../gradle/crowdin/api/ListProjects.kt | 14 - crowdin.yml | 90 ++++++ 24 files changed, 320 insertions(+), 395 deletions(-) create mode 100644 app/src/nonFree/res/values-ar/strings.xml create mode 100644 app/src/nonFree/res/values-es/strings.xml create mode 100644 app/src/nonFree/res/values-fi/strings.xml create mode 100644 app/src/nonFree/res/values-gl-rES/strings.xml create mode 100644 app/src/nonFree/res/values-hu/strings.xml create mode 100644 app/src/nonFree/res/values-ko/strings.xml create mode 100644 app/src/nonFree/res/values-pl/strings.xml delete mode 100644 build-logic/src/main/kotlin/app/passwordstore/gradle/crowdin/BuildOnApiTask.kt delete mode 100644 build-logic/src/main/kotlin/app/passwordstore/gradle/crowdin/CrowdinExtension.kt delete mode 100644 build-logic/src/main/kotlin/app/passwordstore/gradle/crowdin/CrowdinPlugin.kt delete mode 100644 build-logic/src/main/kotlin/app/passwordstore/gradle/crowdin/StringCleanupTask.kt delete mode 100644 build-logic/src/main/kotlin/app/passwordstore/gradle/crowdin/api/ListProjects.kt create mode 100644 crowdin.yml diff --git a/.github/workflows/sync_crowdin.yml b/.github/workflows/sync_crowdin.yml index b0917893..9931d7f8 100644 --- a/.github/workflows/sync_crowdin.yml +++ b/.github/workflows/sync_crowdin.yml @@ -11,35 +11,27 @@ jobs: - name: Setup build environment uses: android-password-store/android-password-store/.github/reusable-workflows/setup-gradle@develop - - name: Download new translations from Crowdin - shell: bash - run: ./gradlew --no-configuration-cache crowdin - env: - CROWDIN_LOGIN: ${{ secrets.CROWDIN_LOGIN }} - CROWDIN_PROJECT_KEY: ${{ secrets.CROWDIN_PROJECT_KEY }} - - - name: Check if PR is required - run: if [[ $(git status -s) != '' ]]; then echo "UPDATED=true" >> $GITHUB_ENV; fi - - - name: Create Pull Request - id: cpr - uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v6.1.0 - if: "env.UPDATED == 'true'" + - name: Sync translations to/from Crowdin + id: crowdin + uses: crowdin/github-action@v2 with: - author: GitHub Actions - base: develop - body: This is an automated pull request to sync localisations from Crowdin. - branch: bot/crowdin-sync - commit-message: "strings: sync with crowdin" - labels: A-localisation, S-automerge - title: Sync localisations from Crowdin - token: ${{ secrets.PSL_UPDATE_TOKEN }} + upload_sources: true + upload_translations: false + download_translations: true + localization_branch_name: l10n_crowdin_translations + create_pull_request: true + pull_request_title: 'New Crowdin Translations' + pull_request_body: 'New Crowdin translations by [Crowdin GH Action](https://github.com/crowdin/github-action)' + pull_request_base_branch_name: 'develop' + env: + GITHUB_TOKEN: ${{ secrets.PSL_UPDATE_TOKEN }} + CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_LOGIN }} + CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PROJECT_KEY }} - name: Enable automerge for PR - if: "${{ steps.cpr.outputs.pull-request-operation == 'created' }}" shell: bash run: | gh pr merge --squash --auto "${PR_URL}" env: GITHUB_TOKEN: ${{ secrets.PSL_UPDATE_TOKEN }} - PR_URL: ${{ steps.cpr.outputs.pull-request-url }} + PR_URL: ${{ steps.crowdin.outputs.pull-request-url }} diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 42c88c14..4e6b1b0b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -6,7 +6,6 @@ plugins { id("com.github.android-password-store.android-application") - id("com.github.android-password-store.crowdin-plugin") id("com.github.android-password-store.kotlin-android") id("com.github.android-password-store.kotlin-kapt") id("com.github.android-password-store.versioning-plugin") @@ -16,11 +15,6 @@ plugins { alias(libs.plugins.kotlin.composeCompiler) } -crowdin { - crowdinIdentifier = "android-password-store" - skipCleanup = false -} - android { compileOptions { isCoreLibraryDesugaringEnabled = true } namespace = "app.passwordstore" diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 9ae38196..03576885 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -10,15 +10,19 @@ Einstellungen - Ordner existiert bereits - Zielordner existiert bereits. Aktuelle Version unterstützt nur eine einzige Datenquelle. Möchtest du die aktuelle Datenquelle löschen?\n(%1$s) + Ordner existiert bereits. + Zielordner existiert bereits. Die aktuelle Version unterstützt nur eine einzige Datenquelle. Möchten Sie die aktuelle Datenquelle löschen?\n(%1$s) Ordner löschen Abbruch - Repository Informationen + Repository-Informationen Commit-Log - Bitte klone oder erstelle ein neues Repository, bevor du versuchst ein Passwort hinzuzufügen oder jegliche Synchronisation-Operation durchführst. - Lösche… + Bitte klonen oder erstellen Sie ein neues Repository, bevor Sie ein Passwort hinzufügen oder eine Synchronisations-Operation durchführen wollen. + + Möchten Sie das Passwort wirklich löschen? + Möchten Sie die %d Passwörter wirklich löschen? + + Wird gelöscht Verschieben Bearbeiten Löschen @@ -27,38 +31,39 @@ Fehler beim Verschieben von Passwörtern Verschieben von %1$s nach %2$s fehlgeschlagen - Füge generiertes Passwort für %1$s mittels Android Passwort Store hinzu. + Füge erstelltes Passwort für %1$s mittels Android Password Store hinzu. Bearbeite das Passwort für %1$s mittels Android Password Store. %1$s aus dem Speicher entfernen. Benenne %1$s in %2$s um. Verschiebe mehrere Passwörter nach %1$s. + Initialisiere PGP-IDs in %1$s. In die Zwischenablage kopiert - Bitte setze einen Pfad - Bitte setze einen Pfad - Du kannst kein leeres Passwort setzen oder leere Extra-Angaben + Bitte setzen Sie einen Dateinamen. + Bitte setzen Sie einen Pfad. + Sie können kein leeres Passwort oder leere Extra-Angaben setzen. - Internal Exception occurred + Es ist ein Fehler während der Git-Operation aufgetreten. - Bitte importieren oder generieren Sie Ihre SSH-Schlüsseldatei in den Einstellungen - Kein SSH-Key angegeben + Bitte importieren oder erstellen Sie Ihre SSH-Schlüsseldatei in den Einstellungen. + Kein SSH-Schlüssel angegeben Importieren - Generieren + Erstellen Authentifizieren - Bitte setze ein Passwort für deinen SSH-Key. Lasse das Feld leer, wenn kein Passwort vergeben werden soll. - Bitte setze ein Passwort für dieses Repository + Bitte geben Sie das Passwort für Ihren SSH-Schlüssel ein. + Bitte geben Sie das Passwort für dieses Repository ein. Repository-URL Authentifizierungsmethode - Nutzername + Benutzername E-Mail-Adresse - Bitte valide Email eingeben + Bitte eine gültige E-Mail-Adresse eingeben Klone! Name Passwort - Extra + Zusätzliche Angaben Benutzername verschlüsseln Auswählen Speichern @@ -66,51 +71,61 @@ Suche Passwort: - Benutzername: + Benutzername + Kopieren Passwort bearbeiten Passwort kopieren Als Klartext teilen Repository - Git-Server Einstellungen - Lokale Git Konfiguration & Dienstprogramme - Importiere SSH-Key - Erstelle SSH-Schlüsselpaar - Zeige erstellten öffentlichen SSH-Key + Git-Server-Einstellungen + Lokale Git-Konfiguration & Dienstprogramme + Importiere SSH-Schlüssel. + Erstelle SSH-Schlüsselpaar. + Zeige erstellten öffentlichen SSH-Schlüssel an. Repository löschen Repository löschen Allgemein Passwörter Timeout für das Kopieren des Passwortes - Legen Sie die Zeit (in Sekunden) fest, die das Passwort in der Zwischenablage liegen soll. 0 bedeutet für immer. Aktueller Wert: %1$s - Kopiere Passwort automatisch - Kopiert das Passwort in die Zwischenablage, wenn der Eintrag entschlüsselt wurde. + Legen Sie die Zeitspanne (in Sekunden) fest, wie lange das Passwort in der Zwischenablage liegen soll. 0 bedeutet für immer. Aktueller Wert: %1$s + Kopiere Passwort automatisch. + Kopiert das Passwort in die Zwischenablage, nachdem es entschlüsselt wurde. Die ausgewählte Datei scheint kein privater SSH-Schlüssel zu sein. - SSH-Key importiert + SSH-Schlüssel importiert Schlüssel-Importfehler Nachricht : \n Suche in Unterordnern Findet Passwörter auch in Unterordnern. - Passwort-Datei-Organisation Passwortsortierung Ordner zuerst Dateien zuerst - Typ unabhängig + typunabhängig Zuletzt verwendet Automatisch ausfüllen Autofill aktivieren Verschiedenes Zwischenablagenverlauf umgehen - Zwischenablage mit aufeinanderfolgenden Zahlen überschwemmen, um ggf. bestehende Passwörter zu leeren - Lösche das lokale (versteckte) Repository + Auf Geräten mit Zwischenablagenverlauf diesen mit Zufallszahlen überschwemmen, um ggf. bestehende Passwörter zu entfernen + Lösche das lokale (versteckte) Repository. Passwörter exportieren - Exportiert die verschlüsselten Passwörter in ein externes Verzeichnis + Exportiert die verschlüsselten Passwörter in ein externes Verzeichnis. Rebase beim Pullen Ein Merge-Commit mit Upstream-Änderungen beim Pullen oder Synchronisieren erstellen - Beim Pullen oder Synchronisieren, Commits rebasen, die nicht im Remote-Repository vorhanden sind + Beim Pullen oder Synchronisieren Commits rebasen, die nicht im Remote-Repository vorhanden sind + Kein Synchronisieren durch Abwärtswischen + Beim Wischen über die Passwortliste keine Git-Synchronisation mit dem Repository anstoßen + Importiere PGP-Schlüssel. + Schlüsselmanager + Im ASCII-Armor-Modus verschlüsseln + Zwischenspeicher für Passphrase aktivieren + WARNUNG: Dieses Feature ist funktionsbereit, befindet sich jedoch noch in der Erprobungsphase. Erfordert eine aktive Bildschirmsperre. + Zwischenspeicher für Passphrase aktivieren + Automatische Löschung des Zwischenspeichers + Löscht die Passphrase aus dem Zwischenspeicher nach Abschalten des Bildschirms. - Passwort generieren - Generieren + Passwort erstellen + Erstellen Einschließen Länge Nummern @@ -120,33 +135,33 @@ Zweideutig Aussprechbar Keine Zeichen hinzugefügt - Länge zu kurz für ausgewählte Kriterien - Fehler beim Generieren eines Passworts, das die Einschränkungen erfüllt. Versuchen Sie, die Länge zu erhöhen. + Länge zu kurz für die gewählten Kriterien + Fehler beim Erstellen eines Passworts, das den Anforderungen genügt. Versuchen Sie es mit einem längeren Passwort. Trennzeichen Passwortgenerator Passwort - Generieren + Erstellen Teilen Später - %1$s\n\nFüge den Public-Key zu Deinem Git-Server hinzu. - Schlüssel werden generiert… + %1$s\n\nFügen Sie den öffentlichen Schlüssel Ihrem Git-Server hinzu. + Schlüssel werden erstellt… Mit Anmeldedaten für Bildschirmsperre schützen RSA ECDSA Ed25519 RSA (3072 Bit)\nWird von allen Servern unterstützt, allerdings ist die Authentifizierung recht langsam. - ECDSA (NIST P-256)\nSchnelle Authentifizierung und unterstützt von den meisten Servern, die noch Updates erhalten. - Ed25519\nSchnelle Authentifizierung, aber nur von eher modernen Servern unterstützt. + ECDSA (NIST P-256)\nSchnelle Authentifizierung, unterstützt von den meisten Servern, die noch Updates erhalten. + Ed25519\nSchnelle Authentifizierung, aber nur von moderneren Servern unterstützt SSH-Schlüssel Existierenden SSH-Schlüssel ersetzen? Möglicherweise verlieren Sie den Zugriff auf Ihren Server. Ersetzen Behalten - Authentifizierung der Bildschirmsperre fehlgeschlagen + Authentifizierung über Bildschirmsperre fehlgeschlagen SSH-Schlüssel freischalten - SSH-Schlüssel generieren + SSH-Schlüssel erstellen OK Ja @@ -158,27 +173,27 @@ Git Push Alles aktuell Commit-Log anzeigen - Zeige das Passwort + Zeige das Passwort. Soll das entschlüsselte Passwort sichtbar sein? Dies deaktiviert nicht das Kopieren. - Generieren - Aktualisieren + Erstellen + Liste aktualisieren Passwort unverschlüsselt senden an… - App Icon + App-Icon Eintrag zum Ausfüllen auswählen Phishing-resistente Suche Übereinstimmung mit %1$s Bestehende Übereinstimmungen löschen - Keine Ergebnisse. + Keine Ergebnisse Eintrag suchen Speichern aufgrund eines internen Fehlers fehlgeschlagen - Diese App wird derzeit nicht unterstützt - Die Passwörter stimmen nicht überein - Passwort generieren… + Diese App wird derzeit nicht unterstützt. + Die Passwörter stimmen nicht überein. + Passwort erstellen… Code aus SMS extrahieren… - Maximale Anzahl an Übereinstimmungen (%1$d) erreicht; Lösche Übereinstimmungen, bevor neue hinzugefügt werden. + Maximale Anzahl an Übereinstimmungen (%1$d) erreicht; lösche Übereinstimmungen, bevor neue hinzugefügt werden. Der Hersteller dieser App hat sich geändert, seit Sie einen Eintrag zum Passwort-Speicher mit ihr verknüpft haben: - Die derzeit installierte App versucht, Ihre Anmeldeinformationen zu stehlen, indem sie vorgibt, eine vertrauenswürdige App zu sein.\n\nVersuchen Sie die App zu deinstallieren und installieren Sie sie erneut aus einer vertrauenswürdigen Quelle wie dem Play Store, Amazon Appstore, F-Droid oder dem Shop Ihres Telefonherstellers. + Die derzeit installierte App versucht, Ihre Anmeldeinformationen zu stehlen, indem sie vorgibt, eine vertrauenswürdige App zu sein.\n\nVersuchen Sie, die App zu deinstallieren und installieren Sie sie erneut aus einer vertrauenswürdigen Quelle wie dem Play Store, Amazon Appstore, F-Droid oder dem Shop Ihres Telefonherstellers. Installiert: %1$s Erweiterte Informationen Autofill deaktiviert lassen @@ -189,13 +204,13 @@ Anmeldedaten ausfüllen und speichern Anmeldedaten ausfüllen Passwörter ausfüllen - Passwörter ausfüllen (kann manchmal sein, dass Sie den Browser neu starten müssen) + Passwörter ausfüllen (manchmal kann ein Neustart des Browsers erforderlich sein) Kein Support Password Store kann das Ausfüllen von Anmeldeformularen und sogar das Speichern von Anmeldedaten in Apps oder auf Webseiten übernehmen. - Um diese Funktion zu aktivieren, tippen Sie auf OK, um zu Autofill-Einstellungen zu gelangen. Dort wählen Sie \"Password Store\" aus der Liste und bestätigen Sie die Bestätigungsaufforderung mit \"OK\". + Tippen Sie auf OK, um diese Funktion zu aktivieren und um zu den Autofill-Einstellungen zu gelangen. Dort wählen Sie \"Password Store\" aus der Liste und bestätigen mit \"OK\". Autofill-Unterstützung mit installierten Browsern: - Der private SSH-Schlüssel konnte nicht geöffnet werden. Bitte überprüfen Sie, ob die Datei existiert + Der private SSH-Schlüssel konnte nicht geöffnet werden. Bitte überprüfen Sie, ob die Datei existiert. Neues Passwort Gespeicherte Passphrase für lokalen SSH-Schlüssel löschen Gespeichertes HTTPS-Passwort löschen @@ -206,29 +221,29 @@ Auf Branch %1$s HEAD abgelöst bei %1$s Kann HEAD nicht lokalisieren - Abbrechen und hochladen + Abbrechen und pushen Biometrische Abfrage Authentifizierungsfehler: %s - Biometrische Authentifizierung aktivieren - Wenn aktiviert, werden Sie beim Starten der App nach Ihrem Fingerabdruck gefragt - Fingerabdrucksensor fehlt oder ist nicht ansprechbar - Lösche gespeicherte OpenKeystore SSH-Schlüssel-ID + Biometrische Authentifizierung + Falls aktiviert, werden Sie beim Starten der App nach Ihrem Fingerabdruck gefragt. + Fingerabdrucksensor fehlt oder ist nicht ansprechbar. + Lösche gespeicherte OpenKeystore SSH-Schlüssel-ID. Ihr öffentlicher Schlüssel - Fehler beim Generieren des SSH-Schlüssels - Dateien und Ordner anzeigen - Nicht-Passwort Dateien und Ordner in der Passwortliste mit einbeziehen + Fehler beim Erstellen des SSH-Schlüssels + Alle Dateien und Ordner anzeigen + Nichtpasswort-Dateien und -Ordner in der Passwortliste anzeigen Ordner erstellen Ordner umbenennen - Der Name der Kategorie darf nicht leer sein - Der Kategoriename existiert bereits - Ziel muss innerhalb des repository sein + Der Name der Kategorie darf nicht leer sein. + Der Kategoriename existiert bereits. + Ziel muss innerhalb des Repositorys sein. Ziel für %1$s angeben Erstellen Suchfeld beim Start öffnen Suchleiste beim Start der App anzeigen Hier tippen, um die Zwischenablage zu löschen - Das Repository muss geklont werden, bevor Änderungen synchronisert werden können. - App Farbthema + Das Repository muss geklont werden, bevor Änderungen synchronisiert werden können. + App-Farbthema Hell Dunkel Durch Energiesparmodus gesetzt @@ -236,83 +251,99 @@ SSH-Schlüssel Passwort Konfiguration erfolgreich gespeichert - Die angegebene Repository URL ist ungültig - Bitte geben Sie den HTTPS Benutzernamen in der Form https://username@example.com/… an - Bitte geben Sie den SSH Benutzernamen in der Form username@example.com:… an + Die angegebene Repository-URL ist ungültig. + Bitte geben Sie den HTTPS-Benutzernamen in der Form https://username@example.com/… an. + Bitte geben Sie den SSH-Benutzernamen in der Form username@example.com:… an. Gültige Authentifizierungsarten für %1$s: %2$s Falsches Kennwort Falsches Passwort Neuen Ordner erstellen Neues Passwort erstellen - Debug logging aktivieren (Erfordert Neustart der App) - Debug logging - Wenn Autofill den Benutzernamen nicht aus der Passwortdatei oder dem Ordner herleiten kann, wird der hier festgelegte Wert verwendet - Standard Benutzername + Debug-Ausgaben aktivieren (Erfordert Neustart der App) + Debug-Logging + Wenn Autofill den Benutzernamen nicht aus der Passwortdatei oder dem Ordner herleiten kann, wird der hier festgelegte Wert verwendet. + Standard-Benutzername Passwort merken Passwort Benutzerdefinierte Domains - Autofill wird Subdomains dieser Domains unterscheiden + Autofill wird Subdomains dieser Domains unterscheiden. company.com\npersonal.com Fehler - Fehler beim Speichern der Passwortdatei auf dem Speicher, bitte versuchen Sie es erneut. - Fehler beim Löschen der Passwortdatei %1$s vom Speicher, bitte löschen Sie die Datei von Hand. - Datei existiert bereits, bitte benutzen Sie einen anderen Dateinamen + Fehler beim Speichern der Passwortdatei im Password Store, bitte versuchen Sie es erneut. + Fehler beim Löschen der Passwortdatei %1$s aus dem Password Store, bitte löschen Sie die Datei von Hand. + Datei existiert bereits, bitte benutzen Sie einen anderen Dateinamen. OTP hinzufügen TOTP-Konfiguration erfolgreich importiert Import der TOTP-Konfiguration fehlgeschlagen - Exportiere Passwörter… - Dateiname darf nicht \'/\' enthalten, Verzeichnis oben setzen + Keine Bilddatei ausgewählt + Passwörter werden exportiert. + .gpg-id wurde gefunden, enthält jedoch ungültige Schlüssel-ID, Fingerabdruck oder Benutzer-ID. + .gpg-id wurde gefunden, enthält jedoch eine kurze Hex-ID, die nicht unterstützt wird. + Dateiname darf kein \'/\' enthalten; Verzeichnis oben setzen Ordner - GPG Schlüssel für Ordner festlegen + PGP-Schlüssel für Ordner festlegen Unbekannter Fehler - Pull fehlgeschlagen. Du befindest dich in einem abgelösten Head. Speichere die Änderungen in \"Einstellungen > Git-Werkzeuge\" auf das Remote-Repository in einem neuen Branch und löse den Konflikt auf deinem Computer auf. - Merge fehlgeschlagen, du bist in einem Konflikt. TODO: Wiederherstellungsmethode hinzufügen. - Push wurde vom Remote abgelehnt. Führe den Pull vor dem Push aus. Du kannst \"Synchronisieren\" statt Pull/Push nutzen, da es beides implementiert + Pull fehlgeschlagen. Sie befinden sich in einem abgelösten Head. Speichern Sie die Änderungen in \"Einstellungen > Lokale Git-Konfiguration & Dienstprogramme\" auf das Remote-Repository in einem neuen Branch und lösen Sie den Konflikt auf Ihrem Computer auf. + Merge fehlgeschlagen, Sie befinden sich in einem Konflikt. TODO: Wiederherstellungsmethode hinzufügen. + Push wurde vom Remote abgelehnt. Führen Sie den Pull vor dem Push aus. Sie können \"Synchronisieren\" statt Pull/Push nutzen, da es beides implementiert Push wurde von Remote abgelehnt, Grund: %1$s - Remote hat den Push abgelehnt. Prüfe die Variable receive.denyNonFastForwards in der Konfigurationsdatei des Ziel-Projektarchivs. + Remote hat den Push abgelehnt. Prüfen Sie die Variable receive.denyNonFastForwards in der Konfigurationsdatei des Ziel-Repositorys. Unbekannter Host: %1$s Git-Operation wird ausgeführt… - Es gab einen Klonflikt während des rebase-Prozesses. Dein lokaler %1$s branch wurde auf einen anderen Branch namens %2$s gepusht.\nNutze diesen Branch um Konflikte auf deinem Computer zu beheben - Das Repository befindet sich nicht im Rebase-Prozess, es ist nicht nötig, den Zustand auf einen weiteren Branch zu pushen + Es gab einen Konflikt während des Rebase-Prozesses. Ihr lokaler Branch %1$s wurde auf einen anderen Branch namens %2$s gepusht.\nNutzen Sie diesen Branch, um den Konflikt auf dem Server zu beheben + Das Repository befindet sich nicht im Rebase-Prozess; es ist nicht nötig, den Zustand auf einen weiteren Branch zu pushen. + Um fortzufahren, muss ein PGP-Schlüssel ausgewählt werden. Dateiname bereits vergeben - Ein Ordner mit diesem Namen existiert bereits + Ein Ordner mit diesem Namen existiert bereits. Los geht\'s - Wähle\nRepository Art - Wählen Sie aus, ob sie ein lokales Repository, oder ein remote Repository anlegen möchten. - Remote Repository klonen + Wählen Sie einen \nRepository-Typ. + Wählen Sie aus, ob Sie ein lokales Repository anlegen, oder ein Remote-Repository klonen möchten. + Remote-Repository klonen Lokales Repository anlegen - Wähle\nGPG Key - Wähle einen GPG-Key, mit dem du den Store initialisieren willst + Wählen Sie einen\nPGP-Schlüssel. + Wählen einen PGP-Schlüssel, mit dem der Store initialisiert werden soll. Schlüssel auswählen Möglicherweise inkorrekte URL - Es sieht so aus, als ob Sie einen benutzerdefinierten Port in Ihrer URL angegeben haben, aber nicht in dem ssh://-Schema.\nDas kann dazu führen, dass Ihr Port als Teil des Pfades betrachtet wird. Drücken Sie hier auf OK um die URL zu korrigieren. - HTTPS URL mit nutzerdefiniertem Port - Es sieht aus, als nutzt du eine HTTPS-URL mit nutzerdefiniertem Port. Das ist nicht unterstützt und wird auf lange Sicht zu Problemen führen. Drücke OK, um den Port aus der URL zu entfernen. - Es wird davon abgeraten, das git://-Protokoll zu nutzen - Das git-Protokoll des git-Daemons untersützt keine verschlüsselten Verbindungen und ist für einen sicheren Betrieb nicht geeignet. + Es sieht so aus, als ob Sie einen benutzerdefinierten Port in Ihrer URL angegeben haben, aber nicht im ssh://-Schema.\nDas kann dazu führen, dass Ihr Port als Teil des Pfades betrachtet wird. Drücken Sie hier auf OK, um die URL zu korrigieren. + HTTPS-URL mit benutzerdefiniertem Port + Es sieht so aus, als nutzen Sie eine HTTPS-URL mit benutzerdefiniertem Port. Das ist nicht unterstützt und wird auf lange Sicht zu Problemen führen. Drücken Sie OK, um den Port aus der URL zu entfernen. + Es wird davon abgeraten, das git://-Protokoll zu nutzen. + Das Git-Protokoll des Git-Daemons unterstützt keine verschlüsselten Verbindungen und ist für einen sicheren Betrieb nicht geeignet. - Proxy Hostname + Proxy-Einstellungen + Proxy-Hostname Port - HTTP(S) Proxy Einstellungen + HTTP(S)-Proxy-Einstellungen Ungültige URL - Gespeicherten Host-Key löschen - Host-Key erfolgreich gelöscht! + Passwörter ausfüllen und speichern (Für das Speichern dürfen keine Dienste zur Barrierefreiheit aktiviert sein.) + Gespeicherten Host-Schlüssel löschen + Host-Schlüssel erfolgreich gelöscht! QR-Code scannen - Wähle ein Bild + Wählen Sie ein Bild. Manuell eingeben Schlüssel - Account + Benutzer-Konto Verknüpfung auf dem Home-Screen erstellen Neues Passwort oder neuen Ordner erstellen - Fehler beim Import des PGP-Keys - PGP-Key erfolgreich importiert - Die Schlüssel-ID des importierten Schlüssels ist unten angegeben. Bitte überprüfe sie auf Korrektheit:\n%1$s - PGP Einstellungen - Ein Fehler ist aufgetreten + Fehler beim Import des PGP-Schlüssels + Ein bestehender Schlüssel mit dieser ID wurde gefunden. Möchten Sie ihn ersetzen? + PGP-Schlüssel erfolgreich importiert + Die ID des importierten Schlüssels ist unten angegeben. Bitte überprüfen Sie deren Korrektheit:\n%1$s + PGP-Einstellungen + Ein Fehler ist aufgetreten. Garbage Collection ausführen + PGP-Schlüsselmanager + Schlüssel löschen? + Name des Remote-Branchs + Importieren Sie einen Schlüssel über die unten befindliche Schaltfläche \"+\". + Keine Schlüssel importiert + Es wurden noch keine PGP-Schlüssel in die App importiert. Wählen Sie eine Schlüsseldatei über die Schaltfläche \"Importieren\" aus. + Freischalten des Passphrase-Zwischenspeichers + AEAD-Verschlüsselung festgestellt + %1$s, siehe https://passwordstore.app/fix-aead für weiterführende Informationen. diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 21c50a19..d6edd7b8 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -95,7 +95,6 @@ Message : \n Filtrage récursif Cherche le mot de passe dans tous les sous-répertoires du répertoire actuel. - Organisation des fichiers de mot de passe Ordre de tri des mots de passe Dossiers en premier Fichiers en premier diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 2b56ae8c..728fc6ae 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -95,7 +95,6 @@ Messaggio : \n Filtro ricorsivo Trova ricorsivamente le password della directory corrente. - Organizzazione dei file di password Ordine password Prima le cartelle Prima i file diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 6ce154d6..6f4b9ed9 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -36,6 +36,7 @@ Remova %1$s do armazenamento. Renomear %1$s para %2$s. Mova múltiplas senhas para %1$s. + Inicializar IDs GPG em %1$s. Copiado para a área de transferência Por favor, informe um nome de arquivo @@ -71,6 +72,7 @@ Pesquisar Senha: Usuário: + Copiar Editar senha Copiar senha Compartilhar como texto @@ -95,7 +97,6 @@ Mensagem : \n Filtragem recursiva Encontrar senhas do diretório corrente recursivamente. - Organização do arquivo de senha Ordenação da Senha Pastas primeiro Arquivos primeiro @@ -117,6 +118,11 @@ Importar chave PGP Gerenciador de Chaves Criptografar no modo de proteção ASCII + Ativar cache da senha + AVISO: este recurso é funcional mas muito experimental. Requer um bloqueio de tela ativo. + Autenticar para ativar o cache + Limpar automaticamente cache de senha + Limpa o cache de senha quando a tela está desligada Gerar Senha Gerar @@ -273,6 +279,7 @@ Nenhum arquivo de imagem foi selecionado Exportando senhas… Encontrado .gpg-id, mas contém um ID de chave, fingerprint ou ID de usuário inválidos + Encontrado .gpg-id, mas contém uma ID hexadecimal curta, que não é suportada Nome do arquivo não deve conter \'/\', defina o diretório acima Diretório Definir chave GPG para diretório @@ -288,6 +295,7 @@ Houve um conflito ao executar o rebase. Houve um push de branch %1$s local para outra branch chamada %2$s\n Use esta branch para resolver o conflito no seu computador O repositório não está sendo rebased, não há necessidade de fazer push para outro branch + A seleção de uma chave GPG é necessária para prosseguir Já existe um arquivo com esse nome Já existe uma pasta com esse nome @@ -335,4 +343,7 @@ Importar uma chave usando o botão Adicionar abaixo Nenhuma chave importada Não há chaves PGP importadas no aplicativo ainda, pressione o botão abaixo para escolher um arquivo de chave + Desbloquear cache da senha + Criptografia AEAD detectada + %1$s, consulte https://passwordstore.app/fix-aead para obter mais informações diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index be12a681..223abe2c 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -100,7 +100,6 @@ Сообщение: \n Рекурсивная фильтрация Рекурсивный поиск паролей в текущей директории - Организация файла паролей Порядок сортировки паролей Сначала папки Сначала файлы diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 420092d0..d2f3ac6c 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -96,7 +96,6 @@ 消息: 递归过滤 递归式寻找当前目录的密码 - 密码文件组 密码排序顺序 目录优先 文件优先 diff --git a/app/src/nonFree/res/values-ar/strings.xml b/app/src/nonFree/res/values-ar/strings.xml new file mode 100644 index 00000000..7a6a3cb6 --- /dev/null +++ b/app/src/nonFree/res/values-ar/strings.xml @@ -0,0 +1,8 @@ + + + + في انتظار الرسائل القصيرة… + diff --git a/app/src/nonFree/res/values-es/strings.xml b/app/src/nonFree/res/values-es/strings.xml new file mode 100644 index 00000000..a80f9454 --- /dev/null +++ b/app/src/nonFree/res/values-es/strings.xml @@ -0,0 +1,8 @@ + + + + Esperando por SMS… + diff --git a/app/src/nonFree/res/values-fi/strings.xml b/app/src/nonFree/res/values-fi/strings.xml new file mode 100644 index 00000000..a57feb73 --- /dev/null +++ b/app/src/nonFree/res/values-fi/strings.xml @@ -0,0 +1,8 @@ + + + + Odotetaan SMS-viestiä… + diff --git a/app/src/nonFree/res/values-gl-rES/strings.xml b/app/src/nonFree/res/values-gl-rES/strings.xml new file mode 100644 index 00000000..b68283db --- /dev/null +++ b/app/src/nonFree/res/values-gl-rES/strings.xml @@ -0,0 +1,8 @@ + + + + Agardando polo SMS… + diff --git a/app/src/nonFree/res/values-hu/strings.xml b/app/src/nonFree/res/values-hu/strings.xml new file mode 100644 index 00000000..6ebce291 --- /dev/null +++ b/app/src/nonFree/res/values-hu/strings.xml @@ -0,0 +1,8 @@ + + + + SMS-re várakozás… + diff --git a/app/src/nonFree/res/values-ko/strings.xml b/app/src/nonFree/res/values-ko/strings.xml new file mode 100644 index 00000000..d98dca63 --- /dev/null +++ b/app/src/nonFree/res/values-ko/strings.xml @@ -0,0 +1,8 @@ + + + + SMS를 기다리는 중입니다… + diff --git a/app/src/nonFree/res/values-pl/strings.xml b/app/src/nonFree/res/values-pl/strings.xml new file mode 100644 index 00000000..ba2f05ed --- /dev/null +++ b/app/src/nonFree/res/values-pl/strings.xml @@ -0,0 +1,8 @@ + + + + Oczekiwanie na SMS… + diff --git a/app/src/nonFree/res/values-uk/strings.xml b/app/src/nonFree/res/values-uk/strings.xml index 60c52f48..86d935ee 100644 --- a/app/src/nonFree/res/values-uk/strings.xml +++ b/app/src/nonFree/res/values-uk/strings.xml @@ -1,4 +1,5 @@ - diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts index e4d082ea..4be841d2 100644 --- a/build-logic/build.gradle.kts +++ b/build-logic/build.gradle.kts @@ -17,10 +17,6 @@ gradlePlugin { id = "com.github.android-password-store.android-library" implementationClass = "app.passwordstore.gradle.LibraryPlugin" } - register("crowdin") { - id = "com.github.android-password-store.crowdin-plugin" - implementationClass = "app.passwordstore.gradle.crowdin.CrowdinDownloadPlugin" - } register("git-hooks") { id = "com.github.android-password-store.git-hooks" implementationClass = "app.passwordstore.gradle.GitHooksPlugin" diff --git a/build-logic/src/main/kotlin/app/passwordstore/gradle/OkHttp.kt b/build-logic/src/main/kotlin/app/passwordstore/gradle/OkHttp.kt index e3d33432..7f26d427 100644 --- a/build-logic/src/main/kotlin/app/passwordstore/gradle/OkHttp.kt +++ b/build-logic/src/main/kotlin/app/passwordstore/gradle/OkHttp.kt @@ -12,12 +12,6 @@ import okhttp3.OkHttpClient object OkHttp { private val certificatePinner = CertificatePinner.Builder() - .add( - "api.crowdin.com", - "sha256/qKpGqFXXIteblI82BcMyRX0eC2o7lpL9XVInWKIG7rc=", - "sha256/DxH4tt40L+eduF6szpY6TONlxhZhBd+pJ9wbHlQ2fuw=", - "sha256/++MBgDH5WGvL9Bcn5Be30cRcL0f5O+NyoXuWtQdX1aI=", - ) .add( "publicsuffix.org", "sha256/Ov/MkC2OkVtTp9MdY+uXOKAuV2Birfdeazval8seMZM=", diff --git a/build-logic/src/main/kotlin/app/passwordstore/gradle/crowdin/BuildOnApiTask.kt b/build-logic/src/main/kotlin/app/passwordstore/gradle/crowdin/BuildOnApiTask.kt deleted file mode 100644 index 0fc143d1..00000000 --- a/build-logic/src/main/kotlin/app/passwordstore/gradle/crowdin/BuildOnApiTask.kt +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved. - * SPDX-License-Identifier: GPL-3.0-only - */ - -package app.passwordstore.gradle.crowdin - -import app.passwordstore.gradle.OkHttp -import app.passwordstore.gradle.crowdin.api.ListProjects -import com.squareup.moshi.Moshi -import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory -import okhttp3.MediaType.Companion.toMediaType -import okhttp3.Request -import okhttp3.RequestBody.Companion.toRequestBody -import org.gradle.api.DefaultTask -import org.gradle.api.provider.Property -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.Internal -import org.gradle.api.tasks.TaskAction -import org.gradle.work.DisableCachingByDefault - -@DisableCachingByDefault(because = "This calls into a remote API and has nothing to cache") -abstract class BuildOnApiTask : DefaultTask() { - - @get:Input abstract val crowdinIdentifier: Property - @get:Internal abstract val crowdinLogin: Property - @get:Internal abstract val crowdinKey: Property - - @TaskAction - fun doWork() { - val moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build() - val projectAdapter = moshi.adapter(ListProjects::class.java) - val projectRequest = - Request.Builder() - .url("$CROWDIN_BASE_URL/projects") - .header("Authorization", "Bearer ${crowdinKey.get()}") - .get() - .build() - OkHttp.CLIENT.newCall(projectRequest).execute().use { response -> - val projects = projectAdapter.fromJson(response.body.source()) - if (projects != null) { - val identifier = - projects.projects - .first { data -> data.project.identifier == crowdinIdentifier.get() } - .project - .id - .toString() - val buildRequest = - Request.Builder() - .url(CROWDIN_BUILD_API_URL.format(identifier)) - .header("Authorization", "Bearer ${crowdinKey.get()}") - .post("{}".toRequestBody("application/json".toMediaType())) - .build() - OkHttp.CLIENT.newCall(buildRequest).execute().close() - } - } - } - - private companion object { - - private const val CROWDIN_BASE_URL = "https://api.crowdin.com/api/v2" - private const val CROWDIN_BUILD_API_URL = "$CROWDIN_BASE_URL/projects/%s/translations/builds" - } -} diff --git a/build-logic/src/main/kotlin/app/passwordstore/gradle/crowdin/CrowdinExtension.kt b/build-logic/src/main/kotlin/app/passwordstore/gradle/crowdin/CrowdinExtension.kt deleted file mode 100644 index b78d66d3..00000000 --- a/build-logic/src/main/kotlin/app/passwordstore/gradle/crowdin/CrowdinExtension.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved. - * SPDX-License-Identifier: GPL-3.0-only - */ - -package app.passwordstore.gradle.crowdin - -import org.gradle.api.provider.Property - -/** Extension for configuring [CrowdinDownloadPlugin] */ -interface CrowdinExtension { - - /** Configure the project name on Crowdin */ - val crowdinIdentifier: Property - - /** - * Don't delete downloaded and extracted translation archives from build directory. - * - * Useful for debugging. - */ - val skipCleanup: Property -} diff --git a/build-logic/src/main/kotlin/app/passwordstore/gradle/crowdin/CrowdinPlugin.kt b/build-logic/src/main/kotlin/app/passwordstore/gradle/crowdin/CrowdinPlugin.kt deleted file mode 100644 index f127507a..00000000 --- a/build-logic/src/main/kotlin/app/passwordstore/gradle/crowdin/CrowdinPlugin.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved. - * SPDX-License-Identifier: GPL-3.0-only - */ - -package app.passwordstore.gradle.crowdin - -import de.undercouch.gradle.tasks.download.Download -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.tasks.Copy -import org.gradle.api.tasks.Delete -import org.gradle.kotlin.dsl.create -import org.gradle.kotlin.dsl.register - -@Suppress("Unused") -class CrowdinDownloadPlugin : Plugin { - - override fun apply(project: Project) { - with(project) { - val extension = extensions.create("crowdin") - val login = providers.environmentVariable("CROWDIN_LOGIN") - val key = providers.environmentVariable("CROWDIN_PROJECT_KEY") - val buildOnApi = - if (login.isPresent && key.isPresent) { - tasks.register("buildOnApi") { - crowdinIdentifier.set(extension.crowdinIdentifier) - crowdinLogin.set(login) - crowdinKey.set(key) - } - } else { - null - } - val downloadCrowdin = - tasks.register("downloadCrowdin") { - if (buildOnApi != null) dependsOn(buildOnApi) - src( - "https://crowdin.com/backend/download/project/${extension.crowdinIdentifier.get()}.zip" - ) - dest(layout.buildDirectory.file("translations.zip")) - overwrite(true) - } - val extractCrowdin = - tasks.register("extractCrowdin") { - from(zipTree(downloadCrowdin.map { it.outputFiles.first() })) - into(layout.buildDirectory.dir("translations")) - } - val extractStrings = - tasks.register("extractStrings") { - from(extractCrowdin.map { it.destinationDir }) - into(layout.projectDirectory.dir("src")) - } - val removeIncompleteStrings = - tasks.register("removeIncompleteStrings") { - sourceDirectory.set( - objects.directoryProperty().fileProvider(extractStrings.map { it.destinationDir }) - ) - } - tasks.register("crowdin") { - dependsOn(removeIncompleteStrings) - delete = - if (extension.skipCleanup.getOrElse(false)) { - emptySet() - } else { - setOf(extractStrings.map { it.source }, downloadCrowdin.map { it.outputFiles }) - } - } - } - } -} diff --git a/build-logic/src/main/kotlin/app/passwordstore/gradle/crowdin/StringCleanupTask.kt b/build-logic/src/main/kotlin/app/passwordstore/gradle/crowdin/StringCleanupTask.kt deleted file mode 100644 index 7f91368c..00000000 --- a/build-logic/src/main/kotlin/app/passwordstore/gradle/crowdin/StringCleanupTask.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved. - * SPDX-License-Identifier: GPL-3.0-only - */ - -package app.passwordstore.gradle.crowdin - -import java.io.File -import javax.xml.parsers.DocumentBuilderFactory -import org.gradle.api.DefaultTask -import org.gradle.api.GradleException -import org.gradle.api.file.DirectoryProperty -import org.gradle.api.tasks.InputDirectory -import org.gradle.api.tasks.TaskAction -import org.gradle.work.DisableCachingByDefault -import org.w3c.dom.Document - -@DisableCachingByDefault(because = "The task runs quickly and has complicated semantics") -abstract class StringCleanupTask : DefaultTask() { - - @get:InputDirectory abstract val sourceDirectory: DirectoryProperty - - @TaskAction - fun clean() { - val sourceSets = arrayOf("main", "nonFree") - for (sourceSet in sourceSets) { - val fileTreeWalk = sourceDirectory.dir("$sourceSet/res").get().asFile.walkTopDown() - val valuesDirectories = - fileTreeWalk.filter { it.isDirectory }.filter { it.name.startsWith("values") } - val stringFiles = fileTreeWalk.filter { it.name == "strings.xml" } - val sourceFile = - stringFiles.firstOrNull { it.path.endsWith("values/strings.xml") } - ?: throw GradleException("No root strings.xml found in '$sourceSet' sourceSet") - val sourceDoc = parseDocument(sourceFile) - val baselineStringCount = countStrings(sourceDoc) - val threshold = 0.80 * baselineStringCount - stringFiles.forEach { file -> - if (file != sourceFile) { - val doc = parseDocument(file) - val stringCount = countStrings(doc) - if (stringCount < threshold) { - file.delete() - } - } - } - valuesDirectories.forEach { dir -> - if (dir.listFiles().isNullOrEmpty()) { - dir.delete() - } - } - } - } - - private fun parseDocument(file: File): Document { - val dbFactory = DocumentBuilderFactory.newInstance() - val documentBuilder = dbFactory.newDocumentBuilder() - return documentBuilder.parse(file) - } - - private fun countStrings(document: Document): Int { - // Normalization is beneficial for us - // https://stackoverflow.com/questions/13786607/normalization-in-dom-parsing-with-java-how-does-it-work - document.documentElement.normalize() - return document.getElementsByTagName("string").length - } -} diff --git a/build-logic/src/main/kotlin/app/passwordstore/gradle/crowdin/api/ListProjects.kt b/build-logic/src/main/kotlin/app/passwordstore/gradle/crowdin/api/ListProjects.kt deleted file mode 100644 index 933d7e02..00000000 --- a/build-logic/src/main/kotlin/app/passwordstore/gradle/crowdin/api/ListProjects.kt +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright © 2014-2024 The Android Password Store Authors. All Rights Reserved. - * SPDX-License-Identifier: GPL-3.0-only - */ - -package app.passwordstore.gradle.crowdin.api - -import com.squareup.moshi.Json - -data class ListProjects(@Json(name = "data") val projects: List) - -data class ProjectData(@Json(name = "data") val project: Project) - -data class Project(val id: Long, val identifier: String) diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 00000000..116a2194 --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,90 @@ +"api_token_env": "CROWDIN_PERSONAL_TOKEN" +"project_id_env": "CROWDIN_PROJECT_ID" +"preserve_hierarchy": true +"files": [ + { + "source": "/app/src/main/res/values/strings.xml", + "dest": "/main_strings.xml", + "translation": "/app/src/main/res/values-%android_code%/strings.xml", + "languages_mapping": &stringmapping { + "android_code": { + "ar": "ar", + "am": "am", + "hy-AM": "hy-rAM", + "az": "az", + "be": "be", + "bn": "bn-rBD", + "bg": "bg", + "ca": "ca", + "cs": "cs", + "da": "da", + "de": "de", + "el": "el", + "es-ES": "es", + "es-AR": "es-rAR", + "es-MX": "es-rMX", + "es-VE": "es-rVE", + "et": "et-rEE", + "eu": "eu-rES", + "fa": "fa", + "fil": "fil", + "fi": "fi", + "fr": "fr", + "gl": "gl-rES", + "hr": "hr", + "hu": "hu", + "is": "is", + "id": "in", + "it": "it", + "he": "iw", + "ja": "ja", + "ka": "ka-rGE", + "km": "km-rKH", + "kn": "kn-rIN", + "ko": "ko", + "ky": "ky-rKG", + "lt": "lt", + "lv": "lv", + "lo": "lo-rLA", + "ms": "ms", + "ml-IN": "ml-rIN", + "mn": "mn-rMN", + "mr": "mr-rIN", + "my": "my-rMM", + "ne-NP": "ne-rNP", + "nl": "nl", + "no": "nb", + "pl": "pl", + "pt-PT": "pt", + "pt-BR": "pt-rBR", + "ro": "ro", + "ru": "ru", + "rm-CH": "rm", + "si-LK": "si-rLK", + "sk": "sk", + "sl": "sl", + "sr": "sr", + "sv-SE": "sv", + "sw": "sw", + "th": "th", + "ta": "ta-rIN", + "te": "te-rIN", + "tr": "tr", + "uk": "uk", + "ur-IN": "ur-rIN", + "uz": "uz", + "vi": "vi", + "zh-CN": "zh-rCN", + "zh-HK": "zh-rHK", + "zh-TW": "zh-rTW", + "zu": "zu" + } + } + }, + { + "source": "/app/src/nonFree/res/values/strings.xml", + "dest": "/nonFree_strings.xml", + "translation": "/app/src/nonFree/res/values-%android_code%/strings.xml", + "languages_mapping": *stringmapping + } +]