Implement most of the fluent localisation system

This commit is contained in:
Olivier 'reivilibre' 2023-03-01 21:21:14 +00:00
parent 0370de40a1
commit 475f9bc55e
2 changed files with 78 additions and 4 deletions

View File

@ -40,6 +40,18 @@ pub enum Value {
Reflective(Box<dyn Reflect>), Reflective(Box<dyn Reflect>),
} }
impl Value {
pub fn get_type_name(&self) -> String {
String::from(match self {
Value::Str(_) => "Str",
Value::Int(_) => "Int",
Value::Bool(_) => "Bool",
Value::List(_) => "List",
Value::Reflective(reflective) => reflective.type_name(),
})
}
}
lazy_static! { lazy_static! {
static ref U8_TYPEID: TypeId = TypeId::of::<u8>(); static ref U8_TYPEID: TypeId = TypeId::of::<u8>();
static ref U16_TYPEID: TypeId = TypeId::of::<u16>(); static ref U16_TYPEID: TypeId = TypeId::of::<u16>();

View File

@ -4,19 +4,81 @@
use crate::engine::Value; use crate::engine::Value;
use crate::interface::LocalisationSystem; use crate::interface::LocalisationSystem;
use fluent_templates::fluent_bundle::types::FluentNumber;
use fluent_templates::fluent_bundle::FluentValue;
use fluent_templates::loader::langid;
use fluent_templates::{ArcLoader, LanguageIdentifier, Loader};
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::BTreeMap; use std::collections::{BTreeMap, HashMap};
pub struct FluentLocalisationSystem {} use thiserror::Error;
fn interpreter_value_to_fluent_value(v: &Value) -> Option<FluentValue> {
match v {
Value::Str(str) => Some(FluentValue::String(Cow::Borrowed(&str))),
Value::Int(int) => {
// This is an unstyled number
// TODO Support fancier numbers
Some(FluentValue::Number(FluentNumber::from(int)))
}
Value::Bool(_) => {
// TODO I can't believe there's no way to expose this to fluent!
None
}
Value::List(_) => None,
Value::Reflective(_) => None,
}
// TODO It might be good to support a `struct` type here with fancier numbers
// or to support FluentNumber types directly, then expose functions to Hornbeam
// templates to create them?
}
pub struct FluentLocalisationSystem {
pub fluent: ArcLoader,
}
impl FluentLocalisationSystem {}
#[derive(Error, Clone, Debug)]
pub enum FluentLocalisationError {
#[error("no translation found for {trans_key} in {lang_id}")]
NoTranslation { trans_key: String, lang_id: String },
#[error("can't convert param {param_name} of type {param_type} to a fluent type")]
IncompatibleValue {
param_name: String,
param_type: String,
},
}
impl LocalisationSystem for FluentLocalisationSystem { impl LocalisationSystem for FluentLocalisationSystem {
type Error = (); type Error = FluentLocalisationError;
fn lookup( fn lookup(
&self, &self,
trans_key: &str, trans_key: &str,
params: &BTreeMap<&str, Value>, params: &BTreeMap<&str, Value>,
) -> Result<Cow<str>, Self::Error> { ) -> Result<Cow<str>, Self::Error> {
todo!() let li: LanguageIdentifier = langid!("en-GB"); // TODO get the language tag from somewhere
let mut mapped_params = HashMap::with_capacity(params.len());
for (&k, v) in params {
if let Some(mapped_val) = interpreter_value_to_fluent_value(v) {
mapped_params.insert(k, mapped_val);
} else {
return Err(FluentLocalisationError::IncompatibleValue {
param_name: String::from(k),
param_type: v.get_type_name(),
});
}
}
match self.fluent.lookup_with_args(&li, trans_key, &mapped_params) {
Some(val) => Ok(Cow::Owned(val)),
None => {
return Err(FluentLocalisationError::NoTranslation {
trans_key: String::from(trans_key),
lang_id: li.to_string(),
});
}
}
} }
} }