fix: localize Argos runtime recovery across desktop and browser

This commit is contained in:
Palash Debnath
2026-09-17 13:15:15 +05:30
parent 5c6d0f7f8f
commit 84290db784
49 changed files with 135 additions and 47 deletions
+11 -3
View File
@@ -1,3 +1,4 @@
import i18n from 'i18next';
import { abortableDelay } from '../utils/abortableDelay.ts';
// Backend base URL.
// • VITE_API_URL → explicit override (any deploy).
@@ -592,9 +593,16 @@ export async function apiFetch(path: string, opts: ApiFetchOptions = {}): Promis
// human-readable `message` — use it for the Error message instead of
// letting the object stringify to "[object Object]".
const msg =
typeof detail === 'string'
? detail
: ((detail as { message?: string })?.message ?? JSON.stringify(detail));
detail &&
typeof detail === 'object' &&
'code' in detail &&
detail.code === 'argos_runtime_unavailable'
? i18n.t('engines.argosRuntimeUnavailable', {
defaultValue: 'Argos runtime unavailable. Reinstall the backend or select NLLB.',
})
: typeof detail === 'string'
? detail
: ((detail as { message?: string })?.message ?? JSON.stringify(detail));
// The backend names the exception type in `error_class` on its 500s.
// Lifting it here is what lets the bug report say which failure it was.
const errorClass =
+2 -1
View File
@@ -864,7 +864,8 @@
"familyDesc_asr": "يحوّل الصوت إلى نص للنسخ والدبلجة والتسميات التوضيحية والإملاء.",
"familyDesc_llm": "مساعد نصي اختياري للترجمة وإعادة الصياغة. يؤدي إيقافه إلى تخطي هذه الخطوات.",
"mpsLongText": "يعمل {{engine}} على شريحة Apple Silicon (MPS) هنا، وهذا النص طويل — قد يتجاوز التوليد الحد الزمني. النص الأقصر، أو تقسيمه إلى عدة مقاطع، سيكون أسرع بكثير.",
"inMemory": "في الذاكرة"
"inMemory": "في الذاكرة",
"argosRuntimeUnavailable": "بيئة تشغيل Argos غير متاحة. أعد تثبيت الخادم الخلفي أو اختر NLLB."
},
"capture": {
"desc": "تعمل مفاتيح التشغيل السريع العامة فقط في تطبيق سطح المكتب. تستخدم واجهة مستخدم الويب اختصارًا <1>Ctrl+Shift+Space</1> داخل الصفحة أثناء التركيز على النافذة.",
+2 -1
View File
@@ -864,7 +864,8 @@
"familyDesc_asr": "Transkribiert Audio für Synchronisation, Untertitel und Diktat.",
"familyDesc_llm": "Optionaler Texthelfer für Übersetzungen und Überarbeitungen. „Aus“ überspringt diese Schritte.",
"mpsLongText": "{{engine}} läuft hier auf Apple Silicon (MPS) und dieser Text ist lang — die Generierung überschreitet möglicherweise das Zeitbudget. Kürzerer Text oder eine Aufteilung in mehrere Takes ist deutlich schneller.",
"inMemory": "Im Speicher"
"inMemory": "Im Speicher",
"argosRuntimeUnavailable": "Die Argos-Laufzeit ist nicht verfügbar. Installiere das Backend neu oder wähle NLLB."
},
"capture": {
"desc": "Globale Hotkeys funktionieren nur in der Desktop-App. Die Web-Benutzeroberfläche verwendet eine In-Page-Verknüpfung <1>Strg+Umschalt+Leertaste</1>, während das Fenster den Fokus hat.",
+2 -1
View File
@@ -2237,7 +2237,8 @@
"generateCaveat": "{{engine}} may be slow on this machine — {{reason}}",
"cpuLongText": "{{engine}} runs on the CPU here, and this text is long — the generation may exceed the time budget. Shorter text, or a CPU-tuned engine (OmniVoice GGUF, Supertonic-3), will be much faster.",
"cpuLongTextTuned": "{{engine}} runs on the CPU here, and this text is long — the generation may exceed the time budget. Shorter text, or splitting it into a few takes, will be much faster.",
"mpsLongText": "{{engine}} runs on Apple Silicon (MPS) here, and this text is long — the generation may exceed the time budget. Shorter text, or splitting it into a few takes, will be much faster."
"mpsLongText": "{{engine}} runs on Apple Silicon (MPS) here, and this text is long — the generation may exceed the time budget. Shorter text, or splitting it into a few takes, will be much faster.",
"argosRuntimeUnavailable": "Argos runtime unavailable. Reinstall the backend or select NLLB."
},
"errors": {
"title": "This tab hit a snag.",
+2 -1
View File
@@ -864,7 +864,8 @@
"familyDesc_asr": "Convierte audio en texto para transcripciones, doblaje, subtítulos y dictado.",
"familyDesc_llm": "Asistente de texto opcional para traducciones y reescrituras. «Desactivado» omite esos pasos.",
"mpsLongText": "{{engine}} se ejecuta en Apple Silicon (MPS) aquí y este texto es largo: la generación puede superar el límite de tiempo. Un texto más corto, o dividirlo en varias tomas, será mucho más rápido.",
"inMemory": "En memoria"
"inMemory": "En memoria",
"argosRuntimeUnavailable": "El entorno de ejecución de Argos no está disponible. Reinstala el backend o selecciona NLLB."
},
"capture": {
"desc": "Las teclas de acceso rápido globales solo funcionan en la aplicación de escritorio. La interfaz de usuario web utiliza un acceso directo <1>Ctrl+Shift+Espacio</1> en la página mientras la ventana tiene el foco.",
+2 -1
View File
@@ -864,7 +864,8 @@
"familyDesc_asr": "Transforme laudio en texte pour la transcription, le doublage, les sous-titres et la dictée.",
"familyDesc_llm": "Assistant textuel facultatif pour la traduction et la réécriture. « Désactivé » ignore ces étapes.",
"mpsLongText": "{{engine}} fonctionne ici sur Apple Silicon (MPS) et ce texte est long — la génération risque de dépasser le budget de temps. Un texte plus court, ou découpé en plusieurs prises, sera bien plus rapide.",
"inMemory": "En mémoire"
"inMemory": "En mémoire",
"argosRuntimeUnavailable": "Le moteur Argos est indisponible. Réinstallez le backend ou sélectionnez NLLB."
},
"capture": {
"desc": "Les raccourcis clavier globaux ne fonctionnent que dans l'application de bureau. L'interface utilisateur Web utilise un raccourci <1>Ctrl+Shift+Espace</1> sur la page lorsque la fenêtre a le focus.",
+2 -1
View File
@@ -864,7 +864,8 @@
"familyDesc_asr": "डबिंग, कैप्शन और डिक्टेशन के लिए ऑडियो को टेक्स्ट में बदलता है।",
"familyDesc_llm": "अनुवाद और पुनर्लेखन के लिए वैकल्पिक टेक्स्ट सहायक। “बंद” होने पर ये चरण छोड़ दिए जाते हैं।",
"mpsLongText": "यहाँ {{engine}} Apple Silicon (MPS) पर चलता है और यह टेक्स्ट लंबा है — जनरेशन समय सीमा पार कर सकता है। छोटा टेक्स्ट, या इसे कुछ हिस्सों में बाँटना, कहीं तेज़ रहेगा।",
"inMemory": "मेमोरी में"
"inMemory": "मेमोरी में",
"argosRuntimeUnavailable": "Argos रनटाइम उपलब्ध नहीं है। बैकएंड फिर से इंस्टॉल करें या NLLB चुनें।"
},
"capture": {
"desc": "ग्लोबल हॉटकीज़ केवल डेस्कटॉप ऐप में काम करती हैं। वेब यूआई इन-पेज <1>Ctrl+Shift+Space</1> शॉर्टकट का उपयोग करता है जबकि विंडो पर फोकस होता है।",
+2 -1
View File
@@ -864,7 +864,8 @@
"familyDesc_asr": "Mengubah audio menjadi teks untuk transkripsi, sulih suara, teks layar, dan dikte.",
"familyDesc_llm": "Pembantu teks opsional untuk terjemahan dan penulisan ulang. “Nonaktif” akan melewati langkah tersebut.",
"mpsLongText": "{{engine}} berjalan di Apple Silicon (MPS) di sini dan teks ini panjang — proses mungkin melampaui batas waktu. Teks lebih pendek, atau membaginya menjadi beberapa bagian, akan jauh lebih cepat.",
"inMemory": "Dalam memori"
"inMemory": "Dalam memori",
"argosRuntimeUnavailable": "Runtime Argos tidak tersedia. Instal ulang backend atau pilih NLLB."
},
"capture": {
"desc": "Tombol pintas global hanya berfungsi di aplikasi desktop. UI web menggunakan pintasan <1>Ctrl+Shift+Space</1> dalam halaman saat jendela memiliki fokus.",
+2 -1
View File
@@ -864,7 +864,8 @@
"familyDesc_asr": "Trasforma laudio in testo per trascrizione, doppiaggio, sottotitoli e dettatura.",
"familyDesc_llm": "Assistente di testo opzionale per traduzioni e riscritture. “Disattivato” salta questi passaggi.",
"mpsLongText": "{{engine}} qui viene eseguito su Apple Silicon (MPS) e questo testo è lungo: la generazione potrebbe superare il limite di tempo. Un testo più breve, o diviso in più riprese, sarà molto più veloce.",
"inMemory": "In memoria"
"inMemory": "In memoria",
"argosRuntimeUnavailable": "Il runtime di Argos non è disponibile. Reinstalla il backend o seleziona NLLB."
},
"capture": {
"desc": "I tasti di scelta rapida globali funzionano solo nell'app desktop. L'interfaccia utente Web utilizza una scorciatoia <1>Ctrl+Shift+Spazio</1> nella pagina mentre la finestra è attiva.",
+2 -1
View File
@@ -864,7 +864,8 @@
"familyDesc_asr": "音声をテキストに変換し、ダビング、字幕、音声入力の文字起こしに使用します。",
"familyDesc_llm": "翻訳や書き換え用の任意のテキスト補助です。「オフ」にするとこれらの手順を省略します。",
"mpsLongText": "ここでは {{engine}} が Apple SiliconMPS)で実行され、このテキストは長いため、生成が時間制限を超える可能性があります。テキストを短くするか、数回に分けたほうが大幅に高速です。",
"inMemory": "メモリに読み込み済み"
"inMemory": "メモリに読み込み済み",
"argosRuntimeUnavailable": "Argos ランタイムを利用できません。バックエンドを再インストールするか、NLLB を選択してください。"
},
"capture": {
"desc": "グローバル ホットキーはデスクトップ アプリでのみ機能します。 Web UI は、ウィンドウにフォーカスがある間、ページ内 <1>Ctrl+Shift+Space</1> ショートカットを使用します。",
+2 -1
View File
@@ -1141,7 +1141,8 @@
"unload": "언로드",
"unloadFailed": "언로드하지 못했습니다: {{message}}",
"unloading": "언로드 중…",
"mpsLongText": "여기서는 {{engine}}이(가) Apple Silicon(MPS)에서 실행되며 이 텍스트는 길어 생성이 시간 제한을 초과할 수 있습니다. 텍스트를 줄이거나 여러 번에 나누면 훨씬 빠릅니다."
"mpsLongText": "여기서는 {{engine}}이(가) Apple Silicon(MPS)에서 실행되며 이 텍스트는 길어 생성이 시간 제한을 초과할 수 있습니다. 텍스트를 줄이거나 여러 번에 나누면 훨씬 빠릅니다.",
"argosRuntimeUnavailable": "Argos 런타임을 사용할 수 없습니다. 백엔드를 다시 설치하거나 NLLB를 선택하세요."
},
"capture": {
"desc": "전역 단축키는 데스크톱 앱에서만 작동합니다. 웹 UI는 창에 포커스가 있는 동안 페이지 내 <1>Ctrl+Shift+Space</1> 단축키를 사용합니다.",
+2 -1
View File
@@ -864,7 +864,8 @@
"familyDesc_asr": "Zet audio om in tekst voor transcriptie, nasynchronisatie, ondertiteling en dicteren.",
"familyDesc_llm": "Optionele teksthulp voor vertalen en herschrijven. Uit slaat deze stappen over.",
"mpsLongText": "{{engine}} draait hier op Apple Silicon (MPS) en deze tekst is lang — de generatie overschrijdt mogelijk het tijdsbudget. Kortere tekst, of opsplitsen in meerdere takes, is veel sneller.",
"inMemory": "In het geheugen"
"inMemory": "In het geheugen",
"argosRuntimeUnavailable": "De Argos-runtime is niet beschikbaar. Installeer de backend opnieuw of kies NLLB."
},
"capture": {
"desc": "Globale sneltoetsen werken alleen in de desktop-app. De webinterface gebruikt een sneltoets <1>Ctrl+Shift+Spatie</1> op de pagina terwijl het venster focus heeft.",
+2 -1
View File
@@ -864,7 +864,8 @@
"familyDesc_asr": "Zamienia dźwięk na tekst do transkrypcji, dubbingu, napisów i dyktowania.",
"familyDesc_llm": "Opcjonalny pomocnik tekstowy do tłumaczeń i przeredagowywania. „Wył.” pomija te kroki.",
"mpsLongText": "{{engine}} działa tutaj na Apple Silicon (MPS), a ten tekst jest długi — generowanie może przekroczyć limit czasu. Krótszy tekst lub podzielenie go na kilka części będzie znacznie szybsze.",
"inMemory": "W pamięci"
"inMemory": "W pamięci",
"argosRuntimeUnavailable": "Środowisko Argos jest niedostępne. Zainstaluj ponownie backend lub wybierz NLLB."
},
"capture": {
"desc": "Globalne skróty klawiszowe działają tylko w aplikacji komputerowej. Interfejs WWW korzysta ze skrótu <1>Ctrl+Shift+Spacja</1> znajdującego się na stronie, gdy okno jest aktywne.",
+2 -1
View File
@@ -864,7 +864,8 @@
"familyDesc_asr": "Transforma áudio em texto para transcrição, dublagem, legendas e ditado.",
"familyDesc_llm": "Assistente de texto opcional para tradução e reescrita. “Desativado” ignora essas etapas.",
"mpsLongText": "{{engine}} é executado em Apple Silicon (MPS) aqui e este texto é longo — a geração pode ultrapassar o limite de tempo. Um texto mais curto, ou dividido em algumas partes, será bem mais rápido.",
"inMemory": "Na memória"
"inMemory": "Na memória",
"argosRuntimeUnavailable": "O ambiente de execução do Argos está indisponível. Reinstale o backend ou selecione NLLB."
},
"capture": {
"desc": "As teclas de atalho globais funcionam apenas no aplicativo de desktop. A IU da web usa um atalho <1>Ctrl+Shift+Space</1> na página enquanto a janela está em foco.",
+2 -1
View File
@@ -864,7 +864,8 @@
"familyDesc_asr": "Преобразует аудио в текст для транскрипции, дубляжа, субтитров и диктовки.",
"familyDesc_llm": "Необязательный текстовый помощник для перевода и перефразирования. Режим «Выкл.» пропускает эти этапы.",
"mpsLongText": "Здесь {{engine}} работает на Apple Silicon (MPS), а этот текст длинный — генерация может превысить лимит времени. Более короткий текст или разбиение на несколько частей будет намного быстрее.",
"inMemory": "В памяти"
"inMemory": "В памяти",
"argosRuntimeUnavailable": "Среда выполнения Argos недоступна. Переустановите серверную часть или выберите NLLB."
},
"capture": {
"desc": "Глобальные горячие клавиши работают только в настольном приложении. Веб-интерфейс использует внутристраничный ярлык <1>Ctrl+Shift+Space</1>, пока окно находится в фокусе.",
+2 -1
View File
@@ -864,7 +864,8 @@
"familyDesc_asr": "Gör om ljud till text för transkribering, dubbning, undertexter och diktering.",
"familyDesc_llm": "Valfri texthjälp för översättning och omskrivning. ”Av” hoppar över dessa steg.",
"mpsLongText": "{{engine}} körs på Apple Silicon (MPS) här och den här texten är lång — genereringen kan överskrida tidsbudgeten. Kortare text, eller uppdelad i flera tagningar, går betydligt snabbare.",
"inMemory": "I minnet"
"inMemory": "I minnet",
"argosRuntimeUnavailable": "Argos körmiljö är inte tillgänglig. Installera om backend eller välj NLLB."
},
"capture": {
"desc": "Globala snabbtangenter fungerar bara i skrivbordsappen. Webbgränssnittet använder en genväg <1>Ctrl+Skift+Mellanslag</1> på sidan medan fönstret har fokus.",
+2 -1
View File
@@ -864,7 +864,8 @@
"familyDesc_asr": "แปลงเสียงเป็นข้อความสำหรับการถอดเสียง การพากย์ คำบรรยาย และการป้อนตามเสียง",
"familyDesc_llm": "ผู้ช่วยข้อความเสริมสำหรับการแปลและเขียนใหม่ เมื่อ “ปิด” จะข้ามขั้นตอนเหล่านี้",
"mpsLongText": "{{engine}} ทำงานบน Apple Silicon (MPS) ที่นี่ และข้อความนี้ยาว — การสร้างอาจเกินงบประมาณเวลา ข้อความที่สั้นลง หรือแบ่งเป็นหลายส่วน จะเร็วกว่ามาก",
"inMemory": "อยู่ในหน่วยความจำ"
"inMemory": "อยู่ในหน่วยความจำ",
"argosRuntimeUnavailable": "ไม่สามารถใช้งานรันไทม์ Argos ได้ โปรดติดตั้งแบ็กเอนด์ใหม่หรือเลือก NLLB"
},
"capture": {
"desc": "ปุ่มลัดส่วนกลางใช้งานได้ในแอปเดสก์ท็อปเท่านั้น UI ของเว็บใช้ทางลัด <1>Ctrl+Shift+Space</1> ในเพจในขณะที่หน้าต่างมีโฟกัส",
+2 -1
View File
@@ -864,7 +864,8 @@
"familyDesc_asr": "Sesi; transkripsiyon, dublaj, altyazı ve dikte için metne dönüştürür.",
"familyDesc_llm": "Çeviri ve yeniden yazma için isteğe bağlı metin yardımcısıdır. “Kapalı” bu adımları atlar.",
"mpsLongText": "{{engine}} burada Apple Silicon (MPS) üzerinde çalışıyor ve bu metin uzun — üretim süre bütçesini aşabilir. Daha kısa bir metin ya da birkaç parçaya bölmek çok daha hızlı olacaktır.",
"inMemory": "Bellekte"
"inMemory": "Bellekte",
"argosRuntimeUnavailable": "Argos çalışma ortamı kullanılamıyor. Arka ucu yeniden yükleyin veya NLLB seçin."
},
"capture": {
"desc": "Genel kısayol tuşları yalnızca masaüstü uygulamasında çalışır. Web kullanıcı arayüzü, pencere odaktayken sayfa içi <1>Ctrl+Shift+Space</1> kısayolunu kullanır.",
+2 -1
View File
@@ -864,7 +864,8 @@
"familyDesc_asr": "Перетворює аудіо на текст для транскрипції, дубляжу, субтитрів і диктування.",
"familyDesc_llm": "Необов’язковий текстовий помічник для перекладу й переписування. «Вимкнено» пропускає ці кроки.",
"mpsLongText": "Тут {{engine}} працює на Apple Silicon (MPS), а цей текст довгий — генерація може перевищити ліміт часу. Коротший текст або розбиття на кілька частин буде значно швидшим.",
"inMemory": "У пам’яті"
"inMemory": "У пам’яті",
"argosRuntimeUnavailable": "Середовище виконання Argos недоступне. Перевстановіть серверну частину або виберіть NLLB."
},
"capture": {
"desc": "Глобальні гарячі клавіші працюють лише в настільній програмі. Веб-інтерфейс використовує ярлик <1>Ctrl+Shift+Пробіл</1> на сторінці, коли вікно має фокус.",
+2 -1
View File
@@ -864,7 +864,8 @@
"familyDesc_asr": "Chuyển âm thanh thành văn bản để phiên âm, lồng tiếng, tạo phụ đề và đọc chính tả.",
"familyDesc_llm": "Trợ lý văn bản tùy chọn cho dịch thuật và viết lại. “Tắt” sẽ bỏ qua các bước này.",
"mpsLongText": "{{engine}} chạy trên Apple Silicon (MPS) ở đây và văn bản này dài — quá trình tạo có thể vượt quá giới hạn thời gian. Văn bản ngắn hơn, hoặc chia thành vài phần, sẽ nhanh hơn nhiều.",
"inMemory": "Trong bộ nhớ"
"inMemory": "Trong bộ nhớ",
"argosRuntimeUnavailable": "Không thể sử dụng môi trường chạy Argos. Hãy cài lại backend hoặc chọn NLLB."
},
"capture": {
"desc": "Phím nóng chung chỉ hoạt động trong ứng dụng máy tính để bàn. Giao diện người dùng web sử dụng phím tắt <1>Ctrl+Shift+Space</1> trong trang trong khi cửa sổ đang có tiêu điểm.",
+2 -1
View File
@@ -1093,7 +1093,8 @@
"installStep_fetch_weights": "正在下载模型权重",
"installStep_persist": "正在保存配置",
"installAria": "安装 {{engine}}",
"mpsLongText": "{{engine}} 在本机上使用 Apple Silicon(MPS)运行,而这段文本较长——生成可能超出时间预算。缩短文本,或分成几次生成会快得多。"
"mpsLongText": "{{engine}} 在本机上使用 Apple Silicon(MPS)运行,而这段文本较长——生成可能超出时间预算。缩短文本,或分成几次生成会快得多。",
"argosRuntimeUnavailable": "Argos 运行时不可用。请重新安装后端或选择 NLLB。"
},
"capture": {
"desc": "全局热键仅在桌面应用中有效。网页界面使用页面内快捷键 <1>Ctrl+Shift+Space</1>(窗口聚焦时可用)。",
+2 -1
View File
@@ -864,7 +864,8 @@
"familyDesc_asr": "將音訊轉換為文字,用於轉錄、配音、字幕和聽寫。",
"familyDesc_llm": "用於翻譯和改寫的選用文字助理。「關閉」會略過這些步驟。",
"mpsLongText": "{{engine}} 在此機器上使用 Apple Silicon(MPS)執行,而這段文字較長 — 生成可能超出時間預算。縮短文字或分成幾次生成會快得多。",
"inMemory": "已載入記憶體"
"inMemory": "已載入記憶體",
"argosRuntimeUnavailable": "Argos 執行環境無法使用。請重新安裝後端或選擇 NLLB。"
},
"capture": {
"desc": "全域熱鍵僅適用於桌面應用程式。當視窗具有焦點時,Web UI 使用頁內 <1>Ctrl+Shift+Space</1> 快速鍵。",
+12
View File
@@ -1,3 +1,4 @@
import i18n from 'i18next';
import { describe, it, expect, vi, afterEach } from 'vitest';
import { apiFetch, ApiError } from '../api/client';
@@ -7,6 +8,17 @@ import { apiFetch, ApiError } from '../api/client';
// few times — but never retry an HTTP error (the backend responded) or a
// deliberate abort, and still surface the actionable error if it stays down.
describe('apiFetch transport-retry', () => {
it('localizes Argos runtime errors without losing recovery metadata', async () => {
const detail = { code: 'argos_runtime_unavailable', message: 'Raw native diagnostic' };
vi.spyOn(i18n, 't').mockReturnValue('Localized recovery guidance');
vi.stubGlobal(
'fetch',
vi.fn().mockResolvedValue(new Response(JSON.stringify({ detail }), { status: 400 })),
);
const err = await apiFetch('/dub/translate').catch((error) => error);
expect(err.message).toContain('Localized recovery guidance');
expect(err.detail).toEqual(detail);
});
afterEach(() => {
vi.useRealTimers();
vi.restoreAllMocks();