projectfluent / fluent-rs

Rust implementation of Project Fluent
https://projectfluent.org
Apache License 2.0
1.08k stars 97 forks source link

How can I clone FluentBundle<FluentResource>? #200

Closed kotovalexarian closed 3 years ago

kotovalexarian commented 3 years ago

Hello. I'm trying to use Fluent in my Rocket web application. I need to access bundle in multiple places:

I can use bundle in Rocket threads with fluent_bundle::concurrent::FluentBundle. However, I can't use it in template helper because it doesn't implement Clone trait. Also I'm not sure how ofter will clone be performed. Maybe that's because of poorly designed architecture of Rocket and/or Handlebars.

How can I solve this?

UPD. This is what I try to do:

error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
  --> src/web.rs:28:26
   |
28 |                    Box::new(|
   |   _________________-________^
   |  |_________________|
   | ||
29 | ||                     _: &Helper,
30 | ||                     _: &Handlebars,
31 | ||                     _: &Context,
...  ||
35 | ||                     i18n;
   | ||                     ---- closure is `FnOnce` because it moves the variable `i18n` out of its environment
36 | ||                     Ok(())
37 | ||                 }),
   | ||_________________^- the requirement to implement `Fn` derives from here
   |  |_________________|
   |                    this closure implements `FnOnce`, not `Fn`
kotovalexarian commented 3 years ago

I've solved the problem with std::sync::Arc, so I close the issue. Sorry for my poor experience with Rust.

pub fn translate(i18n: std::sync::Arc<I18n>) -> Box<dyn HelperDef> {
    Box::new(move |
        helper: &Helper,
        _: &Handlebars,
        _: &Context,
        _: &mut RenderContext,
        output: &mut dyn Output,
    | -> HelperResult {
        let locale = helper.param(0)
            .ok_or(RenderError::new("expected locale param"))?
            .value().as_str()
            .ok_or(RenderError::new("expected locale param"))?;

        let key = helper.param(1)
            .ok_or(RenderError::new("expected key param"))?
            .value().as_str()
            .ok_or(RenderError::new("expected key param"))?;

        let i18n = i18n.clone();

        let l10n = i18n.l10n(locale).ok()
            .ok_or(RenderError::new("unknown locale"))?;

        let translated = l10n.translate(key).ok()
            .ok_or(RenderError::new("translation error"))?;

        output.write(&translated)?;

        Ok(())
    })
}