This is the first time I am using localization for my project and I was overwhelmed by the number of options present in it. When I try to use the translations by using {t("parentBody")} in my JSX it is getting rendered in the browser as-is "parentBody". It is NOT loading the translation (values from the JSON file). I am expecting it to be rendered as value "This is the Parent Body" but instead I see only "parentBody".
I have done the following in my react app in order to localize. Can someone help me with this translations hook, its not loading the translations.
Following are the details about my libraries used:
react: ^17.0.2,
react-dom: ^17.0.2,
i18next : ^21.6.10,
i18next-http-backend: ^1.3.2,
react-i18next: ^11.15.3,
typescript: ^4.5.4,
This is what I am trying to do:
src/index.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import './i18n';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint.
reportWebVitals();
src/react-i18next.d.ts:
import 'react-i18next';
import en from './locales/en/translation.json';
import ta from './locales/ta/translation.json';
declare module 'react-i18next' {
interface CustomTypeOptions {
defaultNS: 'ns1';
resources: {
en: typeof en;
ta: typeof ta;
};
};
};
src/i18n.tsx
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import translationEN from './locales/en/translation.json';
import translationTA from './locales/ta/translation.json';
import Backend from 'i18next-http-backend';
export const defaultNS = 'ns1'
export const resources = {
en : {translation : translationEN},
ta : {translation : translationTA},
} as const;
export const availableLanguages = Object.keys(resources);
i18n
.use(initReactI18next)
.init({
resources,
lng: "en",
fallbackLng : "en",
ns: ['ns1'],
defaultNS,
interpolation : {escapeValue : false},
react: {
useSuspense: false,
},
});
export default i18n;
src/App.tsx
import './App.css';
import React,{ useContext, Suspense} from 'react';
import AllTabs from './components/AllTabs';
import CssBaseline from "@material-ui/core/CssBaseline";
import { ThemeProvider, createTheme } from "@material-ui/core/styles";
import { createStyles, alpha, Theme, makeStyles } from '@material-ui/core/styles';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import IconButton from '@material-ui/core/IconButton';
import Typography from '@material-ui/core/Typography';
import InputBase from '@material-ui/core/InputBase';
import Badge from '@material-ui/core/Badge';
import MenuItem from '@material-ui/core/MenuItem';
import Menu from '@material-ui/core/Menu';
import MenuIcon from '@material-ui/icons/Menu';
import FormControl from '@material-ui/core/FormControl';
import Select from '@material-ui/core/Select';
import InputLabel from '@material-ui/core/InputLabel';
import { useTranslation } from 'react-i18next';
import {availableLanguages} from "./i18n";
const themeDark = createTheme({
palette: {
background: {
default: "#222222"
},
text: {
primary: "#ffffff"
}
}
});
const useStyles = makeStyles((theme: Theme) => ({
grow: {
flexGrow: 1,
},
logo: {
maxWidth: 160,
marginRight: theme.spacing(10),
},
formControl: {
margin: theme.spacing(1),
minWidth: 10,
width: 150,
marginLeft: 20,
},
select: {
"& ul": {
backgroundColor: "#cccccc",
color: "#333333",
},
"& li": {
fontSize: 12,
},
},
}));
export const LanguageContext = React.createContext("en");
function App() {
const {t, i18n} = useTranslation();
const [language,setLanguage] = React.useState("en");
const handleLanguageChange = (event: React.ChangeEvent<{ value: unknown }>) => {
event.preventDefault();
setLanguage(event.target.value as string);
i18n.changeLanguage(event.target.value as string);
};
return (
<Suspense fallback="<div>loading...</div>">
<ThemeProvider theme={themeDark}>
<CssBaseline/>
<div className={`App`}>
<div className={classes.grow}>
<AppBar position="static">
<Toolbar>
<Typography className={classes.title} variant="h6" noWrap>
{t("parentBody")}
</Typography>
<FormControl className={classes.formControl} variant={variantType} size="small">
<InputLabel id = "Choose Language">Language</InputLabel>
<Select
labelId="language-id"
id="language"
value={language}
onChange={e => handleLanguageChange(e)}
label="Language"
MenuProps={{ classes: { paper: classes.select } }}
>
<MenuItem value={"en"}>English</MenuItem>
<MenuItem value={"ta"}>தமிழ்</MenuItem>
</Select>
</FormControl>
</Toolbar>
</AppBar>
</div>
<LanguageContext.Provider value={language}>
<AllTabs/>
</LanguageContext.Provider>
</div>
</ThemeProvider>
</Suspense>
);
}
export default App;
src/locales/en/translation.json:
{
"parentBody" : "This is the Parent Body"
}
If you want to load the translations inMemory via resources option, you do not need the i18next-http-backend dependency. If you want to load the translations via http, you do not need to set the resources option. https://www.i18next.com/how-to/add-or-load-translations
-> Try to set the i18next debug flag to true and check the developer console.
i18n
.use(initReactI18next)
.init({
debug: true,
// ... other options
});
You may also compare with this guide: https://dev.to/adrai/how-to-properly-internationalize-a-react-application-using-i18next-3hdb