CloudCannon / rosey

:rose: Open-source CLI tool for managing translations on static websites.
MIT License
41 stars 0 forks source link

How to handle javascript templates of hydrated components? #28

Open daKmoR opened 1 year ago

daKmoR commented 1 year ago

Question

How would you recommend handling javascript templates of hydrated components?

Description

Let's look at a concrete simplified example Note: this example uses Declarative Shadow Dom which is currently only supported in chromium browsers

πŸ‘‰ index.html

<h1 data-rosey="intro">Let's start</h1>

<say-hi>
  <template shadowroot="open">
    <p data-rosey="welcome">welcome</p>
  </template>
</say-hi>

<button>hydrate</button>

this html can be translated by rosey and could for example look like this in German

πŸ‘‰ index.html

<h1 data-rosey="intro">Lass uns anfangen</h1>

<say-hi>
  <template shadowroot="open">
    <p data-rosey="welcome">Willkommen</p>
  </template>
</say-hi>

<button>hydrate</button>

but now let's say we need to hydrate this say-hi component as it for example tracks how often users hover over the welcome message...

e.g. we need to hydrate the component and it comes with the "template" (again) but that template is not touched by rosey right?

It could look something like this

class SayHi extends HTMLElement {
  connectedCallback() {
    this.shadowRoot.innerHTML = `<p data-rosey="welcome">welcome</p>`;
    // For example: tracking how many people hover the welcome text 
    // this.addEventListener('hover', () => // api call for tracking);
  }
}
document.querySelector('button').addEventListener('click', () => {   
  customElements.define('say-hi', SayHi);
});

You can see it live in action in this codepen https://codepen.io/daKmoR/pen/abKmoxG?editors=1010

so as soon as we hit this hydrate button we will "lose" the translation and the text will become

Lass uns anfangen welcome

Ideas

Puh yeah... as html can be created in all kind of forms within a javascript (web) component it's probably hard/impossible to correctly extract/modify...

Also adjusting and creating duplicate JS is probably also hard "after" it has already been optimized by a bundler πŸ€”

I mean there are project for lit web components which come with some rules/limitation e.g. only declarative html, ...

https://lit.dev/docs/localization/overview/

Maybe it could be combined somehow... πŸ€”

What are your thoughts on this?

bglw commented 1 year ago

πŸ‘‹ Hello @daKmoR!

This is an area we're keen to start looking at, but we haven't done any particular scoping on it yet β€” lots of questions as to how it might best be done! It's a pertinent question for many new not-quite-static stacks that we would like to support, e.g. Next, SvelteKit, Astro.

Most likely the best path would be for Rosey to provide some JS API to the site that allows it to register/retrieve translations. Registering a translation is the harder problem, since Rosey currently performs what is essentially a static analysis of a website to extract the data-rosey tags. To integrate into this flow, Rosey would need to perform a static analysis of the JS to find all translation strings.

The direction I've been looking to investigate might look like the following:

import roseyTranslate from "rosey";

...

this.shadowRoot.innerHTML = `<p>${roseyTranslate({ key: "welcome", original: "welcome" })}</p>`;

...

Where the rosey CLI can discover these function calls and integrate those keys into its existing flow, such that the final output site can call the roseyTranslate function and get the welcome key as expected.

Still lots of scoping to do here, the bundler minification process for example throws a large spanner in the works for making this JS discoverable, which might require a different approach altogether.

So nothing to report yet, but open to further thoughts!