Add wxTranslations::GetAvailableTranslations().

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@64597 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Václav Slavík
2010-06-16 14:09:32 +00:00
parent 6589f1a49a
commit 5e30622919
4 changed files with 171 additions and 22 deletions

View File

@@ -446,6 +446,7 @@ All:
- Added IEC and SI units support to GetHumanReadableSize() (Julien Weinzorn). - Added IEC and SI units support to GetHumanReadableSize() (Julien Weinzorn).
- Add convenient wxString::ToStd{String,Wstring}() helpers. - Add convenient wxString::ToStd{String,Wstring}() helpers.
- Added wxTranslations class to allow localization without changing locale. - 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 - Added wxResourceTranslationsLoader for loading translations from Windows
resources. resources.
- Added wxMessageQueue::Clear(). - Added wxMessageQueue::Clear().

View File

@@ -48,6 +48,7 @@
// forward decls // forward decls
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
class WXDLLIMPEXP_FWD_BASE wxArrayString;
class WXDLLIMPEXP_FWD_BASE wxTranslationsLoader; class WXDLLIMPEXP_FWD_BASE wxTranslationsLoader;
class WXDLLIMPEXP_FWD_BASE wxLocale; class WXDLLIMPEXP_FWD_BASE wxLocale;
@@ -128,6 +129,9 @@ public:
void SetLanguage(wxLanguage lang); void SetLanguage(wxLanguage lang);
void SetLanguage(const wxString& lang); void SetLanguage(const wxString& lang);
// get languages available for this app
wxArrayString GetAvailableTranslations(const wxString& domain) const;
// add standard wxWidgets catalog ("wxstd") // add standard wxWidgets catalog ("wxstd")
bool AddStdCatalog(); bool AddStdCatalog();
@@ -192,6 +196,8 @@ public:
virtual wxMsgCatalog *LoadCatalog(const wxString& domain, virtual wxMsgCatalog *LoadCatalog(const wxString& domain,
const wxString& lang) = 0; const wxString& lang) = 0;
virtual wxArrayString GetAvailableTranslations(const wxString& domain) const = 0;
}; };
@@ -204,6 +210,8 @@ public:
virtual wxMsgCatalog *LoadCatalog(const wxString& domain, virtual wxMsgCatalog *LoadCatalog(const wxString& domain,
const wxString& lang); const wxString& lang);
virtual wxArrayString GetAvailableTranslations(const wxString& domain) const;
}; };
@@ -216,6 +224,8 @@ public:
virtual wxMsgCatalog *LoadCatalog(const wxString& domain, virtual wxMsgCatalog *LoadCatalog(const wxString& domain,
const wxString& lang); const wxString& lang);
virtual wxArrayString GetAvailableTranslations(const wxString& domain) const;
protected: protected:
// returns resource type to use for translations // returns resource type to use for translations
virtual wxString GetResourceType() const { return "MOFILE"; } virtual wxString GetResourceType() const { return "MOFILE"; }

View File

@@ -79,6 +79,15 @@ public:
*/ */
void SetLanguage(const wxString& lang); 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 Add standard wxWidgets catalogs ("wxstd" and possible port-specific
catalogs). catalogs).
@@ -265,6 +274,11 @@ public:
*/ */
virtual wxMsgCatalog *LoadCatalog(const wxString& domain, virtual wxMsgCatalog *LoadCatalog(const wxString& domain,
const wxString& lang) = 0; const wxString& lang) = 0;
/**
Implements wxTranslations::GetAvailableTranslations().
*/
virtual wxArrayString GetAvailableTranslations(const wxString& domain) const = 0;
}; };
/** /**

View File

@@ -41,6 +41,8 @@
#include <ctype.h> #include <ctype.h>
#include <stdlib.h> #include <stdlib.h>
#include "wx/arrstr.h"
#include "wx/dir.h"
#include "wx/file.h" #include "wx/file.h"
#include "wx/filename.h" #include "wx/filename.h"
#include "wx/tokenzr.h" #include "wx/tokenzr.h"
@@ -48,6 +50,10 @@
#include "wx/stdpaths.h" #include "wx/stdpaths.h"
#include "wx/hashset.h" #include "wx/hashset.h"
#ifdef __WXMSW__
#include "wx/msw/wrapwin.h"
#endif
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// simple types // 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() bool wxTranslations::AddStdCatalog()
{ {
if ( !AddCatalog(wxS("wxstd")) ) if ( !AddCatalog(wxS("wxstd")) )
@@ -1348,6 +1362,7 @@ bool wxTranslations::AddCatalog(const wxString& domain,
bool wxTranslations::LoadCatalog(const wxString& domain, const wxString& lang) bool wxTranslations::LoadCatalog(const wxString& domain, const wxString& lang)
{ {
m_loader->GetAvailableTranslations(domain);
wxCHECK_MSG( m_loader, false, "loader can't be NULL" ); wxCHECK_MSG( m_loader, false, "loader can't be NULL" );
wxMsgCatalog *cat = NULL; wxMsgCatalog *cat = NULL;
@@ -1599,25 +1614,33 @@ wxString GetMsgCatalogSubdirs(const wxString& prefix, const wxString& lang)
return searchPath; return searchPath;
} }
// construct the search path for the given language bool HasMsgCatalogInDir(const wxString& dir, const wxString& domain)
static wxString GetFullSearchPath(const wxString& lang)
{ {
// first take the entries explicitly added by the program return wxFileName(dir, domain, "mo").FileExists() ||
wxArrayString paths; wxFileName(dir + wxFILE_SEP_PATH + "LC_MESSAGES", domain, "mo").FileExists();
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));
}
// get prefixes to locale directories; if lang is empty, don't point to
// OSX's .lproj bundles
wxArrayString GetSearchPrefixes(const wxString& lang = wxString())
{
wxArrayString paths;
// first take the entries explicitly added by the program
paths = gs_searchPrefixes;
#if wxUSE_STDPATHS #if wxUSE_STDPATHS
// then look in the standard location // then look in the standard location
const wxString stdp = wxStandardPaths::Get(). wxString stdp;
GetLocalizedResourcesDir(lang, wxStandardPaths::ResourceCat_Messages); if ( lang.empty() )
{
stdp = wxStandardPaths::Get().GetResourcesDir();
}
else
{
stdp = wxStandardPaths::Get().
GetLocalizedResourcesDir(lang, wxStandardPaths::ResourceCat_Messages);
}
if ( paths.Index(stdp) == wxNOT_FOUND ) if ( paths.Index(stdp) == wxNOT_FOUND )
paths.Add(stdp); paths.Add(stdp);
#endif // wxUSE_STDPATHS #endif // wxUSE_STDPATHS
@@ -1629,7 +1652,7 @@ static wxString GetFullSearchPath(const wxString& lang)
const char *pszLcPath = wxGetenv("LC_PATH"); const char *pszLcPath = wxGetenv("LC_PATH");
if ( pszLcPath ) if ( pszLcPath )
{ {
const wxString lcp = GetMsgCatalogSubdirs(pszLcPath, lang); const wxString lcp = pszLcPath;
if ( paths.Index(lcp) == wxNOT_FOUND ) if ( paths.Index(lcp) == wxNOT_FOUND )
paths.Add(lcp); paths.Add(lcp);
} }
@@ -1638,22 +1661,32 @@ static wxString GetFullSearchPath(const wxString& lang)
wxString wxp = wxGetInstallPrefix(); wxString wxp = wxGetInstallPrefix();
if ( !wxp.empty() ) if ( !wxp.empty() )
{ {
wxp = GetMsgCatalogSubdirs(wxp + wxS("/share/locale"), lang); wxp += wxS("/share/locale");
if ( paths.Index(wxp) == wxNOT_FOUND ) if ( paths.Index(wxp) == wxNOT_FOUND )
paths.Add(wxp); paths.Add(wxp);
} }
#endif // __UNIX__ #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; wxString searchPath;
searchPath.reserve(500); 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]; const wxString p = GetMsgCatalogSubdirs(*i, lang);
if ( n != count - 1 )
if ( !searchPath.empty() )
searchPath += wxPATH_SEP; searchPath += wxPATH_SEP;
searchPath += p;
} }
return searchPath; 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 // wxResourceTranslationsLoader
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#ifdef __WINDOWS__ #ifdef __WINDOWS__
wxMsgCatalog *wxResourceTranslationsLoader::LoadCatalog(const wxString& domain, wxMsgCatalog *wxResourceTranslationsLoader::LoadCatalog(const wxString& domain,
const wxString& lang) const wxString& lang)
{ {
const void *mo_data = NULL; const void *mo_data = NULL;
size_t mo_size = 0; size_t mo_size = 0;
@@ -1727,6 +1802,55 @@ wxMsgCatalog *wxResourceTranslationsLoader::LoadCatalog(const wxString& domain,
return cat; 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<EnumCallbackData*>(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<LONG_PTR>(&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__ #endif // __WINDOWS__