1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-07-26 01:18:06 +02:00

Add support for & examples of translatable strings with context...

... This includes functions callable from Nyquist but not yet any examples
of strings with context in any .ny files.

This does include some examples of strings with context, and with both plurals
and context, in C++ files.  It is not intended to fix possible ambiguities
exhaustively.

Note that wxWidgets 3.1.1 is sufficient to support contexts.

If Audacity is build with wxWidgets 3.0, it will run, but strings with
context will fail to translate.
This commit is contained in:
Paul Licameli 2020-05-24 14:58:57 -04:00
commit e526b2b940
7 changed files with 75 additions and 13 deletions

View File

@ -5,7 +5,7 @@ sed -E 's/\.\.\///g' |\
xargs xgettext \ xargs xgettext \
--default-domain=audacity \ --default-domain=audacity \
--directory=.. \ --directory=.. \
--keyword=_ --keyword=XO --keyword=XXO --keyword=XP:1,2 \ --keyword=_ --keyword=XO --keyword=XC:1,2c --keyword=XXO --keyword=XP:1,2 --keyword=XPC:1,2,4c \
--add-comments=" i18n" \ --add-comments=" i18n" \
--add-location=file \ --add-location=file \
--copyright-holder='Audacity Team' \ --copyright-holder='Audacity Team' \
@ -19,7 +19,7 @@ sed -E 's/\.\.\///g' |\
xargs xgettext \ xargs xgettext \
--default-domain=audacity \ --default-domain=audacity \
--directory=.. \ --directory=.. \
--keyword=_ --keyword=ngettext:1,2 \ --keyword=_ --keyword=_C:1,2c --keyword=ngettext:1,2 --keyword=ngettextc:1,2,4c \
--add-comments=" i18n" \ --add-comments=" i18n" \
--add-location=file \ --add-location=file \
--copyright-holder='Audacity Team' \ --copyright-holder='Audacity Team' \

View File

@ -363,7 +363,7 @@ wxString TranslatableString::DoChooseFormat(
? ( nn == 1 ? singular : plural ) ? ( nn == 1 ? singular : plural )
: wxGetTranslation( : wxGetTranslation(
singular, plural, nn singular, plural, nn
#if wxCHECK_VERSION(3, 1, 3) #if HAS_I18N_CONTEXTS
, wxString{} // domain , wxString{} // domain
, context , context
#endif #endif

View File

@ -32,7 +32,13 @@ extern AUDACITY_DLL_API const wxString& GetCustomSubstitution(const wxString& st
// '&', preceding menu accelerators, should NOT occur in the argument. // '&', preceding menu accelerators, should NOT occur in the argument.
#define XO(s) (TranslatableString{ wxT(s), {} }) #define XO(s) (TranslatableString{ wxT(s), {} })
// Marks strings for extraction only, where '&', preceding men accelerators, MAY // Alternative taking a second context argument. A context is a string literal,
// which is not translated, but serves to disambiguate uses of the first string
// that might need differing translations, such as "Light" meaning not-heavy in
// one place but not-dark elsewhere.
#define XC(s, c) (TranslatableString{ wxT(s), {} }.Context(c))
// Marks strings for extraction only, where '&', preceding menu accelerators, MAY
// occur. // occur.
// For now, expands exactly as macro XO does, but in future there will be a // For now, expands exactly as macro XO does, but in future there will be a
// type distinction - for example XXO should be used for menu item names that // type distinction - for example XXO should be used for menu item names that
@ -86,6 +92,10 @@ extern AUDACITY_DLL_API const wxString& GetCustomSubstitution(const wxString& st
#define XP(sing, plur, n) \ #define XP(sing, plur, n) \
TranslatableString{ wxT(sing), {} }.Plural<(n)>( wxT(plur) ) TranslatableString{ wxT(sing), {} }.Plural<(n)>( wxT(plur) )
// Like XP but with an additional context argument, as for XC
#define XPC(sing, plur, n, c) \
TranslatableString{ wxT(sing), {} }.Context(c).Plural<(n)>( wxT(plur) )
#endif #endif
class Internat class Internat
@ -151,4 +161,9 @@ TranslatableStrings Msgids(
const EnumValueSymbol strings[], size_t nStrings); const EnumValueSymbol strings[], size_t nStrings);
TranslatableStrings Msgids( const std::vector<EnumValueSymbol> &strings ); TranslatableStrings Msgids( const std::vector<EnumValueSymbol> &strings );
// Whether disambiguationg contexts are supported
// If not, then the program builds and runs, but strings in the catalog with
// contexts will fail to translate
#define HAS_I18N_CONTEXTS wxCHECK_VERSION(3, 1, 1)
#endif #endif

View File

@ -1897,10 +1897,13 @@ bool PluginManager::DropFile(const wxString &fileName)
// Ask whether to enable the plug-ins // Ask whether to enable the plug-ins
if (auto nIds = ids.size()) { if (auto nIds = ids.size()) {
auto message = XP( auto message = XPC(
/* i18n-hint A plug-in is an optional added program for a sound
effect, or generator, or analyzer */
"Enable this plug-in?\n", "Enable this plug-in?\n",
"Enable these plug-ins?\n", "Enable these plug-ins?\n",
0 0,
"plug-ins"
)( nIds ); )( nIds );
for (const auto &name : names) for (const auto &name : names)
message.Join( Verbatim( name ), wxT("\n") ); message.Join( Verbatim( name ), wxT("\n") );

View File

@ -94,7 +94,8 @@ kBackgroundStrings[ ScreenshotCommand::nBackgrounds ] =
{ {
// These are acceptable dual purpose internal/visible names // These are acceptable dual purpose internal/visible names
{ XO("Blue") }, { XO("Blue") },
{ XO("White") }, /* i18n-hint: This really means the color, not as in "white noise" */
{ XC("White", "color") },
{ XO("None") }, { XO("None") },
}; };

View File

@ -41,9 +41,13 @@ enum kTypes
static const EnumValueSymbol kTypeStrings[nTypes] = static const EnumValueSymbol kTypeStrings[nTypes] =
{ {
// These are acceptable dual purpose internal/visible names // These are acceptable dual purpose internal/visible names
{ XO("White") }, /* i18n-hint: not a color, but "white noise" having a uniform spectrum */
{ XO("Pink") }, { XC("White", "noise") },
{ XO("Brownian") } /* i18n-hint: not a color, but "pink noise" having a spectrum with more power
in low frequencies */
{ XC("Pink", "noise") },
/* i18n-hint: a kind of noise spectrum also known as "red" or "brown" */
{ XC("Brownian", "noise") }
}; };
// Define keys, defaults, minimums, and maximums for the effect parameters // Define keys, defaults, minimums, and maximums for the effect parameters

View File

@ -1443,8 +1443,8 @@ bool NyquistEffect::ProcessOne()
if (rval == nyx_string) { if (rval == nyx_string) {
// Assume the string has already been translated within the Lisp runtime // Assume the string has already been translated within the Lisp runtime
// if necessary, by gettext or ngettext defined below, before it is // if necessary, by one of the gettext functions defined below, before it
// communicated back to C++ // is communicated back to C++
auto msg = Verbatim( NyquistToWxString(nyx_get_string()) ); auto msg = Verbatim( NyquistToWxString(nyx_get_string()) );
if (!msg.empty()) { // Empty string may be used as a No-Op return value. if (!msg.empty()) { // Empty string may be used as a No-Op return value.
Effect::MessageBox( msg ); Effect::MessageBox( msg );
@ -3332,20 +3332,58 @@ void NyquistOutputDialog::OnOk(wxCommandEvent & /* event */)
static LVAL gettext() static LVAL gettext()
{ {
auto string = UTF8CTOWX(getstring(xlgastring())); auto string = UTF8CTOWX(getstring(xlgastring()));
#if !HAS_I18N_CONTEXTS
// allow ignored context argument
if ( moreargs() )
nextarg();
#endif
xllastarg(); xllastarg();
return cvstring(GetCustomTranslation(string).mb_str(wxConvUTF8)); return cvstring(GetCustomTranslation(string).mb_str(wxConvUTF8));
} }
static LVAL gettextc()
{
#if HAS_I18N_CONTEXTS
auto string = UTF8CTOWX(getstring(xlgastring()));
auto context = UTF8CTOWX(getstring(xlgastring()));
xllastarg();
return cvstring(wxGetTranslation( string, "", 0, "", context )
.mb_str(wxConvUTF8));
#else
return gettext();
#endif
}
static LVAL ngettext() static LVAL ngettext()
{ {
auto string1 = UTF8CTOWX(getstring(xlgastring())); auto string1 = UTF8CTOWX(getstring(xlgastring()));
auto string2 = UTF8CTOWX(getstring(xlgastring())); auto string2 = UTF8CTOWX(getstring(xlgastring()));
auto number = getfixnum(xlgafixnum()); auto number = getfixnum(xlgafixnum());
#if !HAS_I18N_CONTEXTS
// allow ignored context argument
if ( moreargs() )
nextarg();
#endif
xllastarg(); xllastarg();
return cvstring( return cvstring(
wxGetTranslation(string1, string2, number).mb_str(wxConvUTF8)); wxGetTranslation(string1, string2, number).mb_str(wxConvUTF8));
} }
static LVAL ngettextc()
{
#if HAS_I18N_CONTEXTS
auto string1 = UTF8CTOWX(getstring(xlgastring()));
auto string2 = UTF8CTOWX(getstring(xlgastring()));
auto number = getfixnum(xlgafixnum());
auto context = UTF8CTOWX(getstring(xlgastring()));
xllastarg();
return cvstring(wxGetTranslation( string1, string2, number, "", context )
.mb_str(wxConvUTF8));
#else
return ngettext();
#endif
}
/*--------------------Audacity Automation -------------------------*/ /*--------------------Audacity Automation -------------------------*/
/* These functions may later move to their own source file. */ /* These functions may later move to their own source file. */
extern void * ExecForLisp( char * pIn ); extern void * ExecForLisp( char * pIn );
@ -3413,8 +3451,9 @@ static void RegisterFunctions()
// All function names must be UP-CASED // All function names must be UP-CASED
static const FUNDEF functions[] = { static const FUNDEF functions[] = {
{ "_", SUBR, gettext }, { "_", SUBR, gettext },
// to do: more i18n functions, for contexts and plurals { "_C", SUBR, gettextc },
{ "NGETTEXT", SUBR, ngettext }, { "NGETTEXT", SUBR, ngettext },
{ "NGETTEXTC", SUBR, ngettextc },
{ "AUD-DO", SUBR, xlc_aud_do }, { "AUD-DO", SUBR, xlc_aud_do },
}; };