File indexing completed on 2024-05-19 04:56:13
0001 /** 0002 * \file loadtranslation.cpp 0003 * Load application translation. 0004 * 0005 * \b Project: Kid3 0006 * \author Urs Fleisch 0007 * \date 26 Mar 2013 0008 * 0009 * Copyright (C) 2013-2024 Urs Fleisch 0010 * 0011 * This file is part of Kid3. 0012 * 0013 * Kid3 is free software; you can redistribute it and/or modify 0014 * it under the terms of the GNU General Public License as published by 0015 * the Free Software Foundation; either version 2 of the License, or 0016 * (at your option) any later version. 0017 * 0018 * Kid3 is distributed in the hope that it will be useful, 0019 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0021 * GNU General Public License for more details. 0022 * 0023 * You should have received a copy of the GNU General Public License 0024 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0025 */ 0026 0027 #include "loadtranslation.h" 0028 #include <QCoreApplication> 0029 #include <QStringList> 0030 #include <QLibraryInfo> 0031 #include <QLocale> 0032 #include <QTranslator> 0033 #include <QFileInfo> 0034 #include <QDir> 0035 #include "config.h" 0036 0037 namespace { 0038 0039 const char* const QT_TRANSLATION_PREFIX = "qtbase_"; 0040 0041 } 0042 0043 /** 0044 * @brief Load application translation. 0045 * 0046 * @param lang preferred language, if not set, the language is determined by 0047 * the system configuration 0048 */ 0049 void Utils::loadTranslation(const QString& lang) 0050 { 0051 QLocale locale; 0052 0053 QStringList languages( 0054 #ifndef Q_OS_WIN32 0055 locale.uiLanguages() 0056 #else 0057 locale.name() 0058 #endif 0059 ); 0060 if (!lang.isEmpty()) { 0061 languages.prepend(lang); 0062 } 0063 0064 // Fix the translations returned from QLocale::uiLanguages() if '_' or '@' 0065 // have been replaced by '-'. "zh_CN" is returned as "zh-CN", "sr@latin" as 0066 // "sr-latin". Both "sr@ijekavian" and "sr@ijekavianlatin" give "sr-ijekavia", 0067 // so this case cannot be fixed. 0068 for (auto it = languages.begin(); it != languages.end(); ++it) { 0069 const int len = it->length(); 0070 if (const int dashPos = it->lastIndexOf(QLatin1Char('-')); 0071 dashPos > 0 && dashPos < len -1) { 0072 (*it)[dashPos] = QLatin1Char(dashPos == len - 3 ? '_' : '@'); 0073 } 0074 // Some more fixes for languages encountered on macOS, 0075 // e.g. "sr-Latn_SP", "zh-Hant_TW". 0076 it->replace(QLatin1String("@Latn"), QLatin1String("@latin")) 0077 .replace(QLatin1String("-Latn"), QLatin1String("@latin")) 0078 .remove(QLatin1String("-Hant")) 0079 .remove(QLatin1String("-Hans")); 0080 } 0081 0082 QString translationsDir; 0083 #ifdef CFG_TRANSLATIONSDIR 0084 translationsDir = QLatin1String(CFG_TRANSLATIONSDIR); 0085 prependApplicationDirPathIfRelative(translationsDir); 0086 #endif 0087 0088 // '-' is added to default delimiters because it is used on Mac OS X instead 0089 // of '_'. 0090 const QString searchDelimiters(QLatin1String("_.-")); 0091 0092 // translation file for Qt 0093 auto qtTr = new QTranslator(qApp); 0094 const auto localeNames = languages; 0095 for (const QString& localeName : localeNames) { 0096 if ( 0097 localeName.startsWith(QLatin1String("en")) || 0098 (!translationsDir.isNull() && 0099 qtTr->load(QLatin1String(QT_TRANSLATION_PREFIX) + localeName, 0100 translationsDir, searchDelimiters)) || 0101 qtTr->load(QLatin1String(QT_TRANSLATION_PREFIX) + localeName, 0102 QLatin1String("."), searchDelimiters) 0103 #if !(defined Q_OS_WIN32 || defined Q_OS_MAC || defined Q_OS_ANDROID) 0104 || qtTr->load(QLatin1String(QT_TRANSLATION_PREFIX) + localeName, 0105 #if QT_VERSION >= 0x060000 0106 QLibraryInfo::path(QLibraryInfo::TranslationsPath), 0107 #else 0108 QLibraryInfo::location(QLibraryInfo::TranslationsPath), 0109 #endif 0110 searchDelimiters) 0111 #endif 0112 ) { 0113 break; 0114 } 0115 } 0116 qApp->installTranslator(qtTr); 0117 0118 // translation file for application strings 0119 auto kid3Tr = new QTranslator(qApp); 0120 for (const QString& localeName : localeNames) { 0121 if ( 0122 (!translationsDir.isNull() && 0123 kid3Tr->load(QLatin1String("kid3_") + localeName, translationsDir, 0124 searchDelimiters)) || 0125 kid3Tr->load(QLatin1String("kid3_") + localeName, QLatin1String("."), 0126 searchDelimiters) || 0127 localeName.startsWith(QLatin1String("en")) 0128 ) { 0129 break; 0130 } 0131 } 0132 qApp->installTranslator(kid3Tr); 0133 } 0134 0135 /** 0136 * Prepend the application directory path to a path if it is relative. 0137 * 0138 * @param path file or directory path, will be modified if relative 0139 */ 0140 void Utils::prependApplicationDirPathIfRelative(QString& path) 0141 { 0142 if (QFileInfo(path).isRelative()) { 0143 if (QString appDir = QCoreApplication::applicationDirPath(); 0144 !appDir.isEmpty()) { 0145 if (!appDir.endsWith(QLatin1Char('/'))) { 0146 appDir.append(QLatin1Char('/')); 0147 } 0148 path.prepend(appDir); 0149 } 0150 } 0151 } 0152 0153 /** 0154 * Load list of available translations. 0155 * @return language codes of installed translations, e.g. {"de", "en", ...}. 0156 */ 0157 QStringList Utils::availableTranslations() 0158 { 0159 QString translationsDir; 0160 #ifdef CFG_TRANSLATIONSDIR 0161 translationsDir = QLatin1String(CFG_TRANSLATIONSDIR); 0162 prependApplicationDirPathIfRelative(translationsDir); 0163 #endif 0164 QDir dir(translationsDir); 0165 const QStringList fileNames = dir.entryList({QLatin1String("kid3_*.qm")}, 0166 QDir::Files, QDir::Name); 0167 QStringList languages; 0168 for (const auto& fileName : fileNames) { 0169 languages.append(fileName.mid(5, fileName.length() - 8)); 0170 } 0171 return languages; 0172 }