Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/toolkit/crashreporter/client/app/src/lang/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 6 kB image not shown  

Quelle  langpack.rs

  Sprache: Rust
 

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


use super::language_info::LanguageInfo;
use super::zip::{read_archive_file_as_string, read_zip, Archive};
use crate::config::installation_resource_path;
use crate::prefs_parser::find_string_pref;
use crate::std::path::{Path, PathBuf};
use anyhow::Context;

const LOCALE_PREF_KEY: &str = "intl.locale.requested";

/// Use the profile language preferences to determine the localization to use.
pub fn read(
    profile_dir: &Path,
    base_locales: &[String],
    useragent_locale: Option<&str>,
) -> anyhow::Result<Option<LanguageInfo>> {
    let Some((identifier, langpack)) =
        select_langpack(profile_dir, base_locales, useragent_locale)?
    else {
        return Ok(None);
    };

    let mut zip = read_zip(&langpack)?;

    let ftl_definitions = read_archive_ftl_definitions(&mut zip, &identifier)?;
    let ftl_branding = read_archive_ftl_branding(&mut zip, &identifier).unwrap_or_else(|e| {
        log::warn!(
            "failed to read branding for {identifier} from {}: {e:#}",
            langpack.display()
        );
        log::info!("using fallback branding info");
        LanguageInfo::default().ftl_branding
    });

    Ok(Some(LanguageInfo {
        identifier,
        ftl_definitions,
        ftl_branding,
    }))
}

/// Select the langpack to use based on profile settings, the useragent locale, and the existence
/// of langpack files.
/// Returns `Ok(None)` if no locales are found in pref and from useragent locale. Also return
/// `Ok(None)` if the locale specified is the base installation locale, as there is no langpack for
/// the base installation locale.
fn select_langpack(
    profile_dir: &Path,
    base_locales: &[String],
    useragent_locale: Option<&str>,
) -> anyhow::Result<Option<(String, PathBuf)>> {
    let mut locales = locales_from_prefs(profile_dir)?
        .into_iter()
        .flatten()
        .chain(useragent_locale.map(str::to_string));

    if locales.clone().count() == 0 {
        return Ok(None);
    }

    // Use the first language that is either the base locale or we can find a langpack extension for
    locales
        .find_map(|lang| {
            if base_locales.contains(&lang) {
                Some(None)
            } else {
                find_langpack_extension(profile_dir, &lang).map(|path| Some((lang, path)))
            }
        })
        .with_context(|| format!("couldn't locate langpack for requested locales ({locales:?})"))
}

fn locales_from_prefs(profile_dir: &Path) -> anyhow::Result<Option<Vec<String>>> {
    let prefs = profile_dir.join("prefs.js");
    if !prefs.exists() {
        log::debug!(
            "no prefs.js exists in {}; not reading localization info",
            profile_dir.display()
        );
        return Ok(None);
    }

    let prefs_contents = std::fs::read_to_string(&prefs)
        .with_context(|| format!("while reading {}", prefs.display()))?;

    // Logic dictated by https://firefox-source-docs.mozilla.org/intl/locale.html#requested-locales

    let Some(langs) = parse_requested_locales(&prefs_contents) else {
        // If the pref is unset, the installation locale should be used.
        log::debug!(
            "no locale pref set in {}; using installation locale",
            prefs.display()
        );
        return Ok(None);
    };

    Ok(Some(if langs.is_empty() {
        // If the pref is an empty string, use the OS locale settings.
        let os_locales: Vec<String> = sys_locale::get_locales().collect();
        if os_locales.is_empty() {
            log::debug!("no OS locales found");
            return Ok(None);
        }
        log::debug!(
            "locale pref blank in {}; using OS locale settings ({os_locales:?})",
            prefs.display()
        );
        os_locales
    } else {
        langs.into_iter().map(|s| s.to_owned()).collect()
    }))
}

/// Parse the language pref (if any) from the prefs file.
///
/// For example:
/// ```rust
/// let input = r#"user_pref("intl.locale.requested", "foo , bar,,");"#;
/// let expected_output = Some(vec!["foo","bar"]);
/// assert_eq!(parse_requested_locales(input), output);
/// ```
///
/// This will parse the locales out of the user prefs file contents, which looks like
/// `user_pref("intl.locale.requested", "<LOCALE LIST>")`.
fn parse_requested_locales(prefs_content: &str) -> Option<Vec<&str>> {
    let v = find_string_pref(prefs_content, LOCALE_PREF_KEY)?;
    Some(
        v.split(",")
            .map(|s| s.trim())
            .filter(|s| !s.is_empty())
            .collect(),
    )
}

/// Find the langpack extension for the given locale.
fn find_langpack_extension(profile_dir: &Path, locale: &str) -> Option<PathBuf> {
    let path_tail = format!("extensions/langpack-{locale}@firefox.mozilla.org.xpi");

    // Check profile extensions
    let profile_path = profile_dir.join(&path_tail);
    if profile_path.exists() {
        return Some(profile_path);
    }

    // Check installation extensions
    let install_path = installation_resource_path().join(format!("browser/{}", &path_tail));
    if install_path.exists() {
        return Some(install_path);
    }

    None
}

fn read_archive_ftl_definitions(
    langpack: &mut Archive,
    language_identifier: &str,
) -> anyhow::Result<String> {
    let path = format!("localization/{language_identifier}/crashreporter/crashreporter.ftl");
    read_archive_file_as_string(langpack, &path)
}

fn read_archive_ftl_branding(
    langpack: &mut Archive,
    language_identifier: &str,
) -> anyhow::Result<String> {
    let path = format!("browser/localization/{language_identifier}/branding/brand.ftl");
    read_archive_file_as_string(langpack, &path)
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn parse_locales_none() {
        assert_eq!(parse_requested_locales(""), None);
    }

    #[test]
    fn parse_locales_empty() {
        assert_eq!(
            parse_requested_locales(r#"user_pref("intl.locale.requested","");"#),
            Some(vec![])
        );
    }

    #[test]
    fn parse_locales() {
        assert_eq!(
            parse_requested_locales(r#"user_pref("intl.locale.requested""fr,en-US");"#),
            Some(vec!["fr""en-US"])
        );
    }
}

Messung V0.5 in Prozent
C=88 H=100 G=94

¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet am  2026-08-22) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.