Description
With the bundle & message API getting reconsidered (most recently in #380), and being redirected to being more explicitly a lowest-level API for messages, I would like for the earlier decision to remove formatToParts()
to be reconsidered, possibly to the extent of only providing a formatToParts
method on the bundle, rather than format
or formatPattern
. My main argument here is that it should be an implementation-specific decision for how to stringify or represent each non-string part.
Having looked through the history, the only arguments for this that I've been able to find were from @stasm:
- Its only use case in
fluent-react
was replaced by overlays (RemoveMessageFormat.formatToParts
#104) - Its implementation was "buggy and under-spec'ed" (Remove
MessageFormat.formatToParts
#104) - Passing "React elements as props to to interpolate them into the translation [...] is a bad localization practice because it results in the translation being split into multiple strings and then interpolated." (DOM fragments localization for fluent-react #103)
Addressing each of the above concerns in turn:
-
At least vue-i18n supports what it calls component interpolation, which effectively allows for components (i.e. objects) to be passed through the localization without stringification. For messageformat I've just filed a PR (Add option for array output messageformat/messageformat#242) enabling this by making the output type configurable, such that its compiled formatter functions may return an array of parts instead of a single string. Similar use cases are likely to be found outside of the core Fluent libraries, should a
formatToParts
method be available.
For another use case, consider translations that would be used in more than one output format. One that I've encountered personally is using the same translations both in React/HTML as well as plain-text emails. In HTML, it's useful to be able to express emphasis for the same strings as<i>foo</i>
, but then use markdown-ish_foo_
in plain-text contexts. -
As is, the implementation of the formatting functions is getting refactored, and from that premise it'd be rather easy to define method's behaviour and output.
-
I don't agree with this assertion. If it were true, why would terms be included in the Fluent spec? Of course it's possible to construct over-complex localizations with interpolated parts, but exactly that is already enabled by terms. Without the variable pass-through that
formatToParts
would enable, the only currently available solution is to use overlays, and to re-parse the output string as XML before being able to construct the actual output. And that seems rather clumsy.
Implementation-wise, the change here would be minimal. Based on stasm:formatPattern
:
- Return
result
rather thanresult.join("")
fromPattern()
in resolver.js - For string patterns, wrap the return from
formatPattern()
in bundle.js in an array, or allow the function to return either a string or an array.
With those changes, here's an example of what would be possible:
accept-terms = I accept the {$tosLink}.
.tos = Terms of service
import React from { react } // just for the example
function AcceptTermsLabel({ bundle, href, ...props }) {
const msg = bundle.getMessage('accept-terms')
const tos = bundle.formatToParts(msg.attributes.tos)
const tosLink = <a href={href} key="tos">{tos}</a>
return (
<label {...props}>
{bundle.formatToParts(msg.value, { tosLink })}
</label>
)
}