Substitute, don't concatenate, when composing localized strings...

... Avoid English syntax bias.
This commit is contained in:
Paul Licameli 2018-01-03 20:47:56 -05:00
parent fa7f1a455b
commit def1d52505
20 changed files with 127 additions and 87 deletions

View File

@ -307,10 +307,11 @@ void AudacityLogger::OnSave(wxCommandEvent & WXUNUSED(e))
}
if (!mText->SaveFile(fName)) {
AudacityMessageBox(_("Couldn't save log to file: ") + fName,
_("Warning"),
wxICON_EXCLAMATION,
mFrame.get());
AudacityMessageBox(
wxString::Format( _("Couldn't save log to file: %s"), fName ),
_("Warning"),
wxICON_EXCLAMATION,
mFrame.get());
return;
}
}

View File

@ -431,7 +431,8 @@ void DependencyDialog::PopulateList()
}
else
{
mFileListCtrl->InsertItem(i, _("MISSING ") + fileName.GetFullPath());
mFileListCtrl->InsertItem(i,
wxString::Format( _("MISSING %s"), fileName.GetFullPath() ) );
mHasMissingFiles = true;
mFileListCtrl->SetItemState(i, 0, wxLIST_STATE_SELECTED); // Deselect.
mFileListCtrl->SetItemTextColour(i, *wxRED);

View File

@ -231,9 +231,10 @@ FreqWindow::FreqWindow(wxWindow * parent, wxWindowID id,
wxArrayString funcChoices;
for (int i = 0, cnt = NumWindowFuncs(); i < cnt; i++)
{
/* i18n-hint: This refers to a "window function", used in the
/* i18n-hint: This refers to a "window function",
* such as Hann or Rectangular, used in the
* Frequency analyze dialog box. */
funcChoices.Add(wxString(WindowFuncName(i)) + wxT(" ") + _("window"));
funcChoices.Add(wxString::Format("%s window", WindowFuncName(i) ) );
}
wxArrayString axisChoices;
@ -1055,7 +1056,8 @@ void FreqWindow::OnExport(wxCommandEvent & WXUNUSED(event))
#endif
f.Open();
if (!f.IsOpened()) {
AudacityMessageBox(_("Couldn't write to file: ") + fName);
AudacityMessageBox( wxString::Format(
_("Couldn't write to file: %s"), fName ) );
return;
}

View File

@ -603,7 +603,8 @@ void LabelDialog::OnImport(wxCommandEvent & WXUNUSED(event))
// Get at the data
f.Open(fileName);
if (!f.IsOpened()) {
AudacityMessageBox(_("Could not open file: ") + fileName);
AudacityMessageBox(
wxString::Format( _("Could not open file: %s"), fileName ));
}
else {
// Create a temporary label track and load the labels
@ -671,7 +672,8 @@ void LabelDialog::OnExport(wxCommandEvent & WXUNUSED(event))
#endif
f.Open();
if (!f.IsOpened()) {
AudacityMessageBox(_("Couldn't write to file: ") + fName);
AudacityMessageBox(
wxString::Format( _("Couldn't write to file: %s"), fName ) );
return;
}

View File

@ -4578,7 +4578,8 @@ void AudacityProject::OnExportLabels()
f.Create();
f.Open();
if (!f.IsOpened()) {
AudacityMessageBox(_("Couldn't write to file: ") + fName);
AudacityMessageBox( wxString::Format(
_("Couldn't write to file: %s"), fName ) );
return;
}
@ -6891,7 +6892,8 @@ void AudacityProject::OnImportLabels()
f.Open(fileName);
if (!f.IsOpened()) {
AudacityMessageBox(_("Could not open file: ") + fileName);
AudacityMessageBox(
wxString::Format( _("Could not open file: %s"), fileName ) );
return;
}

View File

@ -2979,9 +2979,10 @@ void AudacityProject::OpenFile(const wxString &fileNameArg, bool addtohistory)
}
if (!::wxFileExists(fileName)) {
AudacityMessageBox(_("Could not open file: ") + fileName,
_("Error Opening File"),
wxOK | wxCENTRE, this);
AudacityMessageBox(
wxString::Format( _("Could not open file: %s"), fileName ),
("Error Opening File"),
wxOK | wxCENTRE, this);
return;
}
@ -2994,7 +2995,8 @@ void AudacityProject::OpenFile(const wxString &fileNameArg, bool addtohistory)
{
wxFFile ff(fileName, wxT("rb"));
if (!ff.IsOpened()) {
AudacityMessageBox(_("Could not open file: ") + fileName,
AudacityMessageBox(
wxString::Format( _("Could not open file: %s"), fileName ),
_("Error opening file"),
wxOK | wxCENTRE, this);
return;
@ -3074,9 +3076,10 @@ void AudacityProject::OpenFile(const wxString &fileNameArg, bool addtohistory)
AutoSaveFile asf;
if (!asf.Decode(fileName))
{
AudacityMessageBox(_("Could not decode file: ") + fileName,
_("Error decoding file"),
wxOK | wxCENTRE, this);
AudacityMessageBox(
wxString::Format( _("Could not decode file: %s"), fileName ),
_("Error decoding file"),
wxOK | wxCENTRE, this);
return;
}
}
@ -3823,8 +3826,10 @@ bool AudacityProject::Save(bool overwrite /* = true */ ,
wxRemoveFile(safetyFileName);
if ( !wxRenameFile(mFileName, safetyFileName) ) {
AudacityMessageBox(_("Could not create safety file: ") + safetyFileName,
_("Error"), wxICON_STOP, this);
AudacityMessageBox(
wxString::Format(
_("Could not create safety file: %s"), safetyFileName ),
_("Error"), wxICON_STOP, this);
return false;
}
}
@ -5283,8 +5288,10 @@ void AudacityProject::AutoSave()
if (!wxRenameFile(fn + wxT(".tmp"), fn + wxT(".autosave")))
{
AudacityMessageBox(_("Could not create autosave file: ") + fn +
wxT(".autosave"), _("Error"), wxICON_STOP, this);
AudacityMessageBox(
wxString::Format( _("Could not create autosave file: %s"),
fn + wxT(".autosave") ),
_("Error"), wxICON_STOP, this);
return;
}
@ -5302,8 +5309,10 @@ void AudacityProject::DeleteCurrentAutoSaveFile()
{
if (!wxRemoveFile(mAutoSaveFileName))
{
AudacityMessageBox(_("Could not remove old autosave file: ") +
mAutoSaveFileName, _("Error"), wxICON_STOP, this);
AudacityMessageBox(
wxString::Format(
_("Could not remove old autosave file: %s"), mAutoSaveFileName ),
_("Error"), wxICON_STOP, this);
return;
}
}

View File

@ -2420,21 +2420,22 @@ void TrackInfo::Status1DrawFunction
/// indicating whether the track is mono, left, right, or
/// stereo and what sample rate it's using.
auto rate = wt ? wt->GetRate() : 44100.0;
wxString s = wxString::Format(wxT("%dHz"), (int) (rate + 0.5));
wxString s;
if (!wt || (wt->GetLinked()
#ifdef EXPERIMENTAL_OUTPUT_DISPLAY
&& wt->GetChannel() != Track::MonoChannel
#endif
))
s = _("Stereo, ") + s;
s = _("Stereo, %dHz");
else {
if (wt->GetChannel() == Track::MonoChannel)
s = _("Mono, ") + s;
s = _("Mono, %dHz");
else if (wt->GetChannel() == Track::LeftChannel)
s = _("Left, ") + s;
s = _("Left, %dHz");
else if (wt->GetChannel() == Track::RightChannel)
s = _("Right, ") + s;
s = _("Right, %dHz");
}
s = wxString::Format( s, (int) (rate + 0.5) );
StatusDrawFunction( s, dc, rect );
}

View File

@ -245,10 +245,11 @@ void ScreenshotCommand::Capture(const wxString &filename,
// Save the final image
wxImage image = part.ConvertToImage();
if (image.SaveFile(filename)) {
mOutput->Status(_("Saved ") + filename);
mOutput->Status( wxString::Format( _("Saved %s"), filename ) );
}
else {
mOutput->Error(_("Error trying to save file: ") + filename);
mOutput->Error(
wxString::Format( _("Error trying to save file: %s"), filename ) );
}
::wxBell();

View File

@ -313,8 +313,9 @@ bool EffectChangeTempo::TransferDataToWindow()
m_bLoopDetect = false;
// Set the accessibility name here because we need m_pTextCtrl_FromLength to have had its value set
m_pTextCtrl_ToLength->SetName(_("Length in seconds from") + wxT(" ") + m_pTextCtrl_FromLength->GetValue()
+wxT(", ") + _("to"));
m_pTextCtrl_ToLength->SetName(
wxString::Format( _("Length in seconds from %s, to"),
m_pTextCtrl_FromLength->GetValue() ) );
return true;
}

View File

@ -513,7 +513,8 @@ void ContrastDialog::OnExport(wxCommandEvent & WXUNUSED(event))
#endif
f.Open();
if (!f.IsOpened()) {
AudacityMessageBox(_("Couldn't write to file: ") + fName);
AudacityMessageBox(
wxString::Format( _("Couldn't write to file: %s"), fName) );
return;
}

View File

@ -576,10 +576,10 @@ void EffectDtmf::UpdateUI(void)
mDtmfDutyT->SetLabel(wxString::Format(wxT("%.1f %%"), dtmfDutyCycle));
mDtmfDutyT->SetName(mDtmfDutyT->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
mDtmfSilenceT->SetLabel(wxString::Format(wxString(wxT("%.0f ")) + _("ms"), dtmfTone * 1000.0));
mDtmfSilenceT->SetLabel(wxString::Format(_("%.0f ms"), dtmfTone * 1000.0));
mDtmfSilenceT->SetName(mDtmfSilenceT->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
mDtmfToneT->SetLabel(wxString::Format(wxString(wxT("%0.f ")) + _("ms"), dtmfSilence * 1000.0));
mDtmfToneT->SetLabel(wxString::Format(_("%.0f ms"), dtmfSilence * 1000.0));
mDtmfToneT->SetName(mDtmfToneT->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
}

View File

@ -653,7 +653,7 @@ void EffectEqualization::PopulateOrExchange(ShuttleGui & S)
mdBMaxSlider = S.Id(ID_dBMax).AddSlider( {}, 30, 60, 0);
#if wxUSE_ACCESSIBILITY
mdBMaxSlider->SetName(_("Max dB"));
mdBMaxSlider->SetAccessible(safenew SliderAx(mdBMaxSlider, wxString(wxT("%d ")) + _("dB")));
mdBMaxSlider->SetAccessible(safenew SliderAx(mdBMaxSlider, _("%d dB")));
#endif
S.SetStyle(wxSL_VERTICAL | wxSL_INVERSE);
@ -661,7 +661,7 @@ void EffectEqualization::PopulateOrExchange(ShuttleGui & S)
S.AddVariableText(_("- dB"), false, wxCENTER);
#if wxUSE_ACCESSIBILITY
mdBMinSlider->SetName(_("Min dB"));
mdBMinSlider->SetAccessible(safenew SliderAx(mdBMinSlider, wxString(wxT("%d ")) + _("dB")));
mdBMinSlider->SetAccessible(safenew SliderAx(mdBMinSlider, _("%d dB")));
#endif
}
S.EndVerticalLay();
@ -720,11 +720,11 @@ void EffectEqualization::PopulateOrExchange(ShuttleGui & S)
#if wxUSE_ACCESSIBILITY
wxString name;
if( kThirdOct[i] < 1000.)
name.Printf(wxString(wxT("%d ")) + _("Hz"), (int)kThirdOct[i]);
name.Printf(_("%d Hz"), (int)kThirdOct[i]);
else
name.Printf(wxString(wxT("%g ")) + _("kHz"), kThirdOct[i]/1000.);
name.Printf(_("%g kHz"), kThirdOct[i]/1000.);
mSliders[i]->SetName(name);
mSliders[i]->SetAccessible(safenew SliderAx(mSliders[i], wxString(wxT("%d ")) + _("dB")));
mSliders[i]->SetAccessible(safenew SliderAx(mSliders[i], _("%d dB")));
#endif
mSlidersOld[i] = 0;
mEQVals[i] = 0.;
@ -1004,7 +1004,7 @@ bool EffectEqualization::TransferDataFromWindow()
if (dB != mdBMin) {
rr = true;
mdBMin = dB;
tip.Printf(wxString(wxT("%d ")) + _("dB"),(int)mdBMin);
tip.Printf(_("%d dB"), (int)mdBMin);
mdBMinSlider->SetToolTip(tip);
}
@ -1012,7 +1012,7 @@ bool EffectEqualization::TransferDataFromWindow()
if (dB != mdBMax) {
rr = true;
mdBMax = dB;
tip.Printf(wxString(wxT("%d ")) + _("dB"),(int)mdBMax);
tip.Printf(_("%d dB"), (int)mdBMax);
mdBMaxSlider->SetToolTip(tip);
}
@ -3316,10 +3316,11 @@ void EditCurvesDialog::OnRename(wxCommandEvent & WXUNUSED(event))
bad = false;
// build the dialog
AudacityTextEntryDialog dlg( this,
_("Rename '") + mEditCurves[ item ].Name + _("' to..."),
wxString::Format( _("Rename '%s' to..."), mEditCurves[ item ].Name ),
_("Rename...") );
dlg.SetTextValidator( wxFILTER_EXCLUDE_CHAR_LIST );
dlg.SetName( _("Rename '") + mEditCurves[ item ].Name );
dlg.SetName(
wxString::Format( _("Rename '%s'"), mEditCurves[ item ].Name ) );
wxTextValidator *tv = dlg.GetTextValidator();
tv->SetExcludes( exclude ); // Tell the validator about excluded chars
if( dlg.ShowModal() == wxID_CANCEL )

View File

@ -192,12 +192,14 @@ bool EffectNormalize::Process()
// Process only if the right marker is to the right of the left marker
if (mCurT1 > mCurT0) {
wxString msg;
wxString trackName = track->GetName();
auto trackName = track->GetName();
if(!track->GetLinked() || mStereoInd)
msg = topMsg + _("Analyzing: ") + trackName;
msg =
topMsg + wxString::Format( _("Analyzing: %s"), trackName );
else
msg = topMsg + _("Analyzing first track of stereo pair: ") + trackName;
msg =
topMsg + wxString::Format( _("Analyzing first track of stereo pair: %s"), trackName );
float offset, min, max;
bGoodResult = AnalyseTrack(track, msg, curTrackNum, offset, min, max);
if (!bGoodResult )
@ -209,9 +211,11 @@ bool EffectNormalize::Process()
mMult = ratio / extent;
else
mMult = 1.0;
msg = topMsg + _("Processing: ") + trackName;
msg =
topMsg + wxString::Format( _("Processing: %s"), trackName );
if(track->GetLinked() || prevTrack->GetLinked()) // only get here if there is a linked track but we are processing independently
msg = topMsg + _("Processing stereo channels independently: ") + trackName;
msg =
topMsg + wxString::Format( _("Processing stereo channels independently: %s"), trackName );
if (!ProcessOne(track, msg, curTrackNum, offset))
{
@ -225,7 +229,8 @@ bool EffectNormalize::Process()
// so we need to find it's min, max and offset
// as they are needed to calc the multiplier for both tracks
track = (WaveTrack *) iter.Next(); // get the next one
msg = topMsg + _("Analyzing second track of stereo pair: ") + trackName;
msg =
topMsg + wxString::Format( _("Analyzing second track of stereo pair: %s"), trackName );
float offset2, min2, max2;
bGoodResult = AnalyseTrack(track, msg, curTrackNum + 1, offset2, min2, max2);
if ( !bGoodResult )
@ -238,7 +243,8 @@ bool EffectNormalize::Process()
else
mMult = 1.0;
track = (WaveTrack *) iter.Prev(); // go back to the first linked one
msg = topMsg + _("Processing first track of stereo pair: ") + trackName;
msg =
topMsg + wxString::Format( _("Processing first track of stereo pair: %s"), trackName );
if (!ProcessOne(track, msg, curTrackNum, offset))
{
bGoodResult = false;
@ -246,7 +252,8 @@ bool EffectNormalize::Process()
}
track = (WaveTrack *) iter.Next(); // go to the second linked one
curTrackNum++; // keeps progress bar correct
msg = topMsg + _("Processing second track of stereo pair: ") + trackName;
msg =
topMsg + wxString::Format( _("Processing second track of stereo pair: %s"), trackName );
if (!ProcessOne(track, msg, curTrackNum, offset2))
{
bGoodResult = false;

View File

@ -227,7 +227,7 @@ void EffectRepeat::DisplayNewTime()
mT1 - mT0,
mProjectRate);
str = _("Current selection length: ") + nc.GetString();
str = wxString::Format( _("Current selection length: %s"), nc.GetString() );
mCurrentTime->SetLabel(str);
mCurrentTime->SetName(str); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs)
@ -237,7 +237,7 @@ void EffectRepeat::DisplayNewTime()
repeatCount = l;
nc.SetValue((mT1 - mT0) * (repeatCount + 1));
str = _("New selection length: ") + nc.GetString();
str = wxString::Format( _("New selection length: %s"), nc.GetString() );
}
else {
str = _("Warning: No repeats.");

View File

@ -411,7 +411,7 @@ void EffectScienFilter::PopulateOrExchange(ShuttleGui & S)
mdBMaxSlider = S.Id(ID_dBMax).AddSlider( {}, 10, 20, 0);
#if wxUSE_ACCESSIBILITY
mdBMaxSlider->SetName(_("Max dB"));
mdBMaxSlider->SetAccessible(safenew SliderAx(mdBMaxSlider, wxString(wxT("%d ")) + _("dB")));
mdBMaxSlider->SetAccessible(safenew SliderAx(mdBMaxSlider, _("%d dB")));
#endif
S.SetStyle(wxSL_VERTICAL | wxSL_INVERSE);
@ -419,7 +419,7 @@ void EffectScienFilter::PopulateOrExchange(ShuttleGui & S)
S.AddVariableText(_("- dB"), false, wxCENTER);
#if wxUSE_ACCESSIBILITY
mdBMinSlider->SetName(_("Min dB"));
mdBMinSlider->SetAccessible(safenew SliderAx(mdBMinSlider, wxString(wxT("%d ")) + _("dB")));
mdBMinSlider->SetAccessible(safenew SliderAx(mdBMinSlider, _("%d dB")));
#endif
}
S.EndVerticalLay();
@ -579,7 +579,7 @@ bool EffectScienFilter::TransferGraphLimitsFromWindow()
if (dB != mdBMin) {
rr = true;
mdBMin = dB;
tip.Printf(wxString(wxT("%d ")) + _("dB"), (int)mdBMin);
tip.Printf(_("%d dB"), (int)mdBMin);
mdBMinSlider->SetToolTip(tip);
}
@ -587,7 +587,7 @@ bool EffectScienFilter::TransferGraphLimitsFromWindow()
if (dB != mdBMax) {
rr = true;
mdBMax = dB;
tip.Printf(wxString(wxT("%d ")) + _("dB"),(int)mdBMax);
tip.Printf(_("%d dB"),(int)mdBMax);
mdBMaxSlider->SetToolTip(tip);
}

View File

@ -595,9 +595,9 @@ bool Exporter::GetFilename()
// as an extension with no name, like just plain ".wav".
//
if (mFilename.GetName().Left(1) == wxT(".")) {
wxString prompt = _("Are you sure you want to export the file as \"") +
mFilename.GetFullName() +
wxT("\"?\n");
wxString prompt = wxString::Format(
_("Are you sure you want to export the file as \"%s\"?\n"),
mFilename.GetFullName() );
int action = AudacityMessageBox(prompt,
_("Warning"),
@ -1267,9 +1267,11 @@ ExportMixerDialog::ExportMixerDialog( const TrackList *tracks, bool selectedOnly
numTracks++;
const wxString sTrackName = (t->GetName()).Left(20);
if( t->GetChannel() == Track::LeftChannel )
mTrackNames.Add(sTrackName + _( " - L" ));
/* i18n-hint: track name and L abbreviating Left channel */
mTrackNames.Add( wxString::Format( _( "%s - L" ), sTrackName ) );
else if( t->GetChannel() == Track::RightChannel )
mTrackNames.Add(sTrackName + _( " - R" ));
/* i18n-hint: track name and R abbreviating Right channel */
mTrackNames.Add( wxString::Format( _( "%s - R" ), sTrackName ) );
else
mTrackNames.Add(sTrackName);
}

View File

@ -662,14 +662,15 @@ bool Importer::Import(const wxString &fName,
else
{
// We DO have a plugin for this file, but import failed.
wxString pluglist = wxEmptyString;
wxString pluglist;
for (const auto &plugin : compatiblePlugins)
{
if (pluglist == wxEmptyString)
if (pluglist.empty())
pluglist = plugin->GetPluginFormatDescription();
else
pluglist = pluglist + wxT(", ") + plugin->GetPluginFormatDescription();
pluglist = wxString::Format( _("%s, %s"),
pluglist, plugin->GetPluginFormatDescription() );
}
errorMessage.Printf(_("Audacity recognized the type of the file '%s'.\nImporters supposedly supporting such files are:\n%s,\nbut none of them understood this file format."),fName, pluglist);

View File

@ -28,9 +28,9 @@
bool ImportMIDI(const wxString &fName, NoteTrack * dest)
{
if (fName.Length() <= 4){
AudacityMessageBox(
_("Could not open file ") + fName + _(": Filename too short.")
);
AudacityMessageBox( wxString::Format(
_("Could not open file %s: Filename too short."), fName
) );
return false;
}
@ -38,17 +38,17 @@ bool ImportMIDI(const wxString &fName, NoteTrack * dest)
if (fName.Right(4).CmpNoCase(wxT(".mid")) == 0 || fName.Right(5).CmpNoCase(wxT(".midi")) == 0)
is_midi = true;
else if(fName.Right(4).CmpNoCase(wxT(".gro")) != 0) {
AudacityMessageBox(
_("Could not open file ") + fName + _(": Incorrect filetype.")
);
AudacityMessageBox( wxString::Format(
_("Could not open file %s: Incorrect filetype."), fName
) );
return false;
}
wxFFile mf(fName, wxT("rb"));
if (!mf.IsOpened()) {
AudacityMessageBox(
_("Could not open file ") + fName + wxT(".")
);
AudacityMessageBox( wxString::Format(
_("Could not open file %s."), fName
) );
return false;
}
@ -57,9 +57,9 @@ bool ImportMIDI(const wxString &fName, NoteTrack * dest)
//Should we also check if(seq->tracks() == 0) ?
if(new_seq->get_read_error() == alg_error_open){
AudacityMessageBox(
_("Could not open file ") + fName + wxT(".")
);
AudacityMessageBox( wxString::Format(
_("Could not open file %s."), fName
) );
mf.Close();
return false;
}

View File

@ -614,11 +614,13 @@ void KeyConfigPrefs::OnSet(wxCommandEvent & WXUNUSED(event))
}
// Prevent same hotkey combination being used twice.
if (!oldname.IsEmpty()) {
wxString oldlabel = mManager->GetCategoryFromName(oldname) + wxT(" - ") +
mManager->GetPrefixedLabelFromName(oldname);
wxString newlabel = mManager->GetCategoryFromName(newname) + wxT(" - ") +
mManager->GetPrefixedLabelFromName(newname);
if (!oldname.empty()) {
auto oldlabel = wxString::Format( _("%s - %s"),
mManager->GetCategoryFromName(oldname),
mManager->GetPrefixedLabelFromName(oldname) );
auto newlabel = wxString::Format( _("%s - %s"),
mManager->GetCategoryFromName(newname),
mManager->GetPrefixedLabelFromName(newname) );
if (AudacityMessageBox(
wxString::Format(
_("The keyboard shortcut '%s' is already assigned to:\n\n\t'%s'\n\nClick OK to assign the shortcut to\n\n\t'%s'\n\ninstead. Otherwise, click Cancel."),

View File

@ -286,8 +286,14 @@ void MixerToolBar::SetToolTips()
}
if (mOutputSlider->IsEnabled()) {
mOutputSlider->SetToolTipTemplate(wxString::Format(
_("Playback Volume: %%.2f%s"), gAudioIO->OutputMixerEmulated() ? _(" (emulated)") : wxT("")));
wxString format;
if (gAudioIO->OutputMixerEmulated())
format = _("Playback Volume: %s (emulated)");
else
format = _("Playback Volume: %s");
mOutputSlider->SetToolTipTemplate(
wxString::Format( format, "%.2f" ) );
}
else {
mOutputSlider->SetToolTipTemplate(_("Playback Volume (Unavailable; use system mixer.)"));