From 9d230461de0f330cebbe50ea3b6e1b1edce68ed1 Mon Sep 17 00:00:00 2001 From: MathieuG-P <40181755+Zagrios@users.noreply.github.com> Date: Sat, 20 May 2023 23:21:07 +0200 Subject: [PATCH] [feature-136] add translations --- assets/jsons/translations/de.json | 223 +++++++++++------ assets/jsons/translations/en.json | 223 +++++++++++------ assets/jsons/translations/es.json | 223 +++++++++++------ assets/jsons/translations/fr.json | 227 ++++++++++++------ .../link-button.component.tsx | 4 +- .../maps-playlists-panel.component.tsx | 2 +- .../models/delete-models-modal.component.tsx | 11 +- .../download-models-modal.component.tsx | 46 ++-- .../models/link-models-modal.component.tsx | 10 +- .../models/unlink-models-modal.component.tsx | 8 +- .../model-item.component.tsx | 19 +- .../models-grid.component.tsx | 9 +- .../models-panel.component.tsx | 13 +- .../models-tabs-navbar.component.tsx | 12 +- .../models-downloader.service.ts | 2 +- .../models-manager.service.ts | 16 +- 16 files changed, 692 insertions(+), 356 deletions(-) diff --git a/assets/jsons/translations/de.json b/assets/jsons/translations/de.json index c1559641..edcc9f99 100644 --- a/assets/jsons/translations/de.json +++ b/assets/jsons/translations/de.json @@ -598,8 +598,148 @@ "unlink-folder": "Ordner Verknüpfung Aufheben", "link-all": "Alle verlinken" } + } + }, + "maps": { + "map-filter-panel": { + "duration": "Länge", + "tags": "Stichworte", + "specificities": "Allgemein", + "requirements": "Anforderungen" }, - "models": { + "map-types": { + "accuracy": "Präzision", + "balanced": "Ausgeglichen", + "challenge": "Herausforderung", + "dancestyle": "Tanz", + "fitness": "Fitness", + "speed": "Geschwindigkeit", + "tech": "Tech" + }, + "map-styles": { + "dance": "Tanz", + "swing": "Swing", + "nightcore": "Nightcore", + "folk": "Folk", + "family": "Familie", + "ambient": "umgebung", + "funk": "Funk", + "jazz": "Jazz", + "soul": "Soul", + "speedcore": "Speedcore", + "punk": "Punk", + "rb": "R&B", + "holiday": "Urlaub", + "vocaloid": "Vokaloid", + "jrock": "J-Rock", + "trance": "Trance", + "drumbass": "Basstrommel", + "comedy": "Komödie", + "instrumental": "Instrumental", + "hardcore": "Hardcore", + "kpop": "K-Pop", + "indie": "Indie", + "techno": "Techno", + "house": "House", + "game": "Videospiele", + "film": "Filme", + "alt": "Alternativ", + "dubstep": "Dubstep", + "metal": "Metal", + "anime": "Anime", + "hiphop": "HipHop", + "jpop": "J-Pop", + "rock": "Rock", + "pop": "Pop", + "electronic": "Elektronisch", + "classical-orchestral": "Klassisch & Orchestra" + }, + "map-specificities": { + "automapper": "KI", + "ranked": "ranked", + "curated": "curated", + "verified": "verifiziert", + "fullSpread": "full spread" + }, + "difficulties": { + "Easy": "einfach", + "Normal": "normal", + "Hard": "hard", + "Expert": "expert", + "ExpertPlus": "expert+" + }, + "map-item": { + "by": "Von {songAutor}", + "mapped-by": "Gemapped von" + } + }, + "models":{ + "models": "Modelle", + "types": { + "singular": { + "avatar": "Avatar", + "saber": "Säbel", + "platform": "Plattform", + "bloq": "Block" + }, + "plural": { + "avatar": "Avatare", + "saber": "Säbel", + "platform": "Plattformen", + "bloq": "Blöcke" + } + }, + "sorts": { + "name": "Name", + "date": "Datum", + "author": "Autor" + }, + "panel": { + "actions": { + "search": "Ein Modell suchen", + "drop-down": { + "delete": "Modelle löschen", + "export": "Modelle exportieren" + }, + "link-models": "Modelle verlinken", + "unlink-models": "Modelle trennen" + }, + "grid":{ + "loading": "Modelle laden...", + "no-models": "Keine Modelle", + "download-models": "Modelle herunterladen" + } + }, + "modals": { + "delete-model" :{ + "title": "Das Modell löschen", + "desc": "Sind Sie sicher, dass Sie das Modell {modelName} löschen möchten?", + "linked-annotation": "Dieses Modell wird aus allen verlinkten Versionen entfernt." + }, + "delete-models": { + "title": "Modelle löschen", + "desc": "Sind Sie sicher, dass Sie die {nb} Modelle löschen möchten?", + "linked-annotation": "Diese Modelle werden aus allen verlinkten Versionen entfernt." + }, + "download-models": { + "search-btn": "Suche", + "search-placeholder": "Ein Modell suchen", + "search-tips": { + "header": { + "tag": "Tag", + "desc": "Beschreibung" + }, + "author-desc": "Nur Modelle vom angegebenen Autor anzeigen.", + "hash-desc": "Nur Modelle mit dem angegebenen Hash anzeigen.", + "tag-desc": "Nur Modelle mit dem angegebenen Tag anzeigen.", + "name-desc": "Nur Modelle mit dem angegebenen Namen anzeigen.", + "discordid-desc": "Nur Modelle vom angegebenen Discord-Benutzer anzeigen.", + "status-desc": "Nur Modelle mit dem angegebenen Status anzeigen. (nur Profil, und nur für den Autor)" + }, + "no-models": "Keine Modelle gefunden.", + "no-internet": "Keine Internetverbindung.", + "error-occured": "Ein Fehler ist aufgetreten, versuche es später erneut." + }, "link-models": { "avatar": { "title": "Avatare verbinden", @@ -680,79 +820,16 @@ "valid-btn": "Bloqs trennen" } } - } - }, - "maps": { - "map-filter-panel": { - "duration": "Länge", - "tags": "Stichworte", - "specificities": "Allgemein", - "requirements": "Anforderungen" }, - "map-types": { - "accuracy": "Präzision", - "balanced": "Ausgeglichen", - "challenge": "Herausforderung", - "dancestyle": "Tanz", - "fitness": "Fitness", - "speed": "Geschwindigkeit", - "tech": "Tech" - }, - "map-styles": { - "dance": "Tanz", - "swing": "Swing", - "nightcore": "Nightcore", - "folk": "Folk", - "family": "Familie", - "ambient": "umgebung", - "funk": "Funk", - "jazz": "Jazz", - "soul": "Soul", - "speedcore": "Speedcore", - "punk": "Punk", - "rb": "R&B", - "holiday": "Urlaub", - "vocaloid": "Vokaloid", - "jrock": "J-Rock", - "trance": "Trance", - "drumbass": "Basstrommel", - "comedy": "Komödie", - "instrumental": "Instrumental", - "hardcore": "Hardcore", - "kpop": "K-Pop", - "indie": "Indie", - "techno": "Techno", - "house": "House", - "game": "Videospiele", - "film": "Filme", - "alt": "Alternativ", - "dubstep": "Dubstep", - "metal": "Metal", - "anime": "Anime", - "hiphop": "HipHop", - "jpop": "J-Pop", - "rock": "Rock", - "pop": "Pop", - "electronic": "Elektronisch", - "classical-orchestral": "Klassisch & Orchestra" - }, - "map-specificities": { - "automapper": "KI", - "ranked": "ranked", - "curated": "curated", - "verified": "verifiziert", - "fullSpread": "full spread" - }, - "difficulties": { - "Easy": "einfach", - "Normal": "normal", - "Hard": "hard", - "Expert": "expert", - "ExpertPlus": "expert+" - }, - "map-item": { - "by": "Von {songAutor}", - "mapped-by": "Gemapped von" + "notifications": { + "prevent-for-mods": { + "title": "Erforderliche Mods", + "desc": "Stellen Sie sicher, dass Sie die notwendigen Mods installiert haben, um Modelle in BeatSaber zu verwenden", + "go-to-mods": "Gehe zu Mods" + }, + "export-success": { + "title": "Export abgeschlossen 🎉" + } } }, "beat-saver": { diff --git a/assets/jsons/translations/en.json b/assets/jsons/translations/en.json index f3fda60a..cb82159b 100644 --- a/assets/jsons/translations/en.json +++ b/assets/jsons/translations/en.json @@ -598,8 +598,148 @@ "unlink-folder": "Unlink Folder", "link-all": "Link all" } + } + }, + "maps": { + "map-filter-panel": { + "duration": "Duration", + "tags": "tags", + "specificities": "general", + "requirements": "requirements" }, - "models": { + "map-types": { + "accuracy": "accuracy", + "balanced": "balanced", + "challenge": "challenge", + "dancestyle": "dance", + "fitness": "fitness", + "speed": "speed", + "tech": "tech" + }, + "map-styles": { + "dance": "dance", + "swing": "swing", + "nightcore": "nightcore", + "folk": "folk", + "family": "family", + "ambient": "ambient", + "funk": "funk", + "jazz": "jazz", + "soul": "soul", + "speedcore": "speedcore", + "punk": "punk", + "rb": "r&b", + "holiday": "holiday", + "vocaloid": "vocaloid", + "jrock": "j-rock", + "trance": "trance", + "drumbass": "drum & bass", + "comedy": "comedy", + "instrumental": "instrumental", + "hardcore": "hardcore", + "kpop": "k-pop", + "indie": "indie", + "techno": "techno", + "house": "house", + "game": "video game", + "film": "film", + "alt": "alternative", + "dubstep": "dubstep", + "metal": "metal", + "anime": "anime", + "hiphop": "hiphop", + "jpop": "j-pop", + "rock": "rock", + "pop": "pop", + "electronic": "electronic", + "classical-orchestral": "Classical & Orchestral" + }, + "map-specificities": { + "automapper": "AI", + "ranked": "ranked", + "curated": "curated", + "verified": "verified", + "fullSpread": "full spread" + }, + "difficulties": { + "Easy": "easy", + "Normal": "normal", + "Hard": "hard", + "Expert": "expert", + "ExpertPlus": "expert+" + }, + "map-item": { + "by": "By {songAutor}", + "mapped-by": "mapped by" + } + }, + "models":{ + "models": "Models", + "types": { + "singular": { + "avatar": "avatar", + "saber": "saber", + "platform": "platform", + "bloq": "block" + }, + "plural": { + "avatar": "avatars", + "saber": "sabers", + "platform": "platforms", + "bloq": "blocks" + } + }, + "sorts": { + "name": "Name", + "date": "Date", + "author": "Author" + }, + "panel": { + "actions": { + "search": "Search a model", + "drop-down": { + "delete": "Delete models", + "export": "Export models" + }, + "link-models": "Link models", + "unlink-models": "Unlink models" + }, + "grid":{ + "loading": "Loading models...", + "no-models": "No models", + "download-models": "Download models" + } + }, + "modals": { + "delete-model" :{ + "title": "Delete the model", + "desc": "Are you sure you want to delete the model {modelName}?", + "linked-annotation": "This model will be removed from all linked versions." + }, + "delete-models": { + "title": "Delete models", + "desc": "Are you sure you want to delete the {nb} models?", + "linked-annotation": "These models will be removed from all linked versions." + }, + "download-models": { + "search-btn": "Search", + "search-placeholder": "Search a model", + "search-tips": { + "header": { + "tag": "Tag", + "desc": "Description" + }, + "author-desc": "Show only models from the specified author.", + "hash-desc": "Show only models with the specified hash.", + "tag-desc": "Show only models with the specified tag.", + "name-desc": "Show only models with the specified name.", + "discordid-desc": "Show only models from the specified discord user.", + "status-desc": "Show only models with the specified status. (profile only, and only for the author)" + }, + "no-models": "No models found.", + "no-internet": "No internet connection.", + "error-occured": "An error occurred, try again later." + }, "link-models": { "avatar": { "title": "Link Avatars", @@ -680,79 +820,16 @@ "valid-btn": "Unlink Bloqs" } } - } - }, - "maps": { - "map-filter-panel": { - "duration": "Duration", - "tags": "tags", - "specificities": "general", - "requirements": "requirements" }, - "map-types": { - "accuracy": "accuracy", - "balanced": "balanced", - "challenge": "challenge", - "dancestyle": "dance", - "fitness": "fitness", - "speed": "speed", - "tech": "tech" - }, - "map-styles": { - "dance": "dance", - "swing": "swing", - "nightcore": "nightcore", - "folk": "folk", - "family": "family", - "ambient": "ambient", - "funk": "funk", - "jazz": "jazz", - "soul": "soul", - "speedcore": "speedcore", - "punk": "punk", - "rb": "r&b", - "holiday": "holiday", - "vocaloid": "vocaloid", - "jrock": "j-rock", - "trance": "trance", - "drumbass": "drum & bass", - "comedy": "comedy", - "instrumental": "instrumental", - "hardcore": "hardcore", - "kpop": "k-pop", - "indie": "indie", - "techno": "techno", - "house": "house", - "game": "video game", - "film": "film", - "alt": "alternative", - "dubstep": "dubstep", - "metal": "metal", - "anime": "anime", - "hiphop": "hiphop", - "jpop": "j-pop", - "rock": "rock", - "pop": "pop", - "electronic": "electronic", - "classical-orchestral": "Classical & Orchestral" - }, - "map-specificities": { - "automapper": "AI", - "ranked": "ranked", - "curated": "curated", - "verified": "verified", - "fullSpread": "full spread" - }, - "difficulties": { - "Easy": "easy", - "Normal": "normal", - "Hard": "hard", - "Expert": "expert", - "ExpertPlus": "expert+" - }, - "map-item": { - "by": "By {songAutor}", - "mapped-by": "mapped by" + "notifications": { + "prevent-for-mods": { + "title": "Required mods", + "desc": "Make sure you've installed the necessary mods to use models in BeatSaber", + "go-to-mods": "Go to mods" + }, + "export-success": { + "title": "Export completed 🎉" + } } }, "beat-saver": { diff --git a/assets/jsons/translations/es.json b/assets/jsons/translations/es.json index b2edb914..2ddd9a5b 100644 --- a/assets/jsons/translations/es.json +++ b/assets/jsons/translations/es.json @@ -597,8 +597,148 @@ "unlink-folder": "Desenlazar Carpeta", "link-all": "Enlazar todo" } + } + }, + "maps": { + "map-filter-panel": { + "duration": "Duración", + "tags": "tags", + "specificities": "general", + "requirements": "requisitos" }, - "models": { + "map-types": { + "accuracy": "precisión", + "balanced": "equilibrado", + "challenge": "desafío", + "dancestyle": "baile", + "fitness": "fitness", + "speed": "speed", + "tech": "tec" + }, + "map-styles": { + "dance": "baile", + "swing": "swing", + "nightcore": "nightcore", + "folk": "folk", + "family": "familia", + "ambient": "ambiente", + "funk": "funk", + "jazz": "jazz", + "soul": "soul", + "speedcore": "speedcore", + "punk": "punk", + "rb": "r&b", + "holiday": "vacaciones", + "vocaloid": "vocaloid", + "jrock": "j-rock", + "trance": "trance", + "drumbass": "drum & bass", + "comedy": "comedia", + "instrumental": "instrumental", + "hardcore": "hardcore", + "kpop": "k-pop", + "indie": "indie", + "techno": "tecno", + "house": "house", + "game": "videojuego", + "film": "film", + "alt": "alternativa", + "dubstep": "dubstep", + "metal": "metal", + "anime": "anime", + "hiphop": "hiphop", + "jpop": "j-pop", + "rock": "rock", + "pop": "pop", + "electronic": "electrónico", + "classical-orchestral": "Clásico y orquestal" + }, + "map-specificities": { + "automapper": "IA", + "ranked": "rankado", + "curated": "recomendado", + "verified": "verificado", + "fullSpread": "panel completo" + }, + "difficulties": { + "Easy": "fácil", + "Normal": "normal", + "Hard": "difícil", + "Expert": "experto", + "ExpertPlus": "experto+" + }, + "map-item": { + "by": "Por {songAutor}", + "mapped-by": "mapeado por" + } + }, + "models":{ + "models": "Modelos", + "types": { + "singular": { + "avatar": "avatar", + "saber": "sable", + "platform": "plataforma", + "bloq": "bloque" + }, + "plural": { + "avatar": "avatares", + "saber": "sables", + "platform": "plataformas", + "bloq": "bloques" + } + }, + "sorts": { + "name": "Nombre", + "date": "Fecha", + "author": "Autor" + }, + "panel": { + "actions": { + "search": "Buscar un modelo", + "drop-down": { + "delete": "Eliminar modelos", + "export": "Exportar modelos" + }, + "link-models": "Vincular modelos", + "unlink-models": "Desvincular los modelos" + }, + "grid":{ + "loading": "Cargando modelos...", + "no-models": "No hay modelos", + "download-models": "Descargar modelos" + } + }, + "modals": { + "delete-model" :{ + "title": "Eliminar el modelo", + "desc": "¿Estás seguro de que quieres eliminar el modelo {modelName}?", + "linked-annotation": "Este modelo será eliminado de todas las versiones vinculadas." + }, + "delete-models": { + "title": "Eliminar modelos", + "desc": "¿Estás seguro de que quieres eliminar los {nb} modelos?", + "linked-annotation": "Estos modelos serán eliminados de todas las versiones vinculadas." + }, + "download-models": { + "search-btn": "Buscar", + "search-placeholder": "Buscar un modelo", + "search-tips": { + "header": { + "tag": "Etiqueta", + "desc": "Descripción" + }, + "author-desc": "Mostrar solo modelos del autor especificado.", + "hash-desc": "Mostrar solo modelos con el hash especificado.", + "tag-desc": "Mostrar solo modelos con la etiqueta especificada.", + "name-desc": "Mostrar solo modelos con el nombre especificado.", + "discordid-desc": "Mostrar solo modelos del usuario de discord especificado.", + "status-desc": "Mostrar solo modelos con el estado especificado. (solo perfil, y solo para el autor)" + }, + "no-models": "No se encontraron modelos.", + "no-internet": "Sin conexión a Internet.", + "error-occured": "Ocurrió un error, inténtalo de nuevo más tarde." + }, "link-models": { "avatar": { "title": "Vincular avatares", @@ -679,79 +819,16 @@ "valid-btn": "Desvincular bloqs" } } - } - }, - "maps": { - "map-filter-panel": { - "duration": "Duración", - "tags": "tags", - "specificities": "general", - "requirements": "requisitos" }, - "map-types": { - "accuracy": "precisión", - "balanced": "equilibrado", - "challenge": "desafío", - "dancestyle": "baile", - "fitness": "fitness", - "speed": "speed", - "tech": "tec" - }, - "map-styles": { - "dance": "baile", - "swing": "swing", - "nightcore": "nightcore", - "folk": "folk", - "family": "familia", - "ambient": "ambiente", - "funk": "funk", - "jazz": "jazz", - "soul": "soul", - "speedcore": "speedcore", - "punk": "punk", - "rb": "r&b", - "holiday": "vacaciones", - "vocaloid": "vocaloid", - "jrock": "j-rock", - "trance": "trance", - "drumbass": "drum & bass", - "comedy": "comedia", - "instrumental": "instrumental", - "hardcore": "hardcore", - "kpop": "k-pop", - "indie": "indie", - "techno": "tecno", - "house": "house", - "game": "videojuego", - "film": "film", - "alt": "alternativa", - "dubstep": "dubstep", - "metal": "metal", - "anime": "anime", - "hiphop": "hiphop", - "jpop": "j-pop", - "rock": "rock", - "pop": "pop", - "electronic": "electrónico", - "classical-orchestral": "Clásico y orquestal" - }, - "map-specificities": { - "automapper": "IA", - "ranked": "rankado", - "curated": "recomendado", - "verified": "verificado", - "fullSpread": "panel completo" - }, - "difficulties": { - "Easy": "fácil", - "Normal": "normal", - "Hard": "difícil", - "Expert": "experto", - "ExpertPlus": "experto+" - }, - "map-item": { - "by": "Por {songAutor}", - "mapped-by": "mapeado por" + "notifications": { + "prevent-for-mods": { + "title": "Mods necesarios", + "desc": "Asegúrate de haber instalado los mods necesarios para usar modelos en BeatSaber", + "go-to-mods": "Ir a mods" + }, + "export-success": { + "title": "Exportación completada 🎉" + } } }, "beat-saver": { diff --git a/assets/jsons/translations/fr.json b/assets/jsons/translations/fr.json index 82a9777a..f94fd63e 100644 --- a/assets/jsons/translations/fr.json +++ b/assets/jsons/translations/fr.json @@ -12,7 +12,9 @@ "delete": "Supprimer", "accept": "Accepter", "refuse": "Refuser", - "apply": "Appliquer" + "apply": "Appliquer", + "copy": "Copier", + "copied": "Copié !" }, "nav-bar":{ "add-version": "Ajouter une version", @@ -597,8 +599,148 @@ "unlink-folder": "Délier le dossier", "link-all": "Tout lier" } + } + }, + "maps": { + "map-filter-panel": { + "duration": "Durée", + "tags": "tags", + "specificities": "général", + "requirements": "requis" }, - "models": { + "map-types": { + "accuracy": "précision", + "balanced": "équilibrée", + "challenge": "challenge", + "dancestyle": "dance", + "fitness": "fitness", + "speed": "vitesse", + "tech": "tech" + }, + "map-styles": { + "dance": "dance", + "swing": "swing", + "nightcore": "nightcore", + "folk": "folk", + "family": "famille", + "ambient": "ambiante", + "funk": "funk", + "jazz": "jazz", + "soul": "soul", + "speedcore": "speedcore", + "punk": "punk", + "rb": "r&b", + "holiday": "vacance", + "vocaloid": "vocaloid", + "jrock": "j-rock", + "trance": "trance", + "drumbass": "drum & bass", + "comedy": "comédie", + "instrumental": "instrumental", + "hardcore": "hardcore", + "kpop": "k-pop", + "indie": "indé", + "techno": "techno", + "house": "house", + "game": "jeu vidéo", + "film": "film", + "alt": "alternative", + "dubstep": "dubstep", + "metal": "metal", + "anime": "anime", + "hiphop": "hiphop", + "jpop": "j-pop", + "rock": "rock", + "pop": "pop", + "electronic": "éléctronique", + "classical-orchestral": "Classique & Orchestral" + }, + "map-specificities": { + "automapper": "IA", + "ranked": "classée", + "curated": "recommandée", + "verified": "vérifiée", + "fullSpread": "panel complet" + }, + "difficulties": { + "Easy": "facile", + "Normal": "normal", + "Hard": "difficile", + "Expert": "expert", + "ExpertPlus": "expert+" + }, + "map-item": { + "by": "Par {songAutor}", + "mapped-by": "mappée par" + } + }, + "models":{ + "models": "Modèles", + "types": { + "singular": { + "avatar": "avatar", + "saber": "sabre", + "platform": "plateforme", + "bloq": "bloc" + }, + "plural": { + "avatar": "avatars", + "saber": "sabres", + "platform": "plateformes", + "bloq": "blocs" + } + }, + "sorts": { + "name": "nom", + "date": "date", + "author": "auteur" + }, + "panel": { + "actions": { + "search": "Rechercher un modèle", + "drop-down": { + "delete": "Supprimer les modèles", + "export": "Exporter les modèles" + }, + "link-models": "Lier les modèles", + "unlink-models": "Délier les modèles" + }, + "grid":{ + "loading": "Chargement des modèles...", + "no-models": "Aucun modèle", + "download-models": "Télécharger des modèles" + } + }, + "modals": { + "delete-model" :{ + "title": "Supprimer le modèle", + "desc": "Est-tu sûr de vouloir supprimer le modèle {modelName} ?", + "linked-annotation": "Ce modèle sera supprimé de toutes les versions liées." + }, + "delete-models": { + "title": "Supprimer les modèles", + "desc": "Est-tu sûr de vouloir supprimer les {nb} modèles ?", + "linked-annotation": "Ces modèles seront supprimés de toutes les versions liées." + }, + "download-models": { + "search-btn": "Rechercher", + "search-placeholder": "Rechercher un modèle", + "search-tips": { + "header": { + "tag": "Tag", + "desc": "Description" + }, + "author-desc": "Afficher seulement les modèles de l'auteur spécifié.", + "hash-desc": "Afficher seulement les modèles avec le hash spécifié.", + "tag-desc": "Afficher seulement les modèles avec le tag spécifié.", + "name-desc": "Afficher seulement les modèles avec le nom spécifié.", + "discordid-desc": "Afficher seulement les modèles de l'utilisateur discord spécifié.", + "status-desc": "Afficher seulement les modèles avec le status spécifié. (profil seulement, et seulement pour l'auteur)" + }, + "no-models": "Aucun modèles trouvés.", + "no-internet": "Pas de connexion internet.", + "error-occured": "Une erreur est survenue, réessaye plus tard." + }, "link-models":{ "avatar": { "title": "Lier les avatars", @@ -679,79 +821,16 @@ "valid-btn": "Délier les bloqs" } } - } - }, - "maps": { - "map-filter-panel": { - "duration": "Durée", - "tags": "tags", - "specificities": "général", - "requirements": "requis" }, - "map-types": { - "accuracy": "précision", - "balanced": "équilibrée", - "challenge": "challenge", - "dancestyle": "dance", - "fitness": "fitness", - "speed": "vitesse", - "tech": "tech" - }, - "map-styles": { - "dance": "dance", - "swing": "swing", - "nightcore": "nightcore", - "folk": "folk", - "family": "famille", - "ambient": "ambiante", - "funk": "funk", - "jazz": "jazz", - "soul": "soul", - "speedcore": "speedcore", - "punk": "punk", - "rb": "r&b", - "holiday": "vacance", - "vocaloid": "vocaloid", - "jrock": "j-rock", - "trance": "trance", - "drumbass": "drum & bass", - "comedy": "comédie", - "instrumental": "instrumental", - "hardcore": "hardcore", - "kpop": "k-pop", - "indie": "indé", - "techno": "techno", - "house": "house", - "game": "jeu vidéo", - "film": "film", - "alt": "alternative", - "dubstep": "dubstep", - "metal": "metal", - "anime": "anime", - "hiphop": "hiphop", - "jpop": "j-pop", - "rock": "rock", - "pop": "pop", - "electronic": "éléctronique", - "classical-orchestral": "Classique & Orchestral" - }, - "map-specificities": { - "automapper": "IA", - "ranked": "classée", - "curated": "recommandée", - "verified": "vérifiée", - "fullSpread": "panel complet" - }, - "difficulties": { - "Easy": "facile", - "Normal": "normal", - "Hard": "difficile", - "Expert": "expert", - "ExpertPlus": "expert+" - }, - "map-item": { - "by": "Par {songAutor}", - "mapped-by": "mappée par" + "notifications": { + "prevent-for-mods": { + "title": "Mods nécessaires", + "desc": "Assurez-toi d'avoir installé les mods nécessaires pour utiliser des modèles dans BeatSaber", + "go-to-mods": "Aller aux mods" + }, + "export-success": { + "title": "Export terminé 🎉" + } } }, "beat-saver": { diff --git a/src/renderer/components/maps-mangement-components/link-button.component.tsx b/src/renderer/components/maps-mangement-components/link-button.component.tsx index 0b84c594..57148639 100644 --- a/src/renderer/components/maps-mangement-components/link-button.component.tsx +++ b/src/renderer/components/maps-mangement-components/link-button.component.tsx @@ -2,6 +2,7 @@ import { motion } from "framer-motion" import { forwardRef } from "react" import { useThemeColor } from "renderer/hooks/use-theme-color.hook" import { BsmIcon } from "../svgs/bsm-icon.component" +import { useTranslation } from "renderer/hooks/use-translation.hook" type Props = { className?: string, @@ -13,6 +14,7 @@ type Props = { export const LinkButton = motion(forwardRef((props: Props, ref) => { + const t = useTranslation() const color = useThemeColor("first-color"); const linkedColor = (() => { @@ -22,7 +24,7 @@ export const LinkButton = motion(forwardRef((props: Props, ref) => { })() return ( -
{e.preventDefault(); !props.disabled && props.onClick?.()}} style={{pointerEvents: props.disabled ? "none" : "auto"}}> +
{e.preventDefault(); !props.disabled && props.onClick?.()}} style={{pointerEvents: props.disabled ? "none" : "auto"}}>
diff --git a/src/renderer/components/maps-mangement-components/maps-playlists-panel.component.tsx b/src/renderer/components/maps-mangement-components/maps-playlists-panel.component.tsx index 5124c5ff..21d802b4 100644 --- a/src/renderer/components/maps-mangement-components/maps-playlists-panel.component.tsx +++ b/src/renderer/components/maps-mangement-components/maps-playlists-panel.component.tsx @@ -120,7 +120,7 @@ export function MapsPlaylistsPanel({version}: Props) { initial={{rotate: 0}} className="block p-0.5 h-[calc(100%-5px)] aspect-square blur-0 hover:brightness-75" linked={mapsLinked} - title={t(mapsLinked ? "pages.version-viewer.maps.tabs.maps.actions.link-maps.tooltips.unlink" : "pages.version-viewer.maps.tabs.maps.actions.link-maps.tooltips.link")} + title={mapsLinked ? "pages.version-viewer.maps.tabs.maps.actions.link-maps.tooltips.unlink" : "pages.version-viewer.maps.tabs.maps.actions.link-maps.tooltips.link"} onClick={() => onClickLink(index)} /> )} diff --git a/src/renderer/components/modal/modal-types/models/delete-models-modal.component.tsx b/src/renderer/components/modal/modal-types/models/delete-models-modal.component.tsx index d1c87772..76149ad9 100644 --- a/src/renderer/components/modal/modal-types/models/delete-models-modal.component.tsx +++ b/src/renderer/components/modal/modal-types/models/delete-models-modal.component.tsx @@ -23,13 +23,16 @@ export const DeleteModelsModal: ModalComponent 1; + const title = useConstant(() => isMultiple ? t("models.modals.delete-models.title") : t("models.modals.delete-model.title")); + const desc = useConstant(() => isMultiple ? t("models.modals.delete-models.desc", {nb: `${data.models.length}`}) : t("models.modals.delete-model.desc", {modelName: data.models[0].model?.name ?? data.models[0].fileName})); + const linkedAnnotation = useConstant(() => data.linked ? (isMultiple ? t("models.modals.delete-models.linked-annotation") : t("models.modals.delete-model.linked-annotation")) : undefined); + return ( - // TODO TRANSLATIONS
-

{isMultiple ? "Supprimer les modèles" : "Supprimer le modèle"}

+

{title}

-

{isMultiple ? `Es-tu sur de vouloir supprimer les ${data.models.length} modèles ?` : `Es-tu sur de vouloir supprimer le modèle ${data.models[0].model?.name ?? data.models[0].fileName}`}

- {data.linked &&

{isMultiple ? "Ces modèles seront égalements supprimées des versions utilisant les maps partagées" : "Ce modèle sera également supprimée des versions utilisant les maps partagées"}

} +

{desc}

+ {data.linked &&

{linkedAnnotation}

} {!isMultiple && (
setRemember(val)}/> diff --git a/src/renderer/components/modal/modal-types/models/download-models-modal.component.tsx b/src/renderer/components/modal/modal-types/models/download-models-modal.component.tsx index 8b1c759c..8cb29b81 100644 --- a/src/renderer/components/modal/modal-types/models/download-models-modal.component.tsx +++ b/src/renderer/components/modal/modal-types/models/download-models-modal.component.tsx @@ -29,17 +29,18 @@ export const DownloadModelsModal: ModalComponent[]>(() => MODEL_TYPES.map(type => ({ - text: type.toString(), // TODO TRANSLATE + text: `models.types.plural.${type}`, value: type }))); const querySortsOptions = useConstant[]>(() => MS_GET_QUERY_SORTS.map(sort => ({ - text: sort.toString(), // TODO TRANSLATE + text: `models.sorts.${sort}`, value: sort }))); - const t = useTranslation(); const currentDownload = useObservable(modelsDownloader.currentDownload$(), null); const downloadQueue = useObservable(modelsDownloader.getQueue$(), []); const [msModels, msModels$] = useBehaviorSubject([]); @@ -127,43 +128,50 @@ export const DownloadModelsModal: ModalComponent owned.hash === model.hash); } - const filterTipsHTML = useConstant(() => ( + const renderFilterTips = useConstant(() => (
- - - - - - - + + + + + + +
TagDescription
author:Only show models by the specified author.
hash:Only show models with the specified hash.
tag:Only show models with the specified tag.
name:Only show models with the specified name.
discordid:Only show models by the user with the specified discordid.
status:Only show models with the specified approval status. (profile only, and only for the author)
{t("models.modals.download-models.search-tips.header.tag")}{t("models.modals.download-models.search-tips.header.desc")}
author:{t("models.modals.download-models.search-tips.author-desc")}
tag:{t("models.modals.download-models.search-tips.tag-desc")}
hash:{t("models.modals.download-models.search-tips.hash-desc")}
name:{t("models.modals.download-models.search-tips.name-desc")}
discordid:{t("models.modals.download-models.search-tips.discordid-desc")}
status:{t("models.modals.download-models.search-tips.status-desc")}
- )) + )); + + const renderLoadingStatus = () => { + if(isLoading) { return {t("models.panel.grid.loading")} } + if(isOnline) { return {t("models.modals.download-models.no-models")} } + if(!isOnline) { return {t("models.modals.download-models.no-internet")} } + return {t("models.modals.download-models.error-occured")} + } return ( {e.preventDefault(); search()}}>
- currentType$.next(value)}/> + currentType$.next(value)}/>
- searhInput$.next(e.target.value)}/> - + searhInput$.next(e.target.value)}/> +
- {e.preventDefault(); search()}}/> - currentSort$.next(value)}/> + {e.preventDefault(); search()}}/> + currentSort$.next(value)}/>
    {msModels.length === 0 ? (
    -  - {t(isLoading ? "Chargement des modèles" : isOnline ? "Aucun modèles trouvés" : "Pas d'internet")} {/** TODO TRANSLATE **/} +  + {renderLoadingStatus()}
    ) : ( <> diff --git a/src/renderer/components/modal/modal-types/models/link-models-modal.component.tsx b/src/renderer/components/modal/modal-types/models/link-models-modal.component.tsx index 727a14ee..dc0e2dff 100644 --- a/src/renderer/components/modal/modal-types/models/link-models-modal.component.tsx +++ b/src/renderer/components/modal/modal-types/models/link-models-modal.component.tsx @@ -15,17 +15,17 @@ export const LinkModelsModal: ModalComponent = ({resolver, return ( -

    {t(`modals.models.link-models.${data}.title`)}

    +

    {t(`models.modals.link-models.${data}.title`)}

    -

    {t(`modals.models.link-models.${data}.desc`)}

    -

    {t(`modals.models.link-models.${data}.info`)}

    +

    {t(`models.modals.link-models.${data}.desc`)}

    +

    {t(`models.modals.link-models.${data}.info`)}

    - {t(`modals.models.link-models.${data}.keep-models.label`)} + {t(`models.modals.link-models.${data}.keep-models.label`)}
    resolver({exitCode: ModalExitCode.CANCELED})} withBar={false} text="misc.cancel"/> - resolver({exitCode: ModalExitCode.COMPLETED, data: keepMaps})} withBar={false} text={`modals.models.link-models.${data}.valid-btn`}/> + resolver({exitCode: ModalExitCode.COMPLETED, data: keepMaps})} withBar={false} text={`models.modals.link-models.${data}.valid-btn`}/>
    ) diff --git a/src/renderer/components/modal/modal-types/models/unlink-models-modal.component.tsx b/src/renderer/components/modal/modal-types/models/unlink-models-modal.component.tsx index 0a7d1d75..dc1ce821 100644 --- a/src/renderer/components/modal/modal-types/models/unlink-models-modal.component.tsx +++ b/src/renderer/components/modal/modal-types/models/unlink-models-modal.component.tsx @@ -14,16 +14,16 @@ export const UnlinkModelsModal: ModalComponent = ({resolve return (
    -

    {t(`modals.models.unlink-models.${data}.title`)}

    +

    {t(`models.modals.unlink-models.${data}.title`)}

    -

    {t(`modals.models.unlink-models.${data}.desc`)}

    +

    {t(`models.modals.unlink-models.${data}.desc`)}

    - {t(`modals.models.unlink-models.${data}.keep-models.label`)} + {t(`models.modals.unlink-models.${data}.keep-models.label`)}
    resolver({exitCode: ModalExitCode.CANCELED})} withBar={false} text="misc.cancel"/> - resolver({exitCode: ModalExitCode.COMPLETED, data: keepMaps})} withBar={false} text={`modals.models.unlink-models.${data}.valid-btn`}/> + resolver({exitCode: ModalExitCode.COMPLETED, data: keepMaps})} withBar={false} text={`models.modals.unlink-models.${data}.valid-btn`}/>
    ) diff --git a/src/renderer/components/models-management/model-item.component.tsx b/src/renderer/components/models-management/model-item.component.tsx index c1932b5e..89e39d17 100644 --- a/src/renderer/components/models-management/model-item.component.tsx +++ b/src/renderer/components/models-management/model-item.component.tsx @@ -15,6 +15,7 @@ import { BsmIconType } from "../svgs/bsm-icon.component"; import { BsmButton } from "../shared/bsm-button.component"; import { BsmBasicSpinner } from "../shared/bsm-basic-spinner/bsm-basic-spinner.component"; import { isValidUrl } from "shared/helpers/url.helpers"; +import { useTranslation } from "renderer/hooks/use-translation.hook"; type Props = { selected?: boolean, @@ -29,6 +30,7 @@ type Props = { function modelItem(props: Props) { + const t = useTranslation(); const color = useThemeColor("first-color"); const [hovered, setHovered] = useState(false); const [idContentCopied, setIdContentCopied] = useState(null); @@ -59,19 +61,19 @@ function modelItem(props: Props) { return [...new Set(props.tags)]; })(); - const actionButtons = (): {text: string, icon: BsmIconType, action: () => void, iconColor?: string}[] => { - const buttons: {text: string, icon: BsmIconType, action: () => void, iconColor?: string}[] = []; + const actionButtons = (): {icon: BsmIconType, action: () => void, iconColor?: string}[] => { + const buttons: {icon: BsmIconType, action: () => void, iconColor?: string}[] = []; if(props.onDownload && !props.onCancelDownload){ - buttons.push({ text: "Download", icon: "download", action: () => props.onDownload(props.callbackValue) }); // TODO TRANSLATE + buttons.push({ icon: "download", action: () => props.onDownload(props.callbackValue) }); } if(props.onDelete){ - buttons.push({ text: "Delete", icon: "trash", action: () => props.onDelete(props.callbackValue) }); // TODO TRANSLATE + buttons.push({ icon: "trash", action: () => props.onDelete(props.callbackValue) }); } if(props.onCancelDownload){ - buttons.push({ text: "Cancel download", icon: "cross", action: () => props.onCancelDownload(props.callbackValue), iconColor: "red" }); // TODO TRANSLATE + buttons.push({ icon: "cross", action: () => props.onCancelDownload(props.callbackValue), iconColor: "red" }); } return buttons; @@ -86,7 +88,6 @@ function modelItem(props: Props) { } return ( - // TODO TRANSLATE ALL TEXT setHovered(() => true)} onHoverEnd={() => setHovered(() => false)} onClick={props.onClick}>
    @@ -108,17 +109,17 @@ function modelItem(props: Props) {
  • {tag}
  • ))}
- + copyContent(`${props.hash}`, 'hash')}>{props.hash}
{props.id && ( - + copyContent(`${props.id}`, 'id')}>{props.id} )} {props.path && ( - + copyContent(`${props.path}`, 'path')}>{props.path} )} diff --git a/src/renderer/components/models-management/models-grid.component.tsx b/src/renderer/components/models-management/models-grid.component.tsx index 4bf2f920..d8f58283 100644 --- a/src/renderer/components/models-management/models-grid.component.tsx +++ b/src/renderer/components/models-management/models-grid.component.tsx @@ -20,6 +20,7 @@ import { VersionLinkerAction } from "renderer/services/version-folder-linker.ser import { MODEL_TYPE_FOLDERS } from "shared/models/models/constants"; import { useService } from "renderer/hooks/use-service.hook"; import { ModelsDownloaderService } from "renderer/services/models-management/models-downloader.service"; +import { useTranslation } from "renderer/hooks/use-translation.hook"; type Props = { className?: string, @@ -34,6 +35,8 @@ export const ModelsGrid = forwardRef(({className, version, type, search, active} const modelsManager = useService(ModelsManagerService); const modelsDownloader = useService(ModelsDownloaderService); + const t = useTranslation(); + const ref = useRef(); const [models, setModelsLoadObservable,, setModels] = useSwitchableObservable(); @@ -156,7 +159,7 @@ export const ModelsGrid = forwardRef(({className, version, type, search, active} return (
- Chargement des models... {/** TODO TRANSLATE **/} + {t("models.panel.grid.loading")}
) @@ -166,8 +169,8 @@ export const ModelsGrid = forwardRef(({className, version, type, search, active} return (
- Aucun modelès {/** TODO TRANSLATE **/} - {e.preventDefault();}}/> + {t("models.panel.grid.no-models")} + {e.preventDefault();}}/>
) } diff --git a/src/renderer/components/models-management/models-panel.component.tsx b/src/renderer/components/models-management/models-panel.component.tsx index 2af36d7a..02ec4aec 100644 --- a/src/renderer/components/models-management/models-panel.component.tsx +++ b/src/renderer/components/models-management/models-panel.component.tsx @@ -12,6 +12,7 @@ import { ModelsDownloaderService } from "renderer/services/models-management/mod import { useOnUpdate } from "renderer/hooks/use-on-update.hook"; import { NotificationService } from "renderer/services/notification.service"; import { ConfigurationService } from "renderer/services/configuration.service"; +import { useTranslation } from "renderer/hooks/use-translation.hook"; export function ModelsPanel({version, isActive, goToMods}: {version?: BSVersion, isActive: boolean, goToMods: () => void}) { @@ -20,6 +21,8 @@ export function ModelsPanel({version, isActive, goToMods}: {version?: BSVersion, const notification = useService(NotificationService); const config = useService(ConfigurationService); + const t = useTranslation(); + const ref = useRef(); const modelsGridRefs = [useRef(null), useRef(null), useRef(null), useRef(null)]; @@ -31,9 +34,9 @@ export function ModelsPanel({version, isActive, goToMods}: {version?: BSVersion, useOnUpdate(() => { if(!isActive){ return; } - //if(config.get("prevented-for-mods-models")){ return; } + if(config.get("prevented-for-mods-models")){ return; } config.set("prevented-for-mods-models", true); - notification.notifyWarning({ title: "Mods needed", desc: "Be sure to have the mods installed to use models in BeatSaber", actions: [{id: "0", title: "Go to mods"}], duration: 9_000 }).then(res => { + notification.notifyWarning({ title: "models.notifications.prevent-for-mods.title", desc: "models.notifications.prevent-for-mods.desc", actions: [{id: "0", title: "models.notifications.prevent-for-mods.go-to-mods"}], duration: 9_000 }).then(res => { if(res !== "0"){ return; } goToMods(); }); @@ -55,8 +58,8 @@ export function ModelsPanel({version, isActive, goToMods}: {version?: BSVersion, } const threeDotsItems: DropDownItem[] = [ - {text: "TODO TRANSLATE EXPORT", onClick: exportModels, icon: "export"}, - {text: "TODO TRANSLATE DELETE", onClick: deleteModels, icon: "trash"}, + {text: "models.panel.actions.drop-down.export", onClick: exportModels, icon: "export"}, + {text: "models.panel.actions.drop-down.delete", onClick: deleteModels, icon: "trash"}, ]; return ( @@ -64,7 +67,7 @@ export function ModelsPanel({version, isActive, goToMods}: {version?: BSVersion,
{e.preventDefault(); openDownloadModal()}}/>
- setSearch(e.target.value)} tabIndex={-1}/> + setSearch(e.target.value)} tabIndex={-1}/>
diff --git a/src/renderer/components/models-management/models-tabs-navbar.component.tsx b/src/renderer/components/models-management/models-tabs-navbar.component.tsx index e19bc2d2..033b4e67 100644 --- a/src/renderer/components/models-management/models-tabs-navbar.component.tsx +++ b/src/renderer/components/models-management/models-tabs-navbar.component.tsx @@ -8,6 +8,8 @@ import { BsContentNavBar, BsContentNavBarTab } from "../shared/bs-content-nav-ba import { useConstant } from "renderer/hooks/use-constant.hook" import { BsmIcon } from "../svgs/bsm-icon.component" import { MODEL_TYPES } from "../../../shared/models/models/constants"; +import { useService } from "renderer/hooks/use-service.hook" +import { useTranslation } from "renderer/hooks/use-translation.hook" type Props = { className?: string, @@ -20,7 +22,7 @@ export function ModelsTabsNavbar({className, version, tabIndex, onTabChange}: Pr const tabs = useConstant[]>(() => { return MODEL_TYPES.map(type => ({ - text: type, // <= TODO: Translate + text: type, extra: type })) }) @@ -40,7 +42,9 @@ type TabProps = { function ModelTab({version, modelType, active, onClick}: TabProps){ - const modelsManager = useConstant(() => ModelsManagerService.getInstance()); + const modelsManager = useService(ModelsManagerService); + + const t = useTranslation(); const [modelsAreLinked, setModelsAreLinked] = useState(false); const [linkBtnDisabled, setLinkBtnDisabled] = useState(false); @@ -73,7 +77,7 @@ function ModelTab({version, modelType, active, onClick}: TabProps){
  • - {modelType} + {t(`models.types.plural.${modelType}`)}
    {!!version && ( @@ -85,7 +89,7 @@ function ModelTab({version, modelType, active, onClick}: TabProps){ initial={{rotate: 0}} className="block w-6 h-6 aspect-square blur-0 cursor-pointer hover:brightness-75" linked={modelsAreLinked} - title={"aaa"} //TODO ADD TRANSLATION + title={modelsAreLinked ? "models.panel.actions.unlink-models" : "models.panel.actions.link-models"} onClick={onClickLink} /> )} diff --git a/src/renderer/services/models-management/models-downloader.service.ts b/src/renderer/services/models-management/models-downloader.service.ts index e90e459b..c1e47f22 100644 --- a/src/renderer/services/models-management/models-downloader.service.ts +++ b/src/renderer/services/models-management/models-downloader.service.ts @@ -100,7 +100,7 @@ export class ModelsDownloaderService { } public openDownloadModelsModal(version: BSVersion, type?: MSModelType, owned?: BsmLocalModel[]): Promise>{ - return this.modal.openModal(DownloadModelsModal, {version, type, owned}); // TODO MODELS + return this.modal.openModal(DownloadModelsModal, {version, type, owned}); } } diff --git a/src/renderer/services/models-management/models-manager.service.ts b/src/renderer/services/models-management/models-manager.service.ts index 57dc202b..4fb9a88c 100644 --- a/src/renderer/services/models-management/models-manager.service.ts +++ b/src/renderer/services/models-management/models-manager.service.ts @@ -118,12 +118,11 @@ export class ModelsManagerService { this.progressBar.show(exportProgress$, true); - lastValueFrom(exportProgress$).catch(e => { - this.notifications.notifyError({title: "notifications.types.error"}); - }).then(() => { - // TODO TRANSLATE - this.notifications.notifySuccess({title: "TODO TRANSLATE SUCCESS", duration: 3000}); - this.progressBar.complete(); + lastValueFrom(exportProgress$).then(() => { + this.notifications.notifySuccess({title: "models.notifications.export-success.title", duration: 3000}); + }).catch(e => { + this.notifications.notifyError({title: "notifications.types.error", desc: "notifications.common.msg.error-occurred", duration: 3000}); + }).finally(() => { this.progressBar.hide(true); }) @@ -158,8 +157,11 @@ export class ModelsManagerService { if(showProgressBar){ this.progressBar.show(progress$); } return lastValueFrom(progress$) - .catch(() => false) .then(() => true) + .catch(() => { + this.notifications.notifyError({title: "notifications.types.error", desc: "notifications.common.msg.error-occurred", duration: 3000}); + return false; + }) .finally(() => this.progressBar.hide(true)); }