Skip to content

Commit d979416

Browse files
committed
Use locale from LC_MESSAGES
1 parent 62c4aff commit d979416

File tree

4 files changed

+95
-5
lines changed

4 files changed

+95
-5
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ itertools = "0.9.0"
3434
euclid = "0.22.1"
3535
nom = { version = "6.0.1", default-features = false, features = ["std", "regexp"] }
3636
regex = "1.4.2"
37+
libc = "0.2.81"
3738

3839
[profile.release]
3940
lto = true

src/desktop.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ use xdg::BaseDirectories;
66

77
use crate::icon::Icon;
88

9+
mod locale;
10+
911
pub static XDG_DIRS: OnceCell<BaseDirectories> = OnceCell::new();
1012

1113
pub struct Entry {
@@ -83,8 +85,19 @@ fn traverse_dir_entry(mut entries: &mut Vec<Entry>, dir_entry: DirEntry) {
8385
return;
8486
}
8587
};
88+
8689
let main_section = entry.section("Desktop Entry");
87-
match (main_section.attr("Name"), main_section.attr("Exec")) {
90+
let locale = locale::Locale::current();
91+
92+
let localized_entry = |attr_name: &str| {
93+
locale
94+
.keys()
95+
.filter_map(|key| main_section.attr_with_param(attr_name, key))
96+
.next()
97+
.or_else(|| main_section.attr(attr_name))
98+
};
99+
100+
match (localized_entry("Name"), main_section.attr("Exec")) {
88101
(Some(n), Some(e)) => {
89102
entries.push(Entry {
90103
name: n.to_owned(),
@@ -96,14 +109,12 @@ fn traverse_dir_entry(mut entries: &mut Vec<Entry>, dir_entry: DirEntry) {
96109
.to_owned(),
97110
path: dir_entry_path,
98111
exec: e.to_owned(),
99-
// TODO: use `attr_with_param` with locale first
100-
name_with_keywords: n.to_owned()
101-
+ main_section.attr("Keywords").unwrap_or_default(),
112+
name_with_keywords: n.to_owned() + localized_entry("Keywords").unwrap_or_default(),
102113
is_terminal: main_section
103114
.attr("Terminal")
104115
.map(|s| s == "true")
105116
.unwrap_or(false),
106-
icon: main_section.attr("Icon").and_then(|name| {
117+
icon: localized_entry("Icon").and_then(|name| {
107118
let icon_path = Path::new(name);
108119

109120
if icon_path.is_absolute() {

src/desktop/locale.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
use std::ffi::CStr;
2+
3+
use once_cell::sync::OnceCell;
4+
use regex::Regex;
5+
6+
pub struct Locale<'a> {
7+
lang: Option<&'a str>,
8+
country: Option<&'a str>,
9+
modifier: Option<&'a str>,
10+
}
11+
12+
impl Locale<'static> {
13+
pub fn current<'a>() -> &'a Self {
14+
static LOCALE: OnceCell<Option<Locale<'static>>> = OnceCell::new();
15+
LOCALE
16+
.get_or_init(|| {
17+
let s = unsafe {
18+
let ptr = libc::setlocale(libc::LC_MESSAGES, b"\0".as_ptr().cast());
19+
if ptr.is_null() {
20+
return None;
21+
}
22+
CStr::from_ptr(ptr)
23+
}
24+
.to_str()
25+
.ok()?;
26+
27+
let re = Regex::new(
28+
r#"(?x)
29+
^
30+
([[:alpha:]]+) # lang
31+
(?:_([[:alpha:]]+))? # country
32+
(?:\.[^@]*)? # encoding
33+
(?:@(.*))? # modifier
34+
$"#,
35+
)
36+
.unwrap();
37+
38+
let c = re.captures(s)?;
39+
40+
Some(Self {
41+
lang: c.get(1).map(|m| &s[m.range()]),
42+
country: c.get(2).map(|m| &s[m.range()]),
43+
modifier: c.get(3).map(|m| &s[m.range()]),
44+
})
45+
})
46+
.as_ref()
47+
.unwrap_or(&Self {
48+
lang: None,
49+
country: None,
50+
modifier: None,
51+
})
52+
}
53+
54+
pub fn keys(&self) -> impl Iterator<Item = impl AsRef<str>> + '_ {
55+
static LOCALE_ITERS: OnceCell<Vec<String>> = OnceCell::new();
56+
LOCALE_ITERS
57+
.get_or_init(|| {
58+
let mut v = vec![];
59+
if let Some(((l, c), m)) = self.lang.zip(self.country).zip(self.modifier) {
60+
v.push(format!("{}_{}@{}", l, c, m));
61+
}
62+
if let Some((l, c)) = self.lang.zip(self.country) {
63+
v.push(format!("{}_{}", l, c));
64+
}
65+
if let Some((l, m)) = self.lang.zip(self.modifier) {
66+
v.push(format!("{}@{}", l, m));
67+
}
68+
if let Some(l) = self.lang {
69+
v.push(l.to_string());
70+
}
71+
72+
v
73+
})
74+
.clone()
75+
.into_iter()
76+
}
77+
}

0 commit comments

Comments
 (0)