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,4 +1,5 @@
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';
@@ -30,13 +31,14 @@ class _PantallaAdivinanzaState extends State<PantallaAdivinanza> {
@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();
return Scaffold(
appBar: AppBar(
title: const Text('🎯 Adivinanza del impostor'),
title: Text(l10n.impostorGuessTitle),
automaticallyImplyLeading: false,
),
body: Center(
@@ -48,13 +50,13 @@ class _PantallaAdivinanzaState extends State<PantallaAdivinanza> {
const Text('🎭', style: TextStyle(fontSize: 64)),
const SizedBox(height: 16),
Text(
'El impostor eliminado puede\nintentar adivinar la palabra',
l10n.impostorCanGuess,
style: Theme.of(context).textTheme.titleLarge,
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
Text(
'Si acierta, ¡los impostores ganan!',
l10n.ifCorrectImpostorsWin,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: TemaApp.colorNaranja,
),
@@ -64,9 +66,9 @@ class _PantallaAdivinanzaState extends State<PantallaAdivinanza> {
if (_acierto == null) ...[
TextField(
controller: _controlador,
decoration: const InputDecoration(
hintText: '¿Cuál crees que es la palabra?',
prefixIcon: Icon(Icons.search),
decoration: InputDecoration(
hintText: l10n.guessWordHint,
prefixIcon: const Icon(Icons.search),
),
textCapitalization: TextCapitalization.sentences,
textAlign: TextAlign.center,
@@ -98,7 +100,7 @@ class _PantallaAdivinanzaState extends State<PantallaAdivinanza> {
);
}
},
child: const Text('No intentar'),
child: Text(l10n.dontGuess),
),
),
const SizedBox(width: 12),
@@ -109,7 +111,7 @@ class _PantallaAdivinanzaState extends State<PantallaAdivinanza> {
? _intentarAdivinar
: null,
icon: const Icon(Icons.send),
label: const Text('Adivinar'),
label: Text(l10n.guess),
),
),
],
@@ -130,7 +132,7 @@ class _PantallaAdivinanzaState extends State<PantallaAdivinanza> {
const Text('🎭🎉', style: TextStyle(fontSize: 48)),
const SizedBox(height: 12),
Text(
'¡Ha acertado!',
l10n.correctGuess,
style: Theme.of(context)
.textTheme
.headlineMedium
@@ -138,12 +140,12 @@ class _PantallaAdivinanzaState extends State<PantallaAdivinanza> {
),
const SizedBox(height: 8),
Text(
'La palabra era: ${partida.palabraSecreta}',
l10n.theWordWas(partida.palabraSecreta),
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 8),
Text(
'¡Los impostores ganan!',
l10n.impostorsWin,
style: Theme.of(context).textTheme.bodyLarge?.copyWith(
color: TemaApp.colorNaranja,
),
@@ -165,7 +167,7 @@ class _PantallaAdivinanzaState extends State<PantallaAdivinanza> {
);
},
icon: const Icon(Icons.emoji_events),
label: const Text('Ver resultado final'),
label: Text(l10n.seeEndResult),
),
),
],
@@ -184,7 +186,7 @@ class _PantallaAdivinanzaState extends State<PantallaAdivinanza> {
const Text('', style: TextStyle(fontSize: 48)),
const SizedBox(height: 12),
Text(
'¡No ha acertado!',
l10n.wrongGuess,
style: Theme.of(context)
.textTheme
.headlineMedium
@@ -192,7 +194,7 @@ class _PantallaAdivinanzaState extends State<PantallaAdivinanza> {
),
const SizedBox(height: 8),
Text(
'La partida continúa...',
l10n.gameContinues,
style: Theme.of(context).textTheme.bodyLarge,
),
],
@@ -223,7 +225,7 @@ class _PantallaAdivinanzaState extends State<PantallaAdivinanza> {
}
},
icon: const Icon(Icons.skip_next),
label: const Text('Siguiente ronda'),
label: Text(l10n.nextRound),
),
),
],