I need to translate my app, but i don't knomw how to use useTranslation() in the top-level files (i store there some consts which contain some text). One of this file is
import { useTranslation } from "react-i18next";
const {t} = useTranslation()
export const selectThemeOptions = [
{ value: "choose", text: "Choose theme" },
{ value: "Algebra", text: "Algebra" },
{ value: "Geometry", text: "Geomerty" },
{ value: "Programming", text: "Programming" },
{ value: "Logic", text: "Logic" },
];
so in this case i have an error: src\Configs\ThemesOfProblems.js Line 3:13: React Hook "useTranslation" cannot be called at the top level. React Hooks must be called in a React function component or a custom React Hook function react-hooks/rules-of-hooks
I need this array in my component, and it use in the next fragment :
<Form.Group as={Col} controlId="problemTheme">
<Form.Label>{t("userprofile.theme")}</Form.Label>
<Form.Select
name="theme"
value={values.theme}
onChange={handleChange}
isValid={touched.theme && !errors.theme}
isInvalid={!!errors.theme}
onBlur={handleBlur}
>
{selectThemeOptions.map((el, index) => {
return <option key={index} value={el.value}> {el.text} </option>
})}
</Form.Select>
</Form.Group>
And i've got a lot of such situations, i don't have any ideas how to do it
CodePudding user response:
Basically it says it has to be called in a react component. It could be called in a functional component where you return your jsx or a class component that has a render method in it. If you call the function outside of one of these, then you will get this error.
CodePudding user response:
You called const {t} = useTranslation();
outside of a React component, your selectThemeOptions
file seems to be a regular JavaScript
due to the absence of JSX
or a returning statement with your HTML.
Here is the correct way to do it:
/* Everything above this point is considered top-level, hence using your `useTranslation()` hook here would cause an error */
const Component = (props) => {
const { t } = useTranslation();
}
export default Component;
Here is a way to organise your translations:
• Your src
folder should contain an i18n.js
file with the following code:
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import en from "../locales/en.json";
import ru from "../locales/ru.json";
const isReturningUser = "lang" in localStorage; // Returns true if user already used the website.
const savedLanguage = JSON.parse(localStorage.getItem("lang")); // Gets persisted language from previous visit.
// Get previously used language in case of returning user or set language to Russian by default.
const language = isReturningUser ? savedLanguage : "ru";
const resources = {
en: {
translation: en,
},
ru: {
translation: ru,
},
};
i18n.use(initReactI18next).init({
resources,
lng: language,
keyseparator: false,
interpolation: {
escapeValue: false,
},
});
export default i18n;
- Your
src
folder should contain alocales
folder with json files of the languages your application uses. Example:ru.json
anden.json
:
{
"choose": "Выбрать",
"chooseATheme": "Выбрать тему",
"algebra": "Алгебра",
"geometry": "Геометрия",
"programming": "Программирование",
"logic": "Логика",
}
- Your component should look like this – note that the translations are in
json
files instead of your React component – :
import React from "react";
import { useTranslation } from "react-i18next";
const Component = (props) => {
const { t } = useTranslation();
const selectThemeOptions = [
{ value: t("choose"), text: t("chooseATheme") },
{ value: t("algebra"), text: t("algebra") },
{ value: t("geometry"), text: t("geometry") },
{ value: t("programming"), text: t("programming") },
{ value: t("logic"), text: t("logic") },
];
return( //Your UI )
}
export default Component;
This way, your translations wouldn't be hard-coded on your selectThemeOptions
and will adapt to whichever translation your json
locales contain.
Please tell me if this works.
Edit: If you want a concrete example of implementation of my solution here it is: https://github.com/YHADJRABIA/ecommerce/tree/main/src
Edit2: There might be a better solution of doing this, this is merely what worked for me.
Edit3: Following Nikita's comment, here's a solution to use the translation function outside of a react component —How to use react-i18next inside BASIC function (not component)?
P.S. Since you are from Belarus I assume that you want your translation to be made in Russian since Belarusian isn't as widely spoken.