From 2af36e9560c694a750b6aa835d32d12a0393fb83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Va=CC=81clav=20Slavi=CC=81k?= Date: Fri, 9 Feb 2024 18:33:22 +0100 Subject: [PATCH] Partially revert "Add AddAvailableCatalog() and use it in AddStdCatalog()" This commit partially reverts 94b1a17aeb12a1ec723a255089be16cd31a268a2. The above commit changed translation lookup logic to differentiate between msgid and "available" translations (the latter being loaded from a file or resource). It first attempted to use available translations and only felt back to msgid language as the last resort. Unfortunately, doing that broke lookup in cases when the user had msgid language as not-last preference in their UI languages list, or even when a similar translation was available. For example: - msgid=en, user preference [cs,en,fr], only fr.po available: fr would be used instead of en - msgid=en_US or en, user preference [en], but en_GB.po available: British English would be used even for US users This commit fixes this by restoring the previous behavior where msgid language was treated as a first-class citizen in lookup, while preserving the API that allows distinguishing between the two cases. It also reimplements AddStdCatalog() in a more straightforward way that doesn't rely on AddAvailableCatalog(). --- include/wx/translation.h | 2 + src/common/translation.cpp | 97 +++++++++++++++++++------------------- 2 files changed, 50 insertions(+), 49 deletions(-) diff --git a/include/wx/translation.h b/include/wx/translation.h index ca97649a4b..0f38931d2f 100644 --- a/include/wx/translation.h +++ b/include/wx/translation.h @@ -203,6 +203,8 @@ private: static void SetNonOwned(wxTranslations *t); friend class wxLocale; + wxString DoGetBestAvailableTranslation(const wxString& domain, const wxString& additionalAvailableLanguage); + private: wxString m_lang; wxTranslationsLoader *m_loader; diff --git a/src/common/translation.cpp b/src/common/translation.cpp index 7ced54853d..6ed764df5b 100644 --- a/src/common/translation.cpp +++ b/src/common/translation.cpp @@ -1308,13 +1308,11 @@ bool wxTranslations::AddStdCatalog() // the name without the version if it's not found, as message catalogs // typically won't have the version in their names under non-Unix platforms // (i.e. where they're not installed by our own "make install"). - if ( AddAvailableCatalog("wxstd-" wxSTRINGIZE(wxMAJOR_VERSION) "." wxSTRINGIZE(wxMINOR_VERSION)) ) - return true; + wxString domain("wxstd-" wxSTRINGIZE(wxMAJOR_VERSION) "." wxSTRINGIZE(wxMINOR_VERSION)); + if ( GetBestAvailableTranslation(domain).empty() ) + domain = wxS("wxstd"); - if ( AddCatalog(wxS("wxstd")) ) - return true; - - return false; + return AddCatalog(domain); } bool wxTranslations::AddAvailableCatalog(const wxString& domain) @@ -1334,39 +1332,30 @@ bool wxTranslations::AddAvailableCatalog(const wxString& domain) bool wxTranslations::AddCatalog(const wxString& domain, wxLanguage msgIdLanguage) { - if ( AddAvailableCatalog(domain) ) - return true; - const wxString msgIdLang = wxUILocale::GetLanguageCanonicalName(msgIdLanguage); - - // Check if the original strings can be used directly. - bool canUseUntranslated = false; - if ( m_lang.empty() ) - { - // If we are using the default language, check if the message ID - // language is acceptable for this system. - const wxString domain_lang = GetBestTranslation(domain, msgIdLang); - - if ( msgIdLang == domain_lang ) - canUseUntranslated = true; - } - else // But if we have a fixed language, we should just check it instead. - { - // Consider message IDs for another region using the same language - // acceptable. - if ( msgIdLang.BeforeFirst('_') == m_lang.BeforeFirst('_') ) - canUseUntranslated = true; - } - - if ( canUseUntranslated ) + const wxString domain_lang = GetBestTranslation(domain, msgIdLang); + if ( domain_lang.empty() ) { wxLogTrace(TRACE_I18N, - wxS("not using translations for domain '%s' with msgid language '%s'"), - domain, msgIdLang); + wxS("no suitable translation for domain '%s' found"), + domain); + return false; + } + + if ( LoadCatalog(domain, domain_lang) ) + { + wxLogTrace(TRACE_I18N, + wxS("adding '%s' translation for domain '%s' (msgid language '%s')"), + domain_lang, domain, msgIdLang); return true; } - return false; + // LoadCatalog() failed, but GetBestTranslation() returned non-empty language. + // That must mean that msgIdLanguage was used. + wxLogTrace(TRACE_I18N, + wxS("not using translations for domain '%s' with msgid language '%s'"), + domain, msgIdLang); + return true; } @@ -1444,23 +1433,19 @@ wxString wxTranslations::GetBestTranslation(const wxString& domain, wxString wxTranslations::GetBestTranslation(const wxString& domain, const wxString& msgIdLanguage) { - wxString lang = GetBestAvailableTranslation(domain); + // Determine the best language, including the msgId language, which is always + // available because it is present in the code: + wxString lang = DoGetBestAvailableTranslation(domain, msgIdLanguage); + if ( lang.empty() ) { - wxArrayString available; - available.push_back(msgIdLanguage); - available.push_back(msgIdLanguage.BeforeFirst('_')); - lang = GetPreferredUILanguage(available); - if ( lang.empty() ) - { - wxLogTrace(TRACE_I18N, - "no available language for domain '%s'", domain); - } - else - { - wxLogTrace(TRACE_I18N, - "using message ID language '%s' for domain '%s'", lang); - } + wxLogTrace(TRACE_I18N, + "no available language for domain '%s'", domain); + } + else if ( lang == msgIdLanguage || lang == msgIdLanguage.BeforeFirst('_') ) + { + wxLogTrace(TRACE_I18N, + "using message ID language '%s' for domain '%s'", lang, domain); } return lang; @@ -1468,7 +1453,21 @@ wxString wxTranslations::GetBestTranslation(const wxString& domain, wxString wxTranslations::GetBestAvailableTranslation(const wxString& domain) { - const wxArrayString available(GetAvailableTranslations(domain)); + // Determine the best language from the ones with actual translation file: + // As this function never considers the language of the original messages as being + // available, pass empty string as message ID language to the helper function. + return DoGetBestAvailableTranslation(domain, wxString()); +} + +wxString wxTranslations::DoGetBestAvailableTranslation(const wxString& domain, const wxString& additionalAvailableLanguage) +{ + wxArrayString available(GetAvailableTranslations(domain)); + if ( !additionalAvailableLanguage.empty() ) + { + available.push_back(additionalAvailableLanguage); + available.push_back(additionalAvailableLanguage.BeforeFirst('_')); + } + if ( !m_lang.empty() ) { wxLogTrace(TRACE_I18N,