Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1138)

Unified Diff: packages/intl/lib/intl.dart

Issue 2989763002: Update charted to 0.4.8 and roll (Closed)
Patch Set: Removed Cutch from list of reviewers Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « packages/intl/lib/generate_localized.dart ('k') | packages/intl/lib/intl_browser.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: packages/intl/lib/intl.dart
diff --git a/packages/intl/lib/intl.dart b/packages/intl/lib/intl.dart
index d952691ddc2a84d759f77c50d0b6d207de198863..095eb710c1b6097ad50d8a22c57ddc35ee2a91f5 100644
--- a/packages/intl/lib/intl.dart
+++ b/packages/intl/lib/intl.dart
@@ -2,22 +2,20 @@
// 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.
-/**
- * This library provides internationalization and localization. This includes
- * message formatting and replacement, date and number formatting and parsing,
- * and utilities for working with Bidirectional text.
- *
- * This is part of the [intl package]
- * (https://pub.dartlang.org/packages/intl).
- *
- * For things that require locale or other data, there are multiple different
- * ways of making that data available, which may require importing different
- * libraries. See the class comments for more details.
- *
- * There is also a simple example application that can be found in the
- * [example/basic](https://github.com/dart-lang/intl/tree/master/example/basic)
- * directory.
- */
+/// This library provides internationalization and localization. This includes
+/// message formatting and replacement, date and number formatting and parsing,
+/// and utilities for working with Bidirectional text.
+///
+/// This is part of the [intl package]
+/// (https://pub.dartlang.org/packages/intl).
+///
+/// For things that require locale or other data, there are multiple different
+/// ways of making that data available, which may require importing different
+/// libraries. See the class comments for more details.
+///
+/// There is also a simple example application that can be found in the
+/// [example/basic](https://github.com/dart-lang/intl/tree/master/example/basic)
+/// directory.
library intl;
import 'dart:async';
@@ -30,182 +28,177 @@ import 'number_symbols.dart';
import 'number_symbols_data.dart';
import 'src/date_format_internal.dart';
import 'src/intl_helpers.dart';
+import 'package:intl/src/plural_rules.dart' as plural_rules;
part 'src/intl/bidi_formatter.dart';
part 'src/intl/bidi_utils.dart';
+
+part 'src/intl/compact_number_format.dart';
part 'src/intl/date_format.dart';
part 'src/intl/date_format_field.dart';
part 'src/intl/date_format_helpers.dart';
part 'src/intl/number_format.dart';
-/**
- * The Intl class provides a common entry point for internationalization
- * related tasks. An Intl instance can be created for a particular locale
- * and used to create a date format via `anIntl.date()`. Static methods
- * on this class are also used in message formatting.
- *
- * Examples:
- * today(date) => Intl.message(
- * "Today's date is $date",
- * name: 'today',
- * args: [date],
- * desc: 'Indicate the current date',
- * examples: {'date' : 'June 8, 2012'});
- * print(today(new DateTime.now().toString());
- *
- * howManyPeople(numberOfPeople, place) => Intl.plural(
- * zero: 'I see no one at all',
- * one: 'I see one other person',
- * other: 'I see $numberOfPeople other people')} in $place.''',
- * name: 'msg',
- * args: [numberOfPeople, place],
- * desc: 'Description of how many people are seen in a place.',
- * examples: {'numberOfPeople': 3, 'place': 'London'});
- *
- * Calling `howManyPeople(2, 'Athens');` would
- * produce "I see 2 other people in Athens." as output in the default locale.
- * If run in a different locale it would produce appropriately translated
- * output.
- *
- * For more detailed information on messages and localizing them see
- * the main [package documentation](https://pub.dartlang.org/packages/intl)
- *
- * You can set the default locale.
- * Intl.defaultLocale = "pt_BR";
- *
- * To temporarily use a locale other than the default, use the `withLocale`
- * function.
- * var todayString = new DateFormat("pt_BR").format(new DateTime.now());
- * print(withLocale("pt_BR", () => today(todayString));
- *
- * See `tests/message_format_test.dart` for more examples.
- */
+/// The Intl class provides a common entry point for internationalization
+/// related tasks. An Intl instance can be created for a particular locale
+/// and used to create a date format via `anIntl.date()`. Static methods
+/// on this class are also used in message formatting.
+///
+/// Examples:
+/// today(date) => Intl.message(
+/// "Today's date is $date",
+/// name: 'today',
+/// args: [date],
+/// desc: 'Indicate the current date',
+/// examples: const {'date' : 'June 8, 2012'});
+/// print(today(new DateTime.now().toString());
+///
+/// howManyPeople(numberOfPeople, place) => Intl.plural(
+/// zero: 'I see no one at all',
+/// one: 'I see one other person',
+/// other: 'I see $numberOfPeople other people')} in $place.''',
+/// name: 'msg',
+/// args: [numberOfPeople, place],
+/// desc: 'Description of how many people are seen in a place.',
+/// examples: const {'numberOfPeople': 3, 'place': 'London'});
+///
+/// Calling `howManyPeople(2, 'Athens');` would
+/// produce "I see 2 other people in Athens." as output in the default locale.
+/// If run in a different locale it would produce appropriately translated
+/// output.
+///
+/// For more detailed information on messages and localizing them see
+/// the main [package documentation](https://pub.dartlang.org/packages/intl)
+///
+/// You can set the default locale.
+/// Intl.defaultLocale = "pt_BR";
+///
+/// To temporarily use a locale other than the default, use the `withLocale`
+/// function.
+/// var todayString = new DateFormat("pt_BR").format(new DateTime.now());
+/// print(withLocale("pt_BR", () => today(todayString));
+///
+/// See `tests/message_format_test.dart` for more examples.
//TODO(efortuna): documentation example involving the offset parameter?
class Intl {
- /**
- * String indicating the locale code with which the message is to be
- * formatted (such as en-CA).
- */
+ /// String indicating the locale code with which the message is to be
+ /// formatted (such as en-CA).
String _locale;
- /**
- * The default locale. This defaults to being set from systemLocale, but
- * can also be set explicitly, and will then apply to any new instances where
- * the locale isn't specified. Note that a locale parameter to
- * [Intl.withLocale]
- * will supercede this value while that operation is active. Using
- * [Intl.withLocale] may be preferable if you are using different locales
- * in the same application.
- */
+ /// The default locale. This defaults to being set from systemLocale, but
+ /// can also be set explicitly, and will then apply to any new instances where
+ /// the locale isn't specified. Note that a locale parameter to
+ /// [Intl.withLocale]
+ /// will supercede this value while that operation is active. Using
+ /// [Intl.withLocale] may be preferable if you are using different locales
+ /// in the same application.
static String get defaultLocale {
var zoneLocale = Zone.current[#Intl.locale];
return zoneLocale == null ? _defaultLocale : zoneLocale;
}
- static set defaultLocale(String newLocale) => _defaultLocale = newLocale;
+
+ static set defaultLocale(String newLocale) {
+ _defaultLocale = newLocale;
+ }
+
static String _defaultLocale;
- /**
- * The system's locale, as obtained from the window.navigator.language
- * or other operating system mechanism. Note that due to system limitations
- * this is not automatically set, and must be set by importing one of
- * intl_browser.dart or intl_standalone.dart and calling findSystemLocale().
- */
+ /// The system's locale, as obtained from the window.navigator.language
+ /// or other operating system mechanism. Note that due to system limitations
+ /// this is not automatically set, and must be set by importing one of
+ /// intl_browser.dart or intl_standalone.dart and calling findSystemLocale().
static String systemLocale = 'en_US';
- /**
- * Return a new date format using the specified [pattern].
- * If [desiredLocale] is not specified, then we default to [locale].
- */
+ /// Return a new date format using the specified [pattern].
+ /// If [desiredLocale] is not specified, then we default to [locale].
DateFormat date([String pattern, String desiredLocale]) {
var actualLocale = (desiredLocale == null) ? locale : desiredLocale;
return new DateFormat(pattern, actualLocale);
}
- /**
- * Constructor optionally [aLocale] for specifics of the language
- * locale to be used, otherwise, we will attempt to infer it (acceptable if
- * Dart is running on the client, we can infer from the browser/client
- * preferences).
- */
+ /// Constructor optionally [aLocale] for specifics of the language
+ /// locale to be used, otherwise, we will attempt to infer it (acceptable if
+ /// Dart is running on the client, we can infer from the browser/client
+ /// preferences).
Intl([String aLocale]) {
_locale = aLocale != null ? aLocale : getCurrentLocale();
}
- /**
- * Use this for a message that will be translated for different locales. The
- * expected usage is that this is inside an enclosing function that only
- * returns the value of this call and provides a scope for the variables that
- * will be substituted in the message.
- *
- * The [message_str] is the string to be translated, which may be interpolated
- * based on one or more variables. The [name] of the message must
- * match the enclosing function name. For methods, it can also be
- * className_methodName. So for a method hello in class Simple, the name
- * can be either "hello" or "Simple_hello". The name must also be globally
- * unique in the program, so the second form can make it easier to distinguish
- * messages with the same name but in different classes.
- * The [args] repeats the arguments of the enclosing
- * function, [desc] provides a description of usage,
- * [examples] is a Map of exmaples for each interpolated variable. For example
- * hello(yourName) => Intl.message(
- * "Hello, $yourName",
- * name: "hello",
- * args: [yourName],
- * desc: "Say hello",
- * examples = {"yourName": "Sparky"}.
- * The source code will be processed via the analyzer to extract out the
- * message data, so only a subset of valid Dart code is accepted. In
- * particular, everything must be literal and cannot refer to variables
- * outside the scope of the enclosing function. The [examples] map must
- * be a valid const literal map. Similarly, the [desc] argument must
- * be a single, simple string. These two arguments will not be used at runtime
- * but will be extracted from
- * the source code and used as additional data for translators. For more
- * information see the "Messages" section of the main [package documentation]
- * (https://pub.dartlang.org/packages/intl).
- *
- * The [name] and [args] arguments are required, and are used at runtime
- * to look up the localized version and pass the appropriate arguments to it.
- * We may in the future modify the code during compilation to make manually
- * passing those arguments unnecessary.
- */
- static String message(String message_str, {String desc: '',
- Map<String, String> examples: const {}, String locale, String name,
- List<String> args, String meaning}) {
+ /// Use this for a message that will be translated for different locales. The
+ /// expected usage is that this is inside an enclosing function that only
+ /// returns the value of this call and provides a scope for the variables that
+ /// will be substituted in the message.
+ ///
+ /// The [message_str] is the string to be translated, which may be
+ /// interpolated based on one or more variables. The [name] of the message
+ /// must match the enclosing function name. For methods, it can also be
+ /// className_methodName. So for a method hello in class Simple, the name can
+ /// be either "hello" or "Simple_hello". The name must also be globally unique
+ /// in the program, so the second form can make it easier to distinguish
+ /// messages with the same name but in different classes.
+ ///
+ /// The [args] repeats the arguments of the enclosing
+ /// function, [desc] provides a description of usage,
+ /// [examples] is a Map of examples for each interpolated variable.
+ /// For example
+ ///
+ /// hello(yourName) => Intl.message(
+ /// "Hello, $yourName",
+ /// name: "hello",
+ /// args: [yourName],
+ /// desc: "Say hello",
+ /// examples = const {"yourName": "Sparky"}.
+ ///
+ /// The source code will be processed via the analyzer to extract out the
+ /// message data, so only a subset of valid Dart code is accepted. In
+ /// particular, everything must be literal and cannot refer to variables
+ /// outside the scope of the enclosing function. The [examples] map must be a
+ /// valid const literal map. Similarly, the [desc] argument must be a single,
+ /// simple string. These two arguments will not be used at runtime but will be
+ /// extracted from the source code and used as additional data for
+ /// translators. For more information see the "Messages" section of the main
+ /// [package documentation] (https://pub.dartlang.org/packages/intl).
+ ///
+ /// The [name] and [args] arguments are required, and are used at runtime
+ /// to look up the localized version and pass the appropriate arguments to it.
+ /// We may in the future modify the code during compilation to make manually
+ /// passing those arguments unnecessary.
+ static String message(String message_str,
+ {String desc: '',
+ Map<String, dynamic> examples: const {},
+ String locale,
+ String name,
+ List args,
+ String meaning}) =>
+ _message(message_str, locale, name, args, meaning);
+
+ /// Omit the compile-time only parameters so dart2js can see to drop them.
+ static _message(String message_str, String locale, String name, List args,
+ String meaning) {
return messageLookup.lookupMessage(
- message_str, desc, examples, locale, name, args, meaning);
+ message_str, locale, name, args, meaning);
}
- /**
- * Return the locale for this instance. If none was set, the locale will
- * be the default.
- */
+ /// Return the locale for this instance. If none was set, the locale will
+ /// be the default.
String get locale => _locale;
- /**
- * Return true if the locale exists, or if it is null. The null case
- * is interpreted to mean that we use the default locale.
- */
- static bool _localeExists(localeName) => DateFormat.localeExists(localeName);
-
- /**
- * Given [newLocale] return a locale that we have data for that is similar
- * to it, if possible.
- *
- * If [newLocale] is found directly, return it. If it can't be found, look up
- * based on just the language (e.g. 'en_CA' -> 'en'). Also accepts '-'
- * as a separator and changes it into '_' for lookup, and changes the
- * country to uppercase.
- *
- * There is a special case that if a locale named "fallback" is present
- * and has been initialized, this will return that name. This can be useful
- * for messages where you don't want to just use the text from the original
- * source code, but wish to have a universal fallback translation.
- *
- * Note that null is interpreted as meaning the default locale, so if
- * [newLocale] is null it will be returned.
- */
+ /// Given [newLocale] return a locale that we have data for that is similar
+ /// to it, if possible.
+ ///
+ /// If [newLocale] is found directly, return it. If it can't be found, look up
+ /// based on just the language (e.g. 'en_CA' -> 'en'). Also accepts '-'
+ /// as a separator and changes it into '_' for lookup, and changes the
+ /// country to uppercase.
+ ///
+ /// There is a special case that if a locale named "fallback" is present
+ /// and has been initialized, this will return that name. This can be useful
+ /// for messages where you don't want to just use the text from the original
+ /// source code, but wish to have a universal fallback translation.
+ ///
+ /// Note that null is interpreted as meaning the default locale, so if
+ /// [newLocale] is null the default locale will be returned.
static String verifiedLocale(String newLocale, Function localeExists,
{Function onFailure: _throwLocaleError}) {
// TODO(alanknight): Previously we kept a single verified locale on the Intl
@@ -220,8 +213,11 @@ class Intl {
if (localeExists(newLocale)) {
return newLocale;
}
- for (var each in
- [canonicalizedLocale(newLocale), shortLocale(newLocale), "fallback"]) {
+ for (var each in [
+ canonicalizedLocale(newLocale),
+ shortLocale(newLocale),
+ "fallback"
+ ]) {
if (localeExists(each)) {
return each;
}
@@ -229,26 +225,22 @@ class Intl {
return onFailure(newLocale);
}
- /**
- * The default action if a locale isn't found in verifiedLocale. Throw
- * an exception indicating the locale isn't correct.
- */
+ /// The default action if a locale isn't found in verifiedLocale. Throw
+ /// an exception indicating the locale isn't correct.
static String _throwLocaleError(String localeName) {
throw new ArgumentError("Invalid locale '$localeName'");
}
- /** Return the short version of a locale name, e.g. 'en_US' => 'en' */
+ /// Return the short version of a locale name, e.g. 'en_US' => 'en'
static String shortLocale(String aLocale) {
if (aLocale.length < 2) return aLocale;
return aLocale.substring(0, 2).toLowerCase();
}
- /**
- * Return the name [aLocale] turned into xx_YY where it might possibly be
- * in the wrong case or with a hyphen instead of an underscore. If
- * [aLocale] is null, for example, if you tried to get it from IE,
- * return the current system locale.
- */
+ /// Return the name [aLocale] turned into xx_YY where it might possibly be
+ /// in the wrong case or with a hyphen instead of an underscore. If
+ /// [aLocale] is null, for example, if you tried to get it from IE,
+ /// return the current system locale.
static String canonicalizedLocale(String aLocale) {
// Locales of length < 5 are presumably two-letter forms, or else malformed.
// We return them unmodified and if correct they will be found.
@@ -267,61 +259,116 @@ class Intl {
return '${aLocale[0]}${aLocale[1]}_$region';
}
- /**
- * Format a message differently depending on [howMany]. Normally used
- * as part of an `Intl.message` text that is to be translated.
- * Selects the correct plural form from
- * the provided alternatives. The [other] named argument is mandatory.
- */
- static String plural(int howMany, {zero, one, two, few, many, other,
- String desc, Map<String, String> examples, String locale, String name,
- List<String> args, String meaning}) {
+ /// Format a message differently depending on [howMany]. Normally used
+ /// as part of an `Intl.message` text that is to be translated.
+ /// Selects the correct plural form from
+ /// the provided alternatives. The [other] named argument is mandatory.
+ static String plural(int howMany,
+ {zero,
+ one,
+ two,
+ few,
+ many,
+ other,
+ String desc,
+ Map<String, dynamic> examples,
+ String locale,
+ String name,
+ List args,
+ String meaning}) {
// If we are passed a name and arguments, then we are operating as a
// top-level message, so look up our translation by calling Intl.message
// with ourselves as an argument.
if (name != null) {
- return message(plural(howMany,
+ return message(
+ plural(howMany,
zero: zero,
one: one,
two: two,
few: few,
many: many,
- other: other),
- name: name, args: args, locale: locale, meaning: meaning);
+ other: other,
+ locale: locale),
+ name: name,
+ args: args,
+ locale: locale,
+ meaning: meaning);
}
if (other == null) {
throw new ArgumentError("The 'other' named argument must be provided");
}
- // TODO(alanknight): This algorithm needs to be locale-dependent.
- switch (howMany) {
- case 0:
- return (zero == null) ? other : zero;
- case 1:
- return (one == null) ? other : one;
- case 2:
- return (two == null) ? ((few == null) ? other : few) : two;
- default:
- if ((howMany == 3 || howMany == 4) && few != null) return few;
- if (howMany > 10 && howMany < 100 && many != null) return many;
+ if (howMany == null) {
+ throw new ArgumentError("The howMany argument to plural cannot be null");
+ }
+ // If there's an explicit case for the exact number, we use it. This is not
+ // strictly in accord with the CLDR rules, but it seems to be the
+ // expectation. At least I see e.g. Russian translations that have a zero
+ // case defined. The rule for that locale will never produce a zero, and
+ // treats it as other. But it seems reasonable that, even if the language
+ // rules treat zero as other, we might want a special message for zero.
+ if (howMany == 0 && zero != null) return zero;
+ if (howMany == 1 && one != null) return one;
+ if (howMany == 2 && two != null) return two;
+ var pluralRule = _pluralRule(locale, howMany);
+ var pluralCase = pluralRule();
+ switch (pluralCase) {
+ case plural_rules.PluralCase.ZERO:
+ return zero ?? other;
+ case plural_rules.PluralCase.ONE:
+ return one ?? other;
+ case plural_rules.PluralCase.TWO:
+ return two ?? few ?? other;
+ case plural_rules.PluralCase.FEW:
+ return few ?? other;
+ case plural_rules.PluralCase.MANY:
+ return many ?? other;
+ case plural_rules.PluralCase.OTHER:
return other;
+ default:
+ throw new ArgumentError.value(
+ howMany, "howMany", "Invalid plural argument");
}
- throw new ArgumentError("Invalid plural usage for $howMany");
}
- /**
- * Format a message differently depending on [targetGender]. Normally used as
- * part of an Intl.message message that is to be translated.
- */
- static String gender(String targetGender, {String male, String female,
- String other, String desc, Map<String, String> examples, String locale,
- String name, List<String> args, String meaning}) {
+ static var _cachedPluralRule;
+ static String _cachedPluralLocale;
+
+ static _pluralRule(String locale, int howMany) {
+ plural_rules.startRuleEvaluation(howMany);
+ var verifiedLocale = Intl.verifiedLocale(
+ locale, plural_rules.localeHasPluralRules,
+ onFailure: (locale) => 'default');
+ if (_cachedPluralLocale == verifiedLocale) {
+ return _cachedPluralRule;
+ } else {
+ _cachedPluralRule = plural_rules.pluralRules[verifiedLocale];
+ _cachedPluralLocale = verifiedLocale;
+ return _cachedPluralRule;
+ }
+ }
+
+ /// Format a message differently depending on [targetGender]. Normally used as
+ /// part of an Intl.message message that is to be translated.
+ static String gender(String targetGender,
+ {String male,
+ String female,
+ String other,
+ String desc,
+ Map<String, dynamic> examples,
+ String locale,
+ String name,
+ List args,
+ String meaning}) {
// If we are passed a name and arguments, then we are operating as a
// top-level message, so look up our translation by calling Intl.message
// with ourselves as an argument.
if (name != null) {
return message(
gender(targetGender, male: male, female: female, other: other),
- name: name, args: args, locale: locale, meaning: meaning);
+ name: name,
+ args: args,
+ locale: locale,
+ meaning: meaning);
}
if (other == null) {
@@ -337,15 +384,19 @@ class Intl {
}
}
- /**
- * Format a message differently depending on [choice]. We look up the value
- * of [choice] in [cases] and return the result, or an empty string if
- * it is not found. Normally used as part
- * of an Intl.message message that is to be translated.
- */
- static String select(String choice, Map<String, String> cases, {String desc,
- Map<String, String> examples, String locale, String name,
- List<String> args, String meaning}) {
+ /// Format a message differently depending on [choice]. We look up the value
+ /// of [choice] in [cases] and return the result, or an empty string if
+ /// it is not found. Normally used as part
+ /// of an Intl.message message that is to be translated.
+ static String select(Object choice, Map<String, String> cases,
+ {String desc,
+ Map<String, dynamic> examples,
+ String locale,
+ String name,
+ List args,
+ String meaning}) {
+ // Allow passing non-strings, e.g. enums to a select.
+ choice = "$choice";
// If we are passed a name and arguments, then we are operating as a
// top-level message, so look up our translation by calling Intl.message
// with ourselves as an argument.
@@ -356,46 +407,42 @@ class Intl {
var exact = cases[choice];
if (exact != null) return exact;
var other = cases["other"];
- if (other ==
- null) throw new ArgumentError("The 'other' case must be specified");
+ if (other == null)
+ throw new ArgumentError("The 'other' case must be specified");
return other;
}
- /**
- * Run [function] with the default locale set to [locale] and
- * return the result.
- *
- * This is run in a zone, so async operations invoked
- * from within [function] will still have the locale set.
- *
- * In simple usage [function] might be a single
- * `Intl.message()` call or number/date formatting operation. But it can
- * also be an arbitrary function that calls multiple Intl operations.
- *
- * For example
- *
- * Intl.withLocale("fr", () => new NumberFormat.format(123456));
- *
- * or
- *
- * hello(name) => Intl.message(
- * "Hello $name.",
- * name: 'hello',
- * args: [name],
- * desc: 'Say Hello');
- * Intl.withLocale("zh", new Timer(new Duration(milliseconds:10),
- * () => print(hello("World")));
- */
+ /// Run [function] with the default locale set to [locale] and
+ /// return the result.
+ ///
+ /// This is run in a zone, so async operations invoked
+ /// from within [function] will still have the locale set.
+ ///
+ /// In simple usage [function] might be a single
+ /// `Intl.message()` call or number/date formatting operation. But it can
+ /// also be an arbitrary function that calls multiple Intl operations.
+ ///
+ /// For example
+ ///
+ /// Intl.withLocale("fr", () => new NumberFormat.format(123456));
+ ///
+ /// or
+ ///
+ /// hello(name) => Intl.message(
+ /// "Hello $name.",
+ /// name: 'hello',
+ /// args: [name],
+ /// desc: 'Say Hello');
+ /// Intl.withLocale("zh", new Timer(new Duration(milliseconds:10),
+ /// () => print(hello("World")));
static withLocale(String locale, function()) {
var canonical = Intl.canonicalizedLocale(locale);
return runZoned(function, zoneValues: {#Intl.locale: canonical});
}
- /**
- * Accessor for the current locale. This should always == the default locale,
- * unless for some reason this gets called inside a message that resets the
- * locale.
- */
+ /// Accessor for the current locale. This should always == the default locale,
+ /// unless for some reason this gets called inside a message that resets the
+ /// locale.
static String getCurrentLocale() {
if (defaultLocale == null) defaultLocale = systemLocale;
return defaultLocale;
@@ -403,3 +450,34 @@ class Intl {
toString() => "Intl($locale)";
}
+
+/// Convert a string to beginning of sentence case, in a way appropriate to the
+/// locale.
+///
+/// Currently this just converts the first letter to uppercase, which works for
+/// many locales, and we have the option to extend this to handle more cases
+/// without changing the API for clients. It also hard-codes the case of
+/// dotted i in Turkish and Azeri.
+String toBeginningOfSentenceCase(String input, [String locale]) {
+ if (input == null || input.isEmpty) return input;
+ return "${_upperCaseLetter(input[0], locale)}${input.substring(1)}";
+}
+
+/// Convert the input single-letter string to upper case. A trivial
+/// hard-coded implementation that only handles simple upper case
+/// and the dotted i in Turkish/Azeri.
+///
+/// Private to the implementation of [toBeginningOfSentenceCase].
+// TODO(alanknight): Consider hard-coding other important cases.
+// See http://www.unicode.org/Public/UNIDATA/SpecialCasing.txt
+// TODO(alanknight): Alternatively, consider toLocaleUpperCase in browsers.
+// See also https://github.com/dart-lang/sdk/issues/6706
+String _upperCaseLetter(String input, String locale) {
+ // Hard-code the important edge case of i->İ
+ if (locale != null) {
+ if (input == "i" && locale.startsWith("tr") || locale.startsWith("az")) {
+ return "\u0130";
+ }
+ }
+ return input.toUpperCase();
+}
« no previous file with comments | « packages/intl/lib/generate_localized.dart ('k') | packages/intl/lib/intl_browser.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698