-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add ECMA `PluralRules` to `package:intl4x` * Fix conformance * Switch conformance run to daily
- Loading branch information
Showing
14 changed files
with
327 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
## 0.6.1-wip | ||
## 0.7.0 | ||
|
||
- Add conformance testing workflow. | ||
- Add ECMA `PluralRules`. | ||
|
||
## 0.6.0 | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
// 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. | ||
|
||
export 'src/options.dart'; | ||
export 'src/plural_rules/plural_rules.dart'; | ||
export 'src/plural_rules/plural_rules_options.dart'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// 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 '../test_checker.dart'; | ||
import 'plural_rules_impl.dart'; | ||
import 'plural_rules_options.dart'; | ||
|
||
class PluralRules { | ||
final PluralRulesOptions _options; | ||
final PluralRulesImpl _pluralRulesImpl; | ||
|
||
const PluralRules(this._options, this._pluralRulesImpl); | ||
|
||
/// Locale-dependant pluralization, for example in English: | ||
/// | ||
/// select(2) == PluralCategory.other | ||
PluralCategory select(num number) { | ||
if (isInTest) { | ||
return PluralCategory.other; | ||
} else { | ||
return _pluralRulesImpl.selectImpl(number, _options); | ||
} | ||
} | ||
} | ||
|
||
enum PluralCategory { | ||
zero, | ||
one, | ||
two, | ||
few, | ||
many, | ||
other; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// 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 '../locale/locale.dart'; | ||
import 'plural_rules.dart'; | ||
import 'plural_rules_impl.dart'; | ||
import 'plural_rules_options.dart'; | ||
|
||
PluralRulesImpl getPluralSelect4X(Locale locale) => PluralRules4X(locale); | ||
|
||
class PluralRules4X extends PluralRulesImpl { | ||
PluralRules4X(super.locale); | ||
|
||
@override | ||
PluralCategory selectImpl(num number, PluralRulesOptions options) { | ||
throw UnimplementedError('Insert diplomat bindings here'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
// 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 'package:js/js.dart'; | ||
import 'package:js/js_util.dart'; | ||
|
||
import '../locale/locale.dart'; | ||
import '../options.dart'; | ||
import 'plural_rules.dart'; | ||
import 'plural_rules_impl.dart'; | ||
import 'plural_rules_options.dart'; | ||
|
||
PluralRulesImpl? getPluralSelectECMA( | ||
Locale locale, | ||
LocaleMatcher localeMatcher, | ||
) => | ||
_PluralRulesECMA.tryToBuild(locale, localeMatcher); | ||
|
||
@JS('Intl.PluralRules') | ||
class PluralRulesJS { | ||
external factory PluralRulesJS([List<String> locale, Object options]); | ||
external String select(num number); | ||
} | ||
|
||
@JS('Intl.PluralRules.supportedLocalesOf') | ||
external List<String> supportedLocalesOfJS( | ||
List<String> listOfLocales, [ | ||
Object options, | ||
]); | ||
|
||
class _PluralRulesECMA extends PluralRulesImpl { | ||
_PluralRulesECMA(super.locales); | ||
|
||
static PluralRulesImpl? tryToBuild( | ||
Locale locale, | ||
LocaleMatcher localeMatcher, | ||
) { | ||
final supportedLocales = supportedLocalesOf(locale, localeMatcher); | ||
return supportedLocales.isNotEmpty | ||
? _PluralRulesECMA(supportedLocales.first) | ||
: null; | ||
} | ||
|
||
static List<Locale> supportedLocalesOf( | ||
Locale locale, | ||
LocaleMatcher localeMatcher, | ||
) { | ||
final o = newObject<Object>(); | ||
setProperty(o, 'localeMatcher', localeMatcher.jsName); | ||
return List.from(supportedLocalesOfJS([locale.toLanguageTag()], o)) | ||
.whereType<String>() | ||
.map(Locale.parse) | ||
.toList(); | ||
} | ||
|
||
@override | ||
PluralCategory selectImpl(num number, PluralRulesOptions options) { | ||
final categoryString = | ||
PluralRulesJS([locale.toLanguageTag()], options.toJsOptions()) | ||
.select(number); | ||
return PluralCategory.values | ||
.firstWhere((category) => category.name == categoryString); | ||
} | ||
} | ||
|
||
extension on PluralRulesOptions { | ||
Object toJsOptions() { | ||
final o = newObject<Object>(); | ||
setProperty(o, 'localeMatcher', localeMatcher.jsName); | ||
setProperty(o, 'type', type.name); | ||
setProperty(o, 'roundingMode', roundingMode.name); | ||
if (digits?.roundingPriority != null) { | ||
setProperty(o, 'roundingPriority', digits?.roundingPriority!.name); | ||
} | ||
if (digits?.roundingIncrement != null) { | ||
setProperty(o, 'roundingIncrement', digits?.roundingIncrement!); | ||
} | ||
setProperty(o, 'minimumIntegerDigits', minimumIntegerDigits); | ||
if (digits?.fractionDigits.$1 != null) { | ||
setProperty(o, 'minimumFractionDigits', digits?.fractionDigits.$1); | ||
} | ||
if (digits?.fractionDigits.$2 != null) { | ||
setProperty(o, 'maximumFractionDigits', digits?.fractionDigits.$2); | ||
} | ||
if (digits?.significantDigits.$1 != null) { | ||
setProperty(o, 'minimumSignificantDigits', digits?.significantDigits.$1); | ||
} | ||
if (digits?.significantDigits.$2 != null) { | ||
setProperty(o, 'maximumSignificantDigits', digits?.significantDigits.$2); | ||
} | ||
setProperty(o, 'trailingZeroDisplay', trailingZeroDisplay.name); | ||
return o; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// 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 '../../ecma_policy.dart'; | ||
import '../ecma/ecma_policy.dart'; | ||
import '../locale/locale.dart'; | ||
import '../options.dart'; | ||
import '../utils.dart'; | ||
import 'plural_rules.dart'; | ||
import 'plural_rules_4x.dart'; | ||
import 'plural_rules_options.dart'; | ||
import 'plural_rules_stub.dart' if (dart.library.js) 'plural_rules_ecma.dart'; | ||
|
||
abstract class PluralRulesImpl { | ||
final Locale locale; | ||
|
||
PluralRulesImpl(this.locale); | ||
|
||
PluralCategory selectImpl(num number, PluralRulesOptions options); | ||
|
||
factory PluralRulesImpl.build( | ||
Locale locales, | ||
LocaleMatcher localeMatcher, | ||
EcmaPolicy ecmaPolicy, | ||
) => | ||
buildFormatter( | ||
locales, | ||
localeMatcher, | ||
ecmaPolicy, | ||
getPluralSelectECMA, | ||
getPluralSelect4X, | ||
); | ||
} |
55 changes: 55 additions & 0 deletions
55
pkgs/intl4x/lib/src/plural_rules/plural_rules_options.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// 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 '../../number_format.dart'; | ||
|
||
typedef ListStyle = Style; | ||
|
||
class PluralRulesOptions { | ||
final Type type; | ||
final Digits? digits; | ||
final RoundingMode roundingMode; | ||
final int minimumIntegerDigits; | ||
final TrailingZeroDisplay trailingZeroDisplay; | ||
|
||
final LocaleMatcher localeMatcher; | ||
|
||
PluralRulesOptions({ | ||
this.type = Type.cardinal, | ||
Digits? digits, | ||
this.roundingMode = RoundingMode.halfExpand, | ||
this.minimumIntegerDigits = 1, | ||
this.trailingZeroDisplay = TrailingZeroDisplay.auto, | ||
this.localeMatcher = LocaleMatcher.bestfit, | ||
}) : digits = NumberFormatOptions.getDigits(const DecimalStyle(), digits); | ||
|
||
PluralRulesOptions copyWith({ | ||
Type? type, | ||
Digits? digits, | ||
RoundingMode? roundingMode, | ||
int? minimumIntegerDigits, | ||
TrailingZeroDisplay? trailingZeroDisplay, | ||
LocaleMatcher? localeMatcher, | ||
}) { | ||
return PluralRulesOptions( | ||
type: type ?? this.type, | ||
digits: digits ?? this.digits, | ||
roundingMode: roundingMode ?? this.roundingMode, | ||
minimumIntegerDigits: minimumIntegerDigits ?? this.minimumIntegerDigits, | ||
trailingZeroDisplay: trailingZeroDisplay ?? this.trailingZeroDisplay, | ||
localeMatcher: localeMatcher ?? this.localeMatcher, | ||
); | ||
} | ||
} | ||
|
||
/// The number type to use. | ||
enum Type { | ||
/// For cardinal numbers (referring to the quantity of things): One, two, | ||
/// three, four, five, etc. | ||
cardinal, | ||
|
||
/// For ordinal numbers (referring to the ordering or ranking of things): | ||
/// "1st", "2nd", "3rd", etc. | ||
ordinal; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// 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 '../locale/locale.dart'; | ||
import '../options.dart'; | ||
import 'plural_rules_impl.dart'; | ||
|
||
PluralRulesImpl? getPluralSelectECMA( | ||
Locale locale, | ||
LocaleMatcher localeMatcher, | ||
) => | ||
throw UnimplementedError('Cannot use ECMA outside of web environments.'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// 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. | ||
|
||
@TestOn('browser') | ||
library; | ||
|
||
import 'package:intl4x/intl4x.dart'; | ||
import 'package:intl4x/plural_rules.dart'; | ||
import 'package:test/test.dart'; | ||
|
||
import '../utils.dart'; | ||
|
||
void main() { | ||
testWithFormatting('en-US simple', () { | ||
final numberFormatOptions = | ||
Intl(locale: const Locale(language: 'en', region: 'US')) | ||
.plural(PluralRulesOptions()); | ||
|
||
expect(numberFormatOptions.select(0), PluralCategory.other); | ||
expect(numberFormatOptions.select(1), PluralCategory.one); | ||
expect(numberFormatOptions.select(2), PluralCategory.other); | ||
expect(numberFormatOptions.select(3), PluralCategory.other); | ||
}); | ||
|
||
testWithFormatting('ar-EG simple', () { | ||
final numberFormatOptions = | ||
Intl(locale: const Locale(language: 'ar', region: 'EG')) | ||
.plural(PluralRulesOptions()); | ||
|
||
expect(numberFormatOptions.select(0), PluralCategory.zero); | ||
expect(numberFormatOptions.select(1), PluralCategory.one); | ||
expect(numberFormatOptions.select(2), PluralCategory.two); | ||
expect(numberFormatOptions.select(6), PluralCategory.few); | ||
expect(numberFormatOptions.select(18), PluralCategory.many); | ||
}); | ||
|
||
testWithFormatting('en-US ordinal', () { | ||
final numberFormatOptions = | ||
Intl(locale: const Locale(language: 'en', region: 'US')) | ||
.plural(PluralRulesOptions(type: Type.ordinal)); | ||
|
||
expect(numberFormatOptions.select(0), PluralCategory.other); | ||
expect(numberFormatOptions.select(1), PluralCategory.one); | ||
expect(numberFormatOptions.select(2), PluralCategory.two); | ||
expect(numberFormatOptions.select(3), PluralCategory.few); | ||
expect(numberFormatOptions.select(4), PluralCategory.other); | ||
expect(numberFormatOptions.select(21), PluralCategory.one); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters