-
-
Notifications
You must be signed in to change notification settings - Fork 406
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement prototype of
Intl
built-in (#1622)
<!--- Thank you for contributing to Boa! Please fill out the template below, and remove or add any information as you feel neccesary. ---> This pull request is related to #1180. It changes the following: - Creates the `Intl` global - Adds the `Intl.getCanonicalLocales` method At the moment it does not actually use ICU4X behind the scenes; `Intl.getCanonicalLocales` simply acts as if all the locales passed are canonical locales. This will not be the case in the final PR. Co-authored-by: RageKnify <RageKnify@gmail.com>
- Loading branch information
Showing
2 changed files
with
144 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
//! This module implements the global `Intl` object. | ||
//! | ||
//! `Intl` is a built-in object that has properties and methods for i18n. It's not a function object. | ||
//! | ||
//! More information: | ||
//! - [ECMAScript reference][spec] | ||
//! | ||
//! [spec]: https://tc39.es/ecma402/#intl-object | ||
use indexmap::IndexSet; | ||
|
||
use crate::{ | ||
builtins::{Array, BuiltIn, JsArgs}, | ||
object::ObjectInitializer, | ||
property::Attribute, | ||
symbol::WellKnownSymbols, | ||
BoaProfiler, Context, JsResult, JsString, JsValue, | ||
}; | ||
|
||
/// JavaScript `Intl` object. | ||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
pub(crate) struct Intl; | ||
|
||
impl BuiltIn for Intl { | ||
const NAME: &'static str = "Intl"; | ||
|
||
const ATTRIBUTE: Attribute = Attribute::WRITABLE | ||
.union(Attribute::NON_ENUMERABLE) | ||
.union(Attribute::CONFIGURABLE); | ||
|
||
fn init(context: &mut Context) -> JsValue { | ||
let _timer = BoaProfiler::global().start_event(Self::NAME, "init"); | ||
|
||
let string_tag = WellKnownSymbols::to_string_tag(); | ||
let object = ObjectInitializer::new(context) | ||
.function(Self::get_canonical_locales, "getCanonicalLocales", 1) | ||
.property( | ||
string_tag, | ||
Self::NAME, | ||
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE, | ||
) | ||
.build(); | ||
|
||
object.into() | ||
} | ||
} | ||
|
||
impl Intl { | ||
fn canonicalize_locale(locale: &str) -> JsString { | ||
JsString::new(locale) | ||
} | ||
|
||
fn canonicalize_locale_list( | ||
args: &[JsValue], | ||
context: &mut Context, | ||
) -> JsResult<Vec<JsString>> { | ||
// https://tc39.es/ecma402/#sec-canonicalizelocalelist | ||
// 1. If locales is undefined, then | ||
let locales = args.get_or_undefined(0); | ||
if locales.is_undefined() { | ||
// a. Return a new empty List. | ||
return Ok(Vec::new()); | ||
} | ||
|
||
let locales = &args[0]; | ||
|
||
// 2. Let seen be a new empty List. | ||
let mut seen = IndexSet::new(); | ||
|
||
// 3. If Type(locales) is String or Type(locales) is Object and locales has an [[InitializedLocale]] internal slot, then | ||
// TODO: check if Type(locales) is object and handle the internal slots | ||
let o = if locales.is_string() { | ||
// a. Let O be CreateArrayFromList(« locales »). | ||
Array::create_array_from_list([locales.clone()], context) | ||
} else { | ||
// 4. Else, | ||
// a. Let O be ? ToObject(locales). | ||
locales.to_object(context)? | ||
}; | ||
|
||
// 5. Let len be ? ToLength(? Get(O, "length")). | ||
let len = o.length_of_array_like(context)?; | ||
|
||
// 6 Let k be 0. | ||
// 7. Repeat, while k < len, | ||
for k in 0..len { | ||
// a. Let Pk be ToString(k). | ||
// b. Let kPresent be ? HasProperty(O, Pk). | ||
let k_present = o.has_property(k, context)?; | ||
// c. If kPresent is true, then | ||
if k_present { | ||
// i. Let kValue be ? Get(O, Pk). | ||
let k_value = o.get(k, context)?; | ||
// ii. If Type(kValue) is not String or Object, throw a TypeError exception. | ||
if !(k_value.is_object() || k_value.is_string()) { | ||
return Err(context | ||
.throw_type_error("locale should be a String or Object") | ||
.unwrap_err()); | ||
} | ||
// iii. If Type(kValue) is Object and kValue has an [[InitializedLocale]] internal slot, then | ||
// TODO: handle checks for InitializedLocale internal slot (there should be an if statement here) | ||
// 1. Let tag be kValue.[[Locale]]. | ||
// iv. Else, | ||
// 1. Let tag be ? ToString(kValue). | ||
let tag = k_value.to_string(context)?; | ||
// v. If IsStructurallyValidLanguageTag(tag) is false, throw a RangeError exception. | ||
// TODO: implement `IsStructurallyValidLanguageTag` | ||
|
||
// vi. Let canonicalizedTag be CanonicalizeUnicodeLocaleId(tag). | ||
seen.insert(Self::canonicalize_locale(&tag)); | ||
// vii. If canonicalizedTag is not an element of seen, append canonicalizedTag as the last element of seen. | ||
} | ||
// d. Increase k by 1. | ||
} | ||
|
||
// 8. Return seen. | ||
Ok(seen.into_iter().collect::<Vec<JsString>>()) | ||
} | ||
|
||
/// Returns an array containing the canonical locale names. | ||
/// | ||
/// More information: | ||
/// - [ECMAScript reference][spec] | ||
/// - [MDN docs][mdn] | ||
/// | ||
/// [spec]: https://tc39.es/ecma402/#sec-intl.getcanonicallocales | ||
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/getCanonicalLocales | ||
pub(crate) fn get_canonical_locales( | ||
_: &JsValue, | ||
args: &[JsValue], | ||
context: &mut Context, | ||
) -> JsResult<JsValue> { | ||
// 1. Let ll be ? CanonicalizeLocaleList(locales). | ||
let ll = Self::canonicalize_locale_list(args, context)?; | ||
// 2. Return CreateArrayFromList(ll). | ||
Ok(JsValue::Object(Array::create_array_from_list( | ||
ll.into_iter().map(|x| x.into()), | ||
context, | ||
))) | ||
} | ||
} |
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