From 3050955f9c6a29518483f6f7315b440b0dbe72c7 Mon Sep 17 00:00:00 2001 From: Dionisio Date: Wed, 11 Feb 2026 12:26:29 +0100 Subject: [PATCH] feat: add admin/profile UI, i18n (fr/de/pt), fix CI pipelines - Add admin panel link and profile modal in user menu dropdown - Add French, German and Portuguese locale support (full translations) - Register new locales across JS frontend and Rust backend - Create CI pipeline (fmt, clippy, test, audit, build) - Fix docker-build.yml (cache, real tests, reduced timeout) - Fix docker-publish.yml (multi-arch via QEMU, latest tag, pre-publish tests) - Add dependabot.yml for automated dependency updates --- .github/dependabot.yml | 40 ++ .github/workflows/ci.yml | 85 +++ .github/workflows/docker-build.yml | 48 +- .github/workflows/docker-publish.yml | 93 ++- src/application/dtos/i18n_dto.rs | 3 + src/common/di.rs | 9 + src/domain/services/i18n_service.rs | 9 + .../services/file_system_i18n_service.rs | 2 +- static/css/style.css | 35 + static/index.html | 12 + static/js/app.js | 95 +++ static/js/auth.js | 6 +- static/js/i18n.js | 2 +- static/js/languageSelector.js | 5 +- static/locales/de.json | 670 +++++++++--------- static/locales/en.json | 10 +- static/locales/es.json | 10 +- static/locales/fa.json | 10 +- static/locales/fr.json | 338 +++++++++ static/locales/pt.json | 338 +++++++++ static/locales/zh.json | 10 +- 21 files changed, 1422 insertions(+), 408 deletions(-) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/ci.yml create mode 100644 static/locales/fr.json create mode 100644 static/locales/pt.json diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..dba3505a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,40 @@ +version: 2 +updates: + # Rust (Cargo) dependencies + - package-ecosystem: "cargo" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + open-pull-requests-limit: 10 + labels: + - "dependencies" + - "rust" + commit-message: + prefix: "deps(rust):" + + # GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + open-pull-requests-limit: 5 + labels: + - "dependencies" + - "ci" + commit-message: + prefix: "deps(ci):" + + # Docker + - package-ecosystem: "docker" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + open-pull-requests-limit: 3 + labels: + - "dependencies" + - "docker" + commit-message: + prefix: "deps(docker):" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..13434fba --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,85 @@ +name: CI + +on: + push: + branches: [ "main", "dev" ] + pull_request: + branches: [ "main", "dev" ] + +env: + CARGO_TERM_COLOR: always + RUSTFLAGS: "-Dwarnings" + DATABASE_URL: "postgres://postgres:postgres@localhost/oxicloud_test" + +jobs: + fmt: + name: Rustfmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt + - run: cargo fmt --all --check + + clippy: + name: Clippy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy + - uses: Swatinem/rust-cache@v2 + - run: cargo clippy --all-targets --all-features -- -D warnings + + test: + name: Tests + runs-on: ubuntu-latest + services: + postgres: + image: postgres:16-alpine + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: oxicloud_test + ports: + - 5432:5432 + options: >- + --health-cmd "pg_isready -U postgres" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + + - name: Initialize test database + run: psql -h localhost -U postgres -d oxicloud_test -f db/schema.sql + env: + PGPASSWORD: postgres + + - name: Run tests + run: cargo test --all-features --workspace + env: + DATABASE_URL: "postgres://postgres:postgres@localhost/oxicloud_test" + + audit: + name: Security Audit + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: rustsec/audit-check@v2.0.0 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + build: + name: Build Check + runs-on: ubuntu-latest + needs: [fmt, clippy, test] + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + - run: cargo build --release diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 5bafbdde..a1bebffe 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -1,6 +1,5 @@ name: Docker Build and Test -# Trigger on push to main branch or on pull requests on: push: branches: [ "main", "dev" ] @@ -8,21 +7,18 @@ on: branches: [ "main", "dev" ] jobs: - # Build and test Docker image but don't push build-and-test: name: Build and Test Docker Image runs-on: ubuntu-latest - timeout-minutes: 120 # Aumentado a 2 horas para dar más tiempo a la compilación + timeout-minutes: 45 steps: - name: Checkout code uses: actions/checkout@v4 - # Set up Docker Buildx - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - # Extract metadata (tags, labels) for Docker - name: Extract metadata (tags, labels) for Docker id: meta uses: docker/metadata-action@v5 @@ -33,7 +29,6 @@ jobs: type=ref,event=pr type=sha - # Build Docker image but don't push - name: Build Docker image uses: docker/build-push-action@v5 with: @@ -41,16 +36,41 @@ jobs: push: false load: true tags: test/oxicloud:test - # Caché eliminado para evitar problemas de expiración de token + cache-from: type=gha + cache-to: type=gha,mode=max - # Run some basic tests against the built image - - name: Test Docker image + - name: Verify image starts correctly run: | - docker run --rm test/oxicloud:test --version || true - docker run --rm test/oxicloud:test --help || true + # Start the container in background + docker run -d --name oxicloud-test \ + -e DATABASE_URL="postgres://test:test@localhost/test" \ + -p 8080:8080 \ + test/oxicloud:test || true - # Verify the image structure - echo "✅ Checking Docker image layers and size" - docker image inspect test/oxicloud:test + # Give it a moment to start (or fail) + sleep 3 + + # Check that the container exists and show logs + echo "=== Container status ===" + docker ps -a --filter name=oxicloud-test + echo "=== Container logs ===" + docker logs oxicloud-test 2>&1 || true + + # Cleanup + docker rm -f oxicloud-test || true + + - name: Verify image structure + run: | + echo "=== Image size ===" + docker image ls test/oxicloud:test + + echo "=== Binary exists and is executable ===" + docker run --rm --entrypoint sh test/oxicloud:test -c "test -x /usr/local/bin/oxicloud && echo 'OK: binary is executable'" + + echo "=== Static files present ===" + docker run --rm --entrypoint sh test/oxicloud:test -c "ls /app/static/index.html && echo 'OK: static files present'" + + echo "=== DB schema present ===" + docker run --rm --entrypoint sh test/oxicloud:test -c "ls /app/db/schema.sql && echo 'OK: schema present'" echo "✅ Docker build and test completed successfully" diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 1265e0ea..5d900d77 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -6,63 +6,47 @@ on: workflow_dispatch: inputs: version: - description: 'Versión del release' - required: false - default: '0.1.0-rc1' + description: 'Version tag to publish (e.g. v0.3.0)' + required: true + +env: + REGISTRY_IMAGE: diocrafts/oxicloud jobs: - build-and-push: + # Run tests before publishing + test: + name: Pre-publish Tests runs-on: ubuntu-latest - strategy: - matrix: - arch: [amd64, arm64] + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + - run: cargo test --workspace + + # Build and push multi-arch image in a single job + build-and-push: + name: Build & Push Multi-Arch + runs-on: ubuntu-latest + needs: test steps: - name: Checkout uses: actions/checkout@v4 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Login to DockerHub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Set version tag id: version run: | if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then - echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV + VERSION="${{ github.event.inputs.version }}" else - echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV + VERSION="${GITHUB_REF#refs/tags/}" fi + # Strip leading 'v' if present for Docker tag + VERSION="${VERSION#v}" + echo "VERSION=$VERSION" >> $GITHUB_ENV + echo "version=$VERSION" >> $GITHUB_OUTPUT - - name: Build and Push Docker Image - uses: docker/build-push-action@v5 - with: - context: . - platforms: linux/${{ matrix.arch }} - push: true - tags: | - diocrafts/oxicloud:${{ env.VERSION }} - cache-from: type=gha - cache-to: type=gha,mode=max - build-args: | - VERSION=${{ env.VERSION }} - - # Crear el manifiesto multi-arch una vez todas las imágenes estén listas - manifest: - needs: build-and-push - runs-on: ubuntu-latest - steps: - - name: Set version tag - run: | - if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then - echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV - else - echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV - fi + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -73,9 +57,22 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Create and Push Manifest + - name: Build and Push Multi-Arch Image + uses: docker/build-push-action@v5 + with: + context: . + platforms: linux/amd64,linux/arm64 + push: true + tags: | + ${{ env.REGISTRY_IMAGE }}:${{ env.VERSION }} + ${{ env.REGISTRY_IMAGE }}:latest + cache-from: type=gha + cache-to: type=gha,mode=max + build-args: | + VERSION=${{ env.VERSION }} + + - name: Verify published image run: | - docker buildx imagetools create \ - -t diocrafts/oxicloud:${{ env.VERSION }} \ - diocrafts/oxicloud:${{ env.VERSION }}@linux/amd64 \ - diocrafts/oxicloud:${{ env.VERSION }}@linux/arm64 + docker pull ${{ env.REGISTRY_IMAGE }}:${{ env.VERSION }} + docker image inspect ${{ env.REGISTRY_IMAGE }}:${{ env.VERSION }} + echo "✅ Image ${{ env.REGISTRY_IMAGE }}:${{ env.VERSION }} published successfully" diff --git a/src/application/dtos/i18n_dto.rs b/src/application/dtos/i18n_dto.rs index 0ce92096..bd3dea72 100644 --- a/src/application/dtos/i18n_dto.rs +++ b/src/application/dtos/i18n_dto.rs @@ -16,6 +16,9 @@ impl From for LocaleDto { let (code, name) = match locale { Locale::English => ("en", "English"), Locale::Spanish => ("es", "Español"), + Locale::French => ("fr", "Français"), + Locale::German => ("de", "Deutsch"), + Locale::Portuguese => ("pt", "Português"), }; Self { diff --git a/src/common/di.rs b/src/common/di.rs index ee8bfa70..c3df2cbf 100644 --- a/src/common/di.rs +++ b/src/common/di.rs @@ -456,6 +456,15 @@ impl AppServiceFactory { if let Err(e) = i18n_service.load_translations(Locale::Spanish).await { tracing::warn!("Failed to load Spanish translations: {}", e); } + if let Err(e) = i18n_service.load_translations(Locale::French).await { + tracing::warn!("Failed to load French translations: {}", e); + } + if let Err(e) = i18n_service.load_translations(Locale::German).await { + tracing::warn!("Failed to load German translations: {}", e); + } + if let Err(e) = i18n_service.load_translations(Locale::Portuguese).await { + tracing::warn!("Failed to load Portuguese translations: {}", e); + } tracing::info!("Translations preloaded"); } diff --git a/src/domain/services/i18n_service.rs b/src/domain/services/i18n_service.rs index 6b9a88db..8e79e37d 100644 --- a/src/domain/services/i18n_service.rs +++ b/src/domain/services/i18n_service.rs @@ -22,6 +22,9 @@ pub type I18nResult = Result; pub enum Locale { English, Spanish, + French, + German, + Portuguese, } impl Locale { @@ -30,6 +33,9 @@ impl Locale { match self { Locale::English => "en", Locale::Spanish => "es", + Locale::French => "fr", + Locale::German => "de", + Locale::Portuguese => "pt", } } @@ -38,6 +44,9 @@ impl Locale { match code.to_lowercase().as_str() { "en" => Some(Locale::English), "es" => Some(Locale::Spanish), + "fr" => Some(Locale::French), + "de" => Some(Locale::German), + "pt" => Some(Locale::Portuguese), _ => None, } } diff --git a/src/infrastructure/services/file_system_i18n_service.rs b/src/infrastructure/services/file_system_i18n_service.rs index e70a346e..751123c9 100644 --- a/src/infrastructure/services/file_system_i18n_service.rs +++ b/src/infrastructure/services/file_system_i18n_service.rs @@ -139,7 +139,7 @@ impl I18nService for FileSystemI18nService { } async fn available_locales(&self) -> Vec { - vec![Locale::English, Locale::Spanish] + vec![Locale::English, Locale::Spanish, Locale::French, Locale::German, Locale::Portuguese] } async fn is_supported(&self, locale: Locale) -> bool { diff --git a/static/css/style.css b/static/css/style.css index f8cb08e9..06cd2576 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -621,6 +621,41 @@ select:focus { transform: translateX(18px); } +.user-menu-admin { + color: #1d4ed8; +} + +.user-menu-admin i { + color: #3b82f6; +} + +.user-menu-admin:hover { + background: #eff6ff; +} + +.user-menu-role-badge { + padding: 0 20px 4px; +} + +.role-badge { + display: inline-flex; + align-items: center; + gap: 4px; + font-size: 11px; + font-weight: 600; + padding: 2px 10px; + border-radius: 10px; +} + +.role-badge-admin { + background: #dbeafe; + color: #1d4ed8; +} + +.role-badge i { + font-size: 10px; +} + .user-menu-logout { color: #ef4444; margin-bottom: 4px; diff --git a/static/index.html b/static/index.html index 0ae0e039..47965f97 100644 --- a/static/index.html +++ b/static/index.html @@ -114,6 +114,9 @@
usuario@oxicloud.app
+
@@ -125,6 +128,15 @@
0% usado
+ + + +
+ + `; + + document.body.appendChild(overlay); + // Show with animation + requestAnimationFrame(() => overlay.classList.add('show')); + + // Close handlers + overlay.querySelector('#profile-modal-close').addEventListener('click', () => { + overlay.classList.remove('show'); + setTimeout(() => overlay.remove(), 200); + }); + overlay.addEventListener('click', (e) => { + if (e.target === overlay) { + overlay.classList.remove('show'); + setTimeout(() => overlay.remove(), 200); + } + }); +} + /** * Check if user is authenticated and load user's home folder */ diff --git a/static/js/auth.js b/static/js/auth.js index f97d5d4c..28e2f728 100644 --- a/static/js/auth.js +++ b/static/js/auth.js @@ -74,9 +74,9 @@ const ALL_LANGUAGES = [ { code: 'es', name: 'Spanish', nativeName: 'Español', flag: '🇪🇸', popular: true }, { code: 'zh', name: 'Chinese', nativeName: '中文', flag: '🇨🇳', popular: true }, { code: 'fa', name: 'Persian', nativeName: 'فارسی', flag: '🇮🇷', popular: true }, - { code: 'fr', name: 'French', nativeName: 'Français', flag: '🇫🇷', popular: false }, - { code: 'de', name: 'German', nativeName: 'Deutsch', flag: '🇩🇪', popular: false }, - { code: 'pt', name: 'Portuguese', nativeName: 'Português', flag: '🇧🇷', popular: false }, + { code: 'fr', name: 'French', nativeName: 'Français', flag: '🇫🇷', popular: true }, + { code: 'de', name: 'German', nativeName: 'Deutsch', flag: '🇩🇪', popular: true }, + { code: 'pt', name: 'Portuguese', nativeName: 'Português', flag: '🇧🇷', popular: true }, { code: 'it', name: 'Italian', nativeName: 'Italiano', flag: '🇮🇹', popular: false }, { code: 'ru', name: 'Russian', nativeName: 'Русский', flag: '🇷🇺', popular: false }, { code: 'ja', name: 'Japanese', nativeName: '日本語', flag: '🇯🇵', popular: false }, diff --git a/static/js/i18n.js b/static/js/i18n.js index ac23af8c..0f1ce22f 100644 --- a/static/js/i18n.js +++ b/static/js/i18n.js @@ -13,7 +13,7 @@ let currentLocale = // Supported locales (languages that have locale files on the server) // When a locale file is not found, the system gracefully falls back to English -const supportedLocales = ['en', 'es', 'zh', 'fa']; +const supportedLocales = ['en', 'es', 'zh', 'fa', 'fr', 'de', 'pt']; // Fallback to English if locale is not supported if (!supportedLocales.includes(currentLocale)) { diff --git a/static/js/languageSelector.js b/static/js/languageSelector.js index a7efd777..1c94a503 100644 --- a/static/js/languageSelector.js +++ b/static/js/languageSelector.js @@ -13,7 +13,10 @@ function getAvailableLanguages() { { code: 'en', name: 'English', flag: '🇬🇧' }, { code: 'es', name: 'Español', flag: '🇪🇸' }, { code: 'zh', name: '中文', flag: '🇨🇳' }, - { code: 'fa', name: 'فارسی', flag: '🇮🇷' } + { code: 'fa', name: 'فارسی', flag: '🇮🇷' }, + { code: 'fr', name: 'Français', flag: '🇫🇷' }, + { code: 'de', name: 'Deutsch', flag: '🇩🇪' }, + { code: 'pt', name: 'Português', flag: '🇧🇷' } ]; } diff --git a/static/locales/de.json b/static/locales/de.json index 813692e2..8814b7cb 100644 --- a/static/locales/de.json +++ b/static/locales/de.json @@ -1,332 +1,338 @@ -{ - "app": { - "title": "OxiCloud", - "description": "Minimalistisches System zur Cloud-Datenspeicherung" - }, - "nav": { - "files": "Dateien", - "shared": "Freigegebene Elemente", - "recent": "Zuletzt verwendete Elemente", - "favorites": "Favoriten", - "trash": "Papierkorb" - }, - "actions": { - "search": "Dateien durchsuchen...", - "new_folder": "Neuen Ordner erstellen", - "upload": "Hochladen", - "upload_files": "Dateien hochladen", - "upload_folder": "Ordner hochladen", - "rename": "Umbenennen", - "move": "Verschieben nach...", - "move_to": "Verschieben nach", - "delete": "Löschen", - "download": "Herunterladen", - "view": "Anzeigen", - "cancel": "Abbrechen", - "confirm": "Bestätigen", - "share": "Freigeben", - "favorite": "Zu Favoriten hinzufügen", - "unfavorite": "Aus Favoriten entfernen", - "copy": "Kopieren", - "notify": "Benachrichtigen", - "send": "Senden", - "clear_recent": "Verlauf löschen", - "logout": "Abmelden", - "create": "Erstellen", - "search_btn": "Suchen", - "close": "Schließen", - "delete_permanently": "Endgültig löschen", - "empty_trash": "Papierkorb leeren" - }, - "user_menu": { - "appearance": "Darstellung", - "about": "Über OxiCloud", - "about_description": "Plattform zur Cloud-Datenspeicherung, entwickelt mit Rust und Clean Architecture. Leistungsstark, sicher und datenschutzorientiert." - }, - "share": { - "dialogTitle": "Freigabelink erstellen", - "linkLabel": "Freigabelink:", - "copyLink": "Kopieren", - "permissions": "Berechtigungen:", - "permissionRead": "Leseberechtigung", - "permissionWrite": "Schreibberechtigung", - "permissionReshare": "Weiterfreigabeberechtigung", - "password": "Passwortschutz:", - "generatePassword": "Passwort generieren", - "expiration": "Ablaufdatum:", - "update": "Freigabe aktualisieren", - "remove": "Freigabe entfernen", - "notifyTitle": "Benachrichtigung versenden", - "notifyEmailLabel": "E-Mail-Adresse:", - "notifyMessageLabel": "Nachricht (optional):", - "notifySend": "Benachrichtigung senden", - "shareWithOthers": "Mit weiteren Personen teilen", - "sharePublicly": "Öffentlich freigeben", - "shareSettings": "Freigabeeinstellungen", - "shareCopied": "Der Link wurde in die Zwischenablage kopiert.", - "shareCreated": "Der Freigabelink wurde erfolgreich erstellt.", - "shareUpdated": "Die Freigabeeinstellungen wurden erfolgreich aktualisiert.", - "shareRemoved": "Die Freigabe wurde erfolgreich entfernt." - }, - "share_dialogTitle": "Freigabelink erstellen", - "share_linkLabel": "Freigabelink:", - "share_copyLink": "Kopieren", - "share_permissions": "Berechtigungen:", - "share_permissionRead": "Leseberechtigung", - "share_permissionWrite": "Schreibberechtigung", - "share_permissionReshare": "Weiterfreigabeberechtigung", - "share_password": "Passwortschutz:", - "share_generatePassword": "Passwort generieren", - "share_expiration": "Ablaufdatum:", - "share_update": "Freigabe aktualisieren", - "share_remove": "Freigabe entfernen", - "share_notifyTitle": "Benachrichtigung versenden", - "share_notifyEmailLabel": "E-Mail-Adresse:", - "share_notifyMessageLabel": "Nachricht (optional):", - "share_notifySend": "Benachrichtigung senden", - "shared": { - "backToFiles": "Zurück zur Dateiansicht", - "pageTitle": "Freigegebene Elemente", - "pageDescription": "Verwalten Sie Ihre freigegebenen Dateien und Ordner.", - "filterType": "Typ:", - "filterAll": "Alle", - "filterFiles": "Dateien", - "filterFolders": "Ordner", - "sortBy": "Sortieren nach:", - "sortByName": "Name", - "sortByDate": "Freigabedatum", - "sortByExpiration": "Ablaufdatum", - "search": "Suchen", - "colName": "Name", - "colType": "Typ", - "colDateShared": "Freigabedatum", - "colExpiration": "Ablaufdatum", - "colPermissions": "Berechtigungen", - "colPassword": "Passwortschutz", - "colActions": "Aktionen", - "emptyStateTitle": "Derzeit sind keine freigegebenen Elemente vorhanden.", - "emptyStateDesc": "Freigegebene Dateien und Ordner werden hier angezeigt.", - "goToFiles": "Zur Dateiansicht wechseln", - "typeFile": "Datei", - "typeFolder": "Ordner", - "noExpiration": "Kein Ablaufdatum festgelegt", - "hasPassword": "Ja", - "noPassword": "Nein", - "editShare": "Freigabe bearbeiten", - "notifyShare": "Person benachrichtigen", - "copyLink": "Link kopieren", - "removeShare": "Freigabe entfernen", - "linkCopied": "Der Link wurde in die Zwischenablage kopiert.", - "linkCopyFailed": "Der Link konnte nicht kopiert werden.", - "itemUpdated": "Die Freigabeeinstellungen wurden erfolgreich aktualisiert.", - "itemRemoved": "Die Freigabe wurde erfolgreich entfernt.", - "invalidEmail": "Bitte geben Sie eine gültige E-Mail-Adresse ein.", - "notificationSent": "Die Benachrichtigung wurde erfolgreich versendet.", - "notificationFailed": "Die Benachrichtigung konnte nicht versendet werden.", - "shared_backToFiles": "Zurück zur Dateiansicht", - "shared_pageTitle": "Freigegebene Elemente", - "shared_pageDescription": "Verwalten Sie Ihre freigegebenen Dateien und Ordner.", - "shared_filterType": "Typ:", - "shared_filterAll": "Alle", - "shared_filterFiles": "Dateien", - "shared_filterFolders": "Ordner", - "shared_sortBy": "Sortieren nach:", - "shared_sortByName": "Name", - "shared_sortByDate": "Freigabedatum", - "shared_sortByExpiration": "Ablaufdatum", - "shared_search": "Suchen", - "shared_colName": "Name", - "shared_colType": "Typ", - "shared_colDateShared": "Freigabedatum", - "shared_colExpiration": "Ablaufdatum", - "shared_colPermissions": "Berechtigungen", - "shared_colPassword": "Passwortschutz", - "shared_colActions": "Aktionen", - "shared_emptyStateTitle": "Derzeit sind keine freigegebenen Elemente vorhanden.", - "shared_emptyStateDesc": "Freigegebene Dateien und Ordner werden hier angezeigt.", - "shared_goToFiles": "Zur Dateiansicht wechseln", - "shared_typeFile": "Datei", - "shared_typeFolder": "Ordner", - "shared_noExpiration": "Kein Ablaufdatum festgelegt", - "shared_hasPassword": "Ja", - "shared_noPassword": "Nein", - "shared_editShare": "Freigabe bearbeiten", - "shared_notifyShare": "Person benachrichtigen", - "shared_copyLink": "Link kopieren", - "shared_removeShare": "Freigabe entfernen", - "shared_linkCopied": "Der Link wurde in die Zwischenablage kopiert.", - "shared_linkCopyFailed": "Der Link konnte nicht kopiert werden.", - "shared_itemUpdated": "Die Freigabeeinstellungen wurden erfolgreich aktualisiert.", - "shared_itemRemoved": "Die Freigabe wurde erfolgreich entfernt.", - "shared_invalidEmail": "Bitte geben Sie eine gültige E-Mail-Adresse ein.", - "shared_notificationSent": "Die Benachrichtigung wurde erfolgreich versendet.", - "shared_notificationFailed": "Die Benachrichtigung konnte nicht versendet werden." - }, - "files": { - "name": "Name", - "type": "Typ", - "size": "Größe", - "modified": "Geändert am", - "no_files": "In diesem Ordner sind keine Dateien vorhanden.", - "loading": "Dateien werden geladen …", - "view_grid": "Rasteransicht", - "view_list": "Listenansicht", - "file_types": { - "document": "Dokument", - "image": "Bild", - "video": "Video", - "audio": "Audio", - "pdf": "PDF-Dokument", - "text": "Textdokument", - "folder": "Ordner" - } - }, - "dialogs": { - "rename_folder": "Ordner umbenennen", - "rename_file": "Datei umbenennen", - "new_name": "Neuer Name", - "new_folder_title": "Neuen Ordner erstellen", - "folder_name": "Ordnername", - "folder_placeholder": "Neuer Ordner", - "rename_title": "Umbenennen", - "move_file": "Datei verschieben", - "move_folder": "Ordner verschieben", - "select_destination": "Zielordner auswählen:", - "root": "Hauptverzeichnis", - "delete_confirmation": "Sind Sie sicher, dass Sie dieses Element löschen möchten", - "and_contents": "und alle enthaltenen Elemente", - "no_undo": "Diese Aktion kann nicht rückgängig gemacht werden.", - "confirm_title": "Aktion bestätigen", - "confirm_delete": "In den Papierkorb verschieben", - "confirm_delete_file": "Möchten Sie die Datei \"{{name}}\" in den Papierkorb verschieben?", - "confirm_delete_folder": "Möchten Sie den Ordner \"{{name}}\" und alle enthaltenen Elemente in den Papierkorb verschieben?", - "confirm_permanent_delete": "Endgültig löschen", - "confirm_permanent_delete_msg": "Möchten Sie dieses Element dauerhaft löschen? Diese Aktion kann nicht rückgängig gemacht werden.", - "confirm_empty_trash": "Papierkorb leeren", - "confirm_delete_share": "Freigabelink löschen", - "confirm_delete_share_msg": "Möchten Sie diesen Freigabelink löschen?", - "share_file": "Datei freigeben", - "existing_shares": "Bestehende Freigaben", - "share_options": "Freigabeoptionen", - "password": "Passwort", - "expiration": "Ablaufdatum", - "permissions": "Berechtigungen", - "generated_link": "Generierter Link", - "notify": "Benachrichtigung senden", - "recipient": "Empfänger", - "message": "Nachricht" - }, - "dropzone": { - "drag_files": "Ziehen Sie Dateien hierher oder klicken Sie, um Dateien auszuwählen.", - "drop_files": "Legen Sie Dateien hier ab, um den Upload zu starten." - }, - "permissions": { - "read": "Leseberechtigung", - "write": "Schreibberechtigung", - "reshare": "Weiterfreigabeberechtigung" - }, - "errors": { - "file_not_found": "Die Datei wurde nicht gefunden.", - "folder_not_found": "Der Ordner wurde nicht gefunden.", - "delete_error": "Beim Löschen ist ein Fehler aufgetreten.", - "upload_error": "Beim Hochladen ist ein Fehler aufgetreten.", - "rename_error": "Beim Umbenennen ist ein Fehler aufgetreten.", - "move_error": "Beim Verschieben ist ein Fehler aufgetreten.", - "empty_name": "Der Name darf nicht leer sein.", - "name_exists": "Eine Datei oder ein Ordner mit diesem Namen existiert bereits.", - "generic_error": "Es ist ein unerwarteter Fehler aufgetreten." - }, - "breadcrumb": { - "home": "Startseite" - }, - "trash": { - "empty_trash": "Papierkorb leeren", - "empty_state": "Der Papierkorb ist leer.", - "original_location": "Ursprünglicher Speicherort", - "deleted_date": "Löschdatum", - "actions": "Aktionen", - "restore": "Wiederherstellen", - "delete_permanently": "Endgültig löschen", - "empty_confirm": "Sind Sie sicher, dass Sie den Papierkorb leeren möchten? Alle enthaltenen Elemente werden dauerhaft gelöscht." - }, - "auth": { - "login_title": "Anmelden", - "username": "Benutzername", - "username_placeholder": "Bitte geben Sie Ihren Benutzernamen ein", - "password": "Passwort", - "password_placeholder": "Bitte geben Sie Ihr Passwort ein", - "login_button": "Anmelden", - "no_account": "Verfügen Sie noch über kein Konto?", - "register": "Registrieren", - "admin_setup": "Erstmalige Nutzung?", - "setup": "Administrator einrichten", - "register_title": "Konto erstellen", - "email": "E-Mail-Adresse", - "email_placeholder": "Bitte geben Sie Ihre E-Mail-Adresse ein", - "confirm_password": "Passwort bestätigen", - "confirm_password_placeholder": "Bitte bestätigen Sie Ihr Passwort", - "register_button": "Konto erstellen", - "have_account": "Verfügen Sie bereits über ein Konto?", - "login": "Anmelden", - "setup_title": "Ersteinrichtung", - "setup_step1": "Administrator", - "setup_step2": "Systemkonfiguration", - "setup_step3": "Abschluss", - "admin_username": "Administrator-Benutzername", - "admin_email": "Administrator-E-Mail-Adresse", - "admin_password": "Administrator-Passwort", - "create_admin": "Administrator erstellen", - "back_to_login": "System bereits eingerichtet?", - "admin_success": "Das Administrator-Konto wurde erfolgreich erstellt. Sie können sich nun anmelden.", - "account_success": "Das Konto wurde erfolgreich erstellt. Sie können sich nun anmelden.", - "passwords_mismatch": "Die eingegebenen Passwörter stimmen nicht überein.", - "admin_create_error": "Beim Erstellen des Administrator-Kontos ist ein Fehler aufgetreten." - }, - "storage": { - "title": "Speicher", - "calculating": "Speicherplatz wird berechnet...", - "used": "{{percentage}} % verwendet ({{used}} von {{total}})" - }, - "viewer": { - "unsupported_file": "Für diesen Dateityp ist keine Vorschau verfügbar.", - "download_file": "Datei herunterladen", - "zoom_in": "Vergrößern", - "zoom_out": "Verkleinern", - "zoom_reset": "Zoom zurücksetzen" - }, - "language_selector": { - "title": "Willkommen bei OxiCloud", - "subtitle": "Bitte wählen Sie Ihre Sprache", - "continue": "Fortfahren", - "languages": { - "en": "Englisch", - "es": "Spanisch", - "zh": "Chinesisch", - "fa": "Persisch" - } - }, - "favorites": { - "empty_state": "Derzeit sind keine Favoriten vorhanden.", - "empty_hint": "Markieren Sie Dateien oder Ordner, um sie zu Ihren Favoriten hinzuzufügen.", - "add": "Zu Favoriten hinzufügen", - "remove": "Aus Favoriten entfernen" - }, - "recent": { - "title": "Zuletzt verwendete Elemente", - "clear": "Verlauf löschen", - "accessed": "Geöffnet am", - "empty_state": "Keine zuletzt verwendeten Dateien vorhanden.", - "empty_hint": "Geöffnete Dateien werden hier angezeigt." - }, - "notifications": { - "file_renamed": "Datei wurde umbenannt.", - "file_renamed_to": "Die Datei wurde in \"{{name}}\" umbenannt.", - "folder_renamed": "Ordner wurde umbenannt.", - "folder_renamed_to": "Der Ordner wurde in \"{{name}}\" umbenannt.", - "file_uploaded": "Die Datei wurde erfolgreich hochgeladen.", - "file_deleted": "Die Datei wurde in den Papierkorb verschoben.", - "folder_deleted": "Der Ordner wurde in den Papierkorb verschoben.", - "item_deleted_permanently": "Das Element wurde dauerhaft gelöscht.", - "trash_emptied": "Der Papierkorb wurde erfolgreich geleert." - } -} +{ + "app": { + "title": "OxiCloud", + "description": "Minimalistisches Cloud-Speichersystem" + }, + "nav": { + "files": "Dateien", + "shared": "Geteilt", + "recent": "Zuletzt verwendet", + "favorites": "Favoriten", + "trash": "Papierkorb" + }, + "actions": { + "search": "Dateien suchen...", + "new_folder": "Neuer Ordner", + "upload": "Hochladen", + "upload_files": "Dateien hochladen", + "upload_folder": "Ordner hochladen", + "rename": "Umbenennen", + "move": "Verschieben nach...", + "move_to": "Verschieben nach", + "delete": "Löschen", + "download": "Herunterladen", + "view": "Anzeigen", + "cancel": "Abbrechen", + "confirm": "Bestätigen", + "share": "Teilen", + "favorite": "Zu Favoriten hinzufügen", + "unfavorite": "Aus Favoriten entfernen", + "copy": "Kopieren", + "notify": "Benachrichtigen", + "send": "Senden", + "clear_recent": "Zuletzt verwendete löschen", + "logout": "Abmelden", + "create": "Erstellen", + "search_btn": "Suchen", + "close": "Schließen", + "delete_permanently": "Endgültig löschen", + "empty_trash": "Papierkorb leeren" + }, + "user_menu": { + "appearance": "Erscheinungsbild", + "about": "Über OxiCloud", + "about_description": "Cloud-Speicherplattform mit Rust und Clean Architecture. Schnell, sicher und privat.", + "admin_panel": "Admin-Panel", + "profile": "Mein Profil", + "role_user": "Benutzer" + }, + "share": { + "dialogTitle": "Link teilen", + "linkLabel": "Geteilter Link:", + "copyLink": "Kopieren", + "permissions": "Berechtigungen:", + "permissionRead": "Lesen", + "permissionWrite": "Schreiben", + "permissionReshare": "Weiterteilen", + "password": "Passwortschutz:", + "generatePassword": "Generieren", + "expiration": "Ablaufdatum:", + "update": "Freigabe aktualisieren", + "remove": "Freigabe entfernen", + "notifyTitle": "Benachrichtigung senden", + "notifyEmailLabel": "E-Mail-Adresse:", + "notifyMessageLabel": "Nachricht (optional):", + "notifySend": "Benachrichtigung senden", + "shareWithOthers": "Mit anderen teilen", + "sharePublicly": "Öffentlich teilen", + "shareSettings": "Freigabeeinstellungen", + "shareCopied": "Link in Zwischenablage kopiert", + "shareCreated": "Freigabelink erfolgreich erstellt", + "shareUpdated": "Freigabeeinstellungen aktualisiert", + "shareRemoved": "Freigabe erfolgreich entfernt" + }, + "share_dialogTitle": "Link teilen", + "share_linkLabel": "Geteilter Link:", + "share_copyLink": "Kopieren", + "share_permissions": "Berechtigungen:", + "share_permissionRead": "Lesen", + "share_permissionWrite": "Schreiben", + "share_permissionReshare": "Weiterteilen", + "share_password": "Passwortschutz:", + "share_generatePassword": "Generieren", + "share_expiration": "Ablaufdatum:", + "share_update": "Freigabe aktualisieren", + "share_remove": "Freigabe entfernen", + "share_notifyTitle": "Benachrichtigung senden", + "share_notifyEmailLabel": "E-Mail-Adresse:", + "share_notifyMessageLabel": "Nachricht (optional):", + "share_notifySend": "Benachrichtigung senden", + "shared": { + "backToFiles": "Zurück zu Dateien", + "pageTitle": "Geteilte Ressourcen", + "pageDescription": "Verwalten Sie Ihre geteilten Dateien und Ordner", + "filterType": "Typ:", + "filterAll": "Alle", + "filterFiles": "Dateien", + "filterFolders": "Ordner", + "sortBy": "Sortieren nach:", + "sortByName": "Name", + "sortByDate": "Freigabedatum", + "sortByExpiration": "Ablaufdatum", + "search": "Suchen", + "colName": "Name", + "colType": "Typ", + "colDateShared": "Freigabedatum", + "colExpiration": "Ablaufdatum", + "colPermissions": "Berechtigungen", + "colPassword": "Passwort", + "colActions": "Aktionen", + "emptyStateTitle": "Noch keine geteilten Ressourcen", + "emptyStateDesc": "Wenn Sie Dateien oder Ordner teilen, werden sie hier angezeigt", + "goToFiles": "Zu Dateien gehen", + "typeFile": "Datei", + "typeFolder": "Ordner", + "noExpiration": "Kein Ablaufdatum", + "hasPassword": "Ja", + "noPassword": "Nein", + "editShare": "Freigabe bearbeiten", + "notifyShare": "Jemanden benachrichtigen", + "copyLink": "Link kopieren", + "removeShare": "Freigabe entfernen", + "linkCopied": "Link in Zwischenablage kopiert!", + "linkCopyFailed": "Link konnte nicht kopiert werden", + "itemUpdated": "Freigabeeinstellungen aktualisiert", + "itemRemoved": "Freigabe erfolgreich entfernt", + "invalidEmail": "Bitte geben Sie eine gültige E-Mail-Adresse ein", + "notificationSent": "Benachrichtigung erfolgreich gesendet", + "notificationFailed": "Benachrichtigung konnte nicht gesendet werden" + }, + "shared_backToFiles": "Zurück zu Dateien", + "shared_pageTitle": "Geteilte Ressourcen", + "shared_pageDescription": "Verwalten Sie Ihre geteilten Dateien und Ordner", + "shared_filterType": "Typ:", + "shared_filterAll": "Alle", + "shared_filterFiles": "Dateien", + "shared_filterFolders": "Ordner", + "shared_sortBy": "Sortieren nach:", + "shared_sortByName": "Name", + "shared_sortByDate": "Freigabedatum", + "shared_sortByExpiration": "Ablaufdatum", + "shared_search": "Suchen", + "shared_colName": "Name", + "shared_colType": "Typ", + "shared_colDateShared": "Freigabedatum", + "shared_colExpiration": "Ablaufdatum", + "shared_colPermissions": "Berechtigungen", + "shared_colPassword": "Passwort", + "shared_colActions": "Aktionen", + "shared_emptyStateTitle": "Noch keine geteilten Ressourcen", + "shared_emptyStateDesc": "Wenn Sie Dateien oder Ordner teilen, werden sie hier angezeigt", + "shared_goToFiles": "Zu Dateien gehen", + "shared_typeFile": "Datei", + "shared_typeFolder": "Ordner", + "shared_noExpiration": "Kein Ablaufdatum", + "shared_hasPassword": "Ja", + "shared_noPassword": "Nein", + "shared_editShare": "Freigabe bearbeiten", + "shared_notifyShare": "Jemanden benachrichtigen", + "shared_copyLink": "Link kopieren", + "shared_removeShare": "Freigabe entfernen", + "shared_linkCopied": "Link in Zwischenablage kopiert!", + "shared_linkCopyFailed": "Link konnte nicht kopiert werden", + "shared_itemUpdated": "Freigabeeinstellungen aktualisiert", + "shared_itemRemoved": "Freigabe erfolgreich entfernt", + "shared_invalidEmail": "Bitte geben Sie eine gültige E-Mail-Adresse ein", + "shared_notificationSent": "Benachrichtigung erfolgreich gesendet", + "shared_notificationFailed": "Benachrichtigung konnte nicht gesendet werden", + "files": { + "name": "Name", + "type": "Typ", + "size": "Größe", + "modified": "Geändert", + "no_files": "Keine Dateien in diesem Ordner", + "loading": "Dateien werden geladen…", + "view_grid": "Rasteransicht", + "view_list": "Listenansicht", + "file_types": { + "document": "Dokument", + "image": "Bild", + "video": "Video", + "audio": "Audio", + "pdf": "PDF", + "text": "Text", + "folder": "Ordner" + } + }, + "dialogs": { + "rename_folder": "Ordner umbenennen", + "rename_file": "Datei umbenennen", + "new_name": "Neuer Name", + "new_folder_title": "Neuer Ordner", + "folder_name": "Ordnername", + "folder_placeholder": "Mein Ordner", + "rename_title": "Umbenennen", + "move_file": "Datei verschieben", + "move_folder": "Ordner verschieben", + "select_destination": "Zielordner auswählen:", + "root": "Stammverzeichnis", + "delete_confirmation": "Sind Sie sicher, dass Sie löschen möchten", + "and_contents": "und den gesamten Inhalt", + "no_undo": "Diese Aktion kann nicht rückgängig gemacht werden", + "confirm_title": "Aktion bestätigen", + "confirm_delete": "In Papierkorb verschieben", + "confirm_delete_file": "Sind Sie sicher, dass Sie die Datei \"{{name}}\" in den Papierkorb verschieben möchten?", + "confirm_delete_folder": "Sind Sie sicher, dass Sie den Ordner \"{{name}}\" und seinen gesamten Inhalt in den Papierkorb verschieben möchten?", + "confirm_permanent_delete": "Endgültig löschen", + "confirm_permanent_delete_msg": "Sind Sie sicher, dass Sie dieses Element endgültig löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden.", + "confirm_empty_trash": "Papierkorb leeren", + "confirm_delete_share": "Freigabelink löschen", + "confirm_delete_share_msg": "Sind Sie sicher, dass Sie diesen Freigabelink löschen möchten?", + "share_file": "Datei teilen", + "existing_shares": "Bestehende Freigaben", + "share_options": "Freigabeoptionen", + "password": "Passwort", + "expiration": "Ablaufdatum", + "permissions": "Berechtigungen", + "generated_link": "Generierter Link", + "notify": "Benachrichtigung senden", + "recipient": "Empfänger", + "message": "Nachricht" + }, + "dropzone": { + "drag_files": "Dateien hierher ziehen oder klicken zum Auswählen", + "drop_files": "Dateien zum Hochladen ablegen" + }, + "permissions": { + "read": "Lesen", + "write": "Schreiben", + "reshare": "Weiterteilen" + }, + "errors": { + "file_not_found": "Datei nicht gefunden", + "folder_not_found": "Ordner nicht gefunden", + "delete_error": "Fehler beim Löschen", + "upload_error": "Fehler beim Hochladen", + "rename_error": "Fehler beim Umbenennen", + "move_error": "Fehler beim Verschieben", + "empty_name": "Der Name darf nicht leer sein", + "name_exists": "Eine Datei oder ein Ordner mit diesem Namen existiert bereits", + "generic_error": "Ein Fehler ist aufgetreten" + }, + "breadcrumb": { + "home": "Startseite" + }, + "trash": { + "empty_trash": "Papierkorb leeren", + "empty_state": "Der Papierkorb ist leer", + "original_location": "Ursprünglicher Speicherort", + "deleted_date": "Löschdatum", + "actions": "Aktionen", + "restore": "Wiederherstellen", + "delete_permanently": "Endgültig löschen", + "empty_confirm": "Sind Sie sicher, dass Sie den Papierkorb leeren möchten? Alle Elemente werden endgültig gelöscht." + }, + "auth": { + "login_title": "Anmelden", + "username": "Benutzername", + "username_placeholder": "Geben Sie Ihren Benutzernamen ein", + "password": "Passwort", + "password_placeholder": "Geben Sie Ihr Passwort ein", + "login_button": "Anmelden", + "no_account": "Kein Konto?", + "register": "Registrieren", + "admin_setup": "Erstmalig?", + "setup": "Administrator einrichten", + "register_title": "Konto erstellen", + "email": "E-Mail", + "email_placeholder": "Geben Sie Ihre E-Mail ein", + "confirm_password": "Passwort bestätigen", + "confirm_password_placeholder": "Bestätigen Sie Ihr Passwort", + "register_button": "Konto erstellen", + "have_account": "Bereits ein Konto?", + "login": "Anmelden", + "setup_title": "Ersteinrichtung", + "setup_step1": "Admin", + "setup_step2": "System", + "setup_step3": "Abgeschlossen", + "admin_username": "Admin-Benutzername", + "admin_email": "Admin-E-Mail", + "admin_password": "Admin-Passwort", + "create_admin": "Administrator erstellen", + "back_to_login": "Bereits eingerichtet?", + "admin_success": "Administratorkonto erfolgreich erstellt! Sie können sich jetzt anmelden.", + "account_success": "Konto erfolgreich erstellt! Sie können sich jetzt anmelden.", + "passwords_mismatch": "Die Passwörter stimmen nicht überein", + "admin_create_error": "Fehler beim Erstellen des Administratorkontos" + }, + "storage": { + "title": "Speicher", + "calculating": "Berechnung...", + "used": "{{percentage}}% verwendet ({{used}} / {{total}})" + }, + "viewer": { + "unsupported_file": "Dieser Dateityp kann nicht in der Vorschau angezeigt werden.", + "download_file": "Datei herunterladen", + "zoom_in": "Vergrößern", + "zoom_out": "Verkleinern", + "zoom_reset": "Zoom zurücksetzen" + }, + "language_selector": { + "title": "Willkommen bei OxiCloud", + "subtitle": "Bitte wählen Sie Ihre Sprache", + "continue": "Weiter", + "languages": { + "en": "English", + "es": "Español", + "zh": "中文", + "fa": "فارسی", + "fr": "Français", + "de": "Deutsch", + "pt": "Português" + } + }, + "favorites": { + "empty_state": "Noch keine Favoriten", + "empty_hint": "Markieren Sie Dateien oder Ordner mit einem Stern, um sie zu Ihren Favoriten hinzuzufügen", + "add": "Zu Favoriten hinzufügen", + "remove": "Aus Favoriten entfernen" + }, + "recent": { + "title": "Zuletzt verwendet", + "clear": "Zuletzt verwendete löschen", + "accessed": "Zugegriffen", + "empty_state": "Keine zuletzt verwendeten Dateien", + "empty_hint": "Dateien, die Sie öffnen, werden hier angezeigt" + }, + "notifications": { + "file_renamed": "Datei umbenannt", + "file_renamed_to": "Datei umbenannt in \"{{name}}\"", + "folder_renamed": "Ordner umbenannt", + "folder_renamed_to": "Ordner umbenannt in \"{{name}}\"", + "file_uploaded": "Datei hochgeladen", + "file_deleted": "Datei in Papierkorb verschoben", + "folder_deleted": "Ordner in Papierkorb verschoben", + "item_deleted_permanently": "Element endgültig gelöscht", + "trash_emptied": "Papierkorb erfolgreich geleert" + } +} diff --git a/static/locales/en.json b/static/locales/en.json index ca789e94..4b425316 100644 --- a/static/locales/en.json +++ b/static/locales/en.json @@ -41,7 +41,10 @@ "user_menu": { "appearance": "Appearance", "about": "About OxiCloud", - "about_description": "Cloud storage platform built with Rust & Clean Architecture. Fast, secure, and private." + "about_description": "Cloud storage platform built with Rust & Clean Architecture. Fast, secure, and private.", + "admin_panel": "Admin Panel", + "profile": "My Profile", + "role_user": "User" }, "share": { "dialogTitle": "Share Link", @@ -302,7 +305,10 @@ "en": "English", "es": "Español", "zh": "中文", - "fa": "فارسی" + "fa": "فارسی", + "fr": "Français", + "de": "Deutsch", + "pt": "Português" } }, "favorites": { diff --git a/static/locales/es.json b/static/locales/es.json index bdc90b3b..442b945f 100644 --- a/static/locales/es.json +++ b/static/locales/es.json @@ -160,7 +160,10 @@ "user_menu": { "appearance": "Apariencia", "about": "Acerca de OxiCloud", - "about_description": "Plataforma de almacenamiento en la nube creada con Rust y Arquitectura Limpia. Rápida, segura y privada." + "about_description": "Plataforma de almacenamiento en la nube creada con Rust y Arquitectura Limpia. Rápida, segura y privada.", + "admin_panel": "Panel de administración", + "profile": "Mi perfil", + "role_user": "Usuario" }, "files": { "name": "Nombre", @@ -302,7 +305,10 @@ "en": "English", "es": "Español", "zh": "中文", - "fa": "فارسی" + "fa": "فارسی", + "fr": "Français", + "de": "Deutsch", + "pt": "Português" } }, "favorites": { diff --git a/static/locales/fa.json b/static/locales/fa.json index 3e333a75..9991b97d 100644 --- a/static/locales/fa.json +++ b/static/locales/fa.json @@ -39,7 +39,10 @@ "user_menu": { "appearance": "ظاهر", "about": "درباره OxiCloud", - "about_description": "پلتفرم ذخیره‌سازی ابری ساخته شده با Rust و معماری تمیز. سریع، امن و خصوصی." + "about_description": "پلتفرم ذخیره‌سازی ابری ساخته شده با Rust و معماری تمیز. سریع، امن و خصوصی.", + "admin_panel": "پنل مدیریت", + "profile": "نمایه من", + "role_user": "کاربر" }, "share": { "dialogTitle": "پیوند هم‌رسانی", @@ -288,7 +291,10 @@ "en": "English", "es": "Español", "zh": "中文", - "fa": "فارسی" + "fa": "فارسی", + "fr": "Français", + "de": "Deutsch", + "pt": "Português" } }, "favorites": { diff --git a/static/locales/fr.json b/static/locales/fr.json new file mode 100644 index 00000000..2950866a --- /dev/null +++ b/static/locales/fr.json @@ -0,0 +1,338 @@ +{ + "app": { + "title": "OxiCloud", + "description": "Système de stockage cloud minimaliste" + }, + "nav": { + "files": "Fichiers", + "shared": "Partagés", + "recent": "Récents", + "favorites": "Favoris", + "trash": "Corbeille" + }, + "actions": { + "search": "Rechercher des fichiers...", + "new_folder": "Nouveau dossier", + "upload": "Téléverser", + "upload_files": "Téléverser des fichiers", + "upload_folder": "Téléverser un dossier", + "rename": "Renommer", + "move": "Déplacer vers...", + "move_to": "Déplacer vers", + "delete": "Supprimer", + "download": "Télécharger", + "view": "Afficher", + "cancel": "Annuler", + "confirm": "Confirmer", + "share": "Partager", + "favorite": "Ajouter aux favoris", + "unfavorite": "Retirer des favoris", + "copy": "Copier", + "notify": "Notifier", + "send": "Envoyer", + "clear_recent": "Effacer les récents", + "logout": "Se déconnecter", + "create": "Créer", + "search_btn": "Rechercher", + "close": "Fermer", + "delete_permanently": "Supprimer définitivement", + "empty_trash": "Vider la corbeille" + }, + "user_menu": { + "appearance": "Apparence", + "about": "À propos d'OxiCloud", + "about_description": "Plateforme de stockage cloud construite avec Rust et Architecture Propre. Rapide, sécurisée et privée.", + "admin_panel": "Panneau d'administration", + "profile": "Mon profil", + "role_user": "Utilisateur" + }, + "share": { + "dialogTitle": "Lien de partage", + "linkLabel": "Lien partagé :", + "copyLink": "Copier", + "permissions": "Permissions :", + "permissionRead": "Lecture", + "permissionWrite": "Écriture", + "permissionReshare": "Repartager", + "password": "Protection par mot de passe :", + "generatePassword": "Générer", + "expiration": "Date d'expiration :", + "update": "Mettre à jour le partage", + "remove": "Supprimer le partage", + "notifyTitle": "Envoyer une notification", + "notifyEmailLabel": "Adresse e-mail :", + "notifyMessageLabel": "Message (facultatif) :", + "notifySend": "Envoyer la notification", + "shareWithOthers": "Partager avec d'autres", + "sharePublicly": "Partager publiquement", + "shareSettings": "Paramètres de partage", + "shareCopied": "Lien copié dans le presse-papiers", + "shareCreated": "Lien de partage créé avec succès", + "shareUpdated": "Paramètres de partage mis à jour", + "shareRemoved": "Partage supprimé avec succès" + }, + "share_dialogTitle": "Lien de partage", + "share_linkLabel": "Lien partagé :", + "share_copyLink": "Copier", + "share_permissions": "Permissions :", + "share_permissionRead": "Lecture", + "share_permissionWrite": "Écriture", + "share_permissionReshare": "Repartager", + "share_password": "Protection par mot de passe :", + "share_generatePassword": "Générer", + "share_expiration": "Date d'expiration :", + "share_update": "Mettre à jour le partage", + "share_remove": "Supprimer le partage", + "share_notifyTitle": "Envoyer une notification", + "share_notifyEmailLabel": "Adresse e-mail :", + "share_notifyMessageLabel": "Message (facultatif) :", + "share_notifySend": "Envoyer la notification", + "shared": { + "backToFiles": "Retour aux fichiers", + "pageTitle": "Ressources partagées", + "pageDescription": "Gérez vos fichiers et dossiers partagés", + "filterType": "Type :", + "filterAll": "Tous", + "filterFiles": "Fichiers", + "filterFolders": "Dossiers", + "sortBy": "Trier par :", + "sortByName": "Nom", + "sortByDate": "Date de partage", + "sortByExpiration": "Expiration", + "search": "Rechercher", + "colName": "Nom", + "colType": "Type", + "colDateShared": "Date de partage", + "colExpiration": "Expiration", + "colPermissions": "Permissions", + "colPassword": "Mot de passe", + "colActions": "Actions", + "emptyStateTitle": "Aucune ressource partagée", + "emptyStateDesc": "Lorsque vous partagerez des fichiers ou dossiers, ils apparaîtront ici", + "goToFiles": "Aller aux fichiers", + "typeFile": "Fichier", + "typeFolder": "Dossier", + "noExpiration": "Sans expiration", + "hasPassword": "Oui", + "noPassword": "Non", + "editShare": "Modifier le partage", + "notifyShare": "Notifier quelqu'un", + "copyLink": "Copier le lien", + "removeShare": "Supprimer le partage", + "linkCopied": "Lien copié dans le presse-papiers !", + "linkCopyFailed": "Erreur lors de la copie du lien", + "itemUpdated": "Paramètres de partage mis à jour", + "itemRemoved": "Partage supprimé avec succès", + "invalidEmail": "Veuillez entrer une adresse e-mail valide", + "notificationSent": "Notification envoyée avec succès", + "notificationFailed": "Erreur lors de l'envoi de la notification" + }, + "shared_backToFiles": "Retour aux fichiers", + "shared_pageTitle": "Ressources partagées", + "shared_pageDescription": "Gérez vos fichiers et dossiers partagés", + "shared_filterType": "Type :", + "shared_filterAll": "Tous", + "shared_filterFiles": "Fichiers", + "shared_filterFolders": "Dossiers", + "shared_sortBy": "Trier par :", + "shared_sortByName": "Nom", + "shared_sortByDate": "Date de partage", + "shared_sortByExpiration": "Expiration", + "shared_search": "Rechercher", + "shared_colName": "Nom", + "shared_colType": "Type", + "shared_colDateShared": "Date de partage", + "shared_colExpiration": "Expiration", + "shared_colPermissions": "Permissions", + "shared_colPassword": "Mot de passe", + "shared_colActions": "Actions", + "shared_emptyStateTitle": "Aucune ressource partagée", + "shared_emptyStateDesc": "Lorsque vous partagerez des fichiers ou dossiers, ils apparaîtront ici", + "shared_goToFiles": "Aller aux fichiers", + "shared_typeFile": "Fichier", + "shared_typeFolder": "Dossier", + "shared_noExpiration": "Sans expiration", + "shared_hasPassword": "Oui", + "shared_noPassword": "Non", + "shared_editShare": "Modifier le partage", + "shared_notifyShare": "Notifier quelqu'un", + "shared_copyLink": "Copier le lien", + "shared_removeShare": "Supprimer le partage", + "shared_linkCopied": "Lien copié dans le presse-papiers !", + "shared_linkCopyFailed": "Erreur lors de la copie du lien", + "shared_itemUpdated": "Paramètres de partage mis à jour", + "shared_itemRemoved": "Partage supprimé avec succès", + "shared_invalidEmail": "Veuillez entrer une adresse e-mail valide", + "shared_notificationSent": "Notification envoyée avec succès", + "shared_notificationFailed": "Erreur lors de l'envoi de la notification", + "files": { + "name": "Nom", + "type": "Type", + "size": "Taille", + "modified": "Modifié", + "no_files": "Aucun fichier dans ce dossier", + "loading": "Chargement des fichiers…", + "view_grid": "Vue en grille", + "view_list": "Vue en liste", + "file_types": { + "document": "Document", + "image": "Image", + "video": "Vidéo", + "audio": "Audio", + "pdf": "PDF", + "text": "Texte", + "folder": "Dossier" + } + }, + "dialogs": { + "rename_folder": "Renommer le dossier", + "rename_file": "Renommer le fichier", + "new_name": "Nouveau nom", + "new_folder_title": "Nouveau dossier", + "folder_name": "Nom du dossier", + "folder_placeholder": "Mon dossier", + "rename_title": "Renommer", + "move_file": "Déplacer le fichier", + "move_folder": "Déplacer le dossier", + "select_destination": "Sélectionnez le dossier de destination :", + "root": "Racine", + "delete_confirmation": "Êtes-vous sûr de vouloir supprimer", + "and_contents": "et tout son contenu", + "no_undo": "Cette action est irréversible", + "confirm_title": "Confirmer l'action", + "confirm_delete": "Déplacer vers la corbeille", + "confirm_delete_file": "Êtes-vous sûr de vouloir déplacer le fichier « {{name}} » vers la corbeille ?", + "confirm_delete_folder": "Êtes-vous sûr de vouloir déplacer le dossier « {{name}} » et tout son contenu vers la corbeille ?", + "confirm_permanent_delete": "Supprimer définitivement", + "confirm_permanent_delete_msg": "Êtes-vous sûr de vouloir supprimer définitivement cet élément ? Cette action est irréversible.", + "confirm_empty_trash": "Vider la corbeille", + "confirm_delete_share": "Supprimer le lien de partage", + "confirm_delete_share_msg": "Êtes-vous sûr de vouloir supprimer ce lien de partage ?", + "share_file": "Partager le fichier", + "existing_shares": "Partages existants", + "share_options": "Options de partage", + "password": "Mot de passe", + "expiration": "Expiration", + "permissions": "Permissions", + "generated_link": "Lien généré", + "notify": "Envoyer une notification", + "recipient": "Destinataire", + "message": "Message" + }, + "dropzone": { + "drag_files": "Glissez des fichiers ici ou cliquez pour sélectionner", + "drop_files": "Déposez les fichiers pour téléverser" + }, + "permissions": { + "read": "Lecture", + "write": "Écriture", + "reshare": "Repartager" + }, + "errors": { + "file_not_found": "Fichier introuvable", + "folder_not_found": "Dossier introuvable", + "delete_error": "Erreur lors de la suppression", + "upload_error": "Erreur lors du téléversement", + "rename_error": "Erreur lors du renommage", + "move_error": "Erreur lors du déplacement", + "empty_name": "Le nom ne peut pas être vide", + "name_exists": "Un fichier ou dossier portant ce nom existe déjà", + "generic_error": "Une erreur est survenue" + }, + "breadcrumb": { + "home": "Accueil" + }, + "trash": { + "empty_trash": "Vider la corbeille", + "empty_state": "La corbeille est vide", + "original_location": "Emplacement d'origine", + "deleted_date": "Date de suppression", + "actions": "Actions", + "restore": "Restaurer", + "delete_permanently": "Supprimer définitivement", + "empty_confirm": "Êtes-vous sûr de vouloir vider la corbeille ? Tous les éléments seront définitivement supprimés." + }, + "auth": { + "login_title": "Se connecter", + "username": "Nom d'utilisateur", + "username_placeholder": "Entrez votre nom d'utilisateur", + "password": "Mot de passe", + "password_placeholder": "Entrez votre mot de passe", + "login_button": "Se connecter", + "no_account": "Vous n'avez pas de compte ?", + "register": "S'inscrire", + "admin_setup": "Première fois ?", + "setup": "Configurer l'administrateur", + "register_title": "Créer un compte", + "email": "E-mail", + "email_placeholder": "Entrez votre e-mail", + "confirm_password": "Confirmer le mot de passe", + "confirm_password_placeholder": "Confirmez votre mot de passe", + "register_button": "Créer un compte", + "have_account": "Vous avez déjà un compte ?", + "login": "Se connecter", + "setup_title": "Configuration initiale", + "setup_step1": "Admin", + "setup_step2": "Système", + "setup_step3": "Terminé", + "admin_username": "Nom d'utilisateur administrateur", + "admin_email": "E-mail administrateur", + "admin_password": "Mot de passe administrateur", + "create_admin": "Créer l'administrateur", + "back_to_login": "Déjà configuré ?", + "admin_success": "Compte administrateur créé avec succès ! Vous pouvez maintenant vous connecter.", + "account_success": "Compte créé avec succès ! Vous pouvez maintenant vous connecter.", + "passwords_mismatch": "Les mots de passe ne correspondent pas", + "admin_create_error": "Erreur lors de la création du compte administrateur" + }, + "storage": { + "title": "Stockage", + "calculating": "Calcul en cours...", + "used": "{{percentage}}% utilisé ({{used}} / {{total}})" + }, + "viewer": { + "unsupported_file": "Ce type de fichier ne peut pas être prévisualisé.", + "download_file": "Télécharger le fichier", + "zoom_in": "Zoom avant", + "zoom_out": "Zoom arrière", + "zoom_reset": "Réinitialiser le zoom" + }, + "language_selector": { + "title": "Bienvenue sur OxiCloud", + "subtitle": "Veuillez sélectionner votre langue", + "continue": "Continuer", + "languages": { + "en": "English", + "es": "Español", + "zh": "中文", + "fa": "فارسی", + "fr": "Français", + "de": "Deutsch", + "pt": "Português" + } + }, + "favorites": { + "empty_state": "Aucun favori pour le moment", + "empty_hint": "Marquez des fichiers ou dossiers avec une étoile pour les ajouter à vos favoris", + "add": "Ajouter aux favoris", + "remove": "Retirer des favoris" + }, + "recent": { + "title": "Récents", + "clear": "Effacer les récents", + "accessed": "Consulté", + "empty_state": "Aucun fichier récent", + "empty_hint": "Les fichiers que vous ouvrez apparaîtront ici" + }, + "notifications": { + "file_renamed": "Fichier renommé", + "file_renamed_to": "Fichier renommé en « {{name}} »", + "folder_renamed": "Dossier renommé", + "folder_renamed_to": "Dossier renommé en « {{name}} »", + "file_uploaded": "Fichier téléversé", + "file_deleted": "Fichier déplacé vers la corbeille", + "folder_deleted": "Dossier déplacé vers la corbeille", + "item_deleted_permanently": "Élément supprimé définitivement", + "trash_emptied": "Corbeille vidée avec succès" + } +} diff --git a/static/locales/pt.json b/static/locales/pt.json new file mode 100644 index 00000000..6c3c852f --- /dev/null +++ b/static/locales/pt.json @@ -0,0 +1,338 @@ +{ + "app": { + "title": "OxiCloud", + "description": "Sistema de armazenamento em nuvem minimalista" + }, + "nav": { + "files": "Arquivos", + "shared": "Compartilhados", + "recent": "Recentes", + "favorites": "Favoritos", + "trash": "Lixeira" + }, + "actions": { + "search": "Pesquisar arquivos...", + "new_folder": "Nova pasta", + "upload": "Enviar", + "upload_files": "Enviar arquivos", + "upload_folder": "Enviar pasta", + "rename": "Renomear", + "move": "Mover para...", + "move_to": "Mover para", + "delete": "Excluir", + "download": "Baixar", + "view": "Visualizar", + "cancel": "Cancelar", + "confirm": "Confirmar", + "share": "Compartilhar", + "favorite": "Adicionar aos favoritos", + "unfavorite": "Remover dos favoritos", + "copy": "Copiar", + "notify": "Notificar", + "send": "Enviar", + "clear_recent": "Limpar recentes", + "logout": "Sair", + "create": "Criar", + "search_btn": "Pesquisar", + "close": "Fechar", + "delete_permanently": "Excluir permanentemente", + "empty_trash": "Esvaziar lixeira" + }, + "user_menu": { + "appearance": "Aparência", + "about": "Sobre o OxiCloud", + "about_description": "Plataforma de armazenamento em nuvem construída com Rust e Arquitetura Limpa. Rápida, segura e privada.", + "admin_panel": "Painel de administração", + "profile": "Meu perfil", + "role_user": "Usuário" + }, + "share": { + "dialogTitle": "Link de compartilhamento", + "linkLabel": "Link compartilhado:", + "copyLink": "Copiar", + "permissions": "Permissões:", + "permissionRead": "Leitura", + "permissionWrite": "Escrita", + "permissionReshare": "Recompartilhar", + "password": "Proteção por senha:", + "generatePassword": "Gerar", + "expiration": "Data de expiração:", + "update": "Atualizar compartilhamento", + "remove": "Remover compartilhamento", + "notifyTitle": "Enviar notificação", + "notifyEmailLabel": "Endereço de e-mail:", + "notifyMessageLabel": "Mensagem (opcional):", + "notifySend": "Enviar notificação", + "shareWithOthers": "Compartilhar com outros", + "sharePublicly": "Compartilhar publicamente", + "shareSettings": "Configurações de compartilhamento", + "shareCopied": "Link copiado para a área de transferência", + "shareCreated": "Link de compartilhamento criado com sucesso", + "shareUpdated": "Configurações de compartilhamento atualizadas", + "shareRemoved": "Compartilhamento removido com sucesso" + }, + "share_dialogTitle": "Link de compartilhamento", + "share_linkLabel": "Link compartilhado:", + "share_copyLink": "Copiar", + "share_permissions": "Permissões:", + "share_permissionRead": "Leitura", + "share_permissionWrite": "Escrita", + "share_permissionReshare": "Recompartilhar", + "share_password": "Proteção por senha:", + "share_generatePassword": "Gerar", + "share_expiration": "Data de expiração:", + "share_update": "Atualizar compartilhamento", + "share_remove": "Remover compartilhamento", + "share_notifyTitle": "Enviar notificação", + "share_notifyEmailLabel": "Endereço de e-mail:", + "share_notifyMessageLabel": "Mensagem (opcional):", + "share_notifySend": "Enviar notificação", + "shared": { + "backToFiles": "Voltar aos arquivos", + "pageTitle": "Recursos compartilhados", + "pageDescription": "Gerencie seus arquivos e pastas compartilhados", + "filterType": "Tipo:", + "filterAll": "Todos", + "filterFiles": "Arquivos", + "filterFolders": "Pastas", + "sortBy": "Ordenar por:", + "sortByName": "Nome", + "sortByDate": "Data de compartilhamento", + "sortByExpiration": "Expiração", + "search": "Pesquisar", + "colName": "Nome", + "colType": "Tipo", + "colDateShared": "Data de compartilhamento", + "colExpiration": "Expiração", + "colPermissions": "Permissões", + "colPassword": "Senha", + "colActions": "Ações", + "emptyStateTitle": "Nenhum recurso compartilhado ainda", + "emptyStateDesc": "Quando você compartilhar arquivos ou pastas, eles aparecerão aqui", + "goToFiles": "Ir para arquivos", + "typeFile": "Arquivo", + "typeFolder": "Pasta", + "noExpiration": "Sem expiração", + "hasPassword": "Sim", + "noPassword": "Não", + "editShare": "Editar compartilhamento", + "notifyShare": "Notificar alguém", + "copyLink": "Copiar link", + "removeShare": "Remover compartilhamento", + "linkCopied": "Link copiado para a área de transferência!", + "linkCopyFailed": "Falha ao copiar o link", + "itemUpdated": "Configurações de compartilhamento atualizadas", + "itemRemoved": "Compartilhamento removido com sucesso", + "invalidEmail": "Por favor, insira um endereço de e-mail válido", + "notificationSent": "Notificação enviada com sucesso", + "notificationFailed": "Falha ao enviar a notificação" + }, + "shared_backToFiles": "Voltar aos arquivos", + "shared_pageTitle": "Recursos compartilhados", + "shared_pageDescription": "Gerencie seus arquivos e pastas compartilhados", + "shared_filterType": "Tipo:", + "shared_filterAll": "Todos", + "shared_filterFiles": "Arquivos", + "shared_filterFolders": "Pastas", + "shared_sortBy": "Ordenar por:", + "shared_sortByName": "Nome", + "shared_sortByDate": "Data de compartilhamento", + "shared_sortByExpiration": "Expiração", + "shared_search": "Pesquisar", + "shared_colName": "Nome", + "shared_colType": "Tipo", + "shared_colDateShared": "Data de compartilhamento", + "shared_colExpiration": "Expiração", + "shared_colPermissions": "Permissões", + "shared_colPassword": "Senha", + "shared_colActions": "Ações", + "shared_emptyStateTitle": "Nenhum recurso compartilhado ainda", + "shared_emptyStateDesc": "Quando você compartilhar arquivos ou pastas, eles aparecerão aqui", + "shared_goToFiles": "Ir para arquivos", + "shared_typeFile": "Arquivo", + "shared_typeFolder": "Pasta", + "shared_noExpiration": "Sem expiração", + "shared_hasPassword": "Sim", + "shared_noPassword": "Não", + "shared_editShare": "Editar compartilhamento", + "shared_notifyShare": "Notificar alguém", + "shared_copyLink": "Copiar link", + "shared_removeShare": "Remover compartilhamento", + "shared_linkCopied": "Link copiado para a área de transferência!", + "shared_linkCopyFailed": "Falha ao copiar o link", + "shared_itemUpdated": "Configurações de compartilhamento atualizadas", + "shared_itemRemoved": "Compartilhamento removido com sucesso", + "shared_invalidEmail": "Por favor, insira um endereço de e-mail válido", + "shared_notificationSent": "Notificação enviada com sucesso", + "shared_notificationFailed": "Falha ao enviar a notificação", + "files": { + "name": "Nome", + "type": "Tipo", + "size": "Tamanho", + "modified": "Modificado", + "no_files": "Nenhum arquivo nesta pasta", + "loading": "Carregando arquivos…", + "view_grid": "Visualização em grade", + "view_list": "Visualização em lista", + "file_types": { + "document": "Documento", + "image": "Imagem", + "video": "Vídeo", + "audio": "Áudio", + "pdf": "PDF", + "text": "Texto", + "folder": "Pasta" + } + }, + "dialogs": { + "rename_folder": "Renomear pasta", + "rename_file": "Renomear arquivo", + "new_name": "Novo nome", + "new_folder_title": "Nova pasta", + "folder_name": "Nome da pasta", + "folder_placeholder": "Minha pasta", + "rename_title": "Renomear", + "move_file": "Mover arquivo", + "move_folder": "Mover pasta", + "select_destination": "Selecione a pasta de destino:", + "root": "Raiz", + "delete_confirmation": "Tem certeza de que deseja excluir", + "and_contents": "e todo o seu conteúdo", + "no_undo": "Esta ação não pode ser desfeita", + "confirm_title": "Confirmar ação", + "confirm_delete": "Mover para a lixeira", + "confirm_delete_file": "Tem certeza de que deseja mover o arquivo \"{{name}}\" para a lixeira?", + "confirm_delete_folder": "Tem certeza de que deseja mover a pasta \"{{name}}\" e todo o seu conteúdo para a lixeira?", + "confirm_permanent_delete": "Excluir permanentemente", + "confirm_permanent_delete_msg": "Tem certeza de que deseja excluir permanentemente este item? Esta ação não pode ser desfeita.", + "confirm_empty_trash": "Esvaziar lixeira", + "confirm_delete_share": "Excluir link de compartilhamento", + "confirm_delete_share_msg": "Tem certeza de que deseja excluir este link de compartilhamento?", + "share_file": "Compartilhar arquivo", + "existing_shares": "Compartilhamentos existentes", + "share_options": "Opções de compartilhamento", + "password": "Senha", + "expiration": "Expiração", + "permissions": "Permissões", + "generated_link": "Link gerado", + "notify": "Enviar notificação", + "recipient": "Destinatário", + "message": "Mensagem" + }, + "dropzone": { + "drag_files": "Arraste arquivos aqui ou clique para selecionar", + "drop_files": "Solte os arquivos para enviar" + }, + "permissions": { + "read": "Leitura", + "write": "Escrita", + "reshare": "Recompartilhar" + }, + "errors": { + "file_not_found": "Arquivo não encontrado", + "folder_not_found": "Pasta não encontrada", + "delete_error": "Erro ao excluir", + "upload_error": "Erro ao enviar o arquivo", + "rename_error": "Erro ao renomear", + "move_error": "Erro ao mover", + "empty_name": "O nome não pode estar vazio", + "name_exists": "Já existe um arquivo ou pasta com esse nome", + "generic_error": "Ocorreu um erro" + }, + "breadcrumb": { + "home": "Início" + }, + "trash": { + "empty_trash": "Esvaziar lixeira", + "empty_state": "A lixeira está vazia", + "original_location": "Local original", + "deleted_date": "Data de exclusão", + "actions": "Ações", + "restore": "Restaurar", + "delete_permanently": "Excluir permanentemente", + "empty_confirm": "Tem certeza de que deseja esvaziar a lixeira? Todos os itens serão excluídos permanentemente." + }, + "auth": { + "login_title": "Entrar", + "username": "Usuário", + "username_placeholder": "Digite seu nome de usuário", + "password": "Senha", + "password_placeholder": "Digite sua senha", + "login_button": "Entrar", + "no_account": "Não tem uma conta?", + "register": "Cadastre-se", + "admin_setup": "Primeira vez?", + "setup": "Configurar administrador", + "register_title": "Criar conta", + "email": "E-mail", + "email_placeholder": "Digite seu e-mail", + "confirm_password": "Confirmar senha", + "confirm_password_placeholder": "Confirme sua senha", + "register_button": "Criar conta", + "have_account": "Já tem uma conta?", + "login": "Entrar", + "setup_title": "Configuração inicial", + "setup_step1": "Admin", + "setup_step2": "Sistema", + "setup_step3": "Concluído", + "admin_username": "Usuário administrador", + "admin_email": "E-mail do administrador", + "admin_password": "Senha do administrador", + "create_admin": "Criar administrador", + "back_to_login": "Já configurado?", + "admin_success": "Conta de administrador criada com sucesso! Agora você pode entrar.", + "account_success": "Conta criada com sucesso! Agora você pode entrar.", + "passwords_mismatch": "As senhas não coincidem", + "admin_create_error": "Erro ao criar conta de administrador" + }, + "storage": { + "title": "Armazenamento", + "calculating": "Calculando...", + "used": "{{percentage}}% usado ({{used}} / {{total}})" + }, + "viewer": { + "unsupported_file": "Este tipo de arquivo não pode ser visualizado.", + "download_file": "Baixar arquivo", + "zoom_in": "Ampliar", + "zoom_out": "Reduzir", + "zoom_reset": "Redefinir zoom" + }, + "language_selector": { + "title": "Bem-vindo ao OxiCloud", + "subtitle": "Por favor, selecione seu idioma", + "continue": "Continuar", + "languages": { + "en": "English", + "es": "Español", + "zh": "中文", + "fa": "فارسی", + "fr": "Français", + "de": "Deutsch", + "pt": "Português" + } + }, + "favorites": { + "empty_state": "Nenhum favorito ainda", + "empty_hint": "Marque arquivos ou pastas com estrela para adicioná-los aos seus favoritos", + "add": "Adicionar aos favoritos", + "remove": "Remover dos favoritos" + }, + "recent": { + "title": "Recentes", + "clear": "Limpar recentes", + "accessed": "Acessado", + "empty_state": "Nenhum arquivo recente", + "empty_hint": "Os arquivos que você abrir aparecerão aqui" + }, + "notifications": { + "file_renamed": "Arquivo renomeado", + "file_renamed_to": "Arquivo renomeado para \"{{name}}\"", + "folder_renamed": "Pasta renomeada", + "folder_renamed_to": "Pasta renomeada para \"{{name}}\"", + "file_uploaded": "Arquivo enviado", + "file_deleted": "Arquivo movido para a lixeira", + "folder_deleted": "Pasta movida para a lixeira", + "item_deleted_permanently": "Item excluído permanentemente", + "trash_emptied": "Lixeira esvaziada com sucesso" + } +} diff --git a/static/locales/zh.json b/static/locales/zh.json index 8a0f7caf..860235d1 100644 --- a/static/locales/zh.json +++ b/static/locales/zh.json @@ -39,7 +39,10 @@ "user_menu": { "appearance": "外观", "about": "关于 OxiCloud", - "about_description": "基于 Rust 和整洁架构构建的云存储平台。快速、安全、私密。" + "about_description": "基于 Rust 和整洁架构构建的云存储平台。快速、安全、私密。", + "admin_panel": "管理面板", + "profile": "我的资料", + "role_user": "用户" }, "share": { "dialogTitle": "共享链接", @@ -250,7 +253,10 @@ "en": "English", "es": "Español", "zh": "中文", - "fa": "فارسی" + "fa": "فارسی", + "fr": "Français", + "de": "Deutsch", + "pt": "Português" } }, "favorites": {