4 ms·
More and more, I'm starting to think maybe plain text isn't always the best abstraction to be using for defining messages for i18n. If messages were to be defin
by lewisl9029 8y ago
More and more, I'm starting to think maybe plain text isn't always the best abstraction to be using for defining messages for i18n. If messages were to be defined in terms of whatever primitive you're using to build your UI (i.e. React components if you're using React, and raw html template nodes if you're working with plain html), then all of this impedance mismatch might disappear.
In the React case, a component oriented approach to i18n could maybe look something like this:
const DefaultMessage = ({ clickCount }) =>
<span>
Please <a>click here {clickCount}
{pluralize(clickCount, {one: "time", other: "times"})}
</a> to confirm
</span>
// some theoretical language that requires putting "to confirm" between
// "click here" and "7 times", using English for clarity
const MessageInSomeOtherLanguage = ({ clickCount }) =>
<span>
Please <a>click here to confirm {clickCount}
{pluralize(clickCount, {one: "time", other: "times"})}
</a>
</span>
// some theoretical component that renders different components
// based on the language and passes through props
<FormattedComponent
id="confirm"
defaultMessage={DefaultMessage}
props={{ clickCount: 7 }}
/>
This feels a lot more elegant and flexible to me. Though it would make it more difficult for non-technical folks to contribute to translations, which might not be much of a concern if your company has the resources to support localization teams in-house. Am I overlooking any other obvious downsides to this approach? Does anyone know of any libraries that offers a similar API, or have experience using a similar approach?
- ivan_gammel 8y agoIt will be way easier to maintain, if the L10n resources won’t be mixed with the markup or code. Check this for example: https://github.com/resource4j/resource4j https://github.com/resource4j/resource4j
- madeofpalk 8y agoThe problem here is tooling and workflows. Often you'll be using a SaaS product to manage translations, like Lokalise or similar products. At the end of the day, these just give you a whole bunch of strings to put in your app. I've found this really hard. At my last place we just ate the cost (and ugliness) of included HTML in this strings and dangerously inserting them into the page.
- pas 8y agoThat's always a problem, even with templates. Angular does sanitization. Which is of course not ideal from a runtime performance point, but they probably weighted the cost-benefit and found it to be an okay trade-off. Though if the i18n string files are present at build time, then this sanitization step could be done there.
- michaelmior 8y agoDefinitely a problem. I think what will really make Fluent take off is if someone can provide good translation tools and workflow. The syntax looks great, but for most projects, I suspect it's impractical to expect translators to write Fluent manually.
- stasm 8y agoOur goal was to design a simple DSL which is easy to read and make small edits to. Copying and pasting is a powerful learning method :) We're also working on creating richer and more streamlined authoring experience in Pontoon, Mozilla's translation management system. You can read about the current state of Fluent support in Pontoon in my colleague's post at https://blog.mozilla.org/l10n/2019/04/11/implementing-fluent-in-a-localization-tool/ https://blog.mozilla.org/l10n/2019/04/11/implementing-fluent....
- michaelmior 8y agoCool! That looks like a great start :) I don't really do any l10n work myself so this was really just a bystanders perspective.
- whoisthemachine 8y agoThis is an interesting approach, but it's not tooling independent. If you can rely on your translations only seeing use in React components, then it may be just what you need.
- lewisl9029 8y agoThat's a great point. Although maybe one way to make the approach more generic is to treat them as functions that happen to return React Nodes as opposed to stateless functional components. Then you could write an alternative set of functions that returns say Vue components or raw html templates. It still doesn't make individual translations _always_ reusable across paradigms, but I'm not so sure if the impedance mismatch associated with working with raw strings in a modern UI frameworks is worth the translation portability of that de-facto approach. And at the end of the day the only transaction functions you'd have to duplicate are the ones return more than raw strings, so it's not the end of the world.