///|
fn locale_support_entry(
language : String,
english_name : String,
native_name : String,
direction : TextDirection,
cardinal_categories : Array[String],
ordinal_categories : Array[String],
) -> LocaleSupport {
{
language,
english_name,
native_name,
direction,
cardinal_categories,
ordinal_categories,
}
}
///|
/// Return human-facing metadata for every explicitly supported language.
pub fn locale_support_table() -> Array[LocaleSupport] {
[
locale_support_entry("zh", "Chinese", "中文", LeftToRight, ["other"], [
"other",
]),
locale_support_entry(
"en",
"English",
"English",
LeftToRight,
["one", "other"],
["one", "two", "few", "other"],
),
locale_support_entry(
"ja",
"Japanese",
"日本語",
LeftToRight,
["other"],
["other"],
),
locale_support_entry(
"ru",
"Russian",
"Русский",
LeftToRight,
["one", "few", "many", "other"],
["other"],
),
locale_support_entry(
"ar",
"Arabic",
"العربية",
RightToLeft,
["zero", "one", "two", "few", "many", "other"],
["other"],
),
]
}
///|
pub fn locale_support(locale : String) -> LocaleSupport? {
let language = locale_language_lossy(locale)
for support in locale_support_table() {
if support.language == language {
return Some(support)
}
}
None
}
///|
pub fn LocaleSupport::language(self : LocaleSupport) -> String {
self.language
}
///|
pub fn LocaleSupport::english_name(self : LocaleSupport) -> String {
self.english_name
}
///|
pub fn LocaleSupport::native_name(self : LocaleSupport) -> String {
self.native_name
}
///|
pub fn LocaleSupport::direction(self : LocaleSupport) -> TextDirection {
self.direction
}
///|
pub fn LocaleSupport::cardinal_categories(
self : LocaleSupport,
) -> Array[String] {
self.cardinal_categories
}
///|
pub fn LocaleSupport::ordinal_categories(self : LocaleSupport) -> Array[String] {
self.ordinal_categories
}
///|
pub fn LocaleSupport::summary(self : LocaleSupport) -> String {
"\{self.language} \{self.english_name} (\{self.native_name}), \{self.direction.name()}, cardinal=\{self.cardinal_categories.join("/")}, ordinal=\{self.ordinal_categories.join("/")}"
}
///|
fn canonical_available_map(available : Array[String]) -> Map[String, String] {
let output : Map[String, String] = Map([])
for locale in available {
output[canonicalize_locale_lossy(locale)] = locale
}
output
}
///|
fn negotiation_candidates(
requested : String,
default_locale : String?,
) -> Array[String] {
let output : Array[String] = []
let seen : Map[String, Unit] = Map([])
append_locale_chain(output, seen, requested)
match default_locale {
Some(locale) => append_locale_chain(output, seen, locale)
None => ()
}
output
}
///|
/// Negotiate a requested locale against an available locale list.
pub fn negotiate_locale(
requested : String,
available : Array[String],
default_locale? : String,
) -> LocaleNegotiation {
let candidates = negotiation_candidates(requested, default_locale)
let available_map = canonical_available_map(available)
let mut matched : String? = None
let mut used_default = false
let requested_chain = locale_fallback_chain(requested)
for candidate in candidates {
match available_map.get(candidate) {
Some(original) => {
matched = Some(original)
let mut requested_candidate = false
for value in requested_chain {
if value == candidate {
requested_candidate = true
break
}
}
used_default = !requested_candidate
break
}
None => ()
}
}
{
requested: canonicalize_locale_lossy(requested),
candidates,
available,
matched,
used_default,
}
}
///|
pub fn LocaleNegotiation::requested(self : LocaleNegotiation) -> String {
self.requested
}
///|
pub fn LocaleNegotiation::candidates(self : LocaleNegotiation) -> Array[String] {
self.candidates
}
///|
pub fn LocaleNegotiation::available(self : LocaleNegotiation) -> Array[String] {
self.available
}
///|
pub fn LocaleNegotiation::matched(self : LocaleNegotiation) -> String? {
self.matched
}
///|
pub fn LocaleNegotiation::used_default(self : LocaleNegotiation) -> Bool {
self.used_default
}
///|
pub fn LocaleNegotiation::succeeded(self : LocaleNegotiation) -> Bool {
self.matched is Some(_)
}
///|
pub fn LocaleNegotiation::summary(self : LocaleNegotiation) -> String {
match self.matched {
Some(locale) =>
if self.used_default {
"\{self.requested} -> \{locale} (default)"
} else {
"\{self.requested} -> \{locale}"
}
None => "\{self.requested} -> no match"
}
}