Want to contribute? Fork me on Codeberg.org!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

108 lines
2.7 KiB

use derive_more::From;
use rocket_dyn_templates::tera::{self, Value};
use serde::Serialize;
2 years ago
use std::{
collections::HashMap,
fs::{self, File},
io::BufReader,
process::Command,
};
use gettext::Catalog;
#[derive(From, Debug)]
pub enum LoadCatalogsError {
Io(std::io::Error),
Parse(gettext::Error),
MissingDefaultLanguage,
}
pub const DEFAULT: &str = "ja";
type Catalogs = HashMap<String, Catalog>;
pub fn load_catalogs() -> Result<(Catalogs, Vec<LangCode>), LoadCatalogsError> {
let mut catalogs = HashMap::new();
for file in fs::read_dir("i18n")? {
let file = file?;
let path = file.path();
2 years ago
if !file.file_type()?.is_file()
|| !path
.extension()
.map(|extension| extension.eq("po"))
.unwrap_or(false)
{
continue;
}
let language_code = path
.file_stem()
.expect("Invalid translation file name")
.to_string_lossy()
.to_string();
let po_file_path = path;
let mo_file_path = format!("i18n/{}.mo", language_code);
Command::new("msgfmt")
.arg(&po_file_path)
.arg("-o")
.arg(&mo_file_path)
.output()?;
2 years ago
catalogs.insert(
language_code,
Catalog::parse(BufReader::new(File::open(mo_file_path)?))?,
);
}
if !catalogs.contains_key(DEFAULT) {
return Err(LoadCatalogsError::MissingDefaultLanguage);
}
let langs = catalogs
.iter()
2 years ago
.map(|(code, catalog)| LangCode {
code: code.clone(),
name: catalog.gettext("lang").to_owned(),
})
.collect();
Ok((catalogs, langs))
}
2 years ago
pub fn i18n_filter(
value: &Value,
args: &HashMap<String, Value>,
catalogs: &Catalogs,
2 years ago
) -> tera::Result<Value> {
let key = value
.as_str()
.ok_or_else(|| tera::Error::msg("The translation key must be a string"))?;
let langs = args
.get("lang")
.and_then(|value| value.as_array())
.map(|array| {
let mut langs = Vec::with_capacity(array.len());
for lang in array {
langs.push(lang.as_str().unwrap());
}
langs
})
.unwrap_or_else(|| vec![DEFAULT]);
for lang in langs {
if let Some(catalog) = catalogs.get(lang) {
return Ok(Value::String(catalog.gettext(key).to_owned()));
}
}
panic!("Missing catalog");
}
#[derive(Serialize)]
pub struct LangCode {
pub code: String,
pub name: String,
}
pub fn langs_filter(
_value: &Value,
_args: &HashMap<String, Value>,
langs: &Vec<LangCode>,
) -> tera::Result<Value> {
Ok(serde_json::to_value(langs).unwrap())
2 years ago
}