Estoy creando una aplicación en Flutter, hasta ahora estoy usando la internacionalización con JSON donde el idioma de la aplicación se basa en el idioma que el usuario tiene como predeterminado en su teléfono funciona bastante bien, pero me gustaría darle al usuario una oportunidad de cambiar el idioma sin cambiar la configuración de idioma del sistema del teléfono, simplemente haciendo clic en un botón y luego la aplicación cambia el idioma sin pasar por la configuración.
Aquí está el código:
El principal:
import 'package:flutter/material.dart';
import 'package:flutter_app_darkmode/app_localizations.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) => MaterialApp(
supportedLocales: [
Locale('en', "ZA"),
Locale('pt', "MZ"),
],
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate
],
localeResolutionCallback: (locale, supportedLocales) {
for (var supportedLocale in supportedLocales) {
if (supportedLocale.languageCode == locale.languageCode &&
supportedLocale.countryCode == locale.countryCode) {
return supportedLocale;
} else {
if (MyHomePage.local != null) {
for (int i = 0; i < supportedLocales.length; i++) {
if (MyHomePage.local == supportedLocales.elementAt(i)) {
return supportedLocales.elementAt(i);
}}}}}
return supportedLocales.first;
},
home: MyHomePage(),
);}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
class _MyHomePageState extends State<MyHomePage> {
getLocale() {
Locale myLocale = Localizations.localeOf(context);
print(myLocale);}
@override
Widget build(BuildContext context) {
getLocale();
return Scaffold(
body: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
AppLocalizations.of(context).translate('first_string'),
style: TextStyle(fontSize: 25),
textAlign: TextAlign.center,),
Text(
AppLocalizations.of(context).translate('second_string'),
style: TextStyle(fontSize: 25),
textAlign: TextAlign.center,),
RaisedButton(
child: Text('PT'),
onPressed: () {},
),],),),),);}}
La clase app_ubicaciones:
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class AppLocalizations {
final Locale locale;
AppLocalizations(this.locale);
static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
static const LocalizationsDelegate<AppLocalizations> delegate =
_AppLocalizationsDelegate();
Map<String, String> _localizedStrings;
Future<bool> load() async {
String jsonString =
await rootBundle.loadString('lang/${locale.languageCode}.json');
Map<String, dynamic> jsonMap = json.decode(jsonString);
_localizedStrings = jsonMap.map((key, value) {
return MapEntry(key, value.toString());
});
return true;}
String translate(String key) {
return _localizedStrings[key];}}
class _AppLocalizationsDelegate
extends LocalizationsDelegate<AppLocalizations> {
const _AppLocalizationsDelegate();
@override
bool isSupported(Locale locale) {
return ['en', 'pt'].contains(locale.languageCode);}
@override
Future<AppLocalizations> load(Locale locale) async {
AppLocalizations localizations = new AppLocalizations(locale);
await localizations.load();
return localizations;}
@override
bool shouldReload(_AppLocalizationsDelegate old) => false;}
spkersten
Puede configurar el locale
propiedad de MaterialApp
con su método de gestión de estado favorito. Por ejemplo:
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
static _MyAppState of(BuildContext context) => context.findAncestorStateOfType<_MyAppState>();
}
class _MyAppState extends State<MyApp> {
Locale _locale;
void setLocale(Locale value) {
setState(() {
_locale = value;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
locale: _locale,
home: Dashboard(),
);
}
}
class Dashboard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
TextButton(
child: Text("Set locale to German"),
onPressed: () => MyApp.of(context).setLocale(Locale.fromSubtags(languageCode: 'de')),
),
TextButton(
child: Text("Set locale to English"),
onPressed: () => MyApp.of(context).setLocale(Locale.fromSubtags(languageCode: 'en')),
),
],
);
}
}
-
esto funcionó para mí! Con una pequeña modificación: no pude hacer que funcionara cuando mi FlutterApp tenía un StatfulWidget (por ejemplo, MyApp) como ‘inicio’ principal. Así que envolví el widget MyApp con estado en un widget sin estado (por ejemplo, MyAppWrapper). Lo único que hace MyAppWrapper es que tiene un método de compilación que devuelve MyApp().
– drpawelo
2 de julio de 2021 a las 16:16
-
pero esto no sobreviviría a los reinicios de la aplicación, ¿verdad?
– Marco
16 de julio de 2021 a las 16:51
-
@Marcus De hecho, no sobrevive a los reinicios de la aplicación. Tendrías que persistir los datos.
– habla
12 de agosto de 2021 a las 11:51
-
Cualquier ejemplo que persista los cambios.
– AprendeFlutter
12 de abril de 2022 a las 13:07
-
@LearnFlutter podrías usar el Preferencias compartidas paquete y conservar los datos allí cuando cambia la selección. Luego, para leer los datos, podrías hacer esto:
@override void didChangeDependencies() { SharedPreferencesHelper.getLanguageCode().then((languageCode) { setState(() { _locale = Locale(languageCode); }); }); super.didChangeDependencies(); }
– Sam Bains
21 de mayo de 2022 a las 9:17
Balaji Venkatraman
Tienes que usar las localizaciones proporcionadas por Flutter. Debe usar archivos JSON y delegado personalizados para los idiomas admitidos. implementé usando bloc
Pasos a seguir,
- crear una carpeta
assets/languages/
en la carpeta raíz - Crear
JSON
archivos para los idiomas admitidos. Me gusta: en.json, es.json - Cree pares de clave y valor para sus cadenas en cada archivo de acuerdo con sus cadenas de idioma específicas
- En
main.dart
crear por defectolocale, supportedLocales and localizationsDelegates
.
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:movie_app/common/constants/languages.dart';
import 'package:movie_app/presentation/app_localizations.dart';
import 'package:movie_app/presentation/blocs/language/language_bloc.dart';
import 'package:movie_app/presentation/journeys/home/home_screen.dart';
class MovieApp extends StatefulWidget {
@override
_MovieAppState createState() => _MovieAppState();
}
class _MovieAppState extends State<MovieApp> {
LanguageBloc _languageBloc;
@override
void initState() {
_languageBloc = LanguageBloc();
super.initState();
}
@override
void dispose() {
_languageBloc.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
return BlocProvider<LanguageBloc>.value(
value: _languageBloc,
child: BlocBuilder<LanguageBloc, LanguageState>(
builder: (context, state) {
if (state is LanguageLoaded) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Movie App',
home: HomeScreen(),
supportedLocales:
Languages.languages.map((e) => Locale(e.code)).toList(),
locale: state.locale,
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
);
}
return SizedBox.shrink();
},
),
);
}
}
- Ahora crea modelos y constantes de lenguajes.
class LanguageEntity {
final String code;
final String value;
const LanguageEntity({
this.code,
this.value,
});
}
class Languages {
const Languages._();
static const languages = [
LanguageEntity(code: 'en', value: 'English'),
LanguageEntity(code: 'es', value: 'Spanish'),
];
}
- Ahora Crear delegado de localización de aplicaciones
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:movie_app/common/constants/languages.dart';
class AppLocalizations {
final Locale locale;
AppLocalizations(this.locale);
static const LocalizationsDelegate<AppLocalizations> delegate =
_AppLocalizationDelagate();
static AppLocalizations of(context) =>
Localizations.of<AppLocalizations>(context, AppLocalizations);
Map<String, String> _localisedString;
Future<bool> load() async {
final jsonString = await rootBundle
.loadString('assets/languages/${locale.languageCode}.json');
final Map<String, dynamic> jsonMap = json.decode(jsonString);
_localisedString =
jsonMap.map((key, value) => MapEntry(key, value.toString()));
return true;
}
String translate(String key) {
return _localisedString[key];
}
}
class _AppLocalizationDelagate extends LocalizationsDelegate<AppLocalizations> {
const _AppLocalizationDelagate();
@override
bool isSupported(Locale locale) {
return Languages.languages
.map((e) => e.code)
.toList()
.contains(locale.languageCode);
}
@override
bool shouldReload(covariant LocalizationsDelegate old) {
return false;
}
@override
Future<AppLocalizations> load(Locale locale) async {
AppLocalizations appLocalizations = AppLocalizations(locale);
await appLocalizations.load();
return appLocalizations;
}
}
- Ahora crea bloques
import 'dart:async';
import 'package:bloc/bloc.dart';
// import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:movie_app/common/constants/languages.dart';
import 'package:movie_app/domain/entities/language_entity.dart';
part 'language_event.dart';
part 'language_state.dart';
class LanguageBloc extends Bloc<LanguageEvent, LanguageState> {
LanguageBloc() : super(LanguageLoaded(Locale(Languages.languages[0].code)));
@override
Stream<LanguageState> mapEventToState(
LanguageEvent event,
) async* {
if (event is ToggleLanguageEvent) {
yield LanguageLoaded(Locale(event.language.code));
}
}
}
8.Ahora crea un evento
part of 'language_bloc.dart';
abstract class LanguageEvent {
const LanguageEvent();
}
class ToggleLanguageEvent extends LanguageEvent {
final LanguageEntity language;
ToggleLanguageEvent(this.language);
}
- Ahora crea el estado
part of 'language_bloc.dart';
abstract class LanguageState {
const LanguageState();
}
class LanguageLoaded extends LanguageState {
final Locale locale;
LanguageLoaded(this.locale);
}
10.Ahora botón Crear para cambiar de idioma.
RaisedButton(child: ,RaisedButton(child: Text('Switch',
onPressed: (int index) {
BlocProvider.of<LanguageBloc>(context).add(
ToggleLanguageEvent(
Languages.languages[index], // index value can be 0 or 1 in our case
), // 0 - en, 1 - es
);
Navigator.of(context).pop();
},
);
Además, consulte el enlace para una implementación clara
https://www.youtube.com/watch?v=W-2p3zB1z8k
Si está utilizando el proveedor como administración estatal, puede seguir este artículo.
AnasSafi
Debido a que la respuesta aceptada tiene algunas deficiencias, estableceré una nueva:
El cambio de configuración regional de la aplicación se puede hacer de varias maneras, aquí mostraré dos formas:
Camino 1 (usando rxdart
y SharedPreferences
complementos):
Para una mayor comprensión, se creó un proyecto para explicar cómo hacer eso, puede encontrarlo en https://github.com/AnasSafi/flutter_localization_example
Salida del proyecto:
Forma 2:
Nota 1: yo estaba usado Preferencias compartidas complemento para guardar la configuración regional que seleccione el cliente.
Nota 2: Reemplazar Arkansas y PD con su configuración regional predeterminada…
Código completo de dardo principal archivo:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized(); //To solve problem (ServicesBinding.defaultBinaryMessenger was accessed before the binding was initialized)
runApp(MainApp());
}
class MainApp extends StatefulWidget {
const MainApp({Key? key}) : super(key: key);
/*
To Change Locale of App
*/
static void setLocale(BuildContext context, Locale newLocale) async {
_MainAppState? state = context.findAncestorStateOfType<_MainAppState>();
var prefs = await SharedPreferences.getInstance();
prefs.setString('languageCode', newLocale.languageCode);
prefs.setString('countryCode', "");
state?.setState(() {
state._locale = newLocale;
});
}
@override
_MainAppState createState() => _MainAppState();
}
class _MainAppState extends State<MainApp> {
Locale _locale = Locale('ar', 'ps');
@override
void initState() {
super.initState();
this._fetchLocale().then((locale) {
setState(() {
this._locale = locale;
});
});
}
/*
To get local from SharedPreferences if exists
*/
Future<Locale> _fetchLocale() async {
var prefs = await SharedPreferences.getInstance();
String languageCode = prefs.getString('languageCode') ?? 'ar';
String countryCode = prefs.getString('countryCode') ?? 'ps';
return Locale(languageCode, countryCode);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
locale: _locale,
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
const FallbackCupertinoLocalisationsDelegate(),
],
supportedLocales: [
const Locale('en', ''), // English, no country code
const Locale('ar', ''), // Arabic, no country code
],
theme: ThemeData(
primarySwatch: Colors.deepPurple,
),
home: InitializeApp(), // here use your own home name...
);
}
}
/*
To solve problem of hold press on inputs
*/
class FallbackCupertinoLocalisationsDelegate extends LocalizationsDelegate<CupertinoLocalizations> {
const FallbackCupertinoLocalisationsDelegate();
@override
bool isSupported(Locale locale) => true;
@override
Future<CupertinoLocalizations> load(Locale locale) =>
DefaultCupertinoLocalizations.load(locale);
@override
bool shouldReload(FallbackCupertinoLocalisationsDelegate old) => false;
}
Ahora, desde cualquier otra clase, necesita cambiar la configuración regional, puede usar mi camino:
Importar dardo principal archivo, luego use mi simple DropdownButton:
Nota: reemplazar valor: AppLocalizations.of(context)!.locale.toString(), esta línea con su forma de obtener la configuración regional actual de la aplicación…
import 'package:yout_project_name/main.dart';
DropdownButton(
onChanged: (v) => setState(() {
MainApp.setLocale(context, Locale(v.toString(), ""));
}),
value: AppLocalizations.of(context)!.locale.toString(), // change this line with your way to get current locale to select it as default in dropdown
items: [
DropdownMenuItem(
child: Text( 'English'), value: 'en'
),
DropdownMenuItem(
child: Text( 'العربية'), value: 'ar'
),
],
)
Eche un vistazo al paquete language_builder en pub.dev. Es muy fácil de usar. Al envolver su widget raíz con LanguageBuilder, puede configurar el idioma de su aplicación. Dígale a su aplicación que use el idioma de los teléfonos o cámbielo manualmente desde la aplicación.
-
Las preguntas que solicitan recursos están fuera de tema. Esta respuesta solo ofrece un enlace a un nuevo recurso y no muestra cómo implementar el recurso para resolver la pregunta en el OP. Si bien este enlace puede responder la pregunta, es mejor incluir las partes esenciales de la respuesta aquí y proporcionar el enlace como referencia. Las respuestas de solo enlace pueden dejar de ser válidas si la página enlazada cambia. – De la revisión
–Trenton McKinney
28 de septiembre de 2021 a las 18:06
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MainApp());
}
class MainApp extends StatefulWidget {
const MainApp({Key? key}) : super(key: key);
/*
To Change Locale of App
*/
static void setLocale(BuildContext context, Locale newLocale) async {
_MainAppState? state = context.findAncestorStateOfType<_MainAppState>();
var prefs = await SharedPreferences.getInstance();
prefs.setString('languageCode', newLocale.languageCode);
prefs.setString('countryCode', "");
state?.setState(() {
state._locale = newLocale;
});
}
@override
// ignore: library_private_types_in_public_api
_MainAppState createState() => _MainAppState();
}
class _MainAppState extends State<MainApp> {
Locale _locale = const Locale('ar', 'tn');
@override
void initState() {
super.initState();
_fetchLocale().then((locale) {
setState(() {
_locale = locale;
});
});
}
/*
To get local from SharedPreferences if exists
*/
Future<Locale> _fetchLocale() async {
var prefs = await SharedPreferences.getInstance();
String languageCode = prefs.getString('languageCode') ?? 'ar';
String countryCode = prefs.getString('countryCode') ?? 'tn';
return Locale(languageCode, countryCode);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
locale: _locale,
// ignore: prefer_const_literals_to_create_immutables
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
const FallbackCupertinoLocalisationsDelegate(),
],
// ignore: prefer_const_literals_to_create_immutables
supportedLocales: [
const Locale('en', ''), // English, no country code
const Locale('fr', ''),
const Locale('ar', ''),
],
theme: ThemeData(
primarySwatch: Colors.deepPurple,
),
home: const AppContent(), // here use your own home name...
);
}
}
/*
To solve problem of hold press on inputs
*/
class FallbackCupertinoLocalisationsDelegate
extends LocalizationsDelegate<CupertinoLocalizations> {
const FallbackCupertinoLocalisationsDelegate();
@override
bool isSupported(Locale locale) => true;
@override
Future<CupertinoLocalizations> load(Locale locale) =>
DefaultCupertinoLocalizations.load(locale);
@override
bool shouldReload(FallbackCupertinoLocalisationsDelegate old) => false;
}
//___________________________________
class AppContent extends StatefulWidget {
const AppContent({super.key});
@override
State<AppContent> createState() => _AppContentState();
}
class _AppContentState extends State<AppContent> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
Text(AppLocalizations.of(context)!.hello),
const SizedBox(height: 10),
TextButton(
onPressed: () {
setState(() {
MainApp.setLocale(context, const Locale("fr", ""));
});
},
child: const Text("Fr"),
),
const SizedBox(height: 10),
TextButton(
onPressed: () {
setState(() {
MainApp.setLocale(context, const Locale("en", ""));
});
},
child: const Text("En"),
),
const SizedBox(height: 10),
TextButton(
onPressed: () {
setState(() {
MainApp.setLocale(context, const Locale("ar", ""));
});
},
child: const Text("Ar"),
),
const SizedBox(height: 10)
],
),
),
);
}
}
-
Las preguntas que solicitan recursos están fuera de tema. Esta respuesta solo ofrece un enlace a un nuevo recurso y no muestra cómo implementar el recurso para resolver la pregunta en el OP. Si bien este enlace puede responder la pregunta, es mejor incluir las partes esenciales de la respuesta aquí y proporcionar el enlace como referencia. Las respuestas de solo enlace pueden dejar de ser válidas si la página enlazada cambia. – De la revisión
–Trenton McKinney
28 de septiembre de 2021 a las 18:06
esto puede ser útil para ti,desarrolladorlibs.com/2019/03/…
–Shirsh Shukla
18 de diciembre de 2020 a las 12:14
Recomendaría buscar en el paquete Obtener: pub.dev/packages/get. Su soporte de internacionalización es bastante robusto y fácil de usar, puedes leer más aquí: pub.dev/packages/get#internacionalización. Puede usar el método descrito en “cambiar configuración regional” una vez que se presiona el botón para cambiar las traducciones.
– Tanay Neotia
19 de diciembre de 2020 a las 20:24
Yo sugeriría esto: medium.com/@puneetsethi25/…
– puspak saha
23 de diciembre de 2020 a las 12:01