From b10e330590766ea621c0b03401e77a0589558e76 Mon Sep 17 00:00:00 2001 From: "Dedy F. Setyawan" Date: Mon, 13 Jul 2026 18:51:23 +0700 Subject: [PATCH] feat(react-ui): localize MediaHistory, AudioTransform, and Sound components (#10802) - Replace hardcoded text with useTranslation hook in UI components - Add localization support for both English (en) and Indonesian (id) locales Signed-off-by: Dedy F. Setyawan --- .../react-ui/public/locales/en/media.json | 53 ++++++++++++++- .../react-ui/public/locales/id/media.json | 57 ++++++++++++++-- .../react-ui/src/components/MediaHistory.jsx | 10 +-- .../react-ui/src/pages/AudioTransform.jsx | 67 ++++++++++--------- core/http/react-ui/src/pages/Sound.jsx | 42 ++++++------ 5 files changed, 164 insertions(+), 65 deletions(-) diff --git a/core/http/react-ui/public/locales/en/media.json b/core/http/react-ui/public/locales/en/media.json index f971a45c9..7beefe10b 100644 --- a/core/http/react-ui/public/locales/en/media.json +++ b/core/http/react-ui/public/locales/en/media.json @@ -264,14 +264,22 @@ "model": "Model", "prompt": "Prompt", "promptPlaceholder": "Describe the sound you want to generate...", + "instrumental": "Instrumental", + "bpm": "BPM", "duration": "Duration (seconds)", "language": "Language", + "timesignature": "Time Signature", + "keyscale": "Key/Scale", "vocalLanguage": "Vocal language", - "lyrics": "Lyrics (optional)", + "vocalLanguagePlaceholder": "e.g. English", + "caption": "Caption", + "lyrics": "Lyrics", "lyricsPlaceholder": "Lyrics for vocal generation", - "advanced": "Advanced Settings", + "simple": "Simple", + "advanced": "Advanced", "seed": "Seed", - "seedPlaceholder": "Random" + "seedPlaceholder": "Random", + "thinkMode": "Think mode" }, "actions": { "generate": "Generate", @@ -284,6 +292,45 @@ "generateFailed": "Generation failed" } }, + "audioTransform": { + "title": "Audio Transform", + "labels": { + "model": "Model", + "audio": "Audio (required)", + "reference": "Reference (optional)", + "referenceHelp": "Loopback / far-end signal for echo cancellation, target speaker for voice conversion. Leave empty for unconditional transform.", + "advancedParameters": "Advanced parameters", + "advancedParametersHelp": "backend-specific (one key=value per line, e.g. noise_gate=true)", + "advancedParametersPlaceholder": "# Optional. For LocalVQE:\n# noise_gate=true\n# noise_gate_threshold_dbfs=-50" + }, + "input": { + "upload": "Upload", + "uploadDescription": "Drop a file here or", + "uploadBrowse": "browse", + "record": "Record", + "startRecording": "Start recording", + "stop": "Stop", + "encoding": "Encoding...", + "clear": "Clear", + "microphoneUnavailable": "Microphone capture is unavailable in this browser.", + "echoNotice": "Browsers often apply their own WebRTC echo cancellation and noise suppression by default. This usually results in worse performance than running LocalVQE on the raw audio.", + "echoTest": "Echo test (record mic while playing reference)", + "stopEchoTest": "Stop echo test" + }, + "result": { + "audio": "Audio", + "reference": "Reference", + "inputSpectrum": "Input spectrum", + "outputSpectrum": "Output spectrum", + "outputSpectrumHint": "Transform to compare attenuation", + "output": "Output" + }, + "actions": { + "transform": "Transform", + "processing": "Processing..." + }, + "empty": "Choose an audio file (and optional reference) to transform" + }, "talk": { "title": "Talk", "subtitle": "Realtime voice conversation", diff --git a/core/http/react-ui/public/locales/id/media.json b/core/http/react-ui/public/locales/id/media.json index 50bbfa65b..b6b644fda 100644 --- a/core/http/react-ui/public/locales/id/media.json +++ b/core/http/react-ui/public/locales/id/media.json @@ -96,26 +96,73 @@ "model": "Model", "prompt": "Prompt", "promptPlaceholder": "Deskripsikan suara yang ingin Anda buat...", + "instrumental": "Instrumental", + "bpm": "Tempo", "duration": "Durasi (detik)", "language": "Bahasa", + "timesignature": "Tanda birama", + "keyscale": "Tangga nada", "vocalLanguage": "Bahasa vokal", - "lyrics": "Lirik (opsional)", - "lyricsPlaceholder": "Lirik untuk generasi vokal", - "advanced": "Pengaturan Tingkat Lanjutan", + "vocalLanguagePlaceholder": "cth. Bahasa Indonesia", + "caption": "Takarir", + "lyrics": "Lirik", + "lyricsPlaceholder": "Lirik untuk menghasilkan vokal", + "simple": "Sederhana", + "advanced": "Tingkat Lanjutan", "seed": "Seed", - "seedPlaceholder": "Acak" + "seedPlaceholder": "Acak", + "thinkMode": "Mode penalaran" }, "actions": { "generate": "Hasilkan", "generating": "Menghasilkan..." }, - "empty": "Audio yang dihasilkan akan muncul di sini", + "empty": "Suara yang dihasilkan akan muncul di sini", "toasts": { "noPrompt": "Silahkan masukkan prompt", "noModel": "Silahkan pilih model", "generateFailed": "Gagal menghasilkan" } }, + "audioTransform": { + "title": "Transformasi Audio", + "labels": { + "model": "Model", + "audio": "Audio (wajib)", + "reference": "Referensi (opsional)", + "referenceHelp": "Sinyal loopback / ujung jauh untuk pembatalan gema, atau pembicara target untuk konversi suara. Kosongkan untuk transformasi tanpa syarat.", + "advancedParameters": "Parameter tingkat lanjut", + "advancedParametersHelp": "Spesifik backend (satu key=value per baris, contoh: noise_gate=true)", + "advancedParametersPlaceholder": "# Opsional. Untuk LocalVQE:\n# noise_gate=true\n# noise_gate_threshold_dbfs=-50" + }, + "input": { + "upload": "Unggah", + "uploadDescription": "Tarik file di sini atau", + "uploadBrowse": "jelajahi", + "record": "Rekam", + "startRecording": "Mulai merekam", + "stop": "Selesai", + "encoding": "Pengenkodean...", + "clear": "Hapus", + "microphoneUnavailable": "Perekaman mikrofon tidak tersedia di peramban ini.", + "echoNotice": "Peramban sering kali menerapkan pembatalan gema dan penekanan derau WebRTC secara bawaan. Hal ini biasanya menghasilkan performa yang lebih buruk dibandingkan menjalankan LocalVQE pada audio mentah.", + "echoTest": "Tes gema (rekam mik saat memutar referensi)", + "stopEchoTest": "Hentikan tes gema" + }, + "result": { + "audio": "Audio", + "reference": "Referensi", + "inputSpectrum": "Input spektrum", + "outputSpectrum": "Output spektrum", + "outputSpectrumHint": "Transformasi untuk membandingkan atenuasi", + "output": "Output" + }, + "actions": { + "transform": "Transformasi", + "processing": "Memproses..." + }, + "empty": "Pilih file audio (dan referensi opsional) untuk ditransformasikan" + }, "talk": { "title": "Percakapan", "subtitle": "Percakapan suara realtime", diff --git a/core/http/react-ui/src/components/MediaHistory.jsx b/core/http/react-ui/src/components/MediaHistory.jsx index efbac924a..9d98b5416 100644 --- a/core/http/react-ui/src/components/MediaHistory.jsx +++ b/core/http/react-ui/src/components/MediaHistory.jsx @@ -1,5 +1,6 @@ import { memo, useState } from 'react' import { relativeTime } from '../utils/format' +import { useTranslation } from 'react-i18next' const ICONS = { image: 'fa-image', @@ -10,6 +11,7 @@ const ICONS = { } export default memo(function MediaHistory({ entries, selectedId, onSelect, onDelete, onClearAll, mediaType }) { + const { t } = useTranslation('media') const [expanded, setExpanded] = useState(true) return ( @@ -20,11 +22,11 @@ export default memo(function MediaHistory({ entries, selectedId, onSelect, onDel style={{ display: 'flex', alignItems: 'center' }} > - History ({entries.length}) + {t('history.title')} ({entries.length}) {entries.length > 0 && (