summaryrefslogtreecommitdiffstats
path: root/toolkit/crashreporter/client/app/src/lang/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/crashreporter/client/app/src/lang/mod.rs')
-rw-r--r--toolkit/crashreporter/client/app/src/lang/mod.rs89
1 files changed, 89 insertions, 0 deletions
diff --git a/toolkit/crashreporter/client/app/src/lang/mod.rs b/toolkit/crashreporter/client/app/src/lang/mod.rs
new file mode 100644
index 0000000000..9b7495f92a
--- /dev/null
+++ b/toolkit/crashreporter/client/app/src/lang/mod.rs
@@ -0,0 +1,89 @@
+/* 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/. */
+
+mod language_info;
+mod omnijar;
+
+use fluent::{bundle::FluentBundle, FluentArgs, FluentResource};
+use intl_memoizer::concurrent::IntlLangMemoizer;
+#[cfg(test)]
+pub use language_info::LanguageInfo;
+use std::borrow::Cow;
+use std::collections::BTreeMap;
+
+/// Get the localized string bundle.
+pub fn load() -> anyhow::Result<LangStrings> {
+ // TODO support langpacks, bug 1873210
+ omnijar::read().unwrap_or_else(|e| {
+ log::warn!("failed to read localization data from the omnijar ({e}), falling back to bundled content");
+ Default::default()
+ }).load_strings()
+}
+
+/// A bundle of localized strings.
+pub struct LangStrings {
+ bundle: FluentBundle<FluentResource, IntlLangMemoizer>,
+ rtl: bool,
+}
+
+/// Arguments to build a localized string.
+pub type LangStringsArgs<'a> = BTreeMap<&'a str, Cow<'a, str>>;
+
+impl LangStrings {
+ pub fn new(bundle: FluentBundle<FluentResource, IntlLangMemoizer>, rtl: bool) -> Self {
+ LangStrings { bundle, rtl }
+ }
+
+ /// Return whether the localized language has right-to-left text flow.
+ pub fn is_rtl(&self) -> bool {
+ self.rtl
+ }
+
+ pub fn get(&self, index: &str, args: LangStringsArgs) -> anyhow::Result<String> {
+ let mut fluent_args = FluentArgs::with_capacity(args.len());
+ for (k, v) in args {
+ fluent_args.set(k, v);
+ }
+
+ let Some(pattern) = self.bundle.get_message(index).and_then(|m| m.value()) else {
+ anyhow::bail!("failed to get fluent message for {index}");
+ };
+ let mut errs = Vec::new();
+ let ret = self
+ .bundle
+ .format_pattern(pattern, Some(&fluent_args), &mut errs);
+ if !errs.is_empty() {
+ anyhow::bail!("errors while formatting pattern: {errs:?}");
+ }
+ Ok(ret.into_owned())
+ }
+
+ pub fn builder<'a>(&'a self, index: &'a str) -> LangStringBuilder<'a> {
+ LangStringBuilder {
+ strings: self,
+ index,
+ args: Default::default(),
+ }
+ }
+}
+
+/// A localized string builder.
+pub struct LangStringBuilder<'a> {
+ strings: &'a LangStrings,
+ index: &'a str,
+ args: LangStringsArgs<'a>,
+}
+
+impl<'a> LangStringBuilder<'a> {
+ /// Set an argument for the string.
+ pub fn arg<V: Into<Cow<'a, str>>>(mut self, key: &'a str, value: V) -> Self {
+ self.args.insert(key, value.into());
+ self
+ }
+
+ /// Get the localized string.
+ pub fn get(self) -> anyhow::Result<String> {
+ self.strings.get(self.index, self.args)
+ }
+}