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:
83
lib/servicios/servicio_idioma.dart
Normal file
83
lib/servicios/servicio_idioma.dart
Normal file
@@ -0,0 +1,83 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
/// Servicio para gestionar el idioma de la app
|
||||
class ServicioIdioma extends ChangeNotifier {
|
||||
static const _claveIdioma = 'idioma_app';
|
||||
|
||||
Locale? _locale;
|
||||
Locale? get locale => _locale;
|
||||
|
||||
/// Idiomas soportados con su bandera y nombre nativo
|
||||
static const idiomasSoportados = <String, ({String bandera, String nombre})>{
|
||||
'es': (bandera: '🇪🇸', nombre: 'Español'),
|
||||
'en': (bandera: '🇬🇧', nombre: 'English'),
|
||||
'fr': (bandera: '🇫🇷', nombre: 'Français'),
|
||||
'pt': (bandera: '🇧🇷', nombre: 'Português'),
|
||||
'de': (bandera: '🇩🇪', nombre: 'Deutsch'),
|
||||
'it': (bandera: '🇮🇹', nombre: 'Italiano'),
|
||||
'ru': (bandera: '🇷🇺', nombre: 'Русский'),
|
||||
'ja': (bandera: '🇯🇵', nombre: '日本語'),
|
||||
'ko': (bandera: '🇰🇷', nombre: '한국어'),
|
||||
'zh': (bandera: '🇨🇳', nombre: '简体中文'),
|
||||
'zh_TW': (bandera: '🇹🇼', nombre: '繁體中文'),
|
||||
'ar': (bandera: '🇸🇦', nombre: 'العربية'),
|
||||
'hi': (bandera: '🇮🇳', nombre: 'हिन्दी'),
|
||||
'tr': (bandera: '🇹🇷', nombre: 'Türkçe'),
|
||||
'pl': (bandera: '🇵🇱', nombre: 'Polski'),
|
||||
'nl': (bandera: '🇳🇱', nombre: 'Nederlands'),
|
||||
'ca': (bandera: '🏴', nombre: 'Català'),
|
||||
'eu': (bandera: '🏴', nombre: 'Euskara'),
|
||||
};
|
||||
|
||||
static List<Locale> get localesSoportados => idiomasSoportados.keys.map((k) {
|
||||
if (k.contains('_')) {
|
||||
final partes = k.split('_');
|
||||
return Locale(partes[0], partes[1]);
|
||||
}
|
||||
return Locale(k);
|
||||
}).toList();
|
||||
|
||||
/// Carga el idioma guardado en preferencias
|
||||
Future<void> cargar() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final codigo = prefs.getString(_claveIdioma);
|
||||
if (codigo != null) {
|
||||
if (codigo.contains('_')) {
|
||||
final partes = codigo.split('_');
|
||||
_locale = Locale(partes[0], partes[1]);
|
||||
} else {
|
||||
_locale = Locale(codigo);
|
||||
}
|
||||
}
|
||||
// Si no hay preferencia guardada, _locale queda null → se usa el del sistema
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// Cambia el idioma y lo persiste
|
||||
Future<void> cambiarIdioma(String codigoIdioma) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
if (codigoIdioma == 'sistema') {
|
||||
await prefs.remove(_claveIdioma);
|
||||
_locale = null;
|
||||
} else {
|
||||
await prefs.setString(_claveIdioma, codigoIdioma);
|
||||
if (codigoIdioma.contains('_')) {
|
||||
final partes = codigoIdioma.split('_');
|
||||
_locale = Locale(partes[0], partes[1]);
|
||||
} else {
|
||||
_locale = Locale(codigoIdioma);
|
||||
}
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// Devuelve el código de idioma actual (o 'sistema' si usa el del dispositivo)
|
||||
String get codigoActual {
|
||||
if (_locale == null) return 'sistema';
|
||||
if (_locale!.countryCode != null && _locale!.countryCode!.isNotEmpty) {
|
||||
return '${_locale!.languageCode}_${_locale!.countryCode}';
|
||||
}
|
||||
return _locale!.languageCode;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user