Refactor wxTranslationsLoader API.

Instead of calling back into wxTranslations to actually load the data,
return wxMsgCatalog instance from
wxTranslationsLoader::LoadCatalog(). This requires making wxMsgCatalog
public.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@64223 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Václav Slavík 2010-05-06 12:12:53 +00:00
parent ba5619e076
commit 611bed3511
3 changed files with 190 additions and 207 deletions

View File

@ -20,10 +20,9 @@
#include "wx/buffer.h"
#include "wx/language.h"
#if !wxUSE_UNICODE
#include "wx/hashmap.h"
#endif
#include "wx/hashmap.h"
#include "wx/strconv.h"
#include "wx/scopedptr.h"
// ============================================================================
// global decls
@ -51,7 +50,58 @@
class WXDLLIMPEXP_FWD_BASE wxTranslationsLoader;
class WXDLLIMPEXP_FWD_BASE wxLocale;
class wxMsgCatalog;
class wxPluralFormsCalculator;
wxDECLARE_SCOPED_PTR(wxPluralFormsCalculator, wxPluralFormsCalculatorPtr)
// ----------------------------------------------------------------------------
// wxMsgCatalog corresponds to one loaded message catalog.
// ----------------------------------------------------------------------------
class WXDLLIMPEXP_BASE wxMsgCatalog
{
public:
// load the catalog from disk or from data; caller is responsible for
// deleting them if not NULL
static wxMsgCatalog *CreateFromFile(const wxString& filename,
const wxString& domain);
static wxMsgCatalog *CreateFromData(const wxScopedCharBuffer& data,
const wxString& domain);
// get name of the catalog
wxString GetDomain() const { return m_domain; }
// get the translated string: returns NULL if not found
const wxString *GetString(const wxString& sz, unsigned n = UINT_MAX) const;
protected:
wxMsgCatalog(const wxString& domain)
: m_pNext(NULL), m_domain(domain)
#if !wxUSE_UNICODE
, m_conv(NULL)
#endif
{}
#if !wxUSE_UNICODE
~wxMsgCatalog();
#endif
private:
// variable pointing to the next element in a linked list (or NULL)
wxMsgCatalog *m_pNext;
friend class wxTranslations;
wxStringToStringHashMap m_messages; // all messages in the catalog
wxString m_domain; // name of the domain
#if !wxUSE_UNICODE
// the conversion corresponding to this catalog charset if we installed it
// as the global one
wxCSConv *m_conv;
#endif
wxPluralFormsCalculatorPtr m_pluralFormsCalculator;
};
// ----------------------------------------------------------------------------
// wxTranslations: message catalogs
@ -91,12 +141,6 @@ public:
// check if the given catalog is loaded
bool IsLoaded(const wxString& domain) const;
// load catalog data directly from file or memory
bool LoadCatalogFile(const wxString& filename,
const wxString& domain = wxEmptyString);
bool LoadCatalogData(const wxScopedCharTypeBuffer<char>& data,
const wxString& domain = wxEmptyString);
// access to translations
const wxString& GetString(const wxString& origString,
const wxString& domain = wxEmptyString) const;
@ -133,10 +177,6 @@ private:
wxTranslationsLoader *m_loader;
wxMsgCatalog *m_pMsgCat; // pointer to linked list of catalogs
#if !wxUSE_UNICODE
wxStringToStringHashMap m_msgIdCharset;
#endif
};
@ -147,8 +187,8 @@ public:
wxTranslationsLoader() {}
virtual ~wxTranslationsLoader() {}
virtual bool LoadCatalog(wxTranslations *translations,
const wxString& domain, const wxString& lang) = 0;
virtual wxMsgCatalog *LoadCatalog(const wxString& domain,
const wxString& lang) = 0;
};
@ -159,8 +199,8 @@ class WXDLLIMPEXP_BASE wxFileTranslationsLoader
public:
static void AddCatalogLookupPathPrefix(const wxString& prefix);
virtual bool LoadCatalog(wxTranslations *translations,
const wxString& domain, const wxString& lang);
virtual wxMsgCatalog *LoadCatalog(const wxString& domain,
const wxString& lang);
};
@ -170,8 +210,8 @@ class WXDLLIMPEXP_BASE wxResourceTranslationsLoader
: public wxTranslationsLoader
{
public:
virtual bool LoadCatalog(wxTranslations *translations,
const wxString& domain, const wxString& lang);
virtual wxMsgCatalog *LoadCatalog(const wxString& domain,
const wxString& lang);
protected:
// returns resource type to use for translations

View File

@ -169,20 +169,6 @@ public:
*/
bool IsLoaded(const wxString& domain) const;
/**
Directly loads catalog from a file.
It is caller's responsibility to ensure that the catalog contains
correct language. This function is primarily intended for
wxTranslationsLoader implementations.
@param filename Name of the MO file to load.
@param domain Domain to load the translations into (typically
matches file's basename).
*/
bool LoadCatalogFile(const wxString& filename,
const wxString& domain = wxEmptyString);
/**
Retrieves the translation for a string in all loaded domains unless the @a domain
parameter is specified (and then only this catalog/domain is searched).
@ -264,10 +250,10 @@ public:
/**
Called to load requested catalog.
If the catalog is found, LoadCatalog() should call LoadCatalogFile()
on @a translations to add the translation.
If the catalog is found, LoadCatalog() should create wxMsgCatalog
instance with its data and return it. The caller will take ownership
of the catalog.
@param translations wxTranslations requesting loading.
@param domain Domain to load.
@param lang Language to look for. This is "canonical name"
(see wxLocale::GetCanonicalName()), i.e. ISO 639
@ -275,10 +261,10 @@ public:
additional modifiers (e.g. "fr", "en_GB" or
"ca@valencia").
@return @true on successful load, @false otherwise
@return Loaded catalog or NULL on failure.
*/
virtual bool LoadCatalog(wxTranslations *translations,
const wxString& domain, const wxString& lang) = 0;
virtual wxMsgCatalog *LoadCatalog(const wxString& domain,
const wxString& lang) = 0;
};
/**
@ -335,7 +321,6 @@ public:
This class is only available on Windows.
@since 2.9.1
*/
class wxResourceTranslationsLoader : public wxTranslationsLoader
{
@ -356,6 +341,42 @@ protected:
};
/**
Represents a loaded translations message catalog.
This class should only be used directly by wxTranslationsLoader
implementations.
@since 2.9.1
*/
class wxMsgCatalog
{
public:
/**
Creates catalog loaded from a MO file.
@param filename Path to the MO file to load.
@param domain Catalog's domain. This typically matches
the @a filename.
@return Successfully loaded catalog or NULL on failure.
*/
static wxMsgCatalog *CreateFromFile(const wxString& filename,
const wxString& domain);
/**
Creates catalog from MO file data in memory buffer.
@param data Data in MO file format.
@param domain Catalog's domain. This typically matches
the @a filename.
@return Successfully loaded catalog or NULL on failure.
*/
static wxMsgCatalog *CreateFromData(const wxScopedCharBuffer& data,
const wxString& domain);
};
// ============================================================================
// Global functions/macros

View File

@ -45,7 +45,6 @@
#include "wx/filename.h"
#include "wx/tokenzr.h"
#include "wx/fontmap.h"
#include "wx/scopedptr.h"
#include "wx/stdpaths.h"
#include "wx/hashset.h"
@ -69,6 +68,18 @@ const size_t32 MSGCATALOG_MAGIC_SW = 0xde120495;
// implementation
// ============================================================================
namespace
{
#if !wxUSE_UNICODE
// We need to keep track of (char*) msgids in non-Unicode legacy builds. Instead
// of making the public wxMsgCatalog and wxTranslationsLoader APIs ugly, we
// store them in this global map.
wxStringToStringHashMap gs_msgIdCharset;
#endif
} // anonymous namespace
// ----------------------------------------------------------------------------
// Plural forms parser
// ----------------------------------------------------------------------------
@ -414,7 +425,7 @@ private:
wxPluralFormsNodePtr m_plural;
};
wxDEFINE_SCOPED_PTR_TYPE(wxPluralFormsCalculator)
wxDEFINE_SCOPED_PTR(wxPluralFormsCalculator, wxPluralFormsCalculatorPtr)
void wxPluralFormsCalculator::init(wxPluralFormsToken::Number nplurals,
wxPluralFormsNode* plural)
@ -785,12 +796,10 @@ wxPluralFormsCalculator* wxPluralFormsCalculator::make(const char* s)
// http://www.gnu.org/software/autoconf/manual/gettext/MO-Files.html
// ----------------------------------------------------------------------------
WX_DECLARE_EXPORTED_STRING_HASH_MAP(wxString, wxMessagesHash);
class wxMsgCatalogFile
{
public:
typedef wxScopedCharTypeBuffer<char> DataBuffer;
typedef wxScopedCharBuffer DataBuffer;
// ctor & dtor
wxMsgCatalogFile();
@ -803,7 +812,7 @@ public:
wxPluralFormsCalculatorPtr& rPluralFormsCalculator);
// fills the hash with string-translation pairs
bool FillHash(wxMessagesHash& hash, const wxString& msgIdCharset) const;
bool FillHash(wxStringToStringHashMap& hash, const wxString& domain) const;
// return the charset of the strings in this catalog or empty string if
// none/unknown
@ -869,53 +878,6 @@ private:
wxDECLARE_NO_COPY_CLASS(wxMsgCatalogFile);
};
// ----------------------------------------------------------------------------
// wxMsgCatalog corresponds to one loaded message catalog.
//
// This is a "low-level" class and is used only by wxLocale (that's why
// it's designed to be stored in a linked list)
// ----------------------------------------------------------------------------
class wxMsgCatalog
{
public:
#if !wxUSE_UNICODE
wxMsgCatalog() { m_conv = NULL; }
~wxMsgCatalog();
#endif
// load the catalog from disk
bool LoadFile(const wxString& filename,
const wxString& domain,
const wxString& msgIdCharset);
bool LoadData(const wxScopedCharTypeBuffer<char>& data,
const wxString& domain,
const wxString& msgIdCharset);
// get name of the catalog
wxString GetDomain() const { return m_domain; }
// get the translated string: returns NULL if not found
const wxString *GetString(const wxString& sz, unsigned n = UINT_MAX) const;
// public variable pointing to the next element in a linked list (or NULL)
wxMsgCatalog *m_pNext;
private:
wxMessagesHash m_messages; // all messages in the catalog
wxString m_domain; // name of the domain
#if !wxUSE_UNICODE
// the conversion corresponding to this catalog charset if we installed it
// as the global one
wxCSConv *m_conv;
#endif
wxPluralFormsCalculatorPtr m_pluralFormsCalculator;
};
// ----------------------------------------------------------------------------
// wxMsgCatalogFile clas
// ----------------------------------------------------------------------------
@ -1057,10 +1019,10 @@ bool wxMsgCatalogFile::LoadData(const DataBuffer& data,
return true;
}
bool wxMsgCatalogFile::FillHash(wxMessagesHash& hash,
const wxString& msgIdCharset) const
bool wxMsgCatalogFile::FillHash(wxStringToStringHashMap& hash,
const wxString& domain) const
{
wxUnusedVar(msgIdCharset); // silence warning in Unicode build
wxUnusedVar(domain); // silence warning in Unicode build
// conversion to use to convert catalog strings to the GUI encoding
wxMBConv *inputConv = NULL;
@ -1088,6 +1050,8 @@ bool wxMsgCatalogFile::FillHash(wxMessagesHash& hash,
}
#if !wxUSE_UNICODE
wxString msgIdCharset = gs_msgIdCharset[domain];
// conversion to apply to msgid strings before looking them up: we only
// need it if the msgids are neither in 7 bit ASCII nor in the same
// encoding as the catalog
@ -1179,38 +1143,38 @@ wxMsgCatalog::~wxMsgCatalog()
}
#endif // !wxUSE_UNICODE
bool wxMsgCatalog::LoadFile(const wxString& filename,
const wxString& domain,
const wxString& msgIdCharset)
/* static */
wxMsgCatalog *wxMsgCatalog::CreateFromFile(const wxString& filename,
const wxString& domain)
{
wxScopedPtr<wxMsgCatalog> cat(new wxMsgCatalog(domain));
wxMsgCatalogFile file;
m_domain = domain;
if ( !file.LoadFile(filename, cat->m_pluralFormsCalculator) )
return NULL;
if ( !file.LoadFile(filename, m_pluralFormsCalculator) )
return false;
if ( !file.FillHash(cat->m_messages, domain) )
return NULL;
if ( !file.FillHash(m_messages, msgIdCharset) )
return false;
return true;
return cat.release();
}
bool wxMsgCatalog::LoadData(const wxScopedCharTypeBuffer<char>& data,
const wxString& domain,
const wxString& msgIdCharset)
/* static */
wxMsgCatalog *wxMsgCatalog::CreateFromData(const wxScopedCharBuffer& data,
const wxString& domain)
{
wxScopedPtr<wxMsgCatalog> cat(new wxMsgCatalog(domain));
wxMsgCatalogFile file;
m_domain = domain;
if ( !file.LoadData(data, cat->m_pluralFormsCalculator) )
return NULL;
if ( !file.LoadData(data, m_pluralFormsCalculator) )
return false;
if ( !file.FillHash(cat->m_messages, domain) )
return NULL;
if ( !file.FillHash(m_messages, msgIdCharset) )
return false;
return true;
return cat.release();
}
const wxString *wxMsgCatalog::GetString(const wxString& str, unsigned n) const
@ -1220,7 +1184,7 @@ const wxString *wxMsgCatalog::GetString(const wxString& str, unsigned n) const
{
index = m_pluralFormsCalculator->evaluate(n);
}
wxMessagesHash::const_iterator i;
wxStringToStringHashMap::const_iterator i;
if (index != 0)
{
i = m_messages.find(wxString(str) + wxChar(index)); // plural
@ -1349,7 +1313,7 @@ bool wxTranslations::AddCatalog(const wxString& domain,
wxLanguage msgIdLanguage,
const wxString& msgIdCharset)
{
m_msgIdCharset[domain] = msgIdCharset;
gs_msgIdCharset[domain] = msgIdCharset;
return AddCatalog(domain, msgIdLanguage);
}
#endif // !wxUSE_UNICODE
@ -1386,6 +1350,8 @@ bool wxTranslations::LoadCatalog(const wxString& domain, const wxString& lang)
{
wxCHECK_MSG( m_loader, false, "loader can't be NULL" );
wxMsgCatalog *cat = NULL;
#if wxUSE_FONTMAP
// first look for the catalog for this language and the current locale:
// notice that we don't use the system name for the locale as this would
@ -1397,32 +1363,44 @@ bool wxTranslations::LoadCatalog(const wxString& domain, const wxString& lang)
wxString fullname(lang);
fullname << wxS('.') << wxFontMapperBase::GetEncodingName(encSys);
if ( m_loader->LoadCatalog(this, domain, fullname) )
return true;
cat = m_loader->LoadCatalog(domain, fullname);
}
#endif // wxUSE_FONTMAP
// Next try: use the provided name language name:
if ( m_loader->LoadCatalog(this, domain, lang) )
return true;
// Also try just base locale name: for things like "fr_BE" (Belgium
// French) we should use fall back on plain "fr" if no Belgium-specific
// message catalogs exist
wxString baselang = lang.BeforeFirst('_');
if ( lang != baselang )
if ( !cat )
{
if ( m_loader->LoadCatalog(this, domain, baselang) )
return true;
// Next try: use the provided name language name:
cat = m_loader->LoadCatalog(domain, lang);
}
// Nothing worked, the catalog just isn't there
wxLogTrace(TRACE_I18N,
"Catalog \"%s.mo\" not found for language \"%s\".",
domain, lang);
return false;
}
if ( !cat )
{
// Also try just base locale name: for things like "fr_BE" (Belgium
// French) we should use fall back on plain "fr" if no Belgium-specific
// message catalogs exist
wxString baselang = lang.BeforeFirst('_');
if ( lang != baselang )
cat = m_loader->LoadCatalog(domain, baselang);
}
if ( cat )
{
// add it to the head of the list so that in GetString it will
// be searched before the catalogs added earlier
cat->m_pNext = m_pMsgCat;
m_pMsgCat = cat;
return true;
}
else
{
// Nothing worked, the catalog just isn't there
wxLogTrace(TRACE_I18N,
"Catalog \"%s.mo\" not found for language \"%s\".",
domain, lang);
return false;
}
}
// check if the given catalog is loaded
bool wxTranslations::IsLoaded(const wxString& domain) const
@ -1431,62 +1409,6 @@ bool wxTranslations::IsLoaded(const wxString& domain) const
}
bool wxTranslations::LoadCatalogFile(const wxString& filename,
const wxString& domain)
{
wxMsgCatalog *pMsgCat = new wxMsgCatalog;
#if wxUSE_UNICODE
const bool ok = pMsgCat->LoadFile(filename, domain, wxEmptyString/*unused*/);
#else
const bool ok = pMsgCat->LoadFile(filename, domain,
m_msgIdCharset[domain]);
#endif
if ( !ok )
{
// don't add it because it couldn't be loaded anyway
delete pMsgCat;
return false;
}
// add it to the head of the list so that in GetString it will
// be searched before the catalogs added earlier
pMsgCat->m_pNext = m_pMsgCat;
m_pMsgCat = pMsgCat;
return true;
}
bool wxTranslations::LoadCatalogData(const wxScopedCharTypeBuffer<char>& data,
const wxString& domain)
{
wxMsgCatalog *pMsgCat = new wxMsgCatalog;
#if wxUSE_UNICODE
const bool ok = pMsgCat->LoadData(data, domain, wxEmptyString/*unused*/);
#else
const bool ok = pMsgCat->LoadData(data, domain,
m_msgIdCharset[domain]);
#endif
if ( !ok )
{
// don't add it because it couldn't be loaded anyway
delete pMsgCat;
return false;
}
// add it to the head of the list so that in GetString it will
// be searched before the catalogs added earlier
pMsgCat->m_pNext = m_pMsgCat;
m_pMsgCat = pMsgCat;
return true;
}
wxString wxTranslations::ChooseLanguageForDomain(const wxString& WXUNUSED(domain),
const wxString& WXUNUSED(msgIdLang))
{
@ -1750,9 +1672,8 @@ void wxFileTranslationsLoader::AddCatalogLookupPathPrefix(const wxString& prefix
}
bool wxFileTranslationsLoader::LoadCatalog(wxTranslations *translations,
const wxString& domain,
const wxString& lang)
wxMsgCatalog *wxFileTranslationsLoader::LoadCatalog(const wxString& domain,
const wxString& lang)
{
wxString searchPath = GetFullSearchPath(lang);
@ -1764,13 +1685,13 @@ bool wxFileTranslationsLoader::LoadCatalog(wxTranslations *translations,
wxString strFullName;
if ( !wxFindFileInPath(&strFullName, searchPath, fn.GetFullPath()) )
return false;
return NULL;
// open file and read its data
wxLogVerbose(_("using catalog '%s' from '%s'."), domain, strFullName.c_str());
wxLogTrace(TRACE_I18N, wxS("Using catalog \"%s\"."), strFullName.c_str());
return translations->LoadCatalogFile(strFullName, domain);
return wxMsgCatalog::CreateFromFile(strFullName, domain);
}
@ -1779,9 +1700,8 @@ bool wxFileTranslationsLoader::LoadCatalog(wxTranslations *translations,
// ----------------------------------------------------------------------------
#ifdef __WINDOWS__
bool wxResourceTranslationsLoader::LoadCatalog(wxTranslations *translations,
const wxString& domain,
const wxString& lang)
wxMsgCatalog *wxResourceTranslationsLoader::LoadCatalog(const wxString& domain,
const wxString& lang)
{
const void *mo_data = NULL;
@ -1798,12 +1718,14 @@ bool wxResourceTranslationsLoader::LoadCatalog(wxTranslations *translations,
wxLogTrace(TRACE_I18N,
"Using catalog from Windows resource \"%s\".", resname);
const bool ok = translations->LoadCatalogData(
wxCharBuffer::CreateNonOwned(static_cast<const char*>(mo_data), mo_size));
if ( !ok )
wxMsgCatalog *cat = wxMsgCatalog::CreateFromData(
wxCharBuffer::CreateNonOwned(static_cast<const char*>(mo_data), mo_size),
domain);
if ( !cat )
wxLogWarning(_("Resource '%s' is not a valid message catalog."), resname);
return ok;
return cat;
}
#endif // __WINDOWS__