← Back to Blog

Flutter Get Current Locale: Complete Guide to Detecting User Language

flutterlocaleget-localelanguage-detectioni18nlocalization

Flutter Get Current Locale: Complete Guide to Detecting User Language

Knowing your user's current locale is essential for delivering personalized experiences. Whether you need to format dates, display the right currency, or load appropriate translations, Flutter provides several ways to get the current locale.

Quick Answer: Get Current Locale

// Method 1: From BuildContext (most common)
Locale currentLocale = Localizations.localeOf(context);

// Method 2: Platform locale (device setting)
Locale deviceLocale = WidgetsBinding.instance.platformDispatcher.locale;

// Method 3: All preferred locales
List<Locale> preferredLocales = WidgetsBinding.instance.platformDispatcher.locales;

Understanding Locale in Flutter

A Locale object contains:

  • languageCode: ISO 639-1 code (e.g., 'en', 'es', 'zh')
  • countryCode: ISO 3166-1 code (e.g., 'US', 'GB', 'CN')
  • scriptCode: Script variant (e.g., 'Hans', 'Hant' for Chinese)
Locale locale = Locale('en', 'US');
print(locale.languageCode);  // 'en'
print(locale.countryCode);   // 'US'
print(locale.toString());    // 'en_US'

Method 1: Get App's Current Locale (Recommended)

This returns the locale currently used by your app's localization system:

import 'package:flutter/material.dart';

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Get the locale your app is currently using
    Locale currentLocale = Localizations.localeOf(context);

    print('Language: ${currentLocale.languageCode}');
    print('Country: ${currentLocale.countryCode}');

    return Text('Current: ${currentLocale.toString()}');
  }
}

When to use: When you need the locale your app is actually displaying content in.

Method 2: Get Device/Platform Locale

This returns the user's device language setting:

import 'package:flutter/widgets.dart';

// Get primary device locale
Locale deviceLocale = WidgetsBinding.instance.platformDispatcher.locale;

// Get all preferred locales (user's language preference list)
List<Locale> allLocales = WidgetsBinding.instance.platformDispatcher.locales;

When to use: When you want to know what language the user prefers, regardless of what your app supports.

Method 3: Get Locale Without Context

Sometimes you need the locale outside of a widget (in a service, repository, or utility function):

Option A: Global Navigator Key

// In your app setup
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();

MaterialApp(
  navigatorKey: navigatorKey,
  // ...
)

// Anywhere in your code
Locale? getLocaleWithoutContext() {
  final context = navigatorKey.currentContext;
  if (context != null) {
    return Localizations.localeOf(context);
  }
  return null;
}

Option B: Platform Dispatcher (No Context Needed)

import 'dart:ui' as ui;

Locale getDeviceLocale() {
  return ui.PlatformDispatcher.instance.locale;
}

List<Locale> getAllPreferredLocales() {
  return ui.PlatformDispatcher.instance.locales;
}

Option C: Locale Provider with GetIt

import 'package:get_it/get_it.dart';

class LocaleService {
  Locale _currentLocale = Locale('en');

  Locale get currentLocale => _currentLocale;

  void updateLocale(Locale locale) {
    _currentLocale = locale;
  }
}

// Register
GetIt.I.registerSingleton<LocaleService>(LocaleService());

// Use anywhere
Locale locale = GetIt.I<LocaleService>().currentLocale;

Detecting Locale Changes

Listen for locale changes when the user changes their device language:

class MyApp extends StatefulWidget {
  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeLocales(List<Locale>? locales) {
    // Called when device locale changes
    if (locales != null && locales.isNotEmpty) {
      print('Device locale changed to: ${locales.first}');
      // Handle locale change
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // ...
    );
  }
}

Locale Resolution: How Flutter Chooses

When your app starts, Flutter resolves which locale to use:

MaterialApp(
  supportedLocales: [
    Locale('en'),
    Locale('es'),
    Locale('fr'),
  ],
  localeResolutionCallback: (deviceLocale, supportedLocales) {
    // Custom resolution logic
    for (var locale in supportedLocales) {
      if (locale.languageCode == deviceLocale?.languageCode) {
        return locale;
      }
    }
    return supportedLocales.first; // Fallback
  },
)

Default Resolution Order

  1. Exact match (language + country): en_US matches en_US
  2. Language match: en_US matches en
  3. First supported locale (fallback)

Common Use Cases

Format Dates Based on Locale

import 'package:intl/intl.dart';

String formatDate(BuildContext context, DateTime date) {
  final locale = Localizations.localeOf(context).toString();
  return DateFormat.yMMMd(locale).format(date);
}

// Usage
formatDate(context, DateTime.now());
// en_US: "Dec 6, 2025"
// de_DE: "6. Dez. 2025"
// ja_JP: "2025年12月6日"

Format Currency Based on Locale

String formatCurrency(BuildContext context, double amount) {
  final locale = Localizations.localeOf(context).toString();
  final format = NumberFormat.currency(
    locale: locale,
    symbol: _getCurrencySymbol(locale),
  );
  return format.format(amount);
}
// en_US: "$1,234.56"
// de_DE: "1.234,56 €"
// ja_JP: "¥1,235"

Load Locale-Specific Assets

String getLocalizedAsset(BuildContext context, String assetName) {
  final locale = Localizations.localeOf(context);
  final localizedPath = 'assets/${locale.languageCode}/$assetName';
  final defaultPath = 'assets/en/$assetName';

  // Check if localized asset exists, otherwise use default
  return localizedPath; // Add proper asset checking
}

Store User's Preferred Locale

import 'package:shared_preferences/shared_preferences.dart';

class LocalePreferences {
  static const _key = 'user_locale';

  static Future<void> saveLocale(Locale locale) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setString(_key, locale.toString());
  }

  static Future<Locale?> getSavedLocale() async {
    final prefs = await SharedPreferences.getInstance();
    final localeString = prefs.getString(_key);
    if (localeString != null) {
      final parts = localeString.split('_');
      return Locale(parts[0], parts.length > 1 ? parts[1] : null);
    }
    return null;
  }
}

Complete Example: Locale-Aware App

import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

class LocaleAwareApp extends StatefulWidget {
  @override
  State<LocaleAwareApp> createState() => _LocaleAwareAppState();
}

class _LocaleAwareAppState extends State<LocaleAwareApp> {
  Locale? _locale;

  @override
  void initState() {
    super.initState();
    _loadSavedLocale();
  }

  Future<void> _loadSavedLocale() async {
    final savedLocale = await LocalePreferences.getSavedLocale();
    if (savedLocale != null) {
      setState(() => _locale = savedLocale);
    }
  }

  void _changeLocale(Locale newLocale) {
    setState(() => _locale = newLocale);
    LocalePreferences.saveLocale(newLocale);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      locale: _locale,
      localizationsDelegates: AppLocalizations.localizationsDelegates,
      supportedLocales: AppLocalizations.supportedLocales,
      home: HomePage(onLocaleChange: _changeLocale),
    );
  }
}

class HomePage extends StatelessWidget {
  final Function(Locale) onLocaleChange;

  const HomePage({required this.onLocaleChange});

  @override
  Widget build(BuildContext context) {
    final currentLocale = Localizations.localeOf(context);
    final l10n = AppLocalizations.of(context)!;

    return Scaffold(
      appBar: AppBar(title: Text(l10n.appTitle)),
      body: Column(
        children: [
          Text('Current locale: ${currentLocale.toString()}'),
          ElevatedButton(
            onPressed: () => onLocaleChange(Locale('en')),
            child: Text('English'),
          ),
          ElevatedButton(
            onPressed: () => onLocaleChange(Locale('es')),
            child: Text('Español'),
          ),
        ],
      ),
    );
  }
}

Troubleshooting

"Locale not found" Error

// Make sure locale is in supportedLocales
MaterialApp(
  supportedLocales: [
    Locale('en'),
    Locale('es'),
    // Add all locales you want to support
  ],
)

Locale Returns Null

// Use null-safe access
final locale = Localizations.localeOf(context);
// Instead of potentially nullable platform access

Locale Doesn't Update

// Ensure you're calling setState when changing locale
void changeLocale(Locale newLocale) {
  setState(() {
    _currentLocale = newLocale;
  });
}

FlutterLocalisation Makes Locale Management Easy

Managing locales across your app becomes complex fast. FlutterLocalisation helps you:

  • Visual locale management - See all supported locales at a glance
  • Missing translation detection - Know exactly what's missing per locale
  • AI translation - Add new languages instantly
  • Export ready ARB files - Perfectly formatted for Flutter

Stop wrestling with locale code. Try FlutterLocalisation free and manage all your locales from one dashboard.