askama icon indicating copy to clipboard operation
askama copied to clipboard

Internationalization (i18n)

Open Deedasmi opened this issue 6 years ago • 26 comments

I'm loving askama so far, but I'm trying to build my first real web app 'the right way', and support localization from the start. I've never worked on localization before, nor with a parser.

The three main approaches I've come across are:

  1. Static pages for each language. Would need multiple-path support in Askama. Not the most elegant.
  2. String replacement, ala gettext. Jinja appears to best support this style: http://jinja.pocoo.org/docs/2.10/extensions/.
  3. Project fluent, with all it's fancy terms, attributes, functions, etc. Probably out of scope?

2 is probably the most reasonable solution, and staying jinja-like would probably be beneficial. Would it make sense for askama to support some type gettext like function?

Deedasmi avatar Jan 18 '19 12:01 Deedasmi

As far as I knew Fluent represents some really advanced thinking about localization and also has a Rust implementation. So to me doing localization "the right way" in Askama would imply at least knowing what a Fluent integration would look like, and how much complexity it would take to do (and how hard it would be for our users).

From what I've seen, gettext may look simpler but also gets complex in the end.

djc avatar Jan 18 '19 13:01 djc

Fluent actually has quite a simple rust API, most of the complexity is in the implementation: https://docs.rs/fluent-bundle/0.5.0/fluent_bundle/

Essentially, you create a FluentBundle, which represents a set of known translations + a locale, and initialize it by passing in strings in the FTL language; these strings can be loaded from a file or embedded in the executable. Then, you can call bundle.format("message-name", parameters) to get a translated string. parameters can be None or Some(HashMap<&str, FluentValue> { ... }). FluentValue is a simple Number / String enum.

You can also do bundle.format("message-name.attribute", parameters) to access fluent's attributes, which basically just function as little namespaces.

The main impedance mismatch here is that fluent operates at runtime and not compile-time. I could imagine doing some compile-time verification -- checking that the input FTL files parse, maybe even type-checking the messages used in templates -- but you'll still need to actually load and execute the templates at runtime.

Ideally there could be an i18n(locale, message[.attribute], params...) filter + some way to point askama at a directory of localizations, which would be compiled into the target executable. Maybe a proc macro you call in your application crate, similar to #[derive(Template)]?

I'd be happy to work on this in the next few weeks, although I'd need some help since I don't know askama very well :)

kazimuth avatar Feb 11 '19 23:02 kazimuth

Sounds great! Happy to answer questions and provide guidance/feedback on design and implementation.

Having such a filter sounds good to me, the directory also make sense. We could take a similar approach to the templates dir, in that we could have a sane default (i18n?) and a way to change that in configuration.

Not sure yet what you'd need the proc macro for.

djc avatar Feb 12 '19 05:02 djc

Proc macro would let you run compile-time instead of runtime checks on the fluent files. Could be overkill, but I've always thought there's no such thing as too much safety in Rust :)

kazimuth avatar Feb 14 '19 10:02 kazimuth

My PR adds initial support for i18n using Fluent but the Fluent API currently has some issues. Once:

  • https://github.com/projectfluent/fluent-rs/issues/94
  • https://github.com/projectfluent/fluent-rs/issues/88

are addressed, it'll be worth doing another pass. I don't think the i18n API will need to change on askama's end, but it should give users better performance and more support for locale fallback chains.

kazimuth avatar Mar 09 '19 22:03 kazimuth

Most of the relevant code's been moved over here to its own crate, which is almost ready to release. I just want to get askama and rocket working first.

@djc, we can do the integration from either end: we could re-export baked_fluent from askama + add custom codegen to support it, or expose add a filter compatible with askama to baked_fluent. The only thing is that we'd need support for some sort of keyword arguments in filters if we wanted to do it that way.

kazimuth avatar May 13 '19 03:05 kazimuth

Do you have a preference? Either way is fine, really, though my intuitive preference is to have the filter living in askama, since it is an important feature to me.

djc avatar May 13 '19 07:05 djc

I'll open a PR to add support on this end.

Only real issue I see is making sure people can find the docs; I can just duplicate them in the rustdoc over here though.

kazimuth avatar May 14 '19 02:05 kazimuth

@kazimuth what's the status on this? Have you got it working for your own application?

djc avatar Jun 09 '19 18:06 djc

Ah, some life stuff came up. Plus the job I was going to be using this for fell through, so I haven't been working on it much :/

baked_fluent is nearly ready for release, I just wanna get Rocket support working then i'll throw it on crates.io.

All that's needed on this end is the parser + codegen changes from my previous PR, and a reexport of the impl_localize! macro from baked_fluent, plus some doc additions. I may have some time to work on that later this week.

kazimuth avatar Jun 09 '19 19:06 kazimuth

@kazimuth did you have time to work on this?

Weasy666 avatar Jul 24 '19 17:07 Weasy666

Baked_fluent is pretty much functional, i think i'll release it soon. I don't have the bandwidth for an askama integration, unfortunately; if someone's interested in writing that i can provide some tips.

kazimuth avatar Jul 24 '19 17:07 kazimuth

Ah...cool. Thanks for the info.

Weasy666 avatar Jul 24 '19 17:07 Weasy666

@djc Do you have an overview of the current status of this? I have found following PR's / repo's:

  • https://github.com/djc/askama/pull/211 (seemed good, but needed rebasing etc?, Talks about new PR's, only found 1?)
  • https://github.com/djc/askama/pull/237 (talks about a new repo)
  • https://github.com/kazimuth/baked_fluent (has never really finished?)

I am right if I say that the localization feature has not been finished yet? What would be the best way forward for this, in your opinion?

jhoobergs avatar Jan 11 '21 16:01 jhoobergs

You've found basically all there is to find -- that's the latest state as far as I'm aware.

So moving forward, it'd probably be best to maybe fork baked_fluent (assuming that's allowed per its license) and then revive something like #237 to start integrating it with Askama? I'd be happy to mentor someone (you?) through doing the work!

djc avatar Jan 11 '21 21:01 djc

I would like to try it. I'll try getting started tomorrow.

jhoobergs avatar Jan 11 '21 21:01 jhoobergs

Don't hesitate to ask questions, here or on Matrix/Gitter!

djc avatar Jan 11 '21 22:01 djc

Hi, I know this is an old topic but I haven't found anything newer than this issue. What is the current state on this topic? Since I want to build a web app using Askama for templating but I also need Internationalization. I looked at Tera since it can be used with Fluent but I don't like that it serializes structs into JSON and this just doesn't work for my use case. Is there any way to use Fluent or some other crate?

The way I would do it is I guess kinda hacky but I figured I can just add a field to all my structs like this:

#[derive(Template)]
#[template(path = "test.html")]
pub struct User<'a> {
   ...
   username: &'a str,
   fluent:  &'a  FluentBundle<FluentResource>,
}

and in the template call user.fluent.get_message("hello-world")

89Q12 avatar Jun 13 '22 20:06 89Q12

Have a look at #434.

djc avatar Jun 13 '22 20:06 djc

Okay, so I updated the code from the #434(all tests pass) and added the changes you suggested in this comment, the only thing left todo is to sperate it out into its own feature that can be included since I don't think everyone needs or wants fluent deps in their project.

Once I did that I would open a new PR to get this feature done if that is still in scope/wanted?

But that might take me a few days since I'm fairly new to the ecosystem.

89Q12 avatar Jun 15 '22 12:06 89Q12

Yeah, would be great if you can turn that into a new PR, definitely still wanted! No hurry.

djc avatar Jun 15 '22 12:06 djc

After rebasing and refactoring the code, as well as addressing various review questions, CI is now all green again. If there is time, then a renewed review would be highly appreciated!

LeoniePhiline avatar Oct 11 '22 20:10 LeoniePhiline

After rebasing and refactoring the code, as well as addressing various review questions, CI is now all green again. If there is time, then a renewed review would be highly appreciated!

So it never happened and i18n support is still not working?

makorne avatar Jan 06 '24 10:01 makorne

@makorne Have a look at #841 and its related PRs^^

89Q12 avatar Jan 06 '24 10:01 89Q12