Files
pangolin/client/lib/l10n/strings_zh.dart
T
wangjia 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
fix(routing): 堵住 ip_cidr direct 旁路系统层 + 客户端保存失败可见提示
分支审核发现两处 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
2026-08-01 00:32:52 +08:00

608 lines
19 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// strings_zh.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 StringsZh extends AppText {
const StringsZh();
@override
AppLang get lang => AppLang.zh;
@override
String get brand => '穿山甲';
@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 => '前往移动端 App 看广告加时,或升级会员畅享无限时长。';
@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 => '本周流量 (GB)';
@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 => '最近两周流量';
@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 => 'PRO 套餐最多 3 台设备同时在线';
@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 => '专业版';
@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 => 'App 内不支持直接支付。请通过以下渠道获取激活码:';
@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 => '你的邮箱地址';
@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 => '支付宝';
@override
String get payMethodCrypto => 'USDT (TRC20)';
@override
String get choosePayMethod => '选择支付方式';
@override
String get proMonthly => '专业版·月付';
@override
String get proQuarterly => '专业版·季付';
@override
String get proYearly => '专业版·年付';
@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 => '打开支付宝支付';
@override
String get openAlipayHint => '完成支付后返回,本页会自动刷新';
@override
String get openAlipayFailed => '无法打开支付宝,请检查是否已安装或稍后重试';
@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 => '请复制内容后在支付宝内打开';
@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 => '人民币 · 支付宝';
@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 => '哪吒支付';
@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 ['专业版全部功能', '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';
}