I am new to flutter, and I want to get Timezone, language, and county Id when I run my project on my device android or iOS. It should detect Timezone, language and country Id from the location of the device. I am newbie to flutter and don't know how can I get these.
Can I get these via the internal library?
To determine the tz timezone, use both the DateTime. now(). timeZoneName and DateTime. now().
Initialization from Dart library dart , contains a single no-argument function, initializeTimeZones . To initialize the all database variant, import 'package:timezone/data/latest_all. dart' . To initialize the 10y database variant, import 'package:timezone/data/latest_10y.
First of all, you should understand the difference between system settings and your application settings:
import 'dart:io'; final String defaultLocale = Platform.localeName; // Returns locale string in the form 'en_US'
import 'package:flutter/material.dart'; final List<Locale> systemLocales = WidgetsBinding.instance.window.locales; // Returns the list of locales that user defined in the system settings.
or
import 'dart:ui'; final List<Locale> systemLocales = window.locales;
The MaterialApp widget supports localization. It accepts the list of locales that you decided your app supports. That means you should explicitly define them in the widget initialization in the supportedLocales
property and provide so-called "localization delegates" that will do the actual translation to a selected locale (the localizationsDelegates
property). Providing delegates is required if your app supports any other locales except en_US
. When you request an application locale you will get an exact value from the list of supportedLocales
.
final Locale appLocale = Localizations.localeOf(context);
This works only when the MaterialApp
widget is already initialized. You can not use it before the MaterialApp
initialization. Obviously, if your app widget is not initialized, you can not get its locale. To use it, you must call this expression in a child component's build
method. For example:
void main() async { runApp( MaterialApp( title: 'MyApp', home: MyApp(), ) ); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { // Show the name of the current application locale return Text(Localizations.localeOf(context).toString()); } }
This will print the en_US
text on the screen (because this is the default locale and we did not provide anything else). It doesn't matter what the system locale settings are because we didn't define explicitly any locale for our app in this example and thus it returns the default one.
To be able to react on system locale changes, you should use a stateful widget that implements the WidgetsBindingObserver
mixin and define the didChangeLocales
method that will be called on system locale changes:
@override void didChangeLocales(List<Locale> locale) { // This is run when system locales are changed super.didChangeLocales(locale); setState(() { // Do actual stuff on the changes }); }
To summarize all the above, here is the visual example of getting locales on startup and reacting on system settings changes:
import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); // Get the initial locale values final String defaultSystemLocale = Platform.localeName; final List<Locale> systemLocales = WidgetsBinding.instance.window.locales; // Define locales that our app supports (no country codes, see comments below) final appSupportedLocales = <Locale>[ Locale('ru'), Locale('en'), ]; final MyApp myApp = MyApp(defaultSystemLocale, systemLocales); runApp( MaterialApp( title: 'MyApp', home: myApp, supportedLocales: appSupportedLocales, localizationsDelegates: [ // These are default localization delegates that implement the very basic translations for standard controls and date/time formats. GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, ], ) ); } class MyApp extends StatefulWidget { // Store initial locale settings here, they are unchanged final String initialDefaultSystemLocale; final List<Locale> initialSystemLocales; MyApp(this.initialDefaultSystemLocale, this.initialSystemLocales); @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State<MyApp> with WidgetsBindingObserver { // Store dynamic changeable locale settings here, they change with the system changes String currentDefaultSystemLocale; List<Locale> currentSystemLocales; // Here we read the current locale values void setCurrentValues() { currentSystemLocales = WidgetsBinding.instance.window.locales; currentDefaultSystemLocale = Platform.localeName; } @override void initState() { // This is run when the widget is first time initialized WidgetsBinding.instance.addObserver(this); // Subscribe to changes setCurrentValues(); super.initState(); } @override void didChangeLocales(List<Locale> locale) { // This is run when system locales are changed super.didChangeLocales(locale); // Update state with the new values and redraw controls setState(() { setCurrentValues(); }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), body: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[ Text('Initial system default locale: ${widget.initialDefaultSystemLocale}.'), Text('Initial language code: ${widget.initialDefaultSystemLocale.split('_')[0]}, country code: ${widget.initialDefaultSystemLocale.split('_')[1]}.'), Text('Initial system locales:'), for (var locale in widget.initialSystemLocales) Text(locale.toString()), Text(''), Text('Current system default locale: ${currentDefaultSystemLocale}.'), Text('Current system locales:'), for (var locale in currentSystemLocales) Text(locale.toString()), Text(''), Text('Selected application locale: ${Localizations.localeOf(context).toString()}.'), Text(''), Text('Current date: ${Localizations.of<MaterialLocalizations>(context, MaterialLocalizations).formatFullDate(DateTime.now())}.'), Text('Current time zone: ${DateTime.now().timeZoneName} (offset ${DateTime.now().timeZoneOffset}).'), ], ), ); } }
The supported locales are defined without country codes to show you how the selection of the current app locale works. Internally, the MaterialApp
widget is comparing the list of locales supported by the app with the list of user preferences passed by the system and selects the most appropriate one.
Let's assume that we have the following list of system locales (en_US, en_GB, ru_RU):
** Click on thumbnail to see the full screenshot.
Our app will look like this on startup:
We see that initial and current values obviously the same. The app selected the en
locale as its current locale.
Now let's change the list of locales to the following, moving the en_GB locale to top making it the default system locale:
The app will reflect this change:
The app obviously still selects the en
locale as its current locale because it is the closest match to both en_US
and en_GB
locales.
Now let's change the settings to the Russian language as the default system value:
Our app will reflect this change:
Now you can see that the ru
locale was selected as the app locale.
Hope this helps to understand how localization works in Flutter, how to get current values, and how to reflect system changes. The details about locale delegates are not explained because it is off-topic here.
PS: This code is tested under Android only. I think with minor changes it can be adapted to all other platforms.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With