feat(i18n): ④ l10n 漂移闸 + codegen 改纯 node 确定性输出
- gen_l10n_dart.mjs 去掉 dart format:其输出依赖包解析状态、跨环境不稳(首次 4 空格、 重跑 8 空格),会让漂移闸误报。改为确定性终态格式(list 单行 const [])。 analyze 不校验格式,不影响;gen 现零 dart 依赖、纯 node 确定。 - ci/check-codegen-drift.sh 增 l10n 段:重生成 strings_*.dart → git diff 非空即 fail (与 token 段同法,纯 node)。 - 验证:往返无损、重生成零 diff(闸稳定)、flutter analyze 0 issue、244 测试全绿。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A79VtQA1BwTuQN1ThpvYpo
This commit is contained in:
@@ -61,8 +61,7 @@ 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
|
||||
@@ -70,8 +69,7 @@ class StringsEs extends AppText {
|
||||
@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
|
||||
@@ -81,16 +79,13 @@ class StringsEs extends AppText {
|
||||
@override
|
||||
String get smartSelect => 'Selección inteligente';
|
||||
@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
|
||||
@@ -148,8 +143,7 @@ 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
|
||||
@@ -179,18 +173,15 @@ 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
|
||||
@@ -232,8 +223,7 @@ class StringsEs extends AppText {
|
||||
@override
|
||||
String get webUserCenter => 'Centro de usuario (Web)';
|
||||
@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
|
||||
@@ -241,8 +231,7 @@ 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
|
||||
@@ -272,8 +261,7 @@ 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
|
||||
@@ -281,8 +269,7 @@ class StringsEs extends AppText {
|
||||
@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.';
|
||||
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
|
||||
@@ -324,8 +311,7 @@ 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
|
||||
@@ -337,18 +323,15 @@ 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
|
||||
@@ -378,18 +361,15 @@ 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
|
||||
@@ -409,11 +389,9 @@ 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';
|
||||
@override
|
||||
@@ -473,8 +451,7 @@ 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
|
||||
@@ -528,26 +505,11 @@ class StringsEs extends AppText {
|
||||
@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',
|
||||
];
|
||||
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',
|
||||
];
|
||||
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',
|
||||
];
|
||||
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
|
||||
@@ -555,8 +517,7 @@ class StringsEs extends AppText {
|
||||
@override
|
||||
String autoConnectingTo(String name) => 'Conectando automáticamente a $name…';
|
||||
@override
|
||||
String updateAvailableTitle(String version) =>
|
||||
'Nueva versión v$version disponible';
|
||||
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