Files
pangolin/client/lib/l10n/strings_en.dart
T
wangjia 58526b09e6
ci-pangolin / Lint — shellcheck (push) Successful in 7s
ci-pangolin / OpenAPI Sync Check (push) Successful in 19s
ci-pangolin / Redline Scan — 脱敏 (UI 文案) (push) Successful in 7s
ci-pangolin / Flutter — analyze + test (push) Successful in 23s
ci-pangolin / Portable SQL — 可移植性 (mysql/sqlite) (push) Successful in 5s
ci-pangolin / Codegen Drift — token 生成物未漂移 (push) Successful in 5s
ci-pangolin / Go — build + test (push) Successful in 9s
ci-pangolin / E2E Smoke — L4 进程级端到端 (push) Successful in 14s
ci-pangolin / Go — integration (mysql/redis testcontainers) (push) Failing after 4m12s
ci-pangolin / Golden — 视觉回归 (components + auth) (push) Successful in 15s
feat(client): P6 DevicesScreen 重做 + DevicePlatform 枚举
回应「状态码用枚举更好」:新增 DevicePlatform 枚举(线格式 fromWire 解析,
UI 只碰枚举,穷尽 switch),Device.platformKind getter;platform 图标按枚举 switch。
DevicesScreen 按 §7 视觉稿重做:行内 名称+「本机」标 / 平台·客户端版本·最后登录 /
在线绿点光晕·离线灰点 + 行尾 ⋯ 菜单(强制退出 / 清除登录信息·危险红)+ 危险二次
确认弹窗;本机行不显示 ⋯(不自我踢)。l10n 新增在线/离线/最后登录/从未登录/强制
退出/清除登录信息/取消 + 确认文案(中英);「当前设备」改「本机」。
新图标 moreVertical/trash/alertTriangle。localDeviceIdProvider 供本机判定。
测试:devices_screen widget 3 例(本机标+在线/离线+版本渲染 / ⋯菜单→强制退出→
确认→POST logout / 清除→DELETE);全量 flutter test 58 绿。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 06:10:37 +08:00

302 lines
8.3 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_en.dart — English copy resources (single-language display)
//
// Red-line words forbidden: VPN / 翻墙 / 科学上网 / 突破封锁 / 自由穿越 / Go anywhere.
// Positioning: network acceleration / experience optimization + privacy.
// Plan numbers follow design/CLAUDE.md §7.
import 'app_text.dart';
class StringsEn extends AppText {
const StringsEn();
@override
AppLang get lang => AppLang.en;
@override
String get brand => 'Pangolin';
@override
String get online => '● Online';
@override
String get offline => '○ Offline';
@override
String get capOff => 'Tap to connect';
@override
String get capConnecting => 'Connecting…';
@override
String get capOn => 'Connected · Encrypted';
@override
String get connectNow => 'CONNECT';
@override
String get secure => 'SECURE';
@override
String get tabConnect => 'Connect';
@override
String get tabServers => 'Servers';
@override
String get tabStats => 'Stats';
@override
String get tabMe => 'Account';
@override
String get currentNode => 'Current node';
@override
String get download => 'Down';
@override
String get upload => 'Up';
@override
String get latency => 'Ping';
@override
String get quotaToday => 'Left today';
@override
String get minutes => 'min';
@override
String get quotaFree => 'Free · 10 min/day';
@override
String get watchAd => 'Watch ad to start';
@override
String get adUnlocked => 'Unlocked for today';
@override
String get chooseNode => 'Choose server';
@override
String get searchPh => 'Search country / city';
@override
String get smartSelect => 'Smart select';
@override
String get smartSub => 'Picks the best node for your network';
@override
String get recommended => 'Recommended';
@override
String get statsTitle => 'Statistics';
@override
String get trafficMonth => 'Traffic';
@override
String get avgPing => 'Avg ping';
@override
String get durMonth => 'Time';
@override
String get weekTraffic => 'This week (GB)';
@override
List<String> get days7 => const ['M', 'T', 'W', 'T', 'F', 'S', 'S'];
@override
String get byDevice => 'By device';
@override
String get noDeviceUsage => 'No device usage yet';
@override
String get periodMonth => 'This month';
@override
String get periodWeek => 'This week';
@override
String get periodToday => 'Today';
@override
String get statDown => 'Download';
@override
String get statUp => 'Upload';
@override
String get statDuration => 'Duration';
@override
String get chartTwoWeeks => 'Last 2 weeks';
@override
String get allDevices => 'All devices';
@override
String get meTitle => 'Account';
@override
String get proMember => 'PRO member';
@override
String get freePlanName => 'Free';
@override
String get expires => 'Expires';
@override
String get upgradeBtn => 'Renew / Upgrade';
@override
String get accInfoTitle => 'Account info';
@override
String get accEmail => 'Email';
@override
String get accPassword => 'Password';
@override
String get accChange => 'Change';
@override
String get myDevices => 'My devices';
@override
String get devicesSub => 'Up to 5 devices on PRO';
@override
String get thisDevice => 'This device';
@override
String get remove => 'Remove';
@override
String get devOnline => 'Online';
@override
String get devOffline => 'Offline';
@override
String get devLastLogin => 'Last login';
@override
String get devNeverLogin => 'Never logged in';
@override
String get devForceLogout => 'Force logout';
@override
String get devClearLogin => 'Clear login info';
@override
String get devForceLogoutConfirm => 'This revokes the device\'s login session — it will be kicked offline and must sign in again. The device stays in the list.';
@override
String get devClearLoginConfirm => 'This removes the device from the list entirely and revokes its login session and data-plane credential. The device must sign in again to be used.';
@override
String get devCancel => 'Cancel';
@override
String get redeemEntry => 'Redeem & buy';
@override
String get contactEntry => 'Contact us';
@override
String get signOut => 'Sign out';
@override
String get language => 'Language';
@override
String get darkAppearance => 'Dark appearance';
@override
String get stateOn => 'On';
@override
String get followLight => 'Off';
@override
String get protocol => 'Protocol';
@override
String get settingsTitle => 'Settings';
@override
String get autostart => 'Launch at startup';
@override
String get autostartSub => 'Run automatically on system start';
@override
String get smartRoute => 'Smart routing';
@override
String get smartRouteSub => 'Accelerate abroad, direct at home';
@override
String get killSwitch => 'Kill Switch';
@override
String get killSwitchSub => 'Block traffic if the link drops';
@override
String get checkUpdate => 'Check for updates';
@override
String get choosePlan => 'Choose plan';
@override
String get freePlan => 'Free';
@override
String get proPlan => 'Pro';
@override
String get teamPlan => 'Team';
@override
String get perMonth => '/mo';
@override
String get current => 'Current';
@override
String get upgrade => 'Upgrade';
@override
String get choose => 'Choose';
@override
String get mostPopular => 'Popular';
@override
List<String> get featsFree => const [
'1 basic node only',
'10 min per day',
'Watch an ad to start',
'7-day free trial on sign-up',
];
@override
List<String> get featsPro =>
const ['80+ locations', 'Unlimited · fast', '5 devices', 'Streaming optimized'];
@override
List<String> get featsTeam =>
const ['Everything in Pro', '10 seats', 'Central billing', 'Priority support'];
@override
String get redeemTitle => 'Redeem & buy';
@override
String get redeemCodeTitle => 'Redeem a code';
@override
String get redeemPh => 'Enter activation code';
@override
String get redeemBtn => 'Redeem';
@override
String get redeemOk => 'Activated · PRO unlocked';
@override
String get buyTitle => 'Where to buy';
@override
String get buySub => 'In-app payment is unavailable. Get a code via:';
@override
String get chStore => 'Self-serve store';
@override
String get chEmail => 'Email support';
@override
String get contactTitle => 'Contact us';
@override
String get contactIntro =>
'Need help? Reach us via any channel below — usually replies in minutes.';
@override
String get contactEmail => 'Email support';
@override
String get contactStore => 'Self-serve store';
@override
String get contactHoursTitle => 'Support hours';
@override
String get contactHours => 'Daily 9:00 24:00 (GMT+8)';
@override
String get authTagline => 'Fast · Stable · Effortless';
@override
String get tabLogin => 'Log in';
@override
String get tabRegister => 'Sign up';
@override
String get emailLabel => 'Email';
@override
String get emailPh => 'your@email.com';
@override
String get pwLabel => 'Password';
@override
String get pwPh => 'Enter password';
@override
String get setPwPh => 'Set a password (for multi-device login)';
@override
String get codeLabel => 'Verification code';
@override
String codeSentTo(String email) => 'Code sent to $email';
@override
String get sendCode => 'Send code';
@override
String get resend => 'Resend';
@override
String get doLogin => 'Log in';
@override
String get doNext => 'Next';
@override
String get doCreate => 'Create account';
@override
String get forgotPw => 'Forgot password?';
@override
String get tos => 'By continuing you agree to our Terms & Privacy Policy';
@override
String get obSkip => 'Skip';
@override
String get obNext => 'Next';
@override
String get obAllow => 'Allow & continue';
@override
String get obStart => 'Get started';
@override
String get ob1Title => 'Connect worldwide';
@override
String get ob1Sub => '80+ locations, auto-fastest routing, rock-solid.';
@override
String get ob2Title => 'Allow network setup';
@override
String get ob2Sub => 'The system will ask to add a network profile to build the encrypted tunnel.';
@override
String get ob3Title => 'Private by design';
@override
String get ob3Sub => 'End-to-end encrypted. We keep zero browsing logs.';
}