v0.2.0: i18n 18 idiomas + pantalla ajustes + bancos multiidioma

Internacionalización completa:
- 18 ficheros .arb: es, en, fr, pt, de, it, ru, ja, ko, zh, zh_TW, ar, hi, tr, pl, nl, ca, eu
- Todos los strings extraídos de todas las pantallas
- Detección automática de idioma del sistema
- Selector manual en pantalla de ajustes

Pantalla de ajustes nueva:
- Selector de idioma con banderas emoji
- Vibración ON/OFF
- Acerca de (versión, desarrollador)

Bancos de palabras multiidioma:
- palabras.json (castellano, 1000 palabras)
- palabras_en.json (inglés, 1000 palabras)
- palabras_fr.json (francés, 1000 palabras)
- Fallback a castellano si no hay banco del idioma

13138 líneas Dart, 39 ficheros, 0 issues en flutter analyze
This commit is contained in:
ShanaiaBot
2026-04-04 01:18:09 +02:00
parent de2c8ffa18
commit 1bca50af1d
56 changed files with 14389 additions and 201 deletions

View File

@@ -1,5 +1,6 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:el_impostor/l10n/generated/app_localizations.dart';
import 'package:provider/provider.dart';
import '../estado/estado_juego.dart';
import '../tema/tema_app.dart';
@@ -59,6 +60,7 @@ class _PantallaDebateState extends State<PantallaDebate> {
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
final estado = context.watch<EstadoJuego>();
final partida = estado.partida;
if (partida == null) return const SizedBox.shrink();
@@ -70,7 +72,7 @@ class _PantallaDebateState extends State<PantallaDebate> {
return Scaffold(
appBar: AppBar(
title: Text('Debate - Ronda ${partida.rondaActual}'),
title: Text(l10n.debateRound(partida.rondaActual)),
automaticallyImplyLeading: false,
),
body: Padding(
@@ -94,7 +96,7 @@ class _PantallaDebateState extends State<PantallaDebate> {
child: Column(
children: [
Text(
_tiempoAgotado ? '⏰ ¡Tiempo agotado!' : '⏱️ Tiempo restante',
_tiempoAgotado ? l10n.timeUp : l10n.timeRemaining,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: _tiempoAgotado
? TemaApp.colorAcento
@@ -141,12 +143,12 @@ class _PantallaDebateState extends State<PantallaDebate> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Jugadores en debate',
l10n.playersInDebate,
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 4),
Text(
'${partida.jugadoresActivos.length} activos • ${partida.impostoresActivos.length} impostor(es) ocultos',
l10n.activePlayersInfo(partida.jugadoresActivos.length, partida.impostoresActivos.length),
style: Theme.of(context).textTheme.bodyMedium,
),
const SizedBox(height: 12),
@@ -178,7 +180,7 @@ class _PantallaDebateState extends State<PantallaDebate> {
),
),
subtitle: j.eliminado
? const Text('Eliminado')
? Text(l10n.eliminated)
: null,
dense: true,
);
@@ -206,7 +208,7 @@ class _PantallaDebateState extends State<PantallaDebate> {
);
},
icon: const Text('📝', style: TextStyle(fontSize: 18)),
label: const Text('Notas'),
label: Text(l10n.notes),
),
),
const SizedBox(width: 12),
@@ -215,7 +217,7 @@ class _PantallaDebateState extends State<PantallaDebate> {
child: ElevatedButton.icon(
onPressed: _irAVotacion,
icon: const Text('🗳️', style: TextStyle(fontSize: 18)),
label: const Text('Ir a votación'),
label: Text(l10n.goToVoting),
),
),
],