Add Rich Text Support to SolidJS i18n
Describe The Problem To Be Solved
Currently, we can't add links or styled text inside i18n translations in SolidJS. We need a simple way to add components like <A> or tags within our translated text, similar to how next-intl does it.
Suggest A Solution
Add a simple t.rich() method that allows mapping custom tags to Solid components:
Example usage:
{
"message": "Please refer to <guidelines>{name}</guidelines>"
}
const t = useTranslations();
t.rich('message', {
guidelines: (text) => <A href="/guidelines">{text}</A>
name: "the guidelines"
})
Key features:
- Support basic tag mapping
- Work with existing SolidJS components
- Keep the same simple API as regular translations
This would give us an easy way to add links and formatting to our translations while keeping the code clean and maintainable.
I like the simple concept
Maybe not that rich here is a method on whatever t is
If this could be done as a separate helper I wouldn't really mind
Don't see a way to make this type-safe though
At least not without codegen
So the "maintainable" part is up for debate
Thanks for the feedback @thetarnav
You're right about the implementation concerns. I think we could start simple with just basic runtime validation of the tags and mapping object. No need to overcomplicate things with type safety or codegen at this stage.
The separate helper approach you suggested makes sense too. The main goal is just to enable basic rich text support in translations.
I like the idea of a resolveTags helper. Not being type safe may be a drawback, but not one that should concern us. We should use a callback function that emits a warning in DEV and strips the tags in prod.
This is a must need. Not the best/easiest way to implement it, but some feature is better than no feature
I found a good example which next-intl uses internally
https://github.com/formatjs/formatjs/blob/main/packages/icu-messageformat-parser/parser.ts#L346
I would love this!
A workaround would be returning JSX instead of strings and pass in a component like this:
{
message: (Guidelines: ParentComponent, name: string) => <>Please refer to <Guidelines>{params.name}</Guidelines></>
}
t(
"message",
(props) => <A href="/guidelines">{props.children}</A>,
"the guidelines"
)
Dynamic components are not yet supported like this IIRC. You would need to use Dynamic, but otherwise, it illustrates well what is meant.
I'm using the above solution right now and it works without issues as far as i can tell
Ah, then that's already fixed, it seems.