Reputation: 2717
I am attempting to build my own implementation of a system for localizing strings for internationalization in Flutter apps, using Flutter's LocalizationsDelegate
, and loading the localized strings from JSON files (one json file for each locale).
Everything works fine, but when the app is launched, there's a lapse of some milliseconds in which the screen goes black. The reason for this is that, since I am loading the JSON files using json.decode
, the way I am retrieving the localized strings is asynchronous. The app loads its MaterialApp
widget and then starts parsing the JSONs for localization. That is when the app goes black until it parses the JSON successfully.
Here is my implementation of my i18n system:
class Localization extends LocaleCodeAware with LocalizationsProvider {
Localization(this.locale) : super(locale.toString());
final Locale locale;
static Localization of(BuildContext context) =>
Localizations.of<Localization>(context, Localization);
}
class AppLocalizationsDelegate extends LocalizationsDelegate<Localization> {
const AppLocalizationsDelegate();
@override
bool isSupported(Locale locale) => ['en', 'es'].contains(locale.languageCode);
@override
Future<Localization> load(Locale locale) async {
final localization = Localization(locale);
await localization.load();
return localization;
}
@override
bool shouldReload(AppLocalizationsDelegate old) => false;
}
import 'dart:convert';
import 'package:flutter/services.dart';
import 'package:example/resources/asset_paths.dart' as paths;
abstract class LocaleCodeAware {
LocaleCodeAware(this.localeCode);
final String localeCode;
}
mixin LocalizationsProvider on LocaleCodeAware {
static Map<String, String> _values;
Future<void> load() async {
final string = await rootBundle.loadString('${paths.i18n}$localeCode.json');
final Map<String, dynamic> jsonMap = json.decode(string);
_values = jsonMap.map((key, value) => MapEntry(key, value.toString()));
}
String get appTitle => _values['appTitle'];
}
Here is my main.dart
file, with its MaterialApp
widget.
import 'package:flutter/material.dart';
void main() => runApp(ExampleApp());
class ExampleApp extends StatelessWidget {
@override
Widget build(BuildContext context) => MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(primarySwatch: Colors.blue),
localizationsDelegates: [
const AppLocalizationsDelegate(),
],
supportedLocales: const [Locale("en"), Locale("es")],
home: const AppNavigator(),
);
}
If instead of having the localized strings in JSON files, I assign a Map<String, String>
to my _values
map, and I load the strings directly from there, the black screen issue is gone, because the values are hardcoded and can be loaded synchronously.
So my question is, how can I have my app wait in splash screen until the localized strings are loaded from the JSON files?
Upvotes: 0
Views: 890
Reputation: 8712
Do you have any errors in your logs? The black screen could only be caused by 1. The current route not building a visible page or 2. The build()
function of the current route throwing exceptions.
As for loading the localizations while on the splash screen, you can do that within your main()
function:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
List<Locale> locales = WidgetsBinding.instance.window.locales;
// ... logic to decide which locale to use and load localizations for
final string = await rootBundle.loadString('${paths.i18n}$localeCode.json');
final Map<String, dynamic> jsonMap = json.decode(string);
runApp(ExampleApp(jsonMap));
}
This way, you can read the JSON file and convert it to a Map
while on the splash screen, and then pass it to ExampleApp
, which can in turn pass it to AppLocalizationsDelegate
, which can store it as a local variable and use it within load()
.
Upvotes: 4
Reputation: 607
checkout easy_localization package , its simpler than the most out there
Upvotes: 0