localizely / intl_utils

Dart package that creates a binding between your translations from .arb files and your Flutter app
BSD 3-Clause "New" or "Revised" License
135 stars 81 forks source link

L10n.load should return synchronous future, otherwise black frame is shown #90

Closed orestesgaolin closed 2 years ago

orestesgaolin commented 2 years ago

Currently the implementation of load() function returns Future

  static Future<L10n> load(Locale locale) {
    final name = (locale.countryCode?.isEmpty ?? false)
        ? locale.languageCode
        : locale.toString();
    final localeName = Intl.canonicalizedLocale(name);
    return initializeMessages(localeName).then((_) {
      Intl.defaultLocale = localeName;
      final instance = L10n();
      L10n._current = instance;

      return instance;
    });
  }

However, this causes a black frame to appear just before the MaterialApp renders (e.g. like here, but I see this also in our app when we rebuild MaterialApp).

This is frame by frame view of our app when the MaterialApp is rebuilt:

https://user-images.githubusercontent.com/16854239/194139457-af5ac13a-9e1e-43d7-b355-734594da37dd.mp4

It should by default return SynchronousFuture (see example here). I succeeded with something like this:

  static Future<L10n> load(Locale locale) {
    final name = (locale.countryCode?.isEmpty ?? false)
        ? locale.languageCode
        : locale.toString();
    final localeName = Intl.canonicalizedLocale(name);
    initializeMessages(localeName).then((_) {
      Intl.defaultLocale = localeName;
      final instance = L10n();
      L10n._current = instance;

      return instance;
    });

    return SynchronousFuture<L10n>(L10n());
  }

Would you need a reproducible example?

orestesgaolin commented 2 years ago

I found a temporary workaround by implementing custom localization delegate:

class CustomLocalizationDelegate extends AppLocalizationDelegate {
  const CustomLocalizationDelegate();

  static const delegate = CustomLocalizationDelegate();

  @override
  Future<L10n> load(Locale locale) {
    L10n.load(locale);
    // https://github.com/localizely/intl_utils/issues/90
    return SynchronousFuture<L10n>(L10n());
  }
}

And then:

  localizationsDelegates: const [
    CustomLocalizationDelegate.delegate,
    GlobalMaterialLocalizations.delegate,
    GlobalWidgetsLocalizations.delegate,
    GlobalCupertinoLocalizations.delegate,
  ],
lzoran commented 2 years ago

Hi @orestesgaolin,

Thanks for reporting this!

This should be fixed now with the intl_utils 2.8.1. Note that the intl_utils allows deferred loading of localization files (the use_deferred_loading config option), so the released fix should only work if deferred loading is disabled.

Related issues: flutter#87926, flutter#93865, flutter-intl-vscode#76

I'm closing this issue as resolved. In case you notice any irregularity, feel free to reopen it.

orestesgaolin commented 2 years ago

Thanks a lot! Should the delegate get regenerated after this fix? I updated the extension and arb files, but my L10n delegate is still unchanged.

orestesgaolin commented 2 years ago

All right, I think I know what's the issue now:

My dependencies, using Flutter 3.3.8:

dev_dependencies:
  bloc_test: ^9.0.3
  flutter_test:
    sdk: flutter
  very_good_analysis: ^3.0.1
  intl_utils: ^2.8.1

And the pub get output:

Running "flutter pub get" in my-app...                     
Because test >=1.16.0-nullsafety.19 <1.16.6 depends on test_api 0.2.19 and test >=1.16.6 <1.17.10 depends on analyzer ^1.0.0, test >=1.16.0-nullsafety.19 <1.17.10 requires test_api 0.2.19 or analyzer ^1.0.0.
And because test >=1.17.10 <1.20.0 depends on analyzer >=1.0.0 <3.0.0 and test >=1.20.0 <1.21.2 depends on test_api 0.4.9, test >=1.16.0-nullsafety.19 <1.21.2 requires test_api 0.2.19 or 0.4.9 or analyzer >=1.0.0 <3.0.0.
And because test >=1.21.0 <1.21.6 depends on analyzer >=2.0.0 <5.0.0 and test >=1.21.6 <1.21.7 depends on test_api 0.4.14, test >=1.16.0-nullsafety.19 <1.21.7 requires test_api 0.2.19 or 0.4.9 or 0.4.14 or analyzer >=1.0.0 <5.0.0.
And because test >=1.21.7 <1.22.0 depends on test_api 0.4.15 and test >=1.22.0 depends on test_api 0.4.16, test >=1.16.0-nullsafety.19 requires test_api 0.2.19 or 0.4.9 or 0.4.14 or 0.4.15 or 0.4.16 or analyzer >=1.0.0 <5.0.0.
And because intl_utils >=2.8.0 depends on analyzer ^5.0.0 and every version of flutter_test from sdk depends on test_api 0.4.12, one of intl_utils >=2.8.0 or test >=1.16.0-nullsafety.19 or flutter_test from sdk must be false.
And because my_app depends on bloc_test ^9.0.3 which depends on test ^1.16.0, intl_utils >=2.8.0 is incompatible with flutter_test from sdk.
So, because my_app depends on both flutter_test from sdk and intl_utils ^2.8.1, version solving failed.
pub get failed (1; So, because my_app depends on both flutter_test from sdk and intl_utils ^2.8.1, version solving failed.)
exit code 1

Fixed that by:

dependency_overrides:
  analyzer: ^5.2.0
lzoran commented 2 years ago

I updated the extension and arb files, but my L10n delegate is still unchanged.

Only the messages_all.dart file should be updated.

Because test >=1.16.0-nullsafety.19 <1.16.6 depends on test_api 0.2.19 and test >=1.16.6 <1.17.10 depends on analyzer ^1.0.0, test >=1.16.0-nullsafety....

Regarding the problem with dependencies, the intl_utils 2.8.1 now depends on the analyzer: ^5.0.0. Great if dependency override fixed it.