-
Notifications
You must be signed in to change notification settings - Fork 24
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
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this 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: |
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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?"
There was a problem hiding this comment.
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.
|
||
#### 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. |
There was a problem hiding this comment.
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 onLightningElement.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?
There was a problem hiding this comment.
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 onLightningElement.prototype
.By this, I assume you mean that
this.i18n.foo
works, butthis.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. |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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]>
Thanks for the promptly review @nolanlawson
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. |
@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? 🤷) |
Rendered