diff --git a/src/components/ComposeBox.tsx b/src/components/ComposeBox.tsx index 89211232..3e0743b6 100644 --- a/src/components/ComposeBox.tsx +++ b/src/components/ComposeBox.tsx @@ -1,5 +1,6 @@ import { lazy, Suspense, useState, useRef, useCallback, useMemo, useEffect } from 'react'; import { Link } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; import { Paperclip, Smile, AlertTriangle, X, Loader2, Mic, Square, Sticker, BarChart3, Plus, ChevronLeft, Check, Globe, HelpCircle } from 'lucide-react'; import { nip19 } from 'nostr-tools'; import { encode as blurhashEncode } from 'blurhash'; @@ -228,7 +229,7 @@ function CharRing({ count, max }: { count: number; max: number }) { export function ComposeBox({ onSuccess, onPublished, - placeholder = "What's on your mind?", + placeholder, compact = false, replyTo, quotedEvent, @@ -242,10 +243,13 @@ export function ComposeBox({ initialMode = 'post', customPublish, hidePoll = false, - submitLabel = 'Post!', + submitLabel, defaultTags, defaultExpanded = false, }: ComposeBoxProps) { + const { t } = useTranslation(); + const effectivePlaceholder = placeholder ?? t('compose.placeholderDefault'); + const effectiveSubmitLabel = submitLabel ?? t('compose.submitDefault'); const { user, metadata, isLoading: isProfileLoading } = useCurrentUser(); const userProfileUrl = useProfileUrl(user?.pubkey ?? '', metadata); const { mutateAsync: createEvent, isPending, isPending: isPollPending } = useNostrPublish(); @@ -695,9 +699,9 @@ export function ComposeBox({ expand(); } catch { - toast({ title: 'Upload failed', description: 'Could not upload file.', variant: 'destructive' }); + toast({ title: t('compose.submit.uploadFailed'), description: t('compose.submit.uploadFailedBody'), variant: 'destructive' }); } - }, [uploadFile, expand, toast, imageQuality]); + }, [uploadFile, expand, toast, imageQuality, t]); const handlePaste = useCallback(async (e: React.ClipboardEvent) => { const items = e.clipboardData?.items; @@ -723,9 +727,9 @@ export function ComposeBox({ await voiceRecorder.startRecording(); expand(); } catch { - toast({ title: 'Microphone access denied', description: 'Please allow microphone access to record voice messages.', variant: 'destructive' }); + toast({ title: t('compose.voice.micDeniedTitle'), description: t('compose.voice.micDeniedBody'), variant: 'destructive' }); } - }, [voiceRecorder, expand, toast]); + }, [voiceRecorder, expand, toast, t]); /** Stop recording, upload, and publish as kind 1222 or 1244. */ const handleStopAndPublishVoice = useCallback(async () => { @@ -860,14 +864,14 @@ export function ComposeBox({ queryClient.invalidateQueries({ queryKey: ['agora-feed-new-posts', selectedCountryCode] }); } notificationSuccess(); - toast({ title: 'Voice message sent!', description: 'Your voice message has been published.' }); + toast({ title: t('compose.voice.sentTitle'), description: t('compose.voice.sentBody') }); onSuccess?.(); } catch { - toast({ title: 'Error', description: 'Failed to send voice message.', variant: 'destructive' }); + toast({ title: t('common.error'), description: t('compose.voice.sendFailed'), variant: 'destructive' }); } finally { setIsPublishingVoice(false); } - }, [user, voiceRecorder, uploadFile, buildContentWarningTags, customPublish, createEvent, onPublished, replyTo, queryClient, toast, onSuccess, canChooseDestination, selectedCountryCode, statsPubkey]); + }, [user, voiceRecorder, uploadFile, buildContentWarningTags, customPublish, createEvent, onPublished, replyTo, queryClient, toast, onSuccess, canChooseDestination, selectedCountryCode, statsPubkey, t]); const handleSubmit = async () => { if (!content.trim() || !user || charCount > MAX_CHARS) return; @@ -1135,13 +1139,13 @@ export function ComposeBox({ notificationSuccess(); if (!customPublish?.suppressSuccessToast) { toast({ - title: customPublish?.successTitle ?? 'Posted!', - description: customPublish?.successDescription ?? (replyTo ? 'Your reply has been published.' : quotedEvent ? 'Your quote has been published.' : 'Your note has been published.'), + title: customPublish?.successTitle ?? t('compose.submit.posted'), + description: customPublish?.successDescription ?? (replyTo ? t('compose.submit.replyPublished') : quotedEvent ? t('compose.submit.quotePublished') : t('compose.submit.notePublished')), }); } onSuccess?.(); } catch { - toast({ title: 'Error', description: 'Failed to publish note.', variant: 'destructive' }); + toast({ title: t('common.error'), description: t('compose.submit.publishFailed'), variant: 'destructive' }); } }; @@ -1205,10 +1209,10 @@ export function ComposeBox({ queryClient.invalidateQueries({ queryKey: ['agora-feed-new-posts', selectedCountryCode] }); } notificationSuccess(); - toast({ title: 'Poll published!' }); + toast({ title: t('compose.poll.published') }); onSuccess?.(); } catch { - toast({ title: 'Error', description: 'Failed to publish poll.', variant: 'destructive' }); + toast({ title: t('common.error'), description: t('compose.poll.publishFailed'), variant: 'destructive' }); } }; @@ -1241,7 +1245,7 @@ export function ComposeBox({ : "text-muted-foreground hover:text-foreground" )} > - Edit + {t('compose.preview.edit')} @@ -1290,10 +1294,10 @@ export function ComposeBox({ onPaste={handlePaste} placeholder={ mode === 'poll' - ? 'Ask a question…' + ? t('compose.placeholderPoll') : selectedCountryInfo - ? `What's happening in ${selectedCountryInfo.name}?` - : placeholder + ? t('compose.placeholderCountry', { country: selectedCountryInfo.name }) + : effectivePlaceholder } className={cn( 'w-full bg-transparent text-foreground placeholder:text-muted-foreground resize-none outline-none text-lg pt-2.5 pb-2 opacity-85 break-words overflow-hidden transition-[min-height] duration-200 ease-in-out', @@ -1343,8 +1347,8 @@ export function ComposeBox({ onClick={() => setMode('post')} className="flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground transition-colors" > - - Back to post + + {t('compose.poll.backToPost')} )} @@ -1360,7 +1364,7 @@ export function ComposeBox({ prev.map((o) => (o.id === opt.id ? { ...o, label: e.target.value } : o)), ) } - placeholder={`Option ${idx + 1}`} + placeholder={t('compose.poll.optionLabel', { number: idx + 1 })} maxLength={100} className="flex-1 bg-secondary/40 rounded-lg px-3 py-1.5 text-sm outline-none focus:ring-1 focus:ring-primary/40 placeholder:text-muted-foreground" /> @@ -1388,26 +1392,26 @@ export function ComposeBox({ className="flex items-center gap-1.5 text-xs text-primary hover:text-primary/80 transition-colors pt-0.5" > - Add option + {t('compose.poll.addOption')} )} {/* Settings row — pill toggles */}
- {(['singlechoice', 'multiplechoice'] as const).map((t) => ( + {(['singlechoice', 'multiplechoice'] as const).map((pt) => ( ))}
@@ -1437,7 +1441,7 @@ export function ComposeBox({ setCwText(e.target.value)} - placeholder="Content warning reason (optional)" + placeholder={t('compose.placeholderCwReason')} className="h-8 text-base md:text-sm bg-secondary/50 border-0 rounded-lg" />
@@ -1524,9 +1528,9 @@ export function ComposeBox({ {exampleFlag ?? '🌐'}
-

Your country community

+

{t('compose.destination.community')}

- Shown in that country's local feed alongside posts from neighbors. Best for community-relevant updates. + {t('compose.destination.communityExplainer')}

@@ -1537,7 +1541,7 @@ export function ComposeBox({ - Global + {t('compose.destination.global')} {destination === 'world' && ( @@ -1610,15 +1614,15 @@ export function ComposeBox({ className="cursor-pointer text-sm" > - Choose another country… + {t('compose.destination.chooseAnother')} {destination === defaultPostCountry ? (
{(() => { - if (defaultPostCountry === 'world') return 'Global is your default'; + if (defaultPostCountry === 'world') return t('compose.destination.globalIsDefault'); const info = getCountryInfo(defaultPostCountry); - return info ? `${info.name} is your default` : 'This is your default'; + return info ? t('compose.destination.isDefault', { name: info.name }) : t('compose.destination.thisIsDefault'); })()}
) : ( @@ -1629,15 +1633,15 @@ export function ComposeBox({ ? null : getCountryInfo(destination); toast({ - title: 'Default updated', + title: t('compose.destination.defaultUpdated'), description: info - ? `New posts will go to ${info.name} by default.` - : 'New posts will be global by default.', + ? t('compose.destination.defaultUpdatedCountry', { name: info.name }) + : t('compose.destination.defaultUpdatedGlobal'), }); }} className="cursor-pointer text-sm" > - Set as default + {t('compose.destination.setAsDefault')} )} @@ -1651,9 +1655,9 @@ export function ComposeBox({ open={countryPickerOpen} onOpenChange={setCountryPickerOpen} > - + - No countries found. + {t('compose.destination.noResults')} - Global + {t('compose.destination.global')} {destination === 'world' && ( )} @@ -1732,7 +1736,7 @@ export function ComposeBox({ - Cancel + {t('compose.voice.cancel')} {/* Stop & send button */} @@ -1747,7 +1751,7 @@ export function ComposeBox({ ) : ( )} - {isPublishingVoice ? 'Sending...' : 'Send'} + {isPublishingVoice ? t('compose.voice.sending') : t('compose.voice.send')} ) : ( @@ -1767,7 +1771,7 @@ export function ComposeBox({ {isUploading ? : } - Attach file + {t('compose.toolbar.attachFile')} - Voice message + {t('compose.voice.voiceMessage')} )} @@ -1818,7 +1822,7 @@ export function ComposeBox({ - {!pickerOpen && Emoji / GIF} + {!pickerOpen && {t('compose.toolbar.emojiGif')}} {/* Overflow: Poll + CW */} @@ -1840,7 +1844,7 @@ export function ComposeBox({ - {!trayOpen && More} + {!trayOpen && {t('compose.toolbar.more')}}
@@ -1853,7 +1857,7 @@ export function ComposeBox({ onClick={() => { setMode((m) => m === 'poll' ? 'post' : 'poll'); setTrayOpen(false); expand(); }} className={cn('flex items-center gap-2.5 w-full px-3 py-2 rounded-lg text-sm transition-colors', mode === 'poll' ? 'text-primary bg-primary/10' : 'text-muted-foreground hover:text-foreground hover:bg-secondary/60')} > - Poll + {t('compose.toolbar.poll')} )}
@@ -1893,7 +1897,7 @@ export function ComposeBox({ className="rounded-full px-5 font-bold text-white" size="sm" > - {isPollPending ? 'Publishing...' : 'Publish poll'} + {isPollPending ? t('compose.poll.publishing') : t('compose.poll.publish')} ) : ( )} @@ -1927,7 +1931,7 @@ export function ComposeBox({ )} > - Emoji + {t('compose.toolbar.emoji')} )} diff --git a/src/components/ReplyComposeModal.tsx b/src/components/ReplyComposeModal.tsx index d48c58d4..19b76d22 100644 --- a/src/components/ReplyComposeModal.tsx +++ b/src/components/ReplyComposeModal.tsx @@ -1,4 +1,5 @@ import { useCallback, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { X } from 'lucide-react'; import type { NostrEvent } from '@nostrify/nostrify'; @@ -33,6 +34,7 @@ interface ReplyComposeModalProps { } export function ReplyComposeModal({ event, quotedEvent, open, onOpenChange, onSuccess, initialContent, initialMode, title: titleOverride, placeholder: placeholderOverride }: ReplyComposeModalProps) { + const { t } = useTranslation(); const isUrl = event instanceof URL; const isExternalId = typeof event === 'string'; const isExternal = isUrl || isExternalId; @@ -43,8 +45,20 @@ export function ReplyComposeModal({ event, quotedEvent, open, onOpenChange, onSu const [portalContainer, setPortalContainer] = useState(undefined); const isProfileRoot = !isExternal && event instanceof Object && 'kind' in event && event.kind === 0; - const title = titleOverride ?? (initialMode === 'poll' ? 'New poll' : isExternal ? 'New comment' : isProfileRoot ? 'Comment on profile' : isReply ? 'Reply to post' : isQuote ? 'Quote post' : 'New post'); - const placeholder = placeholderOverride ?? (isExternal ? 'Write a comment...' : isReply ? "What's on your mind?" : isQuote ? 'Add a comment...' : "What's happening?"); + const title = titleOverride ?? ( + initialMode === 'poll' ? t('replyModal.title.newPoll') + : isExternal ? t('replyModal.title.newComment') + : isProfileRoot ? t('replyModal.title.commentOnProfile') + : isReply ? t('replyModal.title.replyToPost') + : isQuote ? t('replyModal.title.quotePost') + : t('replyModal.title.newPost') + ); + const placeholder = placeholderOverride ?? ( + isExternal ? t('replyModal.placeholder.writeComment') + : isReply ? t('compose.placeholderDefault') + : isQuote ? t('replyModal.placeholder.addComment') + : t('replyModal.placeholder.whatsHappening') + ); const dialogContentRef = useCallback((node: HTMLElement | null) => { setPortalContainer(node ?? undefined); @@ -95,7 +109,7 @@ export function ReplyComposeModal({ event, quotedEvent, open, onOpenChange, onSu : "text-muted-foreground hover:text-foreground" )} > - Edit + {t('compose.preview.edit')} )} @@ -142,7 +156,7 @@ export function ReplyComposeModal({ event, quotedEvent, open, onOpenChange, onSu
⚠️

- People on Bluesky can't see you because they're not actually decentralized. + {t('replyModal.blueskyDisclaimer')}

)} diff --git a/src/locales/ar.json b/src/locales/ar.json index 41a4c495..75e31751 100644 --- a/src/locales/ar.json +++ b/src/locales/ar.json @@ -1301,5 +1301,92 @@ "copyFailed": "فشل النسخ", "copyFailedDescription": "تعذّر الوصول إلى الحافظة. أظهر المفتاح وانسخه يدويًا." } + }, + "compose": { + "placeholderDefault": "بِمَ تفكر؟", + "placeholderPoll": "اطرح سؤالاً…", + "placeholderCountry": "ماذا يحدث في {{country}}؟", + "placeholderCwReason": "سبب التحذير (اختياري)", + "submitDefault": "انشر!", + "preview": { + "edit": "تحرير", + "previewMode": "معاينة" + }, + "poll": { + "addOption": "إضافة خيار", + "optionLabel": "الخيار {{number}}", + "singleChoice": "اختيار واحد", + "multipleChoice": "اختيارات متعددة", + "backToPost": "العودة إلى المنشور", + "publishing": "جارٍ النشر...", + "publish": "نشر التصويت", + "published": "تم نشر التصويت!", + "publishFailed": "فشل نشر التصويت." + }, + "voice": { + "cancel": "إلغاء", + "send": "إرسال", + "sending": "جارٍ الإرسال...", + "sentTitle": "تم إرسال الرسالة الصوتية!", + "sentBody": "تم نشر رسالتك الصوتية.", + "sendFailed": "فشل إرسال الرسالة الصوتية.", + "micDeniedTitle": "تم رفض الوصول إلى الميكروفون", + "micDeniedBody": "يرجى السماح بالوصول إلى الميكروفون لتسجيل الرسائل الصوتية.", + "voiceMessage": "رسالة صوتية" + }, + "toolbar": { + "attachFile": "إرفاق ملف", + "emojiGif": "إيموجي / GIF", + "more": "المزيد", + "poll": "تصويت", + "spoiler": "حرق أحداث", + "emoji": "إيموجي", + "stickers": "ملصقات" + }, + "submit": { + "posting": "جارٍ النشر...", + "uploadFailed": "فشل الرفع", + "uploadFailedBody": "تعذّر رفع الملف.", + "publishFailed": "فشل نشر الملاحظة.", + "posted": "تم النشر!", + "replyPublished": "تم نشر ردك.", + "quotePublished": "تم نشر اقتباسك.", + "notePublished": "تم نشر ملاحظتك." + }, + "destination": { + "label": "النشر إلى", + "ariaHelp": "ما الفرق بين المنشورات العالمية ومنشورات المجتمع؟", + "ariaTrigger": "وجهة النشر", + "global": "عالمي", + "globalExplainer": "منشور عادي يراه الجميع على Nostr. يمكن لأي شخص في أي مكان رؤيته.", + "community": "مجتمع بلدك", + "communityExplainer": "يظهر في الخلاصة المحلية لذلك البلد مع منشورات الجيران. الأنسب للتحديثات المرتبطة بالمجتمع.", + "chooseAnother": "اختيار بلد آخر…", + "searchPlaceholder": "ابحث عن دول...", + "noResults": "لم يتم العثور على دول.", + "isDefault": "{{name}} هي وجهتك الافتراضية", + "globalIsDefault": "عالمي هو وجهتك الافتراضية", + "thisIsDefault": "هذه هي وجهتك الافتراضية", + "setAsDefault": "تعيين كافتراضي", + "defaultUpdated": "تم تحديث الافتراضي", + "defaultUpdatedCountry": "ستذهب المنشورات الجديدة إلى {{name}} افتراضيًا.", + "defaultUpdatedGlobal": "ستكون المنشورات الجديدة عالمية افتراضيًا." + } + }, + "replyModal": { + "title": { + "newPoll": "تصويت جديد", + "newComment": "تعليق جديد", + "commentOnProfile": "التعليق على الملف الشخصي", + "replyToPost": "الرد على المنشور", + "quotePost": "اقتباس المنشور", + "newPost": "منشور جديد" + }, + "placeholder": { + "writeComment": "اكتب تعليقًا...", + "addComment": "أضف تعليقًا...", + "whatsHappening": "ماذا يحدث؟" + }, + "blueskyDisclaimer": "الأشخاص على Bluesky لا يمكنهم رؤيتك لأنهم في الواقع غير لامركزيين." } } diff --git a/src/locales/en.json b/src/locales/en.json index cf612309..e3ad6478 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -93,6 +93,93 @@ "linkCopied": "Link copied to clipboard" } }, + "compose": { + "placeholderDefault": "What's on your mind?", + "placeholderPoll": "Ask a question…", + "placeholderCountry": "What's happening in {{country}}?", + "placeholderCwReason": "Content warning reason (optional)", + "submitDefault": "Post!", + "preview": { + "edit": "Edit", + "previewMode": "Preview" + }, + "poll": { + "addOption": "Add option", + "optionLabel": "Option {{number}}", + "singleChoice": "Single choice", + "multipleChoice": "Multiple choice", + "backToPost": "Back to post", + "publishing": "Publishing...", + "publish": "Publish poll", + "published": "Poll published!", + "publishFailed": "Failed to publish poll." + }, + "voice": { + "cancel": "Cancel", + "send": "Send", + "sending": "Sending...", + "sentTitle": "Voice message sent!", + "sentBody": "Your voice message has been published.", + "sendFailed": "Failed to send voice message.", + "micDeniedTitle": "Microphone access denied", + "micDeniedBody": "Please allow microphone access to record voice messages.", + "voiceMessage": "Voice message" + }, + "toolbar": { + "attachFile": "Attach file", + "emojiGif": "Emoji / GIF", + "more": "More", + "poll": "Poll", + "spoiler": "Spoiler", + "emoji": "Emoji", + "stickers": "Stickers" + }, + "submit": { + "posting": "Posting...", + "uploadFailed": "Upload failed", + "uploadFailedBody": "Could not upload file.", + "publishFailed": "Failed to publish note.", + "posted": "Posted!", + "replyPublished": "Your reply has been published.", + "quotePublished": "Your quote has been published.", + "notePublished": "Your note has been published." + }, + "destination": { + "label": "Post to", + "ariaHelp": "What's the difference between global and community posts?", + "ariaTrigger": "Post destination", + "global": "Global", + "globalExplainer": "A regular post visible to everyone on Nostr. Anyone, anywhere can see it.", + "community": "Your country community", + "communityExplainer": "Shown in that country's local feed alongside posts from neighbors. Best for community-relevant updates.", + "chooseAnother": "Choose another country…", + "searchPlaceholder": "Search countries...", + "noResults": "No countries found.", + "isDefault": "{{name}} is your default", + "globalIsDefault": "Global is your default", + "thisIsDefault": "This is your default", + "setAsDefault": "Set as default", + "defaultUpdated": "Default updated", + "defaultUpdatedCountry": "New posts will go to {{name}} by default.", + "defaultUpdatedGlobal": "New posts will be global by default." + } + }, + "replyModal": { + "title": { + "newPoll": "New poll", + "newComment": "New comment", + "commentOnProfile": "Comment on profile", + "replyToPost": "Reply to post", + "quotePost": "Quote post", + "newPost": "New post" + }, + "placeholder": { + "writeComment": "Write a comment...", + "addComment": "Add a comment...", + "whatsHappening": "What's happening?" + }, + "blueskyDisclaimer": "People on Bluesky can't see you because they're not actually decentralized." + }, "forms": { "required": "Required", "recommended": "Recommended", diff --git a/src/locales/es.json b/src/locales/es.json index b1798ad2..3a5f568b 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -1301,5 +1301,92 @@ "copyFailed": "Error al copiar", "copyFailedDescription": "No se pudo acceder al portapapeles. Muestra la clave y cópiala manualmente." } + }, + "compose": { + "placeholderDefault": "¿En qué piensas?", + "placeholderPoll": "Haz una pregunta…", + "placeholderCountry": "¿Qué está pasando en {{country}}?", + "placeholderCwReason": "Motivo de la advertencia (opcional)", + "submitDefault": "¡Publicar!", + "preview": { + "edit": "Editar", + "previewMode": "Vista previa" + }, + "poll": { + "addOption": "Añadir opción", + "optionLabel": "Opción {{number}}", + "singleChoice": "Una opción", + "multipleChoice": "Varias opciones", + "backToPost": "Volver a la publicación", + "publishing": "Publicando...", + "publish": "Publicar encuesta", + "published": "¡Encuesta publicada!", + "publishFailed": "No se pudo publicar la encuesta." + }, + "voice": { + "cancel": "Cancelar", + "send": "Enviar", + "sending": "Enviando...", + "sentTitle": "¡Mensaje de voz enviado!", + "sentBody": "Tu mensaje de voz se publicó.", + "sendFailed": "No se pudo enviar el mensaje de voz.", + "micDeniedTitle": "Acceso al micrófono denegado", + "micDeniedBody": "Permite el acceso al micrófono para grabar mensajes de voz.", + "voiceMessage": "Mensaje de voz" + }, + "toolbar": { + "attachFile": "Adjuntar archivo", + "emojiGif": "Emoji / GIF", + "more": "Más", + "poll": "Encuesta", + "spoiler": "Spoiler", + "emoji": "Emoji", + "stickers": "Stickers" + }, + "submit": { + "posting": "Publicando...", + "uploadFailed": "Error al subir", + "uploadFailedBody": "No se pudo subir el archivo.", + "publishFailed": "No se pudo publicar la nota.", + "posted": "¡Publicado!", + "replyPublished": "Tu respuesta se publicó.", + "quotePublished": "Tu cita se publicó.", + "notePublished": "Tu nota se publicó." + }, + "destination": { + "label": "Publicar en", + "ariaHelp": "¿Cuál es la diferencia entre publicaciones globales y de comunidad?", + "ariaTrigger": "Destino de la publicación", + "global": "Global", + "globalExplainer": "Una publicación normal visible para todos en Nostr. Cualquiera puede verla.", + "community": "Comunidad de tu país", + "communityExplainer": "Se muestra en el feed local de ese país junto con publicaciones de vecinos. Ideal para temas comunitarios.", + "chooseAnother": "Elegir otro país…", + "searchPlaceholder": "Buscar países...", + "noResults": "No se encontraron países.", + "isDefault": "{{name}} es tu predeterminado", + "globalIsDefault": "Global es tu predeterminado", + "thisIsDefault": "Este es tu predeterminado", + "setAsDefault": "Establecer como predeterminado", + "defaultUpdated": "Predeterminado actualizado", + "defaultUpdatedCountry": "Las nuevas publicaciones irán a {{name}} por defecto.", + "defaultUpdatedGlobal": "Las nuevas publicaciones serán globales por defecto." + } + }, + "replyModal": { + "title": { + "newPoll": "Nueva encuesta", + "newComment": "Nuevo comentario", + "commentOnProfile": "Comentar en perfil", + "replyToPost": "Responder a la publicación", + "quotePost": "Citar publicación", + "newPost": "Nueva publicación" + }, + "placeholder": { + "writeComment": "Escribe un comentario...", + "addComment": "Agregar un comentario...", + "whatsHappening": "¿Qué está pasando?" + }, + "blueskyDisclaimer": "La gente en Bluesky no puede verte porque en realidad no están descentralizados." } } diff --git a/src/locales/fa.json b/src/locales/fa.json index da6a75cb..46f07372 100644 --- a/src/locales/fa.json +++ b/src/locales/fa.json @@ -1301,5 +1301,92 @@ "copyFailed": "کپی ناموفق بود", "copyFailedDescription": "دسترسی به کلیپ‌بورد ممکن نشد. کلید را نمایش دهید و به‌صورت دستی کپی کنید." } + }, + "compose": { + "placeholderDefault": "به چه فکر می‌کنی؟", + "placeholderPoll": "یک سؤال بپرس…", + "placeholderCountry": "در {{country}} چه می‌گذرد؟", + "placeholderCwReason": "دلیل هشدار محتوا (اختیاری)", + "submitDefault": "ارسال!", + "preview": { + "edit": "ویرایش", + "previewMode": "پیش‌نمایش" + }, + "poll": { + "addOption": "افزودن گزینه", + "optionLabel": "گزینه {{number}}", + "singleChoice": "تک‌گزینه‌ای", + "multipleChoice": "چندگزینه‌ای", + "backToPost": "بازگشت به پست", + "publishing": "در حال انتشار...", + "publish": "انتشار نظرسنجی", + "published": "نظرسنجی منتشر شد!", + "publishFailed": "انتشار نظرسنجی ناموفق بود." + }, + "voice": { + "cancel": "لغو", + "send": "ارسال", + "sending": "در حال ارسال...", + "sentTitle": "پیام صوتی ارسال شد!", + "sentBody": "پیام صوتی شما منتشر شد.", + "sendFailed": "ارسال پیام صوتی ناموفق بود.", + "micDeniedTitle": "دسترسی به میکروفون رد شد", + "micDeniedBody": "برای ضبط پیام صوتی به میکروفون اجازه دسترسی بدهید.", + "voiceMessage": "پیام صوتی" + }, + "toolbar": { + "attachFile": "پیوست فایل", + "emojiGif": "ایموجی / GIF", + "more": "بیشتر", + "poll": "نظرسنجی", + "spoiler": "اسپویلر", + "emoji": "ایموجی", + "stickers": "استیکر" + }, + "submit": { + "posting": "در حال انتشار...", + "uploadFailed": "آپلود ناموفق بود", + "uploadFailedBody": "نتوانست فایل را آپلود کند.", + "publishFailed": "انتشار یادداشت ناموفق بود.", + "posted": "منتشر شد!", + "replyPublished": "پاسخ شما منتشر شد.", + "quotePublished": "نقل قول شما منتشر شد.", + "notePublished": "یادداشت شما منتشر شد." + }, + "destination": { + "label": "ارسال به", + "ariaHelp": "تفاوت پست‌های جهانی و پست‌های انجمن کشور چیست؟", + "ariaTrigger": "مقصد پست", + "global": "جهانی", + "globalExplainer": "یک پست معمولی که برای همه در Nostr قابل مشاهده است. هرکسی، هرجا، می‌تواند آن را ببیند.", + "community": "انجمن کشور شما", + "communityExplainer": "در فید محلی آن کشور در کنار پست‌های همسایگان نمایش داده می‌شود. مناسب برای به‌روزرسانی‌های مرتبط با انجمن.", + "chooseAnother": "انتخاب کشور دیگر…", + "searchPlaceholder": "جست‌وجوی کشورها...", + "noResults": "کشوری یافت نشد.", + "isDefault": "{{name}} پیش‌فرض شماست", + "globalIsDefault": "جهانی پیش‌فرض شماست", + "thisIsDefault": "این پیش‌فرض شماست", + "setAsDefault": "تنظیم به‌عنوان پیش‌فرض", + "defaultUpdated": "پیش‌فرض به‌روزرسانی شد", + "defaultUpdatedCountry": "پست‌های جدید به‌طور پیش‌فرض به {{name}} می‌روند.", + "defaultUpdatedGlobal": "پست‌های جدید به‌طور پیش‌فرض جهانی خواهند بود." + } + }, + "replyModal": { + "title": { + "newPoll": "نظرسنجی جدید", + "newComment": "نظر جدید", + "commentOnProfile": "نظر روی نمایه", + "replyToPost": "پاسخ به پست", + "quotePost": "نقل پست", + "newPost": "پست جدید" + }, + "placeholder": { + "writeComment": "یک نظر بنویس...", + "addComment": "افزودن نظر...", + "whatsHappening": "چه خبر؟" + }, + "blueskyDisclaimer": "افراد در Bluesky نمی‌توانند شما را ببینند چون آن‌ها در واقع غیرمتمرکز نیستند." } } diff --git a/src/locales/km.json b/src/locales/km.json index c9ea955b..422bdddf 100644 --- a/src/locales/km.json +++ b/src/locales/km.json @@ -1301,5 +1301,92 @@ "copyFailed": "ការចម្លងបរាជ័យ", "copyFailedDescription": "មិនអាចចូលប្រើក្ដារតម្បៀតខ្ទាស់បានទេ។ បង្ហាញសោហើយចម្លងវាដោយដៃ។" } + }, + "compose": { + "placeholderDefault": "មានគំនិតអ្វី?", + "placeholderPoll": "សួរសំណួរ…", + "placeholderCountry": "មានរឿងអ្វីនៅ {{country}}?", + "placeholderCwReason": "មូលហេតុនៃការព្រមាន (ស្រេចចិត្ត)", + "submitDefault": "ប្រកាស!", + "preview": { + "edit": "កែសម្រួល", + "previewMode": "មើលជាមុន" + }, + "poll": { + "addOption": "បន្ថែមជម្រើស", + "optionLabel": "ជម្រើស {{number}}", + "singleChoice": "ជម្រើសតែមួយ", + "multipleChoice": "ជម្រើសច្រើន", + "backToPost": "ត្រឡប់ទៅប្រកាស", + "publishing": "កំពុងបោះពុម្ព...", + "publish": "បោះពុម្ពការស្ទង់មតិ", + "published": "បោះពុម្ពការស្ទង់មតិហើយ!", + "publishFailed": "មិនអាចបោះពុម្ពការស្ទង់មតិបានទេ។" + }, + "voice": { + "cancel": "បោះបង់", + "send": "ផ្ញើ", + "sending": "កំពុងផ្ញើ...", + "sentTitle": "បានផ្ញើសារសំឡេង!", + "sentBody": "សារសំឡេងរបស់អ្នកត្រូវបានបោះពុម្ព។", + "sendFailed": "មិនអាចផ្ញើសារសំឡេងបានទេ។", + "micDeniedTitle": "ការចូលប្រើមីក្រូហ្វូនត្រូវបានបដិសេធ", + "micDeniedBody": "សូមអនុញ្ញាតការចូលប្រើមីក្រូហ្វូនដើម្បីថតសារសំឡេង។", + "voiceMessage": "សារសំឡេង" + }, + "toolbar": { + "attachFile": "ភ្ជាប់ឯកសារ", + "emojiGif": "Emoji / GIF", + "more": "បន្ថែម", + "poll": "ស្ទង់មតិ", + "spoiler": "Spoiler", + "emoji": "Emoji", + "stickers": "ស្ទីកឃ័រ" + }, + "submit": { + "posting": "កំពុងបោះពុម្ព...", + "uploadFailed": "ការផ្ទុកឡើងបរាជ័យ", + "uploadFailedBody": "មិនអាចផ្ទុកឡើងឯកសារបានទេ។", + "publishFailed": "មិនអាចបោះពុម្ពកំណត់ត្រាបានទេ។", + "posted": "បានបោះពុម្ព!", + "replyPublished": "ការឆ្លើយតបរបស់អ្នកបានបោះពុម្ព។", + "quotePublished": "ការដកស្រង់របស់អ្នកបានបោះពុម្ព។", + "notePublished": "កំណត់ត្រារបស់អ្នកបានបោះពុម្ព។" + }, + "destination": { + "label": "បោះពុម្ពទៅ", + "ariaHelp": "តើមានភាពខុសគ្នាអ្វីខ្លះរវាងការប្រកាសសកល និងការប្រកាសសហគមន៍?", + "ariaTrigger": "ទីដៅប្រកាស", + "global": "សកល", + "globalExplainer": "ការប្រកាសធម្មតាដែលអាចមើលឃើញដោយអ្នកគ្រប់គ្នានៅលើ Nostr។ នរណាក៏អាចមើលឃើញដែរ។", + "community": "សហគមន៍ប្រទេសរបស់អ្នក", + "communityExplainer": "បង្ហាញនៅក្នុង Feed ក្នុងស្រុករបស់ប្រទេសនោះ ជាមួយការប្រកាសរបស់អ្នកជិតខាង។ ល្អបំផុតសម្រាប់ព័ត៌មានទាក់ទងសហគមន៍។", + "chooseAnother": "ជ្រើសប្រទេសផ្សេង…", + "searchPlaceholder": "ស្វែងរកប្រទេស...", + "noResults": "មិនបានរកឃើញប្រទេស។", + "isDefault": "{{name}} គឺជាលំនាំដើមរបស់អ្នក", + "globalIsDefault": "សកលគឺជាលំនាំដើមរបស់អ្នក", + "thisIsDefault": "នេះគឺជាលំនាំដើមរបស់អ្នក", + "setAsDefault": "កំណត់ជាលំនាំដើម", + "defaultUpdated": "បានធ្វើបច្ចុប្បន្នភាពលំនាំដើម", + "defaultUpdatedCountry": "ការប្រកាសថ្មីនឹងទៅ {{name}} តាមលំនាំដើម។", + "defaultUpdatedGlobal": "ការប្រកាសថ្មីនឹងជាសកលតាមលំនាំដើម។" + } + }, + "replyModal": { + "title": { + "newPoll": "ការស្ទង់មតិថ្មី", + "newComment": "មតិយោបល់ថ្មី", + "commentOnProfile": "មតិលើប្រវត្តិរូប", + "replyToPost": "ឆ្លើយតបទៅប្រកាស", + "quotePost": "ដកស្រង់ប្រកាស", + "newPost": "ប្រកាសថ្មី" + }, + "placeholder": { + "writeComment": "សរសេរមតិយោបល់...", + "addComment": "បន្ថែមមតិយោបល់...", + "whatsHappening": "មានរឿងអ្វី?" + }, + "blueskyDisclaimer": "មនុស្សនៅលើ Bluesky មិនអាចមើលឃើញអ្នកទេ ព្រោះតាមពិតពួកគេមិនមែនជាការវិមជ្ឈការទេ។" } } diff --git a/src/locales/ps.json b/src/locales/ps.json index 8ecf88ba..afd9e232 100644 --- a/src/locales/ps.json +++ b/src/locales/ps.json @@ -1301,5 +1301,92 @@ "copyFailed": "کاپي کول ناکام شو", "copyFailedDescription": "کلپ بورډ ته لاسرسی ونه شو. کیلي وښیئ او په لاسي ډول یې کاپي کړئ." } + }, + "compose": { + "placeholderDefault": "په څه فکر کوې؟", + "placeholderPoll": "یوه پوښتنه وکړئ…", + "placeholderCountry": "په {{country}} کې څه روان دي؟", + "placeholderCwReason": "د محتوا د خبرتیا دلیل (اختیاري)", + "submitDefault": "خپور کړئ!", + "preview": { + "edit": "سمول", + "previewMode": "مخکتنه" + }, + "poll": { + "addOption": "اختیار اضافه کړئ", + "optionLabel": "اختیار {{number}}", + "singleChoice": "یو غوراوی", + "multipleChoice": "ډېر غوراوي", + "backToPost": "پوسټ ته بیرته", + "publishing": "خپریږي...", + "publish": "د نظرپوښتنې خپرول", + "published": "نظرپوښتنه خپره شوه!", + "publishFailed": "د نظرپوښتنې خپرول ناکام شو." + }, + "voice": { + "cancel": "لغوه کول", + "send": "ولېږئ", + "sending": "لېږل کیږي...", + "sentTitle": "صوتي پیغام ولېږل شو!", + "sentBody": "ستاسو صوتي پیغام خپور شو.", + "sendFailed": "د صوتي پیغام لېږل ناکام شو.", + "micDeniedTitle": "د مایکروفون لاسرسی ردیږي", + "micDeniedBody": "د صوتي پیغامونو د ثبتولو لپاره مهرباني وکړئ مایکروفون ته اجازه ورکړئ.", + "voiceMessage": "صوتي پیغام" + }, + "toolbar": { + "attachFile": "فایل ضمیمه کړئ", + "emojiGif": "اموجي / GIF", + "more": "نور", + "poll": "نظرپوښتنه", + "spoiler": "سپایلر", + "emoji": "اموجي", + "stickers": "سټیکرونه" + }, + "submit": { + "posting": "خپریږي...", + "uploadFailed": "اپلوډ ناکام شو", + "uploadFailedBody": "د فایل اپلوډ ونه شو.", + "publishFailed": "د یادښت خپرول ناکام شو.", + "posted": "خپور شو!", + "replyPublished": "ستاسو ځواب خپور شو.", + "quotePublished": "ستاسو نقل خپور شو.", + "notePublished": "ستاسو یادښت خپور شو." + }, + "destination": { + "label": "خپرول", + "ariaHelp": "د نړیوالو او د هیواد ټولنیزو پوسټونو ترمنځ څه توپیر دی؟", + "ariaTrigger": "د خپرولو هدف", + "global": "نړیوال", + "globalExplainer": "یو معمولي پوسټ چې په Nostr کې هر چا ته لیدلی شي. هر څوک، هر چیرته، یې لیدلی شي.", + "community": "ستاسو د هیواد ټولنه", + "communityExplainer": "د هغه هیواد په محلي فیډ کې د ګاونډیانو د پوسټونو سره ښودل کیږي. د ټولنیزو اړوندو تازه معلوماتو لپاره غوره.", + "chooseAnother": "بل هیواد غوره کړئ…", + "searchPlaceholder": "هیوادونه ولټوئ...", + "noResults": "هیڅ هیواد ونه موندل شو.", + "isDefault": "{{name}} ستاسو ډیفالټ دی", + "globalIsDefault": "نړیوال ستاسو ډیفالټ دی", + "thisIsDefault": "دا ستاسو ډیفالټ دی", + "setAsDefault": "د ډیفالټ په توګه وټاکئ", + "defaultUpdated": "ډیفالټ تازه شو", + "defaultUpdatedCountry": "نوي پوسټونه به په ډیفالټ ډول {{name}} ته ولاړ شي.", + "defaultUpdatedGlobal": "نوي پوسټونه به په ډیفالټ ډول نړیوال وي." + } + }, + "replyModal": { + "title": { + "newPoll": "نوې نظرپوښتنه", + "newComment": "نوی تبصره", + "commentOnProfile": "په پروفایل تبصره", + "replyToPost": "پوسټ ته ځواب", + "quotePost": "د پوسټ نقل", + "newPost": "نوی پوسټ" + }, + "placeholder": { + "writeComment": "تبصره ولیکئ...", + "addComment": "تبصره اضافه کړئ...", + "whatsHappening": "څه روان دي؟" + }, + "blueskyDisclaimer": "په Bluesky کې خلک تاسو نه شي لیدلی ځکه چې هغوی واقعیا غیرمرکزي نه دي." } } diff --git a/src/locales/sn.json b/src/locales/sn.json index 0657e550..22c71713 100644 --- a/src/locales/sn.json +++ b/src/locales/sn.json @@ -1301,5 +1301,92 @@ "copyFailed": "Kukopa kwakundikana", "copyFailedDescription": "Hazvina kukwanisika kuwana clipboard. Ratidza kiyi wokopa nemaoko." } + }, + "compose": { + "placeholderDefault": "Uri kufungei?", + "placeholderPoll": "Bvunza mubvunzo…", + "placeholderCountry": "Chii chiri kuitika mu{{country}}?", + "placeholderCwReason": "Chikonzero cheyambiro yezvirimo (zvinosarudzwa)", + "submitDefault": "Tumira!", + "preview": { + "edit": "Gadzirisa", + "previewMode": "Tarisa" + }, + "poll": { + "addOption": "Wedzera sarudzo", + "optionLabel": "Sarudzo {{number}}", + "singleChoice": "Sarudzo imwe", + "multipleChoice": "Zvisarudzo zvakawanda", + "backToPost": "Dzokera kuchinyorwa", + "publishing": "Kunyorwa...", + "publish": "Tumira nzvimbo yokuvhota", + "published": "Nzvimbo yokuvhota yatumirwa!", + "publishFailed": "Hazvina kubudirira kutumira nzvimbo yokuvhota." + }, + "voice": { + "cancel": "Kanzura", + "send": "Tumira", + "sending": "Kutumira...", + "sentTitle": "Meseji yezwi yatumirwa!", + "sentBody": "Meseji yako yezwi yatumirwa.", + "sendFailed": "Hazvina kubudirira kutumira meseji yezwi.", + "micDeniedTitle": "Mvumo yemicrophone yarambidzwa", + "micDeniedBody": "Bvumira microphone kuti urekode meseji dzezwi.", + "voiceMessage": "Meseji yezwi" + }, + "toolbar": { + "attachFile": "Batanidza faira", + "emojiGif": "Emoji / GIF", + "more": "Zvimwe", + "poll": "Kuvhota", + "spoiler": "Spoiler", + "emoji": "Emoji", + "stickers": "Stickers" + }, + "submit": { + "posting": "Kunyorwa...", + "uploadFailed": "Kuisa kwakundikana", + "uploadFailedBody": "Hazvina kubudirira kuisa faira.", + "publishFailed": "Hazvina kubudirira kutumira chinyorwa.", + "posted": "Yatumirwa!", + "replyPublished": "Mhinduro yako yatumirwa.", + "quotePublished": "Kunokora kwako kwatumirwa.", + "notePublished": "Chinyorwa chako chatumirwa." + }, + "destination": { + "label": "Tumira ku", + "ariaHelp": "Pane musiyano upi pakati pezvinyorwa zvepasi rose nezvenharaunda?", + "ariaTrigger": "Kwakutumira", + "global": "Pasi rose", + "globalExplainer": "Chinyorwa chenguva dzose chinooneka nemunhu wose paNostr. Ani naani, kupi nekupi, anogona kuchiona.", + "community": "Nharaunda yenyika yako", + "communityExplainer": "Chinoratidzwa muFeed yenyika iyoyo pamwe nezvinyorwa zvevavakidzani. Chakanaka kwazvo kunyaya dzenharaunda.", + "chooseAnother": "Sarudza imwe nyika…", + "searchPlaceholder": "Tsvaga nyika...", + "noResults": "Hapana nyika yakawanikwa.", + "isDefault": "{{name}} ndiyo yako default", + "globalIsDefault": "Pasi rose ndiyo yako default", + "thisIsDefault": "Iyi ndiyo yako default", + "setAsDefault": "Sarudza sezvinopiwa", + "defaultUpdated": "Default yagadziriswa", + "defaultUpdatedCountry": "Zvinyorwa zvitsva zvichaenda ku{{name}} sezvinopiwa.", + "defaultUpdatedGlobal": "Zvinyorwa zvitsva zvichange zviri zvepasi rose sezvinopiwa." + } + }, + "replyModal": { + "title": { + "newPoll": "Nzvimbo itsva yokuvhota", + "newComment": "Tsinhiro itsva", + "commentOnProfile": "Tsinhira papfungidziro", + "replyToPost": "Pindura chinyorwa", + "quotePost": "Nokora chinyorwa", + "newPost": "Chinyorwa chitsva" + }, + "placeholder": { + "writeComment": "Nyora tsinhiro...", + "addComment": "Wedzera tsinhiro...", + "whatsHappening": "Chii chiri kuitika?" + }, + "blueskyDisclaimer": "Vanhu paBluesky havakukuoni nokuti chaizvoizvo havasi vakapararira." } } diff --git a/src/locales/zh.json b/src/locales/zh.json index 26fcf8d4..6c18d11b 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -1301,5 +1301,92 @@ "copyFailed": "复制失败", "copyFailedDescription": "无法访问剪贴板。请显示密钥后手动复制。" } + }, + "compose": { + "placeholderDefault": "在想什么?", + "placeholderPoll": "提个问题…", + "placeholderCountry": "{{country}} 发生了什么?", + "placeholderCwReason": "内容警告原因(可选)", + "submitDefault": "发布!", + "preview": { + "edit": "编辑", + "previewMode": "预览" + }, + "poll": { + "addOption": "添加选项", + "optionLabel": "选项 {{number}}", + "singleChoice": "单选", + "multipleChoice": "多选", + "backToPost": "返回帖子", + "publishing": "发布中...", + "publish": "发布投票", + "published": "投票已发布!", + "publishFailed": "投票发布失败。" + }, + "voice": { + "cancel": "取消", + "send": "发送", + "sending": "发送中...", + "sentTitle": "语音消息已发送!", + "sentBody": "你的语音消息已发布。", + "sendFailed": "发送语音消息失败。", + "micDeniedTitle": "麦克风访问被拒绝", + "micDeniedBody": "请允许麦克风访问以录制语音消息。", + "voiceMessage": "语音消息" + }, + "toolbar": { + "attachFile": "附加文件", + "emojiGif": "表情 / GIF", + "more": "更多", + "poll": "投票", + "spoiler": "剧透", + "emoji": "表情", + "stickers": "贴纸" + }, + "submit": { + "posting": "发布中...", + "uploadFailed": "上传失败", + "uploadFailedBody": "无法上传文件。", + "publishFailed": "无法发布笔记。", + "posted": "已发布!", + "replyPublished": "你的回复已发布。", + "quotePublished": "你的引用已发布。", + "notePublished": "你的笔记已发布。" + }, + "destination": { + "label": "发布到", + "ariaHelp": "全球帖子和社区帖子有什么区别?", + "ariaTrigger": "发布目标", + "global": "全球", + "globalExplainer": "Nostr 上所有人都能看到的普通帖子。任何人都能看到。", + "community": "你的国家社区", + "communityExplainer": "在该国家的本地 Feed 中与邻居的帖子一起显示。适合社区相关的更新。", + "chooseAnother": "选择其他国家…", + "searchPlaceholder": "搜索国家...", + "noResults": "未找到国家。", + "isDefault": "{{name}} 是你的默认", + "globalIsDefault": "全球是你的默认", + "thisIsDefault": "这是你的默认", + "setAsDefault": "设为默认", + "defaultUpdated": "默认已更新", + "defaultUpdatedCountry": "新帖子将默认发布到 {{name}}。", + "defaultUpdatedGlobal": "新帖子将默认为全球。" + } + }, + "replyModal": { + "title": { + "newPoll": "新投票", + "newComment": "新评论", + "commentOnProfile": "评论资料", + "replyToPost": "回复帖子", + "quotePost": "引用帖子", + "newPost": "新帖子" + }, + "placeholder": { + "writeComment": "写一条评论...", + "addComment": "添加评论...", + "whatsHappening": "有什么新鲜事?" + }, + "blueskyDisclaimer": "Bluesky 上的人看不到你,因为它们实际上不是去中心化的。" } }