2010-04-24 03:06:32 -04:00
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Name: wx/translation.h
|
|
|
|
// Purpose: Internationalization and localisation for wxWidgets
|
|
|
|
// Author: Vadim Zeitlin, Vaclav Slavik,
|
|
|
|
// Michael N. Filippov <michael@idisys.iae.nsk.su>
|
|
|
|
// Created: 2010-04-23
|
|
|
|
// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
|
|
|
|
// (c) 2010 Vaclav Slavik <vslavik@fastmail.fm>
|
|
|
|
// Licence: wxWindows licence
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#ifndef _WX_TRANSLATION_H_
|
|
|
|
#define _WX_TRANSLATION_H_
|
|
|
|
|
|
|
|
#include "wx/defs.h"
|
|
|
|
#include "wx/string.h"
|
|
|
|
|
|
|
|
#if wxUSE_INTL
|
|
|
|
|
2010-04-26 16:51:22 -04:00
|
|
|
#include "wx/buffer.h"
|
2010-04-24 03:06:32 -04:00
|
|
|
#include "wx/language.h"
|
2010-05-06 08:12:53 -04:00
|
|
|
#include "wx/hashmap.h"
|
|
|
|
#include "wx/strconv.h"
|
|
|
|
#include "wx/scopedptr.h"
|
2010-04-24 03:06:32 -04:00
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
// global decls
|
|
|
|
// ============================================================================
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// macros
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// gettext() style macros (notice that xgettext should be invoked with
|
2017-07-29 08:23:29 -04:00
|
|
|
// --keyword="_" --keyword="wxPLURAL:1,2" options
|
|
|
|
// to extract the strings from the sources)
|
2010-04-24 03:06:32 -04:00
|
|
|
#ifndef WXINTL_NO_GETTEXT_MACRO
|
2016-09-20 14:03:21 -04:00
|
|
|
#define _(s) wxGetTranslation((s))
|
|
|
|
#define wxPLURAL(sing, plur, n) wxGetTranslation((sing), (plur), n)
|
2010-04-24 03:06:32 -04:00
|
|
|
#endif
|
|
|
|
|
2017-07-29 08:23:29 -04:00
|
|
|
// wx-specific macro for translating strings in the given context: if you use
|
|
|
|
// them, you need to also add
|
|
|
|
// --keyword="wxGETTEXT_IN_CONTEXT:1c,2" --keyword="wxGETTEXT_IN_CONTEXT_PLURAL:1c,2,3"
|
|
|
|
// options to xgettext invocation.
|
|
|
|
#define wxGETTEXT_IN_CONTEXT(c, s) \
|
|
|
|
wxGetTranslation((s), wxString(), c)
|
|
|
|
#define wxGETTEXT_IN_CONTEXT_PLURAL(c, sing, plur, n) \
|
|
|
|
wxGetTranslation((sing), (plur), n, wxString(), c)
|
|
|
|
|
2010-04-24 03:06:32 -04:00
|
|
|
// another one which just marks the strings for extraction, but doesn't
|
|
|
|
// perform the translation (use -kwxTRANSLATE with xgettext!)
|
|
|
|
#define wxTRANSLATE(str) str
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// forward decls
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
2010-06-16 10:09:32 -04:00
|
|
|
class WXDLLIMPEXP_FWD_BASE wxArrayString;
|
2010-04-24 03:06:32 -04:00
|
|
|
class WXDLLIMPEXP_FWD_BASE wxTranslationsLoader;
|
|
|
|
class WXDLLIMPEXP_FWD_BASE wxLocale;
|
2010-05-06 08:12:53 -04:00
|
|
|
|
|
|
|
class wxPluralFormsCalculator;
|
|
|
|
wxDECLARE_SCOPED_PTR(wxPluralFormsCalculator, wxPluralFormsCalculatorPtr)
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// wxMsgCatalog corresponds to one loaded message catalog.
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
class WXDLLIMPEXP_BASE wxMsgCatalog
|
|
|
|
{
|
|
|
|
public:
|
2010-05-08 11:31:12 -04:00
|
|
|
// Ctor is protected, because CreateFromXXX functions must be used,
|
|
|
|
// but destruction should be unrestricted
|
|
|
|
#if !wxUSE_UNICODE
|
|
|
|
~wxMsgCatalog();
|
|
|
|
#endif
|
|
|
|
|
2010-05-06 08:12:53 -04:00
|
|
|
// 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
|
2016-09-20 14:03:21 -04:00
|
|
|
const wxString *GetString(const wxString& sz, unsigned n = UINT_MAX, const wxString& ct = wxEmptyString) const;
|
2010-05-06 08:12:53 -04:00
|
|
|
|
|
|
|
protected:
|
|
|
|
wxMsgCatalog(const wxString& domain)
|
|
|
|
: m_pNext(NULL), m_domain(domain)
|
|
|
|
#if !wxUSE_UNICODE
|
|
|
|
, m_conv(NULL)
|
|
|
|
#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;
|
|
|
|
};
|
2010-04-24 03:06:32 -04:00
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// wxTranslations: message catalogs
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// this class allows to get translations for strings
|
|
|
|
class WXDLLIMPEXP_BASE wxTranslations
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
wxTranslations();
|
|
|
|
~wxTranslations();
|
|
|
|
|
|
|
|
// returns current translations object, may return NULL
|
|
|
|
static wxTranslations *Get();
|
|
|
|
// sets current translations object (takes ownership; may be NULL)
|
|
|
|
static void Set(wxTranslations *t);
|
|
|
|
|
|
|
|
// changes loader to non-default one; takes ownership of 'loader'
|
|
|
|
void SetLoader(wxTranslationsLoader *loader);
|
|
|
|
|
|
|
|
void SetLanguage(wxLanguage lang);
|
|
|
|
void SetLanguage(const wxString& lang);
|
|
|
|
|
2010-06-16 10:09:32 -04:00
|
|
|
// get languages available for this app
|
|
|
|
wxArrayString GetAvailableTranslations(const wxString& domain) const;
|
|
|
|
|
2012-09-08 04:58:38 -04:00
|
|
|
// find best translation language for given domain
|
|
|
|
wxString GetBestTranslation(const wxString& domain, wxLanguage msgIdLanguage);
|
|
|
|
wxString GetBestTranslation(const wxString& domain,
|
|
|
|
const wxString& msgIdLanguage = "en");
|
|
|
|
|
2010-04-24 03:06:32 -04:00
|
|
|
// add standard wxWidgets catalog ("wxstd")
|
|
|
|
bool AddStdCatalog();
|
|
|
|
|
|
|
|
// add catalog with given domain name and language, looking it up via
|
|
|
|
// wxTranslationsLoader
|
2016-06-25 19:30:59 -04:00
|
|
|
bool AddCatalog(const wxString& domain,
|
|
|
|
wxLanguage msgIdLanguage = wxLANGUAGE_ENGLISH_US);
|
2010-04-24 03:06:32 -04:00
|
|
|
#if !wxUSE_UNICODE
|
|
|
|
bool AddCatalog(const wxString& domain,
|
|
|
|
wxLanguage msgIdLanguage,
|
|
|
|
const wxString& msgIdCharset);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// check if the given catalog is loaded
|
|
|
|
bool IsLoaded(const wxString& domain) const;
|
|
|
|
|
|
|
|
// access to translations
|
2013-09-18 12:03:31 -04:00
|
|
|
const wxString *GetTranslatedString(const wxString& origString,
|
2016-09-20 14:03:21 -04:00
|
|
|
const wxString& domain = wxEmptyString,
|
|
|
|
const wxString& context = wxEmptyString) const;
|
2013-09-18 12:03:31 -04:00
|
|
|
const wxString *GetTranslatedString(const wxString& origString,
|
|
|
|
unsigned n,
|
2016-09-20 14:03:21 -04:00
|
|
|
const wxString& domain = wxEmptyString,
|
|
|
|
const wxString& context = wxEmptyString) const;
|
2010-04-24 03:06:32 -04:00
|
|
|
|
|
|
|
wxString GetHeaderValue(const wxString& header,
|
|
|
|
const wxString& domain = wxEmptyString) const;
|
|
|
|
|
|
|
|
// this is hack to work around a problem with wxGetTranslation() which
|
|
|
|
// returns const wxString& and not wxString, so when it returns untranslated
|
|
|
|
// string, it needs to have a copy of it somewhere
|
|
|
|
static const wxString& GetUntranslatedString(const wxString& str);
|
|
|
|
|
|
|
|
private:
|
2010-04-26 16:51:16 -04:00
|
|
|
// perform loading of the catalog via m_loader
|
2013-09-20 13:27:59 -04:00
|
|
|
bool LoadCatalog(const wxString& domain, const wxString& lang, const wxString& msgIdLang);
|
2010-04-26 16:51:16 -04:00
|
|
|
|
2010-04-24 03:06:32 -04:00
|
|
|
// find catalog by name in a linked list, return NULL if !found
|
|
|
|
wxMsgCatalog *FindCatalog(const wxString& domain) const;
|
|
|
|
|
|
|
|
// same as Set(), without taking ownership; only for wxLocale
|
|
|
|
static void SetNonOwned(wxTranslations *t);
|
|
|
|
friend class wxLocale;
|
|
|
|
|
|
|
|
private:
|
|
|
|
wxString m_lang;
|
|
|
|
wxTranslationsLoader *m_loader;
|
|
|
|
|
|
|
|
wxMsgCatalog *m_pMsgCat; // pointer to linked list of catalogs
|
2015-05-01 13:36:08 -04:00
|
|
|
|
|
|
|
// In addition to keeping all the catalogs in the linked list, we also
|
|
|
|
// store them in a hash map indexed by the domain name to allow finding
|
|
|
|
// them by name efficiently.
|
|
|
|
WX_DECLARE_HASH_MAP(wxString, wxMsgCatalog *, wxStringHash, wxStringEqual, wxMsgCatalogMap);
|
|
|
|
wxMsgCatalogMap m_catalogMap;
|
2010-04-24 03:06:32 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// abstraction of translations discovery and loading
|
|
|
|
class WXDLLIMPEXP_BASE wxTranslationsLoader
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
wxTranslationsLoader() {}
|
|
|
|
virtual ~wxTranslationsLoader() {}
|
|
|
|
|
2010-05-06 08:12:53 -04:00
|
|
|
virtual wxMsgCatalog *LoadCatalog(const wxString& domain,
|
|
|
|
const wxString& lang) = 0;
|
2010-06-16 10:09:32 -04:00
|
|
|
|
|
|
|
virtual wxArrayString GetAvailableTranslations(const wxString& domain) const = 0;
|
2010-04-24 03:06:32 -04:00
|
|
|
};
|
|
|
|
|
2010-04-26 16:51:22 -04:00
|
|
|
|
2010-04-24 03:06:32 -04:00
|
|
|
// standard wxTranslationsLoader implementation, using filesystem
|
|
|
|
class WXDLLIMPEXP_BASE wxFileTranslationsLoader
|
|
|
|
: public wxTranslationsLoader
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
static void AddCatalogLookupPathPrefix(const wxString& prefix);
|
|
|
|
|
2010-05-06 08:12:53 -04:00
|
|
|
virtual wxMsgCatalog *LoadCatalog(const wxString& domain,
|
2014-03-29 20:02:23 -04:00
|
|
|
const wxString& lang) wxOVERRIDE;
|
2010-06-16 10:09:32 -04:00
|
|
|
|
2014-03-29 20:02:23 -04:00
|
|
|
virtual wxArrayString GetAvailableTranslations(const wxString& domain) const wxOVERRIDE;
|
2010-04-24 03:06:32 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2010-04-26 16:51:22 -04:00
|
|
|
#ifdef __WINDOWS__
|
|
|
|
// loads translations from win32 resources
|
|
|
|
class WXDLLIMPEXP_BASE wxResourceTranslationsLoader
|
|
|
|
: public wxTranslationsLoader
|
|
|
|
{
|
|
|
|
public:
|
2010-05-06 08:12:53 -04:00
|
|
|
virtual wxMsgCatalog *LoadCatalog(const wxString& domain,
|
2016-09-25 16:21:28 -04:00
|
|
|
const wxString& lang) wxOVERRIDE;
|
2010-04-26 16:51:22 -04:00
|
|
|
|
2016-09-25 16:21:28 -04:00
|
|
|
virtual wxArrayString GetAvailableTranslations(const wxString& domain) const wxOVERRIDE;
|
2010-06-16 10:09:32 -04:00
|
|
|
|
2010-04-26 16:51:22 -04:00
|
|
|
protected:
|
|
|
|
// returns resource type to use for translations
|
|
|
|
virtual wxString GetResourceType() const { return "MOFILE"; }
|
|
|
|
|
|
|
|
// returns module to load resources from
|
2020-02-03 02:40:01 -05:00
|
|
|
virtual WXHINSTANCE GetModule() const { return NULL; }
|
2010-04-26 16:51:22 -04:00
|
|
|
};
|
|
|
|
#endif // __WINDOWS__
|
|
|
|
|
|
|
|
|
2010-04-24 03:06:32 -04:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// global functions
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// get the translation of the string in the current locale
|
|
|
|
inline const wxString& wxGetTranslation(const wxString& str,
|
2016-09-20 14:03:21 -04:00
|
|
|
const wxString& domain = wxString(),
|
|
|
|
const wxString& context = wxString())
|
2010-04-24 03:06:32 -04:00
|
|
|
{
|
|
|
|
wxTranslations *trans = wxTranslations::Get();
|
2016-09-20 14:03:21 -04:00
|
|
|
const wxString *transStr = trans ? trans->GetTranslatedString(str, domain, context)
|
2013-09-18 12:03:31 -04:00
|
|
|
: NULL;
|
|
|
|
if ( transStr )
|
|
|
|
return *transStr;
|
2010-04-24 03:06:32 -04:00
|
|
|
else
|
|
|
|
// NB: this function returns reference to a string, so we have to keep
|
|
|
|
// a copy of it somewhere
|
|
|
|
return wxTranslations::GetUntranslatedString(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline const wxString& wxGetTranslation(const wxString& str1,
|
|
|
|
const wxString& str2,
|
2010-05-05 08:27:07 -04:00
|
|
|
unsigned n,
|
2016-09-20 14:03:21 -04:00
|
|
|
const wxString& domain = wxString(),
|
|
|
|
const wxString& context = wxString())
|
2010-04-24 03:06:32 -04:00
|
|
|
{
|
|
|
|
wxTranslations *trans = wxTranslations::Get();
|
2016-09-20 14:03:21 -04:00
|
|
|
const wxString *transStr = trans ? trans->GetTranslatedString(str1, n, domain, context)
|
2013-09-18 12:03:31 -04:00
|
|
|
: NULL;
|
|
|
|
if ( transStr )
|
|
|
|
return *transStr;
|
2010-04-24 03:06:32 -04:00
|
|
|
else
|
|
|
|
// NB: this function returns reference to a string, so we have to keep
|
|
|
|
// a copy of it somewhere
|
|
|
|
return n == 1
|
|
|
|
? wxTranslations::GetUntranslatedString(str1)
|
|
|
|
: wxTranslations::GetUntranslatedString(str2);
|
|
|
|
}
|
|
|
|
|
|
|
|
#else // !wxUSE_INTL
|
|
|
|
|
|
|
|
// the macros should still be defined - otherwise compilation would fail
|
|
|
|
|
|
|
|
#if !defined(WXINTL_NO_GETTEXT_MACRO)
|
|
|
|
#if !defined(_)
|
|
|
|
#define _(s) (s)
|
|
|
|
#endif
|
|
|
|
#define wxPLURAL(sing, plur, n) ((n) == 1 ? (sing) : (plur))
|
2017-07-29 08:23:29 -04:00
|
|
|
#define wxGETTEXT_IN_CONTEXT(c, s) (s)
|
|
|
|
#define wxGETTEXT_IN_CONTEXT_PLURAL(c, sing, plur, n) wxPLURAL(sing, plur, n)
|
2010-04-24 03:06:32 -04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#define wxTRANSLATE(str) str
|
|
|
|
|
|
|
|
// NB: we use a template here in order to avoid using
|
|
|
|
// wxLocale::GetUntranslatedString() above, which would be required if
|
|
|
|
// we returned const wxString&; this way, the compiler should be able to
|
|
|
|
// optimize wxGetTranslation() away
|
|
|
|
|
|
|
|
template<typename TString>
|
|
|
|
inline TString wxGetTranslation(TString str)
|
|
|
|
{ return str; }
|
|
|
|
|
|
|
|
template<typename TString, typename TDomain>
|
|
|
|
inline TString wxGetTranslation(TString str, TDomain WXUNUSED(domain))
|
|
|
|
{ return str; }
|
|
|
|
|
2016-09-20 14:03:21 -04:00
|
|
|
template<typename TString, typename TDomain, typename TContext>
|
|
|
|
inline TString wxGetTranslation(TString str, TDomain WXUNUSED(domain), TContext WXUNUSED(context))
|
|
|
|
{ return str; }
|
|
|
|
|
2010-04-24 03:06:32 -04:00
|
|
|
template<typename TString, typename TDomain>
|
|
|
|
inline TString wxGetTranslation(TString str1, TString str2, size_t n)
|
|
|
|
{ return n == 1 ? str1 : str2; }
|
|
|
|
|
|
|
|
template<typename TString, typename TDomain>
|
|
|
|
inline TString wxGetTranslation(TString str1, TString str2, size_t n,
|
|
|
|
TDomain WXUNUSED(domain))
|
|
|
|
{ return n == 1 ? str1 : str2; }
|
|
|
|
|
2016-09-20 14:03:21 -04:00
|
|
|
template<typename TString, typename TDomain, typename TContext>
|
|
|
|
inline TString wxGetTranslation(TString str1, TString str2, size_t n,
|
2017-07-29 08:23:29 -04:00
|
|
|
TDomain WXUNUSED(domain),
|
2016-09-20 14:03:21 -04:00
|
|
|
TContext WXUNUSED(context))
|
|
|
|
{ return n == 1 ? str1 : str2; }
|
|
|
|
|
2010-04-24 03:06:32 -04:00
|
|
|
#endif // wxUSE_INTL/!wxUSE_INTL
|
|
|
|
|
|
|
|
// define this one just in case it occurs somewhere (instead of preferred
|
|
|
|
// wxTRANSLATE) too
|
|
|
|
#if !defined(WXINTL_NO_GETTEXT_MACRO)
|
|
|
|
#if !defined(gettext_noop)
|
|
|
|
#define gettext_noop(str) (str)
|
|
|
|
#endif
|
|
|
|
#if !defined(N_)
|
|
|
|
#define N_(s) (s)
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif // _WX_TRANSLATION_H_
|