diff --git a/package-lock.json b/package-lock.json
index 6b76818..271cafb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7,6 +7,7 @@
"": {
"name": "cabinet-frontend",
"version": "1.0.0",
+ "license": "AGPL-3.0",
"dependencies": {
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/sortable": "^10.0.0",
diff --git a/src/api/promoOffers.ts b/src/api/promoOffers.ts
index a4a8088..fdc656a 100644
--- a/src/api/promoOffers.ts
+++ b/src/api/promoOffers.ts
@@ -139,22 +139,22 @@ export interface PromoOfferLogListResponse {
// Target segments for broadcast
export const TARGET_SEGMENTS = {
- all: 'Все пользователи',
- active: 'Активные подписчики',
- trial: 'Триал пользователи',
- trial_ending: 'Заканчивается триал',
- expiring: 'Заканчивается подписка',
- expired: 'Истекшая подписка',
- zero: 'Нулевой баланс',
- autopay_failed: 'Ошибка автоплатежа',
- low_balance: 'Низкий баланс',
- inactive_30d: 'Неактивны 30 дней',
- inactive_60d: 'Неактивны 60 дней',
- inactive_90d: 'Неактивны 90 дней',
- custom_today: 'Зарегистрированы сегодня',
- custom_week: 'Зарегистрированы за неделю',
- custom_month: 'Зарегистрированы за месяц',
- custom_active_today: 'Активны сегодня',
+ all: 'admin.promoOffers.segments.all',
+ active: 'admin.promoOffers.segments.active',
+ trial: 'admin.promoOffers.segments.trial',
+ trial_ending: 'admin.promoOffers.segments.trialEnding',
+ expiring: 'admin.promoOffers.segments.expiring',
+ expired: 'admin.promoOffers.segments.expired',
+ zero: 'admin.promoOffers.segments.zero',
+ autopay_failed: 'admin.promoOffers.segments.autopayFailed',
+ low_balance: 'admin.promoOffers.segments.lowBalance',
+ inactive_30d: 'admin.promoOffers.segments.inactive30d',
+ inactive_60d: 'admin.promoOffers.segments.inactive60d',
+ inactive_90d: 'admin.promoOffers.segments.inactive90d',
+ custom_today: 'admin.promoOffers.segments.customToday',
+ custom_week: 'admin.promoOffers.segments.customWeek',
+ custom_month: 'admin.promoOffers.segments.customMonth',
+ custom_active_today: 'admin.promoOffers.segments.customActiveToday',
} as const;
export type TargetSegment = keyof typeof TARGET_SEGMENTS;
@@ -163,21 +163,21 @@ export type TargetSegment = keyof typeof TARGET_SEGMENTS;
export const OFFER_TYPE_CONFIG = {
test_access: {
icon: '🧪',
- label: 'Тестовый доступ',
+ labelKey: 'admin.promoOffers.offerType.testAccess',
effect: 'test_access',
- description: 'Временный доступ к дополнительным серверам',
+ descriptionKey: 'admin.promoOffers.offerType.testAccessDesc',
},
extend_discount: {
icon: '💎',
- label: 'Скидка на продление',
+ labelKey: 'admin.promoOffers.offerType.extendDiscount',
effect: 'percent_discount',
- description: 'Скидка для текущих подписчиков',
+ descriptionKey: 'admin.promoOffers.offerType.extendDiscountDesc',
},
purchase_discount: {
icon: '🎯',
- label: 'Скидка на покупку',
+ labelKey: 'admin.promoOffers.offerType.purchaseDiscount',
effect: 'percent_discount',
- description: 'Скидка для новых пользователей',
+ descriptionKey: 'admin.promoOffers.offerType.purchaseDiscountDesc',
},
} as const;
diff --git a/src/components/ConnectionModal.tsx b/src/components/ConnectionModal.tsx
index 73037f9..c024027 100644
--- a/src/components/ConnectionModal.tsx
+++ b/src/components/ConnectionModal.tsx
@@ -453,7 +453,7 @@ export default function ConnectionModal({ onClose }: ConnectionModalProps) {
{getOfferDescription(offer)}
+{getOfferDescription(offer, t)}
- {t( - 'balance.clickToOpenPayment', - 'Нажмите кнопку ниже, чтобы открыть страницу оплаты в новой вкладке', - )} -
+{t('balance.clickToOpenPayment')}
{/* Main open button - NO preventDefault, let work natively for iOS Safari */}- {channelInfo?.message || - t('blocking.channel.defaultMessage', 'Для продолжения работы подпишитесь на наш канал')} + {channelInfo?.message || t('blocking.channel.defaultMessage')}
{/* Error message */} @@ -108,7 +105,7 @@ export default function ChannelSubscriptionScreen() { - {t('blocking.channel.openChannel', 'Открыть канал')} + {t('blocking.channel.openChannel')} {/* Check subscription button */} @@ -139,7 +136,7 @@ export default function ChannelSubscriptionScreen() { d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" > - {t('blocking.channel.checking', 'Проверяем...')} + {t('blocking.channel.checking')} > ) : cooldown > 0 ? ( <> @@ -156,7 +153,7 @@ export default function ChannelSubscriptionScreen() { d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" /> - {t('blocking.channel.waitSeconds', 'Подождите {{seconds}} сек.', { + {t('blocking.channel.waitSeconds', { seconds: cooldown, })} > @@ -170,16 +167,14 @@ export default function ChannelSubscriptionScreen() { d="M5 13l4 4L19 7" /> - {t('blocking.channel.checkSubscription', 'Проверить подписку')} + {t('blocking.channel.checkSubscription')} > )}- {t('blocking.channel.hint', 'После подписки нажмите кнопку проверки')} -
+{t('blocking.channel.hint')}
- {maintenanceInfo?.message || - t( - 'blocking.maintenance.defaultMessage', - 'Сервис временно недоступен. Проводятся технические работы.', - )} + {maintenanceInfo?.message || t('blocking.maintenance.defaultMessage')}
{/* Reason */} {maintenanceInfo?.reason && (- {t('blocking.maintenance.reason', 'Причина')}: -
+{t('blocking.maintenance.reason')}:
{maintenanceInfo.reason}
- {t('blocking.maintenance.waitMessage', 'Пожалуйста, подождите...')} -
+{t('blocking.maintenance.waitMessage')}
); diff --git a/src/locales/en.json b/src/locales/en.json index 866d81a..b9353d8 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -20,7 +20,15 @@ "edit": "Edit", "delete": "Delete", "currency": "$", - "refresh": "Refresh" + "refresh": "Refresh", + "copy": "Copy", + "all": "All", + "units": { + "gb": "GB", + "perGb": "/GB" + }, + "retry": "Retry", + "saving": "Saving..." }, "nav": { "dashboard": "Dashboard", @@ -42,8 +50,14 @@ "noNotifications": "No notifications", "justNow": "Just now", "minutesAgo": "{{count}} min ago", + "minutesAgo_one": "{{count}} min ago", + "minutesAgo_other": "{{count}} min ago", "hoursAgo": "{{count}} h ago", + "hoursAgo_one": "{{count}} h ago", + "hoursAgo_other": "{{count}} h ago", "daysAgo": "{{count}} d ago", + "daysAgo_one": "{{count}} d ago", + "daysAgo_other": "{{count}} d ago", "viewAll": "View all tickets", "newNotification": "New notification", "clickToView": "Click to view", @@ -92,7 +106,11 @@ "verificationSent": "We sent a verification link to:", "clickLinkToVerify": "Click the link in the email to verify your account and log in.", "backToLogin": "Back to login", - "emailNotVerified": "Please verify your email first" + "emailNotVerified": "Please verify your email first", + "forgotPasswordHint": "Enter your email to receive a reset link", + "loginSuccess": "Login successful", + "passwordResetSent": "Password reset link sent to your email", + "sendResetLink": "Send reset link" }, "emailVerification": { "title": "Email Verification", @@ -131,7 +149,11 @@ "expiresAt": "Expires at", "daysLeft": "Days left", "devices": "Devices", - "servers": "Servers", + "devices_one": "{{count}} device", + "devices_other": "{{count}} devices", + "serversLabel": "Servers", + "servers_one": "{{count}} server", + "servers_other": "{{count}} servers", "traffic": "Traffic", "unlimited": "Unlimited", "used": "Used", @@ -142,8 +164,14 @@ "buyDevices": "Buy Devices", "renewalOptions": "Renewal Options", "days": "days", + "days_one": "{{count}} day", + "days_other": "{{count}} days", "hours": "h", + "hours_one": "{{count}} h", + "hours_other": "{{count}} h", "minutes": "m", + "minutes_one": "{{count}} m", + "minutes_other": "{{count}} m", "price": "Price", "noSubscription": "You don't have an active subscription", "getSubscription": "Get Subscription", @@ -157,15 +185,21 @@ "getConfig": "Connect Devices", "autoRenewal": "Auto-renewal", "daysBeforeExpiry": "days before expiry", + "daysBeforeExpiry_one": "{{count}} day before expiry", + "daysBeforeExpiry_other": "{{count}} days before expiry", "selectPeriod": "Select Period", "selectTraffic": "Select Traffic", "selectServers": "Select Servers", "selectDevices": "Devices", "perDevice": "/ device", "devicesFree": "devices free", + "devicesFree_one": "{{count}} device free", + "devicesFree_other": "{{count}} devices free", "perExtraDevice": "/ extra device", "extraDevices": "Extra devices", "extraDevicesIncluded": "Incl. {{count}} extra dev.", + "extraDevicesIncluded_one": "Incl. {{count}} extra dev.", + "extraDevicesIncluded_other": "Incl. {{count}} extra dev.", "baseTariff": "Tariff", "perMonth": "/mo", "summary": "Summary", @@ -186,7 +220,11 @@ "titlePaid": "Trial Subscription", "description": "Try our VPN service!", "days": "days", + "days_one": "{{count}} day", + "days_other": "{{count}} days", "devices": "devices", + "devices_one": "{{count}} device", + "devices_other": "{{count}} devices", "price": "Price", "activate": "Activate Free", "payAndActivate": "Pay & Activate", @@ -241,9 +279,10 @@ "pausedDescription": "Charges stopped. Subscription will be active until", "nextCharge": "Until next charge", "willBeCharged": "Will be charged", - "days_one": "day", - "days_few": "days", - "days_many": "days", + "days_one": "{{count}} day", + "days_few": "{{count}} days", + "days_many": "{{count}} days", + "days": "d.", "hours": "h", "minutes": "m" }, @@ -264,7 +303,9 @@ "free": "Free", "switch": "Switch", "switched": "Tariff switched", - "notEnoughBalance": "Insufficient balance" + "notEnoughBalance": "Insufficient balance", + "dailyPayment": "Daily payment", + "dailyChargeDescription": "Charged daily from your balance" }, "switchTraffic": { "title": "Change Traffic", @@ -274,7 +315,64 @@ "switched": "Traffic changed" }, "purchasedTraffic": "Purchased Traffic", - "trafficResetAt": "Reset" + "trafficResetAt": "Reset", + "additionalOptions": { + "title": "Additional options", + "buyDevices": "Buy more devices", + "currentDeviceLimit": "Current limit: {{count}} devices", + "devicesUnavailable": "Device purchase is not available", + "devicesUnit": "devices", + "buy": "Buy", + "buyTraffic": "Buy more traffic", + "currentTrafficLimit": "Current limit: {{limit}} GB (used {{used}} GB)", + "buyTrafficTitle": "Buy more traffic", + "trafficWarning": "Purchased traffic is added to your current limit and does not carry over to the next period", + "trafficUnavailable": "Traffic purchase is not available for your tariff", + "unlimited": "Unlimited", + "buyTrafficGb": "Buy {{gb}} GB", + "manageServers": "Server management", + "manageServersTitle": "Server management" + }, + "serverManagement": { + "statusLegend": "✅ — connected • ➕ — will be added (paid) • ➖ — will be disconnected", + "discountBanner": "Your server discount: -{{percent}}%", + "forDays": "(for {{days}} days)", + "perMonth": "/mo", + "unavailable": "Unavailable", + "toAdd": "Add:", + "toDisconnect": "Disconnect:", + "paymentProrated": "Payment (prorated for remaining days):", + "applyChanges": "Apply changes", + "selectServersHint": "Select servers to connect or disconnect", + "noServersAvailable": "No servers available to manage" + }, + "legacy": { + "selectTariffTitle": "Select a tariff to renew", + "selectTariffDescription": "Your current subscription was created before tariffs were introduced. To renew, please select one of the available tariffs.", + "currentSubContinues": "Your current subscription will remain active until it expires." + }, + "promoGroup": { + "yourGroup": "Your group: {{name}}", + "personalDiscountsApplied": "Personal discounts applied to prices" + }, + "tariff": { + "perDay": "/ day", + "flexiblePayment": "Flexible payment", + "selectForRenewal": "Select for renewal" + }, + "customDays": { + "title": "Custom number of days", + "perDay": "/day" + }, + "customTraffic": { + "label": "Traffic", + "selectVolume": "Select traffic volume", + "default": "Default: {{label}}" + }, + "summary": { + "period": "Period: {{label}}", + "traffic": "Traffic: {{gb}} GB" + } }, "balance": { "title": "Balance", @@ -365,6 +463,19 @@ "pay": "Pay", "checkStatus": "Check Status", "checking": "Checking..." + }, + "paymentReady": "Payment link is ready", + "clickToOpenPayment": "Click the button below to open the payment page in a new tab", + "openPaymentPage": "Open payment page", + "errors": { + "noPaymentLink": "Server did not return a payment link", + "starsOnlyInTelegram": "Stars payment is only available in Telegram Mini App", + "generic": "Error: {{details}}", + "invoiceFailed": "Failed to create invoice", + "rateLimit": "Please wait {{seconds}} sec.", + "selectMethod": "Select a method", + "enterAmount": "Enter an amount", + "amountRange": "Amount: {{min}} – {{max}} ₽" } }, "referral": { @@ -440,6 +551,7 @@ "fileTooLarge": "File is too large. Maximum size is 10MB.", "uploadFailed": "Failed to upload image", "imageLoadFailed": "Failed to load image", + "tooManyRequests": "Too many requests. Please wait {{seconds}} sec.", "ticketsDisabled": "Tickets Disabled", "useProfile": "Please go to the bot profile to get support", "goToProfile": "Go to Profile", @@ -456,6 +568,8 @@ "stars": "Stars", "telegramStars": "Telegram Stars", "days": "days", + "days_one": "{{count}} day", + "days_other": "{{count}} days", "subscriptionDays": "Subscription days", "day": "Day", "spin": "SPIN!", @@ -492,6 +606,13 @@ } }, "admin": { + "groups": { + "analytics": "Analytics", + "marketing": "Marketing", + "system": "System", + "tariffs": "Tariffs & Sales", + "users": "Users" + }, "nav": { "title": "Admin", "dashboard": "Dashboard", @@ -507,7 +628,10 @@ "payments": "Payments", "remnawave": "RemnaWave", "emailTemplates": "Email Templates", - "paymentMethods": "Payment Methods" + "paymentMethods": "Payment Methods", + "campaigns": "Campaigns", + "promoOffers": "Promo Offers", + "promocodes": "Promo Codes" }, "panel": { "title": "Admin Panel", @@ -525,7 +649,10 @@ "paymentsDesc": "Payment verification", "remnawaveDesc": "Panel management and statistics", "emailTemplatesDesc": "Manage email notification templates", - "paymentMethodsDesc": "Configure payment methods and order" + "paymentMethodsDesc": "Configure payment methods and order", + "campaignsDesc": "Advertising campaigns", + "promoOffersDesc": "Personal discounts", + "promocodesDesc": "Manage promo codes" }, "emailTemplates": { "title": "Email Templates", @@ -548,16 +675,18 @@ "clickToCopy": "Click to copy" }, "payments": { - "title": "Payment Verification", + "title": "Payment verification", "description": "Pending payments in the last 24 hours", - "totalPending": "Total Pending", + "totalPending": "Total pending", "filterByMethod": "Filter by method", "noPayments": "No pending payments", "paid": "Paid", "user": "User", - "openLink": "Open Link", - "checkStatus": "Check Status", - "checking": "Checking..." + "openLink": "Open link", + "checkStatus": "Check status", + "checking": "Checking...", + "prev": "Previous", + "next": "Next" }, "paymentMethods": { "title": "Payment Methods", @@ -587,11 +716,15 @@ "firstTopupAny": "Any", "firstTopupYes": "Made", "firstTopupNo": "Not made", + "firstTopupWas": "Was", + "firstTopupWasNot": "Was not", "promoGroupFilter": "Promo groups", "promoGroupAll": "All groups", "promoGroupSelected": "Selected", "promoGroupsShort": "groups", - "noPromoGroups": "No promo groups" + "noPromoGroups": "No promo groups", + "cancelButton": "Cancel", + "saveButton": "Save" }, "remnawave": { "title": "RemnaWave", @@ -711,14 +844,16 @@ "targetRtp": "target", "prizeDistribution": "Prize Distribution", "times": "times", + "times_one": "{{count}} time", + "times_other": "{{count}} times", "topWins": "Top Wins" } }, "broadcasts": { "title": "Broadcasts", - "subtitle": "Mass messaging to users", + "subtitle": "History and management", "create": "Create Broadcast", - "empty": "No broadcasts yet", + "empty": "No broadcasts", "selectFilter": "Select audience", "selectFilterPlaceholder": "Select filter...", "recipients": "recip.", @@ -738,7 +873,27 @@ "failed": "Failed", "filter": "Filter", "message": "Message", - "unknownAdmin": "Unknown admin" + "unknownAdmin": "Unknown", + "prev": "Previous", + "next": "Next", + "status": { + "queued": "Queued", + "inProgress": "Sending", + "completed": "Completed", + "partial": "Partial", + "failed": "Failed", + "cancelled": "Cancelled", + "cancelling": "Cancelling" + }, + "filterGroups": { + "basic": "Basic", + "subscription": "By subscription", + "traffic": "By traffic", + "registration": "By registration", + "activity": "By activity", + "source": "By source", + "tariff": "By tariff" + } }, "settings": { "title": "System Settings", @@ -772,7 +927,58 @@ "conversionLabel": "Conversion Label (optional)", "googleLabelPlaceholder": "e.g. AbCdEfGhIjKl", "googleLabelHint": "Conversion label for event tracking", - "analyticsHint": "Counters are automatically embedded on all cabinet pages. After saving an ID, scripts are loaded on the next page load. To remove a counter, clear the field and save." + "analyticsHint": "Counters are automatically embedded on all cabinet pages. After saving an ID, scripts are loaded on the next page load. To remove a counter, clear the field and save.", + "inputPlaceholder": "Enter value...", + "ctrlEnterHint": "Ctrl+Enter to save", + "cancelButton": "Cancel", + "saveButton": "Save", + "saveHint": "Save (Enter)", + "cancelHint": "Cancel (Esc)", + "removeFromFavorites": "Remove from favorites", + "addToFavorites": "Add to favorites", + "enabled": "Enabled", + "disabled": "Disabled", + "foundCount": "Found: {{count}}", + "notFound": "Nothing found", + "byQuery": "by query \"{{query}}\"", + "accentColor": "Accent color", + "animatedBackground": "Animated background", + "animatedBackgroundDesc": "Show animated background effects", + "autoFullscreen": "Auto fullscreen", + "autoFullscreenDesc": "Auto expand in Telegram", + "availableThemes": "Available themes", + "colors": { + "background": "Background", + "error": "Error", + "success": "Success", + "surface": "Surface", + "text": "Text", + "textSecondary": "Secondary text", + "warning": "Warning" + }, + "customColors": "Custom colors", + "darkTheme": "Dark theme", + "emailAuth": "Email auth", + "emailAuthDesc": "Allow login via email", + "favoritesEmpty": "No favorites yet", + "favoritesHint": "Star settings to add them here", + "interfaceOptions": "Interface options", + "lightTheme": "Light theme", + "logoAndName": "Logo & name", + "notSpecified": "Not specified", + "projectName": "Project name", + "quickPresets": "Quick presets", + "resetAllColors": "Reset all colors", + "statusColors": "Status colors" + }, + "theme": { + "accentColor": "Accent color", + "customizeColors": "Customize colors", + "hexCode": "HEX code", + "hue": "Hue", + "lightness": "Lightness", + "quickPresets": "Quick presets", + "saturation": "Saturation" }, "apps": { "title": "App Management", @@ -882,8 +1088,14 @@ "tierHint": "1-10, affects priority during upgrade", "unlimited": "Unlimited", "devices": "devices", + "devices_one": "{{count}} device", + "devices_other": "{{count}} devices", "servers": "servers", + "servers_one": "{{count}} server", + "servers_other": "{{count}} servers", "subscriptions": "subscriptions", + "subscriptions_one": "{{count}} subscription", + "subscriptions_other": "{{count}} subscriptions", "trial": "Trial", "inactive": "Inactive", "activate": "Activate", @@ -893,6 +1105,8 @@ "confirmDelete": "Delete tariff?", "confirmDeleteText": "This action cannot be undone. The tariff will be permanently deleted.", "days": "days", + "days_one": "{{count}} day", + "days_other": "{{count}} days", "tabs": { "basic": "Basic", "prices": "Prices", @@ -903,7 +1117,81 @@ "serversHint": "Select servers available for this tariff. You can set individual traffic limits for each server.", "noServers": "No servers available", "serverTrafficLimit": "Traffic limit", - "useDefault": "default" + "useDefault": "default", + "selectType": "Select tariff type", + "periodTariff": "Period-based tariff", + "periodTariffDesc": "Payment for period (7, 30, 90 days, etc.). Flexible periods and prices.", + "dailyTariff": "Daily tariff", + "dailyTariffDesc": "Daily deduction from balance. Can be paused.", + "editTitle": "Edit tariff", + "newPeriodTitle": "New period-based tariff", + "newDailyTitle": "New daily tariff", + "periodPayment": "Payment for period", + "dailyDeduction": "Daily deduction", + "tabBasic": "Basic", + "tabPeriods": "Periods", + "tabServers": "Servers", + "tabExtra": "Additional", + "nameLabel": "Tariff name", + "nameExamplePeriod": "E.g.: Standard", + "nameExampleDaily": "E.g.: Daily", + "descriptionLabel": "Description", + "descriptionPlaceholder2": "Brief tariff description", + "trafficLimitLabel": "Traffic limit", + "gbUnit": "GB", + "trafficLimitHint": "0 = unlimited traffic", + "deviceLimitLabel": "Devices in tariff", + "tierLevelLabel": "Tariff tier level", + "tierLevelHint": "Affects upgrade availability between tariffs", + "periodsTabHint": "Add periods and prices for the tariff. Users will be able to choose from the added periods.", + "addPeriodTitle": "Add period", + "daysLabel": "Days", + "priceLabel": "Price (\u20bd)", + "addButton": "Add", + "noPeriodsHint": "No added periods. Add at least one period.", + "daysShort": "d.", + "serversTabHint": "Select servers available on this tariff.", + "noServersAvailable": "No servers available", + "extraDeviceTitle": "Additional devices", + "devicePriceLabel": "Device price (30 days):", + "devicePriceHint": "0 = device purchase unavailable", + "maxDeviceLabel": "Max. devices on tariff:", + "noLimitHint": "0 = no limits", + "extraTrafficTitle": "Additional traffic", + "trafficMaxLimitLabel": "Max. limit:", + "trafficLimitHint2": "(0 = no limits)", + "trafficPackagesLabel": "Traffic packages:", + "gbPackageUnit": "GB:", + "customDaysTitle": "Custom number of days", + "customDaysDesc": "User selects subscription duration", + "pricePerDayLabel": "Price per day:", + "minDaysLabel": "Min. days:", + "maxDaysLabel": "Max. days:", + "customTrafficTitle": "Custom traffic volume", + "customTrafficDesc": "User selects traffic volume when purchasing", + "pricePerGbLabel": "Price per 1 GB:", + "minTrafficLabel": "Min. GB:", + "maxTrafficLabel": "Max. GB:", + "trafficResetModeTitle": "Traffic reset mode", + "trafficResetModeDesc": "Defines when used traffic resets for subscribers of this tariff", + "resetModeGlobal": "Global setting", + "resetModeGlobalDesc": "Use value from bot config", + "resetModeDaily": "Daily", + "resetModeDailyDesc": "Reset every day", + "resetModeWeekly": "Weekly", + "resetModeWeeklyDesc": "Reset every week", + "resetModeMonthly": "Monthly", + "resetModeMonthlyDesc": "Reset every month", + "resetModeNever": "Never", + "resetModeNeverDesc": "Traffic is not reset", + "cancelButton": "Cancel", + "savingButton": "Saving...", + "saveButton": "Save", + "dailyType": "Daily", + "periodType": "Period-based", + "dailyPriceLabel": "Price per day", + "currencyPerDay": "\u20bd/day", + "dailyDeductionDesc": "Charged daily from user's balance" }, "servers": { "title": "Server Management", @@ -935,6 +1223,426 @@ "disable": "Disable", "toggleTrial": "Toggle Trial", "loadError": "Failed to load server" + }, + "campaigns": { + "title": "Ad Campaigns", + "subtitle": "Manage advertising links", + "createButton": "Create", + "noData": "No ad campaigns", + "bonusType": { + "balance": "Balance", + "subscription": "Subscription", + "tariff": "Tariff", + "none": "Link only" + }, + "overview": { + "totalCampaigns": "Total campaigns", + "active": "Active", + "registrations": "Registrations", + "bonusesIssued": "Bonuses issued" + }, + "table": { + "inactive": "Inactive", + "registrations": "{{count}} registrations", + "revenue": "{{amount}} revenue", + "conversion": "{{rate}}% conversion", + "statistics": "Statistics", + "deactivate": "Deactivate", + "activate": "Activate", + "edit": "Edit", + "delete": "Delete" + }, + "modal": { + "editTitle": "Edit Campaign", + "createTitle": "New Campaign", + "close": "Close" + }, + "form": { + "name": "Name", + "namePlaceholder": "E.g.: Instagram Ad", + "startParameter": "Label (start parameter)", + "startParameterHint": "Latin letters, digits, _ and - only", + "bonusType": "Bonus type", + "balanceBonus": "Balance bonus", + "trialSubscription": "Trial subscription", + "days": "Days", + "trafficGb": "Traffic (GB)", + "devices": "Devices", + "servers": "Servers", + "tariff": "Tariff", + "selectTariff": "Select tariff", + "notSelected": "Not selected", + "tariffOption": "{{traffic}} GB, {{devices}} dev.", + "durationDays": "Duration (days)", + "noBonusDescription": "Campaign without bonuses — only for tracking clicks and registrations.", + "active": "Active", + "cancel": "Cancel", + "save": "Save", + "saving": "Saving..." + }, + "stats": { + "registrations": "Registrations", + "revenue": "Revenue", + "paidUsers": "Paid", + "conversion": "Conversion", + "bonusesIssued": "Bonuses issued", + "subscriptionsIssued": "{{count}} subscriptions", + "tariffsIssued": "{{count}} tariffs", + "avgRevenuePerUser": "Avg revenue per user", + "avgFirstPayment": "Avg first payment", + "trialSubscriptions": "Trial subscriptions", + "trialCount": "{{total}} (active: {{active}})", + "trialConversion": "Trial conversion", + "lastRegistration": "Last registration", + "active": "Active", + "inactive": "Inactive", + "copy": "Copy", + "copied": "Copied!", + "users": "Users" + }, + "users": { + "title": "Campaign Users", + "campaignRegistrations": "{{name}} — {{count}} registrations", + "noUsers": "No registered users", + "user": "User", + "bonus": "Bonus", + "balance": "Balance", + "status": "Status", + "date": "Date", + "noName": "No name", + "paid": "Paid", + "prev": "Prev", + "next": "Next", + "pageOf": "{{page}} of {{totalPages}}" + }, + "confirm": { + "deleteTitle": "Delete campaign?", + "deleteText": "This action cannot be undone. Campaigns with registrations cannot be deleted.", + "cancel": "Cancel", + "delete": "Delete" + } + }, + "promocodes": { + "title": "Promo Codes", + "subtitle": "Manage promo codes and discount groups", + "addPromocode": "Add promo code", + "addGroup": "Add group", + "noPromocodes": "No promo codes", + "noGroups": "No discount groups", + "firstPurchase": "First purchase", + "used": "Used", + "until": "Until", + "discountForHours": "-{{percent}}% for {{hours}}h", + "tabs": { + "promocodes": "Promo codes ({{count}})", + "groups": "Discount groups ({{count}})" + }, + "type": { + "balance": "Balance", + "subscriptionDays": "Subscription days", + "trialSubscription": "Trial subscription", + "promoGroup": "Discount group", + "discount": "Discount %" + }, + "modal": { + "editPromocode": "Edit promo code", + "newPromocode": "New promo code", + "editGroup": "Edit group", + "newGroup": "New discount group", + "close": "Close", + "edit": "Edit" + }, + "form": { + "code": "Promo code", + "type": "Promo code type", + "typeBalance": "Balance top-up", + "typeSubscriptionDays": "Subscription days", + "typeTrialSubscription": "Trial subscription", + "typePromoGroup": "Discount group", + "typeDiscount": "Percentage discount", + "bonusAmount": "Bonus amount", + "rub": "RUB", + "daysCount": "Number of days", + "days": "days", + "discountGroup": "Discount group", + "selectGroup": "Select group...", + "discountPercent": "Discount percent", + "discountHint": "Discount is applied once at payment", + "validityPeriod": "Validity period", + "hours": "hours", + "validityHint": "How many hours after activation the discount is valid", + "maxUses": "Max uses", + "unlimitedHint": "0 = unlimited", + "validUntil": "Valid until", + "validUntilHint": "Leave empty for unlimited promo code", + "active": "Active", + "firstPurchaseOnly": "First purchase only", + "cancel": "Cancel", + "saving": "Saving...", + "save": "Save" + }, + "stats": { + "totalUses": "Total uses", + "today": "Today", + "remaining": "Remaining", + "details": "Promo code details", + "type": "Type", + "bonus": "Bonus", + "daysLabel": "Days", + "discountLabel": "Discount", + "validFor": "Valid for", + "hoursValue": "{{count}} hours", + "limit": "Limit", + "status": "Status", + "active": "Active", + "inactive": "Inactive", + "created": "Created", + "validUntil": "Valid until", + "unlimited": "Unlimited", + "restriction": "Restriction", + "firstPurchaseOnly": "First purchase only", + "usageHistory": "Usage history", + "noUsages": "Promo code has not been used yet", + "totalPromocodes": "Total promo codes", + "activeCount": "Active", + "usagesCount": "Uses", + "exhausted": "Exhausted" + }, + "actions": { + "stats": "Statistics", + "edit": "Edit", + "delete": "Delete" + }, + "groups": { + "name": "Group name", + "namePlaceholder": "VIP clients", + "categoryDiscounts": "Category discounts", + "servers": "Servers", + "traffic": "Traffic", + "devices": "Devices", + "periodDiscounts": "Period discounts", + "add": "Add", + "periodDiscountsHint": "Discount is applied when purchasing a subscription for the specified number of days", + "noPeriodDiscounts": "No period discounts", + "daysPlaceholder": "Days", + "daysArrow": "days →", + "autoAssign": "Auto-assign when spending from", + "autoAssignHint": "0 = do not assign automatically", + "applyToAddons": "Apply to additional services", + "default": "Default", + "daysShort": "{{days}} d.", + "autoFrom": "Auto from {{amount}} RUB", + "members": "{{count}} members" + }, + "confirm": { + "deletePromocode": "Delete promo code?", + "deleteGroup": "Delete group?", + "deletePromocodeText": "The promo code will be permanently deleted.", + "deleteGroupText": "The group will be deleted. Users will lose discounts from this group.", + "deleteButton": "Delete" + } + }, + "users": { + "title": "Users", + "subtitle": "Bot user management", + "search": "Search by ID, name, username...", + "noData": "No users found", + "purchaseCount": "{{count}} purchases", + "noPurchases": "No purchases", + "stats": { + "total": "Total", + "active": "Active", + "withSubscription": "With subscription", + "newToday": "New today", + "blocked": "Blocked" + }, + "status": { + "active": "Active", + "blocked": "Blocked", + "deleted": "Deleted", + "subscription": "Subscription", + "trial": "Trial", + "expired": "Expired" + }, + "filters": { + "allStatuses": "All statuses", + "byDate": "By date", + "byBalance": "By balance", + "byActivity": "By activity", + "bySpent": "By spending" + }, + "pagination": { + "showing": "Showing {{from}}-{{to}} of {{total}}" + }, + "actions": { + "block": "Block", + "unblock": "Unblock", + "apply": "Apply", + "applying": "Applying..." + }, + "confirm": { + "block": "Block this user?" + }, + "detail": { + "tabs": { + "info": "Information", + "subscription": "Subscription", + "balance": "Balance", + "sync": "Synchronization" + }, + "status": "Status", + "language": "Language", + "registration": "Registration", + "lastActivity": "Last activity", + "totalSpent": "Total spent", + "purchases": "Purchases", + "referral": { + "title": "Referral program", + "referrals": "Referrals", + "earned": "Earned", + "commission": "Commission" + }, + "restrictions": { + "title": "Restrictions", + "topup": "• Top-up prohibited", + "subscription": "• Subscription purchase prohibited", + "reason": "Reason" + }, + "subscription": { + "current": "Current subscription", + "tariff": "Tariff", + "notSpecified": "Not specified", + "validUntil": "Valid until", + "traffic": "Traffic", + "devices": "Devices", + "actions": "Actions", + "extend": "Extend", + "changeTariff": "Change tariff", + "cancel": "Cancel", + "activate": "Activate", + "days": "Days", + "selectTariff": "Select tariff", + "unavailable": "(unavailable)", + "noActive": "No active subscription", + "create": "Create subscription", + "creating": "Creating..." + }, + "balance": { + "current": "Current balance", + "amountPlaceholder": "Amount in rubles", + "descriptionPlaceholder": "Description (optional)", + "add": "Add", + "subtract": "Deduct", + "addByAdmin": "Added by admin", + "subtractByAdmin": "Deducted by admin", + "recentTransactions": "Recent transactions" + }, + "sync": { + "hasDifferences": "Differences found", + "synced": "Synchronized", + "bot": "Bot", + "panel": "Panel", + "statusLabel": "Status", + "until": "Until", + "traffic": "Traffic", + "devices": "Devices", + "squads": "Squads", + "notLinked": "Not linked", + "fromPanel": "From panel to bot", + "toPanel": "From bot to panel" + } + } + }, + "promoOffers": { + "title": "Promo Offers", + "subtitle": "Templates, broadcasts and offer logs", + "sendButton": "Send", + "tabs": { + "templates": "Templates ({{count}})", + "logs": "Logs" + }, + "noData": { + "templates": "No templates", + "logs": "No records" + }, + "status": { + "active": "Active", + "inactive": "Inactive" + }, + "table": { + "discount": "Discount", + "offerDuration": "Offer duration", + "hoursShort": "{{hours}}h", + "discountDuration": "Discount duration", + "testAccess": "Test access" + }, + "form": { + "editTemplate": "Edit template", + "templateName": "Template name", + "messageText": "Message text", + "buttonText": "Button text", + "validHours": "Offer duration (hours)", + "activationTime": "Time to activate", + "discountPercent": "Discount (%)", + "testDurationHours": "Access duration (hours)", + "defaultZero": "0 = default", + "activeDiscountHours": "Discount validity (hours)", + "discountDurationHint": "How long the discount lasts after activation", + "templateActive": "Template active", + "saving": "Saving..." + }, + "send": { + "title": "Send promo offer", + "offerTemplate": "Offer template", + "discountLabel": "{{percent}}% discount", + "hoursToActivate": "{{hours}}h to activate", + "sendTo": "Send to", + "segment": "Segment", + "user": "User", + "userIdPlaceholder": "Telegram ID or User ID", + "preview": "Preview", + "sending": "Sending...", + "sendButton": "Send" + }, + "result": { + "sentTitle": "Sent!", + "offersCreated": "Offers created: {{count}}", + "notificationsSent": "Notifications sent: {{count}}", + "notificationsFailed": "(failed: {{count}})", + "sendError": "Failed to send offer" + }, + "actions": { + "created": "Created", + "claimed": "Claimed", + "consumed": "Consumed", + "disabled": "Disabled" + }, + "segments": { + "all": "All users", + "active": "Active subscribers", + "trial": "Trial users", + "trialEnding": "Trial ending", + "expiring": "Subscription expiring", + "expired": "Expired subscription", + "zero": "Zero balance", + "autopayFailed": "Autopay failed", + "lowBalance": "Low balance", + "inactive30d": "Inactive 30 days", + "inactive60d": "Inactive 60 days", + "inactive90d": "Inactive 90 days", + "customToday": "Registered today", + "customWeek": "Registered this week", + "customMonth": "Registered this month", + "customActiveToday": "Active today" + }, + "offerType": { + "testAccess": "Test access", + "testAccessDesc": "Temporary access to additional servers", + "extendDiscount": "Renewal discount", + "extendDiscountDesc": "Discount for current subscribers", + "purchaseDiscount": "Purchase discount", + "purchaseDiscountDesc": "Discount for new users" + } } }, "adminDashboard": { @@ -960,7 +1668,39 @@ "usersOnline": "Online", "traffic": "Traffic", "enable": "Enable", - "disable": "Disable" + "disable": "Disable", + "hide": "Hide ({{count}})", + "showMore": "Show {{count}} more nodes" + }, + "topReferrers": { + "title": "Top referrers", + "stats": "ref., {{count}} invites", + "byEarnings": "By earnings", + "byInvited": "By invites", + "invites": "invites", + "people": "people" + }, + "period": { + "today": "Today", + "week": "Week", + "month": "Month" + }, + "topCampaigns": { + "title": "Top campaign links", + "stats": "camp., {{count}} reg.", + "total": "Total from campaigns" + }, + "recentPayments": { + "title": "Recent payments", + "today": "Today: {{amount}}", + "week": "For the week: {{amount}}" + }, + "table": { + "user": "User", + "type": "Type", + "amount": "Amount", + "method": "Method", + "date": "Date" }, "revenue": { "title": "Revenue", @@ -1001,6 +1741,7 @@ "banSystem": { "title": "Ban Monitoring", "subtitle": "BedolagaBan system management", + "contactTelegram": "Write in Telegram", "notConfigured": "Ban system is not configured", "configureHint": "Set BAN_SYSTEM_API_URL and BAN_SYSTEM_API_TOKEN in configuration", "loadError": "Failed to load data", @@ -1355,6 +2096,8 @@ "error": "Failed to load contests", "noContests": "No contests available", "days": "days", + "days_one": "{{count}} day", + "days_other": "{{count}} days", "play": "Play", "alreadyPlayed": "Already played", "enterAnswer": "Enter your answer", @@ -1366,6 +2109,8 @@ "error": "Failed to load polls", "noPolls": "No polls available", "questions": "questions", + "questions_one": "{{count}} question", + "questions_other": "{{count}} questions", "question": "Question", "of": "of", "start": "Start", @@ -1439,8 +2184,54 @@ "days": "d", "hours": "h", "minutes": "m" + }, + "offers": { + "expired": "Expired", + "testAccess": "Test access", + "discountPercent": "{{percent}}% off", + "specialOffer": "Special offer", + "serverAccess_one": "Access to {{count}} server", + "serverAccess_other": "Access to {{count}} servers", + "additionalServers": "Access to additional servers", + "activateDiscountHint": "Activate discount on subscription purchase", + "activationFailed": "Failed to activate offer", + "discountActiveTitle": "{{percent}}% discount active", + "statusActive": "Active", + "expires": "Expires: {{time}}", + "remaining": "Remaining: {{time}}", + "test": "Test", + "activating": "Activating...", + "activate": "Activate", + "serverAccess": "Server access" } }, + "telegramRedirect": { + "maxRetries": "Maximum retry attempts exceeded. Please try again later.", + "redirecting": "Redirecting...", + "loginAlternative": "Sign in another way", + "openInTelegram": "Open in Telegram", + "openInTelegramDesc": "To sign in automatically, open this app through the Telegram bot", + "redirectToLogin": "Redirecting to login page..." + }, + "deepLink": { + "connecting": "Connecting to", + "redirecting": "Redirecting in", + "seconds": "sec", + "manual": "If nothing happens, click the button below.", + "openApp": "Open App", + "copyLink": "Copy subscription link", + "copied": "Copied!", + "tryAgain": "Try again", + "backToCabinet": "Back to cabinet", + "errorTitle": "Error", + "errorDesc": "Connection link is missing", + "goToSubscription": "Go to subscription", + "howToAdd": "How to add manually:", + "step1": "Copy the link using the button above", + "step2": "Open the app", + "step3": "Find \"+\" or \"Add subscription\"", + "step4": "Select \"From clipboard\" or \"Paste link\"" + }, "blocking": { "maintenance": { "title": "Maintenance", diff --git a/src/locales/fa.json b/src/locales/fa.json index 6e008b2..4df6626 100644 --- a/src/locales/fa.json +++ b/src/locales/fa.json @@ -1,6 +1,7 @@ { "common": { "loading": "در حال بارگذاری...", + "all": "همه", "error": "خطا", "success": "موفق", "save": "ذخیره", @@ -18,7 +19,16 @@ "and": "و", "edit": "ویرایش", "delete": "حذف", - "currency": "تومان" + "currency": "تومان", + "copy": "کپی", + "units": { + "gb": "GB", + "perGb": "/GB" + }, + "add": "افزودن", + "refresh": "بازخوانی", + "retry": "تلاش مجدد", + "saving": "در حال ذخیره..." }, "nav": { "dashboard": "داشبورد", @@ -31,7 +41,8 @@ "contests": "مسابقات", "polls": "نظرسنجی", "info": "اطلاعات", - "wheel": "چرخ شانس" + "wheel": "چرخ شانس", + "menu": "منو" }, "notifications": { "ticketNotifications": "اعلانهای تیکت", @@ -80,7 +91,20 @@ "verificationSent": "لینک تایید به این آدرس ارسال شد:", "clickLinkToVerify": "روی لینک موجود در ایمیل کلیک کنید تا حساب خود را تایید و وارد شوید.", "backToLogin": "بازگشت به ورود", - "emailNotVerified": "لطفاً ابتدا ایمیل خود را تایید کنید" + "emailNotVerified": "لطفاً ابتدا ایمیل خود را تایید کنید", + "emailAlreadyRegistered": "این ایمیل قبلاً ثبت شده", + "firstName": "نام", + "firstNamePlaceholder": "نام شما (اختیاری)", + "forgotPasswordHint": "ایمیل خود را وارد کنید تا لینک بازنشانی دریافت کنید", + "invalidCredentials": "ایمیل یا رمز عبور نامعتبر", + "invalidEmail": "لطفاً یک آدرس ایمیل معتبر وارد کنید", + "loginSuccess": "ورود موفق", + "passwordMismatch": "رمزهای عبور مطابقت ندارند", + "passwordResetSent": "لینک بازنشانی رمز عبور به ایمیل شما ارسال شد", + "passwordTooShort": "رمز عبور باید حداقل ۸ کاراکتر باشد", + "sendResetLink": "ارسال لینک بازنشانی", + "tooManyAttempts": "تلاشهای زیاد. لطفاً بعداً امتحان کنید", + "verificationEmailNotice": "پس از ثبت نام، ایمیل تأیید به آدرس شما ارسال خواهد شد" }, "emailVerification": { "title": "تایید ایمیل", @@ -119,10 +143,13 @@ "expiresAt": "تاریخ انقضا", "daysLeft": "روز باقیمانده", "devices": "دستگاهها", + "devices_other": "{{count}} دستگاه", "extraDevices": "دستگاههای اضافی", "extraDevicesIncluded": "شامل {{count}} دستگاه اضافی", + "extraDevicesIncluded_other": "شامل {{count}} دستگاه اضافی", "baseTariff": "تعرفه", - "servers": "سرورها", + "serversLabel": "سرورها", + "servers_other": "{{count}} سرور", "traffic": "ترافیک", "unlimited": "نامحدود", "used": "استفاده شده", @@ -133,8 +160,11 @@ "buyDevices": "خرید دستگاه", "renewalOptions": "گزینههای تمدید", "days": "روز", + "days_other": "{{count}} روز", "hours": "ساعت", + "hours_other": "{{count}} ساعت", "minutes": "دقیقه", + "minutes_other": "{{count}} دقیقه", "price": "قیمت", "noSubscription": "اشتراک فعال ندارید", "getSubscription": "خرید اشتراک", @@ -148,6 +178,7 @@ "getConfig": "اتصال دستگاهها", "autoRenewal": "تمدید خودکار", "daysBeforeExpiry": "روز قبل از انقضا", + "daysBeforeExpiry_other": "{{count}} روز قبل از انقضا", "selectPeriod": "انتخاب دوره", "selectTraffic": "انتخاب ترافیک", "selectServers": "انتخاب سرورها", @@ -166,7 +197,9 @@ "title": "دوره آزمایشی رایگان", "description": "سرویس VPN ما را رایگان امتحان کنید!", "days": "روز", + "days_other": "{{count}} روز", "devices": "دستگاه", + "devices_other": "{{count}} دستگاه", "price": "هزینه فعالسازی", "activate": "فعالسازی دوره آزمایشی", "unavailable": "دوره آزمایشی در دسترس نیست" @@ -191,6 +224,110 @@ "selectPlatform": "انتخاب پلتفرم", "app": "برنامه", "apps": "برنامه" + }, + "additionalOptions": { + "title": "گزینههای اضافی", + "buyDevices": "خرید دستگاه بیشتر", + "currentDeviceLimit": "محدودیت فعلی: {{count}} دستگاه", + "devicesUnavailable": "خرید دستگاه در دسترس نیست", + "devicesUnit": "دستگاه", + "buy": "خرید", + "buyTraffic": "خرید ترافیک بیشتر", + "currentTrafficLimit": "محدودیت فعلی: {{limit}} GB (مصرف شده {{used}} GB)", + "buyTrafficTitle": "خرید ترافیک بیشتر", + "trafficWarning": "ترافیک خریداری شده به محدودیت فعلی اضافه میشود و به دوره بعدی منتقل نمیشود", + "trafficUnavailable": "خرید ترافیک برای اشتراک شما در دسترس نیست", + "unlimited": "نامحدود", + "buyTrafficGb": "خرید {{gb}} GB", + "manageServers": "مدیریت سرورها", + "manageServersTitle": "مدیریت سرورها" + }, + "serverManagement": { + "statusLegend": "✅ — متصل • ➕ — اضافه خواهد شد (پولی) • ➖ — قطع خواهد شد", + "discountBanner": "تخفیف سرور شما: -{{percent}}%", + "forDays": "(برای {{days}} روز)", + "perMonth": "/ماه", + "unavailable": "در دسترس نیست", + "toAdd": "اضافه کردن:", + "toDisconnect": "قطع کردن:", + "paymentProrated": "پرداخت (متناسب با روزهای باقیمانده):", + "applyChanges": "اعمال تغییرات", + "selectServersHint": "سرورها را برای اتصال یا قطع انتخاب کنید", + "noServersAvailable": "سرور قابل مدیریتی وجود ندارد" + }, + "legacy": { + "selectTariffTitle": "یک تعرفه برای تمدید انتخاب کنید", + "selectTariffDescription": "اشتراک فعلی شما قبل از معرفی تعرفهها ایجاد شده بود. برای تمدید، لطفاً یکی از تعرفههای موجود را انتخاب کنید.", + "currentSubContinues": "اشتراک فعلی شما تا پایان مدت فعال باقی خواهد ماند." + }, + "switchTariff": { + "dailyPayment": "پرداخت روزانه", + "dailyChargeDescription": "روزانه از موجودی کسر میشود", + "currentTariff": "تعرفه فعلی", + "free": "رایگان", + "newTariff": "تعرفه جدید", + "remainingDays": "روزهای باقیمانده", + "switch": "تغییر", + "title": "تغییر تعرفه", + "upgradeCost": "هزینه ارتقا" + }, + "promoGroup": { + "yourGroup": "گروه شما: {{name}}", + "personalDiscountsApplied": "تخفیفهای شخصی بر قیمتها اعمال شده است" + }, + "tariff": { + "perDay": "/ روز", + "flexiblePayment": "پرداخت انعطافپذیر", + "selectForRenewal": "انتخاب برای تمدید" + }, + "customDays": { + "title": "تعداد روز سفارشی", + "perDay": "/روز" + }, + "customTraffic": { + "label": "ترافیک", + "selectVolume": "انتخاب حجم ترافیک", + "default": "پیشفرض: {{label}}" + }, + "summary": { + "period": "دوره: {{label}}", + "traffic": "ترافیک: {{gb}} GB" + }, + "confirmDeleteAllDevices": "همه دستگاهها حذف شوند؟", + "confirmDeleteDevice": "این دستگاه حذف شود؟", + "currentTariff": "فعلی", + "deleteAllDevices": "حذف همه", + "deleteDevice": "حذف دستگاه", + "devicesFree": "دستگاه رایگان", + "from": "از", + "month": "ماه", + "myDevices": "دستگاههای من", + "noDevices": "هیچ دستگاه متصلی نیست", + "perExtraDevice": "/ دستگاه اضافی", + "perMonth": "/ماه", + "purchasedTraffic": "ترافیک خریداری شده", + "trafficResetAt": "بازنشانی", + "dailyPurchase": { + "activate": "فعالسازی با {{price}}", + "canPause": "میتواند در هر زمان متوقف شود", + "chargedDaily": "هر روز از موجودی کسر میشود", + "costPerDay": "هزینه روزانه", + "pausedOnLowBalance": "با کمبود موجودی اشتراک متوقف میشود" + }, + "pause": { + "active": "فعال", + "days": "روز", + "hours": "ساعت", + "insufficientBalance": "موجودی ناکافی برای بازگرداندن اشتراک", + "minutes": "دقیقه", + "nextCharge": "تا کسر بعدی", + "pauseBtn": "توقف", + "paused": "متوقف شده", + "pausedDescription": "کسر متوقف شد. اشتراک فعال خواهد بود تا", + "pausedInfo": "اشتراک متوقف شده", + "resumeBtn": "ادامه", + "title": "توقف اشتراک", + "willBeCharged": "کسر خواهد شد" } }, "balance": { @@ -247,7 +384,25 @@ } }, "minAmountError": "حداقل مبلغ: {{amount}}", - "maxAmountError": "حداکثر مبلغ: {{amount}}" + "maxAmountError": "حداکثر مبلغ: {{amount}}", + "paymentReady": "لینک پرداخت آماده است", + "clickToOpenPayment": "دکمه زیر را بزنید تا صفحه پرداخت در تب جدید باز شود", + "openPaymentPage": "باز کردن صفحه پرداخت", + "errors": { + "noPaymentLink": "سرور لینک پرداخت را برنگرداند", + "starsOnlyInTelegram": "پرداخت Stars فقط در Telegram Mini App در دسترس است", + "generic": "خطا: {{details}}", + "invoiceFailed": "ایجاد فاکتور ناموفق بود", + "rateLimit": "لطفاً {{seconds}} ثانیه صبر کنید", + "selectMethod": "روش را انتخاب کنید", + "enterAmount": "مبلغ را وارد کنید", + "amountRange": "مبلغ: {{min}} – {{max}} ₽" + }, + "insufficientFunds": "موجودی ناکافی", + "missing": "کمبود", + "noPaymentMethods": "روش پرداخت در دسترس نیست", + "selectPaymentMethod": "روش پرداخت را انتخاب کنید", + "topUpToComplete": "برای تکمیل خرید شارژ کنید" }, "referral": { "title": "برنامه معرفی", @@ -321,7 +476,13 @@ "invalidFileType": "نوع فایل نامعتبر. از JPEG، PNG، GIF یا WebP استفاده کنید.", "fileTooLarge": "فایل خیلی بزرگ است. حداکثر 10MB.", "uploadFailed": "آپلود تصویر ناموفق", - "imageLoadFailed": "بارگذاری تصویر ناموفق" + "imageLoadFailed": "بارگذاری تصویر ناموفق", + "tooManyRequests": "درخواستهای زیادی ارسال شده. لطفاً {{seconds}} ثانیه صبر کنید.", + "contactSupport": "برای پشتیبانی با {{username}} تماس بگیرید", + "contactUs": "تماس با پشتیبانی", + "openSupport": "باز کردن پشتیبانی", + "ticketsDisabled": "تیکتها غیرفعال است", + "useExternalLink": "لطفاً از لینک خارجی برای دریافت پشتیبانی استفاده کنید" }, "wheel": { "title": "چرخ شانس", @@ -331,6 +492,7 @@ "stars": "Stars", "telegramStars": "Telegram Stars", "days": "روز", + "days_other": "{{count}} روز", "subscriptionDays": "روز اشتراک", "day": "روز", "spin": "بچرخان!", @@ -348,7 +510,8 @@ "dailyLimitReached": "به محدودیت روزانه رسیدید", "cannotSpin": "فعلاً امکان چرخش نیست", "insufficientBalance": "موجودی کافی نیست", - "topUpRequired": "برای پرداخت شارژ کنید" + "topUpRequired": "برای پرداخت شارژ کنید", + "starsNotAvailable": "پرداخت Stars در دسترس نیست. برنامه را از طریق تلگرام باز کنید." }, "payWithStars": "پرداخت {stars} Stars", "processingPayment": "در حال پردازش...", @@ -359,7 +522,11 @@ "title": "شانس خود را امتحان کنید!", "description": "چرخ را بچرخانید و جایزه ببرید: روز اشتراک، موجودی، ترافیک و بیشتر!", "button": "برو به چرخ" - } + }, + "noPrize": "این بار شانس نیاوردید...", + "payWithDays": "پرداخت با روز", + "starsPaymentSuccessCheckHistory": "پرداخت موفق! تاریخچه یا تلگرام را بررسی کنید.", + "youWon": "شما برنده شدید" }, "admin": { "nav": { @@ -373,7 +540,14 @@ "servers": "سرورها", "broadcasts": "پیامرسانی", "emailTemplates": "قالبهای ایمیل", - "paymentMethods": "روشهای پرداخت" + "paymentMethods": "روشهای پرداخت", + "banSystem": "نظارت بر مسدودسازی", + "campaigns": "کمپینها", + "payments": "پرداختها", + "promoOffers": "پیشنهادات تبلیغاتی", + "promocodes": "کدهای تخفیف", + "remnawave": "RemnaWave", + "users": "کاربران" }, "panel": { "title": "پنل مدیریت", @@ -387,7 +561,14 @@ "serversDesc": "تنظیم سرورهای VPN", "broadcastsDesc": "ارسال پیام گروهی به کاربران", "emailTemplatesDesc": "مدیریت قالبهای اعلان ایمیل", - "paymentMethodsDesc": "تنظیم و ترتیب روشهای پرداخت" + "paymentMethodsDesc": "تنظیم و ترتیب روشهای پرداخت", + "banSystemDesc": "نظارت بر مسدودسازی و تخلفات", + "campaignsDesc": "کمپینهای تبلیغاتی", + "paymentsDesc": "تأیید پرداخت", + "promoOffersDesc": "تخفیفهای شخصی", + "promocodesDesc": "مدیریت کدهای تخفیف", + "remnawaveDesc": "مدیریت پنل و آمار", + "usersDesc": "مدیریت کاربران ربات" }, "emailTemplates": { "title": "قالبهای ایمیل", @@ -464,14 +645,15 @@ "targetRtp": "هدف", "prizeDistribution": "توزیع جوایز", "times": "بار", + "times_other": "{{count}} بار", "topWins": "برترین برندهها" } }, "broadcasts": { - "title": "پیامرسانی", - "subtitle": "ارسال پیام گروهی به کاربران", + "title": "نشریات", + "subtitle": "تاریخچه و مدیریت", "create": "ایجاد پیام", - "empty": "هنوز پیامی ارسال نشده", + "empty": "هیچ نشریهای نیست", "selectFilter": "انتخاب مخاطبین", "selectFilterPlaceholder": "انتخاب فیلتر...", "recipients": "نفر", @@ -491,7 +673,41 @@ "failed": "ناموفق", "filter": "فیلتر", "message": "پیام", - "unknownAdmin": "مدیر ناشناس" + "unknownAdmin": "نامعلوم", + "prev": "قبلی", + "next": "بعدی", + "status": { + "queued": "در صف", + "inProgress": "در حال ارسال", + "completed": "تکمیل شد", + "partial": "جزئی", + "failed": "ناموفق", + "cancelled": "لغو شده", + "cancelling": "در حال لغو" + }, + "filterGroups": { + "basic": "پایه", + "subscription": "بر اساس اشتراک", + "traffic": "بر اساس ترافیک", + "registration": "بر اساس ثبت نام", + "activity": "بر اساس فعالیت", + "source": "بر اساس منبع", + "tariff": "بر اساس تعرفه" + } + }, + "payments": { + "title": "تأیید پرداخت", + "description": "پرداختهای معلق در ۲۴ ساعت گذشته", + "totalPending": "کل معلق", + "filterByMethod": "فیلتر بر اساس روش", + "paid": "پرداخت شده", + "user": "کاربر", + "openLink": "باز کردن لینک", + "checking": "در حال بررسی...", + "checkStatus": "بررسی وضعیت", + "noPayments": "هیچ پرداخت معلقی نیست", + "prev": "قبلی", + "next": "بعدی" }, "settings": { "title": "تنظیمات سیستم", @@ -525,7 +741,49 @@ "conversionLabel": "برچسب تبدیل (اختیاری)", "googleLabelPlaceholder": "مثال: AbCdEfGhIjKl", "googleLabelHint": "برچسب تبدیل برای ردیابی رویدادها", - "analyticsHint": "شمارندهها بهصورت خودکار در تمام صفحات تعبیه میشوند. پس از ذخیره شناسه، اسکریپتها در بارگذاری بعدی صفحه فعال میشوند. برای حذف شمارنده، فیلد را خالی کنید و ذخیره کنید." + "analyticsHint": "شمارندهها بهصورت خودکار در تمام صفحات تعبیه میشوند. پس از ذخیره شناسه، اسکریپتها در بارگذاری بعدی صفحه فعال میشوند. برای حذف شمارنده، فیلد را خالی کنید و ذخیره کنید.", + "inputPlaceholder": "مقدار را وارد کنید...", + "ctrlEnterHint": "Ctrl+Enter برای ذخیره", + "cancelButton": "لغو", + "saveButton": "ذخیره", + "saveHint": "ذخیره (Enter)", + "cancelHint": "لغو (Esc)", + "removeFromFavorites": "حذف از علاقهمندیها", + "addToFavorites": "افزودن به علاقهمندیها", + "enabled": "فعال", + "disabled": "غیرفعال", + "foundCount": "یافت شده: {{count}}", + "notFound": "چیزی یافت نشد", + "byQuery": "جستجوی «{{query}}»", + "accentColor": "رنگ تأکیدی", + "animatedBackground": "پسزمینه متحرک", + "animatedBackgroundDesc": "نمایش جلوههای پسزمینه متحرک", + "autoFullscreen": "تمام صفحه خودکار", + "autoFullscreenDesc": "باز شدن خودکار در تلگرام", + "availableThemes": "پوستههای موجود", + "colors": { + "background": "پسزمینه", + "error": "خطا", + "success": "موفقیت", + "surface": "سطح", + "text": "متن", + "textSecondary": "متن ثانویه", + "warning": "هشدار" + }, + "customColors": "رنگهای سفارشی", + "darkTheme": "پوسته تیره", + "emailAuth": "احراز هویت ایمیل", + "emailAuthDesc": "اجازه ورود با ایمیل", + "favoritesEmpty": "هنوز علاقهمندی ندارید", + "favoritesHint": "ستاره بزنید تا تنظیمات اینجا اضافه شوند", + "interfaceOptions": "گزینههای رابط کاربری", + "lightTheme": "پوسته روشن", + "logoAndName": "لوگو و نام", + "notSpecified": "مشخص نشده", + "projectName": "نام پروژه", + "quickPresets": "پیشتنظیمهای سریع", + "resetAllColors": "بازنشانی همه رنگها", + "statusColors": "رنگهای وضعیت" }, "apps": { "title": "مدیریت برنامهها", @@ -558,7 +816,23 @@ "subscription": "اشتراک", "connect": "اتصال", "additional": "اضافی" - } + }, + "availableConfigs": "پیکربندیهای موجود", + "confirmImport": "وارد کردن", + "export": "صادر کردن", + "exportApps": "صادر کردن برنامهها به JSON", + "import": "وارد کردن", + "importApps": "وارد کردن برنامهها از JSON", + "importCreateError": "ایجاد برخی برنامهها ناموفق بود", + "importError": "فرمت فایل JSON نامعتبر", + "importPreview": "پیشنمایش وارد کردن", + "noAppsToImport": "هیچ برنامهای برای وارد کردن نیست", + "refreshRemnaWave": "بازخوانی از RemnaWave", + "remnaWaveConfigUuid": "UUID پیکربندی", + "remnaWaveConfigUuidHint": "UUID پیکربندی صفحه اشتراک از پنل RemnaWave", + "remnaWaveMode": "نمایش برنامهها از پنل RemnaWave. حالت فقط خواندنی.", + "remnaWaveSettings": "تنظیمات RemnaWave", + "remnaWaveToggle": "تغییر منبع RemnaWave" }, "tickets": { "title": "مدیریت تیکتها", @@ -594,7 +868,13 @@ "checkIntervalDesc": "چند وقت یکبار تیکتهای معوقه را بررسی کنیم (30-600 ثانیه)", "reminderCooldown": "فاصله یادآوری (دقیقه)", "reminderCooldownDesc": "حداقل زمان بین یادآوریها (1-120 دقیقه)", - "settingsUpdateError": "خطا در ذخیره تنظیمات" + "settingsUpdateError": "خطا در ذخیره تنظیمات", + "adminNotificationsEnabled": "اعلانهای مدیر", + "adminNotificationsEnabledDesc": "ارسال اعلان به مدیران درباره تیکتها و پاسخهای جدید", + "cabinetNotifications": "اعلانهای پنل", + "copyTelegramId": "برای کپی شناسه تلگرام کلیک کنید", + "userNotificationsEnabled": "اعلانهای کاربر", + "userNotificationsEnabledDesc": "ارسال اعلان به کاربران درباره پاسخهای مدیر" }, "tariffs": { "title": "مدیریت تعرفهها", @@ -613,8 +893,11 @@ "tierHint": "1-10، روی اولویت ارتقا تأثیر میگذارد", "unlimited": "نامحدود", "devices": "دستگاه", + "devices_other": "{{count}} دستگاه", "servers": "سرور", + "servers_other": "{{count}} سرور", "subscriptions": "اشتراک", + "subscriptions_other": "{{count}} اشتراک", "trial": "آزمایشی", "inactive": "غیرفعال", "activate": "فعالسازی", @@ -624,6 +907,7 @@ "confirmDelete": "تعرفه حذف شود؟", "confirmDeleteText": "این عمل قابل بازگشت نیست. تعرفه برای همیشه حذف میشود.", "days": "روز", + "days_other": "{{count}} روز", "tabs": { "basic": "اصلی", "prices": "قیمتها", @@ -631,7 +915,81 @@ }, "pricesHint": "قیمت هر دوره را تنظیم کنید", "serversHint": "سرورهای موجود برای این تعرفه را انتخاب کنید", - "noServers": "سرور موجود نیست" + "noServers": "سرور موجود نیست", + "selectType": "نوع تعرفه را انتخاب کنید", + "periodTariff": "تعرفه دورهای", + "periodTariffDesc": "پرداخت برای دوره (7، 30، 90 روز و غیره). دورهها و قیمتهای انعطافپذیر.", + "dailyTariff": "تعرفه روزانه", + "dailyTariffDesc": "کسر روزانه از موجودی. میتواند متوقف شود.", + "editTitle": "ویرایش تعرفه", + "newPeriodTitle": "تعرفه دورهای جدید", + "newDailyTitle": "تعرفه روزانه جدید", + "periodPayment": "پرداخت برای دوره", + "dailyDeduction": "کسر روزانه", + "tabBasic": "پایه", + "tabPeriods": "دورهها", + "tabServers": "سرورها", + "tabExtra": "اضافی", + "nameLabel": "نام تعرفه", + "nameExamplePeriod": "مثال: استاندارد", + "nameExampleDaily": "مثال: روزانه", + "descriptionLabel": "توضیحات", + "descriptionPlaceholder2": "توضیح مختصر تعرفه", + "trafficLimitLabel": "محدودیت ترافیک", + "gbUnit": "GB", + "trafficLimitHint": "0 = ترافیک نامحدود", + "deviceLimitLabel": "دستگاهها در تعرفه", + "tierLevelLabel": "سطح تعرفه", + "tierLevelHint": "بر دسترسی ارتقا بین تعرفهها تأثیر میگذارد", + "periodsTabHint": "دورهها و قیمتها را برای تعرفه اضافه کنید. کاربران میتوانند از دورههای اضافه شده انتخاب کنند.", + "addPeriodTitle": "افزودن دوره", + "daysLabel": "روز", + "priceLabel": "قیمت (₽)", + "addButton": "افزودن", + "noPeriodsHint": "هیچ دورهای اضافه نشده. حداقل یک دوره اضافه کنید.", + "daysShort": "روز", + "serversTabHint": "سرورهای موجود در این تعرفه را انتخاب کنید.", + "noServersAvailable": "هیچ سروری در دسترس نیست", + "extraDeviceTitle": "دستگاههای اضافی", + "devicePriceLabel": "قیمت دستگاه (30 روز):", + "devicePriceHint": "0 = خرید دستگاه در دسترس نیست", + "maxDeviceLabel": "حداکثر دستگاه در تعرفه:", + "noLimitHint": "0 = بدون محدودیت", + "extraTrafficTitle": "ترافیک اضافی", + "trafficMaxLimitLabel": "حداکثر محدودیت:", + "trafficLimitHint2": "(0 = بدون محدودیت)", + "trafficPackagesLabel": "بستههای ترافیک:", + "gbPackageUnit": "GB:", + "customDaysTitle": "تعداد روزهای سفارشی", + "customDaysDesc": "کاربر مدت اشتراک را انتخاب میکند", + "pricePerDayLabel": "قیمت روزانه:", + "minDaysLabel": "حداقل روز:", + "maxDaysLabel": "حداکثر روز:", + "customTrafficTitle": "حجم ترافیک سفارشی", + "customTrafficDesc": "کاربر هنگام خرید حجم ترافیک را انتخاب میکند", + "pricePerGbLabel": "قیمت هر GB:", + "minTrafficLabel": "حداقل GB:", + "maxTrafficLabel": "حداکثر GB:", + "trafficResetModeTitle": "حالت بازنشانی ترافیک", + "trafficResetModeDesc": "تعریف میکند که ترافیک استفاده شده مشترکین این تعرفه چه زمانی بازنشانی میشود", + "resetModeGlobal": "تنظیم جهانی", + "resetModeGlobalDesc": "استفاده از مقدار پیکربندی ربات", + "resetModeDaily": "روزانه", + "resetModeDailyDesc": "بازنشانی هر روز", + "resetModeWeekly": "هفتگی", + "resetModeWeeklyDesc": "بازنشانی هر هفته", + "resetModeMonthly": "ماهانه", + "resetModeMonthlyDesc": "بازنشانی هر ماه", + "resetModeNever": "هرگز", + "resetModeNeverDesc": "ترافیک بازنشانی نمیشود", + "cancelButton": "لغو", + "savingButton": "در حال ذخیره...", + "saveButton": "ذخیره", + "dailyType": "روزانه", + "periodType": "دورهای", + "dailyPriceLabel": "قیمت روزانه", + "currencyPerDay": "₽/روز", + "dailyDeductionDesc": "هر روز از موجودی کاربر کسر میشود" }, "servers": { "title": "مدیریت سرورها", @@ -661,41 +1019,545 @@ "full": "پر", "enable": "فعال", "disable": "غیرفعال", - "toggleTrial": "تغییر آزمایشی" + "toggleTrial": "تغییر آزمایشی", + "loadError": "بارگذاری سرور ناموفق بود" }, "paymentMethods": { "title": "روشهای پرداخت", - "description": "تنظیم ترتیب نمایش و شرایط", - "enabled": "فعال", - "disabled": "غیرفعال", + "description": "پیکربندی ترتیب و شرایط نمایش", + "enabled": "روشن", + "disabled": "خاموش", "notConfigured": "تنظیم نشده", - "dragToReorder": "بکشید برای تغییر ترتیب", - "dragHint": "کارتها را بکشید تا ترتیب تغییر کند. برای تنظیم کلیک کنید.", + "dragToReorder": "برای تغییر ترتیب بکشید", + "dragHint": "کارتها را بکشید تا ترتیب تغییر کند. برای پیکربندی کلیک کنید.", "saveOrder": "ذخیره ترتیب", "orderSaved": "ترتیب ذخیره شد", "saved": "تنظیمات ذخیره شد", - "noMethods": "روش پرداختی تنظیم نشده", - "methodEnabled": "روش فعال شد", + "noMethods": "هیچ روش پرداخت پیکربندیشدهای نیست", + "methodEnabled": "روش فعال است", "providerNotConfigured": "ارائهدهنده در env تنظیم نشده", "displayName": "نام نمایشی", "displayNameHint": "برای نام پیشفرض خالی بگذارید", "subOptions": "گزینههای پرداخت", - "minAmount": "حداقل مبلغ (کوپک)", - "maxAmount": "حداکثر مبلغ (کوپک)", + "minAmount": "حداقل مبلغ (کپک)", + "maxAmount": "حداکثر مبلغ (کپک)", "conditions": "شرایط نمایش", "userTypeFilter": "نوع کاربر", "userTypeAll": "همه", "userTypeTelegram": "تلگرام", "userTypeEmail": "ایمیل", "firstTopupFilter": "اولین شارژ", - "firstTopupAny": "هر کدام", - "firstTopupYes": "انجام شده", - "firstTopupNo": "انجام نشده", + "firstTopupAny": "مهم نیست", + "firstTopupYes": "با شارژ", + "firstTopupNo": "بدون شارژ", + "firstTopupWas": "بوده", + "firstTopupWasNot": "نبوده", "promoGroupFilter": "گروههای تبلیغاتی", "promoGroupAll": "همه گروهها", "promoGroupSelected": "انتخاب شده", "promoGroupsShort": "گروه", - "noPromoGroups": "گروه تبلیغاتی نیست" + "noPromoGroups": "هیچ گروه تبلیغاتی نیست", + "cancelButton": "لغو", + "saveButton": "ذخیره" + }, + "campaigns": { + "title": "کمپینهای تبلیغاتی", + "subtitle": "مدیریت لینکهای تبلیغاتی", + "createButton": "ایجاد", + "noData": "کمپین تبلیغاتی وجود ندارد", + "bonusType": { + "balance": "موجودی", + "subscription": "اشتراک", + "tariff": "تعرفه", + "none": "فقط لینک" + }, + "overview": { + "totalCampaigns": "کل کمپینها", + "active": "فعال", + "registrations": "ثبتنامها", + "bonusesIssued": "پاداشهای صادر شده" + }, + "table": { + "inactive": "غیرفعال", + "registrations": "{{count}} ثبتنام", + "revenue": "{{amount}} درآمد", + "conversion": "{{rate}}% تبدیل", + "statistics": "آمار", + "deactivate": "غیرفعال کردن", + "activate": "فعال کردن", + "edit": "ویرایش", + "delete": "حذف" + }, + "modal": { + "editTitle": "ویرایش کمپین", + "createTitle": "کمپین جدید", + "close": "بستن" + }, + "form": { + "name": "نام", + "namePlaceholder": "مثال: تبلیغات اینستاگرام", + "startParameter": "برچسب (پارامتر start)", + "startParameterHint": "فقط حروف لاتین، اعداد، _ و -", + "bonusType": "نوع پاداش", + "balanceBonus": "پاداش موجودی", + "trialSubscription": "اشتراک آزمایشی", + "days": "روز", + "trafficGb": "ترافیک (GB)", + "devices": "دستگاهها", + "servers": "سرورها", + "tariff": "تعرفه", + "selectTariff": "انتخاب تعرفه", + "notSelected": "انتخاب نشده", + "tariffOption": "{{traffic}} GB، {{devices}} دستگاه", + "durationDays": "مدت (روز)", + "noBonusDescription": "کمپین بدون پاداش — فقط برای ردیابی کلیکها و ثبتنامها.", + "active": "فعال", + "cancel": "لغو", + "save": "ذخیره", + "saving": "در حال ذخیره..." + }, + "stats": { + "registrations": "ثبتنامها", + "revenue": "درآمد", + "paidUsers": "پرداخت کرده", + "conversion": "نرخ تبدیل", + "bonusesIssued": "پاداشهای صادر شده", + "subscriptionsIssued": "{{count}} اشتراک", + "tariffsIssued": "{{count}} تعرفه", + "avgRevenuePerUser": "میانگین درآمد هر کاربر", + "avgFirstPayment": "میانگین اولین پرداخت", + "trialSubscriptions": "اشتراکهای آزمایشی", + "trialCount": "{{total}} (فعال: {{active}})", + "trialConversion": "تبدیل آزمایشی", + "lastRegistration": "آخرین ثبتنام", + "active": "فعال", + "inactive": "غیرفعال", + "copy": "کپی", + "copied": "کپی شد!", + "users": "کاربران" + }, + "users": { + "title": "کاربران کمپین", + "campaignRegistrations": "{{name}} — {{count}} ثبتنام", + "noUsers": "کاربر ثبتنام شدهای وجود ندارد", + "user": "کاربر", + "bonus": "پاداش", + "balance": "موجودی", + "status": "وضعیت", + "date": "تاریخ", + "noName": "بدون نام", + "paid": "پرداخت کرده", + "prev": "قبلی", + "next": "بعدی", + "pageOf": "{{page}} از {{totalPages}}" + }, + "confirm": { + "deleteTitle": "حذف کمپین؟", + "deleteText": "این عمل قابل بازگشت نیست. کمپینهایی که ثبتنام دارند قابل حذف نیستند.", + "cancel": "لغو", + "delete": "حذف" + } + }, + "promocodes": { + "title": "کدهای تخفیف", + "subtitle": "مدیریت کدهای تخفیف و گروههای تخفیف", + "addPromocode": "افزودن کد تخفیف", + "addGroup": "افزودن گروه", + "noPromocodes": "کد تخفیفی وجود ندارد", + "noGroups": "گروه تخفیفی وجود ندارد", + "firstPurchase": "اولین خرید", + "used": "استفاده شده", + "until": "تا", + "discountForHours": "-{{percent}}% برای {{hours}} ساعت", + "tabs": { + "promocodes": "کدهای تخفیف ({{count}})", + "groups": "گروههای تخفیف ({{count}})" + }, + "type": { + "balance": "موجودی", + "subscriptionDays": "روزهای اشتراک", + "trialSubscription": "اشتراک آزمایشی", + "promoGroup": "گروه تخفیف", + "discount": "تخفیف %" + }, + "modal": { + "editPromocode": "ویرایش کد تخفیف", + "newPromocode": "کد تخفیف جدید", + "editGroup": "ویرایش گروه", + "newGroup": "گروه تخفیف جدید", + "close": "بستن", + "edit": "ویرایش" + }, + "form": { + "code": "کد تخفیف", + "type": "نوع کد تخفیف", + "typeBalance": "شارژ موجودی", + "typeSubscriptionDays": "روزهای اشتراک", + "typeTrialSubscription": "اشتراک آزمایشی", + "typePromoGroup": "گروه تخفیف", + "typeDiscount": "تخفیف درصدی", + "bonusAmount": "مبلغ پاداش", + "rub": "روبل", + "daysCount": "تعداد روزها", + "days": "روز", + "discountGroup": "گروه تخفیف", + "selectGroup": "گروه را انتخاب کنید...", + "discountPercent": "درصد تخفیف", + "discountHint": "تخفیف یک بار هنگام پرداخت اعمال میشود", + "validityPeriod": "مدت اعتبار", + "hours": "ساعت", + "validityHint": "تخفیف چند ساعت پس از فعالسازی معتبر است", + "maxUses": "حداکثر استفاده", + "unlimitedHint": "0 = نامحدود", + "validUntil": "معتبر تا", + "validUntilHint": "برای کد تخفیف بدون محدودیت زمانی خالی بگذارید", + "active": "فعال", + "firstPurchaseOnly": "فقط برای اولین خرید", + "cancel": "لغو", + "saving": "در حال ذخیره...", + "save": "ذخیره" + }, + "stats": { + "totalUses": "کل استفادهها", + "today": "امروز", + "remaining": "باقیمانده", + "details": "جزئیات کد تخفیف", + "type": "نوع", + "bonus": "پاداش", + "daysLabel": "روزها", + "discountLabel": "تخفیف", + "validFor": "معتبر برای", + "hoursValue": "{{count}} ساعت", + "limit": "محدودیت", + "status": "وضعیت", + "active": "فعال", + "inactive": "غیرفعال", + "created": "ایجاد شده", + "validUntil": "معتبر تا", + "unlimited": "نامحدود", + "restriction": "محدودیت", + "firstPurchaseOnly": "فقط اولین خرید", + "usageHistory": "تاریخچه استفاده", + "noUsages": "کد تخفیف هنوز استفاده نشده است", + "totalPromocodes": "کل کدهای تخفیف", + "activeCount": "فعال", + "usagesCount": "استفادهها", + "exhausted": "تمام شده" + }, + "actions": { + "stats": "آمار", + "edit": "ویرایش", + "delete": "حذف" + }, + "groups": { + "name": "نام گروه", + "namePlaceholder": "مشتریان VIP", + "categoryDiscounts": "تخفیفهای دستهبندی", + "servers": "سرورها", + "traffic": "ترافیک", + "devices": "دستگاهها", + "periodDiscounts": "تخفیفهای دورهای", + "add": "افزودن", + "periodDiscountsHint": "تخفیف هنگام خرید اشتراک برای تعداد روزهای مشخص شده اعمال میشود", + "noPeriodDiscounts": "تخفیف دورهای وجود ندارد", + "daysPlaceholder": "روز", + "daysArrow": "روز →", + "autoAssign": "تخصیص خودکار هنگام هزینه از", + "autoAssignHint": "0 = تخصیص خودکار نشود", + "applyToAddons": "اعمال به خدمات اضافی", + "default": "پیشفرض", + "daysShort": "{{days}} روز", + "autoFrom": "خودکار از {{amount}} روبل", + "members": "{{count}} عضو" + }, + "confirm": { + "deletePromocode": "کد تخفیف حذف شود؟", + "deleteGroup": "گروه حذف شود؟", + "deletePromocodeText": "کد تخفیف به طور دائم حذف خواهد شد.", + "deleteGroupText": "گروه حذف خواهد شد. کاربران تخفیفهای این گروه را از دست خواهند داد.", + "deleteButton": "حذف" + } + }, + "users": { + "title": "کاربران", + "subtitle": "مدیریت کاربران ربات", + "search": "جستجو بر اساس شناسه، نام، نام کاربری...", + "noData": "کاربری یافت نشد", + "purchaseCount": "{{count}} خرید", + "noPurchases": "بدون خرید", + "stats": { + "total": "کل", + "active": "فعال", + "withSubscription": "دارای اشتراک", + "newToday": "جدید امروز", + "blocked": "مسدود شده" + }, + "status": { + "active": "فعال", + "blocked": "مسدود شده", + "deleted": "حذف شده", + "subscription": "اشتراک", + "trial": "آزمایشی", + "expired": "منقضی شده" + }, + "filters": { + "allStatuses": "همه وضعیتها", + "byDate": "بر اساس تاریخ", + "byBalance": "بر اساس موجودی", + "byActivity": "بر اساس فعالیت", + "bySpent": "بر اساس هزینه" + }, + "pagination": { + "showing": "نمایش {{from}}-{{to}} از {{total}}" + }, + "actions": { + "block": "مسدود کردن", + "unblock": "رفع مسدودیت", + "apply": "اعمال", + "applying": "در حال اعمال..." + }, + "confirm": { + "block": "آیا این کاربر مسدود شود؟" + }, + "detail": { + "tabs": { + "info": "اطلاعات", + "subscription": "اشتراک", + "balance": "موجودی", + "sync": "همگامسازی" + }, + "status": "وضعیت", + "language": "زبان", + "registration": "ثبتنام", + "lastActivity": "آخرین فعالیت", + "totalSpent": "کل هزینه", + "purchases": "خریدها", + "referral": { + "title": "برنامه ارجاع", + "referrals": "ارجاعات", + "earned": "درآمد", + "commission": "کمیسیون" + }, + "restrictions": { + "title": "محدودیتها", + "topup": "• شارژ حساب ممنوع", + "subscription": "• خرید اشتراک ممنوع", + "reason": "دلیل" + }, + "subscription": { + "current": "اشتراک فعلی", + "tariff": "تعرفه", + "notSpecified": "مشخص نشده", + "validUntil": "معتبر تا", + "traffic": "ترافیک", + "devices": "دستگاهها", + "actions": "عملیات", + "extend": "تمدید", + "changeTariff": "تغییر تعرفه", + "cancel": "لغو", + "activate": "فعالسازی", + "days": "روز", + "selectTariff": "تعرفه را انتخاب کنید", + "unavailable": "(غیرقابل دسترس)", + "noActive": "اشتراک فعالی وجود ندارد", + "create": "ایجاد اشتراک", + "creating": "در حال ایجاد..." + }, + "balance": { + "current": "موجودی فعلی", + "amountPlaceholder": "مبلغ به روبل", + "descriptionPlaceholder": "توضیحات (اختیاری)", + "add": "افزودن", + "subtract": "کسر", + "addByAdmin": "افزوده شده توسط مدیر", + "subtractByAdmin": "کسر شده توسط مدیر", + "recentTransactions": "تراکنشهای اخیر" + }, + "sync": { + "hasDifferences": "اختلاف وجود دارد", + "synced": "همگامسازی شده", + "bot": "ربات", + "panel": "پنل", + "statusLabel": "وضعیت", + "until": "تا", + "traffic": "ترافیک", + "devices": "دستگاهها", + "squads": "گروهها", + "notLinked": "متصل نشده", + "fromPanel": "از پنل به ربات", + "toPanel": "از ربات به پنل" + } + } + }, + "promoOffers": { + "title": "پیشنهادات تبلیغاتی", + "subtitle": "قالبها، ارسال گروهی و گزارش پیشنهادات", + "sendButton": "ارسال", + "tabs": { + "templates": "قالبها ({{count}})", + "logs": "گزارشها" + }, + "noData": { + "templates": "قالبی وجود ندارد", + "logs": "رکوردی وجود ندارد" + }, + "status": { + "active": "فعال", + "inactive": "غیرفعال" + }, + "table": { + "discount": "تخفیف", + "offerDuration": "مدت پیشنهاد", + "hoursShort": "{{hours}} ساعت", + "discountDuration": "مدت تخفیف", + "testAccess": "دسترسی آزمایشی" + }, + "form": { + "editTemplate": "ویرایش قالب", + "templateName": "نام قالب", + "messageText": "متن پیام", + "buttonText": "متن دکمه", + "validHours": "مدت پیشنهاد (ساعت)", + "activationTime": "زمان فعالسازی", + "discountPercent": "تخفیف (%)", + "testDurationHours": "مدت دسترسی (ساعت)", + "defaultZero": "0 = پیشفرض", + "activeDiscountHours": "اعتبار تخفیف (ساعت)", + "discountDurationHint": "مدت زمان اعتبار تخفیف پس از فعالسازی", + "templateActive": "قالب فعال", + "saving": "در حال ذخیره..." + }, + "send": { + "title": "ارسال پیشنهاد تبلیغاتی", + "offerTemplate": "قالب پیشنهاد", + "discountLabel": "{{percent}}% تخفیف", + "hoursToActivate": "{{hours}} ساعت برای فعالسازی", + "sendTo": "ارسال به", + "segment": "بخش", + "user": "کاربر", + "userIdPlaceholder": "شناسه تلگرام یا شناسه کاربر", + "preview": "پیشنمایش", + "sending": "در حال ارسال...", + "sendButton": "ارسال" + }, + "result": { + "sentTitle": "ارسال شد!", + "offersCreated": "پیشنهادات ایجاد شده: {{count}}", + "notificationsSent": "اعلانهای ارسال شده: {{count}}", + "notificationsFailed": "(ناموفق: {{count}})", + "sendError": "ارسال پیشنهاد ناموفق بود" + }, + "actions": { + "created": "ایجاد شده", + "claimed": "فعال شده", + "consumed": "استفاده شده", + "disabled": "غیرفعال شده" + }, + "segments": { + "all": "همه کاربران", + "active": "مشترکین فعال", + "trial": "کاربران آزمایشی", + "trialEnding": "پایان دوره آزمایشی", + "expiring": "اشتراک در حال انقضا", + "expired": "اشتراک منقضی شده", + "zero": "موجودی صفر", + "autopayFailed": "خطای پرداخت خودکار", + "lowBalance": "موجودی کم", + "inactive30d": "30 روز غیرفعال", + "inactive60d": "60 روز غیرفعال", + "inactive90d": "90 روز غیرفعال", + "customToday": "امروز ثبتنام کرده", + "customWeek": "این هفته ثبتنام کرده", + "customMonth": "این ماه ثبتنام کرده", + "customActiveToday": "امروز فعال" + }, + "offerType": { + "testAccess": "دسترسی آزمایشی", + "testAccessDesc": "دسترسی موقت به سرورهای اضافی", + "extendDiscount": "تخفیف تمدید", + "extendDiscountDesc": "تخفیف برای مشترکین فعلی", + "purchaseDiscount": "تخفیف خرید", + "purchaseDiscountDesc": "تخفیف برای کاربران جدید" + } + }, + "groups": { + "analytics": "تحلیلها", + "marketing": "بازاریابی", + "system": "سیستم", + "tariffs": "تعرفهها و فروش", + "users": "کاربران" + }, + "remnawave": { + "connected": "متصل", + "disconnected": "تنظیم نشده", + "noData": "بارگذاری دادهها ناموفق بود", + "title": "RemnaWave", + "subtitle": "مدیریت پنل و آمار", + "tabs": { + "overview": "نمای کلی", + "nodes": "گرهها", + "squads": "گروهها", + "sync": "همگامسازی" + }, + "nodes": { + "confirmRestartAll": "آیا مطمئنید میخواهید همه گرهها را راهاندازی مجدد کنید؟", + "disable": "غیرفعال", + "disabled": "غیرفعال شده", + "enable": "فعال", + "noNodes": "گرهای یافت نشد", + "offline": "آفلاین", + "online": "آنلاین", + "restart": "راهاندازی مجدد", + "restartAll": "راهاندازی مجدد همه" + }, + "overview": { + "bandwidth": "پهنای باند لحظهای", + "connections": "اتصالات", + "cpu": "هستههای CPU", + "download": "دانلود", + "memory": "حافظه", + "nodesOnline": "گرههای آنلاین", + "server": "سرور", + "system": "سیستم", + "total": "کل", + "totalUsers": "کل کاربران", + "traffic": "آمار ترافیک", + "upload": "آپلود", + "uptime": "زمان فعالیت", + "usersByStatus": "کاربران بر اساس وضعیت", + "usersOnline": "آنلاین" + }, + "squads": { + "noSquads": "گروهی یافت نشد", + "notSynced": "همگام نشده", + "syncServers": "همگامسازی سرورها", + "synced": "همگام شده" + }, + "sync": { + "autoSync": "همگامسازی خودکار", + "cleanup": "پاکسازی", + "cleanupDesc": "حذف اشتراکهای بدون کاربر", + "fromPanel": "همگامسازی از پنل", + "fromPanelDesc": "وارد کردن کاربران از پنل RemnaWave به پایگاه داده ربات", + "manual": "همگامسازی دستی", + "runNow": "اجرای فوری", + "statuses": "همگامسازی وضعیتها", + "statusesDesc": "همگامسازی وضعیت اشتراکها با پنل", + "subscriptions": "اشتراکها", + "toPanel": "همگامسازی به پنل", + "toPanelDesc": "صادر کردن کاربران از پایگاه داده ربات به پنل RemnaWave", + "validate": "اعتبارسنجی", + "validateDesc": "بررسی و رفع ناسازگاریهای اشتراک" + } + }, + "theme": { + "accentColor": "رنگ تأکیدی", + "customizeColors": "سفارشیسازی رنگها", + "hexCode": "کد HEX", + "hue": "رنگمایه", + "lightness": "روشنایی", + "quickPresets": "پیشتنظیمهای سریع", + "saturation": "اشباع" } }, "adminDashboard": { @@ -721,7 +1583,9 @@ "usersOnline": "آنلاین", "traffic": "ترافیک", "enable": "فعال", - "disable": "غیرفعال" + "disable": "غیرفعال", + "hide": "پنهان کردن ({{count}})", + "showMore": "نمایش {{count}} گره بیشتر" }, "revenue": { "title": "درآمد", @@ -746,6 +1610,36 @@ "available": "در دسترس", "withConnections": "با اتصال", "revenue": "درآمد" + }, + "topReferrers": { + "title": "بهترین ارجاعدهندگان", + "stats": "ارجاع، {{count}} دعوت", + "byEarnings": "بر اساس درآمد", + "byInvited": "بر اساس دعوت", + "invites": "دعوت", + "people": "نفر" + }, + "period": { + "today": "امروز", + "week": "هفته", + "month": "ماه" + }, + "topCampaigns": { + "title": "بهترین لینکهای کمپین", + "stats": "کمپین، {{count}} ثبت نام", + "total": "کل از کمپینها" + }, + "recentPayments": { + "title": "پرداختهای اخیر", + "today": "امروز: {{amount}}", + "week": "این هفته: {{amount}}" + }, + "table": { + "user": "کاربر", + "type": "نوع", + "amount": "مبلغ", + "method": "روش", + "date": "تاریخ" } }, "profile": { @@ -828,6 +1722,7 @@ "error": "بارگذاری مسابقات ناموفق", "noContests": "مسابقهای موجود نیست", "days": "روز", + "days_other": "{{count}} روز", "play": "شرکت", "alreadyPlayed": "قبلاً شرکت کردید", "enterAnswer": "پاسخ خود را وارد کنید", @@ -839,6 +1734,7 @@ "error": "بارگذاری نظرسنجیها ناموفق", "noPolls": "نظرسنجی موجود نیست", "questions": "سوال", + "questions_other": "{{count}} سوال", "question": "سوال", "of": "از", "start": "شروع", @@ -912,6 +1808,169 @@ "days": "روز", "hours": "ساعت", "minutes": "دقیقه" + }, + "offers": { + "expired": "منقضی شده", + "testAccess": "دسترسی آزمایشی", + "discountPercent": "تخفیف {{percent}}%", + "specialOffer": "پیشنهاد ویژه", + "serverAccess": "دسترسی به {{count}} سرور", + "serverAccess_other": "دسترسی به {{count}} سرور", + "additionalServers": "دسترسی به سرورهای اضافی", + "activateDiscountHint": "تخفیف خرید اشتراک را فعال کنید", + "activationFailed": "فعالسازی پیشنهاد ناموفق بود", + "discountActiveTitle": "تخفیف {{percent}}% فعال است", + "statusActive": "فعال", + "expires": "انقضا: {{time}}", + "remaining": "باقیمانده: {{time}}", + "test": "آزمایشی", + "activating": "در حال فعالسازی...", + "activate": "فعالسازی" + } + }, + "telegramRedirect": { + "maxRetries": "تعداد تلاشها به حد مجاز رسیده. لطفاً بعداً دوباره امتحان کنید.", + "redirecting": "در حال انتقال...", + "loginAlternative": "ورود به روش دیگر", + "openInTelegram": "در تلگرام باز کنید", + "openInTelegramDesc": "برای ورود خودکار، این برنامه را از طریق ربات تلگرام باز کنید", + "redirectToLogin": "در حال انتقال به صفحه ورود..." + }, + "deepLink": { + "connecting": "در حال اتصال به", + "redirecting": "انتقال در", + "seconds": "ثانیه", + "manual": "اگر اتفاقی نیفتاد، دکمه زیر را بزنید.", + "openApp": "باز کردن برنامه", + "copyLink": "کپی لینک اشتراک", + "copied": "کپی شد!", + "tryAgain": "تلاش مجدد", + "backToCabinet": "بازگشت به کابین", + "errorTitle": "خطا", + "errorDesc": "لینک اتصال یافت نشد", + "goToSubscription": "رفتن به اشتراک", + "howToAdd": "چگونه به صورت دستی اضافه کنیم:", + "step1": "با دکمه بالا لینک را کپی کنید", + "step2": "برنامه را باز کنید", + "step3": "\"+\" یا \"افزودن اشتراک\" را پیدا کنید", + "step4": "\"از کلیپبورد\" یا \"چسباندن لینک\" را انتخاب کنید" + }, + "banSystem": { + "title": "نظارت بر مسدودسازی", + "subtitle": "مدیریت سیستم BedolagaBan", + "configureHint": "BAN_SYSTEM_API_URL و BAN_SYSTEM_API_TOKEN را در پیکربندی تنظیم کنید", + "loadError": "بارگذاری دادهها ناموفق بود", + "notConfigured": "سیستم مسدودسازی پیکربندی نشده", + "contactTelegram": "نوشتن در تلگرام", + "tabs": { + "dashboard": "آمار", + "nodes": "گرهها", + "agents": "عاملها", + "users": "کاربران", + "punishments": "مسدودسازیها", + "violations": "تخلفات", + "reports": "گزارشها", + "traffic": "ترافیک", + "health": "سلامت", + "settings": "تنظیمات" + }, + "stats": { + "panelStatus": "وضعیت پنل", + "connected": "متصل", + "disconnected": "قطع", + "nodesOnline": "گرههای آنلاین", + "agentsOnline": "عاملهای آنلاین", + "activeUsers": "کاربران فعال", + "activeBans": "مسدودسازیهای فعال", + "usersOverLimit": "بیش از حد", + "total": "کل", + "totalRequests": "کل درخواستها", + "uptime": "زمان فعالیت" + }, + "nodes": { + "status": "وضعیت", + "online": "آنلاین", + "offline": "آفلاین", + "users": "کاربران", + "noNodes": "گرهای یافت نشد" + }, + "agents": { + "status": "وضعیت", + "online": "آنلاین", + "offline": "آفلاین", + "node": "گره", + "queue": "صف", + "sent": "ارسال شده", + "totalSent": "کل ارسال", + "dropped": "حذف شده", + "totalDropped": "کل حذف", + "health": "سلامت", + "healthy": "سالم", + "warning": "هشدار", + "critical": "بحرانی", + "noAgents": "عاملی یافت نشد" + }, + "users": { + "status": "وضعیت", + "email": "ایمیل", + "ipCount": "IP", + "limit": "محدودیت", + "ok": "عادی", + "overLimit": "بیش از حد", + "networkType": "نوع شبکه", + "bans": "مسدودسازی", + "searchPlaceholder": "جستجو بر اساس ایمیل...", + "viewDetails": "مشاهده جزئیات" + }, + "punishments": { + "user": "کاربر", + "reason": "دلیل", + "bannedAt": "زمان مسدودسازی", + "enableAt": "زمان رفع", + "ipCount": "IP", + "limit": "محدودیت", + "unban": "رفع مسدودسازی", + "noBans": "مسدودسازی فعالی نیست" + }, + "violations": { + "type": "نوع", + "user": "کاربر", + "description": "توضیحات", + "status": "وضعیت", + "active": "فعال", + "resolved": "حل شده", + "detectedAt": "زمان شناسایی", + "noViolations": "تخلفی یافت نشد" + }, + "reports": { + "period": "دوره", + "currentUsers": "کاربران فعال", + "currentIps": "IP یکتا", + "count": "تخلفات", + "topViolators": "بیشترین تخلفات", + "username": "کاربر" + }, + "traffic": { + "enabled": "نظارت ترافیک", + "status": "وضعیت", + "ok": "عادی", + "overLimit": "بیش از حد", + "bytesTotal": "کل", + "bytesLimit": "محدودیت", + "topUsers": "بیشترین ترافیک", + "username": "کاربر", + "recentViolations": "تخلفات اخیر" + }, + "health": { + "systemStatus": "وضعیت سیستم" + }, + "userDetail": { + "title": "جزئیات کاربر", + "ip": "آدرس IP", + "country": "کشور", + "node": "گره", + "requests": "درخواستها", + "ipHistory": "تاریخچه IP" } }, "blocking": { diff --git a/src/locales/ru.json b/src/locales/ru.json index 988e3fb..709ec6b 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -1,5 +1,6 @@ { "common": { + "all": "Все", "loading": "Загрузка...", "error": "Ошибка", "success": "Успешно", @@ -20,7 +21,14 @@ "edit": "Редактировать", "delete": "Удалить", "currency": "₽", - "refresh": "Обновить" + "refresh": "Обновить", + "copy": "Копировать", + "retry": "Повторить", + "saving": "Сохранение...", + "units": { + "gb": "ГБ", + "perGb": "/ГБ" + } }, "nav": { "dashboard": "Главная", @@ -42,8 +50,17 @@ "noNotifications": "Нет уведомлений", "justNow": "Только что", "minutesAgo": "{{count}} мин. назад", + "minutesAgo_one": "{{count}} мин. назад", + "minutesAgo_few": "{{count}} мин. назад", + "minutesAgo_many": "{{count}} мин. назад", "hoursAgo": "{{count}} ч. назад", + "hoursAgo_one": "{{count}} ч. назад", + "hoursAgo_few": "{{count}} ч. назад", + "hoursAgo_many": "{{count}} ч. назад", "daysAgo": "{{count}} д. назад", + "daysAgo_one": "{{count}} д. назад", + "daysAgo_few": "{{count}} д. назад", + "daysAgo_many": "{{count}} д. назад", "viewAll": "Все тикеты", "newNotification": "Новое уведомление", "clickToView": "Нажмите для просмотра", @@ -86,7 +103,6 @@ "invalidEmail": "Введите корректный email адрес", "emailAlreadyRegistered": "Этот email уже зарегистрирован", "invalidCredentials": "Неверный email или пароль", - "forgotPassword": "Забыли пароль?", "forgotPasswordHint": "Введите email и мы отправим инструкции для сброса пароля.", "passwordResetSent": "Если аккаунт с таким email существует, мы отправили инструкции по сбросу пароля.", "sendResetLink": "Отправить ссылку", @@ -96,7 +112,8 @@ "verificationSent": "Мы отправили ссылку для подтверждения на:", "clickLinkToVerify": "Перейдите по ссылке в письме, чтобы подтвердить аккаунт и войти.", "backToLogin": "Вернуться ко входу", - "emailNotVerified": "Сначала подтвердите email" + "emailNotVerified": "Сначала подтвердите email", + "loginSuccess": "Авторизация успешна" }, "emailVerification": { "title": "Подтверждение email", @@ -144,7 +161,13 @@ "expiresAt": "Действует до", "daysLeft": "Осталось дней", "devices": "Устройства", - "servers": "Серверы", + "devices_one": "{{count}} устройство", + "devices_few": "{{count}} устройства", + "devices_many": "{{count}} устройств", + "serversLabel": "Серверы", + "servers_one": "{{count}} сервер", + "servers_few": "{{count}} сервера", + "servers_many": "{{count}} серверов", "traffic": "Трафик", "unlimited": "Безлимит", "used": "Использовано", @@ -155,8 +178,17 @@ "buyDevices": "Докупить устройства", "renewalOptions": "Варианты продления", "days": "дней", + "days_one": "{{count}} день", + "days_few": "{{count}} дня", + "days_many": "{{count}} дней", "hours": "ч", + "hours_one": "{{count}} ч", + "hours_few": "{{count}} ч", + "hours_many": "{{count}} ч", "minutes": "м", + "minutes_one": "{{count}} м", + "minutes_few": "{{count}} м", + "minutes_many": "{{count}} м", "price": "Цена", "noSubscription": "У вас нет активной подписки", "getSubscription": "Оформить подписку", @@ -170,15 +202,24 @@ "getConfig": "Подключить устройства", "autoRenewal": "Автопродление", "daysBeforeExpiry": "дней до окончания", + "daysBeforeExpiry_one": "{{count}} день до окончания", + "daysBeforeExpiry_few": "{{count}} дня до окончания", + "daysBeforeExpiry_many": "{{count}} дней до окончания", "selectPeriod": "Выберите период", "selectTraffic": "Выберите трафик", "selectServers": "Выберите серверы", "selectDevices": "Устройства", "perDevice": "/ устройство", "devicesFree": "устройств бесплатно", + "devicesFree_one": "{{count}} устройство бесплатно", + "devicesFree_few": "{{count}} устройства бесплатно", + "devicesFree_many": "{{count}} устройств бесплатно", "perExtraDevice": "/ доп. устройство", "extraDevices": "Доп. устройства", "extraDevicesIncluded": "Вкл. {{count}} доп. устр.", + "extraDevicesIncluded_one": "Вкл. {{count}} доп. устр.", + "extraDevicesIncluded_few": "Вкл. {{count}} доп. устр.", + "extraDevicesIncluded_many": "Вкл. {{count}} доп. устр.", "baseTariff": "Тариф", "perMonth": "/мес", "summary": "Итого", @@ -199,7 +240,13 @@ "titlePaid": "Пробная подписка", "description": "Попробуйте наш VPN сервис!", "days": "дней", + "days_one": "{{count}} день", + "days_few": "{{count}} дня", + "days_many": "{{count}} дней", "devices": "устройств", + "devices_one": "{{count}} устройство", + "devices_few": "{{count}} устройства", + "devices_many": "{{count}} устройств", "price": "Стоимость", "activate": "Активировать бесплатно", "payAndActivate": "Оплатить с баланса", @@ -254,11 +301,12 @@ "pausedDescription": "Списания остановлены. Подписка будет действовать до", "nextCharge": "До следующего списания", "willBeCharged": "Будет списано", - "days_one": "день", - "days_few": "дня", - "days_many": "дней", + "days_one": "{{count}} день", + "days_few": "{{count}} дня", + "days_many": "{{count}} дней", "hours": "ч", - "minutes": "м" + "minutes": "м", + "days": "дн." }, "dailyPurchase": { "costPerDay": "Стоимость в день", @@ -277,7 +325,9 @@ "free": "Бесплатно", "switch": "Перейти", "switched": "Тариф изменён", - "notEnoughBalance": "Недостаточно средств" + "notEnoughBalance": "Недостаточно средств", + "dailyPayment": "Оплата за день", + "dailyChargeDescription": "Списывается ежедневно с баланса" }, "switchTraffic": { "title": "Изменить трафик", @@ -287,7 +337,64 @@ "switched": "Трафик изменён" }, "purchasedTraffic": "Докупленный трафик", - "trafficResetAt": "Сброс" + "trafficResetAt": "Сброс", + "additionalOptions": { + "title": "Дополнительные опции", + "buyDevices": "Докупить устройства", + "currentDeviceLimit": "Текущий лимит: {{count}} устройств", + "devicesUnavailable": "Докупка устройств недоступна", + "devicesUnit": "устройств", + "buy": "Купить", + "buyTraffic": "Докупить трафик", + "currentTrafficLimit": "Текущий лимит: {{limit}} ГБ (использовано {{used}} ГБ)", + "buyTrafficTitle": "Докупить трафик", + "trafficWarning": "Докупленный трафик добавляется к текущему лимиту и не переносится на следующий период", + "trafficUnavailable": "Докупка трафика недоступна для вашего тарифа", + "unlimited": "Безлимит", + "buyTrafficGb": "Купить {{gb}} ГБ", + "manageServers": "Управление серверами", + "manageServersTitle": "Управление серверами" + }, + "serverManagement": { + "statusLegend": "✅ — подключено • ➕ — будет добавлено (платно) • ➖ — будет отключено", + "discountBanner": "Ваша скидка на серверы: -{{percent}}%", + "forDays": "(за {{days}} дн.)", + "perMonth": "/мес", + "unavailable": "Недоступен", + "toAdd": "Добавить:", + "toDisconnect": "Отключить:", + "paymentProrated": "К оплате (пропорционально оставшимся дням):", + "applyChanges": "Применить изменения", + "selectServersHint": "Выберите серверы для подключения или отключения", + "noServersAvailable": "Нет доступных серверов для управления" + }, + "legacy": { + "selectTariffTitle": "Выберите тариф для продления", + "selectTariffDescription": "Ваша текущая подписка была создана до введения тарифов. Для продления необходимо выбрать один из доступных тарифов.", + "currentSubContinues": "Ваша текущая подписка продолжит действовать до окончания срока." + }, + "promoGroup": { + "yourGroup": "Ваша группа: {{name}}", + "personalDiscountsApplied": "Персональные скидки применены к ценам" + }, + "tariff": { + "perDay": "/ день", + "flexiblePayment": "Гибкая оплата", + "selectForRenewal": "Выбрать для продления" + }, + "customDays": { + "title": "Произвольное кол-во дней", + "perDay": "/день" + }, + "customTraffic": { + "label": "Трафик", + "selectVolume": "Выбрать объём трафика", + "default": "По умолчанию: {{label}}" + }, + "summary": { + "period": "Период: {{label}}", + "traffic": "Трафик: {{gb}} ГБ" + } }, "balance": { "title": "Баланс", @@ -378,6 +485,19 @@ "pay": "Оплатить", "checkStatus": "Проверить статус", "checking": "Проверка..." + }, + "paymentReady": "Ссылка на оплату готова", + "clickToOpenPayment": "Нажмите кнопку ниже, чтобы открыть страницу оплаты в новой вкладке", + "openPaymentPage": "Открыть страницу оплаты", + "errors": { + "noPaymentLink": "Сервер не вернул ссылку на оплату", + "starsOnlyInTelegram": "Оплата Stars доступна только в Telegram Mini App", + "generic": "Ошибка: {{details}}", + "invoiceFailed": "Не удалось создать счёт", + "rateLimit": "Подождите {{seconds}} сек.", + "selectMethod": "Выберите способ", + "enterAmount": "Введите сумму", + "amountRange": "Сумма: {{min}} – {{max}} ₽" } }, "referral": { @@ -453,6 +573,7 @@ "fileTooLarge": "Файл слишком большой. Максимальный размер 10МБ.", "uploadFailed": "Не удалось загрузить изображение", "imageLoadFailed": "Не удалось загрузить изображение", + "tooManyRequests": "Слишком много запросов. Подождите {{seconds}} сек.", "ticketsDisabled": "Тикеты отключены", "useProfile": "Для получения поддержки перейдите в профиль бота", "goToProfile": "Перейти в профиль", @@ -469,6 +590,9 @@ "stars": "Stars", "telegramStars": "Telegram Stars", "days": "дней", + "days_one": "{{count}} день", + "days_few": "{{count}} дня", + "days_many": "{{count}} дней", "subscriptionDays": "Дни подписки", "day": "День", "spin": "КРУТИТЬ!", @@ -520,7 +644,10 @@ "payments": "Платежи", "remnawave": "RemnaWave", "emailTemplates": "Email-шаблоны", - "paymentMethods": "Платёжные методы" + "paymentMethods": "Платёжные методы", + "campaigns": "Кампании", + "promoOffers": "Промопредложения", + "promocodes": "Промокоды" }, "panel": { "title": "Панель администратора", @@ -538,7 +665,10 @@ "paymentsDesc": "Проверка платежей", "remnawaveDesc": "Управление панелью и статистика", "emailTemplatesDesc": "Шаблоны email-уведомлений", - "paymentMethodsDesc": "Настройка и порядок платежек" + "paymentMethodsDesc": "Настройка и порядок платежек", + "campaignsDesc": "Рекламные кампании", + "promoOffersDesc": "Персональные скидки", + "promocodesDesc": "Управление промокодами" }, "emailTemplates": { "title": "Email-шаблоны", @@ -570,7 +700,9 @@ "user": "Пользователь", "openLink": "Открыть ссылку", "checkStatus": "Проверить статус", - "checking": "Проверка..." + "checking": "Проверка...", + "prev": "Назад", + "next": "Далее" }, "paymentMethods": { "title": "Платёжные методы", @@ -604,7 +736,11 @@ "promoGroupAll": "Все группы", "promoGroupSelected": "Выбранные", "promoGroupsShort": "групп", - "noPromoGroups": "Нет промо-групп" + "noPromoGroups": "Нет промо-групп", + "firstTopupWas": "Было", + "firstTopupWasNot": "Не было", + "cancelButton": "Отмена", + "saveButton": "Сохранить" }, "remnawave": { "title": "RemnaWave", @@ -724,6 +860,9 @@ "targetRtp": "цель", "prizeDistribution": "Распределение призов", "times": "раз", + "times_one": "{{count}} раз", + "times_few": "{{count}} раза", + "times_many": "{{count}} раз", "topWins": "Топ выигрышей" } }, @@ -751,7 +890,27 @@ "failed": "Ошибки", "filter": "Фильтр", "message": "Сообщение", - "unknownAdmin": "Неизвестный админ" + "unknownAdmin": "Неизвестный админ", + "prev": "Назад", + "next": "Далее", + "status": { + "queued": "В очереди", + "inProgress": "Отправляется", + "completed": "Завершено", + "partial": "Частично", + "failed": "Ошибка", + "cancelled": "Отменено", + "cancelling": "Отменяется" + }, + "filterGroups": { + "basic": "Основные", + "subscription": "По подписке", + "traffic": "По трафику", + "registration": "По регистрации", + "activity": "По активности", + "source": "По источнику", + "tariff": "По тарифу" + } }, "settings": { "title": "Настройки системы", @@ -767,6 +926,19 @@ "searchPlaceholder": "Поиск настроек...", "searchCategoriesPlaceholder": "Поиск категорий...", "noSearchResults": "Ничего не найдено", + "inputPlaceholder": "Введите значение...", + "ctrlEnterHint": "Ctrl+Enter для сохранения", + "cancelButton": "Отмена", + "saveButton": "Сохранить", + "saveHint": "Сохранить (Enter)", + "cancelHint": "Отмена (Esc)", + "removeFromFavorites": "Убрать из избранного", + "addToFavorites": "В избранное", + "enabled": "Включено", + "disabled": "Выключено", + "foundCount": "Найдено: {{count}}", + "notFound": "Ничего не найдено", + "byQuery": "по запросу «{{query}}»", "example": "Пример", "favorites": "Избранное", "favoritesEmpty": "Нет избранных настроек", @@ -1000,31 +1172,22 @@ "Notifications Enabled": "Уведомления", "Notifications Expiry Days": "Дней до истечения", "Notifications Traffic Percent": "Процент трафика", - "Admin Notifications Enabled": "Уведомления админов", - "Admin Reports Enabled": "Отчёты админов", "Admin Reports Hour": "Час отчётов", "Database Type": "Тип БД", - "Postgres Host": "Хост", - "Postgres Port": "Порт", "Postgres Database": "Имя БД", - "Postgres User": "Пользователь", - "Postgres Password": "Пароль", "Redis Enabled": "Redis", "Redis Host": "Хост Redis", "Redis Port": "Порт Redis", "Redis Password": "Пароль Redis", "Debug Mode": "Отладка", - "Log Level": "Уровень логов", "Api Url": "URL API", "Api Key": "API ключ", "Api Token": "API токен", - "Webhook Url": "URL вебхука", "Webhook Secret": "Секрет вебхука", "Remnawave Url": "URL RemnaWave", "Remnawave Token": "Токен RemnaWave", "Server Status Enabled": "Статус сервера", "Monitoring Enabled": "Мониторинг", - "Maintenance Mode": "Обслуживание", "Backup Enabled": "Бэкап", "Backup Interval": "Интервал бэкапа", "Support Enabled": "Поддержка", @@ -1432,8 +1595,17 @@ "tierHint": "1-10, влияет на приоритет при переходе", "unlimited": "Безлимит", "devices": "устр.", + "devices_one": "{{count}} устр.", + "devices_few": "{{count}} устр.", + "devices_many": "{{count}} устр.", "servers": "серверов", + "servers_one": "{{count}} сервер", + "servers_few": "{{count}} сервера", + "servers_many": "{{count}} серверов", "subscriptions": "подписок", + "subscriptions_one": "{{count}} подписка", + "subscriptions_few": "{{count}} подписки", + "subscriptions_many": "{{count}} подписок", "trial": "Триал", "inactive": "Неактивен", "activate": "Активировать", @@ -1443,6 +1615,9 @@ "confirmDelete": "Удалить тариф?", "confirmDeleteText": "Это действие нельзя отменить. Тариф будет удален навсегда.", "days": "дней", + "days_one": "{{count}} день", + "days_few": "{{count}} дня", + "days_many": "{{count}} дней", "tabs": { "basic": "Основное", "prices": "Цены", @@ -1453,7 +1628,81 @@ "serversHint": "Выберите серверы, доступные для этого тарифа. Для каждого сервера можно указать индивидуальный лимит трафика.", "noServers": "Нет доступных серверов", "serverTrafficLimit": "Лимит трафика", - "useDefault": "по умолчанию" + "useDefault": "по умолчанию", + "selectType": "Выберите тип тарифа", + "periodTariff": "Периодный тариф", + "periodTariffDesc": "Оплата за период (7, 30, 90 дней и т.д.). Произвольные периоды и цены.", + "dailyTariff": "Суточный тариф", + "dailyTariffDesc": "Ежедневное списание с баланса. Можно ставить на паузу.", + "editTitle": "Редактирование тарифа", + "newPeriodTitle": "Новый периодный тариф", + "newDailyTitle": "Новый суточный тариф", + "periodPayment": "Оплата за период", + "dailyDeduction": "Ежедневное списание", + "tabBasic": "Основное", + "tabPeriods": "Периоды", + "tabServers": "Серверы", + "tabExtra": "Дополнительно", + "nameLabel": "Название тарифа", + "nameExamplePeriod": "Например: Стандарт", + "nameExampleDaily": "Например: Суточный", + "descriptionLabel": "Описание", + "descriptionPlaceholder": "Краткое описание тарифа", + "trafficLimitLabel": "Лимит трафика", + "gbUnit": "ГБ", + "trafficLimitHint": "0 = безлимитный трафик", + "deviceLimitLabel": "Устройств в тарифе", + "tierLevelLabel": "Уровень тарифа", + "tierLevelHint": "Влияет на доступность перехода между тарифами", + "periodsTabHint": "Добавьте периоды и цены для тарифа. Пользователи смогут выбирать из добавленных периодов.", + "addPeriodTitle": "Добавить период", + "daysLabel": "Дней", + "priceLabel": "Цена (₽)", + "addButton": "Добавить", + "noPeriodsHint": "Нет добавленных периодов. Добавьте хотя бы один период.", + "daysShort": "дн.", + "serversTabHint": "Выберите серверы, доступные на этом тарифе.", + "noServersAvailable": "Нет доступных серверов", + "extraDeviceTitle": "Докупка устройств", + "devicePriceLabel": "Цена за устройство (30 дней):", + "devicePriceHint": "0 = докупка недоступна", + "maxDeviceLabel": "Макс. устройств на тарифе:", + "noLimitHint": "0 = без ограничений", + "extraTrafficTitle": "Докупка трафика", + "trafficMaxLimitLabel": "Макс. лимит:", + "trafficLimitHint2": "(0 = без ограничений)", + "trafficPackagesLabel": "Пакеты трафика:", + "gbPackageUnit": "ГБ:", + "customDaysTitle": "Произвольное количество дней", + "customDaysDesc": "Пользователь сам выбирает срок подписки", + "pricePerDayLabel": "Цена за день:", + "minDaysLabel": "Мин. дней:", + "maxDaysLabel": "Макс. дней:", + "customTrafficTitle": "Произвольный объём трафика", + "customTrafficDesc": "Пользователь сам выбирает объём трафика при покупке", + "pricePerGbLabel": "Цена за 1 ГБ:", + "minTrafficLabel": "Мин. ГБ:", + "maxTrafficLabel": "Макс. ГБ:", + "trafficResetModeTitle": "Режим сброса трафика", + "trafficResetModeDesc": "Определяет, когда сбрасывается использованный трафик у подписчиков этого тарифа", + "resetModeGlobal": "Глобальная настройка", + "resetModeGlobalDesc": "Использовать значение из конфига бота", + "resetModeDaily": "Ежедневно", + "resetModeDailyDesc": "Сброс каждый день", + "resetModeWeekly": "Еженедельно", + "resetModeWeeklyDesc": "Сброс каждую неделю", + "resetModeMonthly": "Ежемесячно", + "resetModeMonthlyDesc": "Сброс каждый месяц", + "resetModeNever": "Никогда", + "resetModeNeverDesc": "Трафик не сбрасывается", + "cancelButton": "Отмена", + "savingButton": "Сохранение...", + "saveButton": "Сохранить", + "dailyType": "Суточный", + "periodType": "Периодный", + "dailyPriceLabel": "Цена за день", + "currencyPerDay": "₽/день", + "dailyDeductionDesc": "Списывается ежедневно с баланса пользователя" }, "servers": { "title": "Управление серверами", @@ -1485,6 +1734,442 @@ "disable": "Отключить", "toggleTrial": "Переключить триал", "loadError": "Не удалось загрузить сервер" + }, + "campaigns": { + "title": "Рекламные кампании", + "subtitle": "Управление рекламными ссылками", + "createButton": "Создать", + "noData": "Нет рекламных кампаний", + "bonusType": { + "balance": "Баланс", + "subscription": "Подписка", + "tariff": "Тариф", + "none": "Только ссылка" + }, + "overview": { + "totalCampaigns": "Всего кампаний", + "active": "Активных", + "registrations": "Регистраций", + "bonusesIssued": "Выдано бонусов" + }, + "table": { + "inactive": "Неактивна", + "registrations": "{{count}} регистраций", + "revenue": "{{amount}} доход", + "conversion": "{{rate}}% конверсия", + "statistics": "Статистика", + "deactivate": "Деактивировать", + "activate": "Активировать", + "edit": "Редактировать", + "delete": "Удалить" + }, + "modal": { + "editTitle": "Редактирование кампании", + "createTitle": "Новая кампания", + "close": "Закрыть" + }, + "form": { + "name": "Название", + "namePlaceholder": "Например: Instagram Реклама", + "startParameter": "Метка (start параметр)", + "startParameterHint": "Только латиница, цифры, _ и -", + "bonusType": "Тип бонуса", + "balanceBonus": "Бонус на баланс", + "trialSubscription": "Пробная подписка", + "days": "Дней", + "trafficGb": "Трафик (ГБ)", + "devices": "Устройств", + "servers": "Серверы", + "tariff": "Тариф", + "selectTariff": "Выберите тариф", + "notSelected": "Не выбран", + "tariffOption": "{{traffic}} ГБ, {{devices}} уст.", + "durationDays": "Длительность (дней)", + "noBonusDescription": "Кампания без бонусов - только для отслеживания переходов и регистраций.", + "active": "Активна", + "cancel": "Отмена", + "save": "Сохранить", + "saving": "Сохранение..." + }, + "stats": { + "registrations": "Регистраций", + "revenue": "Доход", + "paidUsers": "Оплатили", + "conversion": "Конверсия", + "bonusesIssued": "Бонусы выданы", + "subscriptionsIssued": "{{count}} подписок", + "tariffsIssued": "{{count}} тарифов", + "avgRevenuePerUser": "Средний доход с пользователя", + "avgFirstPayment": "Средний первый платёж", + "trialSubscriptions": "Пробных подписок", + "trialCount": "{{total}} (активных: {{active}})", + "trialConversion": "Конверсия из триала", + "lastRegistration": "Последняя регистрация", + "active": "Активна", + "inactive": "Неактивна", + "copy": "Копировать", + "copied": "Скопировано!", + "users": "Пользователи" + }, + "users": { + "title": "Пользователи кампании", + "campaignRegistrations": "{{name}} - {{count}} регистраций", + "noUsers": "Нет зарегистрированных пользователей", + "user": "Пользователь", + "bonus": "Бонус", + "balance": "Баланс", + "status": "Статус", + "date": "Дата", + "noName": "Без имени", + "paid": "Платил", + "prev": "Назад", + "next": "Далее", + "pageOf": "{{page}} из {{totalPages}}" + }, + "confirm": { + "deleteTitle": "Удалить кампанию?", + "deleteText": "Это действие нельзя отменить. Кампании с регистрациями удалить нельзя.", + "cancel": "Отмена", + "delete": "Удалить" + } + }, + "promocodes": { + "title": "Промокоды", + "subtitle": "Управление промокодами и группами скидок", + "addPromocode": "Добавить промокод", + "addGroup": "Добавить группу", + "noPromocodes": "Нет промокодов", + "noGroups": "Нет групп скидок", + "firstPurchase": "Первая покупка", + "used": "Использовано", + "until": "До", + "discountForHours": "-{{percent}}% на {{hours}}ч", + "tabs": { + "promocodes": "Промокоды ({{count}})", + "groups": "Группы скидок ({{count}})" + }, + "type": { + "balance": "Баланс", + "subscriptionDays": "Дни подписки", + "trialSubscription": "Тестовая подписка", + "promoGroup": "Группа скидок", + "discount": "Скидка %" + }, + "modal": { + "editPromocode": "Редактирование промокода", + "newPromocode": "Новый промокод", + "editGroup": "Редактирование группы", + "newGroup": "Новая группа скидок", + "close": "Закрыть", + "edit": "Редактировать" + }, + "form": { + "code": "Код промокода", + "type": "Тип промокода", + "typeBalance": "Пополнение баланса", + "typeSubscriptionDays": "Дни подписки", + "typeTrialSubscription": "Тестовая подписка", + "typePromoGroup": "Группа скидок", + "typeDiscount": "Процентная скидка", + "bonusAmount": "Сумма бонуса", + "rub": "руб.", + "daysCount": "Количество дней", + "days": "дней", + "discountGroup": "Группа скидок", + "selectGroup": "Выберите группу...", + "discountPercent": "Процент скидки", + "discountHint": "Скидка применяется один раз при оплате", + "validityPeriod": "Время действия", + "hours": "часов", + "validityHint": "Сколько часов после активации скидка действует", + "maxUses": "Макс. использований", + "unlimitedHint": "0 = безлимит", + "validUntil": "Действует до", + "validUntilHint": "Оставьте пустым для бессрочного промокода", + "active": "Активен", + "firstPurchaseOnly": "Только для первой покупки", + "cancel": "Отмена", + "saving": "Сохранение...", + "save": "Сохранить" + }, + "stats": { + "totalUses": "Всего использований", + "today": "Сегодня", + "remaining": "Осталось", + "details": "Детали промокода", + "type": "Тип", + "bonus": "Бонус", + "daysLabel": "Дней", + "discountLabel": "Скидка", + "validFor": "Действует", + "hoursValue": "{{count}} часов", + "limit": "Лимит", + "status": "Статус", + "active": "Активен", + "inactive": "Неактивен", + "created": "Создан", + "validUntil": "Действует до", + "unlimited": "Бессрочно", + "restriction": "Ограничение", + "firstPurchaseOnly": "Только первая покупка", + "usageHistory": "История использования", + "noUsages": "Промокод еще не использовался", + "totalPromocodes": "Всего промокодов", + "activeCount": "Активных", + "usagesCount": "Использований", + "exhausted": "Исчерпано" + }, + "actions": { + "stats": "Статистика", + "edit": "Редактировать", + "delete": "Удалить" + }, + "groups": { + "name": "Название группы", + "namePlaceholder": "VIP клиенты", + "categoryDiscounts": "Скидки по категориям", + "servers": "На серверы", + "traffic": "На трафик", + "devices": "На устройства", + "periodDiscounts": "Скидки по периодам", + "add": "Добавить", + "periodDiscountsHint": "Скидка применяется при покупке подписки на указанное кол-во дней", + "noPeriodDiscounts": "Нет скидок по периодам", + "daysPlaceholder": "Дни", + "daysArrow": "дней →", + "autoAssign": "Авто-назначение при тратах от", + "autoAssignHint": "0 = не назначать автоматически", + "applyToAddons": "Применять к дополнительным услугам", + "default": "По умолчанию", + "daysShort": "{{days}} дн.", + "autoFrom": "Авто от {{amount}} руб.", + "members": "{{count}} участников" + }, + "confirm": { + "deletePromocode": "Удалить промокод?", + "deleteGroup": "Удалить группу?", + "deletePromocodeText": "Промокод будет удален безвозвратно.", + "deleteGroupText": "Группа будет удалена. Пользователи потеряют скидки этой группы.", + "deleteButton": "Удалить" + } + }, + "users": { + "title": "Пользователи", + "subtitle": "Управление пользователями бота", + "search": "Поиск по ID, имени, username...", + "noData": "Пользователи не найдены", + "purchaseCount": "{{count}} покупок", + "noPurchases": "Нет покупок", + "stats": { + "total": "Всего", + "active": "Активных", + "withSubscription": "С подпиской", + "newToday": "Новых сегодня", + "blocked": "Заблокировано" + }, + "status": { + "active": "Активные", + "blocked": "Заблокированные", + "deleted": "Удалённые", + "subscription": "Подписка", + "trial": "Триал", + "expired": "Истекла" + }, + "filters": { + "allStatuses": "Все статусы", + "byDate": "По дате", + "byBalance": "По балансу", + "byActivity": "По активности", + "bySpent": "По расходам" + }, + "pagination": { + "showing": "Показано {{from}}-{{to}} из {{total}}" + }, + "actions": { + "block": "Заблокировать", + "unblock": "Разблокировать", + "apply": "Применить", + "applying": "Применение..." + }, + "confirm": { + "block": "Заблокировать пользователя?" + }, + "detail": { + "tabs": { + "info": "Информация", + "subscription": "Подписка", + "balance": "Баланс", + "sync": "Синхронизация" + }, + "status": "Статус", + "language": "Язык", + "registration": "Регистрация", + "lastActivity": "Последняя активность", + "totalSpent": "Всего потрачено", + "purchases": "Покупок", + "referral": { + "title": "Реферальная программа", + "referrals": "Рефералов", + "earned": "Заработано", + "commission": "Комиссия" + }, + "restrictions": { + "title": "Ограничения", + "topup": "• Запрет пополнения", + "subscription": "• Запрет покупки подписки", + "reason": "Причина" + }, + "subscription": { + "current": "Текущая подписка", + "tariff": "Тариф", + "notSpecified": "Не указан", + "validUntil": "Действует до", + "traffic": "Трафик", + "devices": "Устройств", + "actions": "Действия", + "extend": "Продлить", + "changeTariff": "Сменить тариф", + "cancel": "Отменить", + "activate": "Активировать", + "days": "Дней", + "selectTariff": "Выберите тариф", + "unavailable": "(недоступен)", + "noActive": "Нет активной подписки", + "create": "Создать подписку", + "creating": "Создание..." + }, + "balance": { + "current": "Текущий баланс", + "amountPlaceholder": "Сумма в рублях", + "descriptionPlaceholder": "Описание (опционально)", + "add": "Начислить", + "subtract": "Списать", + "addByAdmin": "Начисление админом", + "subtractByAdmin": "Списание админом", + "recentTransactions": "Последние транзакции" + }, + "sync": { + "hasDifferences": "Есть расхождения", + "synced": "Синхронизировано", + "bot": "Бот", + "panel": "Панель", + "statusLabel": "Статус", + "until": "До", + "traffic": "Трафик", + "devices": "Устройства", + "squads": "Сквады", + "notLinked": "Не привязан", + "fromPanel": "Из панели в бота", + "toPanel": "Из бота в панель" + } + } + }, + "promoOffers": { + "title": "Промопредложения", + "subtitle": "Шаблоны, рассылка и логи предложений", + "sendButton": "Отправить", + "tabs": { + "templates": "Шаблоны ({{count}})", + "logs": "Логи" + }, + "noData": { + "templates": "Нет шаблонов", + "logs": "Нет записей" + }, + "status": { + "active": "Активен", + "inactive": "Неактивен" + }, + "table": { + "discount": "Скидка", + "offerDuration": "Срок предложения", + "hoursShort": "{{hours}}ч", + "discountDuration": "Действие скидки", + "testAccess": "Тестовый доступ" + }, + "form": { + "editTemplate": "Редактирование шаблона", + "templateName": "Название шаблона", + "messageText": "Текст сообщения", + "buttonText": "Текст кнопки", + "validHours": "Срок предложения (часы)", + "activationTime": "Время на активацию", + "discountPercent": "Скидка (%)", + "testDurationHours": "Длительность доступа (часы)", + "defaultZero": "0 = по умолчанию", + "activeDiscountHours": "Действие скидки (часы)", + "discountDurationHint": "Сколько действует скидка после активации", + "templateActive": "Шаблон активен", + "saving": "Сохранение..." + }, + "send": { + "title": "Отправка промопредложения", + "offerTemplate": "Шаблон предложения", + "discountLabel": "{{percent}}% скидка", + "hoursToActivate": "{{hours}}ч на активацию", + "sendTo": "Кому отправить", + "segment": "Сегмент", + "user": "Пользователь", + "userIdPlaceholder": "Telegram ID или User ID", + "preview": "Предпросмотр", + "sending": "Отправка...", + "sendButton": "Отправить" + }, + "result": { + "sentTitle": "Отправлено!", + "offersCreated": "Создано предложений: {{count}}", + "notificationsSent": "Уведомлений отправлено: {{count}}", + "notificationsFailed": "(не доставлено: {{count}})", + "sendError": "Не удалось отправить предложение" + }, + "actions": { + "created": "Создано", + "claimed": "Активировано", + "consumed": "Использовано", + "disabled": "Деактивировано" + }, + "segments": { + "all": "Все пользователи", + "active": "Активные подписчики", + "trial": "Триал пользователи", + "trialEnding": "Заканчивается триал", + "expiring": "Заканчивается подписка", + "expired": "Истекшая подписка", + "zero": "Нулевой баланс", + "autopayFailed": "Ошибка автоплатежа", + "lowBalance": "Низкий баланс", + "inactive30d": "Неактивны 30 дней", + "inactive60d": "Неактивны 60 дней", + "inactive90d": "Неактивны 90 дней", + "customToday": "Зарегистрированы сегодня", + "customWeek": "Зарегистрированы за неделю", + "customMonth": "Зарегистрированы за месяц", + "customActiveToday": "Активны сегодня" + }, + "offerType": { + "testAccess": "Тестовый доступ", + "testAccessDesc": "Временный доступ к дополнительным серверам", + "extendDiscount": "Скидка на продление", + "extendDiscountDesc": "Скидка для текущих подписчиков", + "purchaseDiscount": "Скидка на покупку", + "purchaseDiscountDesc": "Скидка для новых пользователей" + } + }, + "groups": { + "analytics": "Аналитика", + "marketing": "Маркетинг", + "system": "Система", + "tariffs": "Тарифы и продажи", + "users": "Пользователи" + }, + "theme": { + "accentColor": "Акцентный цвет", + "customizeColors": "Настроить цвета", + "hexCode": "HEX код", + "hue": "Тон", + "lightness": "Яркость", + "quickPresets": "Быстрые пресеты", + "saturation": "Насыщенность" } }, "adminDashboard": { @@ -1510,7 +2195,9 @@ "usersOnline": "Онлайн", "traffic": "Трафик", "enable": "Включить", - "disable": "Отключить" + "disable": "Отключить", + "hide": "Скрыть ({{count}})", + "showMore": "Показать еще {{count}} нод" }, "revenue": { "title": "Доходы", @@ -1546,11 +2233,42 @@ "purchasedWeek": "Неделя", "purchasedMonth": "Месяц", "noTariffs": "Нет тарифов" + }, + "topReferrers": { + "title": "Топ рефералов", + "stats": "реф., {{count}} пригл.", + "byEarnings": "По доходу", + "byInvited": "По пригл.", + "invites": "пригл.", + "people": "чел." + }, + "period": { + "today": "Сегодня", + "week": "Неделя", + "month": "Месяц" + }, + "topCampaigns": { + "title": "Топ РК ссылок", + "stats": "камп., {{count}} рег.", + "total": "Всего от РК" + }, + "recentPayments": { + "title": "Последние платежи", + "today": "Сегодня: {{amount}}", + "week": "За неделю: {{amount}}" + }, + "table": { + "user": "Пользователь", + "type": "Тип", + "amount": "Сумма", + "method": "Метод", + "date": "Дата" } }, "banSystem": { "title": "Мониторинг банов", "subtitle": "Управление системой банов BedolagaBan", + "contactTelegram": "Написать в Telegram", "notConfigured": "Ban система не настроена", "configureHint": "Укажите BAN_SYSTEM_API_URL и BAN_SYSTEM_API_TOKEN в конфигурации", "loadError": "Не удалось загрузить данные", @@ -2063,6 +2781,9 @@ "error": "Ошибка загрузки конкурсов", "noContests": "Нет доступных конкурсов", "days": "дней", + "days_one": "{{count}} день", + "days_few": "{{count}} дня", + "days_many": "{{count}} дней", "play": "Участвовать", "alreadyPlayed": "Уже участвовали", "enterAnswer": "Введите ответ", @@ -2074,6 +2795,9 @@ "error": "Ошибка загрузки опросов", "noPolls": "Нет доступных опросов", "questions": "вопросов", + "questions_one": "{{count}} вопрос", + "questions_few": "{{count}} вопроса", + "questions_many": "{{count}} вопросов", "question": "Вопрос", "of": "из", "start": "Начать", @@ -2147,8 +2871,55 @@ "days": "д", "hours": "ч", "minutes": "м" + }, + "offers": { + "expired": "Истекло", + "testAccess": "Тестовый доступ", + "discountPercent": "Скидка {{percent}}%", + "specialOffer": "Специальное предложение", + "serverAccess": "Доступ к {{count}} серверам", + "serverAccess_one": "Доступ к {{count}} серверу", + "serverAccess_few": "Доступ к {{count}} серверам", + "serverAccess_many": "Доступ к {{count}} серверам", + "additionalServers": "Доступ к дополнительным серверам", + "activateDiscountHint": "Активируйте скидку на покупку подписки", + "activationFailed": "Не удалось активировать предложение", + "discountActiveTitle": "Скидка {{percent}}% активна", + "statusActive": "Действует", + "expires": "Истекает: {{time}}", + "remaining": "Осталось: {{time}}", + "test": "Тест", + "activating": "Активация...", + "activate": "Активировать" } }, + "telegramRedirect": { + "maxRetries": "Превышено количество попыток. Попробуйте позже.", + "redirecting": "Перенаправление...", + "loginAlternative": "Войти другим способом", + "openInTelegram": "Откройте в Telegram", + "openInTelegramDesc": "Для автоматического входа откройте это приложение через бота в Telegram", + "redirectToLogin": "Перенаправление на страницу входа..." + }, + "deepLink": { + "connecting": "Подключение к", + "redirecting": "Перенаправление через", + "seconds": "сек", + "manual": "Если ничего не происходит, нажмите кнопку ниже.", + "openApp": "Открыть приложение", + "copyLink": "Скопировать ссылку подписки", + "copied": "Скопировано!", + "tryAgain": "Попробовать снова", + "backToCabinet": "Вернуться в кабинет", + "errorTitle": "Ошибка", + "errorDesc": "Ссылка для подключения не найдена", + "goToSubscription": "Перейти к подписке", + "howToAdd": "Как добавить вручную:", + "step1": "Скопируйте ссылку кнопкой выше", + "step2": "Откройте приложение", + "step3": "Найдите \"+\" или \"Добавить подписку\"", + "step4": "Выберите \"Из буфера\" или \"Вставить ссылку\"" + }, "blocking": { "maintenance": { "title": "Технические работы", diff --git a/src/locales/zh.json b/src/locales/zh.json index 574b56f..96e3a95 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -18,7 +18,17 @@ "and": "和", "edit": "编辑", "delete": "删除", - "currency": "¥" + "currency": "¥", + "copy": "复制", + "all": "All", + "add": "添加", + "refresh": "刷新", + "retry": "重试", + "saving": "保存中...", + "units": { + "gb": "GB", + "perGb": "/GB" + } }, "nav": { "dashboard": "首页", @@ -81,7 +91,20 @@ "verificationSent": "我们已发送验证链接至:", "clickLinkToVerify": "点击邮件中的链接验证账户并登录。", "backToLogin": "返回登录", - "emailNotVerified": "请先验证邮箱" + "emailNotVerified": "请先验证邮箱", + "emailAlreadyRegistered": "此邮箱已注册", + "firstName": "名字", + "firstNamePlaceholder": "您的名字(可选)", + "forgotPasswordHint": "输入邮箱以接收重置链接", + "invalidCredentials": "邮箱或密码无效", + "invalidEmail": "请输入有效的邮箱地址", + "loginSuccess": "登录成功", + "passwordMismatch": "密码不匹配", + "passwordResetSent": "密码重置链接已发送到您的邮箱", + "passwordTooShort": "密码至少需要8个字符", + "sendResetLink": "发送重置链接", + "tooManyAttempts": "尝试次数过多,请稍后再试", + "verificationEmailNotice": "注册后,验证邮件将发送到您的邮箱" }, "emailVerification": { "title": "邮箱验证", @@ -120,10 +143,13 @@ "expiresAt": "到期时间", "daysLeft": "剩余天数", "devices": "设备", + "devices_other": "{{count}} 个设备", "extraDevices": "额外设备", "extraDevicesIncluded": "含 {{count}} 个额外设备", + "extraDevicesIncluded_other": "含 {{count}} 个额外设备", "baseTariff": "套餐", - "servers": "服务器", + "serversLabel": "服务器", + "servers_other": "{{count}} 个服务器", "traffic": "流量", "unlimited": "无限", "used": "已使用", @@ -134,8 +160,11 @@ "buyDevices": "增加设备", "renewalOptions": "续费选项", "days": "天", + "days_other": "{{count}} 天", "hours": "小时", + "hours_other": "{{count}} 小时", "minutes": "分钟", + "minutes_other": "{{count}} 分钟", "price": "价格", "noSubscription": "您没有有效订阅", "getSubscription": "获取订阅", @@ -149,6 +178,7 @@ "getConfig": "连接设备", "autoRenewal": "自动续费", "daysBeforeExpiry": "到期前天数", + "daysBeforeExpiry_other": "到期前 {{count}} 天", "selectPeriod": "选择时长", "selectTraffic": "选择流量", "selectServers": "选择服务器", @@ -167,7 +197,9 @@ "title": "免费试用", "description": "免费试用我们的VPN服务!", "days": "天", + "days_other": "{{count}} 天", "devices": "设备", + "devices_other": "{{count}} 个设备", "price": "激活费用", "activate": "激活免费试用", "unavailable": "试用不可用" @@ -192,6 +224,110 @@ "selectPlatform": "选择平台", "app": "个应用", "apps": "个应用" + }, + "additionalOptions": { + "title": "附加选项", + "buyDevices": "购买更多设备", + "currentDeviceLimit": "当前限制:{{count}} 台设备", + "devicesUnavailable": "设备购买不可用", + "devicesUnit": "台设备", + "buy": "购买", + "buyTraffic": "购买更多流量", + "currentTrafficLimit": "当前限制:{{limit}} GB(已使用 {{used}} GB)", + "buyTrafficTitle": "购买更多流量", + "trafficWarning": "购买的流量将添加到当前限制,不会延续到下一个周期", + "trafficUnavailable": "您的套餐不支持购买流量", + "unlimited": "无限制", + "buyTrafficGb": "购买 {{gb}} GB", + "manageServers": "服务器管理", + "manageServersTitle": "服务器管理" + }, + "serverManagement": { + "statusLegend": "✅ — 已连接 • ➕ — 将添加(付费)• ➖ — 将断开", + "discountBanner": "您的服务器折扣:-{{percent}}%", + "forDays": "({{days}} 天)", + "perMonth": "/月", + "unavailable": "不可用", + "toAdd": "添加:", + "toDisconnect": "断开:", + "paymentProrated": "应付(按剩余天数比例计算):", + "applyChanges": "应用更改", + "selectServersHint": "选择要连接或断开的服务器", + "noServersAvailable": "没有可管理的服务器" + }, + "legacy": { + "selectTariffTitle": "选择续费套餐", + "selectTariffDescription": "您的当前订阅是在引入套餐之前创建的。要续费,请选择一个可用的套餐。", + "currentSubContinues": "您的当前订阅将继续有效直到到期。" + }, + "switchTariff": { + "dailyPayment": "每日付费", + "dailyChargeDescription": "每日从余额中扣除", + "currentTariff": "当前套餐", + "free": "免费", + "newTariff": "新套餐", + "remainingDays": "剩余天数", + "switch": "切换", + "title": "切换套餐", + "upgradeCost": "升级费用" + }, + "promoGroup": { + "yourGroup": "您的组:{{name}}", + "personalDiscountsApplied": "个人折扣已应用于价格" + }, + "tariff": { + "perDay": "/ 天", + "flexiblePayment": "灵活付费", + "selectForRenewal": "选择续费" + }, + "customDays": { + "title": "自定义天数", + "perDay": "/天" + }, + "customTraffic": { + "label": "流量", + "selectVolume": "选择流量", + "default": "默认:{{label}}" + }, + "confirmDeleteAllDevices": "删除所有设备?", + "confirmDeleteDevice": "删除此设备?", + "currentTariff": "当前", + "deleteAllDevices": "全部删除", + "deleteDevice": "删除设备", + "devicesFree": "免费设备", + "from": "起", + "month": "月", + "myDevices": "我的设备", + "noDevices": "没有已连接的设备", + "perExtraDevice": "/ 额外设备", + "perMonth": "/月", + "purchasedTraffic": "已购流量", + "trafficResetAt": "重置", + "dailyPurchase": { + "activate": "以{{price}}激活", + "canPause": "可随时暂停", + "chargedDaily": "每天从余额中扣费", + "costPerDay": "每天费用", + "pausedOnLowBalance": "余额不足时订阅将暂停" + }, + "pause": { + "active": "活跃", + "days": "天", + "hours": "时", + "insufficientBalance": "余额不足,无法恢复订阅", + "minutes": "分", + "nextCharge": "距下次扣费", + "pauseBtn": "暂停", + "paused": "已暂停", + "pausedDescription": "扣费已停止。订阅有效期至", + "pausedInfo": "订阅已暂停", + "resumeBtn": "恢复", + "title": "暂停订阅", + "willBeCharged": "将扣费" + }, + "summary": { + "period": "周期:{{label}}", + "traffic": "流量:{{gb}} GB" } }, "balance": { @@ -248,7 +384,25 @@ } }, "minAmountError": "最小金额:{{amount}}", - "maxAmountError": "最大金额:{{amount}}" + "maxAmountError": "最大金额:{{amount}}", + "paymentReady": "支付链接已准备就绪", + "clickToOpenPayment": "点击下方按钮在新标签页中打开支付页面", + "openPaymentPage": "打开支付页面", + "errors": { + "noPaymentLink": "服务器未返回支付链接", + "starsOnlyInTelegram": "Stars支付仅在Telegram Mini App中可用", + "generic": "错误:{{details}}", + "invoiceFailed": "创建账单失败", + "rateLimit": "请等待 {{seconds}} 秒", + "selectMethod": "请选择支付方式", + "enterAmount": "请输入金额", + "amountRange": "金额:{{min}} – {{max}} ₽" + }, + "insufficientFunds": "余额不足", + "missing": "缺少", + "noPaymentMethods": "支付方式不可用", + "selectPaymentMethod": "选择支付方式", + "topUpToComplete": "充值以完成购买" }, "referral": { "title": "推荐计划", @@ -322,7 +476,13 @@ "invalidFileType": "文件类型无效。请使用JPEG、PNG、GIF或WebP。", "fileTooLarge": "文件过大。最大10MB。", "uploadFailed": "图片上传失败", - "imageLoadFailed": "图片加载失败" + "imageLoadFailed": "图片加载失败", + "tooManyRequests": "请求过多。请等待 {{seconds}} 秒。", + "contactSupport": "如需帮助,请联系{{username}}", + "contactUs": "联系支持", + "openSupport": "打开支持", + "ticketsDisabled": "工单已禁用", + "useExternalLink": "请使用外部链接获取支持" }, "wheel": { "title": "幸运转盘", @@ -332,6 +492,7 @@ "stars": "Stars", "telegramStars": "Telegram Stars", "days": "天", + "days_other": "{{count}} 天", "subscriptionDays": "订阅天数", "day": "天", "spin": "开始抽奖!", @@ -343,13 +504,18 @@ "oops": "哎呀!", "yourPromoCode": "您的优惠码:", "close": "关闭", + "noPrize": "这次没有中奖...", + "payWithDays": "用天数支付", + "youWon": "恭喜中奖", + "starsPaymentSuccessCheckHistory": "支付成功!请查看历史记录或Telegram获取结果。", "errors": { "networkError": "网络错误", "loadFailed": "加载转盘配置失败", "dailyLimitReached": "已达每日限制", "cannotSpin": "当前无法抽奖", "insufficientBalance": "余额不足", - "topUpRequired": "请充值以支付抽奖费用" + "topUpRequired": "请充值以支付抽奖费用", + "starsNotAvailable": "Stars支付不可用。请通过Telegram打开应用。" }, "payWithStars": "支付 {stars} Stars", "processingPayment": "处理中...", @@ -374,7 +540,14 @@ "servers": "服务器", "broadcasts": "群发", "emailTemplates": "邮件模板", - "paymentMethods": "支付方式" + "paymentMethods": "支付方式", + "banSystem": "封禁监控", + "campaigns": "活动", + "payments": "支付", + "promoOffers": "促销优惠", + "promocodes": "促销码", + "remnawave": "RemnaWave", + "users": "用户" }, "panel": { "title": "管理面板", @@ -388,24 +561,31 @@ "serversDesc": "配置VPN服务器", "broadcastsDesc": "向用户群发消息", "emailTemplatesDesc": "管理邮件通知模板", - "paymentMethodsDesc": "配置支付方式排序和显示条件" + "paymentMethodsDesc": "配置支付方式排序和显示条件", + "banSystemDesc": "封禁监控和违规", + "campaignsDesc": "广告活动", + "paymentsDesc": "支付验证", + "promoOffersDesc": "个性化折扣", + "promocodesDesc": "管理促销码", + "remnawaveDesc": "面板管理和统计", + "usersDesc": "管理机器人用户" }, "paymentMethods": { - "title": "支付方式", - "description": "配置显示顺序和条件", + "title": "支付方法", + "description": "配置顺序和显示条件", "enabled": "开启", "disabled": "关闭", "notConfigured": "未配置", - "dragToReorder": "拖拽排序", - "dragHint": "拖拽卡片更改排序。点击进行配置。", - "saveOrder": "保存排序", - "orderSaved": "排序已保存", + "dragToReorder": "拖动以重新排序", + "dragHint": "拖动卡片以重新排序。点击以配置。", + "saveOrder": "保存顺序", + "orderSaved": "顺序已保存", "saved": "设置已保存", - "noMethods": "没有配置支付方式", - "methodEnabled": "启用方式", - "providerNotConfigured": "env中未配置提供商", + "noMethods": "没有配置的支付方法", + "methodEnabled": "方法已启用", + "providerNotConfigured": "提供商未在env中配置", "displayName": "显示名称", - "displayNameHint": "留空使用默认名称", + "displayNameHint": "留空以使用默认名称", "subOptions": "支付选项", "minAmount": "最小金额(戈比)", "maxAmount": "最大金额(戈比)", @@ -413,16 +593,20 @@ "userTypeFilter": "用户类型", "userTypeAll": "全部", "userTypeTelegram": "Telegram", - "userTypeEmail": "Email", + "userTypeEmail": "电子邮件", "firstTopupFilter": "首次充值", - "firstTopupAny": "不限", - "firstTopupYes": "已充值", - "firstTopupNo": "未充值", + "firstTopupAny": "不重要", + "firstTopupYes": "有充值", + "firstTopupNo": "无充值", + "firstTopupWas": "有过", + "firstTopupWasNot": "没有过", "promoGroupFilter": "促销组", "promoGroupAll": "所有组", - "promoGroupSelected": "选定的", + "promoGroupSelected": "已选择", "promoGroupsShort": "组", - "noPromoGroups": "没有促销组" + "noPromoGroups": "没有促销组", + "cancelButton": "取消", + "saveButton": "保存" }, "emailTemplates": { "title": "邮件模板", @@ -444,6 +628,20 @@ "variables": "可用变量", "clickToCopy": "点击复制" }, + "payments": { + "title": "支付验证", + "description": "最近24小时内的待处理支付", + "totalPending": "总待处理", + "filterByMethod": "按方法筛选", + "paid": "已支付", + "user": "用户", + "openLink": "打开链接", + "checking": "检查中...", + "checkStatus": "检查状态", + "noPayments": "没有待处理的支付", + "prev": "上一页", + "next": "下一页" + }, "wheel": { "title": "幸运转盘设置", "enabled": "已启用", @@ -499,14 +697,15 @@ "targetRtp": "目标", "prizeDistribution": "奖品分布", "times": "次", + "times_other": "{{count}} 次", "topWins": "最高奖品" } }, "broadcasts": { - "title": "群发", - "subtitle": "向用户群发消息", + "title": "广播", + "subtitle": "历史和管理", "create": "创建群发", - "empty": "暂无群发", + "empty": "没有广播", "selectFilter": "选择受众", "selectFilterPlaceholder": "选择筛选条件...", "recipients": "人", @@ -526,7 +725,27 @@ "failed": "失败", "filter": "筛选", "message": "消息", - "unknownAdmin": "未知管理员" + "unknownAdmin": "未知", + "prev": "上一页", + "next": "下一页", + "status": { + "queued": "排队中", + "inProgress": "发送中", + "completed": "已完成", + "partial": "部分完成", + "failed": "失败", + "cancelled": "已取消", + "cancelling": "取消中" + }, + "filterGroups": { + "basic": "基础", + "subscription": "按订阅", + "traffic": "按流量", + "registration": "按注册", + "activity": "按活动", + "source": "按来源", + "tariff": "按套餐" + } }, "settings": { "title": "系统设置", @@ -560,7 +779,49 @@ "conversionLabel": "转化标签(可选)", "googleLabelPlaceholder": "例如: AbCdEfGhIjKl", "googleLabelHint": "用于事件跟踪的转化标签", - "analyticsHint": "计数器自动嵌入所有页面。保存 ID 后,脚本将在下次页面加载时生效。要移除计数器,请清空字段并保存。" + "analyticsHint": "计数器自动嵌入所有页面。保存 ID 后,脚本将在下次页面加载时生效。要移除计数器,请清空字段并保存。", + "inputPlaceholder": "输入值...", + "ctrlEnterHint": "Ctrl+Enter保存", + "cancelButton": "取消", + "saveButton": "保存", + "saveHint": "保存 (Enter)", + "cancelHint": "取消 (Esc)", + "removeFromFavorites": "从收藏中删除", + "addToFavorites": "添加到收藏", + "enabled": "已启用", + "disabled": "已禁用", + "foundCount": "找到:{{count}}", + "notFound": "未找到", + "byQuery": "搜索\"{{query}}\"", + "accentColor": "强调色", + "animatedBackground": "动画背景", + "animatedBackgroundDesc": "显示动画背景效果", + "autoFullscreen": "自动全屏", + "autoFullscreenDesc": "在Telegram中自动展开", + "availableThemes": "可用主题", + "colors": { + "background": "背景", + "error": "错误", + "success": "成功", + "surface": "表面", + "text": "文本", + "textSecondary": "次要文本", + "warning": "警告" + }, + "customColors": "自定义颜色", + "darkTheme": "暗色主题", + "emailAuth": "邮箱认证", + "emailAuthDesc": "允许通过邮箱登录", + "favoritesEmpty": "暂无收藏", + "favoritesHint": "点击星标将设置添加到这里", + "interfaceOptions": "界面选项", + "lightTheme": "亮色主题", + "logoAndName": "标志和名称", + "notSpecified": "未指定", + "projectName": "项目名称", + "quickPresets": "快速预设", + "resetAllColors": "重置所有颜色", + "statusColors": "状态颜色" }, "apps": { "title": "应用管理", @@ -587,6 +848,22 @@ "afterSubscription": "添加订阅后", "stepTitle": "标题", "stepDescription": "描述", + "availableConfigs": "可用配置", + "confirmImport": "导入", + "export": "导出", + "exportApps": "导出应用到JSON", + "import": "导入", + "importApps": "从JSON导入应用", + "importCreateError": "创建某些应用失败", + "importError": "无效的JSON文件格式", + "importPreview": "导入预览", + "noAppsToImport": "没有可导入的应用", + "refreshRemnaWave": "从RemnaWave刷新", + "remnaWaveConfigUuid": "配置UUID", + "remnaWaveConfigUuidHint": "来自RemnaWave面板的订阅页面配置UUID", + "remnaWaveMode": "显示来自RemnaWave面板的应用。只读模式。", + "remnaWaveSettings": "RemnaWave设置", + "remnaWaveToggle": "切换RemnaWave源", "tabs": { "basic": "基本", "installation": "安装", @@ -629,7 +906,13 @@ "checkIntervalDesc": "检查过期工单的频率(30-600秒)", "reminderCooldown": "提醒间隔(分钟)", "reminderCooldownDesc": "提醒之间的最小时间(1-120分钟)", - "settingsUpdateError": "保存设置时出错" + "settingsUpdateError": "保存设置时出错", + "adminNotificationsEnabled": "管理员通知", + "adminNotificationsEnabledDesc": "向管理员发送新工单和回复通知", + "cabinetNotifications": "面板通知", + "copyTelegramId": "点击复制Telegram ID", + "userNotificationsEnabled": "用户通知", + "userNotificationsEnabledDesc": "向用户发送管理员回复通知" }, "tariffs": { "title": "套餐管理", @@ -648,8 +931,11 @@ "tierHint": "1-10,影响升级优先级", "unlimited": "无限", "devices": "设备", + "devices_other": "{{count}} 个设备", "servers": "服务器", + "servers_other": "{{count}} 个服务器", "subscriptions": "订阅", + "subscriptions_other": "{{count}} 个订阅", "trial": "试用", "inactive": "未激活", "activate": "激活", @@ -659,6 +945,7 @@ "confirmDelete": "删除套餐?", "confirmDeleteText": "此操作不可撤销。套餐将被永久删除。", "days": "天", + "days_other": "{{count}} 天", "tabs": { "basic": "基本", "prices": "价格", @@ -666,7 +953,80 @@ }, "pricesHint": "设置每个周期的价格", "serversHint": "选择此套餐可用的服务器", - "noServers": "暂无可用服务器" + "noServers": "暂无可用服务器", + "selectType": "选择套餐类型", + "periodTariff": "周期套餐", + "periodTariffDesc": "按周期付款(7、30、90天等)。灵活的周期和价格。", + "dailyTariff": "日套餐", + "dailyTariffDesc": "每日从余额中扣除。可以暂停。", + "editTitle": "编辑套餐", + "newPeriodTitle": "新周期套餐", + "newDailyTitle": "新日套餐", + "periodPayment": "周期付款", + "dailyDeduction": "每日扣除", + "tabBasic": "基本", + "tabPeriods": "周期", + "tabServers": "服务器", + "tabExtra": "额外", + "nameLabel": "套餐名称", + "nameExamplePeriod": "例如:标准", + "nameExampleDaily": "例如:日套餐", + "descriptionLabel": "描述", + "trafficLimitLabel": "流量限制", + "gbUnit": "GB", + "trafficLimitHint": "0 = 无限流量", + "deviceLimitLabel": "套餐中的设备数", + "tierLevelLabel": "套餐等级", + "tierLevelHint": "影响套餐之间的升级可用性", + "periodsTabHint": "为套餐添加周期和价格。用户将能够从添加的周期中选择。", + "addPeriodTitle": "添加周期", + "daysLabel": "天", + "priceLabel": "价格(₽)", + "addButton": "添加", + "noPeriodsHint": "没有添加的周期。请至少添加一个周期。", + "daysShort": "天", + "serversTabHint": "选择此套餐上可用的服务器。", + "noServersAvailable": "没有可用的服务器", + "extraDeviceTitle": "额外设备", + "devicePriceLabel": "设备价格(30天):", + "devicePriceHint": "0 = 无法购买设备", + "maxDeviceLabel": "套餐最大设备数:", + "noLimitHint": "0 = 无限制", + "extraTrafficTitle": "额外流量", + "trafficMaxLimitLabel": "最大限制:", + "trafficLimitHint2": "(0 = 无限制)", + "trafficPackagesLabel": "流量包:", + "gbPackageUnit": "GB:", + "customDaysTitle": "自定义天数", + "customDaysDesc": "用户自行选择订阅期限", + "pricePerDayLabel": "每天价格:", + "minDaysLabel": "最少天数:", + "maxDaysLabel": "最多天数:", + "customTrafficTitle": "自定义流量", + "customTrafficDesc": "用户在购买时自行选择流量", + "pricePerGbLabel": "每GB价格:", + "minTrafficLabel": "最少GB:", + "maxTrafficLabel": "最多GB:", + "trafficResetModeTitle": "流量重置模式", + "trafficResetModeDesc": "定义此套餐订户的已用流量何时重置", + "resetModeGlobal": "全局设置", + "resetModeGlobalDesc": "使用机器人配置中的值", + "resetModeDaily": "每日", + "resetModeDailyDesc": "每天重置", + "resetModeWeekly": "每周", + "resetModeWeeklyDesc": "每周重置", + "resetModeMonthly": "每月", + "resetModeMonthlyDesc": "每月重置", + "resetModeNever": "从不", + "resetModeNeverDesc": "流量不重置", + "cancelButton": "取消", + "savingButton": "保存中...", + "saveButton": "保存", + "dailyType": "日套餐", + "periodType": "周期套餐", + "dailyPriceLabel": "每天价格", + "currencyPerDay": "₽/天", + "dailyDeductionDesc": "每天从用户余额中扣除" }, "servers": { "title": "服务器管理", @@ -696,7 +1056,507 @@ "full": "已满", "enable": "启用", "disable": "禁用", - "toggleTrial": "切换试用" + "toggleTrial": "切换试用", + "loadError": "加载服务器失败" + }, + "campaigns": { + "title": "广告活动", + "subtitle": "管理广告链接", + "createButton": "创建", + "noData": "没有广告活动", + "bonusType": { + "balance": "余额", + "subscription": "订阅", + "tariff": "套餐", + "none": "仅链接" + }, + "overview": { + "totalCampaigns": "活动总数", + "active": "活跃", + "registrations": "注册数", + "bonusesIssued": "已发放奖励" + }, + "table": { + "inactive": "未激活", + "registrations": "{{count}} 次注册", + "revenue": "{{amount}} 收入", + "conversion": "{{rate}}% 转化", + "statistics": "统计", + "deactivate": "停用", + "activate": "启用", + "edit": "编辑", + "delete": "删除" + }, + "modal": { + "editTitle": "编辑活动", + "createTitle": "新建活动", + "close": "关闭" + }, + "form": { + "name": "名称", + "namePlaceholder": "例如:Instagram 广告", + "startParameter": "标签(start 参数)", + "startParameterHint": "仅限拉丁字母、数字、_ 和 -", + "bonusType": "奖励类型", + "balanceBonus": "余额奖励", + "trialSubscription": "试用订阅", + "days": "天数", + "trafficGb": "流量(GB)", + "devices": "设备数", + "servers": "服务器", + "tariff": "套餐", + "selectTariff": "选择套餐", + "notSelected": "未选择", + "tariffOption": "{{traffic}} GB,{{devices}} 台设备", + "durationDays": "时长(天)", + "noBonusDescription": "无奖励活动——仅用于跟踪点击和注册。", + "active": "启用", + "cancel": "取消", + "save": "保存", + "saving": "保存中..." + }, + "stats": { + "registrations": "注册数", + "revenue": "收入", + "paidUsers": "已付费", + "conversion": "转化率", + "bonusesIssued": "已发放奖励", + "subscriptionsIssued": "{{count}} 个订阅", + "tariffsIssued": "{{count}} 个套餐", + "avgRevenuePerUser": "每用户平均收入", + "avgFirstPayment": "平均首次付款", + "trialSubscriptions": "试用订阅", + "trialCount": "{{total}}(活跃:{{active}})", + "trialConversion": "试用转化率", + "lastRegistration": "最后注册", + "active": "活跃", + "inactive": "未激活", + "copy": "复制", + "copied": "已复制!", + "users": "用户" + }, + "users": { + "title": "活动用户", + "campaignRegistrations": "{{name}} — {{count}} 次注册", + "noUsers": "没有注册用户", + "user": "用户", + "bonus": "奖励", + "balance": "余额", + "status": "状态", + "date": "日期", + "noName": "无名称", + "paid": "已付费", + "prev": "上一页", + "next": "下一页", + "pageOf": "第 {{page}} 页,共 {{totalPages}} 页" + }, + "confirm": { + "deleteTitle": "删除活动?", + "deleteText": "此操作不可撤销。有注册记录的活动无法删除。", + "cancel": "取消", + "delete": "删除" + } + }, + "promocodes": { + "title": "促销码", + "subtitle": "管理促销码和折扣组", + "addPromocode": "添加促销码", + "addGroup": "添加组", + "noPromocodes": "没有促销码", + "noGroups": "没有折扣组", + "firstPurchase": "首次购买", + "used": "已使用", + "until": "有效期至", + "discountForHours": "-{{percent}}% {{hours}}小时", + "tabs": { + "promocodes": "促销码 ({{count}})", + "groups": "折扣组 ({{count}})" + }, + "type": { + "balance": "余额", + "subscriptionDays": "订阅天数", + "trialSubscription": "试用订阅", + "promoGroup": "折扣组", + "discount": "折扣 %" + }, + "modal": { + "editPromocode": "编辑促销码", + "newPromocode": "新促销码", + "editGroup": "编辑组", + "newGroup": "新折扣组", + "close": "关闭", + "edit": "编辑" + }, + "form": { + "code": "促销码", + "type": "促销码类型", + "typeBalance": "余额充值", + "typeSubscriptionDays": "订阅天数", + "typeTrialSubscription": "试用订阅", + "typePromoGroup": "折扣组", + "typeDiscount": "百分比折扣", + "bonusAmount": "奖金金额", + "rub": "卢布", + "daysCount": "天数", + "days": "天", + "discountGroup": "折扣组", + "selectGroup": "选择组...", + "discountPercent": "折扣百分比", + "discountHint": "折扣在付款时一次性使用", + "validityPeriod": "有效期", + "hours": "小时", + "validityHint": "激活后折扣有效的小时数", + "maxUses": "最大使用次数", + "unlimitedHint": "0 = 无限制", + "validUntil": "有效期至", + "validUntilHint": "留空表示永久有效", + "active": "活跃", + "firstPurchaseOnly": "仅限首次购买", + "cancel": "取消", + "saving": "保存中...", + "save": "保存" + }, + "stats": { + "totalUses": "总使用次数", + "today": "今天", + "remaining": "剩余", + "details": "促销码详情", + "type": "类型", + "bonus": "奖金", + "daysLabel": "天数", + "discountLabel": "折扣", + "validFor": "有效期", + "hoursValue": "{{count}} 小时", + "limit": "限制", + "status": "状态", + "active": "活跃", + "inactive": "未激活", + "created": "创建时间", + "validUntil": "有效期至", + "unlimited": "无限期", + "restriction": "限制", + "firstPurchaseOnly": "仅限首次购买", + "usageHistory": "使用记录", + "noUsages": "促销码尚未使用", + "totalPromocodes": "促销码总数", + "activeCount": "活跃的", + "usagesCount": "使用次数", + "exhausted": "已用完" + }, + "actions": { + "stats": "统计", + "edit": "编辑", + "delete": "删除" + }, + "groups": { + "name": "组名称", + "namePlaceholder": "VIP客户", + "categoryDiscounts": "分类折扣", + "servers": "服务器", + "traffic": "流量", + "devices": "设备", + "periodDiscounts": "按期折扣", + "add": "添加", + "periodDiscountsHint": "购买指定天数的订阅时适用折扣", + "noPeriodDiscounts": "没有按期折扣", + "daysPlaceholder": "天", + "daysArrow": "天 →", + "autoAssign": "消费达到时自动分配", + "autoAssignHint": "0 = 不自动分配", + "applyToAddons": "应用于附加服务", + "default": "默认", + "daysShort": "{{days}} 天", + "autoFrom": "自动 从 {{amount}} 卢布", + "members": "{{count}} 名成员" + }, + "confirm": { + "deletePromocode": "删除促销码?", + "deleteGroup": "删除组?", + "deletePromocodeText": "促销码将被永久删除。", + "deleteGroupText": "该组将被删除。用户将失去该组的折扣。", + "deleteButton": "删除" + } + }, + "users": { + "title": "用户", + "subtitle": "机器人用户管理", + "search": "按ID、姓名、用户名搜索...", + "noData": "未找到用户", + "purchaseCount": "{{count}} 次购买", + "noPurchases": "无购买记录", + "stats": { + "total": "总计", + "active": "活跃", + "withSubscription": "有订阅", + "newToday": "今日新增", + "blocked": "已封禁" + }, + "status": { + "active": "活跃", + "blocked": "已封禁", + "deleted": "已删除", + "subscription": "订阅", + "trial": "试用", + "expired": "已过期" + }, + "filters": { + "allStatuses": "所有状态", + "byDate": "按日期", + "byBalance": "按余额", + "byActivity": "按活跃度", + "bySpent": "按消费" + }, + "pagination": { + "showing": "显示 {{from}}-{{to}},共 {{total}}" + }, + "actions": { + "block": "封禁", + "unblock": "解封", + "apply": "应用", + "applying": "应用中..." + }, + "confirm": { + "block": "确定封禁此用户?" + }, + "detail": { + "tabs": { + "info": "信息", + "subscription": "订阅", + "balance": "余额", + "sync": "同步" + }, + "status": "状态", + "language": "语言", + "registration": "注册时间", + "lastActivity": "最后活跃", + "totalSpent": "总消费", + "purchases": "购买次数", + "referral": { + "title": "推荐计划", + "referrals": "推荐人数", + "earned": "已赚取", + "commission": "佣金" + }, + "restrictions": { + "title": "限制", + "topup": "• 禁止充值", + "subscription": "• 禁止购买订阅", + "reason": "原因" + }, + "subscription": { + "current": "当前订阅", + "tariff": "套餐", + "notSpecified": "未指定", + "validUntil": "有效期至", + "traffic": "流量", + "devices": "设备数", + "actions": "操作", + "extend": "延长", + "changeTariff": "更换套餐", + "cancel": "取消", + "activate": "激活", + "days": "天数", + "selectTariff": "选择套餐", + "unavailable": "(不可用)", + "noActive": "无活跃订阅", + "create": "创建订阅", + "creating": "创建中..." + }, + "balance": { + "current": "当前余额", + "amountPlaceholder": "金额(卢布)", + "descriptionPlaceholder": "描述(可选)", + "add": "充值", + "subtract": "扣除", + "addByAdmin": "管理员充值", + "subtractByAdmin": "管理员扣除", + "recentTransactions": "最近交易" + }, + "sync": { + "hasDifferences": "存在差异", + "synced": "已同步", + "bot": "机器人", + "panel": "面板", + "statusLabel": "状态", + "until": "截止", + "traffic": "流量", + "devices": "设备", + "squads": "小组", + "notLinked": "未绑定", + "fromPanel": "从面板同步到机器人", + "toPanel": "从机器人同步到面板" + } + } + }, + "promoOffers": { + "title": "促销优惠", + "subtitle": "模板、群发和优惠日志", + "sendButton": "发送", + "tabs": { + "templates": "模板 ({{count}})", + "logs": "日志" + }, + "noData": { + "templates": "没有模板", + "logs": "没有记录" + }, + "status": { + "active": "活跃", + "inactive": "未激活" + }, + "table": { + "discount": "折扣", + "offerDuration": "优惠期限", + "hoursShort": "{{hours}}小时", + "discountDuration": "折扣有效期", + "testAccess": "测试访问" + }, + "form": { + "editTemplate": "编辑模板", + "templateName": "模板名称", + "messageText": "消息文本", + "buttonText": "按钮文本", + "validHours": "优惠期限(小时)", + "activationTime": "激活时间", + "discountPercent": "折扣 (%)", + "testDurationHours": "访问时长(小时)", + "defaultZero": "0 = 默认", + "activeDiscountHours": "折扣有效期(小时)", + "discountDurationHint": "激活后折扣持续多长时间", + "templateActive": "模板已激活", + "saving": "保存中..." + }, + "send": { + "title": "发送促销优惠", + "offerTemplate": "优惠模板", + "discountLabel": "{{percent}}% 折扣", + "hoursToActivate": "{{hours}}小时内激活", + "sendTo": "发送对象", + "segment": "分组", + "user": "用户", + "userIdPlaceholder": "Telegram ID 或 User ID", + "preview": "预览", + "sending": "发送中...", + "sendButton": "发送" + }, + "result": { + "sentTitle": "已发送!", + "offersCreated": "已创建优惠: {{count}}", + "notificationsSent": "已发送通知: {{count}}", + "notificationsFailed": "(失败: {{count}})", + "sendError": "发送优惠失败" + }, + "actions": { + "created": "已创建", + "claimed": "已领取", + "consumed": "已使用", + "disabled": "已停用" + }, + "segments": { + "all": "所有用户", + "active": "活跃订阅者", + "trial": "试用用户", + "trialEnding": "试用即将结束", + "expiring": "订阅即将到期", + "expired": "已过期订阅", + "zero": "零余额", + "autopayFailed": "自动支付失败", + "lowBalance": "余额不足", + "inactive30d": "30天未活跃", + "inactive60d": "60天未活跃", + "inactive90d": "90天未活跃", + "customToday": "今天注册", + "customWeek": "本周注册", + "customMonth": "本月注册", + "customActiveToday": "今天活跃" + }, + "offerType": { + "testAccess": "测试访问", + "testAccessDesc": "临时访问额外服务器", + "extendDiscount": "续订折扣", + "extendDiscountDesc": "当前订阅者折扣", + "purchaseDiscount": "购买折扣", + "purchaseDiscountDesc": "新用户折扣" + } + }, + "groups": { + "analytics": "分析", + "marketing": "营销", + "system": "系统", + "tariffs": "套餐与销售", + "users": "用户" + }, + "theme": { + "accentColor": "强调色", + "customizeColors": "自定义颜色", + "hexCode": "HEX代码", + "hue": "色调", + "lightness": "亮度", + "quickPresets": "快速预设", + "saturation": "饱和度" + }, + "remnawave": { + "connected": "已连接", + "disconnected": "未配置", + "noData": "加载数据失败", + "title": "RemnaWave", + "subtitle": "面板管理和统计", + "tabs": { + "overview": "概览", + "nodes": "节点", + "squads": "小队", + "sync": "同步" + }, + "nodes": { + "confirmRestartAll": "确定要重启所有节点吗?", + "disable": "禁用", + "disabled": "已禁用", + "enable": "启用", + "noNodes": "未找到节点", + "offline": "离线", + "online": "在线", + "restart": "重启", + "restartAll": "全部重启" + }, + "overview": { + "bandwidth": "实时带宽", + "connections": "连接数", + "cpu": "CPU核心", + "download": "下载", + "memory": "内存", + "nodesOnline": "在线节点", + "server": "服务器", + "system": "系统", + "total": "总计", + "totalUsers": "总用户数", + "traffic": "流量统计", + "upload": "上传", + "uptime": "运行时间", + "usersByStatus": "按状态分类的用户", + "usersOnline": "在线" + }, + "squads": { + "noSquads": "未找到小队", + "notSynced": "未同步", + "syncServers": "同步服务器", + "synced": "已同步" + }, + "sync": { + "autoSync": "自动同步", + "cleanup": "清理", + "cleanupDesc": "删除无用户的孤立订阅", + "fromPanel": "从面板同步", + "fromPanelDesc": "从RemnaWave面板导入用户到机器人数据库", + "manual": "手动同步", + "runNow": "立即运行", + "statuses": "同步状态", + "statusesDesc": "与面板同步订阅状态", + "subscriptions": "订阅", + "toPanel": "同步到面板", + "toPanelDesc": "从机器人数据库导出用户到RemnaWave面板", + "validate": "验证", + "validateDesc": "检查并修复订阅不一致" + } } }, "adminDashboard": { @@ -722,7 +1582,9 @@ "usersOnline": "在线", "traffic": "流量", "enable": "启用", - "disable": "禁用" + "disable": "禁用", + "hide": "隐藏 ({{count}})", + "showMore": "显示更多 {{count}} 个节点" }, "revenue": { "title": "收入", @@ -747,6 +1609,36 @@ "available": "可用", "withConnections": "有连接", "revenue": "收入" + }, + "topReferrers": { + "title": "顶级推荐者", + "stats": "推荐者,{{count}} 邀请", + "byEarnings": "按收入", + "byInvited": "按邀请", + "invites": "邀请", + "people": "人" + }, + "period": { + "today": "今天", + "week": "一周", + "month": "一个月" + }, + "topCampaigns": { + "title": "顶级活动链接", + "stats": "活动,{{count}} 注册", + "total": "活动总计" + }, + "recentPayments": { + "title": "最近的支付", + "today": "今天:{{amount}}", + "week": "本周:{{amount}}" + }, + "table": { + "user": "用户", + "type": "类型", + "amount": "金额", + "method": "方法", + "date": "日期" } }, "profile": { @@ -829,6 +1721,7 @@ "error": "加载活动失败", "noContests": "暂无活动", "days": "天", + "days_other": "{{count}} 天", "play": "参与", "alreadyPlayed": "已参与", "enterAnswer": "输入答案", @@ -840,6 +1733,7 @@ "error": "加载问卷失败", "noPolls": "暂无问卷", "questions": "个问题", + "questions_other": "{{count}} 个问题", "question": "问题", "of": "/", "start": "开始", @@ -913,8 +1807,53 @@ "days": "天", "hours": "时", "minutes": "分" + }, + "offers": { + "expired": "已过期", + "testAccess": "测试访问", + "discountPercent": "折扣 {{percent}}%", + "specialOffer": "特别优惠", + "serverAccess": "访问{{count}}个服务器", + "serverAccess_other": "访问 {{count}} 台服务器", + "additionalServers": "访问额外服务器", + "activateDiscountHint": "激活订阅折扣", + "activationFailed": "无法激活优惠", + "discountActiveTitle": "{{percent}}% 折扣已激活", + "statusActive": "有效", + "expires": "到期:{{time}}", + "remaining": "剩余:{{time}}", + "test": "测试", + "activating": "激活中...", + "activate": "激活" } }, + "telegramRedirect": { + "maxRetries": "重试次数已达上限。请稍后再试。", + "redirecting": "正在跳转...", + "loginAlternative": "使用其他方式登录", + "openInTelegram": "在Telegram中打开", + "openInTelegramDesc": "要自动登录,请通过Telegram机器人打开此应用", + "redirectToLogin": "正在跳转到登录页面..." + }, + "deepLink": { + "connecting": "正在连接", + "redirecting": "将在", + "seconds": "秒后跳转", + "manual": "如果没有反应,请点击下方按钮。", + "openApp": "打开应用", + "copyLink": "复制订阅链接", + "copied": "已复制!", + "tryAgain": "重试", + "backToCabinet": "返回个人中心", + "errorTitle": "错误", + "errorDesc": "未找到连接链接", + "goToSubscription": "前往订阅", + "howToAdd": "如何手动添加:", + "step1": "使用上方按钮复制链接", + "step2": "打开应用", + "step3": "找到\"+\"或\"添加订阅\"", + "step4": "选择\"从剪贴板\"或\"粘贴链接\"" + }, "blocking": { "maintenance": { "title": "系统维护", @@ -933,5 +1872,123 @@ "notSubscribed": "您还没有订阅该频道", "checkError": "检查失败。请稍后重试。" } + }, + "banSystem": { + "title": "封禁监控", + "subtitle": "BedolagaBan系统管理", + "configureHint": "在配置中设置BAN_SYSTEM_API_URL和BAN_SYSTEM_API_TOKEN", + "loadError": "加载数据失败", + "notConfigured": "封禁系统未配置", + "contactTelegram": "在Telegram中联系", + "tabs": { + "dashboard": "统计", + "nodes": "节点", + "agents": "代理", + "users": "用户", + "punishments": "封禁", + "violations": "违规", + "reports": "报告", + "traffic": "流量", + "health": "健康", + "settings": "设置" + }, + "stats": { + "panelStatus": "面板状态", + "connected": "已连接", + "disconnected": "已断开", + "nodesOnline": "在线节点", + "agentsOnline": "在线代理", + "activeUsers": "活跃用户", + "activeBans": "活跃封禁", + "usersOverLimit": "超限", + "total": "总计", + "totalRequests": "总请求数", + "uptime": "运行时间" + }, + "nodes": { + "status": "状态", + "online": "在线", + "offline": "离线", + "users": "用户", + "noNodes": "未找到节点" + }, + "agents": { + "status": "状态", + "online": "在线", + "offline": "离线", + "node": "节点", + "queue": "队列", + "sent": "已发送", + "totalSent": "总发送", + "dropped": "丢弃", + "totalDropped": "总丢弃", + "health": "健康", + "healthy": "健康", + "warning": "警告", + "critical": "严重", + "noAgents": "未找到代理" + }, + "users": { + "status": "状态", + "email": "邮箱", + "ipCount": "IP", + "limit": "限制", + "ok": "正常", + "overLimit": "超限", + "networkType": "网络类型", + "bans": "封禁", + "searchPlaceholder": "按邮箱搜索...", + "viewDetails": "查看详情" + }, + "punishments": { + "user": "用户", + "reason": "原因", + "bannedAt": "封禁时间", + "enableAt": "解封时间", + "ipCount": "IP", + "limit": "限制", + "unban": "解封", + "noBans": "无活跃封禁" + }, + "violations": { + "type": "类型", + "user": "用户", + "description": "描述", + "status": "状态", + "active": "活跃", + "resolved": "已解决", + "detectedAt": "发现时间", + "noViolations": "未发现违规" + }, + "reports": { + "period": "期间", + "currentUsers": "活跃用户", + "currentIps": "唯一IP", + "count": "违规数", + "topViolators": "违规排行", + "username": "用户" + }, + "traffic": { + "enabled": "流量监控", + "status": "状态", + "ok": "正常", + "overLimit": "超限", + "bytesTotal": "总计", + "bytesLimit": "限制", + "topUsers": "流量排行", + "username": "用户", + "recentViolations": "最近违规" + }, + "health": { + "systemStatus": "系统状态" + }, + "userDetail": { + "title": "用户详情", + "ip": "IP地址", + "country": "国家", + "node": "节点", + "requests": "请求数", + "ipHistory": "IP历史" + } } } diff --git a/src/pages/AdminBanSystem.tsx b/src/pages/AdminBanSystem.tsx index 1bf2aa1..18f231f 100644 --- a/src/pages/AdminBanSystem.tsx +++ b/src/pages/AdminBanSystem.tsx @@ -514,7 +514,7 @@ export default function AdminBanSystem() { - {t('banSystem.contactTelegram', { defaultValue: 'Написать в Telegram' })} + {t('banSystem.contactTelegram')} {/* Back Button */} @@ -535,7 +535,7 @@ export default function AdminBanSystem() { d="M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18" /> - {t('common.back', { defaultValue: 'Назад' })} + {t('common.back')} diff --git a/src/pages/AdminBroadcasts.tsx b/src/pages/AdminBroadcasts.tsx index 198ee38..3928233 100644 --- a/src/pages/AdminBroadcasts.tsx +++ b/src/pages/AdminBroadcasts.tsx @@ -112,33 +112,59 @@ const ChevronDownIcon = () => ( ); // Status badge component +const statusConfig: Record