reactjs i18next translate const with json arrays

81 Views Asked by At

My collection (bananeData) to translate

export const bananeData = [
  {
    id: 1,
    periode: 'text to translate', 
    info:'text to translate',
    picture: './media/banane.png'
  },
{
    id: 2,
    periode: ...,
    info: ...,
    picture: ...
  }
]
import React, {Component} from 'react';
import { bananeData } from '../data/bananeData';
import Banana from "./Banana";
import { withNamespaces } from "react-i18next";

class BananaList extends Component {
    state = {
        projects:bananeData
    };

    render() {
        let {projects} = this.state;

        const { t } = this.props;

        return (
            <div>
                <h3>{t('navigation_bananes')}</h3>

                <div>
                    {
                        projects.map(item => {
                            return (
                                <Banana
                                    key={item.id}
                                    item={item}
                                />
                            )
                        })
                    }
                </div>
            </div>
        );
    }
}
export default withNamespaces()(FreelanceList);

My Banana class

import React, {Component} from 'react';

export default class Banana extends Component {
    state = {
        showInfo: false
    }

    handleInfo = () => {
        this.setState({
            showInfo:!this.state.showInfo
        })
    }

    render() {
        let {name, periode, info, picture} = this.props.item

        return (
            <div className="project">
                <h5>{periode}</h5>
                <h3>{name}</h3>
                <img src={picture} alt="" onClick={this.handleInfo} />
                <span className="infos" onClick={this.handleInfo} >
                    <i className="fas fa-plus-circle"></i>
                </span>

                {
                    this.state.showInfo && (
                        <div className="showInfos">
                            <div className="infosContent">
                                <div className="head">
                                    <h2>{name}</h2>
                                </div>
                                <p className="text">{info}</p>
                                <div className="button return" onClick={this.handleInfo}>close</div>
                            </div>
                        </div>
                    )
                }

            </div>
        );
    }
}

My i18next file:

import i18n from 'i18next';
import backend from 'i18next-xhr-backend';
import detector from 'i18next-browser-languagedetector';
import { reactI18nextModule } from 'react-i18next';

import translationEN from './public/locales/en/translation.json';
import translationDE from './public/locales/de/translation.json';
const fallbackLng = 'en';

// the translations
export const languageResources = {
    de: {
        translation: translationDE
    },
    en: {
        translation: translationEN
    }
};

i18n
    .use(detector)
    .use(backend)
    .use(reactI18nextModule) 
    .init({
        lng: 'en',
        resources: languageResources,
        fallbackLng: fallbackLng, 

        keySeparator: false, 

        interpolation: {
            escapeValue: false 
        }
    });

export default i18n;

i use:

"i18next": "^21.6.13",
"i18next-browser-languagedetector": "^6.1.3",
"i18next-xhr-backend": "^3.2.2",

a part of one of my translation.json:

{
  "navigation_homepage": "Startseite",
  "navigation_skills": "Skills",
  ...
  "project_AAA_periode": "2022 - 2023",
  "project_AAA_info": "....",
  "project_BBB_periode": "2019 - 2023",
  "project_BBB_info": "....",
  ....
  "not_found_home": "Startseite",
  "not_found_doesnt_exist": "Seite existiert nicht"
}
1

There are 1 best solutions below

6
On

I downloaded and tested your code; apparently, you are using react-i18next with the v9 version. Below are the two ways to use it in your case - check what I have commented too.

First, the more "conventional" way (for easy understanding, I tried changing your code as little as possible).

Banana.js:

// ...other imports

import { withNamespaces } from "react-i18next";

class Banana extends Component {
    state = {
        showInfo: false
    }

    handleInfo = () => {
        this.setState({
            showInfo: !this.state.showInfo
        })
    }

    render() {
        // Be careful that you do not have `name` defined in `bananeData`;
        // do u mean `id` instead?
        let { name, periode, info, picture } = this.props.item

        // wrap everything you need with i18next; 
        // just make sure the key is already defined in `translation.json`, 
        // and then everything is fine.
        const { t } = this.props;

        return (
            <div className="project">
                <h5>{t(periode)}</h5>
                <h3>{t(name)}</h3>

                <img src={picture} alt="" onClick={this.handleInfo} />
                <span className="infos" onClick={this.handleInfo} >
                    <i className="fas fa-plus-circle"></i>
                </span>

                {
                    this.state.showInfo && (
                        <div className="showInfos">
                            <div className="infosContent">
                                <div className="head">
                                    <h2>{t(name)}</h2>
                                </div>
                                <p className="text">{t(info)}</p>
                                <div className="button return" onClick={this.handleInfo}>close</div>
                            </div>
                        </div>
                    )
                }

            </div>
        );
    }
}

// You have to specify the `namespace` with `translation`. 
// so `react-i18next` can understand which `JSON` file you refer to.
// Or you could define it in the `i18next.js` file with `defaultNS`.
export default withNamespaces('translation')(Banana);

BananaList.js:

// ...same imports

class BananaList extends Component {
    // same as what you write; nothing has changed in this part.
    ...
}

// Keep this as you still have to use `react-i18next` with `navigation_bananes`.
// I also changed the export to `BananaList` as I do not find `freelanceList` from your code.
export default withNamespaces('translation')(BananaList);

Second, the less "conventional" way but you get to minimize calling react-i18next.

BananaList.js:

// ...same imports

class BananaList extends Component {
    state = {
        projects: bananeData
    };

    render() {
        let { projects } = this.state;

        const { t } = this.props;

        return (
            <div>
                <h3>{t('navigation_bananes')}</h3>

                <div>
                    {
                        projects.map(item => {
                            // map the data as key to `react-i18next` here, 
                            // especially if you don't need it in class `Banana` anyway.
                            let newItem = item;
                            newItem.info = t(item.info);
                            newItem.periode = t(item.periode);
                            return (
                                <Banana
                                    key={newItem.id}
                                    item={newItem}
                                />
                            )
                        })
                    }
                </div>
            </div>
        );
    }
}
// Same as adding the required namespace and rewriting to `BananaList`.
export default withNamespaces('translation')(BananaList);

2023-12-09 Update: I am still quite unsure about how each object in bananeData transform into project_AAA, project_BBB, etc. for, for example, project_AAA_periode and project_BBB_periode. However, I'll try my best to provide the guide.

react-i18next is simple, whenever you match the key with it's function, namely t([key_you_used]), it would provide you with the value. Alternatively, it could not provide dynamic translation like translation softwares, and you must pre-set the translation text in the JSON.

Assume that it is what you needed, if your bananeData structures like this:

export const bananeData = [
  {
    // ...others
    info:'project_AAA',
  },
{
    // ...others
    info: 'project_BBB',
  }
]

Then you just have to use t(item.info + '_periode') to trigger translation for project_AAA_periode and project_BBB_periode (or project_AAA_info, etc.).


Else, if the cruicial information of project_AAA or project_BBB is not include anywhere in your data, you might need some sort of a mapper in your code.

A good example would be from id to alphabets from @gooostaw, check his answer on: Convert numbers to letters beyond the 26 character alphabet


Hope the above answer helps.