Better Programming

Advice for programmers.

Follow publication

Resolving AppLocalizations Without Any BuildContext Around

Setting up Android notification channels before invoking runApp

Christian Schmitz
Better Programming
Published in
3 min readMar 29, 2022
Photo by Sigmund on Unsplash

When you read documentation about flutter_localizations you’ll notice, that it’s fairly easy to use the localizations with AppLocalizations.of(context). As this is used when creating widgets within a build tree, you might wonder why this could be an issue, but when you follow the example for setting up the firebase messaging SDK, especially creating the notification channels for Android, you’ll ask yourself:

Where do I get the context from?

Eventually runApp() hasn’t been called yet.

void main() {
final l10n = AppLocalizations.of(???);
setupFirebaseMessaging(l10n);
runApp(App());
}

Looking into the AppLocalizations delegate

We’ll have to get the AppLocalizations instance differently then. Let’s have a look at how these are created; we don’t even have to look far from what we already know of the Flutter localization itself. The AppLocalizations.delegate defines a simple function load(locale), which creates locale dependent instances of AppLocalizations (or throws a FlutterError if the provided locale isn’t supported).

void main() async {
final locale = ???;
final l10n = await AppLocalizations.delegate.load(locale);
...
}

Now we only need to find the best locale to use for the localizations.

Resolving the supported user locale

To resolve the user locale from the list of all supported locales, we have to find a best fit for one of the preferred system defined user locales. This is implemented with the WidgetsApp and usually used by the Flutter localization implementation directly:

When a localeListResolutionCallback is provided, Flutter will first attempt to resolve the locale with the provided localeListResolutionCallback. If the callback or result is null, it will fallback to trying the localeResolutionCallback. If both localeResolutionCallback and localeListResolutionCallback are left null or fail to resolve (return null), basic fallback algorithm will be used. [Flutter]

In most cases it should be sufficient to just use the basic fallback algorithm implemented with the basicLocaleListResolution() function. When you need an algorithm to implement a complete locale resolution as defined with Unicode TR35, you’ll have to provide and use a custom implementation with the localeListResolutionCallback function.

Putting everything together

Photo by Emily Morter on Unsplash

So now that we know how to create the AppLocalizations instance and how to resolve the supported user locale for it, let’s have a look how it all works together in the end. We’ll just declare it as a global property l10n here:

Future<AppLocalizations> get l10n {
final widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
final preferred = widgetsBinding.window.locales;
const supported = AppLocalizations.supportedLocales;
final locale = basicLocaleListResolution(preferred, supported);
return AppLocalizations.delegate.load(locale);
}

Just consider that this implementation is not stateful and should not be used from within a repository or any other abstraction. Consider using a global key or another resolvable value instead.

Eventually, you wouldn’t want to have a string defined in a wrong locale, whenever users decide to change the locale of their device (even if it’s only one in a million).

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Responses (1)

Write a response