Skip to content

Commit

Permalink
Add list format from ICU4X (#810)
Browse files Browse the repository at this point in the history
* Add list formatting from ICU4X

* Rename

* Remove failing tests

* Fix build.dart

* Fix comment
  • Loading branch information
mosuem authored Mar 8, 2024
1 parent 9918522 commit 7710126
Show file tree
Hide file tree
Showing 10 changed files with 75 additions and 50 deletions.
1 change: 1 addition & 0 deletions pkgs/intl4x/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- Add resource identifier annotations.
- Add ICU4X support for plural rules.
- Add ICU4X support for display names.
- Add ICU4X support for list formatting.

## 0.8.1

Expand Down
2 changes: 1 addition & 1 deletion pkgs/intl4x/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ via our [issue tracker](https://github.com/dart-lang/i18n/issues)).
| | Number format | List format | Date format | Collation | Display names | Plural Rules |
|---|:---:|:---:|:---:|:---:|:---:|:---:|
| **ECMA402 (web)** | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
| **ICU4X (web/native)** | :heavy_check_mark: | | | :heavy_check_mark: | :heavy_check_mark: | |
| **ICU4X (web/native)** | :heavy_check_mark: | :heavy_check_mark: | | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |

## Implementation and Goals

Expand Down
2 changes: 1 addition & 1 deletion pkgs/intl4x/build.dart
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ final class CheckoutMode implements BuildMode {

@override
List<Uri> get dependencies => Directory(workingDirectory!)
.listSync()
.listSync(recursive: true)
.whereType<File>()
.map((e) => Uri.file(e.path))
.toList();
Expand Down
45 changes: 43 additions & 2 deletions pkgs/intl4x/lib/src/list_format/list_format_4x.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
// 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 '../bindings/lib.g.dart' as icu;
import '../data.dart';
import '../data_4x.dart';
import '../locale/locale.dart';
import '../locale/locale_4x.dart';
import 'list_format_impl.dart';
import 'list_format_options.dart';

Expand All @@ -12,10 +15,48 @@ ListFormatImpl getListFormatter4X(
ListFormat4X(locale, data, options);

class ListFormat4X extends ListFormatImpl {
ListFormat4X(super.locale, Data data, super.options);
final icu.ListFormatter _formatter;
ListFormat4X(super.locale, Data data, super.options)
: _formatter = _getFormatter(locale, data, options);

@override
String formatImpl(List<String> list) {
throw UnimplementedError('Insert diplomat bindings here');
return _formatter.format(list.to4X());
}

static icu.ListFormatter _getFormatter(
Locale locale,
Data data,
ListFormatOptions options,
) {
final constructor = switch (options.type) {
Type.and => icu.ListFormatter.andWithLength,
Type.or => icu.ListFormatter.orWithLength,
Type.unit => icu.ListFormatter.unitWithLength,
};
return constructor(
data.to4X(),
locale.to4X(),
options.style.to4X(),
);
}
}

extension on ListStyle {
icu.ListLength to4X() => switch (this) {
ListStyle.narrow => icu.ListLength.narrow,
ListStyle.short => icu.ListLength.short,
ListStyle.long => icu.ListLength.wide,
};
}

//TODO: Remove after https://github.com/rust-diplomat/diplomat/issues/378
extension on List<String> {
icu.List to4X() {
final list = icu.List.withCapacity(length);
for (final element in this) {
list.push(element);
}
return list;
}
}
2 changes: 1 addition & 1 deletion pkgs/intl4x/lib/src/list_format/list_format_ecma.dart
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ extension on ListFormatOptions {
Object toJsOptions() {
final o = newObject<Object>();
setProperty(o, 'localeMatcher', localeMatcher.jsName);
setProperty(o, 'type', type.name);
setProperty(o, 'type', type.jsName);
setProperty(o, 'style', style.name);
return o;
}
Expand Down
2 changes: 1 addition & 1 deletion pkgs/intl4x/lib/src/list_format/list_format_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import '../ecma/ecma_policy.dart';
import '../locale/locale.dart';
import '../options.dart';
import '../utils.dart';
import 'list_format_4x.dart';
import 'list_format_options.dart';
import 'list_format_stub.dart' if (dart.library.js) 'list_format_ecma.dart';
import 'list_format_stub_4x.dart' if (dart.library.io) 'list_format_4x.dart';

abstract class ListFormatImpl {
final Locale locale;
Expand Down
12 changes: 9 additions & 3 deletions pkgs/intl4x/lib/src/list_format/list_format_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class ListFormatOptions {
final LocaleMatcher localeMatcher;

const ListFormatOptions({
this.type = Type.conjunction,
this.type = Type.and,
this.style = ListStyle.long,
this.localeMatcher = LocaleMatcher.bestfit,
});
Expand All @@ -39,11 +39,17 @@ class ListFormatOptions {
/// Indicates the type of grouping.
enum Type {
/// For "and"-based grouping of the list items: "A, B, and C".
conjunction,
and('conjunction'),

/// For "or"-based grouping of the list items: "A, B, or C".
disjunction,
or('disjunction'),

/// Grouping the list items as a unit: "A, B, C".
unit;

String get jsName => _jsName ?? name;

final String? _jsName;

const Type([this._jsName]);
}
12 changes: 12 additions & 0 deletions pkgs/intl4x/lib/src/list_format/list_format_stub_4x.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright (c) 2023, 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 '../../list_format.dart';
import '../data.dart';
import '../locale/locale.dart';
import 'list_format_impl.dart';

ListFormatImpl getListFormatter4X(
Locale locale, Data data, ListFormatOptions options) =>
throw UnimplementedError('Cannot use ICU4X in web environments.');
29 changes: 0 additions & 29 deletions pkgs/intl4x/test/icu4x/list_format_test.dart

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,11 @@
// 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.

@TestOn('browser')
library;

import 'package:intl4x/ecma_policy.dart';
import 'package:intl4x/intl4x.dart';
import 'package:intl4x/src/list_format/list_format_options.dart';
import 'package:test/test.dart';

import '../utils.dart';
import 'utils.dart';

void main() {
group('List style options', () {
Expand Down Expand Up @@ -38,12 +34,12 @@ void main() {
final intl = Intl(locale: const Locale(language: 'en', region: 'US'));
testWithFormatting('long', () {
final listFormat =
intl.listFormat(const ListFormatOptions(type: Type.conjunction));
intl.listFormat(const ListFormatOptions(type: Type.and));
expect(listFormat.format(list), 'A, B, and C');
});
testWithFormatting('short', () {
final listFormat =
intl.listFormat(const ListFormatOptions(type: Type.disjunction));
intl.listFormat(const ListFormatOptions(type: Type.or));
expect(listFormat.format(list), 'A, B, or C');
});
testWithFormatting('narrow', () {
Expand All @@ -55,12 +51,10 @@ void main() {

group('List style and type combinations', () {
final list = ['A', 'B', 'C'];
final intl = Intl(
ecmaPolicy: const AlwaysEcma(),
locale: const Locale(language: 'en', region: 'US'));
final intl = Intl(locale: const Locale(language: 'en', region: 'US'));
testWithFormatting('long', () {
final formatter = intl.listFormat(const ListFormatOptions(
style: ListStyle.narrow, type: Type.conjunction));
final formatter = intl.listFormat(
const ListFormatOptions(style: ListStyle.narrow, type: Type.and));
expect(formatter.format(list), 'A, B, C');
});
testWithFormatting('short', () {
Expand Down

0 comments on commit 7710126

Please sign in to comment.