From adc26956884e909e1443a7332731b85fef74cd7f Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Fri, 8 Sep 2017 14:48:06 -0400 Subject: [PATCH 1/4] i18n-hints about the name "Nyquist" ... ... Although "Nyquist" is a proper name, still, translators should have discretion to transliterate it into another alphabet, and also make it consistent with longer translated strings containing it. Not so for debug messages mentioning actual keywords of Nyquist programming. --- src/effects/nyquist/Nyquist.cpp | 9 +++++++++ src/effects/nyquist/Nyquist.h | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/effects/nyquist/Nyquist.cpp b/src/effects/nyquist/Nyquist.cpp index dab6a7d8e..6124e769c 100644 --- a/src/effects/nyquist/Nyquist.cpp +++ b/src/effects/nyquist/Nyquist.cpp @@ -149,6 +149,10 @@ NyquistEffect::NyquistEffect(const wxString &fName) // Interactive Nyquist if (fName == NYQUIST_PROMPT_ID) { + /* i18n-hint: "Nyquist" is an embedded interpreted programming language in + Audacity, named in honor of the Swedish-American Harry Nyquist (or Nyqvist). + In the translations of this and other strings, you may transliterate the + name into another alphabet. */ mName = XO("Nyquist Prompt"); mType = EffectTypeProcess; mOK = true; @@ -159,6 +163,7 @@ NyquistEffect::NyquistEffect(const wxString &fName) if (fName == NYQUIST_WORKER_ID) { // Effect spawned from Nyquist Prompt +/* i18n-hint: It is acceptable to translate this the same as for "Nyquist Prompt" */ mName = XO("Nyquist Worker"); return; } @@ -1389,6 +1394,8 @@ wxString NyquistEffect::NyquistToWxString(const char *nyqString) if (nyqString != NULL && nyqString[0] && str.IsEmpty()) { // invalid UTF-8 string, convert as Latin-1 str = _("[Warning: Nyquist returned invalid UTF-8 string, converted here as Latin-1]"); + // TODO: internationalization of strings from Nyquist effects, at least + // from those shipped with Audacity str += LAT1CTOWX(nyqString); } return str; @@ -1835,6 +1842,8 @@ bool NyquistEffect::ParseProgram(wxInputStream & stream) } if (!mFoundType && mIsPrompt) { + /* i1n-hint: SAL and LISP are names for variant syntaxes for the + Nyquist programming language. Leave them, and 'return', untranslated. */ wxMessageBox(_("Your code looks like SAL syntax, but there is no \'return\' statement.\n\ For SAL, use a return statement such as:\n\treturn *track* * 0.1\n\ or for LISP, begin with an open parenthesis such as:\n\t(mult *track* 0.1)\n ."), diff --git a/src/effects/nyquist/Nyquist.h b/src/effects/nyquist/Nyquist.h index 07eed2d87..5123de117 100644 --- a/src/effects/nyquist/Nyquist.h +++ b/src/effects/nyquist/Nyquist.h @@ -193,7 +193,7 @@ private: bool mOK; wxString mInputCmd; // history: exactly what the user typed wxString mCmd; // the command to be processed - wxString mName; ///< Name of the Effect + wxString mName; ///< Name of the Effect (untranslated) wxString mAction; wxString mInfo; wxString mAuthor; From 42f89458127ef48da5830738516b9c53b5a6f1d5 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Fri, 8 Sep 2017 13:11:54 -0400 Subject: [PATCH 2/4] Fix statically allocated message string in _() (didn't translate!) --- src/Project.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Project.cpp b/src/Project.cpp index a8aafeb19..b027aa72c 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -2906,18 +2906,20 @@ void AudacityProject::OpenFiles(AudacityProject *proj) // Most of this string was duplicated 3 places. Made the warning consistent in this global. // The %s is to be filled with the version string. -static wxString gsLegacyFileWarning = +// PRL: Do not statically allocate a string in _() ! +static wxString gsLegacyFileWarning() { return _("This file was saved by Audacity version %s. The format has changed. \ \n\nAudacity can try to open and save this file, but saving it in this \ \nversion will then prevent any 1.2 or earlier version opening it. \ \n\nAudacity might corrupt the file in opening it, so you should \ back it up first. \ \n\nOpen this file now?"); +} bool AudacityProject::WarnOfLegacyFile( ) { wxString msg; - msg.Printf(gsLegacyFileWarning, _("1.0 or earlier")); + msg.Printf(gsLegacyFileWarning(), _("1.0 or earlier")); // Stop icon, and choose 'NO' by default. int action = @@ -3523,7 +3525,7 @@ bool AudacityProject::HandleXMLTag(const wxChar *tag, const wxChar **attrs) // Specifically detect older versions of Audacity if ( bIsOld | bIsVeryOld ) { wxString msg; - msg.Printf(gsLegacyFileWarning, audacityVersion.c_str()); + msg.Printf(gsLegacyFileWarning(), audacityVersion.c_str()); int icon_choice = wxICON_EXCLAMATION; if( bIsVeryOld ) From 5f298accbd8e96f3925aaf171a8e2f69981bf8f7 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 6 Sep 2017 23:35:54 -0400 Subject: [PATCH 3/4] Translated effect name and description in many places in Effect.cpp... ... including titles of dialogs, messages, About sub-menu of the Manage button, long-form names of Undo items (in history view), message for why command is not allowed when there is no selection Also one place in Effect Rack code but it's commented out --- include/audacity/IdentInterface.h | 4 +++ src/PluginManager.cpp | 12 ++++++++ src/effects/Effect.cpp | 34 +++++++++++++++------- src/effects/Effect.h | 10 +++++++ src/effects/EffectManager.cpp | 2 +- src/effects/EffectRack.cpp | 3 +- src/effects/audiounits/AudioUnitEffect.cpp | 3 +- 7 files changed, 54 insertions(+), 14 deletions(-) diff --git a/include/audacity/IdentInterface.h b/include/audacity/IdentInterface.h index 7f521d745..178a7b78f 100644 --- a/include/audacity/IdentInterface.h +++ b/include/audacity/IdentInterface.h @@ -59,6 +59,10 @@ public: virtual wxString GetVendor() = 0; virtual wxString GetVersion() = 0; virtual wxString GetDescription() = 0; + + // non-virtual convenience functions + const wxString& GetTranslatedName(); + const wxString& GetTranslatedDescription(); }; #endif // __AUDACITY_IDENTINTERFACE_H__ diff --git a/src/PluginManager.cpp b/src/PluginManager.cpp index 20c1c5120..0a890328a 100644 --- a/src/PluginManager.cpp +++ b/src/PluginManager.cpp @@ -2972,3 +2972,15 @@ int PluginManager::b64decode(const wxString &in, void *out) return p - (unsigned char *) out; } + +// These are defined out-of-line here, to keep IdentInterface free of other +// #include directives. +const wxString& IdentInterface::GetTranslatedName() +{ + return wxGetTranslation( GetName() ); +} + +const wxString& IdentInterface::GetTranslatedDescription() +{ + return wxGetTranslation( GetDescription() ); +} diff --git a/src/effects/Effect.cpp b/src/effects/Effect.cpp index 4cff3c95f..ecf65522e 100644 --- a/src/effects/Effect.cpp +++ b/src/effects/Effect.cpp @@ -1050,10 +1050,10 @@ bool Effect::SetAutomationParameters(const wxString & parms) if (!success) { - wxMessageBox( + Effect::MessageBox( wxString::Format( _("%s: Could not load settings below. Default settings will be used.\n\n%s"), - GetName().c_str(), + GetTranslatedName().c_str(), preset.c_str() ) ); @@ -1215,9 +1215,10 @@ bool Effect::DoEffect(wxWindow *parent, bool skipFlag = CheckWhetherSkipEffect(); if (skipFlag == false) { + auto name = GetTranslatedName(); ProgressDialog progress{ - GetName(), - wxString::Format(_("Applying %s..."), GetName().c_str()), + name, + wxString::Format(_("Applying %s..."), name.c_str()), pdlgHideStopButton }; auto vr = valueRestorer( mProgress, &progress ); @@ -2563,7 +2564,7 @@ void Effect::Preview(bool dryOnly) // Apply effect if (!dryOnly) { ProgressDialog progress{ - GetName(), + GetTranslatedName(), _("Preparing preview"), pdlgHideCancelButton }; // Have only "Stop" button. @@ -2608,7 +2609,7 @@ void Effect::Preview(bool dryOnly) // The progress dialog blocks these events. { ProgressDialog progress - (GetName(), _("Previewing"), pdlgHideCancelButton); + (GetTranslatedName(), _("Previewing"), pdlgHideCancelButton); while (gAudioIO->IsStreamActive(token) && previewing == ProgressResult::Success) { ::wxMilliSleep(100); @@ -2630,6 +2631,17 @@ void Effect::Preview(bool dryOnly) } } +int Effect::MessageBox +(const wxString& message, long style, const wxString &titleStr) +{ + wxString title; + if (titleStr.empty()) + title = GetTranslatedName(); + else + title = wxString::Format(_("%s: %s"), GetTranslatedName(), titleStr); + return wxMessageBox(message, title, style, mUIParent); +} + BEGIN_EVENT_TABLE(EffectDialog, wxDialogWrapper) EVT_BUTTON(wxID_OK, EffectDialog::OnOk) END_EVENT_TABLE() @@ -2807,7 +2819,7 @@ END_EVENT_TABLE() EffectUIHost::EffectUIHost(wxWindow *parent, Effect *effect, EffectUIClientInterface *client) -: wxDialogWrapper(parent, wxID_ANY, effect->GetName(), +: wxDialogWrapper(parent, wxID_ANY, effect->GetTranslatedName(), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMINIMIZE_BOX | wxMAXIMIZE_BOX) { @@ -2816,7 +2828,7 @@ EffectUIHost::EffectUIHost(wxWindow *parent, [[((NSView *)GetHandle()) window] setLevel:NSFloatingWindowLevel]; #endif - SetName(effect->GetName()); + SetName( effect->GetTranslatedName() ); SetExtraStyle(wxWS_EX_VALIDATE_RECURSIVELY); mParent = parent; @@ -3177,7 +3189,7 @@ void EffectUIHost::OnApply(wxCommandEvent & evt) { auto flags = AlwaysEnabledFlag; bool allowed = mProject->ReportIfActionNotAllowed( - mEffect->GetName(), + mEffect->GetTranslatedName(), flags, WaveTracksSelectedFlag | TimeSelectedFlag, WaveTracksSelectedFlag | TimeSelectedFlag); @@ -3335,10 +3347,10 @@ void EffectUIHost::OnMenu(wxCommandEvent & WXUNUSED(evt)) auto sub = std::make_unique(); sub->Append(kDummyID, wxString::Format(_("Type: %s"), mEffect->GetFamily().c_str())); - sub->Append(kDummyID, wxString::Format(_("Name: %s"), mEffect->GetName().c_str())); + sub->Append(kDummyID, wxString::Format(_("Name: %s"), mEffect->GetTranslatedName().c_str())); sub->Append(kDummyID, wxString::Format(_("Version: %s"), mEffect->GetVersion().c_str())); sub->Append(kDummyID, wxString::Format(_("Vendor: %s"), mEffect->GetVendor().c_str())); - sub->Append(kDummyID, wxString::Format(_("Description: %s"), mEffect->GetDescription().c_str())); + sub->Append(kDummyID, wxString::Format(_("Description: %s"), mEffect->GetTranslatedDescription().c_str())); menu.Append(0, _("About"), sub.release()); } diff --git a/src/effects/Effect.h b/src/effects/Effect.h index 4c65cbeab..0af69289a 100644 --- a/src/effects/Effect.h +++ b/src/effects/Effect.h @@ -261,6 +261,15 @@ class AUDACITY_DLL_API Effect /* not final */ : public wxEvtHandler, /* not virtual */ bool IsRealtimeActive(); virtual bool IsHidden(); + + // Nonvirtual + // Display a message box, using effect's (translated) name as the prefix + // for the title. + enum : long { DefaultMessageBoxStyle = wxOK | wxCENTRE }; + int MessageBox(const wxString& message, + long style = DefaultMessageBoxStyle, + const wxString& titleStr = wxString{}); + // // protected virtual methods // @@ -268,6 +277,7 @@ class AUDACITY_DLL_API Effect /* not final */ : public wxEvtHandler, // do its processing. // protected: + // Called once each time an effect is called. Perform any initialization; // make sure that the effect can be performed on the selected tracks and // return false otherwise diff --git a/src/effects/EffectManager.cpp b/src/effects/EffectManager.cpp index 1e22e9b37..af7e58e10 100644 --- a/src/effects/EffectManager.cpp +++ b/src/effects/EffectManager.cpp @@ -149,7 +149,7 @@ wxString EffectManager::GetEffectDescription(const PluginID & ID) if (effect) { - return wxString::Format(_("Applied effect: %s"), effect->GetName().c_str()); + return wxString::Format(_("Applied effect: %s"), GetEffectName(ID).c_str()); } return wxEmptyString; diff --git a/src/effects/EffectRack.cpp b/src/effects/EffectRack.cpp index f1ecf8f45..a9f90dd84 100644 --- a/src/effects/EffectRack.cpp +++ b/src/effects/EffectRack.cpp @@ -248,7 +248,8 @@ void EffectRack::Add(Effect *effect, bool active, bool favorite) bb->SetToolTip(_("Remove effect from the rack")); mMainSizer->Add(bb, 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL); - wxStaticText *text = safenew wxStaticText(mPanel, ID_NAME + mNumEffects, effect->GetName()); + wxStaticText *text = safenew wxStaticText(mPanel, ID_NAME + mNumEffects, + effect->GetTranslatedName() ); text->SetToolTip(_("Name of the effect")); mMainSizer->Add(text, 0, wxEXPAND | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 5); diff --git a/src/effects/audiounits/AudioUnitEffect.cpp b/src/effects/audiounits/AudioUnitEffect.cpp index 755c31a76..5ca61e876 100644 --- a/src/effects/audiounits/AudioUnitEffect.cpp +++ b/src/effects/audiounits/AudioUnitEffect.cpp @@ -892,7 +892,8 @@ wxString AudioUnitEffect::GetVersion() wxString AudioUnitEffect::GetDescription() { - return wxT("N/A"); + /* i18n-hint: Can mean "not available," "not applicable," "no answer" */ + return XO("n/a"); } // ============================================================================ From e2129feac9b01f9d3116ac228e2c5d599d262c01 Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Wed, 6 Sep 2017 21:55:23 -0400 Subject: [PATCH 4/4] Translate the items in the popup menu of the scrubbing ruler --- src/tracks/ui/Scrubbing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tracks/ui/Scrubbing.cpp b/src/tracks/ui/Scrubbing.cpp index c40acf8b4..fd8fea2de 100644 --- a/src/tracks/ui/Scrubbing.cpp +++ b/src/tracks/ui/Scrubbing.cpp @@ -1028,7 +1028,7 @@ void Scrubber::PopulatePopupMenu(wxMenu &menu) for (const auto &item : menuItems) { if (cm->GetEnabled(item.name)) { auto test = item.StatusTest; - menu.Append(id, item.label, wxString{}, + menu.Append(id, wxGetTranslation(item.label), wxString{}, test ? wxITEM_CHECK : wxITEM_NORMAL); if(test && (this->*test)()) menu.FindItem(id)->Check();