diff --git a/src/i18n/locales/es.json b/src/i18n/locales/es.json index 3cfc891a1..b5b0a3abb 100644 --- a/src/i18n/locales/es.json +++ b/src/i18n/locales/es.json @@ -2885,5 +2885,9 @@ "Source configured; file checked when loaded": "Fuente configurada; el archivo se comprobará al cargarlo", "Source unavailable": "Fuente no disponible", "Coverage tile failed": "No se pudo cargar la tesela de cobertura", - "Unknown": "Desconocido" + "Unknown": "Desconocido", + "USB work abandoned after a stalled transfer": "Trabajo USB cancelado tras una transferencia bloqueada", + "SDR decoder did not start; receiver stopped": "El decodificador SDR no arrancó; receptor detenido", + "SDR decoder stopped responding; receiver stopped": "El decodificador SDR dejó de responder; receptor detenido", + "SDR decoder fell behind; receiver stopped": "El decodificador SDR se quedó atrás; receptor detenido" } diff --git a/src/i18n/locales/ru.json b/src/i18n/locales/ru.json index 008e2fec6..019415690 100644 --- a/src/i18n/locales/ru.json +++ b/src/i18n/locales/ru.json @@ -2952,5 +2952,9 @@ "Source configured; file checked when loaded": "Источник настроен; файл будет проверен при загрузке", "Source unavailable": "Источник недоступен", "Coverage tile failed": "Не удалось загрузить тайл покрытия", - "Unknown": "Неизвестно" + "Unknown": "Неизвестно", + "USB work abandoned after a stalled transfer": "Работа с USB прервана: передача данных зависла", + "SDR decoder did not start; receiver stopped": "Декодер SDR не запустился; приёмник остановлен", + "SDR decoder stopped responding; receiver stopped": "Декодер SDR перестал отвечать; приёмник остановлен", + "SDR decoder fell behind; receiver stopped": "Декодер SDR не успевает; приёмник остановлен" } diff --git a/src/sdr/controller.js b/src/sdr/controller.js index 60d766928..50fec4a38 100644 --- a/src/sdr/controller.js +++ b/src/sdr/controller.js @@ -17,7 +17,7 @@ import { selectAuthorizedSdrDevice, } from './usbDevices.js'; import { summarizeLocalAdsb } from '../sources/adsbRecords.js'; -import { formatNumber, t } from '../i18n/index.js'; +import { formatNumber, msg, t, translateKnown } from '../i18n/index.js'; export { createRememberingWebUsb } from './usbDevices.js'; @@ -298,7 +298,7 @@ function describeConnectionError(error) { 'RTL-SDR access failed; close other SDR apps and check USB permissions', ); } - return message || t('RTL-SDR connection failed'); + return message ? translateKnown(message) : t('RTL-SDR connection failed'); } function streamingMessage(mode) { @@ -487,11 +487,11 @@ export class SdrController { gate.waiting += 1; const run = async () => { if (epoch !== this._usbEpoch) - throw new Error('USB work abandoned after a stalled transfer'); + throw new Error(msg('USB work abandoned after a stalled transfer')); await Promise.allSettled(gate.reads); // A stalled read may have ended this session while it drained. if (epoch !== this._usbEpoch) - throw new Error('USB work abandoned after a stalled transfer'); + throw new Error(msg('USB work abandoned after a stalled transfer')); return operation(); }; const queued = this._usbTail.then(run, run); @@ -785,10 +785,10 @@ export class SdrController { decoderOverloadSnapshot: snapshot, message: reason === 'startup' - ? 'SDR decoder did not start; receiver stopped' + ? t('SDR decoder did not start; receiver stopped') : reason === 'stalled' - ? 'SDR decoder stopped responding; receiver stopped' - : 'SDR decoder fell behind; receiver stopped', + ? t('SDR decoder stopped responding; receiver stopped') + : t('SDR decoder fell behind; receiver stopped'), }); void this.stop({ preserveMessage: true }); } @@ -1726,7 +1726,7 @@ export class SdrController { // tuneFm reports the failure; no spectrum is valid for this frame. if (!(await this.tuneFm(center, { quiet: true }))) { if (token === this._seekToken) - this._setState({ seeking: false, seekMessage: 'Seek stopped' }); + this._setState({ seeking: false, seekMessage: t('Seek stopped') }); return null; } const sequence = this._spectrumSequence; diff --git a/src/sdr/sdrSeekLocalized.test.mjs b/src/sdr/sdrSeekLocalized.test.mjs index 634180cdd..887d5f012 100644 --- a/src/sdr/sdrSeekLocalized.test.mjs +++ b/src/sdr/sdrSeekLocalized.test.mjs @@ -56,3 +56,25 @@ test('FM seek messages keep their English wording and decimal point', async () = assert.ok(texts.includes('Scanning 98.5 MHz…')); assert.match(texts.at(-1), /^Found 98\.8 MHz · \d+\.\d dB$/); }); + +for (const locale of ['es', 'ru']) { + test(`a failed seek tune and a decoder overload are localized in ${locale}`, async () => { + setLocale(locale); + try { + const { c } = makeController(); + c.tuneFm = async () => false; + assert.equal(await c.seekFm(1), null); + assert.ok(c.state.seekMessage); + assert.notEqual(c.state.seekMessage, 'Seek stopped'); + + c.stop = async () => {}; + for (const reason of ['startup', 'stalled', 'backlog']) { + c._device = {}; + c._overload(reason); + assert.doesNotMatch(c.state.message, /SDR decoder|receiver stopped/); + } + } finally { + setLocale('en'); + } + }); +}