feat: add Persian language support

This commit is contained in:
codytseng
2025-07-20 21:47:10 +08:00
parent 78725c1d14
commit 6d5d4d36c1
3 changed files with 309 additions and 0 deletions

View File

@@ -6,6 +6,7 @@ import ar from './locales/ar'
import de from './locales/de'
import en from './locales/en'
import es from './locales/es'
import fa from './locales/fa'
import fr from './locales/fr'
import it from './locales/it'
import ja from './locales/ja'
@@ -22,6 +23,7 @@ const languages = {
de: { resource: de, name: 'Deutsch' },
en: { resource: en, name: 'English' },
es: { resource: es, name: 'Español' },
fa: { resource: fa, name: 'فارسی' },
fr: { resource: fr, name: 'Français' },
it: { resource: it, name: 'Italiano' },
ja: { resource: ja, name: '日本語' },
@@ -71,6 +73,8 @@ i18n.services.formatter?.add('date', (timestamp, lng) => {
case 'de':
case 'ru':
return dayjs(timestamp).format('DD.MM.YYYY')
case 'fa':
return dayjs(timestamp).format('YYYY/MM/DD')
case 'it':
case 'es':
case 'fr':

300
src/i18n/locales/fa.ts Normal file
View File

@@ -0,0 +1,300 @@
export default {
translation: {
'Welcome! 🥳': 'خوش آمدید! 🥳',
About: 'درباره',
'New Note': 'یادداشت جدید',
Post: 'ارسال',
Home: 'خانه',
'Relay settings': 'تنظیمات رله',
Settings: 'تنظیمات',
SidebarRelays: 'رله‌ها',
Refresh: 'بازخوانی',
Profile: 'پروفایل',
Logout: 'خروج',
Following: 'دنبال می‌کنم',
followings: 'دنبال شونده‌ها',
reposted: 'بازنشر شده',
'just now': 'همین الان',
'n minutes ago': '{{n}} دقیقه پیش',
'n m': '{{n}}د',
'n hours ago': '{{n}} ساعت پیش',
'n h': '{{n}}س',
'n days ago': '{{n}} روز پیش',
'n d': '{{n}}ر',
date: '{{timestamp, date}}',
Follow: 'دنبال کردن',
Unfollow: 'لغو دنبال کردن',
'Follow failed': 'دنبال کردن ناموفق',
'Unfollow failed': 'لغو دنبال کردن ناموفق',
'show new notes': 'نمایش یادداشت‌های جدید',
'loading...': 'در حال بارگذاری...',
'no more notes': 'یادداشت بیشتری وجود ندارد',
'reply to': 'پاسخ به',
reply: 'پاسخ',
Reply: 'پاسخ',
'load more older replies': 'بارگذاری پاسخ‌های قدیمی‌تر',
'Write something...': 'چیزی بنویسید...',
Cancel: 'لغو',
Mentions: 'اشاره‌ها',
'Failed to post': 'ارسال ناموفق',
'Post successful': 'ارسال موفق',
'Your post has been published': 'پست شما منتشر شد',
Repost: 'بازنشر',
Quote: 'نقل قول',
'Copy event ID': 'کپی شناسه رویداد',
'Copy user ID': 'کپی شناسه کاربر',
'View raw event': 'نمایش رویداد خام',
Like: 'پسند',
'switch to light theme': 'تغییر به تم روشن',
'switch to dark theme': 'تغییر به تم تاریک',
'switch to system theme': 'تغییر به تم سیستم',
Note: 'یادداشت',
note: 'یادداشت',
"username's following": 'دنبال شونده‌های {{username}}',
"username's used relays": 'رله‌های استفاده شده {{username}}',
"username's muted": 'بی‌صدا شده‌های {{username}}',
Login: 'ورود',
'Follows you': 'شما را دنبال می‌کند',
'Relay Settings': 'تنظیمات رله',
'Relay set name': 'نام مجموعه رله',
'Add a new relay set': 'افزودن مجموعه رله جدید',
Add: 'افزودن',
'n relays': '{{n}} رله',
Rename: 'تغییر نام',
'Copy share link': 'کپی لینک اشتراک',
Delete: 'حذف',
'Relay already exists': 'رله از قبل موجود است',
'invalid relay URL': 'آدرس رله نامعتبر',
'Add a new relay': 'افزودن رله جدید',
back: 'بازگشت',
'Lost in the void': 'گم شده در خلاء',
'Carry me home': 'مرا به خانه ببر',
'no replies': 'پاسخی وجود ندارد',
'Reply to': 'پاسخ به',
Search: 'جستجو',
'The relays you are connected to do not support search':
'رله‌هایی که متصل هستید از جستجو پشتیبانی نمی‌کنند',
'Show more...': 'نمایش بیشتر...',
'All users': 'همه کاربران',
'Display replies': 'نمایش پاسخ‌ها',
Notes: 'یادداشت‌ها',
Replies: 'پاسخ‌ها',
Notifications: 'اعلان‌ها',
'no more notifications': 'اعلان بیشتری وجود ندارد',
'Using private key login is insecure. It is recommended to use a browser extension for login, such as alby, nostr-keyx or nos2x. If you must use a private key, please set a password for encryption at minimum.':
'استفاده از کلید خصوصی برای ورود ناامن است. توصیه می‌شود از افزونه مرورگر برای ورود استفاده کنید، مانند alby، nostr-keyx یا nos2x. اگر مجبور به استفاده از کلید خصوصی هستید، حداقل یک رمز عبور برای رمزگذاری تنظیم کنید.',
'Login with Browser Extension': 'ورود با افزونه مرورگر',
'Login with Bunker': 'ورود با Bunker',
'Login with Private Key': 'ورود با کلید خصوصی',
'reload notes': 'بازخوانی یادداشت‌ها',
'Logged in Accounts': 'حساب‌های وارد شده',
'Add an Account': 'افزودن حساب',
'More options': 'گزینه‌های بیشتر',
'Add client tag': 'افزودن برچسب کلاینت',
'Show others this was sent via Jumble': 'به دیگران نشان دهید که از طریق Jumble ارسال شده',
'Are you sure you want to logout?': 'آیا مطمئن هستید که می‌خواهید خارج شوید؟',
'relay sets': 'مجموعه‌های رله',
edit: 'ویرایش',
Languages: 'زبان‌ها',
Theme: 'تم',
System: 'سیستم',
Light: 'روشن',
Dark: 'تاریک',
Temporary: 'موقت',
'Choose a relay set': 'یک مجموعه رله انتخاب کنید',
'Switch account': 'تغییر حساب',
Pictures: 'تصاویر',
'Picture note': 'یادداشت تصویری',
'A special note for picture-first clients like Olas':
'یادداشت ویژه برای کلاینت‌های تصویر محور مانند Olas',
'Picture note requires images': 'یادداشت تصویری نیاز به تصاویر دارد',
Relays: 'رله‌ها',
image: 'تصویر',
'R & W': 'خواندن و نوشتن',
Read: 'خواندن',
Write: 'نوشتن',
'Pull relay sets': 'کشیدن مجموعه‌های رله',
'Select the relay sets you want to pull': 'مجموعه‌های رله‌ای که می‌خواهید بکشید انتخاب کنید',
'No relay sets found': 'مجموعه رله‌ای یافت نشد',
'Pull n relay sets': 'کشیدن {{n}} مجموعه رله',
Pull: 'کشیدن',
'Select all': 'انتخاب همه',
'Relay Sets': 'مجموعه‌های رله',
'Read & Write Relays': 'رله‌های خواندن و نوشتن',
'read relays description':
'رله‌های خواندن برای جستجوی رویدادهای مربوط به شما استفاده می‌شوند. سایر کاربران رویدادهایی که می‌خواهند شما ببینید را به رله‌های خواندن شما منتشر می‌کنند.',
'write relays description':
'رله‌های نوشتن برای انتشار رویدادهای شما استفاده می‌شوند. سایر کاربران رویدادهای شما را از رله‌های نوشتن شما جستجو می‌کنند.',
'read & write relays notice':
'تعداد سرورهای خواندن و نوشتن ترجیحاً باید بین ۲ تا ۴ نگه داشته شود.',
"Don't have an account yet?": 'هنوز حساب کاربری ندارید؟',
'or simply generate a private key': 'یا به سادگی یک کلید خصوصی تولید کنید',
'This is a private key. Do not share it with anyone. Keep it safe and secure. You will not be able to recover it if you lose it.':
'این یک کلید خصوصی است. آن را با هیچ کس به اشتراک نگذارید. آن را ایمن و محفوظ نگه دارید. اگر آن را گم کنید نمی‌توانید بازیابی کنید.',
Edit: 'ویرایش',
Save: 'ذخیره',
'Display Name': 'نام نمایشی',
Bio: 'بیوگرافی',
'Nostr Address (NIP-05)': 'آدرس Nostr (NIP-05)',
'Invalid NIP-05 address': 'آدرس NIP-05 نامعتبر',
'Copy private key': 'کپی کلید خصوصی',
'Enter the password to decrypt your ncryptsec':
'رمز عبور را برای رمزگشایی ncryptsec خود وارد کنید',
Back: 'بازگشت',
'optional: encrypt nsec': 'اختیاری: رمزگذاری nsec',
password: 'رمز عبور',
'Sign up': 'ثبت نام',
'Save to': 'ذخیره در',
'Enter a name for the new relay set': 'نامی برای مجموعه رله جدید وارد کنید',
'Save to a new relay set': 'ذخیره در مجموعه رله جدید',
Mute: 'بی‌صدا',
Muted: 'بی‌صدا شده',
Unmute: 'لغو بی‌صدا',
'Unmute user': 'لغو بی‌صدا کردن کاربر',
'Append n relays': 'افزودن {{n}} رله',
Append: 'افزودن',
'Select relays to append': 'رله‌ها را برای افزودن انتخاب کنید',
'calculating...': 'در حال محاسبه...',
'Calculate optimal read relays': 'محاسبه رله‌های خواندن بهینه',
'Login to set': 'برای تنظیم وارد شوید',
'Please login to view following feed': 'لطفاً برای مشاهده فید دنبال شونده‌ها وارد شوید',
'Send only to r': 'فقط به {{r}} ارسال شود',
'Send only to these relays': 'فقط به این رله‌ها ارسال شود',
Explore: 'کاوش',
'Search relays': 'جستجو رله‌ها',
relayInfoBadgeAuth: 'احراز هویت',
relayInfoBadgeSearch: 'جستجو',
relayInfoBadgePayment: 'پرداخت',
Operator: 'اپراتور',
Contact: 'تماس',
Software: 'نرم‌افزار',
Version: 'نسخه',
'Random Relays': 'رله‌های تصادفی',
randomRelaysRefresh: 'بازخوانی',
'Explore more': 'کاوش بیشتر',
'Payment page': 'صفحه پرداخت',
'Supported NIPs': 'NIPهای پشتیبانی شده',
'Open in a': 'باز کردن در {{a}}',
'Cannot handle event of kind k': 'نمی‌توان رویداد از نوع {{k}} را پردازش کرد',
'Sorry! The note cannot be found 😔': 'متأسفانه! یادداشت یافت نشد 😔',
'This user has been muted': 'این کاربر بی‌صدا شده است',
Wallet: 'کیف پول',
Sats: 'ساتوشی',
sats: 'ساتوشی',
'Zap to': 'زپ به',
'Zap n sats': 'زپ {{n}} ساتوشی',
zapComment: 'نظر',
'Default zap amount': 'مقدار پیش‌فرض زپ',
'Default zap comment': 'نظر پیش‌فرض زپ',
'Lightning Address (or LNURL)': 'آدرس لایتنینگ (یا LNURL)',
'Quick zap': 'زپ سریع',
'If enabled, you can zap with a single click. Click and hold for custom amounts':
'در صورت فعال بودن، می‌توانید با یک کلیک زپ کنید. برای مقادیر سفارشی کلیک کرده و نگه دارید',
All: 'همه',
Reactions: 'واکنش‌ها',
Zaps: 'زپ‌ها',
'Enjoying Jumble?': 'از Jumble لذت می‌برید؟',
'Your donation helps me maintain Jumble and make it better! 😊':
'کمک مالی شما به من در نگهداری Jumble و بهتر کردن آن کمک می‌کند! 😊',
'Earlier notifications': 'اعلان‌های قبلی',
'Temporarily display this note': 'نمایش موقت این یادداشت',
buttonFollowing: 'دنبال می‌کنم',
'Are you sure you want to unfollow this user?':
'آیا مطمئن هستید که می‌خواهید این کاربر را دنبال نکنید؟',
'Recent Supporters': 'حامیان اخیر',
'Seen on': 'دیده شده در',
'Temporarily display this reply': 'نمایش موقت این پاسخ',
'Note not found': 'یادداشت یافت نشد',
'no more replies': 'پاسخ بیشتری وجود ندارد',
'Relay sets': 'مجموعه‌های رله',
'Favorite Relays': 'رله‌های مورد علاقه',
"Following's Favorites": 'مورد علاقه دنبال شونده‌ها',
'no more relays': 'رله بیشتری وجود ندارد',
'Favorited by': 'مورد علاقه',
'Post settings': 'تنظیمات پست',
'Media upload service': 'سرویس آپلود رسانه',
'Choose a relay': 'یک رله انتخاب کنید',
'no relays found': 'رله‌ای یافت نشد',
video: 'ویدیو',
'Show n new notes': 'نمایش {{n}} یادداشت جدید',
YouTabName: 'شما',
Bookmark: 'نشانک',
'Remove bookmark': 'حذف نشانک',
'no bookmarks found': 'نشانکی یافت نشد',
'no more bookmarks': 'نشانک بیشتری وجود ندارد',
Bookmarks: 'نشانک‌ها',
'Show more': 'نمایش بیشتر',
General: 'عمومی',
Autoplay: 'پخش خودکار',
'Enable video autoplay on this device': 'فعال کردن پخش خودکار ویدیو در این دستگاه',
'Paste or drop media files to upload': 'فایل‌های رسانه را برای آپلود بچسبانید یا بکشید',
Preview: 'پیش‌نمایش',
'You are about to publish an event signed by [{{eventAuthorName}}]. You are currently logged in as [{{currentUsername}}]. Are you sure?':
'شما در حال انتشار رویدادی امضا شده توسط [{{eventAuthorName}}] هستید. در حال حاضر به عنوان [{{currentUsername}}] وارد شده‌اید. آیا مطمئن هستید؟',
'Platinum Sponsors': 'حامیان پلاتینی',
From: 'از',
'Comment on': 'نظر در مورد',
'View on njump.me': 'مشاهده در njump.me',
'Hide content from untrusted users': 'مخفی کردن محتوا از کاربران غیرقابل اعتماد',
'Only show content from your followed users and the users they follow':
'فقط محتوای کاربران دنبال شده و کاربرانی که آنها دنبال می‌کنند نشان دهید',
'Followed by': 'دنبال شده توسط',
'Mute user privately': 'بی‌صدا کردن کاربر به صورت خصوصی',
'Mute user publicly': 'بی‌صدا کردن کاربر به صورت عمومی',
Quotes: 'نقل قول‌ها',
'Lightning Invoice': 'فاکتور لایتنینگ',
'Bookmark failed': 'نشانک‌گذاری ناموفق',
'Remove bookmark failed': 'حذف نشانک ناموفق',
Translation: 'ترجمه',
Balance: 'موجودی',
characters: 'کاراکتر',
jumbleTranslateApiKeyDescription:
'می‌توانید از این کلید API در هر جای دیگری که از LibreTranslate پشتیبانی می‌کند استفاده کنید. آدرس سرویس {{serviceUrl}} است',
'Top up': 'شارژ',
'Will receive: {n} characters': 'دریافت خواهید کرد: {{n}} کاراکتر',
'Top up {n} sats': 'شارژ {{n}} ساتوشی',
'Minimum top up is {n} sats': 'حداقل شارژ {{n}} ساتوشی است',
Service: 'سرویس',
'Reset API key': 'بازنشانی کلید API',
'Are you sure you want to reset your API key? This action cannot be undone.':
'آیا مطمئن هستید که می‌خواهید کلید API خود را بازنشانی کنید؟ این عمل قابل برگشت نیست.',
Warning: 'هشدار',
'Your current API key will become invalid immediately, and any applications using it will stop working until you update them with the new key.':
'کلید API فعلی شما فوراً نامعتبر خواهد شد و هر برنامه‌ای که از آن استفاده می‌کند تا زمانی که آن را با کلید جدید به‌روزرسانی نکنید کار نخواهد کرد.',
'Service address': 'آدرس سرویس',
Pay: 'پرداخت',
interactions: 'تعاملات',
notifications: 'اعلان‌ها',
'Show untrusted {type}': 'نمایش {{type}} غیرقابل اعتماد',
'Hide untrusted {type}': 'مخفی کردن {{type}} غیرقابل اعتماد',
'Currently hiding {type} from untrusted users.':
'در حال حاضر {{type}} از کاربران غیرقابل اعتماد مخفی می‌شود.',
'Currently showing all {type}.': 'در حال حاضر همه {{type}} نمایش داده می‌شود.',
'Click continue to show all {type}.': 'برای نمایش همه {{type}} روی ادامه کلیک کنید.',
'Click continue to hide {type} from untrusted users.':
'برای مخفی کردن {{type}} از کاربران غیرقابل اعتماد روی ادامه کلیک کنید.',
'Trusted users include people you follow and people they follow.':
'کاربران قابل اعتماد شامل افرادی که دنبال می‌کنید و افرادی که آنها دنبال می‌کنند می‌شوند.',
Continue: 'ادامه',
'Successfully updated mute list': 'لیست بی‌صدا با موفقیت به‌روزرسانی شد',
'No pubkeys found from {url}': 'هیچ کلید عمومی از {{url}} یافت نشد',
'Translating...': 'در حال ترجمه...',
Translate: 'ترجمه',
'Show original': 'نمایش اصل',
Website: 'وب‌سایت',
'Hide untrusted notes': 'مخفی کردن یادداشت‌های غیرقابل اعتماد',
'Open in another client': 'باز کردن در کلاینت دیگر',
Community: 'جامعه',
Group: 'گروه',
'Live event': 'رویداد زنده',
Article: 'مقاله',
Unfavorite: 'حذف از علاقه‌مندی‌ها',
'Recommended relays': 'رله‌های توصیه شده',
'Blossom server URLs': 'آدرس‌های سرور Blossom',
'You need to add at least one blossom server in order to upload media files.':
'برای آپلود فایل‌های رسانه نیاز دارید حداقل یک سرور blossom اضافه کنید.',
'Recommended blossom servers': 'سرورهای blossom توصیه شده',
'Enter Blossom server URL': 'آدرس سرور Blossom را وارد کنید',
Preferred: 'ترجیحی'
}
}

View File

@@ -87,6 +87,9 @@ export function detectLanguage(text?: string): string | null {
if (/[\u0600-\u06ff]/.test(cleanText)) {
return 'ar'
}
if (/[\u0590-\u05FF]/.test(cleanText)) {
return 'fa'
}
if (/[\u0400-\u04ff]/.test(cleanText)) {
return 'ru'
}
@@ -98,6 +101,8 @@ export function detectLanguage(text?: string): string | null {
deu: 'de', // German
eng: 'en', // English
spa: 'es', // Spanish
fas: 'fa', // Persian (Farsi)
pes: 'fa', // Persian (alternative code)
fra: 'fr', // French
ita: 'it', // Italian
jpn: 'ja', // Japanese