blob: 9be1c0d9a3c331d6bff6312cbdfe2ca078bca642 [file] [log] [blame]
// Copyright (c) 2012, 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.
/**
* This defines a class for loading locale data incrementally from
* an external source as JSON. The external sources expected are either
* local files or via HTTP request.
*/
library lazy_locale_data;
import 'dart:async';
import 'dart:convert';
import 'intl_helpers.dart';
/**
* This implements the very basic map-type operations which are used
* in locale lookup, and looks them up based on a URL that defines
* the external source.
*/
class LazyLocaleData {
/// This holds the data we have loaded.
Map map;
/// The object that actually does the data reading.
LocaleDataReader _reader;
/**
* In order to avoid a potentially remote call to see if a locale
* is available, we hold a complete list of all the available
* locales.
*/
List availableLocales;
/**
* Given a piece of remote data, apply [_creationFunction] to it to
* convert it into the right form. Typically this means converting it
* from a Map into an object form.
*/
Function _creationFunction;
/**
* The set of available locales.
*/
Set availableLocaleSet;
/**
* The constructor. The [_reader] specifies where the data comes
* from. The [_creationFunction] creates the appropriate data type
* from the remote data (which typically comes in as a Map). The
* [keys] lists the set of remotely available locale names so we know which
* things can be fetched without having to check remotely.
*/
LazyLocaleData(this._reader, this._creationFunction, List keys) {
map = new Map();
availableLocales = keys;
availableLocaleSet = new Set.from(availableLocales);
}
/**
* Tests if we have data for the locale available. Note that this returns
* true even if the data is known to be available remotely but not yet loaded.
*/
bool containsKey(String locale) => availableLocaleSet.contains(locale);
/** Returns the list of keys/locale names. */
List get keys => availableLocales;
/**
* Returns the data stored for [localeName]. If no data has been loaded
* for [localeName], throws an exception. If no data is available for
* [localeName] then throw an exception with a different message.
*/
operator [](String localeName) {
if (containsKey(localeName)) {
var data = map[localeName];
if (data == null) {
throw new LocaleDataException(
"Locale $localeName has not been initialized."
" Call initializeDateFormatting($localeName, <data url>) first");
} else {
return data;
}
} else {
unsupportedLocale(localeName);
}
}
/**
* Throw an exception indicating that the locale has no data available,
* either locally or remotely.
*/
unsupportedLocale(localeName) {
throw new LocaleDataException('Locale $localeName has no data available');
}
/**
* Initialize for locale. Internal use only. As a user, call
* initializeDateFormatting instead.
*/
Future initLocale(String localeName) {
var data = _reader.read(localeName);
return jsonData(data).then((input) {
map[localeName] = _creationFunction(input);
});
}
/**
* Given a Future [input] whose value is expected to be a string in JSON form,
* return another future that parses the JSON into a usable format.
*/
Future jsonData(Future input) {
return input.then((response) => JSON.decode(response));
}
}