简体   繁体   English

使用 JSON 文件中的 i18n 时,应用程序启动时出现黑屏

[英]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).我正在尝试构建我自己的系统实现,用于在 Flutter 应用程序中本地化字符串以进行国际化,使用 Flutter 的LocalizationsDelegate ,并从 JSON 文件(每个语言环境一个 json 文件)加载本地化的字符串。

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.这样做的原因是,由于我使用json.decode加载 JSON 文件,因此我检索本地化字符串的方式是异步的。 The app loads its MaterialApp widget and then starts parsing the JSONs for localization.该应用程序加载其MaterialApp小部件,然后开始解析 JSON 以进行本地化。 That is when the app goes black until it parses the JSON successfully.那是应用程序在成功解析 JSON 之前变黑的时候。

Here is my implementation of my i18n system:这是我的 i18n 系统的实现:

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.这是我的main.dart文件,带有它的MaterialApp小部件。

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.如果我没有在 JSON 文件中使用本地化字符串,而是将Map<String, String>分配给我的_values映射,然后直接从那里加载字符串,那么黑屏问题就消失了,因为这些值是硬编码的并且可以加载同步。

So my question is, how can I have my app wait in splash screen until the localized strings are loaded from the JSON files?所以我的问题是,如何让我的应用程序在启动画面中等待,直到从 JSON 文件加载本地化字符串?

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.黑屏只能由1.当前路由未构建可见页面或2.当前路由的build()函数抛出异常引起。

As for loading the localizations while on the splash screen, you can do that within your main() function:至于在启动屏幕上加载本地化,您可以在main()函数中执行此操作:

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() .这样,您可以在启动画面上读取 JSON 文件并将其转换为Map ,然后将其传递给ExampleApp ,后者又可以将其传递给AppLocalizationsDelegate ,后者可以将其存储为局部变量并在load()使用它load() .

结帐easy_localization包,它比最简单的有

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM