Merge branch 'i18n-context'

Closes https://github.com/wxWidgets/wxWidgets/pull/530
This commit is contained in:
Vadim Zeitlin 2017-08-09 20:47:41 +02:00
commit 7e80ff4ed8
7 changed files with 150 additions and 27 deletions

View File

@ -76,6 +76,7 @@ All:
- Add wxSecretStore for storing passwords using the OS-provided facilities. - Add wxSecretStore for storing passwords using the OS-provided facilities.
- Add support for compiling application code with wxNO_UNSAFE_WXSTRING_CONV. - Add support for compiling application code with wxNO_UNSAFE_WXSTRING_CONV.
- Add support for translating strings in different contexts (RickS).
- Add support for the micro version (third component) to OS and toolkit version - Add support for the micro version (third component) to OS and toolkit version
functions. See wxGetOsVersion(), wxPlatformInfo, and wxAppTraits. functions. See wxGetOsVersion(), wxPlatformInfo, and wxAppTraits.
- wxLogInfo() now logs messages if the log level is high enough, even without - wxLogInfo() now logs messages if the log level is high enough, even without

View File

@ -35,10 +35,19 @@
// --keyword="_" --keyword="wxPLURAL:1,2" options // --keyword="_" --keyword="wxPLURAL:1,2" options
// to extract the strings from the sources) // to extract the strings from the sources)
#ifndef WXINTL_NO_GETTEXT_MACRO #ifndef WXINTL_NO_GETTEXT_MACRO
#define _(s) wxGetTranslation((s)) #define _(s) wxGetTranslation((s))
#define wxPLURAL(sing, plur, n) wxGetTranslation((sing), (plur), n) #define wxPLURAL(sing, plur, n) wxGetTranslation((sing), (plur), n)
#endif #endif
// 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)
// another one which just marks the strings for extraction, but doesn't // another one which just marks the strings for extraction, but doesn't
// perform the translation (use -kwxTRANSLATE with xgettext!) // perform the translation (use -kwxTRANSLATE with xgettext!)
#define wxTRANSLATE(str) str #define wxTRANSLATE(str) str
@ -79,7 +88,7 @@ public:
wxString GetDomain() const { return m_domain; } wxString GetDomain() const { return m_domain; }
// get the translated string: returns NULL if not found // get the translated string: returns NULL if not found
const wxString *GetString(const wxString& sz, unsigned n = UINT_MAX) const; const wxString *GetString(const wxString& sz, unsigned n = UINT_MAX, const wxString& ct = wxEmptyString) const;
protected: protected:
wxMsgCatalog(const wxString& domain) wxMsgCatalog(const wxString& domain)
@ -154,10 +163,12 @@ public:
// access to translations // access to translations
const wxString *GetTranslatedString(const wxString& origString, const wxString *GetTranslatedString(const wxString& origString,
const wxString& domain = wxEmptyString) const; const wxString& domain = wxEmptyString,
const wxString& context = wxEmptyString) const;
const wxString *GetTranslatedString(const wxString& origString, const wxString *GetTranslatedString(const wxString& origString,
unsigned n, unsigned n,
const wxString& domain = wxEmptyString) const; const wxString& domain = wxEmptyString,
const wxString& context = wxEmptyString) const;
wxString GetHeaderValue(const wxString& header, wxString GetHeaderValue(const wxString& header,
const wxString& domain = wxEmptyString) const; const wxString& domain = wxEmptyString) const;
@ -247,10 +258,11 @@ protected:
// get the translation of the string in the current locale // get the translation of the string in the current locale
inline const wxString& wxGetTranslation(const wxString& str, inline const wxString& wxGetTranslation(const wxString& str,
const wxString& domain = wxString()) const wxString& domain = wxString(),
const wxString& context = wxString())
{ {
wxTranslations *trans = wxTranslations::Get(); wxTranslations *trans = wxTranslations::Get();
const wxString *transStr = trans ? trans->GetTranslatedString(str, domain) const wxString *transStr = trans ? trans->GetTranslatedString(str, domain, context)
: NULL; : NULL;
if ( transStr ) if ( transStr )
return *transStr; return *transStr;
@ -263,10 +275,11 @@ inline const wxString& wxGetTranslation(const wxString& str,
inline const wxString& wxGetTranslation(const wxString& str1, inline const wxString& wxGetTranslation(const wxString& str1,
const wxString& str2, const wxString& str2,
unsigned n, unsigned n,
const wxString& domain = wxString()) const wxString& domain = wxString(),
const wxString& context = wxString())
{ {
wxTranslations *trans = wxTranslations::Get(); wxTranslations *trans = wxTranslations::Get();
const wxString *transStr = trans ? trans->GetTranslatedString(str1, n, domain) const wxString *transStr = trans ? trans->GetTranslatedString(str1, n, domain, context)
: NULL; : NULL;
if ( transStr ) if ( transStr )
return *transStr; return *transStr;
@ -287,6 +300,8 @@ inline const wxString& wxGetTranslation(const wxString& str1,
#define _(s) (s) #define _(s) (s)
#endif #endif
#define wxPLURAL(sing, plur, n) ((n) == 1 ? (sing) : (plur)) #define wxPLURAL(sing, plur, n) ((n) == 1 ? (sing) : (plur))
#define wxGETTEXT_IN_CONTEXT(c, s) (s)
#define wxGETTEXT_IN_CONTEXT_PLURAL(c, sing, plur, n) wxPLURAL(sing, plur, n)
#endif #endif
#define wxTRANSLATE(str) str #define wxTRANSLATE(str) str
@ -304,6 +319,10 @@ template<typename TString, typename TDomain>
inline TString wxGetTranslation(TString str, TDomain WXUNUSED(domain)) inline TString wxGetTranslation(TString str, TDomain WXUNUSED(domain))
{ return str; } { return str; }
template<typename TString, typename TDomain, typename TContext>
inline TString wxGetTranslation(TString str, TDomain WXUNUSED(domain), TContext WXUNUSED(context))
{ return str; }
template<typename TString, typename TDomain> template<typename TString, typename TDomain>
inline TString wxGetTranslation(TString str1, TString str2, size_t n) inline TString wxGetTranslation(TString str1, TString str2, size_t n)
{ return n == 1 ? str1 : str2; } { return n == 1 ? str1 : str2; }
@ -313,6 +332,12 @@ inline TString wxGetTranslation(TString str1, TString str2, size_t n,
TDomain WXUNUSED(domain)) TDomain WXUNUSED(domain))
{ return n == 1 ? str1 : str2; } { return n == 1 ? str1 : str2; }
template<typename TString, typename TDomain, typename TContext>
inline TString wxGetTranslation(TString str1, TString str2, size_t n,
TDomain WXUNUSED(domain),
TContext WXUNUSED(context))
{ return n == 1 ? str1 : str2; }
#endif // wxUSE_INTL/!wxUSE_INTL #endif // wxUSE_INTL/!wxUSE_INTL
// define this one just in case it occurs somewhere (instead of preferred // define this one just in case it occurs somewhere (instead of preferred

View File

@ -454,6 +454,28 @@ public:
*/ */
#define wxPLURAL(string, plural, n) #define wxPLURAL(string, plural, n)
/**
Similar to _() but translates the string in the given context.
See the description of @c context argument of wxGetTranslation().
@see wxGETTEXT_IN_CONTEXT_PLURAL()
@since 3.1.1
*/
#define wxGETTEXT_IN_CONTEXT(context, string)
/**
Similar to wxPLURAL() but translates the string in the given context.
See the description of @c context argument of wxGetTranslation().
@see wxGETTEXT_IN_CONTEXT()
@since 3.1.1
*/
#define wxGETTEXT_IN_CONTEXT_PLURAL(context, string, plural, n)
/** /**
This macro doesn't do anything in the program code -- it simply expands to This macro doesn't do anything in the program code -- it simply expands to
the value of its argument. the value of its argument.
@ -515,6 +537,16 @@ public:
also common in Unix world) syntax is provided: the _() macro is defined to also common in Unix world) syntax is provided: the _() macro is defined to
do the same thing as wxGetTranslation(). do the same thing as wxGetTranslation().
If @a context is not empty (notice that this argument is only available
starting from wxWidgets 3.1.1), item translation is looked up in the
specified context. This allows to have different translations for the same
string appearing in different contexts, e.g. it may be necessary to
translate the same English "Open" verb differently depending on the object
it applies to. To do this, you need to use @c msgctxt in the source message
catalog and specify different contexts for the different occurrences of the
string and then use the same contexts in the calls to this function (or
wxGETTEXT_IN_CONTEXT() or wxGETTEXT_IN_CONTEXT_PLURAL() macros).
This function is thread-safe. This function is thread-safe.
@note This function is not suitable for literal strings using wxT() macro @note This function is not suitable for literal strings using wxT() macro
@ -527,7 +559,8 @@ public:
@header{wx/intl.h} @header{wx/intl.h}
*/ */
const wxString& wxGetTranslation(const wxString& string, const wxString& wxGetTranslation(const wxString& string,
const wxString& domain = wxEmptyString); const wxString& domain = wxEmptyString,
const wxString& context = wxEmptyString);
/** /**
This is an overloaded version of This is an overloaded version of
@ -553,7 +586,8 @@ const wxString& wxGetTranslation(const wxString& string,
*/ */
const wxString& wxGetTranslation(const wxString& string, const wxString& wxGetTranslation(const wxString& string,
const wxString& plural, unsigned n, const wxString& plural, unsigned n,
const wxString& domain = wxEmptyString); const wxString& domain = wxEmptyString,
const wxString& context = wxEmptyString);
/** /**
Macro to be used around all literal strings that should be translated. Macro to be used around all literal strings that should be translated.

Binary file not shown.

View File

@ -2,17 +2,47 @@
# Copyright (C) 1999 wxWindows development team # Copyright (C) 1999 wxWindows development team
# Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> # Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
# #
#: internat.cpp:146
#, fuzzy
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: wxWindows 2.0 i18n sample\n" "Project-Id-Version: wxWindows 2.0 i18n sample\n"
"POT-Creation-Date: 1999-01-13 18:19+0100\n" "POT-Creation-Date: 1999-01-13 18:19+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: 2016-09-20 19:38+0200\n"
"Last-Translator: Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>\n" "Last-Translator: Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"Language-Team: \n"
"Language: fr\n"
"X-Generator: Poedit 1.8.7\n"
msgid "item"
msgstr "Item without context"
msgctxt "context_1"
msgid "item"
msgstr "Item in context 1"
msgctxt "context_2"
msgid "item"
msgstr "Item in context 2"
msgid "sing"
msgid_plural "plur"
msgstr[0] "Singular form without context"
msgstr[1] "Plural form without context"
msgctxt "context_1"
msgid "sing"
msgid_plural "plur"
msgstr[0] "Singular form in context 1"
msgstr[1] "Plural form in context 1"
msgctxt "context_2"
msgid "sing"
msgid_plural "plur"
msgstr[0] "Singular form in context 2"
msgstr[1] "Plural form in context 2"
#: internat.cpp:98 #: internat.cpp:98
msgid "International wxWindows App" msgid "International wxWindows App"
@ -43,9 +73,11 @@ msgid "&Test"
msgstr "&Test" msgstr "&Test"
#: internat.cpp:138 #: internat.cpp:138
msgid "I18n sample\n" msgid ""
"I18n sample\n"
"© 1998, 1999 Vadim Zeitlin and Julian Smart" "© 1998, 1999 Vadim Zeitlin and Julian Smart"
msgstr "Exemple d'i18n\n" msgstr ""
"Exemple d'i18n\n"
"© 1998, 1999 Vadim Zeitlin et Julian Smart" "© 1998, 1999 Vadim Zeitlin et Julian Smart"
#: internat.cpp:139 #: internat.cpp:139

View File

@ -94,7 +94,16 @@ enum
INTERNAT_TEST_1, INTERNAT_TEST_1,
INTERNAT_TEST_2, INTERNAT_TEST_2,
INTERNAT_TEST_3, INTERNAT_TEST_3,
INTERNAT_TEST_MSGBOX INTERNAT_TEST_MSGBOX,
INTERNAT_MACRO_1,
INTERNAT_MACRO_2,
INTERNAT_MACRO_3,
INTERNAT_MACRO_4,
INTERNAT_MACRO_5,
INTERNAT_MACRO_6,
INTERNAT_MACRO_7,
INTERNAT_MACRO_8,
INTERNAT_MACRO_9
}; };
// language data // language data
@ -308,9 +317,23 @@ MyFrame::MyFrame(wxLocale& locale)
test_menu->Append(INTERNAT_TEST_MSGBOX, _("&Message box test"), test_menu->Append(INTERNAT_TEST_MSGBOX, _("&Message box test"),
_("Tests message box buttons labels translation")); _("Tests message box buttons labels translation"));
// Note that all these strings are currently "translated" only in French
// catalog, so you need to use French locale to see them in action.
wxMenu *macro_menu = new wxMenu;
macro_menu->Append(INTERNAT_MACRO_1, _("item"));
macro_menu->Append(INTERNAT_MACRO_2, wxGETTEXT_IN_CONTEXT("context_1", "item"));
macro_menu->Append(INTERNAT_MACRO_3, wxGETTEXT_IN_CONTEXT("context_2", "item"));
macro_menu->Append(INTERNAT_MACRO_4, wxPLURAL("sing", "plur", 1));
macro_menu->Append(INTERNAT_MACRO_5, wxPLURAL("sing", "plur", 2));
macro_menu->Append(INTERNAT_MACRO_6, wxGETTEXT_IN_CONTEXT_PLURAL("context_1", "sing", "plur", 1));
macro_menu->Append(INTERNAT_MACRO_7, wxGETTEXT_IN_CONTEXT_PLURAL("context_1", "sing", "plur", 2));
macro_menu->Append(INTERNAT_MACRO_8, wxGETTEXT_IN_CONTEXT_PLURAL("context_2", "sing", "plur", 1));
macro_menu->Append(INTERNAT_MACRO_9, wxGETTEXT_IN_CONTEXT_PLURAL("context_2", "sing", "plur", 2));
wxMenuBar *menu_bar = new wxMenuBar; wxMenuBar *menu_bar = new wxMenuBar;
menu_bar->Append(file_menu, _("&File")); menu_bar->Append(file_menu, _("&File"));
menu_bar->Append(test_menu, _("&Test")); menu_bar->Append(test_menu, _("&Test"));
menu_bar->Append(macro_menu, _("&Macro"));
SetMenuBar(menu_bar); SetMenuBar(menu_bar);
// this demonstrates RTL support in wxStatusBar: // this demonstrates RTL support in wxStatusBar:

View File

@ -1352,7 +1352,7 @@ wxMsgCatalog *wxMsgCatalog::CreateFromData(const wxScopedCharBuffer& data,
return cat.release(); return cat.release();
} }
const wxString *wxMsgCatalog::GetString(const wxString& str, unsigned n) const const wxString *wxMsgCatalog::GetString(const wxString& str, unsigned n, const wxString& context) const
{ {
int index = 0; int index = 0;
if (n != UINT_MAX) if (n != UINT_MAX)
@ -1362,11 +1362,17 @@ const wxString *wxMsgCatalog::GetString(const wxString& str, unsigned n) const
wxStringToStringHashMap::const_iterator i; wxStringToStringHashMap::const_iterator i;
if (index != 0) if (index != 0)
{ {
i = m_messages.find(wxString(str) + wxChar(index)); // plural if (context.IsEmpty())
i = m_messages.find(wxString(str) + wxChar(index)); // plural, no context
else
i = m_messages.find(wxString(context) + wxString('\x04') + wxString(str) + wxChar(index)); // plural, context
} }
else else
{ {
i = m_messages.find(str); if (context.IsEmpty())
i = m_messages.find(str); // no context
else
i = m_messages.find(wxString(context) + wxString('\x04') + wxString(str)); // context
} }
if ( i != m_messages.end() ) if ( i != m_messages.end() )
@ -1631,14 +1637,16 @@ const wxString& wxTranslations::GetUntranslatedString(const wxString& str)
const wxString *wxTranslations::GetTranslatedString(const wxString& origString, const wxString *wxTranslations::GetTranslatedString(const wxString& origString,
const wxString& domain) const const wxString& domain,
const wxString& context) const
{ {
return GetTranslatedString(origString, UINT_MAX, domain); return GetTranslatedString(origString, UINT_MAX, domain, context);
} }
const wxString *wxTranslations::GetTranslatedString(const wxString& origString, const wxString *wxTranslations::GetTranslatedString(const wxString& origString,
unsigned n, unsigned n,
const wxString& domain) const const wxString& domain,
const wxString& context) const
{ {
if ( origString.empty() ) if ( origString.empty() )
return NULL; return NULL;
@ -1652,14 +1660,14 @@ const wxString *wxTranslations::GetTranslatedString(const wxString& origString,
// does the catalog exist? // does the catalog exist?
if ( pMsgCat != NULL ) if ( pMsgCat != NULL )
trans = pMsgCat->GetString(origString, n); trans = pMsgCat->GetString(origString, n, context);
} }
else else
{ {
// search in all domains // search in all domains
for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext ) for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext )
{ {
trans = pMsgCat->GetString(origString, n); trans = pMsgCat->GetString(origString, n, context);
if ( trans != NULL ) // take the first found if ( trans != NULL ) // take the first found
break; break;
} }
@ -1670,10 +1678,11 @@ const wxString *wxTranslations::GetTranslatedString(const wxString& origString,
wxLogTrace wxLogTrace
( (
TRACE_I18N, TRACE_I18N,
"string \"%s\"%s not found in %slocale '%s'.", "string \"%s\"%s not found in %s%slocale '%s'.",
origString, origString,
(n != UINT_MAX ? wxString::Format("[%ld]", (long)n) : wxString()), (n != UINT_MAX ? wxString::Format("[%ld]", (long)n) : wxString()),
(!domain.empty() ? wxString::Format("domain '%s' ", domain) : wxString()), (!domain.empty() ? wxString::Format("domain '%s' ", domain) : wxString()),
(!context.empty() ? wxString::Format("context '%s' ", context) : wxString()),
m_lang m_lang
); );
} }
@ -1681,7 +1690,6 @@ const wxString *wxTranslations::GetTranslatedString(const wxString& origString,
return trans; return trans;
} }
wxString wxTranslations::GetHeaderValue(const wxString& header, wxString wxTranslations::GetHeaderValue(const wxString& header,
const wxString& domain) const const wxString& domain) const
{ {