tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

lib.rs (10814B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 use icu_locale::{
      6    langid,
      7    subtags::{region, variant, Script},
      8    LanguageIdentifier, LocaleExpander, ParseError,
      9 };
     10 use nsstring::{nsACString, nsAString};
     11 
     12 pub fn langid_for_mozilla(name: &nsACString) -> Result<LanguageIdentifier, ParseError> {
     13    if name.eq_ignore_ascii_case(b"ja-jp-mac") {
     14        Ok(langid!("ja-JP-macos"))
     15    } else {
     16        // Cut out any `.FOO` like `en-US.POSIX`.
     17        let mut name: &[u8] = name.as_ref();
     18        if let Some(ptr) = name.iter().position(|b| b == &b'.') {
     19            name = &name[..ptr];
     20        }
     21        LanguageIdentifier::try_from_utf8(name)
     22    }
     23 }
     24 
     25 /// The unicode ellipsis char "…", or "...", depending on the locale.
     26 #[no_mangle]
     27 pub extern "C" fn locale_service_ellipsis(name: &nsACString, out: &mut nsAString) {
     28    match langid_for_mozilla(name) {
     29        Ok(langid) if langid.language.as_str() == "ja" => out.assign_str("..."),
     30        _ => out.assign_str("…"),
     31    }
     32 }
     33 
     34 /// If true, accesskeys should always be appended for the locale.
     35 #[no_mangle]
     36 pub extern "C" fn locale_service_always_append_accesskeys(name: &nsACString) -> bool {
     37    match langid_for_mozilla(name) {
     38        Ok(langid) => match langid.language.as_str() {
     39            "as" | "ja" => true,
     40            "zh" if langid.region == Some(region!("TW")) => true,
     41            _ => false,
     42        },
     43        Err(_) => false,
     44    }
     45 }
     46 
     47 /// If false, accesskeys should not be separated from the label.
     48 #[no_mangle]
     49 pub extern "C" fn locale_service_insert_separator_before_accesskeys(name: &nsACString) -> bool {
     50    match langid_for_mozilla(name) {
     51        Ok(langid) => match langid.language.as_str() {
     52            "ja" | "ko" => false,
     53            "zh" if langid.region == Some(region!("CN")) => false,
     54            _ => true,
     55        },
     56        Err(_) => true,
     57    }
     58 }
     59 
     60 /// A comma-separated list of valid BCP 47 language tags.
     61 ///
     62 /// The default value is either
     63 ///
     64 ///     $lang, en-US, en
     65 ///
     66 /// or
     67 ///
     68 ///     $lang-$region, $lang, en-US, en
     69 ///
     70 /// if the current locale includes a region subtag.
     71 ///
     72 /// If customizing this, begin with the language tag of your locale.
     73 /// Next, include language tags for other languages that you expect most users of your locale to be able to speak,
     74 /// so that their browsing experience degrades gracefully if content is not available in their primary language.
     75 ///
     76 /// By default, "en-US, en" is appended to the end of the list, providing locales of last resort.
     77 /// If you know that users of your locale would prefer a different variety of English,
     78 /// or if they are not likely to understand English at all,
     79 /// you may opt to include a different English language tag,
     80 /// or to exclude English altogether.
     81 #[no_mangle]
     82 pub extern "C" fn locale_service_default_accept_languages(name: &nsACString, out: &mut nsACString) {
     83    let mut add_en_us = true;
     84    let lang;
     85    let fmt;
     86    let langs = match langid_for_mozilla(name) {
     87        Ok(langid) => {
     88            lang = langid.language;
     89            match lang.as_str() {
     90                "ace" => "ace, id",
     91                "ach" => "ach, en-GB",
     92                "af" => "af, en-ZA, en-GB",
     93                "ak" => "ak, ak-GH",
     94                "an" => "an, es-ES, es, ca",
     95                "ast" => "ast, es-ES, es",
     96                "az" => "az-AZ, az",
     97                "bo" => "bo-CN, bo-IN, bo",
     98                "br" => "br, fr-FR, fr",
     99                "brx" => "brx, as",
    100                "bs" => "bs-BA, bs",
    101                "ca" if langid.variants.get(0) == Some(&variant!("valencia")) => "ca-valencia, ca",
    102                "cak" => "cak, kaq, es",
    103                "crh" => "tr-TR, tr",
    104                "cs" => "cs, sk",
    105                "csb" => "csb, csb-PL, pl",
    106                "cy" => "cy-GB, cy",
    107                "dsb" => "dsb, hsb, de",
    108                "el" => "el-GR, el",
    109                "en" => {
    110                    add_en_us = false;
    111                    match langid.region {
    112                        Some(region) => match region.as_str() {
    113                            "CA" => "en-CA, en-US, en",
    114                            "GB" => "en-GB, en",
    115                            "ZA" => "en-ZA, en-GB, en-US, en",
    116                            _ => "en-US, en",
    117                        },
    118                        _ => "en-US, en",
    119                    }
    120                }
    121                "et" => "et, et-EE",
    122                "fa" => "fa-IR, fa",
    123                "ff" => "ff, fr-FR, fr, en-GB",
    124                "fi" => "fi-FI, fi",
    125                "fr" => "fr, fr-FR",
    126                "frp" => "frp, fr-FR, fr",
    127                "fur" => "fur-IT, fur, it-IT, it",
    128                "fy" => "fy-NL, fy, nl",
    129                "ga" => "ga-IE, ga, en-IE, en-GB",
    130                "gd" => "gd-GB, gd, en-GB",
    131                "gl" => "gl-ES, gl",
    132                "gn" => "gn, es",
    133                "gv" => "gv, en-GB",
    134                "he" => "he, he-IL",
    135                "hr" => "hr, hr-HR",
    136                "hsb" => "hsb, dsb, de",
    137                "hto" => "es-MX, es-ES, es, es-AR, es-CL",
    138                "hu" => "hu-HU, hu",
    139                "hye" => "hye, hy",
    140                "ilo" => "ilo-PH, ilo",
    141                "it" => "it-IT, it",
    142                "ixl" => "ixl, es-MX, es",
    143                "ja" => "ja", // Also catches ja-JP-mac
    144                "ka" => "ka-GE, ka",
    145                "kab" => "kab-DZ, kab, fr-FR, fr",
    146                "kk" => "kk, ru, ru-RU",
    147                "kn" => "kn-IN, kn",
    148                "ko" => "ko-KR, ko",
    149                "lb" => "lb, de-DE, de",
    150                "lg" => "lg, en-GB",
    151                "lij" => "lij, it",
    152                "lt" => "lt, ru, pl",
    153                "ltg" => "ltg, lv",
    154                "mai" => "mai, hi-IN, en",
    155                "meh" => "meh, es-MX, es",
    156                "mix" => "mix, es-MX, es",
    157                "mk" => "mk-MK, mk",
    158                "ml" => "ml-IN, ml",
    159                "mr" => "mr-IN, mr",
    160                "my" => {
    161                    add_en_us = false;
    162                    "my, en-GB, en"
    163                }
    164                "nb" => "nb-NO, nb, no-NO, no, nn-NO, nn",
    165                "nn" => "nn-NO, nn, no-NO, no, nb-NO, nb",
    166                "nr" => "nr-ZA, nr, en-ZA, en-GB",
    167                "nso" => "nso-ZA, nso, en-ZA, en-GB",
    168                "oc" => "oc, ca, fr, es, it",
    169                "pa" => "pa, pa-IN",
    170                "ppl" => "ppl, es-MX, es",
    171                "rm" => "rm, rm-CH, de-CH, de",
    172                "ro" => {
    173                    add_en_us = false;
    174                    "ro-RO, ro-GB, en"
    175                }
    176                "ru" => "ru-RU, ru",
    177                "sah" => "sah, ru-RU, ru",
    178                "sc" => "sc, it-IT, it",
    179                "scn" => "scn, it-IT, it",
    180                "sco" => {
    181                    add_en_us = false;
    182                    "sco, en-GB, en"
    183                }
    184                "si" => "si-LK, si",
    185                "sk" => "sk, cs",
    186                "sl" => {
    187                    add_en_us = false;
    188                    "sl, en-GB, en"
    189                }
    190                "son" => "son, son-ML, fr",
    191                "sq" => "sq, sq-AL",
    192                "sr" => "sr-RS, sr",
    193                "st" => "st-ZA, st, en-ZA, en-GB",
    194                "szl" => {
    195                    add_en_us = false;
    196                    "szl, pl-PL, pl, en, de"
    197                }
    198                "ta" => "ta-IN, ta",
    199                "te" => "te-IN, te",
    200                "tl" => "tl-PH, tl",
    201                "tr" => "tr-TR, tr",
    202                "trs" => "trs, es-MX, es",
    203                "ts" => "ts-ZA, ts, en-ZA, en-GB",
    204                "uk" => "uk-UA, uk",
    205                "ur" => "ur-PK, ur",
    206                "uz" => "uz, ru",
    207                "ve" => "ve-ZA, ve, en-ZA, en-GB",
    208                "vi" => "vi-VN, vi",
    209                "xcl" => "xcl, hy",
    210                "xh" => "xh-ZA, xh",
    211                "zam" => "zam, es-MX, es",
    212                "zh" if langid.region == Some(region!("CN")) => "zh-CN, zh, zh-TW, zh-HK",
    213                _ => {
    214                    if langid.region.is_some() {
    215                        let region = langid.region.unwrap();
    216                        fmt = format!("{lang}-{region}, {lang}");
    217                        fmt.as_str()
    218                    } else {
    219                        lang.as_str()
    220                    }
    221                }
    222            }
    223        }
    224        Err(_) => {
    225            add_en_us = false;
    226            "en-US, en"
    227        }
    228    };
    229    if add_en_us {
    230        out.assign(format!("{langs}, en-US, en").as_str())
    231    } else {
    232        out.assign(langs)
    233    }
    234 }
    235 
    236 /// The initial setting of the language drop-down menu
    237 /// in the Fonts and Colors > Advanced preference panel.
    238 ///
    239 /// Takes one of the values of the menuitems in the "selectLangs" menulist in
    240 /// https://searchfox.org/firefox-main/source/browser/components/preferences/dialogs/fonts.xhtml
    241 #[no_mangle]
    242 pub extern "C" fn locale_service_default_font_language_group(
    243    name: &nsACString,
    244    out: &mut nsACString,
    245 ) {
    246    const X_WESTERN: &'static str = "x-western";
    247    let font_group = match langid_for_mozilla(name) {
    248        Ok(mut langid) => match langid.language.as_str() {
    249            "az" | "mai" | "sat" | "vi" => "x-unicode",
    250            // These should really have their scripts correctly detected below.
    251            "bo" => "x-tibt",
    252            "ckb" | "skr" => "ar",
    253            "hye" | "xcl" => "x-armn",
    254            _ => {
    255                LocaleExpander::new_common().maximize(&mut langid);
    256                match langid.script.as_ref().map(Script::as_str) {
    257                    Some("Arab") => "ar",
    258                    Some("Armn") => "x-armn",
    259                    Some("Beng") => "x-beng",
    260                    Some("Cyrl") => "x-cyrillic",
    261                    Some("Deva") => "x-devanagari",
    262                    Some("Grek") => "el",
    263                    Some("Gujr") => "x-gujr",
    264                    Some("Guru") => "x-guru",
    265                    Some("Hans") => "zh-CN",
    266                    Some("Hant") => "zh-TW",
    267                    Some("Hebr") => "he",
    268                    Some("Jpan") => "ja",
    269                    Some("Knda") => "x-knda",
    270                    Some("Kore") => "ko",
    271                    Some("Laoo") | Some("Thai") => "th",
    272                    Some("Mlym") => "x-mlym",
    273                    Some("Sinh") => "x-sinh",
    274                    Some("Telu") => "x-telu",
    275                    Some("Tibt") => "x-tibt",
    276                    // "Geor" | "Khmr" | "Latn" | "Mymr" | "Taml" => X_WESTERN,
    277                    _ => X_WESTERN,
    278                }
    279            }
    280        },
    281        Err(_) => X_WESTERN,
    282    };
    283    out.assign(font_group)
    284 }