#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
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
// 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;
wxTranslationsLoader *m_loader;
wxMsgCatalog *m_pMsgCat; // pointer to linked list of catalogs
-
-#if !wxUSE_UNICODE
- wxStringToStringHashMap m_msgIdCharset;
-#endif
};
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;
};
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);
};
: 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
*/
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).
/**
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
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;
};
/**
This class is only available on Windows.
@since 2.9.1
-
*/
class wxResourceTranslationsLoader : public wxTranslationsLoader
{
};
+/**
+ 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
#include "wx/filename.h"
#include "wx/tokenzr.h"
#include "wx/fontmap.h"
-#include "wx/scopedptr.h"
#include "wx/stdpaths.h"
#include "wx/hashset.h"
// 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
// ----------------------------------------------------------------------------
wxPluralFormsNodePtr m_plural;
};
-wxDEFINE_SCOPED_PTR_TYPE(wxPluralFormsCalculator)
+wxDEFINE_SCOPED_PTR(wxPluralFormsCalculator, wxPluralFormsCalculatorPtr)
void wxPluralFormsCalculator::init(wxPluralFormsToken::Number nplurals,
wxPluralFormsNode* plural)
// 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();
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
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
// ----------------------------------------------------------------------------
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;
}
#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
}
#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)
{
- wxMsgCatalogFile file;
+ wxScopedPtr<wxMsgCatalog> cat(new wxMsgCatalog(domain));
- m_domain = domain;
+ wxMsgCatalogFile file;
- if ( !file.LoadFile(filename, m_pluralFormsCalculator) )
- return false;
+ if ( !file.LoadFile(filename, cat->m_pluralFormsCalculator) )
+ return NULL;
- if ( !file.FillHash(m_messages, msgIdCharset) )
- return false;
+ if ( !file.FillHash(cat->m_messages, domain) )
+ return NULL;
- 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)
{
- wxMsgCatalogFile file;
+ wxScopedPtr<wxMsgCatalog> cat(new wxMsgCatalog(domain));
- m_domain = domain;
+ wxMsgCatalogFile file;
- if ( !file.LoadData(data, m_pluralFormsCalculator) )
- return false;
+ if ( !file.LoadData(data, cat->m_pluralFormsCalculator) )
+ return NULL;
- if ( !file.FillHash(m_messages, msgIdCharset) )
- return false;
+ if ( !file.FillHash(cat->m_messages, domain) )
+ return NULL;
- return true;
+ return cat.release();
}
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
wxLanguage msgIdLanguage,
const wxString& msgIdCharset)
{
- m_msgIdCharset[domain] = msgIdCharset;
+ gs_msgIdCharset[domain] = msgIdCharset;
return AddCatalog(domain, msgIdLanguage);
}
#endif // !wxUSE_UNICODE
{
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
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;
-}
-
-
-// check if the given catalog is loaded
-bool wxTranslations::IsLoaded(const wxString& domain) const
-{
- return FindCatalog(domain) != NULL;
-}
-
-
-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 )
+ if ( !cat )
{
- // don't add it because it couldn't be loaded anyway
- delete pMsgCat;
- return false;
+ // 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);
}
- // 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 ( 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;
- if ( !ok )
+ return true;
+ }
+ else
{
- // don't add it because it couldn't be loaded anyway
- delete pMsgCat;
+ // Nothing worked, the catalog just isn't there
+ wxLogTrace(TRACE_I18N,
+ "Catalog \"%s.mo\" not found for language \"%s\".",
+ domain, lang);
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;
+// check if the given catalog is loaded
+bool wxTranslations::IsLoaded(const wxString& domain) const
+{
+ return FindCatalog(domain) != NULL;
}
}
-bool wxFileTranslationsLoader::LoadCatalog(wxTranslations *translations,
- const wxString& domain,
- const wxString& lang)
+wxMsgCatalog *wxFileTranslationsLoader::LoadCatalog(const wxString& domain,
+ const wxString& lang)
{
wxString searchPath = GetFullSearchPath(lang);
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);
}
// ----------------------------------------------------------------------------
#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;
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__