icu_experimental/personnames/specifications/
derive_locale.rsuse icu_locale_core::subtags::script;
use icu_locale_core::{subtags, Locale};
use icu_properties::props::Script;
use icu_properties::{script::ScriptWithExtensionsBorrowed, PropertyNamesShortBorrowed};
use crate::personnames::api::NameFieldKind::{Given, Surname};
use crate::personnames::api::{NameFieldKind, PersonName, PersonNamesFormatterError};
pub fn effective_locale<'a>(
formatter_locale: &'a Locale,
person_name_locale: &'a Locale,
) -> Result<&'a Locale, PersonNamesFormatterError> {
let name_script = person_name_locale.id.script.unwrap();
let formatter_script = formatter_locale.id.script.unwrap();
if !compatible_scripts(name_script, formatter_script) {
return Ok(person_name_locale);
}
Ok(formatter_locale)
}
fn compatible_scripts(sc1: subtags::Script, sc2: subtags::Script) -> bool {
let jpan_compatible = [script!("Hani"), script!("Kana"), script!("Hira")];
if sc1 == script!("Jpan") && jpan_compatible.contains(&sc2) {
return true;
}
if sc2 == script!("Jpan") && jpan_compatible.contains(&sc1) {
return true;
}
sc1 == sc2
}
pub fn likely_person_name_locale<N>(
person_name: &N,
swe: ScriptWithExtensionsBorrowed,
scripts: PropertyNamesShortBorrowed<Script>,
) -> Result<Locale, PersonNamesFormatterError>
where
N: PersonName,
{
let mut found_name_script = find_script(person_name, swe, Surname);
if found_name_script.is_none() {
found_name_script = find_script(person_name, swe, Given);
}
let name_script = found_name_script.unwrap_or(icu_properties::props::Script::Unknown);
let locid_script = scripts.get_locale_script(name_script).unwrap();
person_name.name_locale().map_or_else(
|| {
let mut effective_locale = Locale::default();
effective_locale.id.script = Some(locid_script);
Ok(effective_locale)
},
|locale| {
let mut effective_locale = locale.clone();
effective_locale.id.script = Some(locid_script);
Ok(effective_locale)
},
)
}
fn find_script<N>(
person_name: &N,
swe: ScriptWithExtensionsBorrowed,
kind: NameFieldKind,
) -> Option<icu_properties::props::Script>
where
N: PersonName,
{
person_name
.available_name_fields()
.iter()
.filter(|&name_field| name_field.kind == kind)
.find_map(|&name_field| {
person_name.get(name_field).chars().find_map(|c| {
let char_script = swe.get_script_val(c);
match char_script {
Script::Common | Script::Unknown | Script::Inherited => None,
_ => Some(char_script),
}
})
})
}
#[cfg(test)]
mod tests {
use icu_locale::LocaleExpander;
use icu_locale_core::locale;
use litemap::LiteMap;
use super::{effective_locale, likely_person_name_locale};
use crate::personnames::api::{
FieldModifierSet, NameField, NameFieldKind, PersonNamesFormatterError,
};
use crate::personnames::provided_struct::DefaultPersonName;
#[test]
fn test_effective_locale_matching_script() {
let lc = LocaleExpander::new_extended();
let mut locale = locale!("fr");
lc.maximize(&mut locale.id);
assert_eq!(
effective_locale(&locale!("de_Latn_ch"), &locale),
Ok(&locale!("de_Latn_ch"))
);
assert_eq!(
effective_locale(&locale, &locale!("de_Latn_ch")),
Ok(&locale!("fr_Latn_FR"))
);
}
#[test]
fn test_effective_locale_non_matching_script() {
let lc = LocaleExpander::new_extended();
let mut locale = locale!("ja");
lc.maximize(&mut locale.id);
assert_eq!(
effective_locale(&locale!("de_Latn_ch"), &locale),
Ok(&locale!("ja-Jpan-JP"))
);
assert_eq!(
effective_locale(&locale, &locale!("de_Latn_ch")),
Ok(&locale!("de-Latn-CH"))
);
}
#[test]
fn test_effective_locale_compatible_script() {
let lc = LocaleExpander::new_extended();
let mut locale = locale!("ja");
lc.maximize(&mut locale.id);
assert_eq!(
effective_locale(&locale!("ja_Hani_JP"), &locale),
Ok(&locale!("ja_Hani_JP"))
);
assert_eq!(
effective_locale(&locale!("ja_Kana_JP"), &locale),
Ok(&locale!("ja-Kana-JP"))
);
assert_eq!(
effective_locale(&locale!("ja_Hira_JP"), &locale),
Ok(&locale!("ja-Hira-JP"))
);
assert_eq!(
effective_locale(&locale, &locale!("ja_Hani_JP")),
Ok(&locale!("ja-Jpan-JP"))
);
assert_eq!(
effective_locale(&locale, &locale!("ja_Kana_JP")),
Ok(&locale!("ja-Jpan-JP"))
);
assert_eq!(
effective_locale(&locale, &locale!("ja_Hira_JP")),
Ok(&locale!("ja-Jpan-JP"))
);
}
#[test]
fn test_likely_person_names_locale() {
let swe = icu_properties::script::ScriptWithExtensions::new();
let scripts = icu_properties::PropertyNamesShort::<icu_properties::props::Script>::new();
assert_eq!(
likely_person_name_locale(&person_name("Miyazaki", "Hayao").unwrap(), swe, scripts),
Ok(locale!("und_Latn"))
);
assert_eq!(
likely_person_name_locale(&person_name("駿", "宮崎").unwrap(), swe, scripts),
Ok(locale!("und_Hani"))
);
assert_eq!(
likely_person_name_locale(&person_name("하야오", "미야자키").unwrap(), swe, scripts),
Ok(locale!("und_Hang"))
);
assert_eq!(
likely_person_name_locale(
&person_name("アルベルト", "アインシュタイン").unwrap(),
swe,
scripts
),
Ok(locale!("und_Kana"))
);
}
fn person_name(
surname: &str,
first_name: &str,
) -> Result<DefaultPersonName, PersonNamesFormatterError> {
let mut person_data: LiteMap<NameField, String> = LiteMap::new();
person_data.insert(
NameField {
kind: NameFieldKind::Surname,
modifier: FieldModifierSet::default(),
},
String::from(surname),
);
person_data.insert(
NameField {
kind: NameFieldKind::Given,
modifier: FieldModifierSet::default(),
},
String::from(first_name),
);
DefaultPersonName::new(person_data, None, None)
}
}