feat(i18n): l10n codegen — strings.json 单源生成 6 份 strings_*.dart
② 单源 codegen 落地:
- strings.json 补全 lists 段(days7/featsFree/featsPro/featsTeam),
之前 extraction 漏了 4 个 List<String> getter;现 246 getter+4 list+5 method×6 语。
- design/codegen/gen_l10n_dart.mjs:strings.json → strings_{zh,en,ja,ko,ru,es}.dart,
getter 转义 \$、method 保留 $var 插值,dart format 定型(保证漂移闸零 diff)。
- app_text.dart 保持手写(enum/abstract 声明/AppLangMisc 逻辑),编译器强制 concrete⊆abstract 兜底。
- 往返无损:生成的 Dart 重新抽取 == strings.json 逐字节一致;flutter analyze 0 issue、flutter test 244 全绿。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
// strings_es.dart — Recursos de texto en español (visualización monolingüe)
|
||||
// strings_es.dart — Español文案(自动生成 · 勿手改)
|
||||
//
|
||||
// Palabras prohibidas: términos de evasión de censura. Lista en design/CLAUDE.md §1 regla 13.
|
||||
// Posicionamiento: aceleración de red / optimización de la experiencia + privacidad.
|
||||
// La numeración de planes sigue design/CLAUDE.md §7.
|
||||
// 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 StringsEs extends AppText {
|
||||
@@ -27,7 +26,6 @@ class StringsEs extends AppText {
|
||||
String get connectNow => 'CONECTAR';
|
||||
@override
|
||||
String get secure => 'SEGURO';
|
||||
|
||||
@override
|
||||
String get tabConnect => 'Conectar';
|
||||
@override
|
||||
@@ -36,7 +34,6 @@ class StringsEs extends AppText {
|
||||
String get tabStats => 'Estadísticas';
|
||||
@override
|
||||
String get tabMe => 'Cuenta';
|
||||
|
||||
@override
|
||||
String get currentNode => 'Nodo actual';
|
||||
@override
|
||||
@@ -45,7 +42,6 @@ class StringsEs extends AppText {
|
||||
String get upload => 'Subida';
|
||||
@override
|
||||
String get latency => 'Ping';
|
||||
|
||||
@override
|
||||
String get quotaToday => 'Restante hoy';
|
||||
@override
|
||||
@@ -65,20 +61,19 @@ class StringsEs extends AppText {
|
||||
@override
|
||||
String get watchAdMore => 'Mira un anuncio para más tiempo';
|
||||
@override
|
||||
String get quotaExhaustedNotice => 'Tiempo gratis diario agotado. Mejora tu plan para seguir conectado.';
|
||||
String get quotaExhaustedNotice =>
|
||||
'Tiempo gratis diario agotado. Mejora tu plan para seguir conectado.';
|
||||
@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.';
|
||||
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
|
||||
@@ -86,22 +81,22 @@ class StringsEs extends AppText {
|
||||
@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.';
|
||||
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';
|
||||
String get nodeUnhealthySwitched =>
|
||||
'Nodo actual inaccesible: cambiado automáticamente';
|
||||
@override
|
||||
String get nodeUnhealthyError => 'El nodo actual está inaccesible: reconecta o cambia de nodo';
|
||||
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
|
||||
@@ -113,8 +108,6 @@ class StringsEs extends AppText {
|
||||
@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';
|
||||
@@ -134,7 +127,6 @@ class StringsEs extends AppText {
|
||||
String get chartTwoWeeks => 'Últimas 2 semanas';
|
||||
@override
|
||||
String get allDevices => 'Todos los dispositivos';
|
||||
|
||||
@override
|
||||
String get meTitle => 'Cuenta';
|
||||
@override
|
||||
@@ -156,7 +148,8 @@ class StringsEs extends AppText {
|
||||
@override
|
||||
String get deviceLimitTitle => 'Límite de dispositivos alcanzado';
|
||||
@override
|
||||
String get deviceLimitDesc => 'Tu plan permite hasta %s dispositivos. Elimina uno para continuar.';
|
||||
String get deviceLimitDesc =>
|
||||
'Tu plan permite hasta %s dispositivos. Elimina uno para continuar.';
|
||||
@override
|
||||
String get deviceLimitRemoveOldest => 'Eliminar el menos usado recientemente';
|
||||
@override
|
||||
@@ -186,15 +179,18 @@ class StringsEs extends AppText {
|
||||
@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.';
|
||||
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.';
|
||||
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.';
|
||||
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
|
||||
@@ -224,8 +220,6 @@ class StringsEs extends AppText {
|
||||
@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';
|
||||
@@ -238,9 +232,8 @@ class StringsEs extends AppText {
|
||||
@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.';
|
||||
String get updateNotesFallback =>
|
||||
'Esta actualización incluye correcciones y mejoras de estabilidad.';
|
||||
@override
|
||||
String get updateLater => 'Más tarde';
|
||||
@override
|
||||
@@ -248,8 +241,8 @@ class StringsEs extends AppText {
|
||||
@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';
|
||||
|
||||
String get updateCheckFailed =>
|
||||
'Falló la búsqueda de actualizaciones, inténtalo más tarde';
|
||||
@override
|
||||
String get freePlan => 'Gratis';
|
||||
@override
|
||||
@@ -266,20 +259,6 @@ class StringsEs extends AppText {
|
||||
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
|
||||
@@ -293,12 +272,12 @@ class StringsEs extends AppText {
|
||||
@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:';
|
||||
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
|
||||
@@ -314,7 +293,6 @@ class StringsEs extends AppText {
|
||||
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
|
||||
@@ -334,8 +312,6 @@ class StringsEs extends AppText {
|
||||
@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';
|
||||
@@ -348,8 +324,8 @@ class StringsEs extends AppText {
|
||||
@override
|
||||
String get forgotPw => '¿Olvidaste la contraseña?';
|
||||
@override
|
||||
String get tos => 'Al continuar aceptas nuestros Términos y Política de privacidad';
|
||||
|
||||
String get tos =>
|
||||
'Al continuar aceptas nuestros Términos y Política de privacidad';
|
||||
@override
|
||||
String get obSkip => 'Omitir';
|
||||
@override
|
||||
@@ -361,17 +337,18 @@ class StringsEs extends AppText {
|
||||
@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.';
|
||||
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.';
|
||||
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.';
|
||||
|
||||
// ── 购买 / 支付 ──
|
||||
String get ob3Sub =>
|
||||
'Cifrado de extremo a extremo. No guardamos ningún registro de navegación.';
|
||||
@override
|
||||
String get purchaseTitle => 'Comprar plan';
|
||||
@override
|
||||
@@ -401,15 +378,18 @@ class StringsEs extends AppText {
|
||||
@override
|
||||
String get payNetworkLabel => 'Red';
|
||||
@override
|
||||
String get payExactAmountHint => 'Envía el importe exacto; se activa automáticamente';
|
||||
String get payExactAmountHint =>
|
||||
'Envía el importe exacto; se activa automáticamente';
|
||||
@override
|
||||
String get copied => 'Copiado';
|
||||
@override
|
||||
String get openAlipay => 'Pagar con Alipay';
|
||||
@override
|
||||
String get openAlipayHint => 'Vuelve tras pagar; esta página se actualiza automáticamente';
|
||||
String get openAlipayHint =>
|
||||
'Vuelve tras pagar; esta página se actualiza automáticamente';
|
||||
@override
|
||||
String get openAlipayFailed => 'No se pudo abrir Alipay; comprueba que esté instalado o inténtalo de nuevo';
|
||||
String get openAlipayFailed =>
|
||||
'No se pudo abrir Alipay; comprueba que esté instalado o inténtalo de nuevo';
|
||||
@override
|
||||
String get awaitingPayment => 'Esperando el pago';
|
||||
@override
|
||||
@@ -429,13 +409,13 @@ class StringsEs extends AppText {
|
||||
@override
|
||||
String get qrNotSupported => 'Copia el contenido y ábrelo en Alipay';
|
||||
@override
|
||||
String get orderCreateFailed => 'Error al crear el pedido, inténtalo de nuevo más tarde';
|
||||
String get orderCreateFailed =>
|
||||
'Error al crear el pedido, inténtalo de nuevo más tarde';
|
||||
@override
|
||||
String get payUnsupportedRenderType => 'No compatible, cambia el método de pago';
|
||||
String get payUnsupportedRenderType =>
|
||||
'No compatible, cambia el método de pago';
|
||||
@override
|
||||
String get payNoActiveOrder => 'No hay pedidos activos';
|
||||
|
||||
// ── 支付渠道 switch + 订单 ──
|
||||
@override
|
||||
String get payChannel => 'Canal de pago';
|
||||
@override
|
||||
@@ -474,8 +454,6 @@ class StringsEs extends AppText {
|
||||
String get orderRebuy => 'Comprar de nuevo';
|
||||
@override
|
||||
String get payMethodNezha => 'Nazhapay';
|
||||
|
||||
// ── 邀请 / 通知 / 设置分组 / 订单过期(Spec ②③占位) ──
|
||||
@override
|
||||
String get inviteEntry => 'Invita a amigos y gana membresía';
|
||||
@override
|
||||
@@ -495,7 +473,8 @@ class StringsEs extends AppText {
|
||||
@override
|
||||
String get inviteRewardRegister => 'Registro de amigo · +3 días cada uno';
|
||||
@override
|
||||
String get inviteRewardFirstBuy => 'Primera compra del amigo · +7 días cada uno';
|
||||
String get inviteRewardFirstBuy =>
|
||||
'Primera compra del amigo · +7 días cada uno';
|
||||
@override
|
||||
String get inviteRewardJoinTg => 'Unirse al canal de TG · +3 días';
|
||||
@override
|
||||
@@ -546,4 +525,38 @@ class StringsEs extends AppText {
|
||||
String get promoBadge => 'Oferta especial';
|
||||
@override
|
||||
String get promoOriginalPrice => 'Antes';
|
||||
@override
|
||||
List<String> get days7 => const ['L', 'M', 'X', 'J', 'V', 'S', 'D'];
|
||||
@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 adRewarded(int minutes) => '+$minutes min añadidos';
|
||||
@override
|
||||
String nodeSwitchTitle(String name) => '¿Cambiar a $name?';
|
||||
@override
|
||||
String autoConnectingTo(String name) => 'Conectando automáticamente a $name…';
|
||||
@override
|
||||
String updateAvailableTitle(String version) =>
|
||||
'Nueva versión v$version disponible';
|
||||
@override
|
||||
String codeSentTo(String email) => 'Código enviado a $email';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user