Skip to content

Commit

Permalink
Deferred loading messages (#904)
Browse files Browse the repository at this point in the history
* Refactorings

* Add android app with deferred loading

* Add german again

* all

* Fix analysis

* Fix deferred loading

* sort imports

* Nicer linebreaks

* Add license

* Fixes as per review

* Extact to class

* Rename

* Fix bugs

* Adapt workflow
  • Loading branch information
mosuem authored Nov 13, 2024
1 parent f3575ec commit dff57eb
Show file tree
Hide file tree
Showing 64 changed files with 956 additions and 434 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/messages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,6 @@ jobs:
- name: Regenerate and run example
working-directory: pkgs/messages/example
run: |
dart run messages
git diff --exit-code
dart run
dart run messages || exit 1
git diff --exit-code || exit 1
dart run || exit 1
2 changes: 1 addition & 1 deletion pkgs/messages/example/bin/example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import 'dart:io';

import 'package:example/messages.g.dart';
import 'package:example/AboutPage_messages.g.dart';

Future<void> main(List<String> arguments) async {
final messages = AboutPageMessages(
Expand Down
2 changes: 2 additions & 0 deletions pkgs/messages/example/lib/AboutPage_en_empty.g.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// This is a helper file for deferred loading of the messages for locale en,
// generated by `dart run messages`.
2 changes: 2 additions & 0 deletions pkgs/messages/example/lib/AboutPage_fr_empty.g.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// This is a helper file for deferred loading of the messages for locale fr,
// generated by `dart run messages`.
Original file line number Diff line number Diff line change
@@ -1,30 +1,13 @@
// Generated by package:messages_builder.

// ignore_for_file: non_constant_identifier_names
// ignore_for_file: library_prefixes, non_constant_identifier_names
// ignore_for_file: unused_import

import 'package:intl/intl.dart';
import 'package:messages/messages_json.dart';

Message _pluralSelector(
num howMany,
String locale, {
required Message other,
Message? few,
Message? many,
Map<int, Message>? numberCases,
Map<int, Message>? wordCases,
}) {
return Intl.pluralLogic(
howMany,
few: few,
many: many,
zero: numberCases?[0] ?? wordCases?[0],
one: numberCases?[1] ?? wordCases?[1],
two: numberCases?[2] ?? wordCases?[2],
other: other,
locale: locale,
);
}
import 'AboutPage_en_empty.g.dart' deferred as AboutPage_en_empty;
import 'AboutPage_fr_empty.g.dart' deferred as AboutPage_fr_empty;

class AboutPageMessages {
AboutPageMessages(this._assetLoader);
Expand Down Expand Up @@ -60,6 +43,12 @@ class AboutPageMessages {
if (dataFile == null) {
throw ArgumentError('Locale $locale is not in $knownLocales');
}
if (locale == 'en') {
await AboutPage_en_empty.loadLibrary();
} else if (locale == 'fr') {
await AboutPage_fr_empty.loadLibrary();
}

final data = await _assetLoader(dataFile);
final messageList = MessageListJson.fromString(data, _pluralSelector);
if (messageList.preamble.hash != info?.$2) {
Expand Down Expand Up @@ -98,75 +87,23 @@ class AboutPageMessages {
String get otherMsg => _currentMessages.generateStringAtIndex(4, []);
}

class HomePageMessages {
HomePageMessages(this._assetLoader);

final Future<String> Function(String id) _assetLoader;

String _currentLocale = 'en';

final Map<String, MessageList> _messages = {};

static const _dataFiles = {
'de': ('packages/example/assets/testarb_de.arb.json', 'hbDN1MhX'),
'en': ('packages/example/assets/testarb.arb.json', 'dr9Md951')
};

String get currentLocale => _currentLocale;

MessageList get _currentMessages => _messages[currentLocale]!;

String getById(
String id, [
List<dynamic> args = const [],
]) {
return _currentMessages.generateStringAtId(id, args);
}

static Iterable<String> get knownLocales => _dataFiles.keys;

Future<void> loadLocale(String locale) async {
if (!_messages.containsKey(locale)) {
final info = _dataFiles[locale];
final dataFile = info?.$1;
if (dataFile == null) {
throw ArgumentError('Locale $locale is not in $knownLocales');
}
final data = await _assetLoader(dataFile);
final messageList = MessageListJson.fromString(data, _pluralSelector);
if (messageList.preamble.hash != info?.$2) {
throw ArgumentError('''
Messages file for locale $locale has different hash "${messageList.preamble.hash}" than generated code "${info?.$2}".''');
}
_messages[locale] = messageList;
}
_currentLocale = locale;
}

Future<void> loadAllLocales() async {
for (final locale in knownLocales) {
await loadLocale(locale);
}
}

String helloAndWelcome(
String firstName,
String lastName,
) =>
_currentMessages.generateStringAtIndex(0, [firstName, lastName]);

String helloAndWelcome2(
String firstName,
String lastName,
) =>
_currentMessages.generateStringAtIndex(1, [firstName, lastName]);

String newMessages(int newMessages) =>
_currentMessages.generateStringAtIndex(2, [newMessages]);

String newMessages2(
String gender,
int newVar,
) =>
_currentMessages.generateStringAtIndex(3, [gender, newVar]);
Message _pluralSelector(
num howMany,
String locale, {
required Message other,
Message? few,
Message? many,
Map<int, Message>? numberCases,
Map<int, Message>? wordCases,
}) {
return Intl.pluralLogic(
howMany,
few: few,
many: many,
zero: numberCases?[0] ?? wordCases?[0],
one: numberCases?[1] ?? wordCases?[1],
two: numberCases?[2] ?? wordCases?[2],
other: other,
locale: locale,
);
}
2 changes: 2 additions & 0 deletions pkgs/messages/example/lib/HomePage_de_empty.g.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// This is a helper file for deferred loading of the messages for locale de,
// generated by `dart run messages`.
2 changes: 2 additions & 0 deletions pkgs/messages/example/lib/HomePage_en_empty.g.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// This is a helper file for deferred loading of the messages for locale en,
// generated by `dart run messages`.
110 changes: 110 additions & 0 deletions pkgs/messages/example/lib/HomePage_messages.g.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Generated by package:messages_builder.

// ignore_for_file: library_prefixes, non_constant_identifier_names
// ignore_for_file: unused_import

import 'package:intl/intl.dart';
import 'package:messages/messages_json.dart';

import 'HomePage_de_empty.g.dart' deferred as HomePage_de_empty;
import 'HomePage_en_empty.g.dart' deferred as HomePage_en_empty;

class HomePageMessages {
HomePageMessages(this._assetLoader);

final Future<String> Function(String id) _assetLoader;

String _currentLocale = 'en';

final Map<String, MessageList> _messages = {};

static const _dataFiles = {
'de': ('packages/example/assets/testarb_de.arb.json', 'hbDN1MhX'),
'en': ('packages/example/assets/testarb.arb.json', 'dr9Md951')
};

String get currentLocale => _currentLocale;

MessageList get _currentMessages => _messages[currentLocale]!;

String getById(
String id, [
List<dynamic> args = const [],
]) {
return _currentMessages.generateStringAtId(id, args);
}

static Iterable<String> get knownLocales => _dataFiles.keys;

Future<void> loadLocale(String locale) async {
if (!_messages.containsKey(locale)) {
final info = _dataFiles[locale];
final dataFile = info?.$1;
if (dataFile == null) {
throw ArgumentError('Locale $locale is not in $knownLocales');
}
if (locale == 'de') {
await HomePage_de_empty.loadLibrary();
} else if (locale == 'en') {
await HomePage_en_empty.loadLibrary();
}

final data = await _assetLoader(dataFile);
final messageList = MessageListJson.fromString(data, _pluralSelector);
if (messageList.preamble.hash != info?.$2) {
throw ArgumentError('''
Messages file for locale $locale has different hash "${messageList.preamble.hash}" than generated code "${info?.$2}".''');
}
_messages[locale] = messageList;
}
_currentLocale = locale;
}

Future<void> loadAllLocales() async {
for (final locale in knownLocales) {
await loadLocale(locale);
}
}

String helloAndWelcome(
String firstName,
String lastName,
) =>
_currentMessages.generateStringAtIndex(0, [firstName, lastName]);

String helloAndWelcome2(
String firstName,
String lastName,
) =>
_currentMessages.generateStringAtIndex(1, [firstName, lastName]);

String newMessages(int newMessages) =>
_currentMessages.generateStringAtIndex(2, [newMessages]);

String newMessages2(
String gender,
int newVar,
) =>
_currentMessages.generateStringAtIndex(3, [gender, newVar]);
}

Message _pluralSelector(
num howMany,
String locale, {
required Message other,
Message? few,
Message? many,
Map<int, Message>? numberCases,
Map<int, Message>? wordCases,
}) {
return Intl.pluralLogic(
howMany,
few: few,
many: many,
zero: numberCases?[0] ?? wordCases?[0],
one: numberCases?[1] ?? wordCases?[1],
two: numberCases?[2] ?? wordCases?[2],
other: other,
locale: locale,
);
}
2 changes: 1 addition & 1 deletion pkgs/messages/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ package_options:
plural_selector: intl
arb_input_folder: assets/l10n/
message_output_folder: assets/
generated_code_file: lib/messages.g.dart
generated_code_files: lib/
13 changes: 13 additions & 0 deletions pkgs/messages/examples_flutter/my_application/android/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java

# Remember to never publicly share your keystore.
# See https://flutter.dev/to/reference-keystore
key.properties
**/*.keystore
**/*.jks
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
plugins {
id "com.android.application"
id "kotlin-android"
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id "dev.flutter.flutter-gradle-plugin"
}

android {
namespace = "com.example.my_application"
compileSdk = 34
ndkVersion = flutter.ndkVersion

compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8
}

defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "com.example.my_application"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = 33
targetSdk = 34
versionCode = flutter.versionCode
versionName = flutter.versionName
}

buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.debug
}
}
}

flutter {
source = "../.."
}

dependencies {
implementation "com.google.android.play:core:1.10.3"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
Loading

0 comments on commit dff57eb

Please sign in to comment.