Reputation: 127024
I am encountering a problem, where localization works fine, but the applications needs to be restarted in order for the changes to propagate.
I know about OrientationBuilder
, which will call its builder whenever it detects a change in the device's orientation, which in e.g. Android would be considered as a configuration change, just like device language changes.
Is there something like LanguageBuilder
? I could not find anything on my own and not on flutter.io nor on pub. I have read this tutorial and know about Locale
, but I do not see a Stream
for Locale
.
My problem is that changing the language in iOS and Android native is really smooth. It gets handled automatically and perfectly integrates with services like Firebase Remote Config.
I really wonder if there is some method that will allow me to refresh my localization.
So I am asking how I can refresh my Remote Config when the device language changes.
Upvotes: 3
Views: 5551
Reputation: 127024
Device language changes can be detected using a WidgetsBindingObserver
.
It is the simplest to use it with a StatefulWidget
in your State
(with WidgetsBindingObserver
):
class _MyWidgetState extends State<MyWidget> with WidgetsBindingObserver {
@override
void didChangeLocales(List<Locale> locale) {
// The device language was changed when this is called.
}
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
...
}
This means that you can now reload your RemoteConfig
in didChangeLocales
:
@override
void didChangeLocales(List<Locale> locale) {
_updateRemoteConfig();
}
Future<void> _updateRemoteConfig() async {
final remoteConfig = await RemoteConfig.instance;
await remoteConfig.activateFetched(); // This will apply the new locale.
}
Upvotes: 3
Reputation: 277707
No there's no Builder
for Locale
.
Instead, there's an InheritedWidget
which you can subscribe to using Localizations.of
.
Since it is an InheritedWidget
, all widgets that call Localizations.of
will automatically refresh on locale change.
EDIT :
A example on how to live reload text using Flutter Locale system :
Let's assume you have the following class that holds translations :
class MyData {
String title;
MyData({this.title});
}
You'd then have a LocalizationsDelegate
that contains such data. A dumb implementation would be the following :
class MyLocale extends LocalizationsDelegate<MyData> {
MyData data;
MyLocale(this.data);
@override
bool isSupported(Locale locale) {
return true;
}
@override
Future<MyData> load(Locale locale) async {
return data;
}
@override
bool shouldReload(MyLocale old) {
return old.data != data;
}
}
To use it simply pass it to MaterialApp.localizationsDelegates
(be sure to add flutter_localizations
to your pubspec.yaml
) :
LocalizationsDelegate myLocale = MyLocale(MyData(title: "Foo"));
...
MaterialApp(
localizationsDelegates: [
myLocale,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
);
You can then freely live reload your translations by replacing myLocale
with a new MyLocale
instance.
Here's a full example of a click counter app. But where the current count is instead stored inside Locale
(because why not ?)
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
class MyCount {
String count;
MyCount({this.count});
}
class MyCountLocale extends LocalizationsDelegate<MyCount> {
MyCount data;
MyCountLocale(this.data);
@override
bool isSupported(Locale locale) {
return true;
}
@override
Future<MyCount> load(Locale locale) async {
return data;
}
@override
bool shouldReload(MyCountLocale old) {
return old.data != data;
}
}
Future<void> main() async {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
ValueNotifier<int> count = ValueNotifier<int>(0);
LocalizationsDelegate myLocale;
@override
void initState() {
count.addListener(() {
setState(() {
myLocale = MyCountLocale(MyCount(count: count.value.toString()));
});
});
myLocale = MyCountLocale(MyCount(count: count.value.toString()));
super.initState();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
localizationsDelegates: [
myLocale,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
home: MyHomePage(count: count),
);
}
}
class MyHomePage extends StatefulWidget {
final ValueNotifier<int> count;
MyHomePage({this.count});
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
primary: true,
appBar: AppBar(),
body: Column(
children: <Widget>[
FloatingActionButton(
onPressed: () => widget.count.value++,
child: Icon(Icons.plus_one),
),
ListTile(
title: Text(Localizations.of<MyCount>(context, MyCount).count),
),
],
),
);
}
}
Upvotes: 7