fix(i18n): backfill 120 missing keys + close 2 typo regressions from purchase refactor

Surface: users (and especially Серёжа в bugs topic) were seeing raw i18n keys
like `subscription.promoGroup.title` rendered as literal text on the renewal
screen. Audit found 118 keys referenced in code that were absent from all 4
locale files, plus 140 keys missing only in zh/fa (silently falling back to
Russian for those users).

Root causes:
- cf52999 (extract TariffPickerGrid) introduced `subscription.promoGroup.title`
  that never existed — should have been `subscription.promoGroup.yourGroup`.
- Subscription.tsx used `subscription.autopay.title` (object path) while
  SubscriptionListCard.tsx used `subscription.autopay` (leaf) — i18next can't
  hold both shapes for the same key.
- Many user-flow keys (subscription.notFound, subscriptions.empty, common.ok,
  successNotification.*, etc.) were never added when their components landed.
- Historical drift had ~140 keys in ru/en that never got zh/fa translations.

Fix:
- Rename TariffPickerGrid usage `promoGroup.title` → `promoGroup.yourGroup`.
- Rename Subscription.tsx usage `autopay.title` → `autopay`.
- Add 116 brand-new keys across ru/en/zh/fa (464 entries).
- Add 8 partially-missing keys (en+ru gaps) for landing periods, dashboard
  campaign/referrer stats, and promo offer failure counts.
- Translate 280 entries to close the zh/fa drift.

Final state: 0 keys missing in any of the 4 locale files for any code-referenced
translation key. Build + tsc green.
This commit is contained in:
c0mrade
2026-05-28 18:47:58 +03:00
parent 574da67ca0
commit e1f401c333
6 changed files with 1026 additions and 182 deletions

View File

@@ -26,11 +26,19 @@
"all": "All",
"units": {
"gb": "GB",
"perGb": "/GB"
"perGb": "/GB",
"days": "days",
"mo": "mo"
},
"retry": "Retry",
"saving": "Saving...",
"understand": "Got it"
"understand": "Got it",
"balance": "Balance",
"copied": "Copied",
"no_results": "No results",
"ok": "OK",
"processing": "Processing…",
"rangeTo": "to"
},
"nav": {
"dashboard": "Dashboard",
@@ -45,7 +53,8 @@
"info": "Info",
"wheel": "Fortune Wheel",
"menu": "Menu",
"gift": "Gift"
"gift": "Gift",
"navigation": "Navigation"
},
"notifications": {
"ticketNotifications": "Ticket Notifications",
@@ -148,7 +157,17 @@
"tariff": "Tariff",
"validUntil": "Valid until",
"goToSubscription": "Go to Subscription",
"goToBalance": "Go to Balance"
"goToBalance": "Go to Balance",
"devicesAdded": "+{{count}} devices",
"devicesPurchased": {
"title": "Devices added"
},
"totalDevices": "Total devices: {{count}}",
"totalTraffic": "Total traffic: {{value}}",
"trafficAdded": "+{{value}} traffic",
"trafficPurchased": {
"title": "Traffic added"
}
},
"auth": {
"login": "Login",
@@ -290,7 +309,10 @@
"subscription": "Subscription",
"referrals": "Referrals",
"earnings": "Earnings"
}
},
"manageAll": "Manage all",
"showAll": "Show all",
"subscriptions": "Subscriptions"
},
"subscription": {
"title": "Subscription",
@@ -346,7 +368,8 @@
"cta": {
"expiredHint": "Choose a plan and pay",
"trialHint": "More traffic and devices",
"activeHint": "Renewal and plan change"
"activeHint": "Renewal and plan change",
"renewHint": "Subscription expired — renew to continue using"
},
"connectionInfo": "Connection Info",
"copyLink": "Copy Link",
@@ -458,7 +481,8 @@
"goToApps": "Go to Apps settings",
"qrTitle": "Subscription QR Code",
"qrScanHint": "Scan to connect",
"qrButton": "QR Code"
"qrButton": "QR Code",
"openQr": "Open QR code"
},
"myDevices": "My Devices",
"noDevices": "No connected devices",
@@ -561,7 +585,14 @@
"buyTrafficGb": "Buy {{gb}} GB",
"buyUnlimited": "Buy Unlimited",
"manageServers": "Squad management",
"manageServersTitle": "Squad management"
"manageServersTitle": "Squad management",
"connectedDevices": "Connected devices",
"currentDeviceLimit": "Current device limit",
"decrementDevices": "Decrease devices",
"disconnectDevicesFirst": "Disconnect extra devices first",
"incrementDevices": "Add devices",
"minDeviceLimit": "Minimum device limit",
"newDeviceLimit": "New device limit"
},
"serverManagement": {
"statusLegend": "✅ — connected • — will be added (paid) • — will be disconnected",
@@ -620,7 +651,27 @@
"stopScan": "Close camera",
"noCamera": "Camera access denied",
"codeFound": "Code found"
}
},
"allTariffsPurchased": "All tariffs already purchased",
"autopay": "Auto-renew",
"backToList": "Back to subscriptions",
"confirmDelete": "Delete subscription?",
"dailyAutoCharge": "Daily auto-charge",
"defaultName": "Subscription",
"delete": "Delete",
"deleteTitle": "Delete subscription",
"get_config": "Get config",
"loadError": "Failed to load subscription",
"newTariff": "New tariff",
"noOptionsAvailable": "No options available",
"noRenewalOptions": "No renewal options",
"notFound": "Subscription not found",
"notFoundDesc": "It may have been deleted or not yet activated",
"servers": "Servers",
"statusActive": "Active",
"statusExpired": "Expired",
"statusLimited": "Limited",
"statusTrial": "Trial"
},
"balance": {
"title": "Balance",
@@ -738,7 +789,9 @@
"already_used_by_user": "You have already used this promo code",
"user_not_found": "User not found",
"server_error": "Server error"
}
},
"daysLeft": "Days left: {{count}}",
"selectSubscription": "Select a subscription"
},
"minAmountError": "Minimum amount: {{amount}} ₽",
"maxAmountError": "Maximum amount: {{amount}} ₽",
@@ -798,7 +851,8 @@
"timeoutDesc": "Payment processing is taking longer than usual. You can try checking the status again.",
"goToBalance": "Go to Balance",
"tryAgain": "Try Again"
}
},
"top_up": "Top up balance"
},
"referral": {
"title": "Referral Program",
@@ -984,7 +1038,8 @@
"useExternalLink": "Please use the external link to get support",
"openSupport": "Open Support",
"contactSupport": "Please contact {{username}} for support",
"contactUs": "Contact Support"
"contactUs": "Contact Support",
"create_ticket": "Create ticket"
},
"wheel": {
"title": "Fortune Wheel",
@@ -1017,7 +1072,8 @@
"insufficientBalance": "Insufficient balance",
"topUpRequired": "Top up your balance to pay for spin",
"starsNotAvailable": "Stars payment not available. Open the app via Telegram.",
"noSubscription": "An active subscription is required to spin the wheel. Activate your subscription first."
"noSubscription": "An active subscription is required to spin the wheel. Activate your subscription first.",
"selectSubscription": "Select a subscription first"
},
"payWithStars": "Pay with Stars",
"payWithDays": "Pay with days",
@@ -1036,7 +1092,8 @@
"title": "Try your luck!",
"description": "Spin the wheel and win prizes: subscription days, balance, traffic and more!",
"button": "Go to wheel"
}
},
"selectSubscription": "Select subscription"
},
"admin": {
"backgrounds": {
@@ -1544,7 +1601,8 @@
"promoGroupsShort": "groups",
"noPromoGroups": "No promo groups",
"cancelButton": "Cancel",
"saveButton": "Save"
"saveButton": "Save",
"notFound": "Payment method not found"
},
"remnawave": {
"title": "RemnaWave",
@@ -1611,7 +1669,8 @@
"offline": "Offline",
"disabled": "Disabled",
"users": "Users"
}
},
"usersOnlineCount": "{{count}} online"
},
"squads": {
"synced": "Synced",
@@ -1642,7 +1701,9 @@
"localSettings": "Local Settings",
"trialEligible": "Trial Eligible",
"price": "Price",
"users": "Users"
"users": "Users",
"inboundsCount": "{{count}} inbounds",
"membersCount": "{{count}} members"
},
"sync": {
"autoSync": "Auto Sync",
@@ -1820,7 +1881,12 @@
"btnConnect": "Connect",
"btnSubscription": "Subscription",
"btnSupport": "Support",
"btnHome": "Home"
"btnHome": "Home",
"category": "Category",
"categoryNews": "News",
"categoryPromo": "Promo",
"categorySystem": "System",
"stopping": "Stopping…"
},
"pinnedMessages": {
"title": "Pinned Messages",
@@ -2310,7 +2376,10 @@
"remnaWaveSettings": "RemnaWave Settings",
"remnaWaveConfigUuid": "Config UUID",
"remnaWaveConfigUuidHint": "UUID of subscription page config from RemnaWave panel",
"availableConfigs": "Available configs"
"availableConfigs": "Available configs",
"noConfigs": "No configs",
"remnaWaveConnected": "RemnaWave connected",
"remnaWaveDisconnected": "RemnaWave disconnected"
},
"tickets": {
"title": "Ticket Management",
@@ -2361,7 +2430,13 @@
"userNotificationsEnabled": "User Notifications",
"userNotificationsEnabledDesc": "Send notifications to users about admin replies",
"adminNotificationsEnabled": "Admin Notifications",
"adminNotificationsEnabledDesc": "Send notifications to admins about new tickets and replies"
"adminNotificationsEnabledDesc": "Send notifications to admins about new tickets and replies",
"replyFailed": "Failed to send reply",
"validation": {
"checkIntervalRange": "Check interval must be between 1 and 1440 minutes",
"reminderCooldownRange": "Reminder cooldown must be between 0 and 1440 minutes",
"slaMinutesRange": "SLA must be between 1 and 10080 minutes"
}
},
"tariffs": {
"title": "Tariff Management",
@@ -2588,7 +2663,8 @@
"deactivate": "Deactivate",
"activate": "Activate",
"edit": "Edit",
"delete": "Delete"
"delete": "Delete",
"registrations": "Registrations"
},
"modal": {
"editTitle": "Edit Campaign",
@@ -2658,7 +2734,9 @@
"totalSpending": "Subscription Spending",
"periodComparison": "Period comparison",
"vsLastWeek": "vs last week",
"topRegistrations": "Top registrations"
"topRegistrations": "Top registrations",
"subscriptionsIssued": "Subscriptions issued",
"tariffsIssued": "Tariffs issued"
},
"users": {
"title": "Campaign Users",
@@ -2682,7 +2760,10 @@
"delete": "Delete"
},
"loadError": "Failed to load campaign",
"updateError": "Failed to save changes"
"updateError": "Failed to save changes",
"validation": {
"nameRequired": "Name is required"
}
},
"withdrawals": {
"title": "Withdrawals",
@@ -2853,7 +2934,10 @@
"createTitle": "Create Campaign",
"createSubtitle": "Campaign will be auto-assigned to the partner",
"autoAssignNote": "Campaign will be automatically assigned to partner {{name}}",
"createAndAssign": "Create & Assign"
"createAndAssign": "Create & Assign",
"earnings": "Earnings",
"referrals": "Referrals",
"registrations": "Registrations"
},
"dangerZone": {
"title": "Danger Zone",
@@ -2928,7 +3012,10 @@
"firstPurchaseOnly": "First purchase only",
"cancel": "Cancel",
"saving": "Saving...",
"save": "Save"
"save": "Save",
"defaultTrialTariff": "Default trial tariff",
"selectTariff": "Select tariff",
"tariff": "Tariff"
},
"stats": {
"title": "Promo code statistics",
@@ -2958,7 +3045,8 @@
"totalPromocodes": "Total promo codes",
"activeCount": "Active",
"usagesCount": "Uses",
"exhausted": "Exhausted"
"exhausted": "Exhausted",
"hoursValue": "{{count}}h"
},
"actions": {
"stats": "Statistics",
@@ -3249,7 +3337,9 @@
"expired": "expired",
"daysLeft": "d left",
"deviceLimitUpdated": "Device limit updated",
"invalidDays": "Please enter a valid number of days (greater than 0)"
"invalidDays": "Please enter a valid number of days (greater than 0)",
"backToList": "Back to subscriptions",
"createNew": "Create new"
},
"balance": {
"current": "Current balance",
@@ -3333,7 +3423,9 @@
"alreadyReferred": "already has referrer",
"noUsersFound": "No users found"
}
}
},
"notFound": "User not found",
"purchaseCount": "Purchases: {{count}}"
},
"promoOffers": {
"title": "Promo Offers",
@@ -3342,7 +3434,8 @@
"tabs": {
"templates_one": "Templates ({{count}} template)",
"templates_other": "Templates ({{count}} templates)",
"logs": "Logs"
"logs": "Logs",
"templates": "Templates"
},
"noData": {
"templates": "No templates",
@@ -3372,7 +3465,9 @@
"activeDiscountHours": "Discount validity (hours)",
"discountDurationHint": "How long the discount lasts after activation",
"templateActive": "Template active",
"saving": "Saving..."
"saving": "Saving...",
"noServers": "No servers",
"testSquads": "Test squads"
},
"send": {
"title": "Send promo offer",
@@ -3398,7 +3493,10 @@
"notificationsSent_other": "Notifications sent: {{count}}",
"notificationsFailed_one": "(failed: {{count}})",
"notificationsFailed_other": "(failed: {{count}})",
"sendError": "Failed to send offer"
"sendError": "Failed to send offer",
"notificationsSent": "Notifications sent",
"offersCreated": "Offers created",
"notificationsFailed": "(failed: {{count}})"
},
"notFound": "Template not found",
"noActiveTemplates": "No active templates",
@@ -3535,7 +3633,8 @@
"selectedPermissions_other": "{{count}} permissions selected",
"cancel": "Cancel",
"saving": "Saving...",
"save": "Save"
"save": "Save",
"selectedPermissions": "Selected permissions"
},
"presets": {
"moderator": "Moderator",
@@ -3555,7 +3654,9 @@
"updateFailed": "Failed to update role",
"nameRequired": "Role name is required",
"deleteFailed": "Failed to delete role"
}
},
"permissionsCount": "{{count}} permissions",
"usersCount": "{{count}} users"
},
"roleAssign": {
"title": "Role Assignment",
@@ -3608,7 +3709,8 @@
"roleRequired": "Please select a role",
"assignFailed": "Failed to assign role",
"revokeFailed": "Failed to revoke role"
}
},
"totalAssignments": "Total assignments: {{count}}"
},
"policies": {
"title": "Access Policies",
@@ -3676,7 +3778,8 @@
"day3": "Wed",
"day4": "Thu",
"day5": "Fri",
"day6": "Sat"
"day6": "Sat",
"ipCount": "IP count"
},
"confirm": {
"title": "Delete policy?",
@@ -3762,7 +3865,10 @@
"hoursAgo_one": "{{count}} hr ago",
"hoursAgo_other": "{{count}} hrs ago",
"daysAgo_one": "{{count}} day ago",
"daysAgo_other": "{{count}} days ago"
"daysAgo_other": "{{count}} days ago",
"daysAgo": "{{count}}d ago",
"hoursAgo": "{{count}}h ago",
"minutesAgo": "{{count}}m ago"
},
"pagination": {
"pageSize": "Per page:",
@@ -3775,7 +3881,8 @@
"errors": {
"loadFailed": "Failed to load audit log",
"retry": "Try again"
}
},
"totalEntries": "Total entries: {{count}}"
},
"landings": {
"title": "Landing Pages",
@@ -3869,7 +3976,8 @@
"funnel": "Funnel",
"loadError": "Failed to load statistics",
"noPurchases": "No purchases",
"paid": "paid"
"paid": "paid",
"dailyPurchases": "Purchases per day"
},
"purchases": {
"title": "Purchases",
@@ -3895,7 +4003,16 @@
"page": "Page {{current}} of {{total}}",
"prev": "Previous",
"next": "Next"
}
},
"methodCurrency": "Currency",
"methodDescPlaceholder": "Short description shown to the user",
"methodDescription": "Method description",
"methodDisplayName": "Display name",
"methodIconUrl": "Icon URL",
"methodMaxAmount": "Maximum amount",
"methodMinAmount": "Minimum amount",
"methodReturnUrl": "Return URL",
"stickyPayButton": "Sticky pay button"
},
"infoPages": {
"title": "Information Pages",
@@ -4007,7 +4124,8 @@
"disable": "Disable",
"hide": "Hide ({{count}})",
"showMore_one": "Show {{count}} more node",
"showMore_other": "Show {{count}} more nodes"
"showMore_other": "Show {{count}} more nodes",
"showMore": "Show more"
},
"topReferrers": {
"title": "Top referrers",
@@ -4457,7 +4575,8 @@
"yandex": "Yandex",
"discord": "Discord",
"vk": "VK"
}
},
"backToAccounts": "Back to accounts"
}
},
"theme": {
@@ -4611,7 +4730,8 @@
"warning": "A cancelled promo code cannot be reused. The discount will stop working immediately.",
"confirm": "Cancel discount",
"deactivating": "Cancelling...",
"error": "Failed to cancel promo code. Please try again later."
"error": "Failed to cancel promo code. Please try again later.",
"success": "Offer deactivated"
}
},
"telegramRedirect": {
@@ -4788,7 +4908,9 @@
"nDays_one": "{{count}} day",
"nDays_other": "{{count}} days",
"nMonths_one": "{{count}} month",
"nMonths_other": "{{count}} months"
"nMonths_other": "{{count}} months",
"nDays": "{{count}} days",
"nMonths": "{{count}} months"
}
},
"gift": {
@@ -4966,5 +5088,12 @@
"linkUrlPrompt": "URL:"
}
}
},
"subscriptions": {
"buy": "Buy subscription",
"buyAnother": "Buy another subscription",
"empty": "You have no subscriptions yet",
"emptyDesc": "Choose a tariff to get started",
"title": "My subscriptions"
}
}