diff --git a/autotests/klocalizedstringtest.h b/autotests/klocalizedstringtest.h --- a/autotests/klocalizedstringtest.h +++ b/autotests/klocalizedstringtest.h @@ -40,11 +40,13 @@ void testLocalizedTranslator(); void semanticTags(); + void multipleLanguages(); private: bool m_hasFrench; + bool m_hasCatalan; QTemporaryDir m_tempDir; - bool compileCatalogs(const QStringList &catalogs, const QDir &dataDir); + bool compileCatalogs(const QStringList &catalogs, const QDir &dataDir, const QString &language); }; #endif // KLOCALIZEDSTRINGTEST_H diff --git a/autotests/klocalizedstringtest.cpp b/autotests/klocalizedstringtest.cpp --- a/autotests/klocalizedstringtest.cpp +++ b/autotests/klocalizedstringtest.cpp @@ -41,6 +41,14 @@ KLocalizedString::setApplicationDomain("ki18n-test"); m_hasFrench = true; + m_hasCatalan = true; + + setlocale(LC_ALL, "ca_ES.utf8"); + if (setlocale(LC_ALL, nullptr) != QByteArray("ca_ES.utf8")) { + qDebug() << "Failed to set locale to ca_ES.utf8."; + m_hasCatalan = false; + } + if (m_hasFrench) { setlocale(LC_ALL, "fr_FR.utf8"); if (setlocale(LC_ALL, nullptr) != QByteArray("fr_FR.utf8")) { @@ -56,7 +64,10 @@ } QDir dataDir(m_tempDir.path()); if (m_hasFrench) { - m_hasFrench = compileCatalogs({QFINDTESTDATA("po/fr/ki18n-test.po"), QFINDTESTDATA("po/fr/ki18n-test-qt.po")}, dataDir); + m_hasFrench = compileCatalogs({QFINDTESTDATA("po/fr/ki18n-test.po"), QFINDTESTDATA("po/fr/ki18n-test-qt.po")}, dataDir, "fr"); + } + if (m_hasCatalan) { + m_hasCatalan = compileCatalogs({QFINDTESTDATA("po/ca/ki18n-test.po")}, dataDir, "ca"); } if (m_hasFrench) { qputenv("XDG_DATA_DIRS", @@ -76,9 +87,10 @@ #endif } -bool KLocalizedStringTest::compileCatalogs(const QStringList &testPoPaths, const QDir &dataDir) +bool KLocalizedStringTest::compileCatalogs(const QStringList &testPoPaths, const QDir &dataDir, const QString &lang) { - if (!dataDir.mkpath("locale/fr/LC_MESSAGES")) { + const QString lcMessages = QString("locale/%1/LC_MESSAGES").arg(lang); + if (!dataDir.mkpath(lcMessages)) { qDebug() << "Failed to create locale subdirectory " "inside temporary directory."; return false; @@ -93,8 +105,8 @@ int pos_2 = testPoPath.lastIndexOf(QLatin1Char('.')); QString domain = testPoPath.mid(pos_1 + 1, pos_2 - pos_1 - 1); QString testMoPath; - testMoPath = QString::fromLatin1("%1/locale/fr/LC_MESSAGES/%2.mo") - .arg(dataDir.path(), domain); + testMoPath = QString::fromLatin1("%1/%3/%2.mo") + .arg(dataDir.path(), domain, lcMessages); QProcess process; QStringList arguments; arguments << testPoPath << QLatin1String("-o") << testMoPath; @@ -438,6 +450,9 @@ QSet availableLanguages; availableLanguages.insert("fr"); availableLanguages.insert("en_US"); + if (m_hasCatalan) { + availableLanguages.insert("ca"); + } QCOMPARE(KLocalizedString::availableApplicationTranslations(), availableLanguages); } @@ -521,14 +536,36 @@ QSKIP("French test files not usable."); } QTemporaryDir dir; - compileCatalogs({QFINDTESTDATA("po/fr/ki18n-test2.po")}, dir.path()); + compileCatalogs({QFINDTESTDATA("po/fr/ki18n-test2.po")}, dir.path(), "fr"); KLocalizedString::addDomainLocaleDir("ki18n-test2", dir.path() + "/locale"); QSet expectedAvailableTranslations({"en_US", "fr"}); QCOMPARE(KLocalizedString::availableDomainTranslations("ki18n-test2"), expectedAvailableTranslations); QCOMPARE(i18nd("ki18n-test2", "Cheese"), QString::fromUtf8("Fromage")); } +void KLocalizedStringTest::multipleLanguages() +{ + if (!m_hasFrench || !m_hasCatalan) { + QSKIP("French or Catalan test files not usable."); + } + KLocalizedString::setLanguages({"ca"}); + QCOMPARE(i18n("Job"), QString::fromUtf8("Job")); // This is not the actual catalan translation but who cares + KLocalizedString::setLanguages({"fr"}); + QCOMPARE(i18n("Job"), QString::fromUtf8("Tâche")); + KLocalizedString::setLanguages({"ca", "fr"}); + QCOMPARE(i18n("Job"), QString::fromUtf8("Job")); // This is not the actual catalan translation but who cares + + + KLocalizedString::setLanguages({"ca"}); + QCOMPARE(i18n("Loadable modules"), QString::fromUtf8("Loadable modules")); // The po doesn't have a translation so we get the English text + KLocalizedString::setLanguages({"fr"}); + QCOMPARE(i18n("Loadable modules"), QString::fromUtf8("Modules chargeables")); + KLocalizedString::setLanguages({"ca", "fr"}); + QCOMPARE(i18n("Loadable modules"), QString::fromUtf8("Modules chargeables")); // The Catalan po doesn't have a translation so we get the English text +} + + #include #include #include diff --git a/autotests/po/ca/ki18n-test.po b/autotests/po/ca/ki18n-test.po new file mode 100644 --- /dev/null +++ b/autotests/po/ca/ki18n-test.po @@ -0,0 +1,21 @@ +msgid "" +msgstr "" +"Project-Id-Version: ki18n-test\n" +"POT-Creation-Date: 2012-01-01 00:00+0100\n" +"PO-Revision-Date: 2012-01-01 12:00+0100\n" +"Last-Translator: Catalunya \n" +"Language-Team: Catalan \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +# This is not a real Catalan translation, but +# who cares, it makes the test easier +msgid "Job" +msgstr "Job" + +# Untranslated on purpose +msgid "Loadable modules" +msgstr "" diff --git a/src/kcatalog.cpp b/src/kcatalog.cpp --- a/src/kcatalog.cpp +++ b/src/kcatalog.cpp @@ -211,9 +211,10 @@ if (!d->localeDir.isEmpty()) { QMutexLocker locker(&catalogStaticData()->mutex); d->setupGettextEnv(); - const char *msgstr = dgettext(d->domain.constData(), msgid.constData()); + const char *msgid_char = msgid.constData(); + const char *msgstr = dgettext(d->domain.constData(), msgid_char); d->resetSystemLanguage(); - return msgstr != msgid + return msgstr != msgid_char // Yes we want pointer comparison ? QString::fromUtf8(msgstr) : QString(); } else { @@ -227,9 +228,10 @@ if (!d->localeDir.isEmpty()) { QMutexLocker locker(&catalogStaticData()->mutex); d->setupGettextEnv(); - const char *msgstr = dpgettext_expr(d->domain.constData(), msgctxt.constData(), msgid.constData()); + const char *msgid_char = msgid.constData(); + const char *msgstr = dpgettext_expr(d->domain.constData(), msgctxt.constData(), msgid_char); d->resetSystemLanguage(); - return msgstr != msgid + return msgstr != msgid_char // Yes we want pointer comparison ? QString::fromUtf8(msgstr) : QString(); } else { @@ -244,14 +246,16 @@ if (!d->localeDir.isEmpty()) { QMutexLocker locker(&catalogStaticData()->mutex); d->setupGettextEnv(); - const char *msgstr = dngettext(d->domain.constData(), msgid.constData(), msgid_plural.constData(), n); + const char *msgid_char = msgid.constData(); + const char *msgid_plural_char = msgid_plural.constData(); + const char *msgstr = dngettext(d->domain.constData(), msgid_char, msgid_plural_char, n); d->resetSystemLanguage(); // If original and translation are same, dngettext will return // the original pointer, which is generally fine, except in // the corner cases where e.g. msgstr[1] is same as msgid. // Therefore check for pointer difference only with msgid or // only with msgid_plural, and not with both. - return (n == 1 && msgstr != msgid) || (n != 1 && msgstr != msgid_plural) + return (n == 1 && msgstr != msgid_char) || (n != 1 && msgstr != msgid_plural_char) ? QString::fromUtf8(msgstr) : QString(); } else { @@ -267,9 +271,11 @@ if (!d->localeDir.isEmpty()) { QMutexLocker locker(&catalogStaticData()->mutex); d->setupGettextEnv(); - const char *msgstr = dnpgettext_expr(d->domain.constData(), msgctxt.constData(), msgid.constData(), msgid_plural.constData(), n); + const char *msgid_char = msgid.constData(); + const char *msgid_plural_char = msgid_plural.constData(); + const char *msgstr = dnpgettext_expr(d->domain.constData(), msgctxt.constData(), msgid_char, msgid_plural_char, n); d->resetSystemLanguage(); - return (n == 1 && msgstr != msgid) || (n != 1 && msgstr != msgid_plural) + return (n == 1 && msgstr != msgid_char) || (n != 1 && msgstr != msgid_plural_char) ? QString::fromUtf8(msgstr) : QString(); } else {