Skip to content

Commit 17757fc

Browse files
authored
Add DateTime formatting for ICU4X (#788)
* Add `DateTime` formatting for ICU4X * Adapt to testing * Adapting tests * Add skips to test * Fix `islamic` calendar match * Update ICU4X * Address comments * Refactor * Refactor the other method too * Add checks to readme * Prepare for publish * Topics to list * Update SDK dep * Fix pana issues * Update example
1 parent 7710126 commit 17757fc

10 files changed

+346
-175
lines changed

pkgs/intl4x/CHANGELOG.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
## 0.8.2-wip
1+
## 0.8.2
22

33
- Add ICU4X support for number formatting.
44
- Add resource identifier annotations.
55
- Add ICU4X support for plural rules.
66
- Add ICU4X support for display names.
77
- Add ICU4X support for list formatting.
8+
- Add ICU4X support for datetime formatting.
89

910
## 0.8.1
1011

pkgs/intl4x/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ via our [issue tracker](https://github.com/dart-lang/i18n/issues)).
1818
| | Number format | List format | Date format | Collation | Display names | Plural Rules |
1919
|---|:---:|:---:|:---:|:---:|:---:|:---:|
2020
| **ECMA402 (web)** | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
21-
| **ICU4X (web/native)** | :heavy_check_mark: | :heavy_check_mark: | | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
21+
| **ICU4X (web/native)** | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
2222

2323
## Implementation and Goals
2424

pkgs/intl4x/example/pubspec.yaml

+1-3
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,8 @@ environment:
99
dependencies:
1010
intl4x:
1111
path: ../
12-
js: ^0.6.7
12+
js: ^0.7.1
1313

1414
dev_dependencies:
15-
build_runner: ^2.4.0
16-
build_web_compilers: ^3.0.0
1715
dart_flutter_team_lints: ^1.0.0
1816
lints: ^2.0.0

pkgs/intl4x/lib/src/datetime_format/datetime_format_4x.dart

+139-3
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import '../../datetime_format.dart';
6+
import '../bindings/lib.g.dart' as icu;
57
import '../data.dart';
8+
import '../data_4x.dart';
69
import '../locale/locale.dart';
10+
import '../locale/locale_4x.dart';
711
import 'datetime_format_impl.dart';
8-
import 'datetime_format_options.dart';
912

1013
DateTimeFormatImpl getDateTimeFormatter4X(
1114
Locale locale,
@@ -15,10 +18,143 @@ DateTimeFormatImpl getDateTimeFormatter4X(
1518
DateTimeFormat4X(locale, data, options);
1619

1720
class DateTimeFormat4X extends DateTimeFormatImpl {
18-
DateTimeFormat4X(super.locale, Data data, super.options);
21+
final icu.DateTimeFormatter? _dateTimeFormatter;
22+
final icu.DateFormatter? _dateFormatter;
23+
final icu.TimeFormatter? _timeFormatter;
24+
final icu.ZonedDateTimeFormatter? _zonedDateTimeFormatter;
25+
final icu.DataProvider _data;
26+
27+
DateTimeFormat4X(super.locale, Data data, super.options)
28+
: _data = data.to4X(),
29+
_dateTimeFormatter = _setDateTimeFormatter(options, data, locale),
30+
_timeFormatter = options.timeFormatStyle != null
31+
? icu.TimeFormatter.withLength(
32+
data.to4X(),
33+
locale.to4X(),
34+
options.dateFormatStyle?.timeTo4xOptions() ??
35+
icu.TimeLength.short,
36+
)
37+
: null,
38+
_dateFormatter = _setDateFormatter(options, data, locale),
39+
_zonedDateTimeFormatter = options.timeZone != null
40+
? icu.ZonedDateTimeFormatter.withLengths(
41+
data.to4X(),
42+
locale.to4X(),
43+
options.dateFormatStyle?.dateTo4xOptions() ??
44+
icu.DateLength.short, //TODO: Check defaults
45+
options.timeFormatStyle?.timeTo4xOptions() ??
46+
icu.TimeLength.short, //TODO: Check defaults
47+
)
48+
: null;
49+
50+
static icu.DateTimeFormatter? _setDateTimeFormatter(
51+
DateTimeFormatOptions options,
52+
Data data,
53+
Locale locale,
54+
) {
55+
final dateFormatStyle = options.dateFormatStyle;
56+
final timeFormatStyle = options.timeFormatStyle;
57+
58+
if (dateFormatStyle == null || timeFormatStyle == null) {
59+
return null;
60+
}
61+
62+
return icu.DateTimeFormatter.withLengths(
63+
data.to4X(),
64+
locale.to4X(),
65+
dateFormatStyle.dateTo4xOptions(),
66+
timeFormatStyle.timeTo4xOptions(),
67+
);
68+
}
69+
70+
static icu.DateFormatter? _setDateFormatter(
71+
DateTimeFormatOptions options,
72+
Data data,
73+
Locale locale,
74+
) {
75+
final dateFormatStyle = options.dateFormatStyle;
76+
final timeFormatStyle = options.timeFormatStyle;
77+
78+
if (dateFormatStyle == null && timeFormatStyle != null) {
79+
return null;
80+
}
81+
82+
return icu.DateFormatter.withLength(
83+
data.to4X(),
84+
locale.to4X(),
85+
dateFormatStyle?.dateTo4xOptions() ?? icu.DateLength.short,
86+
);
87+
}
1988

2089
@override
2190
String formatImpl(DateTime datetime) {
22-
throw UnimplementedError('Insert diplomat bindings here');
91+
final calendarKind = options.calendar?.to4x() ?? icu.AnyCalendarKind.iso;
92+
final isoDateTime = icu.DateTime.fromIsoInCalendar(
93+
datetime.year,
94+
datetime.month,
95+
datetime.day,
96+
datetime.hour,
97+
datetime.minute,
98+
datetime.second,
99+
datetime.microsecond * 1000,
100+
icu.Calendar.forKind(_data, calendarKind),
101+
);
102+
if (_zonedDateTimeFormatter != null) {
103+
final ianaToBcp47Mapper = icu.IanaToBcp47Mapper(_data);
104+
final timeZone = icu.CustomTimeZone.empty()
105+
..trySetIanaTimeZoneId(ianaToBcp47Mapper, options.timeZone!);
106+
return _zonedDateTimeFormatter.formatDatetimeWithCustomTimeZone(
107+
isoDateTime,
108+
timeZone,
109+
);
110+
} else if (_dateTimeFormatter != null) {
111+
return _dateTimeFormatter.formatDatetime(isoDateTime);
112+
} else if (_dateFormatter != null) {
113+
return _dateFormatter.formatDatetime(isoDateTime);
114+
} else if (_timeFormatter != null) {
115+
return _timeFormatter.formatDatetime(isoDateTime);
116+
} else {
117+
throw UnimplementedError(
118+
'Custom skeletons are not yet supported in ICU4X. '
119+
'Either date or time formatting has to be enabled.');
120+
}
23121
}
24122
}
123+
124+
extension on TimeFormatStyle {
125+
icu.TimeLength timeTo4xOptions() => switch (this) {
126+
TimeFormatStyle.full => icu.TimeLength.full,
127+
TimeFormatStyle.long => icu.TimeLength.long,
128+
TimeFormatStyle.medium => icu.TimeLength.medium,
129+
TimeFormatStyle.short => icu.TimeLength.short,
130+
};
131+
icu.DateLength dateTo4xOptions() => switch (this) {
132+
TimeFormatStyle.full => icu.DateLength.full,
133+
TimeFormatStyle.long => icu.DateLength.long,
134+
TimeFormatStyle.medium => icu.DateLength.medium,
135+
TimeFormatStyle.short => icu.DateLength.short,
136+
};
137+
}
138+
139+
extension on Calendar {
140+
icu.AnyCalendarKind to4x() => switch (this) {
141+
Calendar.buddhist => icu.AnyCalendarKind.buddhist,
142+
Calendar.chinese => icu.AnyCalendarKind.chinese,
143+
Calendar.coptic => icu.AnyCalendarKind.coptic,
144+
Calendar.dangi => icu.AnyCalendarKind.dangi,
145+
Calendar.ethioaa => icu.AnyCalendarKind.ethiopianAmeteAlem,
146+
Calendar.ethiopic => icu.AnyCalendarKind.ethiopian,
147+
Calendar.gregory => icu.AnyCalendarKind.gregorian,
148+
Calendar.hebrew => icu.AnyCalendarKind.hebrew,
149+
Calendar.indian => icu.AnyCalendarKind.indian,
150+
Calendar.islamic => icu.AnyCalendarKind.islamicObservational,
151+
Calendar.islamicUmalqura => icu.AnyCalendarKind.islamicUmmAlQura,
152+
Calendar.islamicTbla => icu.AnyCalendarKind.islamicTabular,
153+
Calendar.islamicCivil => icu.AnyCalendarKind.islamicCivil,
154+
Calendar.islamicRgsa => icu.AnyCalendarKind.islamicObservational,
155+
Calendar.iso8601 => icu.AnyCalendarKind.iso,
156+
Calendar.japanese => icu.AnyCalendarKind.japanese,
157+
Calendar.persian => icu.AnyCalendarKind.persian,
158+
Calendar.roc => icu.AnyCalendarKind.roc,
159+
};
160+
}

pkgs/intl4x/lib/src/datetime_format/datetime_format_impl.dart

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@ import '../ecma/ecma_policy.dart';
99
import '../locale/locale.dart';
1010
import '../options.dart';
1111
import '../utils.dart';
12-
import 'datetime_format_4x.dart';
1312
import 'datetime_format_options.dart';
1413
import 'datetime_format_stub.dart'
1514
if (dart.library.js) 'datetime_format_ecma.dart';
15+
import 'datetime_format_stub_4x.dart'
16+
if (dart.library.io) 'datetime_format_4x.dart';
1617

1718
/// This is an intermediate to defer to the actual implementations of
1819
/// datetime formatting.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import '../data.dart';
6+
import '../locale/locale.dart';
7+
import 'datetime_format_impl.dart';
8+
import 'datetime_format_options.dart';
9+
10+
DateTimeFormatImpl getDateTimeFormatter4X(
11+
Locale locale,
12+
Data data,
13+
DateTimeFormatOptions options,
14+
) =>
15+
throw UnimplementedError('Cannot use ICU4X in web environments.');

pkgs/intl4x/pubspec.yaml

+15-10
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,32 @@
11
name: intl4x
22
description: >-
33
A lightweight modular library for internationalization (i18n) functionality.
4-
version: 0.8.2-wip
4+
version: 0.8.2
55
repository: https://github.com/dart-lang/i18n/tree/main/pkgs/intl4x
6-
platforms: ## TODO: Add native platforms once ICU4X is integrated.
6+
platforms:
77
web:
8+
android:
9+
ios:
10+
linux:
11+
macos:
12+
windows:
13+
topics:
14+
- i18n
815

916
environment:
10-
sdk: ">=3.0.0 <4.0.0"
17+
sdk: ">=3.3.0 <4.0.0"
1118

1219
dependencies:
1320
ffi: ^2.1.0
14-
js: ^0.6.5
21+
js: ^0.7.1
1522
meta: ^1.12.0
1623

1724
dev_dependencies:
1825
archive: ^3.4.10
1926
args: ^2.4.2
20-
build_runner: ^2.1.4
21-
build_web_compilers: ^3.2.1
2227
collection: ^1.18.0
23-
dart_flutter_team_lints: ^1.0.0
24-
lints: ^2.0.0
25-
native_assets_cli: ^0.3.2
28+
dart_flutter_team_lints: ^2.1.1
29+
lints: ^3.0.0
30+
native_assets_cli: ^0.4.2
2631
path: ^1.9.0
27-
test: ^1.22.1
32+
test: ^1.22.1

0 commit comments

Comments
 (0)