Localize the application detail page.

Move the largest dashboard page (app detail) onto a dashboard.appDetail
dictionary: header actions, status/lifecycle banners, configuration,
deployment history, source upload, custom-domain + DNS guide, resources
& scaling, storage, rollback/snapshots, DB restore, service credentials,
renewal and upgrade modals — with localized statuses, locale-aware dates
and RTL-aware layout.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
keyhan
2026-06-11 23:45:16 +03:30
parent 8d423f8224
commit aca69fc5e6
4 changed files with 567 additions and 305 deletions
+153
View File
@@ -1016,6 +1016,159 @@ const fa = {
insufficientRenew: 'موجودی کیف‌پول کافی نیست. کیف‌پول را شارژ کن یا از طریق فاکتور پرداخت کن.',
cycles: { hourly: 'ساعتی', monthly: 'ماهانه', yearly: 'سالانه' },
},
appDetail: {
productTypeApp: 'اپلیکیشن',
cycles: { hourly: 'ساعتی', monthly: 'ماهانه', yearly: 'سالانه' },
// header actions
deploy: 'انتشار', redeploy: 'انتشار مجدد', start: 'شروع', stop: 'توقف', restart: 'ری‌استارت',
preview: 'پیش‌نمایش', delete: 'حذف', renewNow: 'تمدید اکنون', renewApplication: 'تمدید اپلیکیشن',
rebuildTitle: 'بازسازی از آخرین سورس‌کد', instantRollback: 'بازگردانی فوری',
// toasts
deploymentTriggered: 'دیپلوی آغاز شد!', deployFailed: 'شروع دیپلوی ناموفق بود',
redeployStarted: 'انتشار مجدد آغاز شد', redeployFailed: 'انتشار مجدد ناموفق بود',
appStarted: 'اپلیکیشن اجرا شد', startFailed: 'اجرای اپلیکیشن ناموفق بود',
appStopped: 'اپلیکیشن متوقف شد', stopFailed: 'توقف اپلیکیشن ناموفق بود',
appRestarting: 'در حال ری‌استارت اپلیکیشن…', restartFailed: 'ری‌استارت اپلیکیشن ناموفق بود',
sourceUploaded: 'سورس‌کد با موفقیت آپلود شد!', uploadFailed: 'آپلود سورس‌کد ناموفق بود',
uploadSourceFirst: 'سورس‌کد را آپلود و روی «انتشار» بزن تا شروع کنی',
sourceCodeUploaded: 'سورس‌کد آپلود شد',
fileMax10: 'حجم فایل باید حداکثر ۱۰ گیگابایت باشد', fileZipOnly: 'لطفاً فایل .zip یا .tar.gz آپلود کن',
previewHttps: 'پیش‌نمایش روی دامنهٔ HTTPS باز شد.', previewPort: 'پیش‌نمایش روی پورت {port} باز شد',
previewFailed: 'دریافت آدرس پیش‌نمایش ناموفق بود. مطمئن شو اپ منتشر شده است.',
domainSet: 'دامنه تنظیم شد. لطفاً رکوردهای DNS را پیکربندی کن.',
domainVerified: 'دامنه با موفقیت تأیید شد!',
customDomainRemoved: 'دامنهٔ اختصاصی حذف شد',
removeDomainTitle: 'حذف دامنهٔ اختصاصی',
removeDomainConfirm: 'مطمئنی می‌خواهی «{domain}» را حذف کنی؟ وب‌سایت فقط از طریق دامنهٔ پلتفرم در دسترس خواهد بود.',
remove: 'حذف',
copied: 'کپی شد!', copy: 'کپی',
resourcesUpdated: 'منابع به‌روزرسانی شد', updateResourcesFailed: 'به‌روزرسانی منابع ناموفق بود',
resourcesUpdatedSuccess: 'منابع با موفقیت به‌روزرسانی شد!', noChanges: 'تغییری برای اعمال نیست',
renewFirst: 'پیش از تغییر منابع، اپلیکیشن را تمدید کن',
upgradedPaid: 'منابع ارتقا یافت! {amount} تومان پرداخت شد',
upgradeFailed: 'ارتقای منابع ناموفق بود', calcFailed: 'محاسبهٔ هزینهٔ ارتقا ناموفق بود',
invoiceCreated: 'فاکتور ساخته شد. روش پرداخت را انتخاب کن.', invoiceFailed: 'ساخت فاکتور ارتقا ناموفق بود',
dbRestored: 'دیتابیس با موفقیت بازیابی شد!', dbInvalidFile: 'لطفاً فایل .sql، .dump یا .gz آپلود کن',
fileMax500: 'حجم فایل باید کمتر از ۵۰۰ مگابایت باشد', dbUploadFailed: 'آپلود dump دیتابیس ناموفق بود',
snapshotStarted: 'ساخت اسنپ‌شات آغاز شد', snapshotCreateFailed: 'ساخت اسنپ‌شات ناموفق بود',
snapshotDeleted: 'اسنپ‌شات حذف شد', snapshotDeleteFailed: 'حذف اسنپ‌شات ناموفق بود',
deleteSnapshotTitle: 'حذف اسنپ‌شات؟', deleteSnapshotMessage: 'حذف «{label}»؟ فایل‌های آرشیوشده برای همیشه حذف می‌شوند.',
deleteSnapshot: 'حذف اسنپ‌شات',
rollbackFailed: 'بازگردانی ناموفق بود', rollbackCompleted: 'بازگردانی کامل شد:\n',
rollbackSnapTitle: 'بازگردانی به «{label}»؟',
rollbackSnapMessage: 'این کار بازیابی می‌کند:\n• دیپلوی اپ از طریق K8s revision (فوری)\n• فایل‌های wp-content (وردپرس)\n• dump دیتابیس\n\nوضعیت فعلی بازنویسی خواهد شد.',
rollbackRevTitle: 'بازگردانی به Revision {n}؟',
rollbackRevMessage: 'این کار Helm release را به revision {n} بازمی‌گرداند.{cause}\n\nنیازی به بازسازی نیست — در چند ثانیه اعمال می‌شود.',
description: 'توضیح',
deleteAppTitle: 'حذف «{name}»؟',
deleteAppMessage: 'این کار همهٔ منابع کوبرنتیز، داده‌ها و رکوردهای دیپلوی را برای همیشه حذف می‌کند.\n\n',
deleteAppCredit: 'منابع پیش‌پرداختِ باقی‌مانده‌ات روی داشبورد نمایش داده می‌شود تا بدون هزینهٔ اضافی روی اپ جدید استفاده کنی.',
appDeleted: 'اپلیکیشن حذف شد', appDeletedCredit: 'اپلیکیشن حذف شد. منابع پیش‌پرداختت روی داشبورد است.',
deleteAppFailed: 'حذف اپلیکیشن ناموفق بود',
downloadInProgress: 'یک دانلود از قبل در حال انجام است. لطفاً صبر کن.',
downloading: 'در حال دانلود {name}… برای فایل‌های بزرگ ممکن است تا ۱۵ دقیقه طول بکشد.',
downloadedSuccess: '{name} با موفقیت دانلود شد!',
downloadTimeout: 'دانلود پس از ۱۵ دقیقه منقضی شد. دوباره تلاش کن یا لاگ سرور را بررسی کن.',
downloadFailed: 'دانلود {name} ناموفق بود', downloadCurrentFailed: 'دانلود {name} فعلی ناموفق بود',
// status / config card
configuration: 'پیکربندی', runtime: 'رانتایم', image: 'ایمیج', status: 'وضعیت',
cpu: 'CPU', memory: 'حافظه', replicas: 'رپلیکاها', cluster: 'کلاستر', pool: 'پول', workload: 'workload', port: 'پورت',
cpuRequest: 'درخواست CPU', cpuLimit: 'محدودیت CPU', memoryRequest: 'درخواست حافظه', memoryLimit: 'محدودیت حافظه',
database: 'دیتابیس', databaseVolume: 'والیوم دیتابیس', gitConnected: 'ریپازیتوری Git متصل است',
deployMarker: 'نشان دیپلوی', billing: 'صورت‌حساب', name: 'نام', domain: 'دامنه',
// deployment history
deploymentHistory: 'تاریخچهٔ دیپلوی', noDeployments: 'هنوز دیپلویی نیست',
uploadToStart: 'سورس‌کد را آپلود و روی «انتشار» بزن تا شروع کنی',
// source upload
sourceCode: 'سورس‌کد', replace: 'جایگزینی', uploadSourceClick: 'سورس‌کد را آپلود و روی «انتشار» بزن تا شروع کنی',
// domain
customDomain: 'دامنهٔ اختصاصی', addCustomDomain: 'افزودن دامنهٔ اختصاصی', setUpCustomDomain: 'راه‌اندازی دامنهٔ اختصاصی',
platformDomain: 'دامنهٔ پلتفرم', domainPlaceholder: 'example.com یا www.example.com', dnsSetupGuide: 'راهنمای تنظیم DNS',
removeCustomDomain: 'حذف دامنهٔ اختصاصی',
// resources
resourcesScaling: 'منابع و مقیاس‌بندی', monitor: 'پایش', hide: 'پنهان', show: 'نمایش',
liveUsage: 'مصرف زنده', loadingMetrics: 'در حال بارگذاری متریک‌ها…', metrics: 'متریک‌ها', pods: 'پادها', ready: 'آماده',
noMetrics: 'هنوز متریکی نیست', storageUsage: 'مصرف فضای ذخیره', loadingStorageMetrics: 'در حال بارگذاری متریک‌های فضای ذخیره…',
noStorageData: 'داده‌ی فضای ذخیره موجود نیست', storageMetricsUnavailable: 'متریک فضای ذخیره در دسترس نیست',
used: 'مصرف‌شده', applyChanges: 'اعمال تغییرات', applying: 'در حال اعمال…', processing: 'در حال پردازش…',
// snapshots / revisions
newSnapshot: 'اسنپ‌شات جدید', creating: 'در حال ساخت…',
k8sRevisions: 'K8s Revisionها', fileSnapshots: 'اسنپ‌شات فایل', fullSnapshots: 'اسنپ‌شات کامل',
loadingRevisions: 'در حال بارگذاری revisionها…', noRevisions: 'هیچ revisionی موجود نیست',
revisionsAfterDeploy: 'Revisionها پس از اولین دیپلوی نمایان می‌شوند.',
loadingSnapshots: 'در حال بارگذاری اسنپ‌شات‌ها…', noSnapshots: 'هنوز اسنپ‌شاتی نیست',
maxSnapshots: 'حداکثر ۱۰ اسنپ‌شات نگه داشته می‌شود. قدیمی‌ترها خودکار حذف می‌شوند.',
rollback: 'بازگردانی', instant: 'فوری', current: 'فعلی', full: 'کامل',
instantRollbackTitle: 'بازگردانی فوری به این revision',
rollbackSnapTitleBtn: 'بازگردانی به این اسنپ‌شات (از K8s revision استفاده و DB/wp-content را بازیابی می‌کند)',
downloadCurrentState: 'دانلود وضعیت فعلی',
downloadCurrentNote: 'یک کپی از فایل‌های زندهٔ فعلی را بدون ساخت اسنپ‌شات دانلود کن. فایل‌های بزرگ ممکن است تا ۱۵ دقیقه طول بکشند.',
downloadSource: 'دانلود سورس‌کد', downloadWpContent: 'دانلود wp-content', downloadDatabaseDump: 'دانلود dump دیتابیس',
sourceCodeArtifact: 'سورس‌کد', databaseDump: 'dump دیتابیس', downloading2: 'در حال دانلود…',
// db restore
restoreDatabaseDump: 'بازیابی dump دیتابیس', uploadSqlToRestore: 'آپلود SQL dump برای بازیابی',
restoringDatabase: 'در حال بازیابی دیتابیس…', restoreOutput: 'خروجی بازیابی',
dbOnlyInternal: 'دیتابیس فقط داخل کلاستر در دسترس است. به‌صورت خارجی expose نشده.',
// service credentials
serviceCredentials: 'اطلاعات ورود سرویس', serviceCredsAfterDeploy: 'رمزهای سرویس پس از انتشار اپلیکیشن در دسترس هستند.',
password: 'رمز عبور',
// logs
logs: 'لاگ‌ها',
// plan expiry / renewal
planExpiringSoon: 'پلن به‌زودی منقضی می‌شود', planExpires: 'انقضای پلن: {date}', extendPlan: 'تمدید پلن',
renewService: 'تمدید اپلیکیشن', wallet: 'کیف‌پول', walletBalance: 'موجودی کیف‌پول', payFromWallet: 'پرداخت از کیف‌پول',
insufficientRenew: 'موجودی کیف‌پول کافی نیست. کیف‌پول را شارژ کن یا از طریق فاکتور پرداخت کن.',
bestForMost: 'مناسب اکثر کاربران', saveUpTo20: 'تا ۲۰٪ صرفه‌جویی',
// upgrade confirm modal
confirmResourceUpgrade: 'تأیید ارتقای منابع', currentHourlyCost: 'هزینهٔ ساعتی فعلی', newHourlyCost: 'هزینهٔ ساعتی جدید',
remainingHours: 'ساعت‌های باقی‌مانده در بازه', proratedAmount: 'مبلغ تسهیم‌شده برای پرداخت',
feeIncludedNote: 'این هزینه در محاسبهٔ هزینهٔ کل لحاظ شده است.', thisMayTake: 'ممکن است چند دقیقه طول بکشد',
cancel: 'انصراف',
private: 'خصوصی', active: 'فعال',
deployingBtn: 'در حال انتشار…',
adjustCpuMemStorage: 'تنظیم CPU / حافظه و فضای ذخیره',
calculating: 'در حال محاسبه…',
connectionInfoInternal: 'اطلاعات اتصال (کلاستر داخلی)',
createInvoicePay: 'ساخت فاکتور و پرداخت',
customDomainPending: 'دامنهٔ اختصاصی — در انتظار تأیید DNS',
customDomainFee: 'هزینهٔ دامنهٔ اختصاصی:',
dragDrop: 'یک',
fileHereBrowse: 'فایل را اینجا بکش، یا برای انتخاب کلیک کن',
expandDiskNote: 'دیسک را در «تنظیم CPU / حافظه و فضای ذخیره» پایین گسترش بده.',
maxSize10gb: 'حداکثر اندازه: ۱۰ گیگابایت',
maxSize500mb: 'حداکثر اندازه: ۵۰۰ مگابایت',
payAsYouGo: 'پرداخت به‌اندازهٔ مصرف، تمدید خودکار',
pickComponentNote: 'انتخاب کن کدام بخش به‌روزرسانی شود. CPU و حافظه به‌ازای هر workload اعمال می‌شوند؛ فضای ذخیره فقط می‌تواند رشد کند (گسترش). اپلیکیشن اصلی ممکن است برای ارتقاهای پولی از صورت‌حساب استفاده کند؛ دیتابیس و سرویس‌های اختیاری مستقیماً در کلاستر اعمال می‌شوند.',
rabbitmqVolume: 'والیوم RabbitMQ (اختیاری)',
redisVolume: 'والیوم Redis (اختیاری)',
rollbackSnapshots: 'بازگردانی و اسنپ‌شات‌ها',
snapshotsAutoNote: 'اسنپ‌شات‌ها پیش از هر دیپلوی به‌صورت خودکار ساخته می‌شوند، یا می‌توانی دستی یکی بسازی.',
snapshotsIncludeNote: 'شامل سورس‌کد، dump دیتابیس و wp-content. از این‌ها برای بازیابی داده یا دانلود بکاپ استفاده کن. پیش از هر دیپلوی خودکار ساخته می‌شوند.',
revisionsHelmNote: 'با استفاده از revisionهای Helm release. در چند ثانیه به پیکربندی قبلی برمی‌گردد — بدون نیاز به بازسازی. تا ۱۰ revision نگه داشته می‌شود.',
record: 'رکورد:',
cpuColon: 'CPU:', memoryColon: 'حافظه:', sidecars: 'Sidecarها:',
typeColon: 'نوع:', valueColon: 'مقدار:', nameHost: 'نام/هاست:', cnameTarget: 'مقصد CNAME:',
orText: 'یا',
verifyDns: 'تأیید DNS', checking: 'در حال بررسی…',
dnsStep1: '۱. وارد ثبت‌کنندهٔ دامنه‌ات شو (مثلاً Cloudflare، Namecheap، GoDaddy)',
dnsStep2: '۲. به مدیریت DNS دامنه‌ات برو',
dnsStep3a: '۳. یک رکورد ', dnsStep3b: ' اضافه کن:',
dnsStep4a: '۴. اگر از دامنهٔ ریشه (بدون www) استفاده می‌کنی، از ثبت‌کننده‌ای که CNAME flattening را پشتیبانی می‌کند استفاده کن (مثلاً Cloudflare)، یا به‌جای آن از ',
dnsStep4b: ' استفاده کن.',
dnsStep5: '۵. ۵ تا ۳۰ دقیقه برای انتشار DNS صبر کن (در برخی موارد تا ۴۸ ساعت)',
dnsStep6a: '۶. روی دکمهٔ ', dnsStep6b: ' بالا کلیک کن',
scheduledForDeletion: 'اپلیکیشن برای حذف زمان‌بندی شده!',
suspendedPayment: 'اپلیکیشن معلق شد — پرداخت لازم است',
willBeDeletedOn: 'این اپلیکیشن در {date} برای همیشه حذف می‌شود. برای جلوگیری از از‌دست‌رفتن داده، اکنون تمدید کن.',
soon: 'به‌زودی',
planExpiredRestore: 'پلن شما منقضی شده است. برای بازگرداندن دسترسی به سرویس تمدید کن.',
planExpiresEarly: 'پلن شما در {date} منقضی می‌شود. برای جلوگیری از قطع سرویس، زودتر تمدید کن.',
selectBillingCycle: 'یک دورهٔ صورت‌حساب برای تمدید «{name}» انتخاب کن',
toman: 'تومان', tomanPerHour: 'تومان/ساعت',
walletShortBy: 'موجودی کیف‌پول {n} تومان کم است. می‌توانی مابه‌التفاوت را از طریق درگاه در صفحهٔ فاکتور پرداخت کنی.',
revision: 'نسخهٔ', hoursUnit: '{n} ساعت',
payFromWalletBtn: 'پرداخت از کیف‌پول', applyDirectly: 'اعمال مستقیم',
},
},
};