diff --git a/AGENTS.md b/AGENTS.md index f16761fe..3b06fe76 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -266,16 +266,16 @@ The router provides automatic scroll-to-top on navigation and a 404 `NotFound` p ## Internationalization -All user-facing strings live in `src/locales/.json`. `en.json` is the source of truth; ten other locales ship alongside it: `ar`, `es`, `fa`, `fr`, `km`, `ps`, `pt`, `ru`, `sn`, `zh`. +All user-facing strings live in `src/locales/.json`. `en.json` is the source of truth; fifteen other locales ship alongside it: `ar`, `es`, `fa`, `fr`, `hi`, `id`, `km`, `ps`, `pt`, `ru`, `sn`, `sw`, `tr`, `zh`, `zh-Hant`. **When you edit, add, or remove a translated string, update every locale in the same change — not just `en.json`.** Leaving the other locales stale ships an inconsistent app: users in other languages either see outdated copy or get an English fallback in the middle of a localized screen. This applies to FAQ entries, guide bodies, button labels, error messages — every value reachable through `t()`. Concrete rules: -- **Edits to an existing key** — change the value in `en.json` first, then update the corresponding key in all ten other locales. Translate the new content into each language; don't paste English. Preserve `{{interpolation}}` placeholders, markdown links, and technical tokens (`sp1…`, `BIP-352`, kind numbers, etc.) verbatim. +- **Edits to an existing key** — change the value in `en.json` first, then update the corresponding key in all fifteen other locales. Translate the new content into each language; don't paste English. Preserve `{{interpolation}}` placeholders, markdown links, and technical tokens (`sp1…`, `BIP-352`, kind numbers, etc.) verbatim. - **New keys** — add to `en.json` first, then add the same key with a translated value in every other locale. `src/test/locales.test.ts` fails the build if any locale ships a key that doesn't exist in `en.json`, but the inverse (a key missing from a non-English locale) is allowed and falls back to English at runtime — which is exactly the user-visible mess you're trying to avoid. - **Removed keys** — delete from `en.json` and every other locale together. Leftover keys are dead translations and clutter future diffs. -- **Parallelize the translation work** — when updating one English string across all ten locales, dispatch the per-language edits to subagents in parallel rather than translating ten files sequentially. Provide each subagent the new English source, the existing translation snippet (so it matches established voice), and explicit instructions to preserve placeholders and technical tokens. +- **Parallelize the translation work** — when updating one English string across all fifteen locales, dispatch the per-language edits to subagents in parallel rather than translating fifteen files sequentially. Provide each subagent the new English source, the existing translation snippet (so it matches established voice), and explicit instructions to preserve placeholders and technical tokens. Always run `npm run test` after locale changes — `locales.test.ts` catches structural drift, and the wider suite catches any `t()` calls that referenced a key you renamed. diff --git a/src/components/auth/AuthDialog.tsx b/src/components/auth/AuthDialog.tsx index eba2b1df..cfdcb422 100644 --- a/src/components/auth/AuthDialog.tsx +++ b/src/components/auth/AuthDialog.tsx @@ -3,12 +3,14 @@ import { Upload, ChevronDown, ChevronUp, + ArrowLeft, + ArrowRight, Loader2, ExternalLink, } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; -import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'; +import { Dialog, DialogContent, DialogTitle } from '@/components/ui/dialog'; import { Collapsible, CollapsibleContent, @@ -26,8 +28,10 @@ import { type NostrConnectStatus, } from '@/hooks/useLoginActions'; import { useIsMobile } from '@/hooks/useIsMobile'; +import { useToast } from '@/hooks/useToast'; import { useOnboarding } from '@/contexts/onboardingContextDef'; import { useTranslation } from 'react-i18next'; +import { cn } from '@/lib/utils'; interface AuthDialogProps { isOpen: boolean; @@ -45,17 +49,6 @@ type Step = 'welcome' | 'login' | 'connect'; const validateNsec = (nsec: string) => /^nsec1[a-zA-Z0-9]{58}$/.test(nsec); const validateBunkerUri = (uri: string) => uri.startsWith('bunker://'); -const connectStatusLabel = (status: NostrConnectStatus | null): string => { - switch (status) { - case 'awaiting-connect': - return 'Waiting for signer connection…'; - case 'getting-public-key': - return 'Getting public key…'; - default: - return ''; - } -}; - /** Check if running on an actual mobile device (not just a small screen). */ function isMobileDevice(): boolean { if (typeof navigator === 'undefined') return false; @@ -69,7 +62,6 @@ const AuthDialog: React.FC = ({ isOpen, onClose }) => { const [loginNsec, setLoginNsec] = useState(''); const [isLoggingIn, setIsLoggingIn] = useState(false); const [loginError, setLoginError] = useState(''); - const [showMoreOptions, setShowMoreOptions] = useState(false); // Nostrconnect / bunker state const [nostrConnectParams, setNostrConnectParams] = useState(null); @@ -93,7 +85,19 @@ const AuthDialog: React.FC = ({ isOpen, onClose }) => { const login = useLoginActions(); const { config } = useAppContext(); const { startSignup } = useOnboarding(); + const { toast } = useToast(); const { t } = useTranslation(); + + const connectStatusLabel = (status: NostrConnectStatus | null): string => { + switch (status) { + case 'awaiting-connect': + return t('auth.waitingForSigner'); + case 'getting-public-key': + return t('auth.gettingPublicKey'); + default: + return ''; + } + }; // Stable refs so the nostrconnect listening effect below doesn't restart on // every parent render. Parents typically pass inline arrow functions for // onClose, and useLoginActions returns a fresh object each render — without @@ -125,7 +129,6 @@ const AuthDialog: React.FC = ({ isOpen, onClose }) => { setLoginNsec(''); setIsLoggingIn(false); setLoginError(''); - setShowMoreOptions(false); setNostrConnectParams(null); setNostrConnectUri(''); setConnectError(null); @@ -228,7 +231,7 @@ const AuthDialog: React.FC = ({ isOpen, onClose }) => { await login.bunker(bunkerUri); onClose(); } catch { - setConnectError('Failed to connect. Check the bunker URI.'); + setConnectError(t('auth.errorBunkerConnect')); setIsLoggingIn(false); } }; @@ -255,11 +258,11 @@ const AuthDialog: React.FC = ({ isOpen, onClose }) => { // Login: submit the entered nsec. const handleLogin = () => { if (!loginNsec.trim()) { - setLoginError('Enter your secret key.'); + setLoginError(t('auth.errorEnterSecretKey')); return; } if (!validateNsec(loginNsec)) { - setLoginError('Invalid secret key. Must start with nsec1.'); + setLoginError(t('auth.errorInvalidSecretKey')); return; } @@ -271,7 +274,7 @@ const AuthDialog: React.FC = ({ isOpen, onClose }) => { login.nsec(loginNsec); onClose(); } catch { - setLoginError("Couldn't log in with this key."); + setLoginError(t('auth.errorLoginFailed')); setIsLoggingIn(false); } }, 50); @@ -287,10 +290,10 @@ const AuthDialog: React.FC = ({ isOpen, onClose }) => { if (content && validateNsec(content.trim())) { setLoginNsec(content.trim()); } else { - setLoginError('File does not contain a valid secret key.'); + setLoginError(t('auth.errorFileNoKey')); } }; - reader.onerror = () => setLoginError('Failed to read file.'); + reader.onerror = () => setLoginError(t('auth.errorFileRead')); reader.readAsText(file); }; @@ -301,7 +304,11 @@ const AuthDialog: React.FC = ({ isOpen, onClose }) => { await login.extension(); onClose(); } catch (e) { - setLoginError(e instanceof Error ? e.message : 'Extension login failed.'); + toast({ + variant: 'destructive', + title: t('auth.extensionErrorTitle'), + description: e instanceof Error ? e.message : t('auth.errorExtensionFailed'), + }); setIsLoggingIn(false); } }; @@ -309,9 +316,9 @@ const AuthDialog: React.FC = ({ isOpen, onClose }) => { const getTitle = () => { switch (step) { case 'login': - return 'Log in'; + return t('auth.loginTitle'); case 'connect': - return 'Connect signer'; + return t('auth.connectSignerTitle'); default: return ''; } @@ -367,85 +374,57 @@ const AuthDialog: React.FC = ({ isOpen, onClose }) => { ) : ( <> - - +
+ + {getTitle()} - +
- {/* Login step. */} + {/* Login step. The secret-key form is always visible and first, + followed by the extension button (when available), then a + text link out to the remote-signer (connect) step. */} {step === 'login' && (
- {hasExtension ? ( - <> - + - - - - - Use secret key - - - - - - - - ) : ( - <> - - - + {hasExtension && ( + )}
)} @@ -458,7 +437,7 @@ const AuthDialog: React.FC = ({ isOpen, onClose }) => {

{connectError}

) : showProgressView ? ( @@ -476,7 +455,7 @@ const AuthDialog: React.FC = ({ isOpen, onClose }) => { onClick={handleConnectRetry} className="text-sm text-primary hover:underline underline-offset-4 font-medium" > - Cancel + {t('auth.cancel')}
) : nostrConnectUri ? ( @@ -490,7 +469,7 @@ const AuthDialog: React.FC = ({ isOpen, onClose }) => { {isMobile && ( )} @@ -504,7 +483,7 @@ const AuthDialog: React.FC = ({ isOpen, onClose }) => { {/* Manual bunker URI fallback. */} - Enter bunker URI manually + {t('auth.enterBunkerManually')} {showBunkerInput ? ( ) : ( @@ -515,12 +494,12 @@ const AuthDialog: React.FC = ({ isOpen, onClose }) => { setBunkerUri(e.target.value)} - placeholder="bunker://…" + placeholder={t('auth.bunkerPlaceholder')} className="text-base md:text-sm" /> {bunkerUri && !validateBunkerUri(bunkerUri) && ( - Invalid bunker URI format. + {t('auth.invalidBunkerFormat')} )} - - )} @@ -562,6 +534,7 @@ interface NsecLoginFormProps { onSubmit: () => void; onFileChange: (e: React.ChangeEvent) => void; fileInputRef: React.RefObject; + t: (key: string) => string; } const NsecLoginForm: React.FC = ({ @@ -573,6 +546,7 @@ const NsecLoginForm: React.FC = ({ onSubmit, onFileChange, fileInputRef, + t, }) => (
{ @@ -582,27 +556,26 @@ const NsecLoginForm: React.FC = ({ className="space-y-3" data-nsec-allowed > - { - setLoginNsec(e.target.value); - if (loginError) setLoginError(''); - }} - placeholder="nsec1…" - autoComplete="off" - className={loginError ? 'border-destructive focus-visible:ring-destructive' : ''} - /> - {loginError &&

{loginError}

} + + {t('auth.secretKeyLabel')} + + {/* nsec input and the key-file upload icon share a row. */}
- + { + setLoginNsec(e.target.value); + if (loginError) setLoginError(''); + }} + placeholder={t('auth.nsecPlaceholder')} + autoComplete="off" + className={cn( + 'flex-1', + loginError && 'border-destructive focus-visible:ring-destructive', + )} + /> = ({ type="button" variant="outline" size="icon" + className="shrink-0" + aria-label={t('auth.uploadKeyFile')} + title={t('auth.uploadKeyFile')} onClick={() => fileInputRef.current?.click()} >
+ + {loginError &&

{loginError}

} + + ); diff --git a/src/locales/ar.json b/src/locales/ar.json index d17678c7..9daae14d 100644 --- a/src/locales/ar.json +++ b/src/locales/ar.json @@ -131,7 +131,34 @@ "logout": "تسجيل الخروج", "addAccount": "إضافة حساب آخر", "createNewAccount": "إنشاء حساب جديد", - "loginExisting": "تسجيل الدخول بحساب موجود" + "loginExisting": "تسجيل الدخول بحساب موجود", + "loginTitle": "تسجيل الدخول", + "connectSignerTitle": "ربط أداة التوقيع", + "back": "رجوع", + "secretKeyLabel": "استخدام المفتاح السري", + "nsecPlaceholder": "nsec1…", + "uploadKeyFile": "رفع ملف المفتاح", + "loggingIn": "جارٍ تسجيل الدخول…", + "loginWithExtension": "تسجيل الدخول باستخدام إضافة", + "useRemoteSigner": "استخدام أداة توقيع عن بُعد", + "tryAgain": "حاول مرة أخرى", + "cancel": "إلغاء", + "openSignerApp": "فتح تطبيق التوقيع", + "enterBunkerManually": "إدخال رابط البنكر يدويًا", + "bunkerPlaceholder": "bunker://…", + "invalidBunkerFormat": "صيغة رابط البنكر غير صالحة.", + "connecting": "جارٍ الاتصال…", + "connect": "اتصال", + "waitingForSigner": "في انتظار اتصال أداة التوقيع…", + "gettingPublicKey": "جارٍ الحصول على المفتاح العام…", + "errorEnterSecretKey": "أدخل مفتاحك السري.", + "errorInvalidSecretKey": "مفتاح سري غير صالح. يجب أن يبدأ بـ nsec1.", + "errorLoginFailed": "تعذّر تسجيل الدخول بهذا المفتاح.", + "errorFileNoKey": "الملف لا يحتوي على مفتاح سري صالح.", + "errorFileRead": "فشل في قراءة الملف.", + "errorExtensionFailed": "فشل تسجيل الدخول باستخدام الإضافة.", + "errorBunkerConnect": "فشل الاتصال. تحقق من رابط البنكر.", + "extensionErrorTitle": "فشل تسجيل الدخول باستخدام الإضافة" }, "onboarding": { "ariaLabel": "إعداد الحساب", diff --git a/src/locales/en.json b/src/locales/en.json index 779f6ceb..0c7c900f 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -132,7 +132,34 @@ "logout": "Log out", "addAccount": "Add another account", "createNewAccount": "Create new account", - "loginExisting": "Log in with existing" + "loginExisting": "Log in with existing", + "loginTitle": "Log in", + "connectSignerTitle": "Connect signer", + "back": "Back", + "secretKeyLabel": "Use secret key", + "nsecPlaceholder": "nsec1…", + "uploadKeyFile": "Upload key file", + "loggingIn": "Logging in…", + "loginWithExtension": "Log in with extension", + "useRemoteSigner": "Use a remote signer", + "tryAgain": "Try again", + "cancel": "Cancel", + "openSignerApp": "Open signer app", + "enterBunkerManually": "Enter bunker URI manually", + "bunkerPlaceholder": "bunker://…", + "invalidBunkerFormat": "Invalid bunker URI format.", + "connecting": "Connecting…", + "connect": "Connect", + "waitingForSigner": "Waiting for signer connection…", + "gettingPublicKey": "Getting public key…", + "errorEnterSecretKey": "Enter your secret key.", + "errorInvalidSecretKey": "Invalid secret key. Must start with nsec1.", + "errorLoginFailed": "Couldn't log in with this key.", + "errorFileNoKey": "File does not contain a valid secret key.", + "errorFileRead": "Failed to read file.", + "errorExtensionFailed": "Extension login failed.", + "errorBunkerConnect": "Failed to connect. Check the bunker URI.", + "extensionErrorTitle": "Extension login failed" }, "onboarding": { "ariaLabel": "Account setup", diff --git a/src/locales/es.json b/src/locales/es.json index 8f2a756c..8bf785b0 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -131,7 +131,34 @@ "logout": "Cerrar sesión", "addAccount": "Agregar otra cuenta", "createNewAccount": "Crear cuenta nueva", - "loginExisting": "Iniciar sesión con una existente" + "loginExisting": "Iniciar sesión con una existente", + "loginTitle": "Iniciar sesión", + "connectSignerTitle": "Conectar firmante", + "back": "Atrás", + "secretKeyLabel": "Usar clave secreta", + "nsecPlaceholder": "nsec1…", + "uploadKeyFile": "Subir archivo de clave", + "loggingIn": "Iniciando sesión…", + "loginWithExtension": "Iniciar sesión con extensión", + "useRemoteSigner": "Usar un firmante remoto", + "tryAgain": "Intentar de nuevo", + "cancel": "Cancelar", + "openSignerApp": "Abrir aplicación de firma", + "enterBunkerManually": "Introducir URI de bunker manualmente", + "bunkerPlaceholder": "bunker://…", + "invalidBunkerFormat": "Formato de URI de bunker no válido.", + "connecting": "Conectando…", + "connect": "Conectar", + "waitingForSigner": "Esperando la conexión del firmante…", + "gettingPublicKey": "Obteniendo clave pública…", + "errorEnterSecretKey": "Introduce tu clave secreta.", + "errorInvalidSecretKey": "Clave secreta no válida. Debe empezar con nsec1.", + "errorLoginFailed": "No se pudo iniciar sesión con esta clave.", + "errorFileNoKey": "El archivo no contiene una clave secreta válida.", + "errorFileRead": "No se pudo leer el archivo.", + "errorExtensionFailed": "Error al iniciar sesión con la extensión.", + "errorBunkerConnect": "No se pudo conectar. Comprueba el URI del bunker.", + "extensionErrorTitle": "Error al iniciar sesión con la extensión" }, "onboarding": { "ariaLabel": "Configuración de la cuenta", diff --git a/src/locales/fa.json b/src/locales/fa.json index 17c5a87e..9cb80428 100644 --- a/src/locales/fa.json +++ b/src/locales/fa.json @@ -131,7 +131,34 @@ "logout": "خروج", "addAccount": "افزودن حساب دیگر", "createNewAccount": "ایجاد حساب جدید", - "loginExisting": "ورود با حساب موجود" + "loginExisting": "ورود با حساب موجود", + "loginTitle": "ورود", + "connectSignerTitle": "اتصال امضاکننده", + "back": "بازگشت", + "secretKeyLabel": "استفاده از کلید مخفی", + "nsecPlaceholder": "nsec1…", + "uploadKeyFile": "بارگذاری فایل کلید", + "loggingIn": "در حال ورود…", + "loginWithExtension": "ورود با افزونه", + "useRemoteSigner": "استفاده از امضاکننده راه دور", + "tryAgain": "تلاش دوباره", + "cancel": "لغو", + "openSignerApp": "باز کردن برنامه امضاکننده", + "enterBunkerManually": "وارد کردن دستی نشانی bunker", + "bunkerPlaceholder": "bunker://…", + "invalidBunkerFormat": "قالب نشانی bunker نامعتبر است.", + "connecting": "در حال اتصال…", + "connect": "اتصال", + "waitingForSigner": "در انتظار اتصال امضاکننده…", + "gettingPublicKey": "در حال دریافت کلید عمومی…", + "errorEnterSecretKey": "کلید مخفی خود را وارد کنید.", + "errorInvalidSecretKey": "کلید مخفی نامعتبر است. باید با nsec1 شروع شود.", + "errorLoginFailed": "ورود با این کلید ممکن نشد.", + "errorFileNoKey": "فایل حاوی کلید مخفی معتبری نیست.", + "errorFileRead": "خواندن فایل ناموفق بود.", + "errorExtensionFailed": "ورود با افزونه ناموفق بود.", + "errorBunkerConnect": "اتصال ناموفق بود. نشانی bunker را بررسی کنید.", + "extensionErrorTitle": "ورود با افزونه ناموفق بود" }, "onboarding": { "ariaLabel": "راه‌اندازی حساب", diff --git a/src/locales/fr.json b/src/locales/fr.json index 5651c46f..03ee3423 100644 --- a/src/locales/fr.json +++ b/src/locales/fr.json @@ -131,7 +131,34 @@ "logout": "Se déconnecter", "addAccount": "Ajouter un autre compte", "createNewAccount": "Créer un compte", - "loginExisting": "Se connecter avec un compte existant" + "loginExisting": "Se connecter avec un compte existant", + "loginTitle": "Se connecter", + "connectSignerTitle": "Connecter le signataire", + "back": "Retour", + "secretKeyLabel": "Utiliser la clé secrète", + "nsecPlaceholder": "nsec1…", + "uploadKeyFile": "Importer un fichier de clé", + "loggingIn": "Connexion…", + "loginWithExtension": "Se connecter avec l'extension", + "useRemoteSigner": "Utiliser un signataire distant", + "tryAgain": "Réessayer", + "cancel": "Annuler", + "openSignerApp": "Ouvrir l'application de signature", + "enterBunkerManually": "Saisir l'URI bunker manuellement", + "bunkerPlaceholder": "bunker://…", + "invalidBunkerFormat": "Format d'URI bunker invalide.", + "connecting": "Connexion…", + "connect": "Connecter", + "waitingForSigner": "En attente de la connexion du signataire…", + "gettingPublicKey": "Récupération de la clé publique…", + "errorEnterSecretKey": "Saisissez votre clé secrète.", + "errorInvalidSecretKey": "Clé secrète invalide. Elle doit commencer par nsec1.", + "errorLoginFailed": "Impossible de se connecter avec cette clé.", + "errorFileNoKey": "Le fichier ne contient pas de clé secrète valide.", + "errorFileRead": "Échec de la lecture du fichier.", + "errorExtensionFailed": "Échec de la connexion par extension.", + "errorBunkerConnect": "Échec de la connexion. Vérifiez l'URI bunker.", + "extensionErrorTitle": "Échec de la connexion par extension" }, "onboarding": { "ariaLabel": "Configuration du compte", diff --git a/src/locales/hi.json b/src/locales/hi.json index 04795652..3ec3581f 100644 --- a/src/locales/hi.json +++ b/src/locales/hi.json @@ -131,7 +131,34 @@ "logout": "लॉग आउट करें", "addAccount": "एक और अकाउंट जोड़ें", "createNewAccount": "नया खाता बनाएँ", - "loginExisting": "मौजूदा खाते से लॉग इन करें" + "loginExisting": "मौजूदा खाते से लॉग इन करें", + "loginTitle": "लॉग इन करें", + "connectSignerTitle": "साइनर कनेक्ट करें", + "back": "वापस", + "secretKeyLabel": "गुप्त कुंजी का उपयोग करें", + "nsecPlaceholder": "nsec1…", + "uploadKeyFile": "कुंजी फ़ाइल अपलोड करें", + "loggingIn": "लॉग इन हो रहा है…", + "loginWithExtension": "एक्सटेंशन से लॉग इन करें", + "useRemoteSigner": "रिमोट साइनर का उपयोग करें", + "tryAgain": "पुनः प्रयास करें", + "cancel": "रद्द करें", + "openSignerApp": "साइनर ऐप खोलें", + "enterBunkerManually": "बंकर URI मैन्युअल रूप से दर्ज करें", + "bunkerPlaceholder": "bunker://…", + "invalidBunkerFormat": "अमान्य बंकर URI प्रारूप।", + "connecting": "कनेक्ट हो रहा है…", + "connect": "कनेक्ट करें", + "waitingForSigner": "साइनर कनेक्शन की प्रतीक्षा हो रही है…", + "gettingPublicKey": "सार्वजनिक कुंजी प्राप्त हो रही है…", + "errorEnterSecretKey": "अपनी गुप्त कुंजी दर्ज करें।", + "errorInvalidSecretKey": "अमान्य गुप्त कुंजी। इसे nsec1 से शुरू होना चाहिए।", + "errorLoginFailed": "इस कुंजी से लॉग इन नहीं हो सका।", + "errorFileNoKey": "फ़ाइल में मान्य गुप्त कुंजी नहीं है।", + "errorFileRead": "फ़ाइल पढ़ने में विफल।", + "errorExtensionFailed": "एक्सटेंशन लॉगिन विफल।", + "errorBunkerConnect": "कनेक्ट करने में विफल। बंकर URI जाँचें।", + "extensionErrorTitle": "एक्सटेंशन लॉगिन विफल" }, "onboarding": { "ariaLabel": "अकाउंट सेटअप", diff --git a/src/locales/id.json b/src/locales/id.json index 87897b88..e05e968b 100644 --- a/src/locales/id.json +++ b/src/locales/id.json @@ -131,7 +131,34 @@ "logout": "Keluar", "addAccount": "Tambah akun lain", "createNewAccount": "Buat akun baru", - "loginExisting": "Masuk dengan akun yang ada" + "loginExisting": "Masuk dengan akun yang ada", + "loginTitle": "Masuk", + "connectSignerTitle": "Hubungkan penanda tangan", + "back": "Kembali", + "secretKeyLabel": "Gunakan kunci rahasia", + "nsecPlaceholder": "nsec1…", + "uploadKeyFile": "Unggah berkas kunci", + "loggingIn": "Sedang masuk…", + "loginWithExtension": "Masuk dengan ekstensi", + "useRemoteSigner": "Gunakan penanda tangan jarak jauh", + "tryAgain": "Coba lagi", + "cancel": "Batal", + "openSignerApp": "Buka aplikasi penanda tangan", + "enterBunkerManually": "Masukkan URI bunker secara manual", + "bunkerPlaceholder": "bunker://…", + "invalidBunkerFormat": "Format URI bunker tidak valid.", + "connecting": "Menghubungkan…", + "connect": "Hubungkan", + "waitingForSigner": "Menunggu koneksi penanda tangan…", + "gettingPublicKey": "Mengambil kunci publik…", + "errorEnterSecretKey": "Masukkan kunci rahasia Anda.", + "errorInvalidSecretKey": "Kunci rahasia tidak valid. Harus diawali dengan nsec1.", + "errorLoginFailed": "Tidak dapat masuk dengan kunci ini.", + "errorFileNoKey": "Berkas tidak berisi kunci rahasia yang valid.", + "errorFileRead": "Gagal membaca berkas.", + "errorExtensionFailed": "Login ekstensi gagal.", + "errorBunkerConnect": "Gagal menghubungkan. Periksa URI bunker.", + "extensionErrorTitle": "Login ekstensi gagal" }, "onboarding": { "ariaLabel": "Penyiapan akun", diff --git a/src/locales/km.json b/src/locales/km.json index 1bf20a3a..a028e4ff 100644 --- a/src/locales/km.json +++ b/src/locales/km.json @@ -131,7 +131,34 @@ "logout": "ចេញពីគណនី", "addAccount": "បន្ថែមគណនីផ្សេងទៀត", "createNewAccount": "បង្កើតគណនីថ្មី", - "loginExisting": "ចូលដោយគណនីដែលមានស្រាប់" + "loginExisting": "ចូលដោយគណនីដែលមានស្រាប់", + "loginTitle": "ចូល", + "connectSignerTitle": "ភ្ជាប់កម្មវិធីចុះហត្ថលេខា", + "back": "ត្រឡប់", + "secretKeyLabel": "ប្រើសោសម្ងាត់", + "nsecPlaceholder": "nsec1…", + "uploadKeyFile": "ផ្ទុកឯកសារសោឡើង", + "loggingIn": "កំពុងចូល…", + "loginWithExtension": "ចូលដោយផ្នែកបន្ថែម", + "useRemoteSigner": "ប្រើកម្មវិធីចុះហត្ថលេខាពីចម្ងាយ", + "tryAgain": "ព្យាយាមម្តងទៀត", + "cancel": "បោះបង់", + "openSignerApp": "បើកកម្មវិធីចុះហត្ថលេខា", + "enterBunkerManually": "បញ្ចូល URI bunker ដោយដៃ", + "bunkerPlaceholder": "bunker://…", + "invalidBunkerFormat": "ទម្រង់ URI bunker មិនត្រឹមត្រូវ។", + "connecting": "កំពុងភ្ជាប់…", + "connect": "ភ្ជាប់", + "waitingForSigner": "កំពុងរង់ចាំការភ្ជាប់កម្មវិធីចុះហត្ថលេខា…", + "gettingPublicKey": "កំពុងទាញយកសោសាធារណៈ…", + "errorEnterSecretKey": "បញ្ចូលសោសម្ងាត់របស់អ្នក។", + "errorInvalidSecretKey": "សោសម្ងាត់មិនត្រឹមត្រូវ។ ត្រូវចាប់ផ្តើមដោយ nsec1។", + "errorLoginFailed": "មិនអាចចូលដោយសោនេះបានទេ។", + "errorFileNoKey": "ឯកសារមិនមានសោសម្ងាត់ត្រឹមត្រូវទេ។", + "errorFileRead": "បរាជ័យក្នុងការអានឯកសារ។", + "errorExtensionFailed": "ការចូលដោយផ្នែកបន្ថែមបានបរាជ័យ។", + "errorBunkerConnect": "បរាជ័យក្នុងការភ្ជាប់។ ពិនិត្យ URI bunker។", + "extensionErrorTitle": "ការចូលដោយផ្នែកបន្ថែមបានបរាជ័យ" }, "onboarding": { "ariaLabel": "ការរៀបចំគណនី", diff --git a/src/locales/ps.json b/src/locales/ps.json index ad5899cb..fde9c809 100644 --- a/src/locales/ps.json +++ b/src/locales/ps.json @@ -131,7 +131,34 @@ "logout": "وتل", "addAccount": "بل حساب اضافه کول", "createNewAccount": "نوی حساب جوړ کړئ", - "loginExisting": "د موجوده حساب سره ننوتل" + "loginExisting": "د موجوده حساب سره ننوتل", + "loginTitle": "ننوتل", + "connectSignerTitle": "لاسلیک کوونکی نښلول", + "back": "شاته", + "secretKeyLabel": "پټ کیلي وکاروئ", + "nsecPlaceholder": "nsec1…", + "uploadKeyFile": "د کیلي فایل پورته کول", + "loggingIn": "ننوتل کیږي…", + "loginWithExtension": "د توسیع په مرسته ننوتل", + "useRemoteSigner": "لیرې لاسلیک کوونکی وکاروئ", + "tryAgain": "بیا هڅه وکړئ", + "cancel": "لغوه کول", + "openSignerApp": "د لاسلیک کوونکي اپلیکیشن پرانیستل", + "enterBunkerManually": "د bunker URI په لاس داخل کړئ", + "bunkerPlaceholder": "bunker://…", + "invalidBunkerFormat": "د bunker URI ناسم بڼه.", + "connecting": "نښلول کیږي…", + "connect": "نښلول", + "waitingForSigner": "د لاسلیک کوونکي د نښلون په تمه…", + "gettingPublicKey": "عامه کیلي ترلاسه کیږي…", + "errorEnterSecretKey": "خپله پټه کیلي داخل کړئ.", + "errorInvalidSecretKey": "ناسمه پټه کیلي. باید په nsec1 پیل شي.", + "errorLoginFailed": "د دې کیلي سره ننوتل ونشول.", + "errorFileNoKey": "فایل کې سمه پټه کیلي نشته.", + "errorFileRead": "د فایل لوستل پاتې راغلل.", + "errorExtensionFailed": "د توسیع ننوتل پاتې راغلل.", + "errorBunkerConnect": "نښلول پاتې راغلل. د bunker URI وګورئ.", + "extensionErrorTitle": "د توسیع ننوتل پاتې راغلل" }, "onboarding": { "ariaLabel": "د حساب جوړونه", diff --git a/src/locales/pt.json b/src/locales/pt.json index b76824c4..af861e44 100644 --- a/src/locales/pt.json +++ b/src/locales/pt.json @@ -131,7 +131,34 @@ "logout": "Sair", "addAccount": "Adicionar outra conta", "createNewAccount": "Criar nova conta", - "loginExisting": "Entrar com uma conta existente" + "loginExisting": "Entrar com uma conta existente", + "loginTitle": "Entrar", + "connectSignerTitle": "Conectar assinador", + "back": "Voltar", + "secretKeyLabel": "Usar chave secreta", + "nsecPlaceholder": "nsec1…", + "uploadKeyFile": "Enviar arquivo de chave", + "loggingIn": "Entrando…", + "loginWithExtension": "Entrar com extensão", + "useRemoteSigner": "Usar um assinador remoto", + "tryAgain": "Tentar novamente", + "cancel": "Cancelar", + "openSignerApp": "Abrir aplicativo assinador", + "enterBunkerManually": "Inserir URI bunker manualmente", + "bunkerPlaceholder": "bunker://…", + "invalidBunkerFormat": "Formato de URI bunker inválido.", + "connecting": "Conectando…", + "connect": "Conectar", + "waitingForSigner": "Aguardando conexão do assinador…", + "gettingPublicKey": "Obtendo chave pública…", + "errorEnterSecretKey": "Insira sua chave secreta.", + "errorInvalidSecretKey": "Chave secreta inválida. Deve começar com nsec1.", + "errorLoginFailed": "Não foi possível entrar com esta chave.", + "errorFileNoKey": "O arquivo não contém uma chave secreta válida.", + "errorFileRead": "Falha ao ler o arquivo.", + "errorExtensionFailed": "Falha no login com extensão.", + "errorBunkerConnect": "Falha ao conectar. Verifique o URI bunker.", + "extensionErrorTitle": "Falha no login com extensão" }, "onboarding": { "ariaLabel": "Configuração da conta", diff --git a/src/locales/ru.json b/src/locales/ru.json index 28addfc7..2b31e372 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -131,7 +131,34 @@ "logout": "Выйти", "addAccount": "Добавить ещё один аккаунт", "createNewAccount": "Создать новый аккаунт", - "loginExisting": "Войти в существующий" + "loginExisting": "Войти в существующий", + "loginTitle": "Войти", + "connectSignerTitle": "Подключить подписывающее устройство", + "back": "Назад", + "secretKeyLabel": "Использовать секретный ключ", + "nsecPlaceholder": "nsec1…", + "uploadKeyFile": "Загрузить файл ключа", + "loggingIn": "Вход…", + "loginWithExtension": "Войти через расширение", + "useRemoteSigner": "Использовать удалённое подписывающее устройство", + "tryAgain": "Попробовать снова", + "cancel": "Отмена", + "openSignerApp": "Открыть приложение подписи", + "enterBunkerManually": "Ввести URI bunker вручную", + "bunkerPlaceholder": "bunker://…", + "invalidBunkerFormat": "Неверный формат URI bunker.", + "connecting": "Подключение…", + "connect": "Подключить", + "waitingForSigner": "Ожидание подключения подписывающего устройства…", + "gettingPublicKey": "Получение открытого ключа…", + "errorEnterSecretKey": "Введите ваш секретный ключ.", + "errorInvalidSecretKey": "Неверный секретный ключ. Должен начинаться с nsec1.", + "errorLoginFailed": "Не удалось войти с этим ключом.", + "errorFileNoKey": "Файл не содержит действительного секретного ключа.", + "errorFileRead": "Не удалось прочитать файл.", + "errorExtensionFailed": "Не удалось войти через расширение.", + "errorBunkerConnect": "Не удалось подключиться. Проверьте URI bunker.", + "extensionErrorTitle": "Не удалось войти через расширение" }, "onboarding": { "ariaLabel": "Настройка аккаунта", diff --git a/src/locales/sn.json b/src/locales/sn.json index ba6c1ad3..8d3f7945 100644 --- a/src/locales/sn.json +++ b/src/locales/sn.json @@ -131,7 +131,34 @@ "logout": "Buda", "addAccount": "Wedzera imwe akaunti", "createNewAccount": "Gadzira account itsva", - "loginExisting": "Pinda neyiripo" + "loginExisting": "Pinda neyiripo", + "loginTitle": "Pinda", + "connectSignerTitle": "Batanidza chisaini", + "back": "Dzokera", + "secretKeyLabel": "Shandisa kiyi yakavanzika", + "nsecPlaceholder": "nsec1…", + "uploadKeyFile": "Tumira faira rekiyi", + "loggingIn": "Kupinda…", + "loginWithExtension": "Pinda neextension", + "useRemoteSigner": "Shandisa chisaini chiri kure", + "tryAgain": "Edza zvakare", + "cancel": "Kanzura", + "openSignerApp": "Vhura app yechisaini", + "enterBunkerManually": "Isa URI ye bunker pachako", + "bunkerPlaceholder": "bunker://…", + "invalidBunkerFormat": "Fomati ye URI ye bunker isina kunaka.", + "connecting": "Kubatanidza…", + "connect": "Batanidza", + "waitingForSigner": "Kumirira kubatana kwechisaini…", + "gettingPublicKey": "Kutora kiyi yeruzhinji…", + "errorEnterSecretKey": "Isa kiyi yako yakavanzika.", + "errorInvalidSecretKey": "Kiyi yakavanzika isina kunaka. Inofanira kutanga ne nsec1.", + "errorLoginFailed": "Hazvina kukwanisa kupinda nekiyi iyi.", + "errorFileNoKey": "Faira harina kiyi yakavanzika iri nani.", + "errorFileRead": "Hazvina kukwanisa kuverenga faira.", + "errorExtensionFailed": "Kupinda neextension kwakundikana.", + "errorBunkerConnect": "Hazvina kukwanisa kubatanidza. Ongorora URI ye bunker.", + "extensionErrorTitle": "Kupinda neextension kwakundikana" }, "onboarding": { "ariaLabel": "Kugadzira akaunti", diff --git a/src/locales/sw.json b/src/locales/sw.json index 66659e87..677bc7af 100644 --- a/src/locales/sw.json +++ b/src/locales/sw.json @@ -131,7 +131,34 @@ "logout": "Toka", "addAccount": "Ongeza akaunti nyingine", "createNewAccount": "Fungua akaunti mpya", - "loginExisting": "Ingia kwa iliyopo" + "loginExisting": "Ingia kwa iliyopo", + "loginTitle": "Ingia", + "connectSignerTitle": "Unganisha kifaa cha kusaini", + "back": "Rudi", + "secretKeyLabel": "Tumia ufunguo wa siri", + "nsecPlaceholder": "nsec1…", + "uploadKeyFile": "Pakia faili ya ufunguo", + "loggingIn": "Inaingia…", + "loginWithExtension": "Ingia kwa kiendelezi", + "useRemoteSigner": "Tumia kifaa cha kusaini cha mbali", + "tryAgain": "Jaribu tena", + "cancel": "Ghairi", + "openSignerApp": "Fungua programu ya kusaini", + "enterBunkerManually": "Weka URI ya bunker mwenyewe", + "bunkerPlaceholder": "bunker://…", + "invalidBunkerFormat": "Muundo wa URI ya bunker si sahihi.", + "connecting": "Inaunganisha…", + "connect": "Unganisha", + "waitingForSigner": "Inasubiri muunganisho wa kifaa cha kusaini…", + "gettingPublicKey": "Inapata ufunguo wa umma…", + "errorEnterSecretKey": "Weka ufunguo wako wa siri.", + "errorInvalidSecretKey": "Ufunguo wa siri si sahihi. Lazima uanze na nsec1.", + "errorLoginFailed": "Imeshindwa kuingia kwa ufunguo huu.", + "errorFileNoKey": "Faili haina ufunguo wa siri halali.", + "errorFileRead": "Imeshindwa kusoma faili.", + "errorExtensionFailed": "Kuingia kwa kiendelezi kumeshindwa.", + "errorBunkerConnect": "Imeshindwa kuunganisha. Angalia URI ya bunker.", + "extensionErrorTitle": "Kuingia kwa kiendelezi kumeshindwa" }, "onboarding": { "ariaLabel": "Usanidi wa akaunti", diff --git a/src/locales/tr.json b/src/locales/tr.json index 39c68c19..e5699b64 100644 --- a/src/locales/tr.json +++ b/src/locales/tr.json @@ -131,7 +131,34 @@ "logout": "Çıkış yap", "addAccount": "Başka hesap ekle", "createNewAccount": "Yeni hesap oluştur", - "loginExisting": "Mevcut hesapla giriş yap" + "loginExisting": "Mevcut hesapla giriş yap", + "loginTitle": "Giriş yap", + "connectSignerTitle": "İmzalayıcıya bağlan", + "back": "Geri", + "secretKeyLabel": "Gizli anahtar kullan", + "nsecPlaceholder": "nsec1…", + "uploadKeyFile": "Anahtar dosyası yükle", + "loggingIn": "Giriş yapılıyor…", + "loginWithExtension": "Eklenti ile giriş yap", + "useRemoteSigner": "Uzak imzalayıcı kullan", + "tryAgain": "Tekrar dene", + "cancel": "İptal", + "openSignerApp": "İmzalayıcı uygulamasını aç", + "enterBunkerManually": "Bunker URI'sini elle gir", + "bunkerPlaceholder": "bunker://…", + "invalidBunkerFormat": "Geçersiz bunker URI biçimi.", + "connecting": "Bağlanılıyor…", + "connect": "Bağlan", + "waitingForSigner": "İmzalayıcı bağlantısı bekleniyor…", + "gettingPublicKey": "Açık anahtar alınıyor…", + "errorEnterSecretKey": "Gizli anahtarınızı girin.", + "errorInvalidSecretKey": "Geçersiz gizli anahtar. nsec1 ile başlamalı.", + "errorLoginFailed": "Bu anahtarla giriş yapılamadı.", + "errorFileNoKey": "Dosya geçerli bir gizli anahtar içermiyor.", + "errorFileRead": "Dosya okunamadı.", + "errorExtensionFailed": "Eklenti ile giriş başarısız oldu.", + "errorBunkerConnect": "Bağlanılamadı. Bunker URI'sini kontrol edin.", + "extensionErrorTitle": "Eklenti ile giriş başarısız oldu" }, "onboarding": { "ariaLabel": "Hesap kurulumu", diff --git a/src/locales/zh-Hant.json b/src/locales/zh-Hant.json index 7029b004..17c10aba 100644 --- a/src/locales/zh-Hant.json +++ b/src/locales/zh-Hant.json @@ -131,7 +131,34 @@ "logout": "退出登入", "addAccount": "新增其他賬戶", "createNewAccount": "建立新帳戶", - "loginExisting": "使用現有帳戶登入" + "loginExisting": "使用現有帳戶登入", + "loginTitle": "登入", + "connectSignerTitle": "連接簽名器", + "back": "返回", + "secretKeyLabel": "使用私鑰", + "nsecPlaceholder": "nsec1…", + "uploadKeyFile": "上傳金鑰檔案", + "loggingIn": "正在登入…", + "loginWithExtension": "使用擴充功能登入", + "useRemoteSigner": "使用遠端簽名器", + "tryAgain": "重試", + "cancel": "取消", + "openSignerApp": "開啟簽名器應用程式", + "enterBunkerManually": "手動輸入 bunker URI", + "bunkerPlaceholder": "bunker://…", + "invalidBunkerFormat": "bunker URI 格式無效。", + "connecting": "正在連接…", + "connect": "連接", + "waitingForSigner": "正在等待簽名器連接…", + "gettingPublicKey": "正在取得公鑰…", + "errorEnterSecretKey": "請輸入您的私鑰。", + "errorInvalidSecretKey": "私鑰無效。必須以 nsec1 開頭。", + "errorLoginFailed": "無法使用此金鑰登入。", + "errorFileNoKey": "檔案不包含有效的私鑰。", + "errorFileRead": "讀取檔案失敗。", + "errorExtensionFailed": "擴充功能登入失敗。", + "errorBunkerConnect": "連接失敗。請檢查 bunker URI。", + "extensionErrorTitle": "擴充功能登入失敗" }, "onboarding": { "ariaLabel": "帳號設定", diff --git a/src/locales/zh.json b/src/locales/zh.json index b742b321..1c58fcc1 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -131,7 +131,34 @@ "logout": "退出登录", "addAccount": "添加其他账户", "createNewAccount": "创建新账户", - "loginExisting": "使用现有账户登录" + "loginExisting": "使用现有账户登录", + "loginTitle": "登录", + "connectSignerTitle": "连接签名器", + "back": "返回", + "secretKeyLabel": "使用私钥", + "nsecPlaceholder": "nsec1…", + "uploadKeyFile": "上传密钥文件", + "loggingIn": "正在登录…", + "loginWithExtension": "使用扩展登录", + "useRemoteSigner": "使用远程签名器", + "tryAgain": "重试", + "cancel": "取消", + "openSignerApp": "打开签名器应用", + "enterBunkerManually": "手动输入 bunker URI", + "bunkerPlaceholder": "bunker://…", + "invalidBunkerFormat": "bunker URI 格式无效。", + "connecting": "正在连接…", + "connect": "连接", + "waitingForSigner": "正在等待签名器连接…", + "gettingPublicKey": "正在获取公钥…", + "errorEnterSecretKey": "请输入您的私钥。", + "errorInvalidSecretKey": "私钥无效。必须以 nsec1 开头。", + "errorLoginFailed": "无法使用此密钥登录。", + "errorFileNoKey": "文件不包含有效的私钥。", + "errorFileRead": "读取文件失败。", + "errorExtensionFailed": "扩展登录失败。", + "errorBunkerConnect": "连接失败。请检查 bunker URI。", + "extensionErrorTitle": "扩展登录失败" }, "onboarding": { "ariaLabel": "账户设置",