# HG changeset patch # User Paper # Date 1699253504 18000 # Node ID 79714c95a145b2df7e16f7e7b2d1a62543845927 # Parent 2004b41d4a59a60ce36019762428cb2631420614 *: add translation files and locale files I forgot to add these in the last commit :p also now you have to ask cmake to update the translations because before the ts files were not tracked (obviously) diff -r 2004b41d4a59 -r 79714c95a145 CMakeLists.txt --- a/CMakeLists.txt Sun Nov 05 23:31:49 2023 -0500 +++ b/CMakeLists.txt Mon Nov 06 01:51:44 2023 -0500 @@ -12,6 +12,7 @@ option(BUILD_SHARED_LIBS "Build using shared libraries" ON) option(USE_QT6 "Force build with Qt 6" OFF) option(USE_QT5 "Force build with Qt 5" OFF) +option(UPDATE_TRANSLATIONS "Update *.ts translation files" OFF) add_subdirectory(dep/anitomy) add_subdirectory(dep/animia) @@ -22,7 +23,7 @@ if (USE_QT6) set(QT_VERSION_MAJOR 6) -elseif(USE_Qt5) +elseif(USE_QT5) set(QT_VERSION_MAJOR 5) else() find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core) @@ -123,9 +124,11 @@ set_source_files_properties(${TS_FILES} PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/rc/locale") # dumb little hack to get this working on Qt5 and Qt6 -cmake_language(CALL qt${QT_VERSION_MAJOR}_create_translation ${SRC_FILES} ${TS_FILES} OPTIONS "-I${CMAKE_CURRENT_SOURCE_DIR}/include") +if (UPDATE_TRANSLATIONS) + cmake_language(CALL qt${QT_VERSION_MAJOR}_create_translation ${SRC_FILES} ${TS_FILES} OPTIONS "-I${CMAKE_CURRENT_SOURCE_DIR}/include") +endif() cmake_language(CALL qt${QT_VERSION_MAJOR}_add_translation QM_FILES ${TS_FILES}) -list(APPEND SRC_FILES ${QM_FILES}) +add_custom_target(translation ALL SOURCES ${QM_FILES} DEPENDS ${TS_FILES}) function(qt_create_resource_file outfile) set(QRC "\n\t\n") @@ -139,7 +142,7 @@ endfunction() qt_create_resource_file("${CMAKE_CURRENT_BINARY_DIR}/rc/locale.qrc" ${QM_FILES}) -list(APPEND SRC_FILES "${CMAKE_CURRENT_BINARY_DIR}/rc/locale.qrc") +add_custom_target(resources DEPENDS translation SOURCES "${CMAKE_CURRENT_BINARY_DIR}/rc/locale.qrc") # This is also used in the Win32 rc file set(RC_INFO_STRING "A lightweight anime tracker built with Qt.") @@ -173,6 +176,7 @@ endif() add_executable(minori WIN32 MACOSX_BUNDLE ${SRC_FILES}) +add_dependencies(minori resources) set_property(TARGET minori PROPERTY CXX_STANDARD 11) set_property(TARGET minori PROPERTY AUTOMOC ON) set_property(TARGET minori PROPERTY AUTORCC ON) diff -r 2004b41d4a59 -r 79714c95a145 include/gui/locale.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/include/gui/locale.h Mon Nov 06 01:51:44 2023 -0500 @@ -0,0 +1,35 @@ +#ifndef __gui__locale_h +#define __gui__locale_h + +#include +#include +#include +#include +#include + +namespace Locale { + +std::string GetLocaleFullName(const QLocale& locale); + +class Locale { +public: + Locale(); + Locale(const std::string& name); + QLocale GetLocale(); + std::vector GetAvailableLocales(); + void RefreshAvailableLocales(); // why would this ever be called? + bool IsLocaleAvailable(const QLocale& locale); + bool SetActiveLocale(const QLocale& locale); + +private: + bool SwitchTranslator(QTranslator& translator, const QString& name); + + QTranslator _translator; + QTranslator _translator_qt; + QLocale _locale; + std::vector _available_translations = {}; +}; + +} + +#endif // __gui__locale_h diff -r 2004b41d4a59 -r 79714c95a145 rc/dark.qss --- a/rc/dark.qss Sun Nov 05 23:31:49 2023 -0500 +++ b/rc/dark.qss Mon Nov 06 01:51:44 2023 -0500 @@ -38,27 +38,26 @@ AnimeListPage::pane { margin: 0.04em; + border: 0.04em solid #808080; + top: -0.04em; + left: -0.04em; } -AnimeListPage::pane, QTabWidget::pane:top { border: 0.04em solid #808080; top: -0.04em; } -AnimeListPage::pane, QTabWidget::pane:bottom { border: 0.04em solid #808080; bottom: -0.04em; } -AnimeListPage::pane, QTabWidget::pane:left { border: 0.04em solid #808080; left: -0.04em; } -AnimeListPage::pane, QTabWidget::pane:right { border: 0.04em solid #808080; right: -0.04em; @@ -153,7 +152,7 @@ } QPushButton:hover { - background-color: rgba(57, 66, 75, 1.0); + background-color: #39424B; } /* diff -r 2004b41d4a59 -r 79714c95a145 rc/locale/en_GB.ts --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rc/locale/en_GB.ts Mon Nov 06 01:51:44 2023 -0500 @@ -0,0 +1,852 @@ + + + + + AboutWindow + + + About Minori + + + + + AnimeInfoWidget + + + Alternative titles + + + + + Details + + + + + Type: +Episodes: +Status: +Season: +Genres: +Score: + + + + + Synopsis + + + + + AnimeListPage + + + + Column visibility + + + + + Reset to defaults + + + + + Information + + + + + Delete from list... + + + + + AnimeListPageModel + + + Anime title + + + + + Progress + + + + + Episodes + + + + + Type + + + + + Score + + + + + Season + + + + + Date started + + + + + Date completed + + + + + Notes + + + + + Average score + + + + + Last updated + + + + + InformationDialog + + + Anime Information + + + + + Anime list + + + + + Episodes watched: + + + + + Rewatching + + + + + Status: + + + + + Score: + + + + + Notes: + + + + + Enter your notes about this anime + + + + + Date started: + + + + + Date completed: + + + + + Main information + + + + + My list and settings + + + + + MainWindow + + + Now Playing + + + + + Anime List + + + + + History + + + + + Statistics + + + + + Search + + + + + Seasons + + + + + Torrents + + + + + &File + + + + + &Library folders + + + + + &Add new folder... + + + + + &Scan available episodes + + + + + Play &next episode + + + + + Play &random episode + + + + + E&xit + + + + + &Services + + + + + Synchronize &list + Synchronise &list + + + + &AniList + + + + + + + Go to my &profile + + + + + Go to my &stats + + + + + &Kitsu + + + + + Go to my &feed + + + + + Go to my &library + + + + + &MyAnimeList + + + + + Go to my p&anel + + + + + Go to my &history + + + + + &Tools + + + + + &Export anime list + + + + + Export as &Markdown... + + + + + Export as MyAnimeList &XML... + + + + + Enable anime &recognition + + + + + Enable auto &sharing + + + + + Enable &auto synchronization + Enable &auto synchronisation + + + + &Settings + + + + + &View + + + + + &Now Playing + + + + + &Anime List + + + + + &History + + + + + &Statistics + + + + + S&earch + + + + + Se&asons + + + + + &Torrents + + + + + Show sidebar + + + + + &Help + + + + + &About Minori + + + + + About &Qt + + + + + &Synchronize + &Synchronise + + + + Add new folder... + + + + + Placeholder + + + + + S&ettings + + + + + NowPlayingPages::Default + + + Now Playing + + + + + QCoreApplication + + + Currently watching + + + + + Plan to watch + + + + + Completed + + + + + Dropped + + + + + On hold + + + + + Not in list + + + + + TV + + + + + TV short + + + + + OVA + + + + + Special + + + + + ONA + + + + + Music + + + + + + + Unknown + + + + + Winter + + + + + Summer + + + + + Movie + + + + + Fall + + + + + Spring + + + + + Currently airing + + + + + Finished airing + + + + + Not yet aired + + + + + Cancelled + + + + + On hiatus + + + + + AniList + + + + + None + + + + + Native + + + + + English + + + + + Romaji + + + + + Author: + + + + + Third party components: + + + + + Special thanks: + + + + + for creating Taiga + + + + + and + + + + + for creating BreezeStyleSheets, on which the dark theme in this program is based off of + + + + + for providing some sample code for detecting dark mode on Windows and macOS + + + + + for providing information on getting open file descriptors on macOS + + + + + SettingsDialog + + + Settings + + + + + Services + + + + + Application + + + + + SettingsPageApplication + + + Actions + + + + + Double click: + + + + + View anime info + + + + + Middle click: + + + + + Play next episode + + + + + Appearance + + + + + Title language preference: + + + + + Romaji + + + + + Native + + + + + English + + + + + Application theme: + + + + + Default + + + + + Light + + + + + Dark + + + + + Highlight anime if next episode is available in library folders + + + + + Display highlighted anime above others + + + + + Set application locale (requires restart): + + + + + Progress + + + + + Display aired episodes (estimated) + + + + + Display available episodes in library folders + + + + + Application + + + + + Anime list + + + + + SettingsPageServices + + + Active service and metadata provider: + + + + + + AniList + + + + + Synchronization + Synchronisation + + + + Note: Minori is unable to synchronize multiple services at the same time. + Note: Minori is unable to synchronise multiple services at the same time. + + + + Account + + + + + Username: (not your email address) + + + + + Authorize... + Authorise... + + + + Re-authorize... + Re-authorise... + + + + <a href="http://anilist.co/">Create a new AniList account</a> + + + + + Services + + + + + Main + + + + + StatisticsPage + + + Anime list + + + + + Anime count: +Episode count: +Time spent watching: +Time to complete: +Average score: +Score deviation: + + + + + Score distribution + + + + + Minori + + + + + Uptime: +Requests made: + + + + diff -r 2004b41d4a59 -r 79714c95a145 rc/locale/es.ts --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rc/locale/es.ts Mon Nov 06 01:51:44 2023 -0500 @@ -0,0 +1,863 @@ + + + + + AboutWindow + + + About Minori + Acerca de Minori + + + + AnimeInfoWidget + + + Alternative titles + Títulos alternativos + + + + Details + Información + + + + Type: +Episodes: +Status: +Season: +Genres: +Score: + Formato: +Episodios: +Estado: +Temporada: +Géneros: +Puntuación: + + + + Synopsis + Sinopsis + + + + AnimeListPage + + + + Column visibility + Visibilidad de la columna + + + + Reset to defaults + Restablecer valores predeterminado + + + + Information + Información + + + + Delete from list... + Borrar de la lista... + + + + AnimeListPageModel + + + Anime title + Título del anime + + + + Progress + Progreso + + + + Episodes + Episodios + + + + Type + Formato + + + + Score + Puntuación + + + + Season + Temporada + + + + Date started + Fecha de inicio + + + + Date completed + Fecha de finalización + + + + Notes + Notas + + + + Average score + Puntuación media + + + + Last updated + Última actualización + + + + InformationDialog + + + Anime Information + Información sobre el anime + + + + Main information + Información principal + + + + Anime list + Lista de anime + + + + Episodes watched: + Episodios vistos: + + + + Rewatching + Volver a ver + + + + Status: + Estado: + + + + Score: + Puntuación: + + + + Notes: + Notas: + + + + Enter your notes about this anime + Introduce tus notas sobre este anime + + + + Date started: + Fecha de inicio: + + + + Date completed: + Fecha de finalización: + + + + My list and settings + Mi lista y configuración + + + + MainWindow + + + Now Playing + Jugando ahora + + + + Anime List + Lista de anime + + + + History + Historia + + + + Statistics + Estadísticas + + + + Search + Buscar + + + + Seasons + Temporadas + + + + Torrents + + + + + &File + &Fichero + + + + &Library folders + Directorios de la biblioteca (&L) + + + + &Add new folder... + &Añadir una nueva directorios... + + + + &Scan available episodes + E&scanear episodios disponibles + + + + Play &next episode + Ver el próximo episodio (&N) + + + + Play &random episode + Ver episodio aleato&rio + + + + E&xit + Salida (&X) + + + + &Services + &Servicios + + + + Synchronize &list + Sincronizar &lista + + + + &AniList + &AniList + + + + + + Go to my &profile + Ir a mi &perfil + + + + Go to my &stats + Ir a mis e&stadísticas + + + + &Kitsu + &Kitsu + + + + Go to my &feed + Ir a mi &feed + + + + Go to my &library + Ir a mi biblioteca (&L) + + + + &MyAnimeList + &MyAnimeList + + + + Go to my p&anel + Ir a mi p&anel + + + + Go to my &history + Ir a mi &historia + + + + &Tools + Ins&trumentos + + + + &Export anime list + &Exportar lista de anime + + + + Export as &Markdown... + Exportar como &Markdown... + + + + Export as MyAnimeList &XML... + Exportar como &XML de MyAnimeList + + + + Enable anime &recognition + Activar el &reconocimiento de anime + + + + Enable auto &sharing + Activar el uso compartido automático (&S) + + + + Enable &auto synchronization + Activar la sincronización &automática + + + + &Settings + Configuración (&S) + + + + &View + &Ver + + + + &Now Playing + Jugando ahora (&N) + + + + &Anime List + Lista de &anime + + + + &History + &Historia + + + + &Statistics + E&stadísticas + + + + S&earch + Buscar (&S) + + + + Se&asons + Tempor&adas + + + + &Torrents + + + + + Show sidebar + Mostrar barra lateral + + + + &Help + Ayuda (&H) + + + + &About Minori + &Acerca de Minori + + + + About &Qt + Acerca de &Qt + + + + &Synchronize + &Sincronice + + + + Add new folder... + Añadir una nueva carpeta... + + + + Placeholder + Marcador de posición + + + + S&ettings + Configuración (&S) + + + + NowPlayingPages::Default + + + Now Playing + Jugando ahora + + + + QCoreApplication + + + Currently watching + Actualmente viendo + + + + Plan to watch + Plan para ver + + + + Completed + Completado + + + + Dropped + Dejado + + + + On hold + En espera + + + + Not in list + No en la lista + + + + TV + TV + + + + TV short + Corto + + + + OVA + OVA + + + + Movie + Película + + + + Special + Especial + + + + ONA + ONA + + + + Music + Música + + + + + + Unknown + Desconocido + + + + Winter + Invierno + + + + Summer + Verano + + + + Fall + Otoño + + + + Spring + Primavera + + + + Currently airing + En emisión + + + + Finished airing + Emisión terminada + + + + Not yet aired + Aún no emitido + + + + Cancelled + Cancelado + + + + On hiatus + En pausa + + + + AniList + AniList + + + + None + Ninguno + + + + Native + Nativo + + + + English + Inglés + + + + Romaji + Romaji + + + + Author: + Autor: + + + + Third party components: + Componentes de terceros: + + + + Special thanks: + Agradecimientos especiales: + + + + for creating Taiga + para crear Taiga + + + + and + y + + + + for creating BreezeStyleSheets, on which the dark theme in this program is based off of + para crear BreezeStyleSheets, en el que se basa el tema oscuro de este programa + + + + for providing some sample code for detecting dark mode on Windows and macOS + por proporcionar algunos ejemplos de código para detectar el modo oscuro en Windows y macOS + + + + for providing information on getting open file descriptors on macOS + para obtener información sobre descriptores de archivos abiertos en macOS + + + + SettingsDialog + + + Settings + Configuración + + + + Services + Servicios + + + + Application + Aplicación + + + + SettingsPageApplication + + + Actions + Acciones + + + + Double click: + Haz doble clic: + + + + View anime info + Ver información sobre el anime + + + + Middle click: + Clic central: + + + + Play next episode + Ver el próximo episodio + + + + Appearance + Apariencia + + + + Title language preference: + Preferencia lingüística del título + + + + Romaji + Romaji + + + + Native + Nativo + + + + English + Inglés + + + + Application theme: + Tema de aplicación: + + + + Default + Predeterminado + + + + Light + Luminoso + + + + Dark + Oscuro + + + + Set application locale (requires restart): + Establecer la configuración regional de la aplicación (requiere reinicio): + + + + Display highlighted anime above others + Mostrar el anime destacado por encima de los demás + + + + Highlight anime if next episode is available in library folders + Resaltar el anime si el siguiente episodio está disponible en las directorios de la biblioteca + + + + Progress + Progreso + + + + Display aired episodes (estimated) + Mostrar episodios emitidos (estimación) + + + + Display available episodes in library folders + Mostrar los episodios disponibles en las directorios de la biblioteca + + + + Application + Aplicación + + + + Anime list + Lista de anime + + + + SettingsPageServices + + + Synchronization + Sincronización + + + + Active service and metadata provider: + Proveedor activo de servicios y metadatos: + + + + + AniList + AniList + + + + Note: Minori is unable to synchronize multiple services at the same time. + Nota: Minori no puede sincronizar varios servicios al mismo tiempo. + + + + Account + Cuenta + + + + Username: (not your email address) + Nombre de usuario: (no su dirección de correo electrónico) + + + + Authorize... + Autoriza... + + + + Re-authorize... + Reautorizar... + + + + <a href="http://anilist.co/">Create a new AniList account</a> + <a href="http://anilist.co/">Crear una nueva cuenta AniList</a> + + + + Services + Servicios + + + + Main + Principal + + + + StatisticsPage + + + Anime list + Lista de anime + + + + Anime count: +Episode count: +Time spent watching: +Time to complete: +Average score: +Score deviation: + Recuento de animes: +Recuento de episodios: +Tiempo dedicado a ver: +Tiempo para completar: +Puntuación media: +Desviación de la puntuación: + + + + Score distribution + Distribución de la puntuación + + + + Minori + Minori + + + + Uptime: +Requests made: + Tiempo de actividad: +Peticiones realizadas: + + + diff -r 2004b41d4a59 -r 79714c95a145 src/gui/locale.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gui/locale.cc Mon Nov 06 01:51:44 2023 -0500 @@ -0,0 +1,108 @@ +#include "gui/locale.h" +#include "core/strings.h" +#include +#include +#include +#include +#include +#include + +namespace Locale { + +std::string GetLocaleFullName(const QLocale& locale) { + QString res = QLocale::languageToString(locale.language()); + if (locale.country() != QLocale::AnyCountry) + res += " (" + QLocale::countryToString(locale.country()) + ")"; + return Strings::ToUtf8String(res); +} + +Locale::Locale() { + RefreshAvailableLocales(); + + /* default to en_US */ + if (!IsLocaleAvailable(QLocale())) + SetActiveLocale(QLocale("en_US")); + else /* TODO: is this needed? */ + SetActiveLocale(QLocale()); +} + +Locale::Locale(const std::string& name) { + RefreshAvailableLocales(); + SetActiveLocale(QLocale(Strings::ToQString(name))); +} + +QLocale Locale::GetLocale() { + return _locale; +} + +std::vector Locale::GetAvailableLocales() { + return _available_translations; +} + +void Locale::RefreshAvailableLocales() { + _available_translations.clear(); + + /* we will always have en_US */ + _available_translations.push_back(QLocale("en_US")); + + QDir dir(":/locale"); + if (!dir.exists()) + return; + + QStringList translations = dir.entryList({"*.qm"}, QDir::Files); + + _available_translations.reserve(translations.size()); + for (const QString& str : translations) { + _available_translations.push_back(QLocale(str.mid(0, str.lastIndexOf(".")))); + } +} + +bool Locale::IsLocaleAvailable(const QLocale& locale) { + for (const QLocale& l : _available_translations) + if (l == locale) + return true; + return false; +} + +bool Locale::SetActiveLocale(const QLocale& locale) { + if (!IsLocaleAvailable(locale)) + return false; + if (_locale == locale) + return true; /* we're... already on this locale :) */ + + _locale = locale; + QLocale::setDefault(_locale); + + /* we can still do stuff even if one thing fails! */ + bool return_value = true; + + const QString name = _locale.name(); + if (!SwitchTranslator(_translator, QString(":/locale/%1.qm").arg(name))) + return_value = false; + + const QString path = qApp->applicationDirPath(); + if (!SwitchTranslator(_translator_qt, path + QString("/translations/qt_%1.qm").arg(name))) { + /* Sometimes Qt will have proper translations for the language, but not the specific + country. In that case, we still want to use that language. */ + const int underscore_index = name.lastIndexOf("_"); + if (!underscore_index) + return false; + + const QString short_name = name.mid(0, underscore_index); + if (!SwitchTranslator(_translator_qt, path + QString("/translations/qt_%1.qm").arg(short_name))) + return_value = false; + } + + return return_value; +} + +bool Locale::SwitchTranslator(QTranslator& translator, const QString& path) { + qApp->removeTranslator(&translator); + + if (!translator.load(path)) + return false; + qApp->installTranslator(&translator); + return true; +} + +}