opral / inlang-paraglide-js

Tree-shakable i18n library build on the inlang ecosystem.
https://inlang.com/m/gerre34r/library-inlang-paraglideJs
23 stars 0 forks source link

Come up with a way to do Component Interpolation #72

Closed LorisSigrist closed 2 weeks ago

LorisSigrist commented 2 months ago

Context

It's currently unclear how component interpolation could be implemented in Paraglide. Interpolating components would almost certainly require a framework-specific runtime/renderer. However, if we just have message functions, how can such a renderer insert a component?

This could force us to switch to the AST approach, where instead of a message function, the message is compiled to an AST that a small runtime utility then renders.

const my_message = ["Please accept the ", ["component": "Terms and conditions"], "before continuing"]
m(my_message)

This would require major API changes so I would really appreciate alternative suggestions

Alternative Idea:

Another clever suggestion comes from this discussion: https://github.com/orgs/opral/discussions/913#discussioncomment-9126828

It suggests having the messages return an array that can be used as a JSX value directly.

const my_message ({ link }) = ["Click on the" , link]

<h1> 
  {{ my_message({link: <a>test</a> }) }}
</h1>

Unfortunately this also has drawbacks :

Proposal

See thread

LorisSigrist commented 2 weeks ago

Message Bundles declare up front which parameters are components. This means the 90% case where there aren't any components can stay the same. Functions still return strings as usual.

In the 10% case there are components used we can return an array, like so:

const my_message_with_link = ({ link, href }) => [
    "Hello ",
    link({ href, children: "World" }),
    " Wassup?",
]

This array-based AST is convenient, since it's ready to use in many JSX based frameworks.
In react the above example can be rendered like this:

<>
  {m.my_message_with_link({
     href: "/somewhere",
     link: ({ children, href }) => <Link href={href}>{children}</Link>
   })}
</>

I believe vue would look basically the same.

JSX-less framework can render using a helper component. In Svelte you do

<T message={m.my_message_with_link} params={{ ...stuff }} />

It may be possible to simplify this using svelte 5 snippets, since snippets are just functions.

TLDR: There is a clear path to component interpolation that can be done without breaking changes