dennisreimann / uiengine

Workbench for UI-driven development
https://uiengine.uix.space/
MIT License
366 stars 25 forks source link

UIEngine and i18n #45

Closed MrAvantiC closed 5 years ago

MrAvantiC commented 5 years ago

Hey Dennis, I have a question regarding how to handle i18n in UIEngine, maybe you have some experience here already. What I already did is setup a basic setup using react-i18next which can be found here: https://github.com/MrAvantiC/uiengine-i18n

One constraint I have is, that since I want to use components that are built in the UIEngine later in our Next.js application, I have to differentiate where to import the relevant functions to translate texts from. In case of Next.js that means I need the functions of the next-i18next package whereas in UIEngine I'd need the same function of the react-i18next package.

I managed to solve this by "injecting" the translation-function using the webpack-renderers for each component, like this:

const { useTranslation } = require('react-i18next')

module.exports = function serverRender(Component, props) {
  const newProps = { ...props, useTranslation }

  return renderToString(Component(newProps))
}

...which allows me to use them in the Component itself. Now, I'm able to do the same in Next.js when I use the component, which works fine for now.

What doesn't work yet

I would really like to display the different translations as variants in UIEngine. Unfortunately, I have not yet found a way to achieve that.

Approach 1 My first approach was to change the language of react-i18next based on the property I pass into each component. So, my variant would be called like this:

// Footer/variants/german.jsx

import React from 'react'
import Footer from '../Footer.jsx'

// the default language is set to en
export default props => <Footer {...props} language='de'/>

...and then use it when webpack renders the component, like that:

module.exports = function serverRender(Component, props) {
  const { language } = props
  // change language based on prop

Contrary to my assumptions on how the build-process works, the props in this function are not the ones passed into the variant but are instead always empty. So this doesn't work... :/

Approach 2 The other place where I could think of to setup the language without actually affecting the implementation of the component itself was to change the language when configuring the variants:

// Footer/variants/german.jsx

import React from 'react'
import Footer from '../Footer.jsx'
import i18n from '../../../../i18n/i18n'

export default props => {
  i18n.changeLanguage('de') // the default language is set to en

  return <Footer {...props} />
}

Strangely enough, this seems to work on the server side - so the initial html contains the german translation - and then on client-side hydration, it changes back to the default (english) translation.

I can't figure out at the moment why this behaves differently on the client-side. Do you have an idea what is missing here, or maybe even a better approach in the first place? :)

Regards, René

dennisreimann commented 5 years ago

Hey René, it will take me some time to have a closer look, but I'll get back to you on this.

Quick tip: The variant props come from the context of the variant definition. So you could have one variant file, that gets rendered several times – i.e. per language. This is what the component.config.js could look like:

const languages = ['en', 'de']

module.exports = {
  title: "Footer",

  variants: languages.map(lang => (
    {
      file: "Footer.jsx",
      title: lang,
      context: {
        lang,
        customProp1: "Hello",
        customProp2: "World"
      }
    }
  ))
}

Does this work for you?

dennisreimann commented 5 years ago

Can you add me as a collaborator to this project so that I can send you a working PR?

MrAvantiC commented 5 years ago

Hey Dennis, thanks for the quick feedback! Sure thing, I added you.

MrAvantiC commented 5 years ago

Hey Denniy, just checked out the PR. Guess I missed that part of the documentation, sorry about that!

It's working flawlessly right now, thank you!

dennisreimann commented 5 years ago

@all-contributors please add @MrAvantiC for example.

allcontributors[bot] commented 5 years ago

@dennisreimann

I've put up a pull request to add @MrAvantiC! :tada: