Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions pkgs/intl4x/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 1.0.0-alpha.3-wip

- Add `calendar.dart` entrypoint exposing `Calendar` and `Weekday` with `Weekday.firstDayOfWeek` API.

## 1.0.0-alpha.2

- Add `locale.dart` entrypoint exposing only `Locale`.
Expand Down
13 changes: 13 additions & 0 deletions pkgs/intl4x/lib/calendar.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) 2026, 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.

/// Calendar types and weekday information.
///
/// Provides [Calendar] and [Weekday] enums for working with calendar systems
/// and week-start information.
/// @docImport 'src/options.dart';
library;

export 'src/locale/locale.dart' show Locale;
export 'src/options.dart' show Calendar, Weekday;
15 changes: 15 additions & 0 deletions pkgs/intl4x/lib/src/first_day_of_week/first_day_of_week.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) 2026, 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 '../ecma/ecma_native.dart'
if (dart.library.js_interop) '../ecma/ecma_web.dart';
import '../locale/locale.dart';
import '../options.dart';
import 'first_day_of_week_stub.dart'
if (dart.library.js_interop) 'first_day_of_week_ecma.dart';
import 'first_day_of_week_stub_4x.dart'
if (dart.library.ffi) 'first_day_of_week_4x.dart';

Weekday getFirstDayOfWeek(Locale locale) =>
useBrowser ? getFirstDayOfWeekECMA(locale) : getFirstDayOfWeek4X(locale);
22 changes: 22 additions & 0 deletions pkgs/intl4x/lib/src/first_day_of_week/first_day_of_week_4x.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (c) 2026, 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 'package:icu4x/icu4x.dart' as icu;

import '../locale/locale.dart';
import '../locale/locale_4x.dart';
import '../options.dart';

Weekday getFirstDayOfWeek4X(Locale locale) {
final weekInfo = icu.WeekInformation((locale as Locale4x).get4X);
return switch (weekInfo.firstWeekday) {
icu.Weekday.monday => Weekday.monday,
icu.Weekday.tuesday => Weekday.tuesday,
icu.Weekday.wednesday => Weekday.wednesday,
icu.Weekday.thursday => Weekday.thursday,
icu.Weekday.friday => Weekday.friday,
icu.Weekday.saturday => Weekday.saturday,
icu.Weekday.sunday => Weekday.sunday,
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) 2026, 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:js_interop';
import 'dart:js_interop_unsafe';

import '../locale/locale.dart';
import '../options.dart';

@JS('Intl.Locale')
extension type _LocaleJS._(JSObject _) implements JSObject {
external factory _LocaleJS(String s);
external JSObject? get weekInfo;
external JSObject? getWeekInfo();
}

Weekday getFirstDayOfWeekECMA(Locale locale) {
final jsLocale = _LocaleJS(locale.toLanguageTag());
JSObject? weekInfo;
if (jsLocale.hasProperty('getWeekInfo'.toJS).toDart) {
weekInfo = jsLocale.getWeekInfo();
} else if (jsLocale.hasProperty('weekInfo'.toJS).toDart) {
weekInfo = jsLocale.weekInfo;
}
if (weekInfo != null) {
final firstDayJS = weekInfo.getProperty('firstDay'.toJS);
if (firstDayJS != null && firstDayJS.isA<JSNumber>()) {
final firstDay = (firstDayJS as JSNumber).toDartInt;
if (firstDay >= 1 && firstDay <= 7) {
return Weekday.fromIsoIndex(firstDay);
}
}
}
return Weekday.monday;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright (c) 2026, 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 '../locale/locale.dart';
import '../options.dart';

Weekday getFirstDayOfWeekECMA(Locale locale) =>
throw UnimplementedError('Cannot use ECMA outside of web environments.');
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright (c) 2026, 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 '../locale/locale.dart';
import '../options.dart';

Weekday getFirstDayOfWeek4X(Locale locale) =>
throw UnimplementedError('Cannot use ICU4X in web environments.');
41 changes: 39 additions & 2 deletions pkgs/intl4x/lib/src/options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,45 @@
// 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.

/// Common options used across intl4x libraries.
library;
import 'first_day_of_week/first_day_of_week.dart';
import 'locale/locale.dart' show Locale;

/// Weekdays.
enum Weekday {
monday(1),
tuesday(2),
wednesday(3),
thursday(4),
friday(5),
saturday(6),
sunday(7);

/// The ISO 8601 standard index, where Monday is 1 and Sunday is 7.
final int isoIndex;

const Weekday(this.isoIndex);

/// Returns the first day of the week for the given [locale].
factory Weekday.firstDayOfWeek([Locale? locale]) =>
getFirstDayOfWeek(locale ?? Locale.system);

/// Returns the [Weekday] corresponding to the given ISO 8601 index (1 for
/// Monday, 7 for Sunday).
factory Weekday.fromIsoIndex(int isoIndex) => switch (isoIndex) {
1 => Weekday.monday,
2 => Weekday.tuesday,
3 => Weekday.wednesday,
4 => Weekday.thursday,
5 => Weekday.friday,
6 => Weekday.saturday,
7 => Weekday.sunday,
_ => throw ArgumentError.value(
isoIndex,
'isoIndex',
'Must be between 1 and 7',
),
};
}

/// Calendar types for date and time formatting.
enum Calendar {
Expand Down
2 changes: 1 addition & 1 deletion pkgs/intl4x/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: intl4x
description: >-
A lightweight modular library for internationalization (i18n) functionality.
version: 1.0.0-alpha.2
version: 1.0.0-alpha.3-wip
repository: https://github.com/dart-lang/i18n/tree/main/pkgs/intl4x
issue_tracker: https://github.com/dart-lang/i18n/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Aintl4x

Expand Down
46 changes: 46 additions & 0 deletions pkgs/intl4x/test/calendar_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) 2026, 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 'package:intl4x/calendar.dart';
import 'package:test/test.dart';

import 'utils.dart';

void main() {
group('firstDayOfWeek', () {
testWithFormatting('en-US', () {
final locale = Locale.parse('en-US');
expect(Weekday.firstDayOfWeek(locale), Weekday.sunday);
});

testWithFormatting('fr-FR', () {
final locale = Locale.parse('fr-FR');
expect(Weekday.firstDayOfWeek(locale), Weekday.monday);
});

testWithFormatting('ar-EG', () {
final locale = Locale.parse('ar-EG');
expect(Weekday.firstDayOfWeek(locale), Weekday.saturday);
});
});

group('Weekday ISO enum', () {
test('values', () {
expect(Weekday.monday.isoIndex, 1);
expect(Weekday.tuesday.isoIndex, 2);
expect(Weekday.wednesday.isoIndex, 3);
expect(Weekday.thursday.isoIndex, 4);
expect(Weekday.friday.isoIndex, 5);
expect(Weekday.saturday.isoIndex, 6);
expect(Weekday.sunday.isoIndex, 7);
});

test('fromIsoIndex', () {
expect(Weekday.fromIsoIndex(1), Weekday.monday);
expect(Weekday.fromIsoIndex(7), Weekday.sunday);
expect(() => Weekday.fromIsoIndex(0), throwsArgumentError);
expect(() => Weekday.fromIsoIndex(8), throwsArgumentError);
});
});
}
40 changes: 40 additions & 0 deletions pkgs/intl4x/test/locale_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) 2026, 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 'package:intl4x/datetime_format.dart';
import 'package:test/test.dart';

void main() {
group('Locale', () {
test('parse and toLanguageTag', () {
final locale = Locale.parse('en-US');
expect(locale.toLanguageTag(), 'en-US');
expect(locale.toString(), 'en-US');
});

test('toLanguageTag', () {
final locale = Locale.parse('de-DE');
expect(locale.toLanguageTag(), 'de-DE');
});

test('withCalendar', () {
final locale = Locale.parse('en-US').withCalendar(Calendar.buddhist);
expect(locale.toLanguageTag(), 'en-US-u-ca-buddhist');
});

test('withNumberingSystem', () {
final locale = Locale.parse(
'en-US',
).withNumberingSystem(NumberingSystem.arabic);
expect(locale.toLanguageTag(), 'en-US-u-nu-arab');
});

test('withClockStyle', () {
final locale = Locale.parse(
'en-US',
).withClockStyle(ClockStyle.oneToTwelve);
expect(locale.toLanguageTag(), 'en-US-u-hc-h12');
});
});
}
Loading