[librsvg: 13/23] Use a new Language / UserLanguage enum instead of LanguageTags everywhere
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 13/23] Use a new Language / UserLanguage enum instead of LanguageTags everywhere
- Date: Mon, 24 May 2021 17:47:32 +0000 (UTC)
commit 7459bc1fc6421971728a72ee5904436bc73bc7b6
Author: Federico Mena Quintero <federico gnome org>
Date: Fri May 21 13:23:26 2021 -0500
Use a new Language / UserLanguage enum instead of LanguageTags everywhere
src/accept_language.rs | 82 ++++++++++++++++++++++++++++++++++++++++++++++++--
src/cond.rs | 25 ++++++++-------
src/drawing_ctx.rs | 40 +++++-------------------
src/element.rs | 10 +++---
src/structure.rs | 2 +-
5 files changed, 104 insertions(+), 55 deletions(-)
---
diff --git a/src/accept_language.rs b/src/accept_language.rs
index 4be8ace2..775d9a2c 100644
--- a/src/accept_language.rs
+++ b/src/accept_language.rs
@@ -5,7 +5,31 @@ use locale_config::{LanguageRange, Locale};
use std::str::FromStr;
-#[derive(Debug, PartialEq)]
+/// Used to set the language for rendering.
+///
+/// SVG documents can use the `<switch>` element whose children have a `systemLanguage`
+/// attribute; only the first child which has a `systemLanguage` that matches the user's
+/// preferences will be rendered.
+///
+/// This enum, used with `CairoRenderer::with_language`, configures how to obtain the
+/// user's prefererred languages.
+pub enum Language {
+ /// Use the Unix environment variables `LANGUAGE`, `LC_ALL`, `LC_MESSAGES` and `LANG` to obtain the
+ /// user's language. This uses [`g_get_language_names()`][ggln] underneath.
+ ///
+ /// [ggln]: https://developer.gnome.org/glib/stable/glib-I18N.html#g-get-language-names
+ FromEnvironment,
+ AcceptLanguage(AcceptLanguage),
+}
+
+/// `Language` but with the environment's locale converted to something we can use.
+#[derive(Clone)]
+pub enum UserLanguage {
+ LanguageTags(LanguageTags),
+ AcceptLanguage(AcceptLanguage),
+}
+
+#[derive(Clone, Debug, PartialEq)]
struct Weight(Option<f32>);
impl Weight {
@@ -14,7 +38,7 @@ impl Weight {
}
}
-#[derive(Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
struct Item {
tag: LanguageTag,
weight: Weight,
@@ -23,7 +47,7 @@ struct Item {
/// Stores a parsed version of an HTTP Accept-Language header.
///
/// https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.5
-#[derive(Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
pub struct AcceptLanguage(Box<[Item]>);
/// Errors when parsing an `AcceptLanguage`.
@@ -65,6 +89,10 @@ impl AcceptLanguage {
pub fn iter(&self) -> impl Iterator<Item = (&LanguageTag, f32)> {
self.0.iter().map(|item| (&item.tag, item.weight.numeric()))
}
+
+ fn any_matches(&self, tag: &LanguageTag) -> bool {
+ self.iter().any(|(self_tag, _weight)| tag.matches(self_tag))
+ }
}
impl Item {
@@ -179,6 +207,54 @@ impl LanguageTags {
}
}
+impl UserLanguage {
+ pub fn new(language: &Language) -> UserLanguage {
+ match *language {
+ Language::FromEnvironment => UserLanguage::LanguageTags(
+ LanguageTags::from_locale(&locale_from_environment())
+ .map_err(|s| {
+ rsvg_log!("could not convert locale to language tags: {}", s);
+ })
+ .unwrap_or_else(|_| LanguageTags::empty()),
+ ),
+
+ Language::AcceptLanguage(ref a) => UserLanguage::AcceptLanguage(a.clone()),
+ }
+ }
+
+ pub fn any_matches(&self, tags: &LanguageTags) -> bool {
+ match *self {
+ UserLanguage::LanguageTags(ref language_tags) => {
+ tags.iter().any(|tag| language_tags.any_matches(tag))
+ }
+ UserLanguage::AcceptLanguage(ref accept_language) => {
+ tags.iter().any(|tag| accept_language.any_matches(tag))
+ }
+ }
+ }
+}
+
+/// Gets the user's preferred locale from the environment and
+/// translates it to a `Locale` with `LanguageRange` fallbacks.
+///
+/// The `Locale::current()` call only contemplates a single language,
+/// but glib is smarter, and `g_get_langauge_names()` can provide
+/// fallbacks, for example, when LC_MESSAGES="en_US.UTF-8:de" (USA
+/// English and German). This function converts the output of
+/// `g_get_language_names()` into a `Locale` with appropriate
+/// fallbacks.
+fn locale_from_environment() -> Locale {
+ let mut locale = Locale::invariant();
+
+ for name in glib::get_language_names() {
+ if let Ok(range) = LanguageRange::from_unix(&name) {
+ locale.add(&range);
+ }
+ }
+
+ locale
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/src/cond.rs b/src/cond.rs
index 1751657f..401f6534 100644
--- a/src/cond.rs
+++ b/src/cond.rs
@@ -7,7 +7,7 @@ use std::str::FromStr;
use language_tags::LanguageTag;
-use crate::accept_language::LanguageTags;
+use crate::accept_language::{LanguageTags, UserLanguage};
use crate::error::*;
// No extensions at the moment.
@@ -111,8 +111,8 @@ impl SystemLanguage {
}
/// Evaluate a systemLanguage value for conditional processing.
- pub fn eval(&self, locale_tags: &LanguageTags) -> bool {
- self.0.iter().any(|tag| locale_tags.any_matches(tag))
+ pub fn eval(&self, user_language: &UserLanguage) -> bool {
+ user_language.any_matches(&self.0)
}
}
@@ -165,8 +165,7 @@ mod tests {
#[test]
fn system_language() {
let locale = Locale::new("de,en-US").unwrap();
-
- let locale_tags = LanguageTags::from_locale(&locale).unwrap();
+ let user_language = UserLanguage::LanguageTags(LanguageTags::from_locale(&locale).unwrap());
assert!(SystemLanguage::from_attribute("").is_err());
@@ -175,56 +174,56 @@ mod tests {
assert_eq!(
SystemLanguage::from_attribute("fr")
.unwrap()
- .eval(&locale_tags),
+ .eval(&user_language),
false
);
assert_eq!(
SystemLanguage::from_attribute("en")
.unwrap()
- .eval(&locale_tags),
+ .eval(&user_language),
false
);
assert_eq!(
SystemLanguage::from_attribute("de")
.unwrap()
- .eval(&locale_tags),
+ .eval(&user_language),
true
);
assert_eq!(
SystemLanguage::from_attribute("en-US")
.unwrap()
- .eval(&locale_tags),
+ .eval(&user_language),
true
);
assert_eq!(
SystemLanguage::from_attribute("en-GB")
.unwrap()
- .eval(&locale_tags),
+ .eval(&user_language),
false
);
assert_eq!(
SystemLanguage::from_attribute("DE")
.unwrap()
- .eval(&locale_tags),
+ .eval(&user_language),
true
);
assert_eq!(
SystemLanguage::from_attribute("de-LU")
.unwrap()
- .eval(&locale_tags),
+ .eval(&user_language),
true
);
assert_eq!(
SystemLanguage::from_attribute("fr, de")
.unwrap()
- .eval(&locale_tags),
+ .eval(&user_language),
true
);
}
diff --git a/src/drawing_ctx.rs b/src/drawing_ctx.rs
index 42df5fa2..75003eca 100644
--- a/src/drawing_ctx.rs
+++ b/src/drawing_ctx.rs
@@ -1,7 +1,6 @@
//! The main context structure which drives the drawing process.
use float_cmp::approx_eq;
-use locale_config::{LanguageRange, Locale};
use once_cell::sync::Lazy;
use pango::FontMapExt;
use regex::{Captures, Regex};
@@ -10,7 +9,7 @@ use std::cell::RefCell;
use std::convert::TryFrom;
use std::rc::{Rc, Weak};
-use crate::accept_language::LanguageTags;
+use crate::accept_language::{Language, UserLanguage};
use crate::aspect_ratio::AspectRatio;
use crate::bbox::BoundingBox;
use crate::coord_units::CoordUnits;
@@ -151,7 +150,7 @@ pub struct DrawingCtx {
cr_stack: Rc<RefCell<Vec<cairo::Context>>>,
cr: cairo::Context,
- locale_tags: LanguageTags,
+ user_language: UserLanguage,
viewport_stack: Rc<RefCell<Vec<Viewport>>>,
@@ -253,27 +252,6 @@ impl Drop for DrawingCtx {
}
}
-/// Gets the user's preferred locale from the environment and
-/// translates it to a `Locale` with `LanguageRange` fallbacks.
-///
-/// The `Locale::current()` call only contemplates a single language,
-/// but glib is smarter, and `g_get_langauge_names()` can provide
-/// fallbacks, for example, when LC_MESSAGES="en_US.UTF-8:de" (USA
-/// English and German). This function converts the output of
-/// `g_get_language_names()` into a `Locale` with appropriate
-/// fallbacks.
-fn locale_from_environment() -> Locale {
- let mut locale = Locale::invariant();
-
- for name in glib::get_language_names() {
- if let Ok(range) = LanguageRange::from_unix(&name) {
- locale.add(&range);
- }
- }
-
- locale
-}
-
impl DrawingCtx {
fn new(
cr: &cairo::Context,
@@ -289,18 +267,14 @@ impl DrawingCtx {
let viewport_stack = vec![initial_viewport];
- let locale_tags = LanguageTags::from_locale(&locale_from_environment())
- .map_err(|s| {
- rsvg_log!("could not convert locale to language tags: {}", s);
- })
- .unwrap_or_else(|_| LanguageTags::empty());
+ let user_language = UserLanguage::new(&Language::FromEnvironment);
DrawingCtx {
initial_viewport,
dpi,
cr_stack: Rc::new(RefCell::new(Vec::new())),
cr: cr.clone(),
- locale_tags,
+ user_language,
viewport_stack: Rc::new(RefCell::new(viewport_stack)),
drawsub_stack,
measuring,
@@ -324,7 +298,7 @@ impl DrawingCtx {
dpi: self.dpi,
cr_stack,
cr,
- locale_tags: self.locale_tags.clone(),
+ user_language: self.user_language.clone(),
viewport_stack: self.viewport_stack.clone(),
drawsub_stack: Vec::new(),
measuring: self.measuring,
@@ -332,8 +306,8 @@ impl DrawingCtx {
}
}
- pub fn locale_tags(&self) -> &LanguageTags {
- &self.locale_tags
+ pub fn user_language(&self) -> &UserLanguage {
+ &self.user_language
}
pub fn toplevel_viewport(&self) -> Rect {
diff --git a/src/element.rs b/src/element.rs
index 5618241b..c6b60194 100644
--- a/src/element.rs
+++ b/src/element.rs
@@ -6,7 +6,7 @@ use std::collections::{HashMap, HashSet};
use std::fmt;
use std::ops::Deref;
-use crate::accept_language::LanguageTags;
+use crate::accept_language::UserLanguage;
use crate::bbox::BoundingBox;
use crate::cond::{RequiredExtensions, RequiredFeatures, SystemLanguage};
use crate::css::{Declaration, Origin};
@@ -177,7 +177,7 @@ impl<T: SetAttributes + Draw> ElementInner<T> {
self.values = values.clone();
}
- fn get_cond(&self, locale_tags: &LanguageTags) -> bool {
+ fn get_cond(&self, user_language: &UserLanguage) -> bool {
self.required_extensions
.as_ref()
.map(|v| v.eval())
@@ -190,7 +190,7 @@ impl<T: SetAttributes + Draw> ElementInner<T> {
&& self
.system_language
.as_ref()
- .map(|v| v.eval(locale_tags))
+ .map(|v| v.eval(user_language))
.unwrap_or(true)
}
@@ -532,8 +532,8 @@ impl Element {
call_inner!(self, set_computed_values, values);
}
- pub fn get_cond(&self, locale_tags: &LanguageTags) -> bool {
- call_inner!(self, get_cond, locale_tags)
+ pub fn get_cond(&self, user_language: &UserLanguage) -> bool {
+ call_inner!(self, get_cond, user_language)
}
pub fn get_transform(&self) -> Transform {
diff --git a/src/structure.rs b/src/structure.rs
index 8a386f1b..aafebd23 100644
--- a/src/structure.rs
+++ b/src/structure.rs
@@ -87,7 +87,7 @@ impl Draw for Switch {
&mut |an, dc| {
if let Some(child) = node.children().filter(|c| c.is_element()).find(|c| {
let elt = c.borrow_element();
- elt.get_cond(&dc.locale_tags()) && !elt.is_in_error()
+ elt.get_cond(&dc.user_language()) && !elt.is_in_error()
}) {
child.draw(an, &CascadedValues::new(cascaded, &child), dc, clipping)
} else {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]