feat(client/i18n): 新增 日/韩/俄/西 4 语,默认语种改英文

- AppLang enum 扩为 zh/en/ja/ko/ru/es;新增 strings_{ja,ko,ru,es}.dart
  (各 161 条,照 strings_en.dart 结构逐条翻译,无红线词,scan-redline 过)
- app_providers: localeProvider 默认 AppLang.en(国际化默认);appTextProvider
  三元改 switch 全覆盖 6 语
- AppLang.nativeLabel 扩展(各语言本地名);settings/account 两处 _LangSwitch
  段控改下拉(6 语横排会挤)
- flutter analyze lib 仅剩 2 个既有 withOpacity deprecation info

注:节点/套餐名、错误消息等 ~11 处数据驱动的 zh/en 三元暂回退 en(非崩溃,
后续可扩多语字段)。localeProvider 暂无持久化(沿用原设计,后续可加)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
This commit is contained in:
wangjia
2026-07-07 13:20:16 +08:00
parent c3b64e8d0f
commit 3aeb2a8680
8 changed files with 1594 additions and 49 deletions
+373
View File
@@ -0,0 +1,373 @@
// strings_es.dart — Recursos de texto en español (visualización monolingüe)
//
// Palabras prohibidas: VPN / traspasar muros / red científica / romper el bloqueo / cruce libre / Go anywhere.
// Posicionamiento: aceleración de red / optimización de la experiencia + privacidad.
// La numeración de planes sigue design/CLAUDE.md §7.
import 'app_text.dart';
class StringsEs extends AppText {
const StringsEs();
@override
AppLang get lang => AppLang.es;
@override
String get brand => 'Pangolin';
@override
String get online => '● En línea';
@override
String get offline => '○ Desconectado';
@override
String get capOff => 'Toca para conectar';
@override
String get capConnecting => 'Conectando…';
@override
String get capOn => 'Conectado · Cifrado';
@override
String get connectNow => 'CONECTAR';
@override
String get secure => 'SEGURO';
@override
String get tabConnect => 'Conectar';
@override
String get tabServers => 'Servidores';
@override
String get tabStats => 'Estadísticas';
@override
String get tabMe => 'Cuenta';
@override
String get currentNode => 'Nodo actual';
@override
String get download => 'Bajada';
@override
String get upload => 'Subida';
@override
String get latency => 'Ping';
@override
String get quotaToday => 'Restante hoy';
@override
String get minutes => 'min';
@override
String get quotaFree => 'Gratis · 10 min/día';
@override
String get planFreeTag => 'Gratis';
@override
String get watchAd => 'Mira un anuncio para empezar';
@override
String get adUnlocked => 'Desbloqueado por hoy';
@override
String get quotaLeftLabel => 'Restante';
@override
String get quotaUsedUp => 'Tiempo gratis diario agotado';
@override
String get watchAdMore => 'Mira un anuncio para más tiempo';
@override
String get quotaExhaustedNotice => 'Tiempo gratis diario agotado. Mira un anuncio para añadir tiempo o mejora tu plan.';
@override
String get adPlaying => 'Reproduciendo anuncio…';
@override
String adRewarded(int minutes) => '+$minutes min añadidos';
@override
String get adFailed => 'No se pudo añadir tiempo, inténtalo de nuevo';
@override
String get quotaDesktopTitle => 'Tiempo gratis diario agotado';
@override
String get quotaDesktopBody => 'Mira anuncios en la app móvil para añadir tiempo, o mejora tu plan para acceso ilimitado.';
@override
String get gotIt => 'Entendido';
@override
String get chooseNode => 'Elegir servidor';
@override
String get searchPh => 'Buscar país / ciudad';
@override
String get smartSelect => 'Selección inteligente';
@override
String nodeSwitchTitle(String name) => '¿Cambiar a $name?';
@override
String get nodeSwitchBody => 'Esto desconecta el enlace actual y reconecta a este nodo.';
@override
String get nodeSwitchConfirm => 'Cambiar';
@override
String get nodeUnhealthySwitched => 'Nodo actual inaccesible: cambiado automáticamente';
@override
String get nodeUnhealthyError => 'El nodo actual está inaccesible: reconecta o cambia de nodo';
@override
String get nodeReconnecting => 'Red inestable, reconectando…';
@override
String get smartSub => 'Elige el mejor nodo para tu red';
@override
String get recommended => 'Recomendado';
@override
String get statsTitle => 'Estadísticas';
@override
String get trafficMonth => 'Tráfico';
@override
String get avgPing => 'Ping medio';
@override
String get durMonth => 'Tiempo';
@override
String get weekTraffic => 'Esta semana (GB)';
@override
List<String> get days7 => const ['L', 'M', 'X', 'J', 'V', 'S', 'D'];
@override
String get byDevice => 'Por dispositivo';
@override
String get noDeviceUsage => 'Aún no hay uso por dispositivo';
@override
String get periodMonth => 'Este mes';
@override
String get periodWeek => 'Esta semana';
@override
String get periodToday => 'Hoy';
@override
String get statDown => 'Descarga';
@override
String get statUp => 'Subida';
@override
String get statDuration => 'Duración';
@override
String get chartTwoWeeks => 'Últimas 2 semanas';
@override
String get allDevices => 'Todos los dispositivos';
@override
String get meTitle => 'Cuenta';
@override
String get proMember => 'Miembro PRO';
@override
String get freePlanName => 'Gratis';
@override
String get expires => 'Vence';
@override
String get upgradeBtn => 'Renovar / Mejorar';
@override
String get accInfoTitle => 'Información de la cuenta';
@override
String get accEmail => 'Correo';
@override
String get accPassword => 'Contraseña';
@override
String get accChange => 'Cambiar';
@override
String get deviceLimitTitle => 'Límite de dispositivos alcanzado';
@override
String get deviceLimitDesc => 'Tu plan permite hasta %s dispositivos. Elimina uno para continuar.';
@override
String get deviceLimitRemoveOldest => 'Eliminar el menos usado recientemente';
@override
String get myDevices => 'Mis dispositivos';
@override
String get devicesSub => 'Hasta 3 dispositivos en PRO';
@override
String get thisDevice => 'Este dispositivo';
@override
String get remove => 'Eliminar';
@override
String get devOnline => 'En línea';
@override
String get devOffline => 'Desconectado';
@override
String get devLastOnline => 'Última conexión';
@override
String get devNeverLogin => 'Nunca ha iniciado sesión';
@override
String get devForceLogout => 'Forzar cierre de sesión';
@override
String get devClearLogin => 'Borrar datos de sesión';
@override
String get devRename => 'Renombrar';
@override
String get devRenameHint => 'Nombre del dispositivo';
@override
String get devSave => 'Guardar';
@override
String get devForceLogoutConfirm => 'Esto revoca la sesión del dispositivo: será desconectado y deberá iniciar sesión de nuevo. El dispositivo permanece en la lista.';
@override
String get devClearLoginConfirm => 'Esto elimina el dispositivo de la lista por completo y revoca su sesión y su credencial del plano de datos. El dispositivo deberá iniciar sesión de nuevo para poder usarse.';
@override
String get devCancel => 'Cancelar';
@override
String get sessionRevokedTitle => 'Se cerró la sesión de este dispositivo';
@override
String get sessionRevokedBody => 'Tu cuenta cerró la sesión de este dispositivo desde otro dispositivo. Inicia sesión de nuevo.';
@override
String get sessionRevokedOk => 'Iniciar sesión de nuevo';
@override
String get redeemEntry => 'Canjear y comprar';
@override
String get contactEntry => 'Contáctanos';
@override
String get signOut => 'Cerrar sesión';
@override
String get language => 'Idioma';
@override
String get darkAppearance => 'Apariencia oscura';
@override
String get stateOn => 'Activado';
@override
String get followLight => 'Desactivado';
@override
String get protocol => 'Protocolo';
@override
String get settingsTitle => 'Ajustes';
@override
String get autostart => 'Iniciar al arrancar';
@override
String get autostartSub => 'Ejecutar automáticamente al iniciar el sistema';
@override
String get autoConnect => 'Conexión automática';
@override
String get autoConnectSub => 'Conectar automáticamente al abrir';
@override
String autoConnectingTo(String name) => 'Conectando automáticamente a $name';
@override
String get smartRoute => 'Enrutamiento inteligente';
@override
String get smartRouteSub => 'Acelera en el extranjero, directo en casa';
@override
String get killSwitch => 'Kill Switch';
@override
String get killSwitchSub => 'Bloquea el tráfico si se cae el enlace';
@override
String get checkUpdate => 'Buscar actualizaciones';
@override
String get webUserCenter => 'Centro de usuario (Web)';
@override
String updateAvailableTitle(String version) => 'Nueva versión v$version disponible';
@override
String get updateNotesFallback => 'Esta actualización incluye correcciones y mejoras de estabilidad.';
@override
String get updateLater => 'Más tarde';
@override
String get updateDownload => 'Descargar actualización';
@override
String get updateUpToDate => 'Ya tienes la última versión';
@override
String get updateCheckFailed => 'Falló la búsqueda de actualizaciones, inténtalo más tarde';
@override
String get choosePlan => 'Elegir plan';
@override
String get freePlan => 'Gratis';
@override
String get proPlan => 'Pro';
@override
String get teamPlan => 'Equipo';
@override
String get perMonth => '/mes';
@override
String get current => 'Actual';
@override
String get upgrade => 'Mejorar';
@override
String get choose => 'Elegir';
@override
String get mostPopular => 'Popular';
@override
List<String> get featsFree => const [
'Solo 1 nodo básico',
'10 min al día',
'Mira un anuncio para empezar',
'Prueba gratis de 7 días al registrarte',
];
@override
List<String> get featsPro =>
const ['Más de 80 ubicaciones', 'Ilimitado · rápido', '5 dispositivos', 'Optimizado para streaming'];
@override
List<String> get featsTeam =>
const ['Todo lo de Pro', '10 plazas', 'Facturación centralizada', 'Soporte prioritario'];
@override
String get redeemTitle => 'Canjear y comprar';
@override
String get redeemCodeTitle => 'Canjear un código';
@override
String get redeemPh => 'Introduce el código de activación';
@override
String get redeemBtn => 'Canjear';
@override
String get redeemOk => 'Activado · PRO desbloqueado';
@override
String get buyTitle => 'Dónde comprar';
@override
String get buySub => 'El pago dentro de la app no está disponible. Consigue un código mediante:';
@override
String get chStore => 'Tienda autoservicio';
@override
String get chEmail => 'Soporte por correo';
@override
String get contactTitle => 'Contáctanos';
@override
String get contactIntro =>
'¿Necesitas ayuda? Escríbenos por cualquiera de los canales de abajo: solemos responder en minutos.';
@override
String get contactEmail => 'Soporte por correo';
@override
String get contactStore => 'Tienda autoservicio';
@override
String get contactHoursTitle => 'Horario de soporte';
@override
String get contactHours => 'Todos los días 9:00 24:00 (GMT+8)';
@override
String get authTagline => 'Rápido · Estable · Sin complicaciones';
@override
String get tabLogin => 'Iniciar sesión';
@override
String get tabRegister => 'Registrarse';
@override
String get emailLabel => 'Correo';
@override
String get emailPh => 'tu@correo.com';
@override
String get pwLabel => 'Contraseña';
@override
String get pwPh => 'Introduce la contraseña';
@override
String get setPwPh => 'Crea una contraseña (para acceso multidispositivo)';
@override
String get codeLabel => 'Código de verificación';
@override
String codeSentTo(String email) => 'Código enviado a $email';
@override
String get sendCode => 'Enviar código';
@override
String get resend => 'Reenviar';
@override
String get doLogin => 'Iniciar sesión';
@override
String get doNext => 'Siguiente';
@override
String get doCreate => 'Crear cuenta';
@override
String get forgotPw => '¿Olvidaste la contraseña?';
@override
String get tos => 'Al continuar aceptas nuestros Términos y Política de privacidad';
@override
String get obSkip => 'Omitir';
@override
String get obNext => 'Siguiente';
@override
String get obAllow => 'Permitir y continuar';
@override
String get obStart => 'Empezar';
@override
String get ob1Title => 'Conéctate en todo el mundo';
@override
String get ob1Sub => 'Más de 80 ubicaciones, enrutamiento al más rápido automático, sólido como una roca.';
@override
String get ob2Title => 'Permite la configuración de red';
@override
String get ob2Sub => 'El sistema te pedirá añadir un perfil de red para crear el túnel cifrado.';
@override
String get ob3Title => 'Privado por diseño';
@override
String get ob3Sub => 'Cifrado de extremo a extremo. No guardamos ningún registro de navegación.';
}