I am using flutter localizations for changing language in my flutter app. I want to change my app's language in real time and have implemented logic for that. Now, I want that when user closes app and restarts it, he gets same language he chose before, i.e. language should not set back to default after user closes the app. For this purpose, I am using shared preferences to save the code of language that user selected, and now I can't retrieve it in the beginning of the app. Please help!
locale_provider.dart:
import 'package:flutter/material.dart';
import 'package:myapp/l10n/l10n.dart';
import 'package:shared_preferences/shared_preferences.dart';
class LocaleProvider extends ChangeNotifier {
Locale? _locale = const Locale('en');
Locale? get locale => _locale;
void setLocale(Locale locale) {
if (!L10n.all.contains(locale)) return;
_locale = locale;
notifyListeners();
//setLocaleSettings(locale);
}
void clearLocale() {
_locale = null;
notifyListeners();
}
void changeLocaleSettings(Locale newLocale) async {
if(newLocale == Locale('en')) {
_locale = Locale('en');
} else if(newLocale==Locale('uk')){
_locale = Locale('uk');
} else if(newLocale==Locale('ru')){
_locale = Locale('ru');
}
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString("code", _locale?.countryCode??"en");
notifyListeners();
}
Future getLocaleFromSettings() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String code = prefs.getString("code")??"en";
Locale newLocale = Locale(code);
if(newLocale == Locale('en')) {
_locale = Locale('en');
} else if(newLocale==Locale('uk')){
_locale = Locale('uk');
} else if(newLocale==Locale('ru')){
_locale = Locale('ru');
}
}
}
In my language selection dropdown, I am changing language like this:
class LanguagePickerWidget extends StatelessWidget {
const LanguagePickerWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final provider = Provider.of<LocaleProvider>(context);
final locale1 = provider.locale ?? const Locale('en');
return DropdownButtonHideUnderline(
child: SizedBox(
width: 15,
child: Theme(
data: Theme.of(context).copyWith(
canvasColor: Colors.green.shade300,
),
child: DropdownButton(
borderRadius:BorderRadius.circular(12),
isExpanded: true,
itemHeight: null,
value: locale1,
icon: Container(
//width: 10.0
),
items: L10n.all.map(
(locale) {
final flag = L10n.getFlag(locale.languageCode);
return DropdownMenuItem(
child: Align(
alignment: Alignment.center,
child: Text(
flag,
style: const TextStyle(fontSize: 22.0),
),
),
value: locale,
onTap: () {
final provider = Provider.of<LocaleProvider>(context, listen: false);
provider.setLocale(locale);
provider.changeLocaleSettings(locale);
print(locale);
},
);
},
).toList(),
onChanged: (_) {},
),
),
),
);
}
}
In main.dart:
class MyApp extends StatelessWidget {
MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) => ChangeNotifierProvider(
create: (context) => LocaleProvider(),
builder: (context, child) {
final provider = Provider.of<LocaleProvider>(context);
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
scaffoldBackgroundColor: Colors.lightGreen[100],
primarySwatch: Colors.green,
),
//locale: provider.locale,
supportedLocales: L10n.all,
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
home: const HomePage(),
);
});
}
It works pretty well for changing the language in runtime.. And now I don't understand how to retrieve and set the previously selected language (from shared preferences)? Please help!
CodePudding user response:
Create a default constructor for LocaleProvider
class and put this code inside it
LocaleProvider(){
Fututre.delayed(Duration.zero, getLocaleFromSettings);
}
and at the end of your function getLocaleFromSettings()
, call notifyListeners();
the reason to use FutureBuilder
is that if you called notifyListeners
while building frame is processing it will give you an error, so adding some delay to prevent rendering issues
CodePudding user response:
tried this get locale whenever you intialize LocaleProvider class:-
import 'package:flutter/material.dart';
import 'package:myapp/l10n/l10n.dart';
import 'package:shared_preferences/shared_preferences.dart';
class LocaleProvider extends ChangeNotifier {
Locale? locale;
LocaleProvider({this.locale});
Locale? get locale => _locale;
void setLocale(Locale locale) {
if (!L10n.all.contains(locale)) return;
_locale = locale;
notifyListeners();
//setLocaleSettings(locale);
}
void clearLocale() {
_locale = null;
notifyListeners();
}
void changeLocaleSettings(Locale newLocale) async {
if(newLocale == Locale('en')) {
_locale = Locale('en');
} else if(newLocale==Locale('uk')){
_locale = Locale('uk');
} else if(newLocale==Locale('ru')){
_locale = Locale('ru');
}
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString("code", _locale?.countryCode??"en");
notifyListeners();
}
Future getLocaleFromSettings() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String code = prefs.getString("code")??"en";
Locale newLocale = Locale(code);
if(newLocale == Locale('en')) {
_locale = Locale('en');
} else if(newLocale==Locale('uk')){
_locale = Locale('uk');
} else if(newLocale==Locale('ru')){
_locale = Locale('ru');
}
}
}
use this in main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
SharedPreferences _sharedPreferences = await SharedPreferences.getInstance();
string savedLangugae = get from sharepreference;
runApp(MultiProvider(providers: [
ChangeNotifierProvider(create: (_) => LocaleProvider(locale:Locale(savedLanguage))),
], child: const MyApp()));
}
Hope it will work.