File indexing completed on 2024-11-24 03:56:29

0001 /*
0002  * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best>
0003  *
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  */
0006 
0007 #include "translation_service.hpp"
0008 
0009 #include <QLocale>
0010 #include <QTranslator>
0011 #include <QCoreApplication>
0012 #include <QRegularExpression>
0013 
0014 #include "app/application.hpp"
0015 #include "app/log/log.hpp"
0016 
0017 void app::TranslationService::initialize ( QString default_lang_code )
0018 {
0019     if ( !default_lang_code.isEmpty() )
0020     {
0021         QString name = language_name(default_lang_code);
0022         if ( !name.isEmpty() )
0023             register_translation(name,default_lang_code, QString());
0024     }
0025 
0026     QDir translations = Application::instance()->data_file("translations");
0027     QStringList translation_files = translations.entryList({"*.qm"});
0028 
0029     QRegularExpression re("[^_]+_([^.]+)\\.qm");
0030     for (auto &file: std::as_const(translation_files))
0031     {
0032         auto match = re.match(file);
0033         if ( match.hasMatch() )
0034         {
0035             QString code = match.captured(1);
0036             QString name = language_name(code);
0037             if ( !name.isEmpty() )
0038                 register_translation(name,code,translations.absoluteFilePath(file));
0039         }
0040         else
0041         {
0042             log::LogStream("Translations") << "Unrecognised translation file name pattern:" << file;
0043         }
0044     }
0045 
0046     change_lang_code(QLocale::system().name());
0047 }
0048 
0049 QString app::TranslationService::language_name(QString lang_code)
0050 {
0051     QLocale lang_loc = QLocale(lang_code);
0052     QString name = lang_loc.nativeLanguageName();
0053     QString specifier;
0054 
0055     if ( lang_code.contains("_") )
0056     {
0057         if ( lang_loc.script() != QLocale::AnyScript )
0058             specifier = QLocale::scriptToString(lang_loc.script());
0059 
0060 #if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
0061         if ( lang_loc.territory() != QLocale::AnyTerritory )
0062         {
0063             if ( !specifier.isEmpty() )
0064                 specifier += ", ";
0065             specifier = lang_loc.nativeTerritoryName();
0066         }
0067 #else
0068         if ( lang_loc.country() != QLocale::AnyCountry )
0069         {
0070             if ( !specifier.isEmpty() )
0071                 specifier += ", ";
0072             specifier = lang_loc.nativeCountryName();
0073         }
0074 #endif
0075     }
0076 
0077     if ( !name.isEmpty() )
0078     {
0079         name[0] = name[0].toUpper();
0080         if ( !specifier.isEmpty() )
0081             name += " (" + specifier + ")";
0082     }
0083 
0084     return name;
0085 }
0086 
0087 
0088 void app::TranslationService::register_translation(QString name, QString code, QString file)
0089 {
0090     lang_names[name] = code;
0091     if ( !file.isEmpty() )
0092     {
0093         translators[code] = new QTranslator;
0094         if ( !translators[code]->load(file) )
0095         {
0096             log::Log("Translations").log(
0097                 QString("Error on loading translation file %1 for language %2 (%3)")
0098                 .arg(file).arg(name).arg(code)
0099             );
0100         }
0101     }
0102 }
0103 
0104 
0105 
0106 QString app::TranslationService::current_language_name()
0107 {
0108     return lang_names.key(current_language);
0109 }
0110 
0111 QString app::TranslationService::current_language_code()
0112 {
0113     return current_language;
0114 }
0115 
0116 QTranslator *app::TranslationService::translator()
0117 {
0118     return translators[current_language];
0119 }
0120 
0121 const QMap<QString, QString>& app::TranslationService::available_languages()
0122 {
0123     return lang_names;
0124 }
0125 
0126 void app::TranslationService::change_lang_code(QString code)
0127 {
0128 
0129     if ( !translators.contains(code) )
0130     {
0131         QString base_code = code.left(code.lastIndexOf('_')); // en_US -> en
0132         bool found = false;
0133         for (const auto &installed_code: translators.keys())
0134         {
0135             if ( installed_code.left(installed_code.lastIndexOf('_')) == base_code )
0136             {
0137                 code = installed_code;
0138                 found = true;
0139                 break;
0140             }
0141         }
0142         if ( !found )
0143         {
0144             log::Log("Translations").log(
0145                 QString("There is no translation for language %1 (%2)")
0146                 .arg(language_name(code))
0147                 .arg(code)
0148             );
0149             return;
0150         }
0151     }
0152 
0153     QCoreApplication* app = QCoreApplication::instance();
0154     app->removeTranslator(translator());
0155     current_language = code;
0156     app->installTranslator(translator());
0157 }