6f232d4043
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (push) Successful in 25s
ci-pangolin / Cleartext Scan — Android 禁明文 (push) Successful in 19s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (push) Successful in 18s
ci-pangolin / Golden — 视觉回归 (全量:components/auth/desktop/tablet) (push) Failing after 13m6s
ci-pangolin / Go — integration (mysql/redis testcontainers) (push) Failing after 13m16s
ci-pangolin / E2E Smoke — L4 进程级端到端 (push) Failing after 13m25s
ci-pangolin / Go — build + test (push) Failing after 13m35s
ci-pangolin / DS-flow — 原型/跨端同源/代码色单源闸 (push) Failing after 13m45s
ci-pangolin / Codegen Drift — token 生成物未漂移 (push) Failing after 13m54s
ci-pangolin / Flutter — analyze + test (push) Failing after 14m5s
ci-pangolin / OpenAPI Sync Check (push) Failing after 14m16s
ci-pangolin / Lint — shellcheck (push) Failing after 14m27s
分支审核发现两处 Important,合并前修复。
① [安全] direct 的 ip_cidr 用户规则可自伤式旁路整条隧道:
Validate 原先只校 CIDR 语法。用户提交 ip_cidr=0.0.0.0/0 action=direct
(或 172.16.0.0/12,含隧道 DNS 172.19.0.2)会并入 TUN 入站
route_exclude_address(OS/auto_route 层,位于系统强制层之下),被排除的
流量根本不进 sing-box → hijack-dns 与整条隧道被静默旁路,违反「系统层
用户不可越」铁律。
- Validate: direct 的 ip_cidr 拒绝 catch-all(/0)及与保留段 172.16.0.0/12
重叠(写入闸)。
- clientconfig 渲染层:新增 routing.SafeToExclude 守卫,只有安全的 direct
ip_cidr 才并入 route_exclude_address(纵深防护,兜底写入闸之前的历史坏行)。
- 测试 TestValidateDirectIPCIDRReservedGuard 钉死:拒 catch-all/隧道段重叠、
放行 proxy catch-all 与不重叠 direct。
② [健壮性] 客户端保存失败静默回滚 + 抛未捕获异步异常 + 对话框无字段校验:
_persist 失败会 rethrow(约定调用方 catch),但屏幕层所有回调
(setMode/setBuiltin/addRule/removeRule/reorder/resetToDefault)均未 catch,
规则闪现即消失、无提示,且 rethrow 变 zone 未处理异常。
- 新增 _guardSave 守卫:await + 失败弹 SnackBar(AuthApiException 显服务端
双语文案含校验错,其余回退通用「保存失败」),包裹全部变更类回调。
- 添加规则对话框:_valueError 字段级预校验(ip_cidr 用 InternetAddress
校验、geo 白名单仅 cn),非法即禁用保存并内联红字提示;语义级(保留段)
仍由服务端权威判定经 SnackBar 呈现。
- l10n 单源新增 routingSaveFailed / routingRuleValueInvalid(6 语),regen。
go test ./... 全绿;flutter analyze 无 error;flutter test 265 全过无 golden 回归;
codegen 幂等、原型 i18n 无漂移。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
608 lines
26 KiB
Dart
608 lines
26 KiB
Dart
// strings_ru.dart — Русский文案(自动生成 · 勿手改)
|
||
//
|
||
// GENERATED by design/codegen/gen_l10n_dart.mjs from design/i18n/strings.json.
|
||
// 改文案:改 strings.json 后重跑 codegen;新增 key 需同步 app_text.dart 抽象声明。
|
||
import 'app_text.dart';
|
||
|
||
class StringsRu extends AppText {
|
||
const StringsRu();
|
||
|
||
@override
|
||
AppLang get lang => AppLang.ru;
|
||
|
||
@override
|
||
String get brand => 'Pangolin';
|
||
@override
|
||
String get online => '● В сети';
|
||
@override
|
||
String get offline => '○ Не в сети';
|
||
@override
|
||
String get capOff => 'Нажмите для подключения';
|
||
@override
|
||
String get capConnecting => 'Подключение…';
|
||
@override
|
||
String get capOn => 'Подключено · Шифрование';
|
||
@override
|
||
String get connectNow => 'ПОДКЛЮЧИТЬ';
|
||
@override
|
||
String get secure => 'ЗАЩИЩЕНО';
|
||
@override
|
||
String get tabConnect => 'Подключение';
|
||
@override
|
||
String get tabServers => 'Серверы';
|
||
@override
|
||
String get tabStats => 'Статистика';
|
||
@override
|
||
String get tabMe => 'Аккаунт';
|
||
@override
|
||
String get currentNode => 'Текущий узел';
|
||
@override
|
||
String get download => 'Приём';
|
||
@override
|
||
String get upload => 'Отдача';
|
||
@override
|
||
String get latency => 'Пинг';
|
||
@override
|
||
String get quotaToday => 'Осталось сегодня';
|
||
@override
|
||
String get minutes => 'мин';
|
||
@override
|
||
String get quotaFree => 'Бесплатно · 10 мин/день';
|
||
@override
|
||
String get planFreeTag => 'Бесплатно';
|
||
@override
|
||
String get watchAd => 'Смотрите рекламу, чтобы начать';
|
||
@override
|
||
String get adUnlocked => 'Открыто на сегодня';
|
||
@override
|
||
String get quotaLeftLabel => 'Осталось';
|
||
@override
|
||
String get quotaUsedUp => 'Дневной бесплатный лимит исчерпан';
|
||
@override
|
||
String get watchAdMore => 'Смотрите рекламу, чтобы добавить время';
|
||
@override
|
||
String get quotaExhaustedNotice => 'Дневной бесплатный лимит исчерпан. Оформите подписку, чтобы продолжить подключение.';
|
||
@override
|
||
String get adPlaying => 'Реклама воспроизводится…';
|
||
@override
|
||
String get adFailed => 'Не удалось добавить время, попробуйте ещё раз';
|
||
@override
|
||
String get quotaDesktopTitle => 'Дневной бесплатный лимит исчерпан';
|
||
@override
|
||
String get quotaDesktopBody => 'Смотрите рекламу в мобильном приложении, чтобы добавить время, или оформите подписку для безлимитного доступа.';
|
||
@override
|
||
String get gotIt => 'Понятно';
|
||
@override
|
||
String get chooseNode => 'Выбор сервера';
|
||
@override
|
||
String get searchPh => 'Поиск страны / города';
|
||
@override
|
||
String get smartSelect => 'Умный выбор';
|
||
@override
|
||
String get nodeSwitchBody => 'Текущее соединение будет разорвано и восстановлено через этот узел.';
|
||
@override
|
||
String get nodeSwitchConfirm => 'Переключить';
|
||
@override
|
||
String get nodeUnhealthySwitched => 'Текущий узел недоступен — переключение выполнено автоматически';
|
||
@override
|
||
String get nodeUnhealthyError => 'Текущий узел недоступен — переподключитесь или смените узел';
|
||
@override
|
||
String get nodeReconnecting => 'Сеть нестабильна, переподключение…';
|
||
@override
|
||
String get routingRulesReconnecting => 'Правила обновлены, переподключение…';
|
||
@override
|
||
String get smartSub => 'Подбирает лучший узел для вашей сети';
|
||
@override
|
||
String get recommended => 'Рекомендуется';
|
||
@override
|
||
String get statsTitle => 'Статистика';
|
||
@override
|
||
String get trafficMonth => 'Трафик';
|
||
@override
|
||
String get avgPing => 'Средний пинг';
|
||
@override
|
||
String get durMonth => 'Время';
|
||
@override
|
||
String get weekTraffic => 'На этой неделе (ГБ)';
|
||
@override
|
||
String get byDevice => 'По устройствам';
|
||
@override
|
||
String get noDeviceUsage => 'Пока нет данных по устройствам';
|
||
@override
|
||
String get periodMonth => 'Этот месяц';
|
||
@override
|
||
String get periodWeek => 'Эта неделя';
|
||
@override
|
||
String get periodToday => 'Сегодня';
|
||
@override
|
||
String get statDown => 'Приём';
|
||
@override
|
||
String get statUp => 'Отдача';
|
||
@override
|
||
String get statDuration => 'Длительность';
|
||
@override
|
||
String get chartTwoWeeks => 'Последние 2 недели';
|
||
@override
|
||
String get allDevices => 'Все устройства';
|
||
@override
|
||
String get meTitle => 'Аккаунт';
|
||
@override
|
||
String get proMember => 'PRO-подписка';
|
||
@override
|
||
String get freePlanName => 'Бесплатный';
|
||
@override
|
||
String get expires => 'Действует до';
|
||
@override
|
||
String get upgradeBtn => 'Продлить / Улучшить';
|
||
@override
|
||
String get accInfoTitle => 'Данные аккаунта';
|
||
@override
|
||
String get accEmail => 'Эл. почта';
|
||
@override
|
||
String get accPassword => 'Пароль';
|
||
@override
|
||
String get accChange => 'Изменить';
|
||
@override
|
||
String get deviceLimitTitle => 'Достигнут лимит устройств';
|
||
@override
|
||
String get deviceLimitDesc => 'Ваш тариф допускает до %s устройств. Удалите одно, чтобы продолжить.';
|
||
@override
|
||
String get deviceLimitRemoveOldest => 'Удалить давно неиспользуемое';
|
||
@override
|
||
String get myDevices => 'Мои устройства';
|
||
@override
|
||
String get devicesSub => 'До 3 устройств на PRO';
|
||
@override
|
||
String get thisDevice => 'Это устройство';
|
||
@override
|
||
String get remove => 'Удалить';
|
||
@override
|
||
String get devOnline => 'В сети';
|
||
@override
|
||
String get devOffline => 'Не в сети';
|
||
@override
|
||
String get devLastOnline => 'Был(а) в сети';
|
||
@override
|
||
String get devNeverLogin => 'Ни разу не входил(а)';
|
||
@override
|
||
String get devForceLogout => 'Принудительный выход';
|
||
@override
|
||
String get devClearLogin => 'Очистить данные входа';
|
||
@override
|
||
String get devRename => 'Переименовать';
|
||
@override
|
||
String get devRenameHint => 'Имя устройства';
|
||
@override
|
||
String get devSave => 'Сохранить';
|
||
@override
|
||
String get devForceLogoutConfirm => 'Это завершит сеанс входа устройства — оно будет отключено и потребует повторного входа. Устройство останется в списке.';
|
||
@override
|
||
String get devClearLoginConfirm => 'Это полностью удалит устройство из списка и отзовёт его сеанс входа и учётные данные передачи данных. Чтобы снова использовать устройство, нужно войти заново.';
|
||
@override
|
||
String get devCancel => 'Отмена';
|
||
@override
|
||
String get sessionRevokedTitle => 'Это устройство было отключено';
|
||
@override
|
||
String get sessionRevokedBody => 'Вход с этого устройства завершён с другого устройства вашего аккаунта. Пожалуйста, войдите снова.';
|
||
@override
|
||
String get sessionRevokedOk => 'Войти снова';
|
||
@override
|
||
String get redeemEntry => 'Активация';
|
||
@override
|
||
String get contactEntry => 'Связаться с нами';
|
||
@override
|
||
String get signOut => 'Выйти';
|
||
@override
|
||
String get language => 'Язык';
|
||
@override
|
||
String get darkAppearance => 'Тёмная тема';
|
||
@override
|
||
String get stateOn => 'Вкл.';
|
||
@override
|
||
String get followLight => 'Выкл.';
|
||
@override
|
||
String get protocol => 'Протокол';
|
||
@override
|
||
String get settingsTitle => 'Настройки';
|
||
@override
|
||
String get autostart => 'Запуск при старте системы';
|
||
@override
|
||
String get autostartSub => 'Запускать автоматически при включении системы';
|
||
@override
|
||
String get autoConnect => 'Автоподключение';
|
||
@override
|
||
String get autoConnectSub => 'Подключаться автоматически при запуске';
|
||
@override
|
||
String get smartRoute => 'Умная маршрутизация';
|
||
@override
|
||
String get smartRouteSub => 'Ускорение для зарубежных ресурсов, прямой доступ для локальных';
|
||
@override
|
||
String get killSwitch => 'Kill Switch';
|
||
@override
|
||
String get killSwitchSub => 'Блокировать трафик при разрыве соединения';
|
||
@override
|
||
String get checkUpdate => 'Проверить обновления';
|
||
@override
|
||
String get webUserCenter => 'Личный кабинет (веб)';
|
||
@override
|
||
String get updateNotesFallback => 'Это обновление включает исправления и улучшения стабильности.';
|
||
@override
|
||
String get updateLater => 'Позже';
|
||
@override
|
||
String get updateDownload => 'Скачать обновление';
|
||
@override
|
||
String get updateUpToDate => 'У вас установлена последняя версия';
|
||
@override
|
||
String get updateCheckFailed => 'Не удалось проверить обновления, попробуйте позже';
|
||
@override
|
||
String get freePlan => 'Бесплатный';
|
||
@override
|
||
String get proPlan => 'Pro';
|
||
@override
|
||
String get teamPlan => 'Команда';
|
||
@override
|
||
String get perMonth => '/мес';
|
||
@override
|
||
String get current => 'Текущий';
|
||
@override
|
||
String get upgrade => 'Улучшить';
|
||
@override
|
||
String get choose => 'Выбрать';
|
||
@override
|
||
String get mostPopular => 'Популярный';
|
||
@override
|
||
String get redeemTitle => 'Активация и покупка';
|
||
@override
|
||
String get redeemCodeTitle => 'Активировать код';
|
||
@override
|
||
String get redeemPh => 'Введите код активации';
|
||
@override
|
||
String get redeemBtn => 'Активировать';
|
||
@override
|
||
String get redeemOk => 'Активировано · PRO открыт';
|
||
@override
|
||
String get buyTitle => 'Где купить';
|
||
@override
|
||
String get buySub => 'Оплата внутри приложения недоступна. Получить код можно через:';
|
||
@override
|
||
String get chStore => 'Магазин самообслуживания';
|
||
@override
|
||
String get chEmail => 'Поддержка по эл. почте';
|
||
@override
|
||
String get contactTitle => 'Связаться с нами';
|
||
@override
|
||
String get contactIntro => 'Нужна помощь? Свяжитесь с нами любым способом ниже — обычно отвечаем за считанные минуты.';
|
||
@override
|
||
String get contactEmail => 'Поддержка по эл. почте';
|
||
@override
|
||
String get contactStore => 'Магазин самообслуживания';
|
||
@override
|
||
String get contactWebsite => 'Веб-сайт';
|
||
@override
|
||
String get contactHoursTitle => 'Часы поддержки';
|
||
@override
|
||
String get contactHours => 'Ежедневно 9:00 – 24:00 (GMT+8)';
|
||
@override
|
||
String get authTagline => 'Быстро · Стабильно · Без усилий';
|
||
@override
|
||
String get tabLogin => 'Вход';
|
||
@override
|
||
String get tabRegister => 'Регистрация';
|
||
@override
|
||
String get emailLabel => 'Эл. почта';
|
||
@override
|
||
String get emailPh => 'your@email.com';
|
||
@override
|
||
String get pwLabel => 'Пароль';
|
||
@override
|
||
String get pwPh => 'Введите пароль';
|
||
@override
|
||
String get setPwPh => 'Задайте пароль (для входа с нескольких устройств)';
|
||
@override
|
||
String get codeLabel => 'Код подтверждения';
|
||
@override
|
||
String get sendCode => 'Отправить код';
|
||
@override
|
||
String get resend => 'Отправить снова';
|
||
@override
|
||
String get doLogin => 'Войти';
|
||
@override
|
||
String get doNext => 'Далее';
|
||
@override
|
||
String get doCreate => 'Создать аккаунт';
|
||
@override
|
||
String get forgotPw => 'Забыли пароль?';
|
||
@override
|
||
String get tos => 'Продолжая, вы принимаете наши Условия и Политику конфиденциальности';
|
||
@override
|
||
String get obSkip => 'Пропустить';
|
||
@override
|
||
String get obNext => 'Далее';
|
||
@override
|
||
String get obAllow => 'Разрешить и продолжить';
|
||
@override
|
||
String get obStart => 'Начать';
|
||
@override
|
||
String get ob1Title => 'Подключение по всему миру';
|
||
@override
|
||
String get ob1Sub => '80+ локаций, автоматический выбор самого быстрого маршрута, надёжная стабильность.';
|
||
@override
|
||
String get ob2Title => 'Разрешите настройку сети';
|
||
@override
|
||
String get ob2Sub => 'Система запросит добавление сетевого профиля для создания зашифрованного туннеля.';
|
||
@override
|
||
String get ob3Title => 'Приватность по умолчанию';
|
||
@override
|
||
String get ob3Sub => 'Сквозное шифрование. Мы не храним журналы просмотров.';
|
||
@override
|
||
String get purchaseTitle => 'Купить тариф';
|
||
@override
|
||
String get paymentTitle => 'Оплата';
|
||
@override
|
||
String get buyNow => 'Купить';
|
||
@override
|
||
String get payMethodAlipay => 'Alipay';
|
||
@override
|
||
String get payMethodCrypto => 'USDT (TRC20)';
|
||
@override
|
||
String get choosePayMethod => 'Выберите способ оплаты';
|
||
@override
|
||
String get proMonthly => 'Pro · Помесячно';
|
||
@override
|
||
String get proQuarterly => 'Pro · Квартал';
|
||
@override
|
||
String get proYearly => 'Pro · Год';
|
||
@override
|
||
String get perQuarter => '/квартал';
|
||
@override
|
||
String get perYear => '/год';
|
||
@override
|
||
String get payAmountLabel => 'Сумма перевода';
|
||
@override
|
||
String get payAddressLabel => 'Адрес для оплаты';
|
||
@override
|
||
String get payNetworkLabel => 'Сеть';
|
||
@override
|
||
String get payExactAmountHint => 'Отправьте точную сумму — активация произойдёт автоматически';
|
||
@override
|
||
String get copied => 'Скопировано';
|
||
@override
|
||
String get openAlipay => 'Оплатить через Alipay';
|
||
@override
|
||
String get openAlipayHint => 'Вернитесь после оплаты — страница обновится автоматически';
|
||
@override
|
||
String get openAlipayFailed => 'Не удалось открыть Alipay. Проверьте, установлен ли он, или повторите';
|
||
@override
|
||
String get awaitingPayment => 'Ожидание оплаты';
|
||
@override
|
||
String get paySucceeded => 'Активировано';
|
||
@override
|
||
String get payExpiresAt => 'Действует до';
|
||
@override
|
||
String get payDone => 'Готово';
|
||
@override
|
||
String get payFailed => 'Оплата не удалась';
|
||
@override
|
||
String get payRetry => 'Повторить';
|
||
@override
|
||
String get switchPayMethod => 'Сменить способ оплаты';
|
||
@override
|
||
String get cancelOrder => 'Отменить заказ';
|
||
@override
|
||
String get qrNotSupported => 'Скопируйте и откройте в Alipay';
|
||
@override
|
||
String get orderCreateFailed => 'Не удалось создать заказ, повторите попытку позже';
|
||
@override
|
||
String get payUnsupportedRenderType => 'Не поддерживается, смените способ оплаты';
|
||
@override
|
||
String get payNoActiveOrder => 'Нет активных заказов';
|
||
@override
|
||
String get payChannel => 'Способ оплаты';
|
||
@override
|
||
String get payChannelUsdt => 'USDT · Крипто';
|
||
@override
|
||
String get payChannelCny => 'Юань · Alipay';
|
||
@override
|
||
String get perMonthSuffix => ' /мес';
|
||
@override
|
||
String get ordersTitle => 'Мои заказы';
|
||
@override
|
||
String get orderDetailTitle => 'Детали заказа';
|
||
@override
|
||
String get ordersEmpty => 'Заказов пока нет';
|
||
@override
|
||
String get orderNoLabel => 'Номер заказа';
|
||
@override
|
||
String get orderPlanLabel => 'Тариф';
|
||
@override
|
||
String get orderMethodLabel => 'Способ оплаты';
|
||
@override
|
||
String get orderAmountLabel => 'Сумма';
|
||
@override
|
||
String get orderCreatedLabel => 'Создан';
|
||
@override
|
||
String get orderPaidLabel => 'Оплачен';
|
||
@override
|
||
String get orderStatusPaid => 'Активирован';
|
||
@override
|
||
String get orderStatusCanceled => 'Отменён';
|
||
@override
|
||
String get orderContinuePay => 'Продолжить оплату';
|
||
@override
|
||
String get orderRefresh => 'Обновить';
|
||
@override
|
||
String get orderRebuy => 'Купить снова';
|
||
@override
|
||
String get payMethodNezha => 'Nazhapay';
|
||
@override
|
||
String get inviteEntry => 'Приглашайте друзей и получайте членство';
|
||
@override
|
||
String get inviteEntrySub => 'Друг регистрируется · оба получают дни подписки';
|
||
@override
|
||
String get inviteTitle => 'Пригласить друзей';
|
||
@override
|
||
String get inviteCodeLabel => 'Код приглашения';
|
||
@override
|
||
String get inviteLinkLabel => 'Ссылка приглашения';
|
||
@override
|
||
String get inviteCopyCode => 'Скопировать код';
|
||
@override
|
||
String get inviteCopyLink => 'Скопировать ссылку';
|
||
@override
|
||
String get inviteRewardsTitle => 'Правила наград';
|
||
@override
|
||
String get inviteRewardRegister => 'Регистрация друга · +3 дня каждому';
|
||
@override
|
||
String get inviteRewardFirstBuy => 'Первая покупка друга · +7 дней каждому';
|
||
@override
|
||
String get inviteRewardJoinTg => 'Вступление в TG-канал · +3 дня';
|
||
@override
|
||
String get inviteProgressTitle => 'Мои награды';
|
||
@override
|
||
String get inviteTasksTitle => 'Больше способов заработать';
|
||
@override
|
||
String get inviteJoinTgTitle => 'Вступить в Telegram-канал';
|
||
@override
|
||
String get inviteJoinTgBtn => 'Вступить в канал';
|
||
@override
|
||
String get inviteVerifyBtn => 'Проверить и получить';
|
||
@override
|
||
String get inviteTaskDone => 'Получено +3 дня';
|
||
@override
|
||
String get inviteStatInvited => 'Приглашено';
|
||
@override
|
||
String get inviteStatConverted => 'Конвертировано';
|
||
@override
|
||
String get inviteStatDays => 'Всего получено (дней)';
|
||
@override
|
||
String get inviteCodeFieldLabel => 'Код приглашения (необязательно)';
|
||
@override
|
||
String get notifTitle => 'Уведомления';
|
||
@override
|
||
String get notifEmpty => 'Пока нет уведомлений';
|
||
@override
|
||
String get notifTypeNews => 'Новости';
|
||
@override
|
||
String get notifTypeFeature => 'Функции';
|
||
@override
|
||
String get notifTypeImportant => 'Важное';
|
||
@override
|
||
String get notifTypeReward => 'Начислено';
|
||
@override
|
||
String get notifTypeVersion => 'Обновление';
|
||
@override
|
||
String get notifTypePromo => 'Акция';
|
||
@override
|
||
String get settingsGroupConn => 'Подключение';
|
||
@override
|
||
String get settingsGroupAppearance => 'Внешний вид';
|
||
@override
|
||
String get settingsGroupAbout => 'О приложении';
|
||
@override
|
||
String get orderStatusExpired => 'Истёк';
|
||
@override
|
||
String get promoBadge => 'Спецпредложение';
|
||
@override
|
||
String get promoOriginalPrice => 'Было';
|
||
@override
|
||
String get routingRulesTitle => 'Правила маршрутизации';
|
||
@override
|
||
String get routingRulesSub => 'Настройка: напрямую / туннель / отклонить';
|
||
@override
|
||
String get routingLanDirect => 'Локальная и частная сеть напрямую';
|
||
@override
|
||
String get routingLanForced => 'Всегда включено';
|
||
@override
|
||
String get routingForcedPill => '🔒 Принудительно';
|
||
@override
|
||
String get routingProxyMode => 'Режим прокси';
|
||
@override
|
||
String get routingModeGlobal => 'Глобально';
|
||
@override
|
||
String get routingModeSmart => 'Умный';
|
||
@override
|
||
String get routingModeDirect => 'Напрямую';
|
||
@override
|
||
String get routingBuiltin => 'Встроенные правила';
|
||
@override
|
||
String get routingCnDirect => 'Прямой доступ внутри страны';
|
||
@override
|
||
String get routingMyRulesOrdered => 'Мои правила · по порядку, срабатывает первое совпадение';
|
||
@override
|
||
String get routingMyRulesFirst => 'Мои правила · срабатывает первое совпадение';
|
||
@override
|
||
String get routingFinalLong => 'Итог (ни одно правило не совпало)';
|
||
@override
|
||
String get routingFinalShort => 'Итог (нет совпадений)';
|
||
@override
|
||
String get routingFinalFallback => 'FINAL — резерв';
|
||
@override
|
||
String get routingTypeDomainSuffix => 'Суффикс домена';
|
||
@override
|
||
String get routingTypeDomainSuffixCi => 'Суффикс домена · CI-источник';
|
||
@override
|
||
String get routingTypeDomainSuffixMirror => 'Суффикс домена · зеркало';
|
||
@override
|
||
String get routingTypeGeosite => 'Набор правил GeoSite';
|
||
@override
|
||
String get routingTypeDomain => 'Домен';
|
||
@override
|
||
String get routingTypeDomainKeyword => 'Ключевое слово домена';
|
||
@override
|
||
String get routingTypeIpCidr => 'Диапазон IP (CIDR)';
|
||
@override
|
||
String get routingTypeGeoip => 'Набор правил GeoIP';
|
||
@override
|
||
String get routingActDirect => 'Напрямую';
|
||
@override
|
||
String get routingActProxy => 'Туннель';
|
||
@override
|
||
String get routingActReject => 'Отклонить';
|
||
@override
|
||
String get routingForcedRow => '⚠ Домен принудительно направлен через туннель системой; правило неактивно';
|
||
@override
|
||
String get routingRuleShadowed => 'Перекрыто правилом выше';
|
||
@override
|
||
String get routingModeNote => '«Мои правила» действуют только в режиме умной маршрутизации. Глобальный прокси / прямое соединение игнорируют пользовательские правила (принудительные системные правила по-прежнему применяются).';
|
||
@override
|
||
String get routingRuleValueHint => 'например, example.com или 192.168.1.0/24';
|
||
@override
|
||
String get routingNoRules => 'Пользовательских правил пока нет';
|
||
@override
|
||
String get routingAddRule => 'Добавить правило';
|
||
@override
|
||
String get routingSaveFailed => 'Не удалось сохранить, попробуйте ещё раз';
|
||
@override
|
||
String get routingRuleValueInvalid => 'Неверный формат';
|
||
@override
|
||
String get routingImport => 'Импорт из текста';
|
||
@override
|
||
String get routingReset => 'Сбросить настройки';
|
||
@override
|
||
String get routingResetConfirmTitle => 'Сбросить к правилам по умолчанию?';
|
||
@override
|
||
String get routingResetConfirmBody => 'Это удалит все ваши пользовательские правила и восстановит заводскую таблицу маршрутизации.';
|
||
@override
|
||
String get routingResetConfirmAction => 'Сбросить';
|
||
@override
|
||
String get routingBack => 'Назад к настройкам';
|
||
@override
|
||
List<String> get days7 => const ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'];
|
||
@override
|
||
List<String> get featsFree => const ['Только 1 базовый узел', '10 минут в день', 'Смотрите рекламу, чтобы начать', '7 дней бесплатно при регистрации'];
|
||
@override
|
||
List<String> get featsPro => const ['80+ локаций', 'Безлимитно · быстро', '5 устройств', 'Оптимизация для стриминга'];
|
||
@override
|
||
List<String> get featsTeam => const ['Всё из Pro', '10 мест', 'Единый счёт', 'Приоритетная поддержка'];
|
||
@override
|
||
String adRewarded(int minutes) => '+$minutes мин добавлено';
|
||
@override
|
||
String nodeSwitchTitle(String name) => 'Переключиться на $name?';
|
||
@override
|
||
String autoConnectingTo(String name) => 'Автоподключение к $name…';
|
||
@override
|
||
String updateAvailableTitle(String version) => 'Доступна новая версия v$version';
|
||
@override
|
||
String codeSentTo(String email) => 'Код отправлен на $email';
|
||
}
|