google / mdbook-i18n-helpers

Translation support for mdbook. The plugins here give you a structured way to maintain a translated book.
Apache License 2.0
127 stars 25 forks source link

Create mdbook-tera-backend renderer #80

Closed sakex closed 10 months ago

sakex commented 12 months ago

Here is the prototype, it does almost everything we want already, I just need to port the actual LanguagePicker

You can see that the code to create a custom component is pretty straightforward (see the test component in src/custom_components/test_component.rs).

You can check the test in src/custom_component_renderer/book_directory_renderer.rs to see how it all works.

Fixes #70.

mgeisler commented 12 months ago

Hey @sakex, thanks for putting this up! I think my only major concern is how people (myself included! 🙂) will create and modify the custom components?

I had hoped they would be defined in the theme, just like I see Tera allows you to create new macros in a template file.

I feel this is crucial since I need a way of looking at the output when modify the templates. So I need to be able to run mdbool serve and see the output right away.

sakex commented 12 months ago

A separate custom-made component is definitely doable.

It could look like

book.toml

[output.i18-helper.components]
MyCustomComponent = "path/to/comp.html"
comp.html

<div>
some stuff in there, maybe tera templates too
</div>
index.html
...
<MyCustomComponent />
...
sakex commented 12 months ago

Because in my test component, I'm generating the HTML using DOM manipulations with the scraper crate. But we don't have to do it that way, we can also do HTML::parse on a string and then inject the parsed node to the original tree.

sakex commented 12 months ago

For complex and common components, we will create them inside of the crate. Otherwise, users will be able to create their own. I'll add that feature in a further CL though, if that works for you.

LanguagePicker should definitely live here for instance. Also I'd really like to create an <ExercizeCodeBlock /> and a <WasmCodeBlock /> in the future. Because the components created here don't need to be used in the template, they can also be added to the markdown directly

mgeisler commented 12 months ago

A separate custom-made component is definitely doable.

It could look like

book.toml

[output.i18-helper.components]
MyCustomComponent = "path/to/comp.html"
comp.html

<div>
some stuff in there, maybe tera templates too
</div>

This is the main question: how do I create a component with custom logic? With loops, variables, if statements, etc? I have the impression that I need to write Rust code for that?

I liked using Tera much more: there we can keep our code to a minimum. I don't really like code: more code is normally more trouble :smile: Put differently, I don't want us to maintain a template system here. Pushing all logic to the template library should make our life easier.

It also makes things clearer for downstream users: just modify index.hbs to hook in the call that loads a macro from mdbook-i18n-helpers.html and then use those macros where you like. I think it would even be possible to let downstream users override parts of the macros using the inheritance system in Tera, but I'm not 100% sure.

sakex commented 12 months ago

Let's do it that way then, I think it will look pretty goodOn Sep 16, 2023 16:54, Martin Geisler @.***> wrote:

A separate custom-made component is definitely doable. It could look like book.toml

[output.i18-helper.components] MyCustomComponent = "path/to/comp.html"

comp.html

some stuff in there, maybe tera templates too

This is the main question: how do I create a component with custom logic? With loops, variables, if statements, etc? I have the impression that I need to write Rust code for that? I liked using Tera much more: there we can keep our code to a minimum. I don't really like code: more code is normally more trouble 😄 Put differently, I don't want us to maintain a template system here. Pushing all logic to the template library should make our life easier. It also makes things clearer for downstream users: just modify index.hbs to hook in the call that loads a macro from mdbook-i18n-helpers.html and then use those macros where you like. I think it would even be possible to let downstream users override parts of the macros using the inheritance system in Tera, but I'm not 100% sure.

—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you were mentioned.Message ID: @.***>

sakex commented 11 months ago

@mgeisler I have implemented all the features we wanted (load template, dependencies, attributes from HTML).

You can see an example in action there:

https://github.com/google/comprehensive-rust/pull/1216

sakex commented 11 months ago

We are missing documentation, I will add it after we've finalized the conversation. I will also create a book inside of this repository for testing purposes in a future CL

mgeisler commented 11 months ago

Hey @sakex, thanks for putting this up! I think it is simpler than before, but I still think it can become even simpler.

We are missing documentation, I will add it after we've finalized the conversation. I will also create a book inside of this repository for testing purposes in a future CL

I see many new files introduced here with lots of Rust code. This raises questions for me:

In my mind, the "shape" of a new renderer should be so that it

When I see more code than this, I conclude that the renderer does more than it has to do.

As an example, I would expect the work in #84 to build on top of such a bare-bones renderer by supplying it with template macros that know about i18n. The backend that runs mdbook build for every language must know about i18n, but the mdbook-tera-backend must not. That is really the test which checks if the design is loosely coupled and if the components are reusable.

sakex commented 11 months ago

Hey @sakex, thanks for putting this up! I think it is simpler than before, but I still think it can become even simpler.

We are missing documentation, I will add it after we've finalized the conversation. I will also create a book inside of this repository for testing purposes in a future CL

I see many new files introduced here with lots of Rust code. This raises questions for me:

  • How will other projects use this? Remember that the new backend is a binary for them, so they cannot extend it with Rust code. They cannot implement the trait you define so it seems they cannot create new custom components?

There is no trait anymore, everything is done via templates. Please take a look at https://github.com/google/comprehensive-rust/pull/1216

  • Why do we need a custom component?

It's a struct not a trait, just an internal that let people define their new components

It is, please take a look at https://github.com/google/comprehensive-rust/pull/1216

  • If it does not support this, then we should not use Tera. Those two issues are the high-priority goals of writing a new rendering engine. They are the only reason we care to write code for this 🙂

In my mind, the "shape" of a new renderer should be so that it

  • only depends on tera or any other template engine (no HTML parsing needed).

The HTML part is a very low amount of code, but it makes the template system much cleaner, wrapping tera in handlebars just looks very bad. I have tried, and I don't think that many people will want to put up with it.

  • doesn't know anything about i18n.

It doesn't

  • lets users (including us) build up a vocabulary of commonly used functions in the template language (not Rust). I imagine this simply means that the user tells you about a directory where the template macros live. You then add that to an include path and the user can then define everything in there.

Look at https://github.com/google/comprehensive-rust/pull/1216, there are macros and includes supported

When I see more code than this, I conclude that the renderer does more than it has to do.

As an example, I would expect the work in #84 to build on top of such a bare-bones renderer by supplying it with template macros that know about i18n. The backend that runs mdbook build for every language must know about i18n, but the mdbook-tera-backend must not. That is really the test which checks if the design is loosely coupled and if the components are reusable.

mgeisler commented 11 months ago

Hey @sakex, please add docstrings to all functions — explain why the function is there and how they fit into the bigger picture.

sakex commented 10 months ago

@mgeisler tests added

mgeisler commented 10 months ago

@mgeisler tests added

Thank you, this helps a lot in the confidence as we refactor this going forward.