mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-11-13 07:40:59 +00:00
feat(ui): a calm, native-looking card when a view fails or TREK was updated
The error and new-version fallback was a bordered box with a warning triangle and the raw error message on show. It is now one centred card with a round symbol (a friendly one for an update), a short title and line, and a full-width reload button; the technical message stays for issue reports, folded under Details. Phone, PWA and desktop alike.
This commit is contained in:
@@ -205,7 +205,20 @@ describe('ErrorBoundary', () => {
|
||||
);
|
||||
// --m-* only resolves inside MobileShell's .m-root; the desktop classes would
|
||||
// render an invisible card there.
|
||||
expect(screen.getByRole('alert').className).toContain('bg-m-card');
|
||||
expect(screen.getByRole('alert').querySelector('.bg-m-card')).not.toBeNull();
|
||||
expect(screen.getByRole('alert').querySelector('.bg-surface-card')).toBeNull();
|
||||
});
|
||||
|
||||
it('FE-COMP-ERRBOUND-014b: the technical message stays for an issue report, folded away', () => {
|
||||
render(
|
||||
<ErrorBoundary boundaryId="route" level="route">
|
||||
<Boom />
|
||||
</ErrorBoundary>,
|
||||
);
|
||||
// The message stays in the page for an issue report, inside a closed details.
|
||||
const details = screen.getByText('kaboom').closest('details') as HTMLDetailsElement;
|
||||
expect(details).not.toBeNull();
|
||||
expect(details.open).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { AlertTriangle, RefreshCw, RotateCcw } from 'lucide-react'
|
||||
import { AlertTriangle, RefreshCw, RotateCcw, Sparkles } from 'lucide-react'
|
||||
import { useTranslation } from '../../i18n'
|
||||
import { isChunkLoadError, reloadOnceForChunk, reloadOntoCurrentBuild } from '../../utils/chunkReload'
|
||||
|
||||
@@ -131,55 +131,74 @@ export function ErrorFallback({ error, reset, isChunkError, level, variant, labe
|
||||
: isPanel ? t('common.errorPanelBody') : t('common.errorBody')
|
||||
|
||||
const message = error instanceof Error ? error.message : null
|
||||
const Icon = isChunkError ? Sparkles : AlertTriangle
|
||||
const muted = mobile ? 'text-m-muted' : 'text-content-secondary'
|
||||
|
||||
return (
|
||||
<div
|
||||
role="alert"
|
||||
className={[
|
||||
'flex flex-col items-center justify-center gap-3 rounded-xl border p-6 text-center',
|
||||
isPanel ? 'h-full min-h-[180px]' : 'm-6 min-h-[240px]',
|
||||
mobile ? 'border-[color:var(--m-rowbr)] bg-m-card text-m-ink' : 'border-edge bg-surface-card',
|
||||
'flex flex-col items-center justify-center text-center',
|
||||
isPanel ? 'h-full min-h-[180px] p-4' : 'min-h-[60vh] p-6',
|
||||
].join(' ')}
|
||||
>
|
||||
<AlertTriangle size={22} className={mobile ? 'text-m-muted' : 'text-content-muted'} aria-hidden />
|
||||
<div className="space-y-1">
|
||||
<p className={`text-subtitle font-semibold ${mobile ? 'text-m-ink' : 'text-content'}`}>{title}</p>
|
||||
{label && <p className={`text-body ${mobile ? 'text-m-muted' : 'text-content-secondary'}`}>{label}</p>}
|
||||
<p className={`text-body ${mobile ? 'text-m-muted' : 'text-content-secondary'}`}>{body}</p>
|
||||
</div>
|
||||
{/* One calm card, the way a native app reports it: a round symbol, a short
|
||||
title and line, and one clear action. */}
|
||||
<div
|
||||
className={[
|
||||
'flex w-full max-w-sm flex-col items-center gap-4 rounded-[24px] border px-6 py-7',
|
||||
'shadow-[0_18px_48px_-24px_rgba(0,0,0,.35)]',
|
||||
mobile ? 'border-[color:var(--m-rowbr)] bg-m-card text-m-ink' : 'border-edge bg-surface-card',
|
||||
].join(' ')}
|
||||
>
|
||||
<span
|
||||
className={[
|
||||
'flex h-14 w-14 items-center justify-center rounded-full',
|
||||
isChunkError ? 'bg-accent text-accent-text' : mobile ? 'bg-[color:var(--m-ic)] text-m-muted' : 'bg-surface-secondary text-content-muted',
|
||||
].join(' ')}
|
||||
>
|
||||
<Icon size={24} strokeWidth={2} aria-hidden />
|
||||
</span>
|
||||
<div className="space-y-1.5">
|
||||
<p className={`text-title font-semibold ${mobile ? 'text-m-ink' : 'text-content'}`}>{title}</p>
|
||||
{label && <p className={`text-body ${muted}`}>{label}</p>}
|
||||
<p className={`text-body ${muted}`}>{body}</p>
|
||||
</div>
|
||||
|
||||
{/* Worth showing: TREK is self-hosted, so the person seeing this is often the
|
||||
same person who will paste it into an issue. */}
|
||||
{message && (
|
||||
<code className={`max-w-full truncate text-caption ${mobile ? 'text-m-faint' : 'text-content-faint'}`}>
|
||||
{message}
|
||||
</code>
|
||||
)}
|
||||
<div className="flex w-full flex-col gap-2">
|
||||
{(!isPanel || isChunkError) && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => reloadPage(isChunkError)}
|
||||
className="inline-flex w-full items-center justify-center gap-2 rounded-full bg-accent px-4 py-3 text-body font-semibold text-accent-text transition-transform active:scale-[.98]"
|
||||
>
|
||||
<RefreshCw size={16} aria-hidden />
|
||||
{t('common.errorReload')}
|
||||
</button>
|
||||
)}
|
||||
{/* No retry for a dead chunk — React.lazy would throw again immediately. */}
|
||||
{!isChunkError && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={reset}
|
||||
className={[
|
||||
'inline-flex w-full items-center justify-center gap-2 rounded-full border px-4 py-3 text-body font-semibold transition-transform active:scale-[.98]',
|
||||
mobile ? 'border-[color:var(--m-rowbr)] text-m-ink' : 'border-edge text-content',
|
||||
].join(' ')}
|
||||
>
|
||||
<RotateCcw size={16} aria-hidden />
|
||||
{t('common.errorRetry')}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap items-center justify-center gap-2 pt-1">
|
||||
{/* No retry for a dead chunk — React.lazy would throw again immediately. */}
|
||||
{!isChunkError && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={reset}
|
||||
className="inline-flex items-center gap-1.5 rounded-lg bg-accent px-3 py-2 text-caption font-medium text-white"
|
||||
>
|
||||
<RotateCcw size={14} aria-hidden />
|
||||
{t('common.errorRetry')}
|
||||
</button>
|
||||
)}
|
||||
{(!isPanel || isChunkError) && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => reloadPage(isChunkError)}
|
||||
className={[
|
||||
'inline-flex items-center gap-1.5 rounded-lg border px-3 py-2 text-caption font-medium',
|
||||
mobile ? 'border-[color:var(--m-rowbr)] text-m-ink' : 'border-edge text-content',
|
||||
].join(' ')}
|
||||
>
|
||||
<RefreshCw size={14} aria-hidden />
|
||||
{t('common.errorReload')}
|
||||
</button>
|
||||
{/* Kept, folded away: TREK is self-hosted, so the person seeing this is
|
||||
often the same person who will paste it into an issue. */}
|
||||
{message && (
|
||||
<details className={`w-full text-caption ${mobile ? 'text-m-faint' : 'text-content-faint'}`}>
|
||||
<summary className="cursor-pointer select-none">{t('common.errorDetails')}</summary>
|
||||
<code className="mt-2 block max-w-full break-words text-start">{message}</code>
|
||||
</details>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -193,30 +212,42 @@ export function ErrorFallback({ error, reset, isChunkError, level, variant, labe
|
||||
*/
|
||||
export function RootErrorFallback({ error, isChunkError }: FallbackState) {
|
||||
const message = error instanceof Error ? error.message : null
|
||||
const Icon = isChunkError ? Sparkles : AlertTriangle
|
||||
return (
|
||||
<div
|
||||
role="alert"
|
||||
className="flex min-h-dvh flex-col items-center justify-center gap-3 p-6 text-center"
|
||||
className="flex min-h-dvh flex-col items-center justify-center p-6 text-center"
|
||||
style={{ fontFamily: 'var(--font-system)' }}
|
||||
>
|
||||
<AlertTriangle size={24} className="text-content-muted" aria-hidden />
|
||||
<p className="text-subtitle font-semibold text-content">
|
||||
{isChunkError ? 'A new version is available' : 'TREK could not start'}
|
||||
</p>
|
||||
<p className="text-body text-content-secondary">
|
||||
{isChunkError
|
||||
? 'TREK was updated while this tab was open. Reload to get the new version.'
|
||||
: 'Reloading usually fixes this. Your data is safe.'}
|
||||
</p>
|
||||
{message && <code className="max-w-full truncate text-caption text-content-faint">{message}</code>}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => reloadPage(isChunkError)}
|
||||
className="mt-1 inline-flex items-center gap-1.5 rounded-lg bg-accent px-3 py-2 text-caption font-medium text-white"
|
||||
>
|
||||
<RefreshCw size={14} aria-hidden />
|
||||
Reload page
|
||||
</button>
|
||||
<div className="flex w-full max-w-sm flex-col items-center gap-4 rounded-[24px] border border-edge bg-surface-card px-6 py-7 shadow-[0_18px_48px_-24px_rgba(0,0,0,.35)]">
|
||||
<span className={`flex h-14 w-14 items-center justify-center rounded-full ${isChunkError ? 'bg-accent text-accent-text' : 'bg-surface-secondary text-content-muted'}`}>
|
||||
<Icon size={24} strokeWidth={2} aria-hidden />
|
||||
</span>
|
||||
<div className="space-y-1.5">
|
||||
<p className="text-title font-semibold text-content">
|
||||
{isChunkError ? 'A new version is available' : 'TREK could not start'}
|
||||
</p>
|
||||
<p className="text-body text-content-secondary">
|
||||
{isChunkError
|
||||
? 'TREK was updated while this tab was open. Reload to get the new version.'
|
||||
: 'Reloading usually fixes this. Your data is safe.'}
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => reloadPage(isChunkError)}
|
||||
className="inline-flex w-full items-center justify-center gap-2 rounded-full bg-accent px-4 py-3 text-body font-semibold text-accent-text transition-transform active:scale-[.98]"
|
||||
>
|
||||
<RefreshCw size={16} aria-hidden />
|
||||
Reload page
|
||||
</button>
|
||||
{message && (
|
||||
<details className="w-full text-caption text-content-faint">
|
||||
<summary className="cursor-pointer select-none">Details</summary>
|
||||
<code className="mt-2 block max-w-full break-words text-start">{message}</code>
|
||||
</details>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -88,5 +88,6 @@ const common: TranslationStrings = {
|
||||
'common.errorUpdateBody': 'تم تحديث TREK أثناء فتح علامة التبويب هذه. أعد التحميل للحصول على الإصدار الجديد.',
|
||||
'common.errorPluginTitle': 'تعذّر عرض هذه الإضافة',
|
||||
'common.needsConnection': 'يتطلب هذا اتصالاً. حاول مرة أخرى عندما يعود TREK للاتصال.',
|
||||
'common.errorDetails': 'التفاصيل',
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -80,5 +80,6 @@ const common: TranslationStrings = {
|
||||
'common.errorUpdateBody': 'Bu səhifə açıq olarkən TREK yeniləndi. Yeni versiyanı əldə etmək üçün səhifəni yenilə.',
|
||||
'common.errorPluginTitle': 'Bu plagini göstərmək mümkün olmadı',
|
||||
'common.needsConnection': 'Bunun üçün bağlantı lazımdır. TREK yenidən onlayn olduqda bir daha cəhd edin.',
|
||||
'common.errorDetails': 'Təfərrüatlar',
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -81,5 +81,6 @@ const common: TranslationStrings = {
|
||||
'O TREK foi atualizado enquanto esta aba estava aberta. Recarregue para obter a nova versão.',
|
||||
'common.errorPluginTitle': 'Não foi possível exibir este plugin',
|
||||
'common.needsConnection': 'Isso precisa de conexão. Tente de novo quando o TREK voltar a ficar online.',
|
||||
'common.errorDetails': 'Detalhes',
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -82,5 +82,6 @@ const common: TranslationStrings = {
|
||||
"TREK s'ha actualitzat mentre aquesta pestanya era oberta. Torna a carregar per obtenir la versió nova.",
|
||||
'common.errorPluginTitle': "No s'ha pogut mostrar aquest connector",
|
||||
'common.needsConnection': 'Això necessita connexió. Torna-ho a provar quan TREK torni a estar en línia.',
|
||||
'common.errorDetails': 'Detalls',
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -82,5 +82,6 @@ const common: TranslationStrings = {
|
||||
'common.errorUpdateBody': 'TREK byl aktualizován, zatímco byla tato karta otevřená. Načtěte znovu pro novou verzi.',
|
||||
'common.errorPluginTitle': 'Tento plugin se nepodařilo zobrazit',
|
||||
'common.needsConnection': 'Na tohle je potřeba připojení. Zkus to znovu, až bude TREK zase online.',
|
||||
'common.errorDetails': 'Podrobnosti',
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -81,5 +81,6 @@ const common: TranslationStrings = {
|
||||
'TREK wurde aktualisiert, während dieser Tab offen war. Lade neu, um die neue Version zu erhalten.',
|
||||
'common.errorPluginTitle': 'Dieses Plugin konnte nicht angezeigt werden',
|
||||
'common.needsConnection': 'Dafür braucht es eine Verbindung. Versuch es noch einmal, sobald TREK wieder online ist.',
|
||||
'common.errorDetails': 'Details', // same-as-en
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -80,5 +80,6 @@ const common: TranslationStrings = {
|
||||
'common.errorUpdateBody': 'TREK was updated while this tab was open. Reload to get the new version.',
|
||||
'common.errorPluginTitle': 'This plugin could not be shown',
|
||||
'common.needsConnection': 'This needs a connection. Try again once TREK is back online.',
|
||||
'common.errorDetails': 'Details',
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -81,5 +81,6 @@ const common: TranslationStrings = {
|
||||
'TREK se actualizó mientras esta pestaña estaba abierta. Recarga para obtener la nueva versión.',
|
||||
'common.errorPluginTitle': 'No se pudo mostrar este plugin',
|
||||
'common.needsConnection': 'Esto necesita conexión. Vuelve a intentarlo cuando TREK esté de nuevo en línea.',
|
||||
'common.errorDetails': 'Detalles',
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -81,5 +81,6 @@ const common: TranslationStrings = {
|
||||
'TREKi uuendati ajal, kui see vahekaart oli avatud. Uue versiooni kasutamiseks laadi leht uuesti.',
|
||||
'common.errorPluginTitle': 'Seda pluginat ei saanud kuvada',
|
||||
'common.needsConnection': 'Selleks on vaja ühendust. Proovi uuesti, kui TREK on taas võrgus.',
|
||||
'common.errorDetails': 'Üksikasjad',
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -81,5 +81,6 @@ const common: TranslationStrings = {
|
||||
'TREK a été mis à jour pendant que cet onglet était ouvert. Rechargez pour obtenir la nouvelle version.',
|
||||
'common.errorPluginTitle': "Ce plugin n'a pas pu être affiché",
|
||||
'common.needsConnection': 'Cela nécessite une connexion. Réessaie dès que TREK sera de nouveau en ligne.',
|
||||
'common.errorDetails': 'Détails',
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -81,5 +81,6 @@ const common: TranslationStrings = {
|
||||
'Το TREK ενημερώθηκε ενώ αυτή η καρτέλα ήταν ανοιχτή. Κάντε επαναφόρτωση για τη νέα έκδοση.',
|
||||
'common.errorPluginTitle': 'Δεν ήταν δυνατή η εμφάνιση αυτού του πρόσθετου',
|
||||
'common.needsConnection': 'Αυτό χρειάζεται σύνδεση. Δοκίμασε ξανά μόλις το TREK συνδεθεί ξανά.',
|
||||
'common.errorDetails': 'Λεπτομέρειες',
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -82,6 +82,7 @@ const common: TranslationStrings = {
|
||||
'common.errorUpdateBody': 'TREK עודכן בזמן שהלשונית הייתה פתוחה. רעננו כדי לקבל את הגרסה החדשה.',
|
||||
'common.errorPluginTitle': 'לא ניתן להציג את התוסף הזה',
|
||||
'common.needsConnection': 'הפעולה הזו דורשת חיבור. נסו שוב כש-TREK יחזור לרשת.',
|
||||
'common.errorDetails': 'פרטים',
|
||||
};
|
||||
|
||||
export default common;
|
||||
|
||||
@@ -80,5 +80,6 @@ const common: TranslationStrings = {
|
||||
'common.errorUpdateBody': 'A TREK frissült, amíg ez a lap nyitva volt. Töltse újra az új verzióért.',
|
||||
'common.errorPluginTitle': 'Ezt a bővítményt nem sikerült megjeleníteni',
|
||||
'common.needsConnection': 'Ehhez kapcsolat kell. Próbáld újra, amint a TREK újra online lesz.',
|
||||
'common.errorDetails': 'Részletek',
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -78,5 +78,6 @@ const common: TranslationStrings = {
|
||||
'common.errorUpdateBody': 'TREK diperbarui saat tab ini terbuka. Muat ulang untuk mendapatkan versi baru.',
|
||||
'common.errorPluginTitle': 'Plugin ini tidak dapat ditampilkan',
|
||||
'common.needsConnection': 'Ini memerlukan koneksi. Coba lagi begitu TREK kembali online.',
|
||||
'common.errorDetails': 'Detail',
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -81,5 +81,6 @@ const common: TranslationStrings = {
|
||||
'TREK è stato aggiornato mentre questa scheda era aperta. Ricarica per ottenere la nuova versione.',
|
||||
'common.errorPluginTitle': 'Impossibile mostrare questo plugin',
|
||||
'common.needsConnection': 'Serve una connessione. Riprova quando TREK tornerà online.',
|
||||
'common.errorDetails': 'Dettagli',
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -79,5 +79,6 @@ const common: TranslationStrings = {
|
||||
'このタブを開いている間に TREK が更新されました。再読み込みして新しいバージョンを取得してください。',
|
||||
'common.errorPluginTitle': 'このプラグインを表示できませんでした',
|
||||
'common.needsConnection': 'この操作には接続が必要です。TREK がオンラインに戻ってから、もう一度お試しください。',
|
||||
'common.errorDetails': '詳細',
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -78,5 +78,6 @@ const common: TranslationStrings = {
|
||||
'common.errorUpdateBody': '이 탭이 열려 있는 동안 TREK이 업데이트되었습니다. 새로고침하여 새 버전을 받으세요.',
|
||||
'common.errorPluginTitle': '이 플러그인을 표시할 수 없습니다',
|
||||
'common.needsConnection': '연결이 필요한 작업입니다. TREK가 다시 온라인이 되면 다시 시도하세요.',
|
||||
'common.errorDetails': '세부 정보',
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -81,5 +81,6 @@ const common: TranslationStrings = {
|
||||
'TREK is bijgewerkt terwijl dit tabblad open stond. Herlaad om de nieuwe versie te krijgen.',
|
||||
'common.errorPluginTitle': 'Deze plug-in kon niet worden getoond',
|
||||
'common.needsConnection': 'Hiervoor is een verbinding nodig. Probeer het opnieuw zodra TREK weer online is.',
|
||||
'common.errorDetails': 'Details', // same-as-en
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -84,5 +84,6 @@ const common: TranslationStrings = {
|
||||
'common.errorUpdateBody': 'TREK został zaktualizowany, gdy ta karta była otwarta. Odśwież, aby pobrać nową wersję.',
|
||||
'common.errorPluginTitle': 'Nie udało się wyświetlić tej wtyczki',
|
||||
'common.needsConnection': 'To wymaga połączenia. Spróbuj ponownie, gdy TREK znów będzie online.',
|
||||
'common.errorDetails': 'Szczegóły',
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -85,5 +85,6 @@ const common: TranslationStrings = {
|
||||
'TREK обновился, пока эта вкладка была открыта. Обновите страницу, чтобы получить новую версию.',
|
||||
'common.errorPluginTitle': 'Не удалось показать этот плагин',
|
||||
'common.needsConnection': 'Для этого нужно подключение. Попробуйте ещё раз, когда TREK снова будет онлайн.',
|
||||
'common.errorDetails': 'Подробности',
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -83,5 +83,6 @@ const common: TranslationStrings = {
|
||||
'TREK bol aktualizovaný, kým bola táto karta otvorená. Znova načítajte stránku pre novú verziu.',
|
||||
'common.errorPluginTitle': 'Tento plugin sa nepodarilo zobraziť',
|
||||
'common.needsConnection': 'Na toto je potrebné pripojenie. Skús to znova, keď bude TREK opäť online.',
|
||||
'common.errorDetails': 'Podrobnosti',
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -81,5 +81,6 @@ const common: TranslationStrings = {
|
||||
'TREK uppdaterades medan den här fliken var öppen. Ladda om för att hämta den nya versionen.',
|
||||
'common.errorPluginTitle': 'Det här tillägget kunde inte visas',
|
||||
'common.needsConnection': 'Det här kräver en anslutning. Försök igen när TREK är online igen.',
|
||||
'common.errorDetails': 'Detaljer',
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -78,5 +78,6 @@ const common: TranslationStrings = {
|
||||
'common.errorUpdateBody': 'TREK ได้รับการอัปเดตขณะที่แท็บนี้เปิดอยู่ โหลดซ้ำเพื่อรับเวอร์ชันใหม่',
|
||||
'common.errorPluginTitle': 'ไม่สามารถแสดงปลั๊กอินนี้ได้',
|
||||
'common.needsConnection': 'การทำงานนี้ต้องใช้การเชื่อมต่อ ลองอีกครั้งเมื่อ TREK กลับมาออนไลน์',
|
||||
'common.errorDetails': 'รายละเอียด',
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -80,5 +80,6 @@ const common: TranslationStrings = {
|
||||
'common.errorUpdateBody': 'Bu sekme açıkken TREK güncellendi. Yeni sürümü almak için sayfayı yenileyin.',
|
||||
'common.errorPluginTitle': 'Bu eklenti gösterilemedi',
|
||||
'common.needsConnection': 'Bunun için bağlantı gerekiyor. TREK yeniden çevrimiçi olduğunda tekrar dene.',
|
||||
'common.errorDetails': 'Ayrıntılar',
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -84,5 +84,6 @@ const common: TranslationStrings = {
|
||||
'common.errorUpdateBody': 'TREK оновився, поки ця вкладка була відкрита. Перезавантажте, щоб отримати нову версію.',
|
||||
'common.errorPluginTitle': 'Не вдалося показати цей плагін',
|
||||
'common.needsConnection': "Для цього потрібне з'єднання. Спробуйте ще раз, коли TREK знову буде онлайн.",
|
||||
'common.errorDetails': 'Подробиці',
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -78,5 +78,6 @@ const common: TranslationStrings = {
|
||||
'common.errorUpdateBody': 'TREK đã được cập nhật trong khi thẻ này đang mở. Hãy tải lại để nhận phiên bản mới.',
|
||||
'common.errorPluginTitle': 'Không thể hiển thị plugin này',
|
||||
'common.needsConnection': 'Thao tác này cần kết nối. Hãy thử lại khi TREK trực tuyến trở lại.',
|
||||
'common.errorDetails': 'Chi tiết',
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -78,5 +78,6 @@ const common: TranslationStrings = {
|
||||
'common.errorUpdateBody': '此分頁開啟期間 TREK 已更新。請重新載入以取得新版本。',
|
||||
'common.errorPluginTitle': '無法顯示此外掛程式',
|
||||
'common.needsConnection': '此操作需要網路連線。請在 TREK 恢復連線後再試一次。',
|
||||
'common.errorDetails': '詳細資訊',
|
||||
};
|
||||
export default common;
|
||||
|
||||
@@ -78,5 +78,6 @@ const common: TranslationStrings = {
|
||||
'common.errorUpdateBody': '此标签页打开期间 TREK 已更新。请重新加载以获取新版本。',
|
||||
'common.errorPluginTitle': '无法显示此插件',
|
||||
'common.needsConnection': '此操作需要网络连接。请在 TREK 恢复联网后重试。',
|
||||
'common.errorDetails': '详细信息',
|
||||
};
|
||||
export default common;
|
||||
|
||||
Reference in New Issue
Block a user