How to get timezone, Language and County Id in flutter by the location of device in flutter?

80,308

Solution 1

https://flutter.io/tutorials/internationalization/#tracking-locale

Locale myLocale = Localizations.localeOf(context);

provides countryCode and languageCode

https://docs.flutter.io/flutter/dart-ui/Locale-class.html

The timezone should be available with (not tried)

DateTime.now().timeZoneName

https://docs.flutter.io/flutter/dart-core/DateTime-class.html

Solution 2

Flutter locales explained

First of all, you should understand the difference between system settings and your application settings:

  • System settings - what the system provides to your app as user preferences for your information.
  • Application settings - what you decided (explicitly or implicitly) to be the application locale. You may allow your users to select any locale of your app or let Flutter to do it for you.

Getting current system preferences

Get the current default system locale

import 'dart:io';

final String defaultLocale = Platform.localeName; // Returns locale string in the form 'en_US'

Get the list of system locales

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;

Locale of your application

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.

Getting your application locale

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.

Catch system locale changes

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
    });
  }

Full example

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.

initial list of locales

Our app will look like this on startup:

initial app state

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:

UK locale on top

The app will reflect this change:

app with the UK locale

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:

RU locale on top

Our app will reflect this change:

app with the RU locale

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.

Solution 3

Try this:

import 'dart:ui' as ui;
......
 @override
  Widget build(BuildContext context) {
// get system language code
    _sysLng = ui.window.locale.languageCode;    
...

Solution 4

you can use

import 'dart:io' show Platform;

String languageCode = Platform.localeName.split('_')[0];
String countryCode = Platform.localeName.split('_')[1];

Solution 5

If you write Platform.localeName, it gives you language and country like "en_US", "tr_TR".

To take just "en" or "tr", you can use substring() and take first 2 letter.

String deviceLanguage= Platform.localeName.substring(0,2);

It gives to you only "en" or "tr" etc...

If you want the country codes, use this;

String deviceCountry= Platform.localeName.substring(3,5);

It gives to you only "US" or "TR" etc...

Share:
80,308

Related videos on Youtube

Ammy Kang
Author by

Ammy Kang

Android Developer

Updated on July 08, 2022

Comments

  • Ammy Kang
    Ammy Kang almost 2 years

    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?

  • Ammy Kang
    Ammy Kang almost 6 years
    Thanks @Gunter, but I am getting country code "US" and language id "en", how can I get it accordingly my current location, as I am in India it should show "IND"
  • Günter Zöchbauer
    Günter Zöchbauer almost 6 years
    You need to add flutter_localizations flutter.io/tutorials/internationalization/#setting-up Let me know if this helps, I haven't tried this myself yet.
  • Idee
    Idee over 5 years
    @AmmyKang are you using an emulator?
  • Oliver Dixon
    Oliver Dixon about 5 years
    someDateTime.toLocal() works nice if you are using ISO timestamps
  • valerybodak
    valerybodak almost 5 years
    Locale myLocale = Localizations.localeOf(context); does not work for me. myLocale.languageCode is always "en"
  • Oliver Dixon
    Oliver Dixon almost 5 years
    Returns null always at the start of the app.
  • John Smith Optional
    John Smith Optional almost 5 years
    When I do this, I get the error "Failed assertion", "Scope != null, a Localizations ancestor was not found".
  • JerryZhou
    JerryZhou over 4 years
    I got same error of "Scope != null, a Localizations ancestor was not found"
  • Oliver Dixon
    Oliver Dixon over 4 years
    Always returns 'en' no matter what.
  • Louis de Decker
    Louis de Decker over 4 years
    using iOS 13 there seems to be a bug as it returns null ... so I don't find this method reliable. From now on I only use Locale myLocale = Localizations.localeOf(context);
  • Dazzibao
    Dazzibao about 4 years
    No that does not work. It always returns a hard coded american "en_US" locale, whatever the device locale/country is. This should should not be marked as answer...
  • Günter Zöchbauer
    Günter Zöchbauer about 4 years
    Do you have this code inside or outside of build()? I haven't used it in a while but I have some vague memory that this has to be inside build (or code called from build) but not for example in main() {...}.
  • Ahmed Osama
    Ahmed Osama about 4 years
    I love you .. time savior for me .. works with provider and easy localization package
  • Keyur Padalia
    Keyur Padalia almost 4 years
    The reason that Localizations.localeOf(context) does not work for everyone: it gives the locale of the current context, which is derived from the system locale but has been resolved to one of the locales in supportedLocales. This is a parameter passed to the MaterialApp or WidgetsApp widget, and the default is only [en_US]. Using WidgetsBinding.instance.window.locale gives you the raw thing.
  • Cliff Helsel
    Cliff Helsel almost 4 years
    This doesn't work for me if I change the iOS Simulator to US Spanish. I still get "en", "US".
  • schankam
    schankam almost 4 years
    If you guys are on iOS, do not actually forget to add supported languages in your info.plist otherwise you won't have it available.
  • Alexander  Pravdin
    Alexander Pravdin almost 4 years
    This method doesn't work before the WidgetsApp/MaterialApp widget is initialized.
  • Alexander  Pravdin
    Alexander Pravdin almost 4 years
    Also, Localizations.localeOf(context) returns locale that YOU defined as supported by your app in the supportedLocales parameter of the MaterialApp widget. If you didn't pass any locale there, you will get en_US always.
  • Cenk YAGMUR
    Cenk YAGMUR over 3 years
    I fixed it a while ago
  • ChrisH
    ChrisH over 3 years
    THIS is how a question gets answered. Nicely done, despite only being (as described) applicable to Android.
  • Joel Broström
    Joel Broström over 2 years
    Holy s**t this is god tier answer! I came for something else but do not regret reading this :) @AmmyKang would you mind changing this to the "right" answer?