From d4335f6125d7209090f54dc25fb94f9a271e232e Mon Sep 17 00:00:00 2001 From: ACX <8075870+acx10@users.noreply.github.com> Date: Thu, 12 Feb 2026 23:38:59 -0700 Subject: [PATCH] feat(i18n): add Weblate integration and auth translations (#2727) * feat(i18n): add Weblate integration and auth translations for all languages * chore: cache-bust Weblate widget URL --- README.md | 17 +++ booklore-ui/src/i18n/de/auth.json | 25 +++- booklore-ui/src/i18n/fr/auth.json | 25 +++- booklore-ui/src/i18n/it/auth.json | 25 +++- booklore-ui/src/i18n/nl/auth.json | 25 +++- booklore-ui/src/i18n/pl/auth.json | 25 +++- booklore-ui/src/i18n/pt/auth.json | 25 +++- booklore-ui/src/i18n/ru/auth.json | 25 +++- scripts/weblate-setup.sh | 183 ++++++++++++++++++++++++++++++ 9 files changed, 368 insertions(+), 7 deletions(-) create mode 100755 scripts/weblate-setup.sh diff --git a/README.md b/README.md index 60f8393a7..97a4a450c 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ [![Discord](https://img.shields.io/badge/Join_Discord-5865F2?style=for-the-badge&logo=discord&logoColor=white)](https://discord.gg/Ee5hd458Uz) [![Open Collective](https://img.shields.io/opencollective/all/booklore?style=for-the-badge&color=7FADF2&logo=opencollective)](https://opencollective.com/booklore) +[![Translate](https://img.shields.io/weblate/progress/booklore?style=for-the-badge&logo=weblate&logoColor=white&color=2ECCAA)](https://hosted.weblate.org/engage/booklore/) --- @@ -391,6 +392,22 @@ Join community! +--- + +
+ +## 🌍 **Translations** + +Help translate BookLore into your language! + + + Translation status + + +Read more about translations [here](https://hosted.weblate.org/engage/booklore/). + +
+ ---
diff --git a/booklore-ui/src/i18n/de/auth.json b/booklore-ui/src/i18n/de/auth.json index 0967ef424..845807612 100644 --- a/booklore-ui/src/i18n/de/auth.json +++ b/booklore-ui/src/i18n/de/auth.json @@ -1 +1,24 @@ -{} +{ + "login": { + "title": "Willkommen zurück", + "subtitle": "Melden Sie sich an, um fortzufahren", + "usernameLabel": "Benutzername", + "usernamePlaceholder": "Benutzername eingeben", + "passwordLabel": "Passwort", + "passwordPlaceholder": "Passwort eingeben", + "signIn": "Anmelden", + "orContinueWith": "oder weiter mit", + "redirectingTo": "Weiterleitung zu {{provider}}...", + "oidcTrouble": "Probleme mit {{provider}}? Lokale Anmeldung verwenden", + "reEnableOidc": "{{provider}}-Anmeldung wieder aktivieren", + "connectionError": "Verbindung zum Server nicht möglich. Bitte überprüfen Sie Ihre Verbindung und versuchen Sie es erneut.", + "unexpectedError": "Ein unerwarteter Fehler ist aufgetreten. Bitte versuchen Sie es erneut.", + "oidcInitError": "OIDC-Anmeldung fehlgeschlagen. Bitte versuchen Sie es erneut oder verwenden Sie die lokale Anmeldung.", + "oidcWarningTitle": "OIDC-Authentifizierungsprobleme", + "retryOidc": "OIDC erneut versuchen", + "useLocalLogin": "Lokale Anmeldung verwenden", + "oidcAutoDisabled": "Die Authentifizierung über {{provider}} wurde nach {{count}} aufeinanderfolgenden Fehlern (einschließlich Zeitüberschreitungen) automatisch deaktiviert. Sie können es erneut versuchen oder mit der lokalen Anmeldung fortfahren.", + "oidcManuallyDisabled": "Die Authentifizierung über {{provider}} wurde manuell deaktiviert. Sie können sie wieder aktivieren oder mit der lokalen Anmeldung fortfahren.", + "oidcErrors": "Die Authentifizierung über {{provider}} hat {{count}} Fehler festgestellt, möglicherweise aufgrund von Zeitüberschreitungen oder Serverproblemen." + } +} diff --git a/booklore-ui/src/i18n/fr/auth.json b/booklore-ui/src/i18n/fr/auth.json index 0967ef424..7905be7ee 100644 --- a/booklore-ui/src/i18n/fr/auth.json +++ b/booklore-ui/src/i18n/fr/auth.json @@ -1 +1,24 @@ -{} +{ + "login": { + "title": "Bon retour", + "subtitle": "Connectez-vous pour continuer", + "usernameLabel": "Nom d'utilisateur", + "usernamePlaceholder": "Entrez votre nom d'utilisateur", + "passwordLabel": "Mot de passe", + "passwordPlaceholder": "Entrez votre mot de passe", + "signIn": "Se connecter", + "orContinueWith": "ou continuer avec", + "redirectingTo": "Redirection vers {{provider}}...", + "oidcTrouble": "Des problèmes avec {{provider}} ? Utilisez la connexion locale", + "reEnableOidc": "Réactiver la connexion {{provider}}", + "connectionError": "Impossible de se connecter au serveur. Veuillez vérifier votre connexion et réessayer.", + "unexpectedError": "Une erreur inattendue s'est produite. Veuillez réessayer.", + "oidcInitError": "Échec de la connexion OIDC. Veuillez réessayer ou utilisez la connexion locale.", + "oidcWarningTitle": "Problèmes d'authentification OIDC", + "retryOidc": "Réessayer OIDC", + "useLocalLogin": "Utiliser la connexion locale", + "oidcAutoDisabled": "L'authentification {{provider}} a été automatiquement désactivée après {{count}} échecs consécutifs (y compris les délais d'attente). Vous pouvez réessayer ou continuer avec la connexion locale.", + "oidcManuallyDisabled": "L'authentification {{provider}} a été désactivée manuellement. Vous pouvez la réactiver ou continuer avec la connexion locale.", + "oidcErrors": "L'authentification {{provider}} a rencontré {{count}} erreur(s), possiblement en raison de délais d'attente ou de problèmes serveur." + } +} diff --git a/booklore-ui/src/i18n/it/auth.json b/booklore-ui/src/i18n/it/auth.json index 0967ef424..5116fa3b6 100644 --- a/booklore-ui/src/i18n/it/auth.json +++ b/booklore-ui/src/i18n/it/auth.json @@ -1 +1,24 @@ -{} +{ + "login": { + "title": "Bentornato", + "subtitle": "Accedi per continuare il tuo viaggio", + "usernameLabel": "Nome utente", + "usernamePlaceholder": "Inserisci il tuo nome utente", + "passwordLabel": "Password", + "passwordPlaceholder": "Inserisci la tua password", + "signIn": "Accedi", + "orContinueWith": "o continua con", + "redirectingTo": "Reindirizzamento a {{provider}}...", + "oidcTrouble": "Problemi con {{provider}}? Usa l'accesso locale", + "reEnableOidc": "Riattiva l'accesso con {{provider}}", + "connectionError": "Impossibile connettersi al server. Controlla la connessione e riprova.", + "unexpectedError": "Si è verificato un errore imprevisto. Riprova.", + "oidcInitError": "Impossibile avviare l'accesso OIDC. Riprova o usa l'accesso locale.", + "oidcWarningTitle": "Problemi di autenticazione OIDC", + "retryOidc": "Riprova OIDC", + "useLocalLogin": "Usa accesso locale", + "oidcAutoDisabled": "L'autenticazione {{provider}} è stata disattivata automaticamente dopo {{count}} errori consecutivi (inclusi i timeout). Puoi riprovare o continuare con l'accesso locale.", + "oidcManuallyDisabled": "L'autenticazione {{provider}} è stata disattivata manualmente. Puoi riattivarla o continuare con l'accesso locale.", + "oidcErrors": "L'autenticazione {{provider}} ha riscontrato {{count}} errore/i, probabilmente a causa di timeout o problemi del server." + } +} diff --git a/booklore-ui/src/i18n/nl/auth.json b/booklore-ui/src/i18n/nl/auth.json index 0967ef424..abb4629f5 100644 --- a/booklore-ui/src/i18n/nl/auth.json +++ b/booklore-ui/src/i18n/nl/auth.json @@ -1 +1,24 @@ -{} +{ + "login": { + "title": "Welkom terug", + "subtitle": "Log in om verder te gaan", + "usernameLabel": "Gebruikersnaam", + "usernamePlaceholder": "Voer je gebruikersnaam in", + "passwordLabel": "Wachtwoord", + "passwordPlaceholder": "Voer je wachtwoord in", + "signIn": "Inloggen", + "orContinueWith": "of ga verder met", + "redirectingTo": "Doorverwijzen naar {{provider}}...", + "oidcTrouble": "Problemen met {{provider}}? Gebruik lokale login", + "reEnableOidc": "{{provider}}-login opnieuw inschakelen", + "connectionError": "Kan geen verbinding maken met de server. Controleer je verbinding en probeer het opnieuw.", + "unexpectedError": "Er is een onverwachte fout opgetreden. Probeer het opnieuw.", + "oidcInitError": "OIDC-login mislukt. Probeer het opnieuw of gebruik de lokale login.", + "oidcWarningTitle": "OIDC-authenticatieproblemen", + "retryOidc": "OIDC opnieuw proberen", + "useLocalLogin": "Lokale login gebruiken", + "oidcAutoDisabled": "{{provider}}-authenticatie is automatisch uitgeschakeld na {{count}} opeenvolgende fouten (inclusief time-outs). Je kunt het opnieuw proberen of doorgaan met de lokale login.", + "oidcManuallyDisabled": "{{provider}}-authenticatie is handmatig uitgeschakeld. Je kunt het opnieuw inschakelen of doorgaan met de lokale login.", + "oidcErrors": "{{provider}}-authenticatie heeft {{count}} fout(en) ondervonden, mogelijk door time-outs of serverproblemen." + } +} diff --git a/booklore-ui/src/i18n/pl/auth.json b/booklore-ui/src/i18n/pl/auth.json index 0967ef424..264a3301d 100644 --- a/booklore-ui/src/i18n/pl/auth.json +++ b/booklore-ui/src/i18n/pl/auth.json @@ -1 +1,24 @@ -{} +{ + "login": { + "title": "Witaj ponownie", + "subtitle": "Zaloguj się, aby kontynuować", + "usernameLabel": "Nazwa użytkownika", + "usernamePlaceholder": "Wprowadź nazwę użytkownika", + "passwordLabel": "Hasło", + "passwordPlaceholder": "Wprowadź hasło", + "signIn": "Zaloguj się", + "orContinueWith": "lub kontynuuj przez", + "redirectingTo": "Przekierowanie do {{provider}}...", + "oidcTrouble": "Problemy z {{provider}}? Użyj logowania lokalnego", + "reEnableOidc": "Ponownie włącz logowanie przez {{provider}}", + "connectionError": "Nie można połączyć się z serwerem. Sprawdź połączenie i spróbuj ponownie.", + "unexpectedError": "Wystąpił nieoczekiwany błąd. Spróbuj ponownie.", + "oidcInitError": "Nie udało się uruchomić logowania OIDC. Spróbuj ponownie lub użyj logowania lokalnego.", + "oidcWarningTitle": "Problemy z uwierzytelnianiem OIDC", + "retryOidc": "Ponów OIDC", + "useLocalLogin": "Użyj logowania lokalnego", + "oidcAutoDisabled": "Uwierzytelnianie {{provider}} zostało automatycznie wyłączone po {{count}} kolejnych błędach (w tym przekroczeniach czasu). Możesz spróbować ponownie lub kontynuować z logowaniem lokalnym.", + "oidcManuallyDisabled": "Uwierzytelnianie {{provider}} zostało ręcznie wyłączone. Możesz je ponownie włączyć lub kontynuować z logowaniem lokalnym.", + "oidcErrors": "Uwierzytelnianie {{provider}} napotkało {{count}} błąd(ów), prawdopodobnie z powodu przekroczeń czasu lub problemów z serwerem." + } +} diff --git a/booklore-ui/src/i18n/pt/auth.json b/booklore-ui/src/i18n/pt/auth.json index 0967ef424..c60d8c583 100644 --- a/booklore-ui/src/i18n/pt/auth.json +++ b/booklore-ui/src/i18n/pt/auth.json @@ -1 +1,24 @@ -{} +{ + "login": { + "title": "Bem-vindo de volta", + "subtitle": "Inicie sessão para continuar", + "usernameLabel": "Nome de utilizador", + "usernamePlaceholder": "Introduza o seu nome de utilizador", + "passwordLabel": "Palavra-passe", + "passwordPlaceholder": "Introduza a sua palavra-passe", + "signIn": "Iniciar sessão", + "orContinueWith": "ou continuar com", + "redirectingTo": "A redirecionar para {{provider}}...", + "oidcTrouble": "Problemas com {{provider}}? Use o início de sessão local", + "reEnableOidc": "Reativar início de sessão com {{provider}}", + "connectionError": "Não é possível ligar ao servidor. Verifique a sua ligação e tente novamente.", + "unexpectedError": "Ocorreu um erro inesperado. Tente novamente.", + "oidcInitError": "Falha ao iniciar o início de sessão OIDC. Tente novamente ou use o início de sessão local.", + "oidcWarningTitle": "Problemas de autenticação OIDC", + "retryOidc": "Tentar OIDC novamente", + "useLocalLogin": "Usar início de sessão local", + "oidcAutoDisabled": "A autenticação {{provider}} foi automaticamente desativada após {{count}} falhas consecutivas (incluindo tempos limite). Pode tentar novamente ou continuar com o início de sessão local.", + "oidcManuallyDisabled": "A autenticação {{provider}} foi desativada manualmente. Pode reativá-la ou continuar com o início de sessão local.", + "oidcErrors": "A autenticação {{provider}} encontrou {{count}} erro(s), possivelmente devido a tempos limite ou problemas no servidor." + } +} diff --git a/booklore-ui/src/i18n/ru/auth.json b/booklore-ui/src/i18n/ru/auth.json index 0967ef424..a13c58c98 100644 --- a/booklore-ui/src/i18n/ru/auth.json +++ b/booklore-ui/src/i18n/ru/auth.json @@ -1 +1,24 @@ -{} +{ + "login": { + "title": "С возвращением", + "subtitle": "Войдите, чтобы продолжить", + "usernameLabel": "Имя пользователя", + "usernamePlaceholder": "Введите имя пользователя", + "passwordLabel": "Пароль", + "passwordPlaceholder": "Введите пароль", + "signIn": "Войти", + "orContinueWith": "или продолжить через", + "redirectingTo": "Перенаправление на {{provider}}...", + "oidcTrouble": "Проблемы с {{provider}}? Используйте локальный вход", + "reEnableOidc": "Повторно включить вход через {{provider}}", + "connectionError": "Не удаётся подключиться к серверу. Проверьте подключение и попробуйте снова.", + "unexpectedError": "Произошла непредвиденная ошибка. Попробуйте снова.", + "oidcInitError": "Не удалось инициировать вход через OIDC. Попробуйте снова или используйте локальный вход.", + "oidcWarningTitle": "Проблемы аутентификации OIDC", + "retryOidc": "Повторить OIDC", + "useLocalLogin": "Использовать локальный вход", + "oidcAutoDisabled": "Аутентификация {{provider}} была автоматически отключена после {{count}} последовательных ошибок (включая тайм-ауты). Вы можете повторить попытку или продолжить с локальным входом.", + "oidcManuallyDisabled": "Аутентификация {{provider}} была отключена вручную. Вы можете включить её снова или продолжить с локальным входом.", + "oidcErrors": "Аутентификация {{provider}} обнаружила {{count}} ошибку(ок), возможно, из-за тайм-аутов или проблем с сервером." + } +} diff --git a/scripts/weblate-setup.sh b/scripts/weblate-setup.sh new file mode 100755 index 000000000..2c3792a11 --- /dev/null +++ b/scripts/weblate-setup.sh @@ -0,0 +1,183 @@ +#!/usr/bin/env bash +# +# Weblate Setup Script for BookLore +# +# Creates the Weblate project and all 25 translation components via the API. +# Run once after creating your Hosted Weblate account. +# +# Prerequisites: +# 1. Get your API token from https://hosted.weblate.org/accounts/profile/#api +# 2. Ensure your GitHub repo (booklore-app/booklore) is public (required for Libre plan) +# +# Usage: +# WEBLATE_TOKEN=your-api-token ./scripts/weblate-setup.sh +# + +set -euo pipefail + +# ─── Configuration ──────────────────────────────────────────────────────────── +WEBLATE_URL="${WEBLATE_URL:-https://hosted.weblate.org}" +API="${WEBLATE_URL}/api" +TOKEN="${WEBLATE_TOKEN:?Set WEBLATE_TOKEN to your Weblate API token}" + +PROJECT_NAME="BookLore" +PROJECT_SLUG="booklore" +PROJECT_WEB="https://github.com/booklore-app/booklore" + +REPO_URL="https://github.com/booklore-app/booklore.git" +REPO_BRANCH="develop" +FILE_BASE="booklore-ui/src/i18n" + +SOURCE_LANG="en" + +# All languages the project supports +LANGUAGES="en es de fr it nl pl pt ru" + +# All 25 translation domain files (without .json extension) +COMPONENTS=( + common + auth + nav + dashboard + settings + settings-email + settings-reader + settings-view + settings-metadata + settings-library-metadata + settings-application + settings-users + settings-naming + settings-opds + settings-tasks + settings-auth + settings-device + settings-profile + app + shared + layout + library-creator + bookdrop + metadata +) + +# ─── Helpers ────────────────────────────────────────────────────────────────── +auth_header="Authorization: Token ${TOKEN}" +content_type="Content-Type: application/json" + +api_post() { + local endpoint="$1" + local data="$2" + local response + response=$(curl -s -w "\n%{http_code}" -X POST "${API}${endpoint}" \ + -H "${auth_header}" \ + -H "${content_type}" \ + -d "${data}") + local http_code + http_code=$(echo "$response" | tail -1) + local body + body=$(echo "$response" | sed '$d') + + if [[ "$http_code" -ge 200 && "$http_code" -lt 300 ]]; then + echo " OK (${http_code})" + return 0 + elif [[ "$http_code" == "400" ]] && echo "$body" | grep -q "already exists"; then + echo " Already exists, skipping" + return 0 + else + echo " FAILED (${http_code}): ${body}" + return 1 + fi +} + +# Pretty name from slug: settings-email -> Settings Email +pretty_name() { + echo "$1" | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++) $i=toupper(substr($i,1,1)) tolower(substr($i,2))}1' +} + +# ─── Step 1: Create Project ────────────────────────────────────────────────── +echo "=== Creating project: ${PROJECT_NAME} ===" +api_post "/projects/" "$(cat <