Each time the msg function is called, it returns a version of the given string or Lit template in the active locale. However, this result is just a normal string or template; it is not intrinsically capable of re-rendering itself when the locale changes.
For this reason, it is important to write msg calls in a way that ensures they will be re-evaluated each time the Lit render method runs. This way, when the locale changes, the correct string or template for the latest locale will be returned.
One situation where it is easy to make a mistake here is when localizing property default values. It may seem natural to write this:
// Don't do this!
label=msg('Default label')
render() {
returnhtml`<button>${this.label}</button>`;
}
However, the above pattern provides no opportunity for the default label to be updated when the locale changes. The default value will get stuck at the version from the locale that happened to be active when the element was instantiated.
A simple fix is to move the default value fallback directly into the render method:
While @lit/localize has full support for embedding HTML markup inside localized templates, it's best to avoid doing so whenever possible. This is because:
It's easier for translators to deal with simple string phrases instead of phrases with embedded markup.
It avoids unnecessary re-translation work when markup changes, such as when adding a class that affects appearance without changing the meaning.
It will typically be faster to swap locales, because fewer parts of the DOM will need to update. Also, less JavaScript will be included in your bundles, because common markup will not need to be duplicated into each translation.
Not ideal:
render() {
// Don't do this! There's no reason to include the <button> tag in this
// localized template.
returnmsg(html`<button>Launch rocket</button>`);
}
Ideal:
render() {
// Much better! Now the phrase "Launch rocket" can be translated more easily
Breaking templates into smaller pieces can also be helpful:
render() {
// Don't do this!
returnmsg(html`
<p>The red button makes the rocket go up.</p>
<p>The green button makes the rocket do a flip.</p>
`);
}
render() {
// Better! No markup needs to be processed by translators, and each sentence
// can be translated independently.
returnhtml`
<p>${msg('The red button makes the rocket go up.')}</p>
<p>${msg('The green button makes the rocket do a flip.')}</p>
`;
}
When using transform mode, templates will be automatically flattened to make them as small and efficient as possible. After transformation, the above example won't have any placeholders, because it knows that strings can be directly merged into HTML templates.
There are cases where HTML should be included in the localized template. For example where an HTML tag is needed in the middle of a phrase:
render() {
returnmsg(html`Lift off in <b>T-${this.countdown}</b> seconds`);
Static analysis is used to determine when you are calling the @lit/localizemsg function and other APIs, as opposed to a different function with the same name.
It is possible to re-export or re-assign the msg function and other APIs, and most of the time this will just work.
However, certain patterns may be too dynamic for static analysis to understand. If a message is failing to be extracted, and you have re-assigned or re-exported the msg function, this could be the cause.
To force a function to be analyzed as a @lit/localize API, you can use a JSDoc @type comment in JavaScript, or a type cast in TypeScript: