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
84 lines
3.0 KiB
Dart
84 lines
3.0 KiB
Dart
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;
|
|
}
|
|
}
|