Open amannn opened 10 months ago
Note this doesn't handle the case where I want to pass the messages as an object from another component.
I.e.
const MyComponent = ({ translationValues }) => t.rich('translationKey', translatioNValues);
So IMHO the whole RichTranslations and MarkupTranslations should support non-functions.
You mean when translationValues
contains functions, right? Can you share more about the practical use case?
You mean when
translationValues
contains functions, right? Can you share more about the practical use case?
Wdym by that? I should be able to pass translation values as props between any component if I wish. Shouldnt be blocked by an implementation detail of making them a function.
In other words, what if I have dynamic values and want to map them, I'd be unable due to next-intl requiring markup or rich text to be wrapped on functions...
I should be able to pass translation values as props between any component if I wish.
React defines the rules for which props are serializable.
next-intl
provides an API that allows for rich text formatting where any custom component can be used:
t.rich('hint', {
help: (chunks) => <Link href="/help">{chunks}</Link>
})
Theoretically, React elements themselves are serializable, so from an API perspective the value of help
here is serializable:
t.rich('hint', {
help: <Link href="/help" />
})
However, if the element that is passed to help
comes from a Server Component and t.rich
executes in a Client Component, then only the markup is transferred—not the component. This is quite the point of the RSC model. Therefore, practically this API doesn't work.
Long story short, I can't think of an API that has the same flexibility as the current t.rich
that would accept a fully serializable config. Staying within either a server or client module graph for rich text elements solves the problem from a different angle. Due to the way the RSC model works, you can import rich text elements even from both from Server and Client Components.
My comment on top of this thread describes examples for sharing common rich text elements. I think it's helpful to discuss this based on concrete examples to be able to find good solutions.
In case you can think of a better pattern, let me know!
I think sharing this with you is self-explanatory.
Pretty much there's a translation key that we want to have a specific part of it to be surrounded with a "span" element (https://github.com/nodejs/nodejs.org/blob/main/i18n/locales/en.json#L84), that's it.
This was possible before, because react-intl allowed me to replace a variable, such as {something}
(https://github.com/nodejs/nodejs.org/blob/c72dc046dffda7d8b056623602c80bac3dd6a8f4/i18n/locales/en.json#L19) with something else (https://github.com/nodejs/nodejs.org/blob/c72dc046dffda7d8b056623602c80bac3dd6a8f4/layouts/DocsLayout.tsx#L21)
I understand that this is unrelated to next-intl, and react-intl would face the same issues once I've used server components; Hence me indulging if it makes sense to support something else.
In the end, I just want to be able to share translation values from Component A to Component B. Right not it works because both components are client components, but I feel that maybe next-intl should support a way to transfer rich-text content independent if the component is RSC or CSC... 🤔
Not a big deal, but I feel that it'd be nice if it was supported. Either by something like:
const translationContext: RichTranslationValues = {
graySpan: '<span className="small color-lightgray">{0}</span>'
}
Encapsulating the HTML code within a string and then eval'ing it. And the translation key be like:
"apiLts": "{fullLtsNodeVersion} API <graySpan>something</graySpan>",
I know this is just a poor example, and definitely a stretch.
Also sorry if I'm just crying wold here, @amannn, please feel more than free to just disregard my request!
This was possible before, because react-intl allowed me to replace a variable, such as
{something}
(https://github.com/nodejs/nodejs.org/blob/c72dc046dffda7d8b056623602c80bac3dd6a8f4/i18n/locales/en.json#L19) with something else (https://github.com/nodejs/nodejs.org/blob/c72dc046dffda7d8b056623602c80bac3dd6a8f4/layouts/DocsLayout.tsx#L21)
That's an interesting one, because you didn't need chunks previously (since "LTS" was hardcoded):
spanLts: <span className="small color-lightgray">LTS</span>,
next-intl
could most likely support passing a React Element without chunks for rich text, by directly assigning the element to a value (without a function). In fact, I think it already does, we'd only have to update the types for such a call.
There's currently an expandable section in the rich text docs about self-closing tags. This could be updated accordingly as part of this change.
In regard to rich text content with chunks: I don't see eval'ing as a good direction here, to be honest. The provided elements can not just be HTML, but any React component.
To come back to your example: I think there could also be a question here about which parts of the component should be Server or Client Components. Briefly looking into the code, I'm wondering if the rendering of the sidebar could be achieved in RSC and only individual items that need to be highlighted if they're active could be Client Components. The next-intl App Router example does just that for the navigation. If you're staying within RSC for the rendering of the items, then this problem also disappears.
Hope this helps!
'm wondering if the rendering of the sidebar could be achieved in RSC and only individual items that need to be highlighted if they're active could be Client Components.
Hm, true, I think I can make it RSC compatible.
In regard to rich text content with chunks: I don't see eval'ing as a good direction here, to be honest. The provided elements can not just be HTML, but any React component.
Right, I'm also not a fan of this. But I believe at least for the case you mentioned above about without chunks, worth documenting it and updating the types. Can be useful for some folks :)
Right, I'm also not a fan of this. But I believe at least for the case you mentioned above about without chunks, worth documenting it and updating the types. Can be useful for some folks :)
Yep, I agree!
Aaand, found a way to make it RSC by removing the only Hook that was "client-dependent"
Awesome! 👏
I've added https://github.com/amannn/next-intl/issues/1285 to investigate a better way to achieve global error handling.
Is your feature request related to a problem? Please describe.
These three config options accept functions and can therefore not be serialized currently:
defaultTranslationValues
onError
getMessageFallback
Due to this, we can't automatically pass them from an RSC render to the client side.
It might be worth investigating serializable alternatives, to avoid this.
Describe the solution you'd like
defaultTranslationValues
Maybe a better option could be to deprecate the option altogether and ask users to share values e.g. via a component:
… or imports:
As a nice side effect, this would allow us to statically type the arguments of a given ICU string (see https://github.com/amannn/next-intl/issues/410), since there are no potential global values floating around.
Another benefit could be to remove ambiguity between values that should be used for
t.rich
andt.markup
(see https://github.com/amannn/next-intl/issues/1181).onError
See https://github.com/amannn/next-intl/issues/1285
getMessageFallback
See https://github.com/amannn/next-intl/issues/1285
Alternatives:
MISSING: {namespace}.{key}
?Describe alternatives you've considered
NextIntlClientProvider
can be added in a client-side module graph to configure the non-serializable config options, see the docs.