drogel
drogel

Reputation: 2717

Black screen on app launch when using i18n from JSON files

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

Answers (2)

Ovidiu
Ovidiu

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

Pompidou
Pompidou

Reputation: 607

checkout easy_localization package , its simpler than the most out there

Upvotes: 0

Related Questions