Handlebars helper for i18n of templates using Fluent

The other day I made a handlebars helper based on fluent (available on npm). This allows localization of any template (websites, documents, etc.) that is either already using Handlebars where it can be added as a pre-processing step. My use case was localizing bits of Markdown documents before passing them to Pandoc, but there could be lots of other uses.

The Handlebars usage is pretty basic, the language and any other context variables are passed from Handlebars to Fluent along with the key to be translated, you could have data coming from one place and translations from another.

Just mentioning this here because before I made it I looked here for it and found nothing…maybe this will help some other poor soul.

Thanks for letting us know.

This is similar to what @Manish did in https://github.com/rust-lang/www.rust-lang.org/blob/master/src/i18n.rs?

Axel

That code is somewhat opaque to me (and yes I know @Manish could code me into a corner) but it looks like that is more of a wrapper around Handlebars (or a Rust implementation of it, not the Javascript original) rather than a helper working inside it and extending it. Is there a template somewhere that shows both data substitutions using Handlebars and localization in the same template?

Nah, that’s a handlebars helper not a wrapper. But yes, it uses the rust implementation of handlebars since the website is written in . It handles a bunch of things (the ability to have parameters, fallback, block vs inline) so it gets a bit complex.

Here’s a template using inline helpers, and here’s one using block helpers

The difference between your helper and mine is:

  • language selection is coded in a less reusable way in mine (but I plan to split this out)
  • I use {{text}} not {{fluent}}
  • you support {{text foo.bar}} , we do not. If I make this into a separate crate I probably would
  • we have a block form of the helper which works as {{#text foo}}{{#textparam bar}}blah{{/textparam}}{{/text}}

Overall not too different. At some point I’ll publish a crate for this helper and probably use {{fluent}} instead of {{text}}.

I do suggest adding a block helper, we had cases where we needed to interpolate something big in a large block of text, like a code sample, and it helps to not have to shove everything into a string.

Thanks for the dissection @Manish. I’ll look into adding a block helper. I thought about it already but didn’t have a use case for it hovering over me so I went ahead without. That being said since I still don’t have a use case it would be helpful to see one broken down it a little more detail.

Was there a specific reason you chose not to support attributes? Does your implementation support passing variables the same way, i.e. {{text welcome name="World"}})?

The other question I have at least in your explanation is whether you require the key to be a string ({{text "foo"}} or whether you were able to just parse it as whatever ({{text foo}}). I ran into a problem with the latter but it might have been less a Handlebars issue and more a Javascript issue.

I’d be happy to adjust my implementation so they are as consistent as possible. Since I’m the only one (I know of) that has it deployed the sooner the better :wink: .

Here’s one, rendered here. Both the ASCII file tree and the cargo run output are interpolated in this string.

Was there a specific reason you chose not to support attributes?

Didn’t need it for the website. The Rust handlebars implementation makes attributes a bit tricky to deal with; still totally doable, but not worth the effort if I’m only doing this for the website.

Does your implementation support passing variables the same way, i.e. {{text welcome name="World"}} )?

Yes

The other question I have at least in your explanation is whether you require the key to be a string ( {{text "foo"}} or whether you were able to just parse it as whatever ( {{text foo}} )

Only {{text foo}} works right now. This extends well to potential attribute support, since handlebars allows for {{text foo.bar}} syntax, I just haven’t added it.

We could also support strings without any ambiguity. It is cleaner to use paths so I did.

I think settling on {{fluent foo baz="quux"}}, {{fluent foo.bar baz="quux"}} with additional parsing for {{fluent "foo" baz="quux"}} would be really awesome, if we can both make it work. Plus a block mode version (probably use {{#fluentparam}}) if you think it’s necessary.

1 Like

Hey Manish please see my comment on Github. Plain keys that get passed as a string value appears to be impossible on the Javascript side and every helper I could find requires quoted strings. Unless I’m missing something there I’m going to recommend the Rust helper be adjusted to conform to that norm so that the end user template syntax is the same across implementations.

Note I have implemented a block version of the helper including {{#fluentparam}} to set data values that get used in their parent {{#fluent}} context as discussed. One step closer to parity.