Skip to content

Commit

Permalink
Adapt package:messages to be loading mechanism independent (#843)
Browse files Browse the repository at this point in the history
* Squashed commit

* Add newline

* Add g.dart files to generated

* Upgrade to dart:asset

* Add changelogs

* Add wip

* Run tests only on dev

* Add logger

* Update examples

* Do not use dart:asset

* Use a dart run script instead of hooks

* Also output code in dart run

* Adapt workflow

* Fixes

* Add licenses

* typo

* Fix issues

* Sort on key

* Refactor to list

* Sort

* Clean ups

* sort deps

* Changelog

* Remove build_runner remaisn

* Delete old examples

* Add new examples

* Fix flutter specific package loading

* Fix zero word case

* Switch to flutter in wf

* Fix CI

* Setup flutter

* use dart not flutter

* do not check flutter examples

* Changes as per review

* Update CI sha

* Use main channel

* use beta channel

* Use new CI tool

* Rename

* Add licenses

* Use dart run messages again
  • Loading branch information
mosuem authored Oct 31, 2024
1 parent c878218 commit 3820422
Show file tree
Hide file tree
Showing 95 changed files with 1,724 additions and 653 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pkgs/intl4x/lib/src/bindings/* linguist-generated=true
pkgs/intl4x/**/*.g.dart linguist-generated=true
30 changes: 18 additions & 12 deletions .github/workflows/messages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,28 +21,34 @@ jobs:
defaults:
run:
working-directory: pkgs/messages
strategy:
matrix:
sdk: [stable, dev] # {pkgs.versions}
dependencies: [path, published]
include:
- sdk: stable
run-tests: true

steps:
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
- uses: dart-lang/setup-dart@0a8a0fc875eb934c15d08629302413c671d3f672

- uses: flutter-actions/setup-flutter@61f93c6f11e0234fa9ec4df59362c9699b979660
with:
sdk: ${{matrix.sdk}}
channel: beta

- run: dart pub get

- run: dart pub get
working-directory: pkgs/messages/example

- run: (cd example_json; dart pub get)
- run: flutter pub get
working-directory: pkgs/messages/examples_flutter/my_application

- run: flutter pub get
working-directory: pkgs/messages/examples_flutter/my_shopping_cart

- run: dart analyze --fatal-infos

- run: dart format --output=none --set-exit-if-changed .
if: ${{matrix.run-tests}}

- run: dart test
if: ${{matrix.run-tests}}

- name: Regenerate and run example
working-directory: pkgs/messages/example
run: |
dart run messages
git diff --exit-code
dart run
4 changes: 2 additions & 2 deletions .github/workflows/messages_builder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ jobs:
working-directory: pkgs/messages_builder
strategy:
matrix:
sdk: [stable, dev] # {pkgs.versions}
sdk: [dev]
include:
- sdk: stable
- sdk: dev
run-tests: true
steps:
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/messages_serializer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ jobs:
working-directory: pkgs/messages_serializer
strategy:
matrix:
sdk: [stable, dev] # {pkgs.versions}
sdk: [dev]
include:
- sdk: stable
- sdk: dev
run-tests: true
steps:
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/messages_shrinker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ jobs:
working-directory: pkgs/messages_shrinker
strategy:
matrix:
sdk: [stable, dev] # {pkgs.versions}
sdk: [dev]
include:
- sdk: stable
- sdk: dev
run-tests: true
steps:
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9
Expand Down
4 changes: 4 additions & 0 deletions pkgs/messages/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.3.0-wip

- Adapt to output data files to assets.

## 0.2.0

- Remove `IntlObject` interface.
Expand Down
7 changes: 3 additions & 4 deletions pkgs/messages/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,9 @@ The `builder` to generate the named methods and data files from the input `arb`
The logic for serializing `arb` message files into data files.

## Example
Add `package:messages` and `package:messages_builder` to your dependencies:
Add `package:messages` to your dependencies:
```bash
dart pub add messages
dart pub add dev:messages_builder
```

Given translation message files in two languages:
Expand Down Expand Up @@ -68,7 +67,7 @@ This translated file was created by a translator given the reference `en.arb`.
```
you can then run

`dart run build_runner build -d`
`dart run messages`

This will generate both code to call your messages, as well as data files which will be shipped with your application. You can then use these generated files by importing the generated files:

Expand Down Expand Up @@ -105,4 +104,4 @@ package_options:
// multi
// line
// header
```
```
31 changes: 31 additions & 0 deletions pkgs/messages/bin/messages.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:io';

Future<void> main(List<String> args) async {
final runBuilder = await Process.run('dart', ['run', 'messages_builder']);
stdout.write(runBuilder.stdout as String);

final runBuilderStdErr = runBuilder.stderr as String;
final messagesBuilderNotInDeps =
runBuilderStdErr.contains('Could not find package `messages_builder`');
if (messagesBuilderNotInDeps) {
print('Adding `package:messages_builder` to dev dependencies...');
final addBuilder = await runDart(['pub', 'add', 'dev:messages_builder']);
if (addBuilder.exitCode == 0) {
print('Re-running message generation');
await runDart(['run', 'messages_builder']);
}
} else {
stderr.write(runBuilderStdErr);
}
}

Future<ProcessResult> runDart(List<String> arguments) async {
final processResult = await Process.run('dart', arguments);
stdout.write(processResult.stdout as String);
stderr.write(processResult.stderr as String);
return processResult;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@

# Conventional directory for build output.
build/
bin/example/
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,4 @@
}
},
"helloAndWelcome2": "Welcome {firstName} von {lastName}!"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
"helloAndWelcome2": "Willkommen {firstName} von {lastName} 2",
"newMessages": "testde {newMessages, plural, =0 {No new messages} =1 {One new message} two{Two new Messages} other {test {newMessages} new messages}}",
"newMessages2": "testdse is just a simple message"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,4 @@
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{
"@@context": "AboutPage",
"@@locale": "fr",
"helloAndWelcome": "Welcome {firstName} von {lastName} <",
"otherMsg": "other",
"aboutMessage": "Sur {websitename}",
"newMessages": "test {newMessages, plural, =0 {No new messages} =1 {One new message} two{Two new Messages} other {test {newMessages} new messages}}",
"newMessages2": "test {gender, select,male {No new messages} female {One new message} other{Two new Messages} other {test {gender} new messages of type {newVar}}}"
}
}
1 change: 1 addition & 0 deletions pkgs/messages/example/assets/testarb.arb.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[0,"en","dr9Md951",1,null,["helloAndWelcome","Welcome von !",[8,0],[13,1]],["helloAndWelcome2","Welcome von !",[8,0],[13,1]],[6,"newMessages","test ",[3,0,["test new messages",[5,0]],[0,"No new messages",1,"One new message","w2","Two new Messages"]]],[6,"newMessages2","test ",[4,0,"Two new Messages",{"male":"No new messages","female":"One new message"}]]]
1 change: 1 addition & 0 deletions pkgs/messages/example/assets/testarb_de.arb.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[0,"de","hbDN1MhX",1,null,["helloAndWelcome","Willkommen von ",[11,0],[16,1]],["helloAndWelcome2","Willkommen von 2",[11,0],[16,1]],[6,"newMessages","testde ",[3,0,["test new messages",[5,0]],[0,"No new messages",1,"One new message","w2","Two new Messages"]]],["newMessages2","testdse is just a simple message"]]
1 change: 1 addition & 0 deletions pkgs/messages/example/assets/testarbctx2.arb.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[0,"en","QrwRSsOy",1,null,["aboutMessage","About ",[6,0]],["helloAndWelcome","Welcome von <",[8,0],[13,1]],[6,"newMessages","test ",[3,0,["test new messages",[5,0]],[0,"No new messages",1,"One new message","w2","Two new Messages"]]],[6,"newMessages2","test ",[4,0,"Two new Messages",{"male":"No new messages","female":"One new message"}]],["otherMsg","other"]]
1 change: 1 addition & 0 deletions pkgs/messages/example/assets/testarbctx2_fr.arb.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[0,"fr","390XWry3",1,null,["aboutMessage","Sur ",[4,0]],["helloAndWelcome","Welcome von <",[8,0],[13,1]],[6,"newMessages","test ",[3,0,["test new messages",[5,0]],[0,"No new messages",1,"One new message","w2","Two new Messages"]]],[6,"newMessages2","test ",[4,0,"Two new Messages",{"male":"No new messages","female":"One new message"}]],["otherMsg","other"]]
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@

import 'dart:io';

import 'package:example_json/testarbctx2.g.dart';
import 'package:example/messages.g.dart';

Future<void> main(List<String> arguments) async {
final messages =
AboutPageMessages((String id) async => File(id).readAsString());
final messages = AboutPageMessages(
(id) => File(id.split('/').skip(2).join('/')).readAsString(),
);
// final index = AboutPageMessagesEnum.aboutMessage;

await messages.loadLocale('en');
Expand Down
172 changes: 172 additions & 0 deletions pkgs/messages/example/lib/messages.g.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
// Generated by package:messages_builder.

// ignore_for_file: non_constant_identifier_names

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,
);
}

class AboutPageMessages {
AboutPageMessages(this._assetLoader);

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

String _currentLocale = 'en';

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

static const _dataFiles = {
'en': ('packages/example/assets/testarbctx2.arb.json', 'QrwRSsOy'),
'fr': ('packages/example/assets/testarbctx2_fr.arb.json', '390XWry3')
};

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 aboutMessage(String websitename) =>
_currentMessages.generateStringAtIndex(0, [websitename]);

String helloAndWelcome(
String firstName,
int 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]);

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]);
}
Loading

0 comments on commit 3820422

Please sign in to comment.