mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
[feature-136] add translations
This commit is contained in:
@@ -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": {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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 (
|
||||
<div ref={ref} className={props.className} title={props.title} onClick={e => {e.preventDefault(); !props.disabled && props.onClick?.()}} style={{pointerEvents: props.disabled ? "none" : "auto"}}>
|
||||
<div ref={ref} className={props.className} title={props.title ? t(props.title) : undefined} onClick={e => {e.preventDefault(); !props.disabled && props.onClick?.()}} style={{pointerEvents: props.disabled ? "none" : "auto"}}>
|
||||
<span className="absolute top-0 left-0 h-full w-full rounded-full brightness-50 opacity-75 dark:opacity-20 dark:filter-none" style={{backgroundColor: linkedColor}}/>
|
||||
<BsmIcon className="p-1 absolute top-0 left-0 h-full w-full !bg-transparent -rotate-45 brightness-150" icon={props.linked ? "link" : "unlink"} style={{color: linkedColor}} />
|
||||
</div>
|
||||
|
||||
+1
-1
@@ -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)}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -23,13 +23,16 @@ export const DeleteModelsModal: ModalComponent<void, {models: BsmLocalModel[], l
|
||||
|
||||
const isMultiple = data.models.length > 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
|
||||
<form className="text-gray-800 dark:text-gray-200">
|
||||
<h1 className="text-3xl uppercase tracking-wide w-full text-center">{isMultiple ? "Supprimer les modèles" : "Supprimer le modèle"}</h1>
|
||||
<h1 className="text-3xl uppercase tracking-wide w-full text-center">{title}</h1>
|
||||
<BsmImage className="mx-auto h-24" image={BeatConflict}/>
|
||||
<p className="max-w-sm w-full">{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}`}</p>
|
||||
{data.linked && <p className="text-sm italic mt-2 cursor-help w-fit" title="TODO TITLE">{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"}</p>}
|
||||
<p className="max-w-sm w-full">{desc}</p>
|
||||
{data.linked && <p className="text-sm italic mt-2 w-fit">{linkedAnnotation}</p>}
|
||||
{!isMultiple && (
|
||||
<div className="flex items-center relative py-2 gap-1 mt-1">
|
||||
<BsmCheckbox className="h-5 relative z-[1]" checked={remember} onChange={(val) => setRemember(val)}/>
|
||||
|
||||
+27
-19
@@ -29,17 +29,18 @@ export const DownloadModelsModal: ModalComponent<void, {version: BSVersion, type
|
||||
const modelSaber = useService(ModelSaberService);
|
||||
const os = useService(OsDiagnosticService);
|
||||
|
||||
const t = useTranslation();
|
||||
|
||||
const modelTypesOptions = useConstant<BsmSelectOption<MSModelType>[]>(() => MODEL_TYPES.map(type => ({
|
||||
text: type.toString(), // TODO TRANSLATE
|
||||
text: `models.types.plural.${type}`,
|
||||
value: type
|
||||
})));
|
||||
|
||||
const querySortsOptions = useConstant<BsmSelectOption<MSGetSort>[]>(() => 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<MSModel[]>([]);
|
||||
@@ -127,43 +128,50 @@ export const DownloadModelsModal: ModalComponent<void, {version: BSVersion, type
|
||||
return !!ownedModels.some(owned => owned.hash === model.hash);
|
||||
}
|
||||
|
||||
const filterTipsHTML = useConstant(() => (
|
||||
const renderFilterTips = useConstant(() => (
|
||||
<div className="w-fit flex">
|
||||
<table className="w-fit whitespace-nowrap grow shrink-0 text-sm">
|
||||
<tbody>
|
||||
<tr className="font-bold"><td className="mr-3 block">Tag</td><td>Description</td></tr>
|
||||
<tr><td className="mr-3 block">author:</td><td>Only show models by the specified author.</td></tr>
|
||||
<tr><td className="mr-3 block">hash:</td><td>Only show models with the specified hash.</td></tr>
|
||||
<tr><td className="mr-3 block">tag:</td><td>Only show models with the specified tag.</td></tr>
|
||||
<tr><td className="mr-3 block">name:</td><td>Only show models with the specified name.</td></tr>
|
||||
<tr><td className="mr-3 block">discordid:</td><td>Only show models by the user with the specified discordid.</td></tr>
|
||||
<tr><td className="mr-3 block">status:</td><td>Only show models with the specified approval status. (profile only, and only for the author)</td></tr>
|
||||
<tr className="font-bold"><td className="mr-3 block">{t("models.modals.download-models.search-tips.header.tag")}</td><td>{t("models.modals.download-models.search-tips.header.desc")}</td></tr>
|
||||
<tr><td className="mr-3 block">author:</td><td>{t("models.modals.download-models.search-tips.author-desc")}</td></tr>
|
||||
<tr><td className="mr-3 block">tag:</td><td>{t("models.modals.download-models.search-tips.tag-desc")}</td></tr>
|
||||
<tr><td className="mr-3 block">hash:</td><td>{t("models.modals.download-models.search-tips.hash-desc")}</td></tr>
|
||||
<tr><td className="mr-3 block">name:</td><td>{t("models.modals.download-models.search-tips.name-desc")}</td></tr>
|
||||
<tr><td className="mr-3 block">discordid:</td><td>{t("models.modals.download-models.search-tips.discordid-desc")}</td></tr>
|
||||
<tr><td className="mr-3 block">status:</td><td>{t("models.modals.download-models.search-tips.status-desc")}</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
))
|
||||
));
|
||||
|
||||
const renderLoadingStatus = () => {
|
||||
if(isLoading) { return <span className="text-lg">{t("models.panel.grid.loading")}</span> }
|
||||
if(isOnline) { return <span className="text-lg">{t("models.modals.download-models.no-models")}</span> }
|
||||
if(!isOnline) { return <span className="text-lg">{t("models.modals.download-models.no-internet")}</span> }
|
||||
return <span className="text-lg">{t("models.modals.download-models.error-occured")}</span>
|
||||
}
|
||||
|
||||
return (
|
||||
<form className="text-gray-800 dark:text-gray-200 flex flex-col max-w-[95vw] w-[970px] h-[85vh] gap-3" onSubmit={e => {e.preventDefault(); search()}}>
|
||||
<div className="flex h-9 gap-2 shrink-0">
|
||||
<BsmSelect className="bg-light-main-color-1 dark:bg-main-color-1 rounded-full px-1 pb-0.5 text-center" options={modelTypesOptions} selected={currentType} onChange={(value) => currentType$.next(value)}/>
|
||||
<BsmSelect className="bg-light-main-color-1 dark:bg-main-color-1 rounded-full px-1 pb-0.5 text-center capitalize" options={modelTypesOptions} selected={currentType} onChange={(value) => currentType$.next(value)}/>
|
||||
<div className="h-ful grow relative flex justify-center items-center">
|
||||
<input className="h-full w-full bg-light-main-color-1 dark:bg-main-color-1 rounded-full px-2 pb-0.5" type="text" name="" id="" placeholder="TODO TRANSLATE Rechercher un modèle" value={searhInput} onChange={e => searhInput$.next(e.target.value)}/>
|
||||
<Tippy placement="bottom" content={filterTipsHTML} allowHTML={true} maxWidth={Infinity}>
|
||||
<input className="h-full w-full bg-light-main-color-1 dark:bg-main-color-1 rounded-full px-2 pb-0.5" type="text" name="" id="" placeholder={t("models.modals.download-models.search-placeholder")} value={searhInput} onChange={e => searhInput$.next(e.target.value)}/>
|
||||
<Tippy placement="bottom" content={renderFilterTips} allowHTML={true} maxWidth={Infinity}>
|
||||
<div className="absolute right-0 h-full w-fit p-1 cursor-pointer">
|
||||
<BsmButton className="h-full rounded-full p-1 aspect-square" typeColor="primary" icon="info" withBar={false}/>
|
||||
</div>
|
||||
</Tippy>
|
||||
|
||||
</div>
|
||||
<BsmButton className="shrink-0 rounded-full py-1 px-3 !bg-light-main-color-1 dark:!bg-main-color-1 flex justify-center items-center capitalize" icon="search" type="submit" text="modals.download-maps.search-btn" withBar={false} onClick={e => {e.preventDefault(); search()}}/>
|
||||
<BsmSelect className="bg-light-main-color-1 dark:bg-main-color-1 rounded-full px-1 pb-0.5 text-center" options={querySortsOptions} onChange={(value) => currentSort$.next(value)}/>
|
||||
<BsmButton className="shrink-0 rounded-full py-1 px-3 !bg-light-main-color-1 dark:!bg-main-color-1 flex justify-center items-center capitalize" icon="search" type="submit" text="models.modals.download-models.search-btn" withBar={false} onClick={e => {e.preventDefault(); search()}}/>
|
||||
<BsmSelect className="bg-light-main-color-1 dark:bg-main-color-1 rounded-full px-1 pb-0.5 text-center capitalize" options={querySortsOptions} onChange={(value) => currentSort$.next(value)}/>
|
||||
</div>
|
||||
<ul className="w-full grow flex content-start flex-wrap gap-4 pt-1.5 px-2 overflow-y-scroll overflow-x-hidden scrollbar-thin scrollbar-thumb-rounded-full scrollbar-thumb-neutral-900 z-0" >
|
||||
{msModels.length === 0 ? (
|
||||
<div className="w-full h-full flex flex-col items-center justify-center">
|
||||
<img className={`w-32 h-32 ${isLoading && "spin-loading"}`} src={isLoading ? BeatWaitingImg : BeatConflictImg} alt=" "/>
|
||||
<span className="text-lg">{t(isLoading ? "Chargement des modèles" : isOnline ? "Aucun modèles trouvés" : "Pas d'internet")}</span> {/** TODO TRANSLATE **/}
|
||||
<img className={`w-32 h-32 ${isLoading && "spin-loading"}`} src={(isLoading && !error) ? BeatWaitingImg : BeatConflictImg} alt=" "/>
|
||||
{renderLoadingStatus()}
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
|
||||
@@ -15,17 +15,17 @@ export const LinkModelsModal: ModalComponent<boolean, MSModelType> = ({resolver,
|
||||
|
||||
return (
|
||||
<form className="text-gray-800 dark:text-gray-200">
|
||||
<h1 className="text-3xl uppercase tracking-wide w-full text-center">{t(`modals.models.link-models.${data}.title`)}</h1>
|
||||
<h1 className="text-3xl uppercase tracking-wide w-full text-center">{t(`models.modals.link-models.${data}.title`)}</h1>
|
||||
<BsmImage className="mx-auto h-24" image={BeatRunning} />
|
||||
<p className="max-w-sm w-full">{t(`modals.models.link-models.${data}.desc`)}</p>
|
||||
<p className="max-w-sm w-full text-sm italic mt-2">{t(`modals.models.link-models.${data}.info`)}</p>
|
||||
<p className="max-w-sm w-full">{t(`models.modals.link-models.${data}.desc`)}</p>
|
||||
<p className="max-w-sm w-full text-sm italic mt-2">{t(`models.modals.link-models.${data}.info`)}</p>
|
||||
<div className="relative h-5 flex my-3 items-center">
|
||||
<BsmCheckbox className="h-full aspect-square relative bg-inherit mr-1.5 z-[1]" checked={keepMaps} onChange={setKeepMaps}/>
|
||||
<span className="text-sm mb-0.5 cursor-help" title={t(`modals.models.link-models.${data}.keep-models.title`)}>{t(`modals.models.link-models.${data}.keep-models.label`)}</span>
|
||||
<span className="text-sm mb-0.5 cursor-help" title={t(`models.modals.link-models.${data}.keep-models.title`)}>{t(`models.modals.link-models.${data}.keep-models.label`)}</span>
|
||||
</div>
|
||||
<div className="grid grid-flow-col grid-cols-2 gap-4 mt-4">
|
||||
<BsmButton typeColor="cancel" className="rounded-md text-center transition-all" onClick={() => resolver({exitCode: ModalExitCode.CANCELED})} withBar={false} text="misc.cancel"/>
|
||||
<BsmButton typeColor="primary" className="rounded-md text-center transition-all" onClick={() => resolver({exitCode: ModalExitCode.COMPLETED, data: keepMaps})} withBar={false} text={`modals.models.link-models.${data}.valid-btn`}/>
|
||||
<BsmButton typeColor="primary" className="rounded-md text-center transition-all" onClick={() => resolver({exitCode: ModalExitCode.COMPLETED, data: keepMaps})} withBar={false} text={`models.modals.link-models.${data}.valid-btn`}/>
|
||||
</div>
|
||||
</form>
|
||||
)
|
||||
|
||||
@@ -14,16 +14,16 @@ export const UnlinkModelsModal: ModalComponent<boolean, MSModelType> = ({resolve
|
||||
|
||||
return (
|
||||
<form className="text-gray-800 dark:text-gray-200">
|
||||
<h1 className="text-3xl uppercase tracking-wide w-full text-center">{t(`modals.models.unlink-models.${data}.title`)}</h1>
|
||||
<h1 className="text-3xl uppercase tracking-wide w-full text-center">{t(`models.modals.unlink-models.${data}.title`)}</h1>
|
||||
<BsmImage className="mx-auto h-24" image={BeatConflict} />
|
||||
<p className="max-w-sm w-full">{t(`modals.models.unlink-models.${data}.desc`)}</p>
|
||||
<p className="max-w-sm w-full">{t(`models.modals.unlink-models.${data}.desc`)}</p>
|
||||
<div className="relative h-5 flex my-3 items-center">
|
||||
<BsmCheckbox className="h-full aspect-square relative bg-inherit mr-1.5 z-[1]" checked={keepMaps} onChange={setKeepMaps}/>
|
||||
<span className="text-sm mb-0.5 cursor-help" title={t(`modals.models.unlink-models.${data}.keep-models.title`)}>{t(`modals.models.unlink-models.${data}.keep-models.label`)}</span>
|
||||
<span className="text-sm mb-0.5 cursor-help" title={t(`models.modals.unlink-models.${data}.keep-models.title`)}>{t(`models.modals.unlink-models.${data}.keep-models.label`)}</span>
|
||||
</div>
|
||||
<div className="grid grid-flow-col grid-cols-2 gap-4 mt-4">
|
||||
<BsmButton typeColor="cancel" className="rounded-md text-center transition-all" onClick={() => resolver({exitCode: ModalExitCode.CANCELED})} withBar={false} text="misc.cancel"/>
|
||||
<BsmButton typeColor="error" className="rounded-md text-center transition-all" onClick={() => resolver({exitCode: ModalExitCode.COMPLETED, data: keepMaps})} withBar={false} text={`modals.models.unlink-models.${data}.valid-btn`}/>
|
||||
<BsmButton typeColor="error" className="rounded-md text-center transition-all" onClick={() => resolver({exitCode: ModalExitCode.COMPLETED, data: keepMaps})} withBar={false} text={`models.modals.unlink-models.${data}.valid-btn`}/>
|
||||
</div>
|
||||
</form>
|
||||
)
|
||||
|
||||
@@ -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<T> = {
|
||||
selected?: boolean,
|
||||
@@ -29,6 +30,7 @@ type Props<T> = {
|
||||
|
||||
function modelItem<T = unknown>(props: Props<T>) {
|
||||
|
||||
const t = useTranslation();
|
||||
const color = useThemeColor("first-color");
|
||||
const [hovered, setHovered] = useState(false);
|
||||
const [idContentCopied, setIdContentCopied] = useState<string>(null);
|
||||
@@ -59,19 +61,19 @@ function modelItem<T = unknown>(props: Props<T>) {
|
||||
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<T = unknown>(props: Props<T>) {
|
||||
}
|
||||
|
||||
return (
|
||||
// TODO TRANSLATE ALL TEXT
|
||||
<motion.li className={`relative flex-grow min-w-[14rem] h-56 cursor-pointer ${props.className ?? ""}`} onHoverStart={() => setHovered(() => true)} onHoverEnd={() => setHovered(() => false)} onClick={props.onClick}>
|
||||
<GlowEffect visible={props.selected || hovered}/>
|
||||
<div className="absolute top-0 left-0 w-full h-full rounded-lg overflow-hidden blur-none bg-black shadow-sm shadow-black">
|
||||
@@ -108,17 +109,17 @@ function modelItem<T = unknown>(props: Props<T>) {
|
||||
<li key={tag} className="inline-block mr-1 text-xs bg-white text-black px-1 rounded-full p-0.5">{tag}</li>
|
||||
))}
|
||||
</ul>
|
||||
<Tippy placement="top" content={idContentCopied === "hash" ? "Copied!" : "Copy hash"} followCursor="horizontal" plugins={[followCursor]} hideOnClick={false}>
|
||||
<Tippy placement="top" content={idContentCopied === "hash" ? t("misc.copied") : t("misc.copy")} followCursor="horizontal" plugins={[followCursor]} hideOnClick={false}>
|
||||
<span className="mt-0.5 cursor-copy block w-full max-w-fit overflow-hidden whitespace-nowrap text-ellipsis bg-main-color-1 rounded-md p-1 uppercase text-xs" onClick={() => copyContent(`${props.hash}`, 'hash')}>{props.hash}</span>
|
||||
</Tippy>
|
||||
<div className="flex gap-1">
|
||||
{props.id && (
|
||||
<Tippy placement="top" content={idContentCopied === "id" ? "Copied!" : "Copy id"} followCursor="horizontal" plugins={[followCursor]} hideOnClick={false}>
|
||||
<Tippy placement="top" content={idContentCopied === "id" ? t("misc.copied") : t("misc.copy")} followCursor="horizontal" plugins={[followCursor]} hideOnClick={false}>
|
||||
<span className="cursor-copy w-fit shrink-0 max-w-full overflow-hidden whitespace-nowrap text-ellipsis bg-main-color-1 rounded-md p-1 uppercase text-xs" onClick={() => copyContent(`${props.id}`, 'id')}>{props.id}</span>
|
||||
</Tippy>
|
||||
)}
|
||||
{props.path && (
|
||||
<Tippy placement="top" content={idContentCopied === "path" ? "Copied!" : "Copy path"} followCursor="horizontal" plugins={[followCursor]} hideOnClick={false}>
|
||||
<Tippy placement="top" content={idContentCopied === "path" ? t("misc.copied") : t("misc.copy")} followCursor="horizontal" plugins={[followCursor]} hideOnClick={false}>
|
||||
<span className="cursor-copy w-fit max-w-full overflow-hidden whitespace-nowrap text-ellipsis bg-main-color-1 rounded-md p-1 text-xs" onClick={() => copyContent(`${props.path}`, 'path')}>{props.path}</span>
|
||||
</Tippy>
|
||||
)}
|
||||
|
||||
@@ -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<BsmLocalModel[]>();
|
||||
@@ -156,7 +159,7 @@ export const ModelsGrid = forwardRef(({className, version, type, search, active}
|
||||
return (
|
||||
<div className="h-full flex flex-col items-center justify-center flex-wrap gap-1 text-gray-800 dark:text-gray-200">
|
||||
<BsmImage className="w-32 h-32 spin-loading" image={BeatWaitingImg}/>
|
||||
<span className="font-bold">Chargement des models...</span> {/** TODO TRANSLATE **/}
|
||||
<span className="font-bold">{t("models.panel.grid.loading")}</span>
|
||||
<TextProgressBar value$={progress$}/>
|
||||
</div>
|
||||
)
|
||||
@@ -166,8 +169,8 @@ export const ModelsGrid = forwardRef(({className, version, type, search, active}
|
||||
return (
|
||||
<div className="h-full flex flex-col items-center justify-center flex-wrap gap-1 text-gray-800 dark:text-gray-200">
|
||||
<BsmImage className="h-32" image={BeatConflict}/>
|
||||
<span className="font-bold">Aucun modelès</span> {/** TODO TRANSLATE **/}
|
||||
<BsmButton className="font-bold rounded-md p-2" text="Télécharger des modèles" typeColor="primary" withBar={false} onClick={e => {e.preventDefault();}}/>
|
||||
<span className="font-bold">{t("models.panel.grid.no-models")}</span>
|
||||
<BsmButton className="font-bold rounded-md p-2" text="models.panel.grid.download-models" typeColor="primary" withBar={false} onClick={e => {e.preventDefault();}}/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
<div className="w-full shrink-0 flex h-9 justify-center px-40 gap-2 mb-3 text-main-color-1 dark:text-white">
|
||||
<BsmButton className="flex items-center justify-center w-fit rounded-full px-2 py-1 font-bold" icon="add" text="misc.add" typeColor="primary" withBar={false} onClick={e => {e.preventDefault(); openDownloadModal()}}/>
|
||||
<div className="h-full rounded-full bg-light-main-color-2 dark:bg-main-color-2 grow p-[6px]">
|
||||
<input type="text" className="h-full w-full bg-light-main-color-1 dark:bg-main-color-1 rounded-full px-2" placeholder={"TODO TRANSLATE"} onChange={e => setSearch(e.target.value)} tabIndex={-1}/>
|
||||
<input type="text" className="h-full w-full bg-light-main-color-1 dark:bg-main-color-1 rounded-full px-2" placeholder={t("models.panel.actions.search")} onChange={e => setSearch(e.target.value)} tabIndex={-1}/>
|
||||
</div>
|
||||
<BsmDropdownButton items={threeDotsItems} className="h-full flex aspect-square relative rounded-full z-[1] bg-light-main-color-1 dark:bg-main-color-3" buttonClassName="rounded-full h-full w-full p-[6px]" icon="three-dots" withBar={false} menuTranslationY="6px" align="center"/>
|
||||
</div>
|
||||
|
||||
@@ -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<BsContentNavBarTab<MSModelType>[]>(() => {
|
||||
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){
|
||||
<li className={`relative w-full cursor-pointer flex-1 text-center text-lg font-bold flex justify-center items-center content-center px-7 dim-on-hover ${active ? "dim" : ""}`} onClick={onClick}>
|
||||
<div className="flex flex-col gap-0.5 justify-start items-center text-main-color-1 dark:text-gray-200">
|
||||
<BsmIcon icon={modelType} className="w-7 h-7"/>
|
||||
<span className=" font-thin italic text-xs">{modelType}</span>
|
||||
<span className=" font-thin italic text-xs">{t(`models.types.plural.${modelType}`)}</span>
|
||||
</div>
|
||||
<div className="flex items-center absolute top-1.5 left-1.5">
|
||||
{!!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}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -100,7 +100,7 @@ export class ModelsDownloaderService {
|
||||
}
|
||||
|
||||
public openDownloadModelsModal(version: BSVersion, type?: MSModelType, owned?: BsmLocalModel[]): Promise<ModalResponse<void>>{
|
||||
return this.modal.openModal(DownloadModelsModal, {version, type, owned}); // TODO MODELS
|
||||
return this.modal.openModal(DownloadModelsModal, {version, type, owned});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user