Properly support multiple languages
This commit is contained in:
parent
811c06f5f8
commit
1256fef318
@ -38,16 +38,10 @@ async fn main() -> eyre::Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn say_hello(Path((_lang, name)): Path<(String, String)>) -> impl IntoResponse {
|
async fn say_hello(Path((lang, name)): Path<(String, String)>) -> impl IntoResponse {
|
||||||
// TODO This should be translated with Fluent!
|
Rendered(render_template_string!(TEMPLATING, say_hello, lang, {
|
||||||
|
|
||||||
//let template = templates.prepare("say_hello", None, Params::default().set("name", name));
|
|
||||||
|
|
||||||
Rendered(render_template_string!(TEMPLATING, say_hello, "en-GB", {
|
|
||||||
name: name
|
name: name
|
||||||
}))
|
}))
|
||||||
|
|
||||||
// HtmlTemplate(template)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Rendered(Result<String, hornbeam::TemplateError>);
|
struct Rendered(Result<String, hornbeam::TemplateError>);
|
||||||
|
1
demo_hornbeam_project/translations/fr-FR/say_hello.ftl
Normal file
1
demo_hornbeam_project/translations/fr-FR/say_hello.ftl
Normal file
@ -0,0 +1 @@
|
|||||||
|
hello = Bonjour { $name } !
|
@ -10,7 +10,6 @@ use hornbeam_interpreter::localisation::fluent::{
|
|||||||
FluentLocalisationError, FluentLocalisationSystem,
|
FluentLocalisationError, FluentLocalisationSystem,
|
||||||
};
|
};
|
||||||
use hornbeam_interpreter::{InterpreterError, LoadedTemplates};
|
use hornbeam_interpreter::{InterpreterError, LoadedTemplates};
|
||||||
use notify::Watcher;
|
|
||||||
use std::convert::Infallible;
|
use std::convert::Infallible;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
@ -23,7 +22,6 @@ pub use hornbeam_interpreter::Params;
|
|||||||
|
|
||||||
use crate::interpreted::hot_reload::start_hot_reloader;
|
use crate::interpreted::hot_reload::start_hot_reloader;
|
||||||
pub use lazy_static::lazy_static;
|
pub use lazy_static::lazy_static;
|
||||||
use tokio::io;
|
|
||||||
|
|
||||||
#[cfg(feature = "hot_reload")]
|
#[cfg(feature = "hot_reload")]
|
||||||
pub mod hot_reload;
|
pub mod hot_reload;
|
||||||
@ -174,7 +172,7 @@ macro_rules! render_template_string {
|
|||||||
// TODO LOCALE
|
// TODO LOCALE
|
||||||
{
|
{
|
||||||
let manager = $manager.load();
|
let manager = $manager.load();
|
||||||
let prepared = manager.prepare(stringify!($template_name), None, $crate::interpreter_params!{ $($params)* });
|
let prepared = manager.prepare(stringify!($template_name), None, $crate::interpreter_params!{ $($params)* }, $locale);
|
||||||
let finished_string = prepared.render_to_string();
|
let finished_string = prepared.render_to_string();
|
||||||
if $crate::is_hot_reload_enabled() {
|
if $crate::is_hot_reload_enabled() {
|
||||||
// Hacky, but inject the auto-hot-reloader into the page :P
|
// Hacky, but inject the auto-hot-reloader into the page :P
|
||||||
|
@ -28,6 +28,7 @@ pub(crate) struct Interpreter<'a, O, LS> {
|
|||||||
pub(crate) program: &'a BTreeMap<String, Arc<Vec<Step>>>,
|
pub(crate) program: &'a BTreeMap<String, Arc<Vec<Step>>>,
|
||||||
pub(crate) output: O,
|
pub(crate) output: O,
|
||||||
pub(crate) localisation: Arc<LS>,
|
pub(crate) localisation: Arc<LS>,
|
||||||
|
pub(crate) locale: String,
|
||||||
pub(crate) scopes: Vec<Scope<'a>>,
|
pub(crate) scopes: Vec<Scope<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -577,7 +578,7 @@ impl<'a, O: OutputSystem + Send, LS: LocalisationSystem + Sync + Send> Interpret
|
|||||||
|
|
||||||
let localised_text = self
|
let localised_text = self
|
||||||
.localisation
|
.localisation
|
||||||
.lookup(trans_key, ¶meters_evaluated)
|
.lookup(trans_key, ¶meters_evaluated, &self.locale)
|
||||||
.map_err(|underlying| InterpreterError::Localisation {
|
.map_err(|underlying| InterpreterError::Localisation {
|
||||||
underlying,
|
underlying,
|
||||||
trans_key: (trans_key as &str).to_owned(),
|
trans_key: (trans_key as &str).to_owned(),
|
||||||
|
@ -24,6 +24,7 @@ pub trait LocalisationSystem {
|
|||||||
&self,
|
&self,
|
||||||
trans_key: &str,
|
trans_key: &str,
|
||||||
params: &BTreeMap<&str, Value>,
|
params: &BTreeMap<&str, Value>,
|
||||||
|
locale: &str,
|
||||||
) -> Result<Cow<str>, Self::Error>;
|
) -> Result<Cow<str>, Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,6 +149,7 @@ impl<'a, LS> LoadedTemplates<LS> {
|
|||||||
template_name: &str,
|
template_name: &str,
|
||||||
fragment_name: Option<&str>,
|
fragment_name: Option<&str>,
|
||||||
params: Params,
|
params: Params,
|
||||||
|
locale: String,
|
||||||
) -> PreparedTemplate<LS> {
|
) -> PreparedTemplate<LS> {
|
||||||
PreparedTemplate {
|
PreparedTemplate {
|
||||||
all_instructions: Arc::new(self.template_functions.clone()),
|
all_instructions: Arc::new(self.template_functions.clone()),
|
||||||
@ -158,6 +160,7 @@ impl<'a, LS> LoadedTemplates<LS> {
|
|||||||
},
|
},
|
||||||
variables: params,
|
variables: params,
|
||||||
localisation: self.localisation.clone(),
|
localisation: self.localisation.clone(),
|
||||||
|
locale,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -167,6 +170,7 @@ pub struct PreparedTemplate<LS> {
|
|||||||
pub(crate) entrypoint: String,
|
pub(crate) entrypoint: String,
|
||||||
pub(crate) variables: Params,
|
pub(crate) variables: Params,
|
||||||
pub(crate) localisation: Arc<LS>,
|
pub(crate) localisation: Arc<LS>,
|
||||||
|
pub(crate) locale: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<LS: LocalisationSystem + Sync + Send> PreparedTemplate<LS> {
|
impl<LS: LocalisationSystem + Sync + Send> PreparedTemplate<LS> {
|
||||||
@ -179,6 +183,7 @@ impl<LS: LocalisationSystem + Sync + Send> PreparedTemplate<LS> {
|
|||||||
program: &self.all_instructions,
|
program: &self.all_instructions,
|
||||||
output,
|
output,
|
||||||
localisation: self.localisation,
|
localisation: self.localisation,
|
||||||
|
locale: self.locale,
|
||||||
scopes: vec![Scope {
|
scopes: vec![Scope {
|
||||||
variables: self.variables.params,
|
variables: self.variables.params,
|
||||||
slots: Default::default(),
|
slots: Default::default(),
|
||||||
|
@ -18,6 +18,7 @@ impl LocalisationSystem for NoLocalisation {
|
|||||||
&self,
|
&self,
|
||||||
_trans_key: &str,
|
_trans_key: &str,
|
||||||
_params: &BTreeMap<&str, Value>,
|
_params: &BTreeMap<&str, Value>,
|
||||||
|
_locale: &str,
|
||||||
) -> Result<Cow<str>, Self::Error> {
|
) -> Result<Cow<str>, Self::Error> {
|
||||||
Err("No localisation support available.")
|
Err("No localisation support available.")
|
||||||
}
|
}
|
||||||
@ -34,6 +35,7 @@ impl LocalisationSystem for DebugLocalisationSystem {
|
|||||||
&self,
|
&self,
|
||||||
trans_key: &str,
|
trans_key: &str,
|
||||||
params: &BTreeMap<&str, Value>,
|
params: &BTreeMap<&str, Value>,
|
||||||
|
_locale: &str,
|
||||||
) -> Result<Cow<str>, Self::Error> {
|
) -> Result<Cow<str>, Self::Error> {
|
||||||
Ok(Cow::from(format!("@{trans_key}{{{params:?}}}")))
|
Ok(Cow::from(format!("@{trans_key}{{{params:?}}}")))
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ use crate::engine::Value;
|
|||||||
use crate::interface::LocalisationSystem;
|
use crate::interface::LocalisationSystem;
|
||||||
use fluent_templates::fluent_bundle::types::FluentNumber;
|
use fluent_templates::fluent_bundle::types::FluentNumber;
|
||||||
use fluent_templates::fluent_bundle::FluentValue;
|
use fluent_templates::fluent_bundle::FluentValue;
|
||||||
use fluent_templates::loader::langid;
|
|
||||||
use fluent_templates::{ArcLoader, LanguageIdentifier, Loader};
|
use fluent_templates::{ArcLoader, LanguageIdentifier, Loader};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
@ -60,6 +59,9 @@ pub enum FluentLocalisationError {
|
|||||||
#[error("no translation found for {trans_key} in {lang_id}")]
|
#[error("no translation found for {trans_key} in {lang_id}")]
|
||||||
NoTranslation { trans_key: String, lang_id: String },
|
NoTranslation { trans_key: String, lang_id: String },
|
||||||
|
|
||||||
|
#[error("bad language ID {lang_id:?}")]
|
||||||
|
BadLocale { lang_id: String },
|
||||||
|
|
||||||
#[error("can't convert param {param_name} of type {param_type} to a fluent type")]
|
#[error("can't convert param {param_name} of type {param_type} to a fluent type")]
|
||||||
IncompatibleValue {
|
IncompatibleValue {
|
||||||
param_name: String,
|
param_name: String,
|
||||||
@ -74,8 +76,14 @@ impl LocalisationSystem for FluentLocalisationSystem {
|
|||||||
&self,
|
&self,
|
||||||
trans_key: &str,
|
trans_key: &str,
|
||||||
params: &BTreeMap<&str, Value>,
|
params: &BTreeMap<&str, Value>,
|
||||||
|
locale: &str,
|
||||||
) -> Result<Cow<str>, Self::Error> {
|
) -> Result<Cow<str>, Self::Error> {
|
||||||
let li: LanguageIdentifier = langid!("en-GB"); // TODO get the language tag from somewhere
|
let li: LanguageIdentifier =
|
||||||
|
LanguageIdentifier::from_bytes(locale.as_bytes()).map_err(|_| {
|
||||||
|
FluentLocalisationError::BadLocale {
|
||||||
|
lang_id: locale.to_owned(),
|
||||||
|
}
|
||||||
|
})?;
|
||||||
let mut mapped_params = HashMap::with_capacity(params.len());
|
let mut mapped_params = HashMap::with_capacity(params.len());
|
||||||
for (&k, v) in params {
|
for (&k, v) in params {
|
||||||
if let Some(mapped_val) = interpreter_value_to_fluent_value(v) {
|
if let Some(mapped_val) = interpreter_value_to_fluent_value(v) {
|
||||||
|
Loading…
Reference in New Issue
Block a user