From ecda4ef8bc5c101d52802fbe7a45ee2f8581cb5f Mon Sep 17 00:00:00 2001 From: York Date: Mon, 22 Jun 2026 22:17:50 +0800 Subject: [PATCH] fix: add i18n for EQ settings (#2174) * fix: add i18n for EQ settings * reuse common reset i18n labels --- src/i18n/locales/en.json | 34 +++++++ .../components/playback/eq-settings.tsx | 99 +++++++++---------- 2 files changed, 82 insertions(+), 51 deletions(-) diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index f23694ae6..8de3eee90 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -845,6 +845,22 @@ "enableAutoTranslation": "Enable auto translation", "enableFurigana_description": "Display pronunciation guides (furigana) over Japanese kanji lyrics.", "enableFurigana": "Enable furigana generation", + "equalizer_descriptionMpv": "Parametric equalizer via FFmpeg lavfi (MPV)", + "equalizer_descriptionWebAudio": "Parametric equalizer via Web Audio API", + "equalizer": "Equalizer", + "equalizerBands_description": "Per-band gain. Drag up/down or type a value. Range: -12 to +12 dB.", + "equalizerBands": "Bands", + "equalizerPreamp_description": "Input gain before EQ bands. Set negative when boosting bands to prevent clipping (MPV).", + "equalizerPreamp": "Preamp", + "equalizerPreset_description": "Apply a built-in or saved custom EQ curve", + "equalizerPreset": "Preset", + "equalizerPresetDeletePlaceholder": "Delete custom...", + "equalizerPresetGroupBuiltIn": "Built-in", + "equalizerPresetGroupCustom": "Custom", + "equalizerPresetNamePlaceholder": "Preset name...", + "equalizerPresetSelectPlaceholder": "Select preset", + "equalizerSavePreset_description": "Save the current EQ settings as a named preset", + "equalizerSavePreset": "Save preset", "enableRemote_description": "Enables the remote control server to allow other devices to control the application", "enableRemote": "Enable remote control server", "exitToTray_description": "Exit the application to the system tray", @@ -1026,6 +1042,24 @@ "showVisualizerInSidebar": "Show visualizer in player sidebar", "combinedLyricsAndVisualizer_description": "Combine lyrics and visualizer into the same panel", "combinedLyricsAndVisualizer": "Combine lyrics and visualizer in player sidebar", + "compressor_descriptionMpv": "Dynamic range compressor via FFmpeg acompressor (MPV)", + "compressor_descriptionWebAudio": "Dynamic range compressor via Web Audio API", + "compressor": "Compressor", + "compressorAttack_description": "How quickly the compressor engages after the signal exceeds the threshold.", + "compressorAttack": "Attack", + "compressorKnee_description": "Soft-knee width. Higher values make the transition into compression more gradual.", + "compressorKnee": "Knee", + "compressorMakeupGain_description": "Output gain applied after compression to restore loudness.", + "compressorMakeupGain": "Makeup Gain", + "compressorPreset_description": "Apply a built-in or saved custom compressor setting", + "compressorRatio_description": "Compression ratio, e.g. 4 = 4:1.", + "compressorRatio": "Ratio", + "compressorRelease_description": "How quickly the compressor releases after the signal drops below the threshold.", + "compressorRelease": "Release", + "compressorReset_description": "Restore all compressor parameters to their default values", + "compressorSavePreset_description": "Save the current compressor settings as a named preset", + "compressorThreshold_description": "Signal level above which compression begins.", + "compressorThreshold": "Threshold", "preservePitch_description": "Preserves pitch when modifying playback speed", "preservePitch": "Preserve pitch", "audioFadeOnStatusChange": "Audio fade on status change", diff --git a/src/renderer/features/settings/components/playback/eq-settings.tsx b/src/renderer/features/settings/components/playback/eq-settings.tsx index efe647c42..c27ecb281 100644 --- a/src/renderer/features/settings/components/playback/eq-settings.tsx +++ b/src/renderer/features/settings/components/playback/eq-settings.tsx @@ -1,6 +1,7 @@ import { useMove } from '@mantine/hooks'; import isElectron from 'is-electron'; import { memo, useCallback, useContext, useEffect, useRef, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { buildMpvAudioFilters, @@ -257,6 +258,7 @@ function EqBandSlider({ // ─── Main component ─────────────────────────────────────────────────────────── export const EqSettings = memo(() => { + const { t } = useTranslation(); const settings = usePlaybackSettings(); const { setSettings } = useSettingsStoreActions(); @@ -443,13 +445,13 @@ export const EqSettings = memo(() => { // ── Preset select data ──────────────────────────────────────────────────── const eqPresetSelectData = [ { - group: 'Built-in', + group: t('setting.equalizerPresetGroupBuiltIn'), items: Object.keys(EQ_PRESETS).map((name) => ({ label: name, value: name })), }, ...(Object.keys(customEqPresets).length > 0 ? [ { - group: 'Custom', + group: t('setting.equalizerPresetGroupCustom'), items: Object.keys(customEqPresets).map((name) => ({ label: name, value: name, @@ -461,13 +463,13 @@ export const EqSettings = memo(() => { const compPresetSelectData = [ { - group: 'Built-in', + group: t('setting.equalizerPresetGroupBuiltIn'), items: Object.keys(COMP_PRESETS).map((name) => ({ label: name, value: name })), }, ...(Object.keys(customCompPresets).length > 0 ? [ { - group: 'Custom', + group: t('setting.equalizerPresetGroupCustom'), items: Object.keys(customCompPresets).map((name) => ({ label: name, value: name, @@ -488,9 +490,9 @@ export const EqSettings = memo(() => { ), description: settings.type === PlayerType.LOCAL - ? 'Parametric equalizer via FFmpeg lavfi (MPV)' - : 'Parametric equalizer via Web Audio API', - title: 'Equalizer', + ? t('setting.equalizer', { context: 'descriptionMpv' }) + : t('setting.equalizer', { context: 'descriptionWebAudio' }), + title: t('setting.equalizer'), }, ...(settings.equalizer.enabled ? ([ @@ -505,7 +507,7 @@ export const EqSettings = memo(() => { const preset = customEqPresets[name] ?? EQ_PRESETS[name]; if (preset) applyEqPreset(preset); }} - placeholder="Select preset" + placeholder={t('setting.equalizerPresetSelectPlaceholder')} searchable value={null} w={180} @@ -521,15 +523,15 @@ export const EqSettings = memo(() => { if (!name) return; handleDeleteEqPreset(name); }} - placeholder="Delete custom..." + placeholder={t('setting.equalizerPresetDeletePlaceholder')} value={null} w={160} /> )} ), - description: 'Apply a built-in or saved custom EQ curve', - title: 'Preset', + description: t('setting.equalizerPreset', { context: 'description' }), + title: t('setting.equalizerPreset'), }, { control: ( @@ -539,7 +541,7 @@ export const EqSettings = memo(() => { onKeyDown={(e) => { if (e.key === 'Enter') handleSaveEqPreset(); }} - placeholder="Preset name..." + placeholder={t('setting.equalizerPresetNamePlaceholder')} value={saveEqName} w={180} /> @@ -548,12 +550,12 @@ export const EqSettings = memo(() => { onClick={handleSaveEqPreset} variant="subtle" > - Save + {t('common.save')} ), - description: 'Save the current EQ settings as a named preset', - title: 'Save preset', + description: t('setting.equalizerSavePreset', { context: 'description' }), + title: t('setting.equalizerSavePreset'), }, { control: ( @@ -600,13 +602,12 @@ export const EqSettings = memo(() => { w={70} /> ), - description: - 'Input gain before EQ bands. Set negative when boosting bands to prevent clipping (MPV).', - title: 'Preamp', + description: t('setting.equalizerPreamp', { context: 'description' }), + title: t('setting.equalizerPreamp'), }, { control: ( @@ -625,9 +626,8 @@ export const EqSettings = memo(() => { ))} ), - description: - 'Per-band gain. Drag up/down or type a value. Range: -12 to +12 dB.', - title: 'Bands', + description: t('setting.equalizerBands', { context: 'description' }), + title: t('setting.equalizerBands'), }, ] as SettingOption[]) : []), @@ -644,60 +644,57 @@ export const EqSettings = memo(() => { unit: string; }[] = [ { - description: 'Signal level above which compression begins.', + description: t('setting.compressorThreshold', { context: 'description' }), key: 'threshold', max: 0, min: -60, step: 1, - title: 'Threshold', + title: t('setting.compressorThreshold'), unit: 'dB', }, { - description: 'Compression ratio, e.g. 4 = 4:1.', + description: t('setting.compressorRatio', { context: 'description' }), key: 'ratio', max: 20, min: 1, step: 0.5, - title: 'Ratio', + title: t('setting.compressorRatio'), unit: ':1', }, { - description: - 'How quickly the compressor engages after the signal exceeds the threshold.', + description: t('setting.compressorAttack', { context: 'description' }), key: 'attack', max: 2000, min: 0.1, step: 1, - title: 'Attack', + title: t('setting.compressorAttack'), unit: 'ms', }, { - description: - 'How quickly the compressor releases after the signal drops below the threshold.', + description: t('setting.compressorRelease', { context: 'description' }), key: 'release', max: 9000, min: 1, step: 10, - title: 'Release', + title: t('setting.compressorRelease'), unit: 'ms', }, { - description: 'Output gain applied after compression to restore loudness.', + description: t('setting.compressorMakeupGain', { context: 'description' }), key: 'makeup', max: 30, min: 0, step: 0.5, - title: 'Makeup Gain', + title: t('setting.compressorMakeupGain'), unit: 'dB', }, { - description: - 'Soft-knee width. Higher values make the transition into compression more gradual.', + description: t('setting.compressorKnee', { context: 'description' }), key: 'knee', max: 10, min: 1, step: 0.5, - title: 'Knee', + title: t('setting.compressorKnee'), unit: 'dB', }, ]; @@ -713,9 +710,9 @@ export const EqSettings = memo(() => { ), description: settings.type === PlayerType.LOCAL - ? 'Dynamic range compressor via FFmpeg acompressor (MPV)' - : 'Dynamic range compressor via Web Audio API', - title: 'Compressor', + ? t('setting.compressor', { context: 'descriptionMpv' }) + : t('setting.compressor', { context: 'descriptionWebAudio' }), + title: t('setting.compressor'), }, ...(settings.compressor.enabled ? ([ @@ -730,7 +727,7 @@ export const EqSettings = memo(() => { const preset = customCompPresets[name] ?? COMP_PRESETS[name]; if (preset) applyCompPreset(preset); }} - placeholder="Select preset" + placeholder={t('setting.equalizerPresetSelectPlaceholder')} searchable value={null} w={180} @@ -746,15 +743,15 @@ export const EqSettings = memo(() => { if (!name) return; handleDeleteCompPreset(name); }} - placeholder="Delete custom..." + placeholder={t('setting.equalizerPresetDeletePlaceholder')} value={null} w={160} /> )} ), - description: 'Apply a built-in or saved custom compressor setting', - title: 'Preset', + description: t('setting.compressorPreset', { context: 'description' }), + title: t('setting.equalizerPreset'), }, { control: ( @@ -764,7 +761,7 @@ export const EqSettings = memo(() => { onKeyDown={(e) => { if (e.key === 'Enter') handleSaveCompPreset(); }} - placeholder="Preset name..." + placeholder={t('setting.equalizerPresetNamePlaceholder')} value={saveCompName} w={180} /> @@ -773,12 +770,12 @@ export const EqSettings = memo(() => { onClick={handleSaveCompPreset} variant="subtle" > - Save + {t('common.save')} ), - description: 'Save the current compressor settings as a named preset', - title: 'Save preset', + description: t('setting.compressorSavePreset', { context: 'description' }), + title: t('setting.equalizerSavePreset'), }, // One SettingOption per compressor parameter — Slider + NumberInput ...compParams.map(({ description, key, max, min, step, title, unit }) => ({ @@ -834,11 +831,11 @@ export const EqSettings = memo(() => { { control: ( ), - description: 'Restore all compressor parameters to their default values', - title: 'Reset', + description: t('setting.compressorReset', { context: 'description' }), + title: t('common.reset'), }, ] as SettingOption[]) : []),