From 5e3062291922189a215b81a0ae4fc4022ace597b Mon Sep 17 00:00:00 2001 From: =?utf8?q?V=C3=A1clav=20Slav=C3=ADk?= Date: Wed, 16 Jun 2010 14:09:32 +0000 Subject: [PATCH] Add wxTranslations::GetAvailableTranslations(). git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@64597 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/changes.txt | 1 + include/wx/translation.h | 10 +++ interface/wx/translation.h | 14 ++++ src/common/translation.cpp | 166 ++++++++++++++++++++++++++++++++----- 4 files changed, 170 insertions(+), 21 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index 12422a6ed6..ebca103e84 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -446,6 +446,7 @@ All: - Added IEC and SI units support to GetHumanReadableSize() (Julien Weinzorn). - Add convenient wxString::ToStd{String,Wstring}() helpers. - Added wxTranslations class to allow localization without changing locale. + It provides more flexible languages enumeration API as well. - Added wxResourceTranslationsLoader for loading translations from Windows resources. - Added wxMessageQueue::Clear(). diff --git a/include/wx/translation.h b/include/wx/translation.h index 344379ec36..67b2bd8afc 100644 --- a/include/wx/translation.h +++ b/include/wx/translation.h @@ -48,6 +48,7 @@ // forward decls // ---------------------------------------------------------------------------- +class WXDLLIMPEXP_FWD_BASE wxArrayString; class WXDLLIMPEXP_FWD_BASE wxTranslationsLoader; class WXDLLIMPEXP_FWD_BASE wxLocale; @@ -128,6 +129,9 @@ public: void SetLanguage(wxLanguage lang); void SetLanguage(const wxString& lang); + // get languages available for this app + wxArrayString GetAvailableTranslations(const wxString& domain) const; + // add standard wxWidgets catalog ("wxstd") bool AddStdCatalog(); @@ -192,6 +196,8 @@ public: virtual wxMsgCatalog *LoadCatalog(const wxString& domain, const wxString& lang) = 0; + + virtual wxArrayString GetAvailableTranslations(const wxString& domain) const = 0; }; @@ -204,6 +210,8 @@ public: virtual wxMsgCatalog *LoadCatalog(const wxString& domain, const wxString& lang); + + virtual wxArrayString GetAvailableTranslations(const wxString& domain) const; }; @@ -216,6 +224,8 @@ public: virtual wxMsgCatalog *LoadCatalog(const wxString& domain, const wxString& lang); + virtual wxArrayString GetAvailableTranslations(const wxString& domain) const; + protected: // returns resource type to use for translations virtual wxString GetResourceType() const { return "MOFILE"; } diff --git a/interface/wx/translation.h b/interface/wx/translation.h index fc1c35a229..069d4994f9 100644 --- a/interface/wx/translation.h +++ b/interface/wx/translation.h @@ -79,6 +79,15 @@ public: */ void SetLanguage(const wxString& lang); + /** + Returns list of all translations of @a domain that were found. + + This method can be used e.g. to populate list of application's + translations offered to the user. To do this, pass the app's main + catalog as @a domain. + */ + wxArrayString GetAvailableTranslations(const wxString& domain) const; + /** Add standard wxWidgets catalogs ("wxstd" and possible port-specific catalogs). @@ -265,6 +274,11 @@ public: */ virtual wxMsgCatalog *LoadCatalog(const wxString& domain, const wxString& lang) = 0; + + /** + Implements wxTranslations::GetAvailableTranslations(). + */ + virtual wxArrayString GetAvailableTranslations(const wxString& domain) const = 0; }; /** diff --git a/src/common/translation.cpp b/src/common/translation.cpp index 1e89106f9a..71a16ca847 100644 --- a/src/common/translation.cpp +++ b/src/common/translation.cpp @@ -41,6 +41,8 @@ #include #include +#include "wx/arrstr.h" +#include "wx/dir.h" #include "wx/file.h" #include "wx/filename.h" #include "wx/tokenzr.h" @@ -48,6 +50,10 @@ #include "wx/stdpaths.h" #include "wx/hashset.h" +#ifdef __WXMSW__ + #include "wx/msw/wrapwin.h" +#endif + // ---------------------------------------------------------------------------- // simple types // ---------------------------------------------------------------------------- @@ -1286,6 +1292,14 @@ void wxTranslations::SetLanguage(const wxString& lang) } +wxArrayString wxTranslations::GetAvailableTranslations(const wxString& domain) const +{ + wxCHECK_MSG( m_loader, false, "loader can't be NULL" ); + + return m_loader->GetAvailableTranslations(domain); +} + + bool wxTranslations::AddStdCatalog() { if ( !AddCatalog(wxS("wxstd")) ) @@ -1348,6 +1362,7 @@ bool wxTranslations::AddCatalog(const wxString& domain, bool wxTranslations::LoadCatalog(const wxString& domain, const wxString& lang) { + m_loader->GetAvailableTranslations(domain); wxCHECK_MSG( m_loader, false, "loader can't be NULL" ); wxMsgCatalog *cat = NULL; @@ -1599,25 +1614,33 @@ wxString GetMsgCatalogSubdirs(const wxString& prefix, const wxString& lang) return searchPath; } -// construct the search path for the given language -static wxString GetFullSearchPath(const wxString& lang) +bool HasMsgCatalogInDir(const wxString& dir, const wxString& domain) +{ + return wxFileName(dir, domain, "mo").FileExists() || + wxFileName(dir + wxFILE_SEP_PATH + "LC_MESSAGES", domain, "mo").FileExists(); +} + +// get prefixes to locale directories; if lang is empty, don't point to +// OSX's .lproj bundles +wxArrayString GetSearchPrefixes(const wxString& lang = wxString()) { - // first take the entries explicitly added by the program wxArrayString paths; - paths.reserve(gs_searchPrefixes.size() + 1); - size_t n, - count = gs_searchPrefixes.size(); - for ( n = 0; n < count; n++ ) - { - paths.Add(GetMsgCatalogSubdirs(gs_searchPrefixes[n], lang)); - } + // first take the entries explicitly added by the program + paths = gs_searchPrefixes; #if wxUSE_STDPATHS // then look in the standard location - const wxString stdp = wxStandardPaths::Get(). - GetLocalizedResourcesDir(lang, wxStandardPaths::ResourceCat_Messages); - + wxString stdp; + if ( lang.empty() ) + { + stdp = wxStandardPaths::Get().GetResourcesDir(); + } + else + { + stdp = wxStandardPaths::Get(). + GetLocalizedResourcesDir(lang, wxStandardPaths::ResourceCat_Messages); + } if ( paths.Index(stdp) == wxNOT_FOUND ) paths.Add(stdp); #endif // wxUSE_STDPATHS @@ -1629,7 +1652,7 @@ static wxString GetFullSearchPath(const wxString& lang) const char *pszLcPath = wxGetenv("LC_PATH"); if ( pszLcPath ) { - const wxString lcp = GetMsgCatalogSubdirs(pszLcPath, lang); + const wxString lcp = pszLcPath; if ( paths.Index(lcp) == wxNOT_FOUND ) paths.Add(lcp); } @@ -1638,22 +1661,32 @@ static wxString GetFullSearchPath(const wxString& lang) wxString wxp = wxGetInstallPrefix(); if ( !wxp.empty() ) { - wxp = GetMsgCatalogSubdirs(wxp + wxS("/share/locale"), lang); + wxp += wxS("/share/locale"); if ( paths.Index(wxp) == wxNOT_FOUND ) paths.Add(wxp); } #endif // __UNIX__ + return paths; +} - // finally construct the full search path +// construct the search path for the given language +wxString GetFullSearchPath(const wxString& lang) +{ wxString searchPath; searchPath.reserve(500); - count = paths.size(); - for ( n = 0; n < count; n++ ) + + const wxArrayString prefixes = GetSearchPrefixes(lang); + + for ( wxArrayString::const_iterator i = prefixes.begin(); + i != prefixes.end(); + ++i ) { - searchPath += paths[n]; - if ( n != count - 1 ) + const wxString p = GetMsgCatalogSubdirs(*i, lang); + + if ( !searchPath.empty() ) searchPath += wxPATH_SEP; + searchPath += p; } return searchPath; @@ -1695,15 +1728,57 @@ wxMsgCatalog *wxFileTranslationsLoader::LoadCatalog(const wxString& domain, } +wxArrayString wxFileTranslationsLoader::GetAvailableTranslations(const wxString& domain) const +{ + wxArrayString langs; + const wxArrayString prefixes = GetSearchPrefixes(); + + wxLogTrace(TRACE_I18N, + "looking for available translations of \"%s\" in search path \"%s\"", + domain, wxJoin(prefixes, wxPATH_SEP[0])); + + for ( wxArrayString::const_iterator i = prefixes.begin(); + i != prefixes.end(); + ++i ) + { + wxDir dir; + if ( !dir.Open(*i) ) + continue; + + wxString lang; + for ( bool ok = dir.GetFirst(&lang, "", wxDIR_DIRS); + ok; + ok = dir.GetNext(&lang) ) + { + const wxString langdir = *i + wxFILE_SEP_PATH + lang; + if ( HasMsgCatalogInDir(langdir, domain) ) + { +#ifdef __WXOSX__ + wxString rest; + if ( lang.EndsWith(".lproj", &rest) ) + lang = rest; +#endif // __WXOSX__ + + wxLogTrace(TRACE_I18N, + "found %s translation of \"%s\"", lang, domain); + langs.push_back(lang); + } + } + } + + return langs; +} + + // ---------------------------------------------------------------------------- // wxResourceTranslationsLoader // ---------------------------------------------------------------------------- #ifdef __WINDOWS__ + wxMsgCatalog *wxResourceTranslationsLoader::LoadCatalog(const wxString& domain, const wxString& lang) { - const void *mo_data = NULL; size_t mo_size = 0; @@ -1727,6 +1802,55 @@ wxMsgCatalog *wxResourceTranslationsLoader::LoadCatalog(const wxString& domain, return cat; } + +namespace +{ + +struct EnumCallbackData +{ + wxString prefix; + wxArrayString langs; +}; + +BOOL CALLBACK EnumTranslations(HMODULE WXUNUSED(hModule), + LPCTSTR WXUNUSED(lpszType), + LPTSTR lpszName, + LONG_PTR lParam) +{ + wxString name(lpszName); + name.MakeLower(); // resource names are case insensitive + + EnumCallbackData *data = reinterpret_cast(lParam); + + wxString lang; + if ( name.StartsWith(data->prefix, &lang) && !lang.empty() ) + data->langs.push_back(lang); + + return TRUE; // continue enumeration +} + +} // anonymous namespace + + +wxArrayString wxResourceTranslationsLoader::GetAvailableTranslations(const wxString& domain) const +{ + EnumCallbackData data; + data.prefix = domain + "_"; + data.prefix.MakeLower(); // resource names are case insensitive + + if ( !EnumResourceNames(GetModule(), + GetResourceType(), + EnumTranslations, + reinterpret_cast(&data)) ) + { + const DWORD err = GetLastError(); + if ( err != NO_ERROR && err != ERROR_RESOURCE_TYPE_NOT_FOUND ) + wxLogSysError(_("Couldn't enumerate translations")); + } + + return data.langs; +} + #endif // __WINDOWS__ -- 2.45.2