i18n: translate ComposeBox + ReplyComposeModal

Adds the compose.* namespace covering ComposeBox: placeholders
(default, poll, country-scoped, content warning), preview / edit toggle,
poll mode (Add option, Option N, Single/Multiple choice, Back to post,
Publish poll, success/failure toasts), voice recording (Cancel, Send,
Sending, mic-denied toast, voice-message tooltip), toolbar
(Attach file, Emoji/GIF, More, Poll, Spoiler, Emoji, Stickers tabs),
submit (Posting / Posted toasts, upload-failed / publish-failed),
and destination dropdown (Post to label, Global / community
explainer popover, Choose another country picker, search placeholder,
empty state, Set as default, default-updated toasts).

Also adds replyModal.* for ReplyComposeModal — the six title fallbacks
(New poll, New comment, Comment on profile, Reply to post, Quote post,
New post), three placeholder fallbacks, and the Bluesky disclaimer.

ComposeBox's hardcoded default placeholder ('What's on your mind?') and
submitLabel ('Post!') props moved from prop defaults to t() fallbacks
inside the component so existing call sites can keep passing translated
strings unchanged. Renamed an inner .map((t) => …) variable in the poll
type/duration row to .map((pt) => …) since t shadowed the i18next t.
Added rtl:rotate-180 to the 'Back to post' chevron since it visually
points left/back.

ar / es / zh / fa / ps / km / sn translations drafted inline; km, sn,
ps, fa still pending native-speaker review.
This commit is contained in:
mkfain
2026-05-23 19:16:53 -05:00
parent fe4162bd00
commit 850f35c29d
10 changed files with 778 additions and 64 deletions
+63 -59
View File
@@ -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<HTMLTextAreaElement>) => {
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')}
</button>
<button
onClick={() => setInternalPreviewMode(true)}
@@ -1252,7 +1256,7 @@ export function ComposeBox({
: "text-muted-foreground hover:text-foreground"
)}
>
Preview
{t('compose.preview.previewMode')}
</button>
</div>
</div>
@@ -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"
>
<ChevronLeft className="size-3.5" />
Back to post
<ChevronLeft className="size-3.5 rtl:rotate-180" />
{t('compose.poll.backToPost')}
</button>
)}
@@ -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"
>
<Plus className="size-3" />
Add option
{t('compose.poll.addOption')}
</button>
)}
</div>
{/* Settings row — pill toggles */}
<div className="flex flex-wrap gap-2 pt-0.5">
{(['singlechoice', 'multiplechoice'] as const).map((t) => (
{(['singlechoice', 'multiplechoice'] as const).map((pt) => (
<button
key={t}
key={pt}
type="button"
onClick={() => setPollType(t)}
onClick={() => setPollType(pt)}
className={cn(
'text-xs px-2.5 py-1 rounded-full border transition-colors',
pollType === t
pollType === pt
? 'border-primary bg-primary/10 text-primary font-medium'
: 'border-border text-muted-foreground hover:text-foreground hover:border-foreground/30',
)}
>
{t === 'singlechoice' ? 'Single choice' : 'Multiple choice'}
{pt === 'singlechoice' ? t('compose.poll.singleChoice') : t('compose.poll.multipleChoice')}
</button>
))}
<div className="w-px bg-border self-stretch mx-0.5" />
@@ -1437,7 +1441,7 @@ export function ComposeBox({
<Input
value={cwText}
onChange={(e) => 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"
/>
<button
@@ -1478,13 +1482,13 @@ export function ComposeBox({
{canChooseDestination && isExpanded && (
<div className="mt-2 flex items-center justify-end gap-2">
<span className="text-xs font-medium text-muted-foreground">
Post to
{t('compose.destination.label')}
</span>
<Popover>
<PopoverTrigger asChild>
<button
type="button"
aria-label="What's the difference between global and community posts?"
aria-label={t('compose.destination.ariaHelp')}
className={cn(
'inline-flex items-center justify-center size-5 rounded-full shrink-0',
'text-muted-foreground/70 hover:text-foreground hover:bg-muted/60',
@@ -1513,9 +1517,9 @@ export function ComposeBox({
<div className="flex gap-3">
<span className="text-2xl leading-none shrink-0" aria-hidden="true">🌍</span>
<div className="flex-1 min-w-0">
<p className="text-sm font-semibold">Global</p>
<p className="text-sm font-semibold">{t('compose.destination.global')}</p>
<p className="text-xs text-muted-foreground mt-0.5">
A regular post visible to everyone on Nostr. Anyone, anywhere can see it.
{t('compose.destination.globalExplainer')}
</p>
</div>
</div>
@@ -1524,9 +1528,9 @@ export function ComposeBox({
{exampleFlag ?? '🌐'}
</span>
<div className="flex-1 min-w-0">
<p className="text-sm font-semibold">Your country community</p>
<p className="text-sm font-semibold">{t('compose.destination.community')}</p>
<p className="text-xs text-muted-foreground mt-0.5">
Shown in that country's local feed alongside posts from neighbors. Best for community-relevant updates.
{t('compose.destination.communityExplainer')}
</p>
</div>
</div>
@@ -1537,7 +1541,7 @@ export function ComposeBox({
</Popover>
<DropdownMenu>
<DropdownMenuTrigger
aria-label="Post destination"
aria-label={t('compose.destination.ariaTrigger')}
className={cn(
'inline-flex items-center justify-center h-8 w-auto gap-1.5 px-2.5 py-1 text-base leading-none',
'bg-muted/50 hover:bg-muted shadow-none',
@@ -1559,7 +1563,7 @@ export function ComposeBox({
>
<span className="inline-flex items-center gap-2 flex-1">
<span aria-hidden="true">🌍</span>
<span>Global</span>
<span>{t('compose.destination.global')}</span>
</span>
{destination === 'world' && (
<Check className="size-4 text-primary" aria-hidden />
@@ -1610,15 +1614,15 @@ export function ComposeBox({
className="cursor-pointer text-sm"
>
<Globe className="size-4 mr-2 text-muted-foreground" aria-hidden />
Choose another country
{t('compose.destination.chooseAnother')}
</DropdownMenuItem>
<DropdownMenuSeparator />
{destination === defaultPostCountry ? (
<div className="px-2 py-1.5 text-xs text-muted-foreground">
{(() => {
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');
})()}
</div>
) : (
@@ -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')}
</DropdownMenuItem>
)}
</DropdownMenuContent>
@@ -1651,9 +1655,9 @@ export function ComposeBox({
open={countryPickerOpen}
onOpenChange={setCountryPickerOpen}
>
<CommandInput placeholder="Search countries..." />
<CommandInput placeholder={t('compose.destination.searchPlaceholder')} />
<CommandList>
<CommandEmpty>No countries found.</CommandEmpty>
<CommandEmpty>{t('compose.destination.noResults')}</CommandEmpty>
<CommandGroup>
<CommandItem
value="Global 🌍"
@@ -1663,7 +1667,7 @@ export function ComposeBox({
}}
>
<span aria-hidden="true" className="mr-2">🌍</span>
<span>Global</span>
<span>{t('compose.destination.global')}</span>
{destination === 'world' && (
<Check className="ml-auto size-4 text-primary" aria-hidden />
)}
@@ -1732,7 +1736,7 @@ export function ComposeBox({
<X className="size-[18px]" />
</button>
</TooltipTrigger>
<TooltipContent>Cancel</TooltipContent>
<TooltipContent>{t('compose.voice.cancel')}</TooltipContent>
</Tooltip>
{/* Stop & send button */}
@@ -1747,7 +1751,7 @@ export function ComposeBox({
) : (
<Square className="size-3.5 mr-1.5" fill="currentColor" />
)}
{isPublishingVoice ? 'Sending...' : 'Send'}
{isPublishingVoice ? t('compose.voice.sending') : t('compose.voice.send')}
</Button>
</div>
) : (
@@ -1767,7 +1771,7 @@ export function ComposeBox({
{isUploading ? <Loader2 className="size-[18px] animate-spin" /> : <Paperclip className="size-[18px]" />}
</button>
</TooltipTrigger>
<TooltipContent>Attach file</TooltipContent>
<TooltipContent>{t('compose.toolbar.attachFile')}</TooltipContent>
</Tooltip>
<input
@@ -1798,7 +1802,7 @@ export function ComposeBox({
<Mic className="size-[18px]" />
</button>
</TooltipTrigger>
<TooltipContent>Voice message</TooltipContent>
<TooltipContent>{t('compose.voice.voiceMessage')}</TooltipContent>
</Tooltip>
)}
@@ -1818,7 +1822,7 @@ export function ComposeBox({
<Smile className="size-[18px]" />
</button>
</TooltipTrigger>
{!pickerOpen && <TooltipContent>Emoji / GIF</TooltipContent>}
{!pickerOpen && <TooltipContent>{t('compose.toolbar.emojiGif')}</TooltipContent>}
</Tooltip>
{/* Overflow: Poll + CW */}
@@ -1840,7 +1844,7 @@ export function ComposeBox({
</button>
</PopoverTrigger>
</TooltipTrigger>
{!trayOpen && <TooltipContent>More</TooltipContent>}
{!trayOpen && <TooltipContent>{t('compose.toolbar.more')}</TooltipContent>}
</Tooltip>
<PopoverContent side="top" align="start" sideOffset={6} className="w-44 p-1.5 rounded-xl border-border shadow-lg">
<div className="flex flex-col gap-0.5">
@@ -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')}
>
<BarChart3 className="size-4" /><span className="font-medium">Poll</span>
<BarChart3 className="size-4" /><span className="font-medium">{t('compose.toolbar.poll')}</span>
</button>
)}
<button
@@ -1861,7 +1865,7 @@ export function ComposeBox({
onClick={() => { setCwEnabled((v) => !v); setTrayOpen(false); expand(); }}
className={cn('flex items-center gap-2.5 w-full px-3 py-2 rounded-lg text-sm transition-colors', cwEnabled ? 'text-amber-500 bg-amber-500/10' : 'text-muted-foreground hover:text-foreground hover:bg-secondary/60')}
>
<AlertTriangle className="size-4" /><span className="font-medium">Spoiler</span>
<AlertTriangle className="size-4" /><span className="font-medium">{t('compose.toolbar.spoiler')}</span>
</button>
</div>
</PopoverContent>
@@ -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')}
</Button>
) : (
<Button
@@ -1902,7 +1906,7 @@ export function ComposeBox({
className="rounded-full px-5 font-bold text-white"
size="sm"
>
{isPending || isCommentPending ? 'Posting...' : submitLabel}
{isPending || isCommentPending ? t('compose.submit.posting') : effectiveSubmitLabel}
</Button>
)}
</div>
@@ -1927,7 +1931,7 @@ export function ComposeBox({
)}
>
<Smile className="size-3.5" />
Emoji
{t('compose.toolbar.emoji')}
</button>
<button
type="button"
@@ -1957,7 +1961,7 @@ export function ComposeBox({
)}
>
<Sticker className="size-3.5" />
Stickers
{t('compose.toolbar.stickers')}
</button>
)}
</div>
+19 -5
View File
@@ -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<HTMLElement | undefined>(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')}
</button>
<button
onClick={() => setPreviewMode(true)}
@@ -106,7 +120,7 @@ export function ReplyComposeModal({ event, quotedEvent, open, onOpenChange, onSu
: "text-muted-foreground hover:text-foreground"
)}
>
Preview
{t('compose.preview.previewMode')}
</button>
</div>
)}
@@ -142,7 +156,7 @@ export function ReplyComposeModal({ event, quotedEvent, open, onOpenChange, onSu
<div className="mx-4 mb-2 rounded-lg border border-amber-500/30 bg-amber-500/5 px-3 py-2 flex items-start gap-2 shrink-0">
<span className="text-sm leading-relaxed shrink-0" aria-hidden>&#x26A0;&#xFE0F;</span>
<p className="text-xs text-amber-700 dark:text-amber-400 leading-relaxed">
People on Bluesky can&apos;t see you because they&apos;re not actually decentralized.
{t('replyModal.blueskyDisclaimer')}
</p>
</div>
)}
+87
View File
@@ -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 لا يمكنهم رؤيتك لأنهم في الواقع غير لامركزيين."
}
}
+87
View File
@@ -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",
+87
View File
@@ -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."
}
}
+87
View File
@@ -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 نمی‌توانند شما را ببینند چون آن‌ها در واقع غیرمتمرکز نیستند."
}
}
+87
View File
@@ -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 មិនអាចមើលឃើញអ្នកទេ ព្រោះតាមពិតពួកគេមិនមែនជាការវិមជ្ឈការទេ។"
}
}
+87
View File
@@ -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 کې خلک تاسو نه شي لیدلی ځکه چې هغوی واقعیا غیرمرکزي نه دي."
}
}
+87
View File
@@ -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."
}
}
+87
View File
@@ -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 上的人看不到你,因为它们实际上不是去中心化的。"
}
}