Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: LWC Localization Mechanism (Intl V2) #75

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft

Conversation

caridy
Copy link
Contributor

@caridy caridy commented Jan 25, 2023

@caridy caridy marked this pull request as draft January 25, 2023 00:59
Copy link
Contributor

@nolanlawson nolanlawson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great to me overall and it seems like a reasonable direction to go in. Adding a new parser and compiler output to support is painful, but it would address a real developer need.

Since Fluent is not a web standard though, I think we need to be super-cautious about this and ensure we're hitching our wagon to the right horse. Have we evaluated all alternatives? Are there any extensions to the syntax that are promising?

</template>
```

And a message file associated to the same template as follow:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we link to the Fluent spec you had in mind? I assume it's this one.

y.html
```

The way LWC can register these association is the same used for the default template, using `registerComponent`. Additionally, we must provide a way for a developer to import fluent dependencies declaratively using import declaration, the same way we allow importing templates. In this case, we must provide a new hook for the developer to return a custom fluent reference, in the same fashion that `render()` method works.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would simplify this to just say that a *.fluent file is associated with a co-located *.js file and must share the same name (e.g. foo.fluent for foo.js). AIUI there is no need to make explicit any relationship between the HTML files and the fluent files – the fluent files simply add properties to the component, and components can already have properties which are referenced by templates, so really we're just saying that the fluent file adds properties to the component.

Severing this relationship also avoids hairy questions like "What if a *.js file imports a *.html file from another directory?"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exactly! if the js exports a component (meaning it calls registerComponent), the fluent file can be associated at that point.

text/0000-intl-v2.md Outdated Show resolved Hide resolved

#### Connecting The Dots

When a component is about to be rendered, the engine must use the default associated fluent, if exist. If the hook is defined in user-land, it must be invoked to resolve the custom fluent reference. If the fluent reference is new, an internal fluent instance must be created, binding that instance to the component instance in question. The messages exported by the fluent instance must be made available via `i18n` getter on `LightningElement.prototype`. Each message exported from the fluent instance must be a getter, and must be constructed on demand when the message is accessed. This must be done prior to invocation of the template.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the hook is defined in user-land, it must be invoked to resolve the custom fluent reference.

What does this mean? Are you proposing something like programmatic style sheets, but for fluent files?

The messages exported by the fluent instance must be made available via i18n getter on LightningElement.prototype.

By this, I assume you mean that this.i18n.foo works, but this.template.querySelector('x-component').i18n.foo does not work, correct? In other words, i18n is only exposed to code inside the component, not outside the component?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the hook is defined in user-land, it must be invoked to resolve the custom fluent reference.

What does this mean? Are you proposing something like programmatic style sheets, but for fluent files?

I'm not sure anymore... if we are saying that this implicit association is sufficiently, then no. Let's think about it.

The messages exported by the fluent instance must be made available via i18n getter on LightningElement.prototype.

By this, I assume you mean that this.i18n.foo works, but this.template.querySelector('x-component').i18n.foo does not work, correct? In other words, i18n is only exposed to code inside the component, not outside the component?

Correct. Just like template.


### 2. Q: Do we need a reverse parser? from Fluent to Grammaticus? if someone were going to write a label as a Fluent message, how do we make sure this can be put through the grammaticus engine for translations?

Caridy: I don't think that should be the case for 1P, certain, we can lint 1P to make sure that everything that they use in the fluent file is either interpolation of existing entities or labels, or direct usage of entities and labels. For 2P/3P, the question remains.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the downside of dropping Grammaticus support entirely? In other words, what do we gain by adding Grammaticus support?

Based on my read of this post, Grammaticus is not directly exposed to component authors today; it is just used internally.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is the thing... for Admins, the UI to localize their app is backed up by the Grammaticus system in Java land. I will love to drop it entirely, but that's not going to happen. Keep in mind that neither Aura, LWR nor LWC has been able to integrate it yet.


### Prior Art

FormatJS, which relies of helpers and template literals to define the messages, and format the data. Our own implementation of the label system today, which promotes the import of a platform label, and the manual transformation of such string value to produce the final result. As a result, that component is just not localizable anymore.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be great to expand this section with examples from other popular frameworks (React, Vue, Svelte, Angular, etc.) and meta frameworks (Next, Nuxt, SvelteKit, Remix, etc.). How do they handle i18n?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can certainly add more details, formatjs website does have a good set of examples for some of those frameworks.

Co-authored-by: Nolan Lawson <[email protected]>
@caridy
Copy link
Contributor Author

caridy commented Jan 30, 2023

This looks great to me overall and it seems like a reasonable direction to go in. Adding a new parser and compiler output to support is painful, but it would address a real developer need.

Thanks for the promptly review @nolanlawson

Since Fluent is not a web standard though, I think we need to be super-cautious about this and ensure we're hitching our wagon to the right horse. Have we evaluated all alternatives? Are there any extensions to the syntax that are promising?

At the moment, there are only two major formats for complex messages, one from ICU (Message Format, colloquially called MF1), and one from Mozilla (Fluent). Mozilla is proposing, or at least it was, that fluent (which was designed to fulfill the short-comings of MF1) to become MF2, and become part of ECMA402. At least that was the plan half a decade ago. jejejeje.

Although I must say that Fluent is NOT the core of this proposal, we can have the exact same proposal using MF1. The core here is the state machinery for LWC to provision and compute the messages.

@nolanlawson
Copy link
Contributor

@caridy Makes sense! The pros and cons of ICU vs Fluent would be interested to discuss in the RFC, though. At some point, we need to pick one. (Unless we support both? 🤷)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants