The translations do not work I only see the keys. Instead of having "Welcome to MySite" I only have "welcome.title MySite".
my i18nextConf.js file
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import Backend from 'i18next-xhr-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
const fallbackLng = ['fr'];
const availableLanguages = ['en','fr'];
i18n
.use(Backend) // load translations using http (default public/assets/locals/en/translations)
.use(LanguageDetector) // detect user language
.use(initReactI18next) // pass the i18n instance to react-i18next.
.init({
fallbackLng, // fallback language is english.
backend: {
/* translation file path */
// loadPath: './translations/{{lng}}/{{ns}}.json'
loadPath: './translations/{{lng}}/common.json'
},
detection: {
checkWhitelist: true, // options for language detection
},
debug: false,
whitelist: availableLanguages,
interpolation: {
escapeValue: false, // no need for react. it escapes by default
},
});
export default i18n;
My index.js file
import React,{ Suspense } from 'react';
import './i18nextConf';
// code omitted
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<Suspense fallback={null}>
<App />
</Suspense>
</Provider>
</React.StrictMode>,
document.getElementById('root')
);
My translations files in src/translations/en/common.json and src/translations/fr/common.json
{
"welcome": {
"title": "Welcome to "
}
}
my CustomComponent.js
import React,{ Component } from 'react';
import { withTranslation } from "react-i18next";
class CustomComponent extends Component {
render() {
const { t } = this.props;
return (
<div className="section-title">
<h2 className={classes.myTitle}>{t('welcome.title')}</h2>
</div>
);
}
}
export default withTranslation()(CustomComponent);
Is there something wrong with my configuration ? What do I have to change ?
Those translation files will be served from the base path from where your index.html is also loaded and in-case it's an app created using create-react-app, that folder is public.
So I think when you are saying in loadPath that load files from ./translations/{{lng}}/common.json, the request actually gets resolved to public/translation/en/common.json but your files are located at src..... as you stated.
You can try either moving those files inside public (check this example for reference also ) or you can try the other syntax where you explicitly import the json from each file (inside src) and add it to a resources object which you pass to configuration as shown here
Related
I have a Nextjs app. I have used it to build the Coinbase clone. Since it uses window object to connect to metamsk, I need to disable the SSR in Nextjs. But some how if I disable the SSR and restart the server it's breaking my styles. Take a look below, check how the style of Navbar title Assets changes when I disable SSR and restart the dev server:
With SSR enabled:
With SSR disabled:
Here's my _app.js:
import dynamic from "next/dynamic";
import { ThemeProvider, createTheme } from '#mui/material/styles';
import CssBaseline from '#mui/material/CssBaseline';
import { ChainId, ThirdwebProvider } from "#thirdweb-dev/react";
import { MoralisProvider } from "react-moralis";
import NoSSR from "./NoSSR";
import '../styles/globals.css'
const darkTheme = createTheme({
palette: {
mode: 'dark',
background:{
dark:'#0a0b0d',
}
},
});
function MyApp({ Component, pageProps }) {
return (
<NoSSR>
<ThemeProvider theme={darkTheme}>
<CssBaseline/>
{/* <ThirdwebProvider desiredChainId={ChainId.Rinkeby}>
</ThirdwebProvider> */}
<MoralisProvider serverUrl={'https://124a8yab5jee.usemoralis.com:2053/server'} appId='Seyf64uxlgqgxt5Y75p1M4Hq21CC5osXcvj4T8Yw'>
<Component {...pageProps} />
</MoralisProvider>
</ThemeProvider>
</NoSSR>
)
}
export default MyApp;
NoSSR.js:
import dynamic from 'next/dynamic'
import React from 'react'
const NoSsr = props => (
<React.Fragment>{props.children}</React.Fragment>
)
export default dynamic(() => Promise.resolve(NoSsr), {
ssr: false
})
I am not getting why it's happening, is it a bug in Nextjs? I am also using Material UI libaray.
The fact that you used NoSSR in your _app.js and as a wrapper for the whole project means you don't want SSR option for any part of your code which is confusing because if you don't need SSR you don't have to go through nextjs. If you have a single component that needs to run on client side I suggest you only wrap that component on your NoSSR.
Also I suggest to put your globals.css in src folder (src is in root)
I'm using React with react-i18next
My index.tsx File contains some components and I can use the Translation function there
index.js
import React, { Suspense } from 'react'
import ReactDOM from 'react-dom';
import * as utils from './Utils';
import './i18n';
import { useTranslation, withTranslation, Trans } from 'react-i18next';
...
const { t, i18n } = useTranslation();
//I can use the translate function here
t("title");
//call a util function
utils.helperFunction(...);
...
Everything works fine here.
I now created some helper functions in an additional file
Utils.tsx
...
import { useTranslation, withTranslation, Trans } from 'react-i18next';
...
export function helperFunction(props: any){
//do stuff
//now I need some translation here - but useTranslation is not working?
const { t, i18n } = useTranslation();
t("needTranslation");
}
How can I use the same translation logic inside my helper function? (without always passing the t function to the helper-method)
Or is the usage of the hook the wrong approach here?
The following error occurs
React Hook "useTranslation" is called in function "helperFunction" which is neither a React function component or a custom React Hook function react-hooks/rules-of-hooks
I fixed my issue by not using the useTranslation hook anymore
Instead I moved the i18n initalizitation to a file (i18n.tsx - exports i18n)
and import and use it in my Utils class
My Utils.tsx file now looks like this
Utils.tsx
...
import i18n from '../i18n';
...
export function helperFunction(props: any){
//do stuff
//use imported i18n and call the t() method
i18n.t("needTranslation");
}
i18n.tsx
import i18n from "i18next";
import Backend from 'i18next-xhr-backend';
import { initReactI18next } from 'react-i18next';
i18n
.use(Backend)
.use(initReactI18next) // passes i18n down to react-i18next
.init({
lng: "es",
fallbackLng: 'en',
backend: {
loadPath: '/static/locales/{{lng}}/{{ns}}.json'
},
interpolation: {
escapeValue: false
}
});
export default i18n;
Or is the usage of the hook the wrong approach here?
I would say that because useTranslation is a hook and if you try to use it in the helper function, it won't allow you to do so and you'd have to return a react function component or custom React Hook function as the message says
It looks like you forgot a quote t("needTranslation); -> t("needTranslation");
After I ran your code I see why your code isn't working. If you want to extract component logic into reusable functions, then you should make a custom hook. For more info look at the docs.
import React from "react";
import ReactDOM from "react-dom";
import i18n from "i18next";
import "./i18n.js";
import { useTranslation, initReactI18next } from "react-i18next";
i18n
.use(initReactI18next)
.init({
resources: {
en: {
translation: {
title: "Hello world",
subtitle: "Hello stackoverflow"
}
}
},
lng: "en",
fallbackLng: "en",
interpolation: {
escapeValue: false
}
});
function App() {
const { t } = useTranslation();
useHelperFunction();
return <h1>{t("title")}</h1>;
}
// you need to turn the helper function into a hook
function useHelperFunction() {
const { t } = useTranslation();
return <h2>{t("subtitle")}</h2>;
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
I am trying to create a react-native application, I'm currently at the starting point and I cannot understand an issue that I encountered.
I need to integrate i18next for translations. I did this by following their step-by-step tutorial
I have the following code
App.js
import React, { Suspense, Component } from 'react';
import { ScrollView, StyleSheet, Text, View, } from 'react-native';
import { useTranslation } from 'react-i18next';
import { Colors, } from 'react-native/Libraries/NewAppScreen';
const MyComponent = () => {
const { t, i18n } = useTranslation();
return <Text>{t('index.welcome')}</Text>;
};
const App = () => {
return (
<Suspense fallback="loading">
<ScrollView
contentInsetAdjustmentBehavior="automatic"
style={styles.scrollView}>
<View style={styles.body}>
<MyComponent />
</View>
</ScrollView>
</Suspense>
);
};
const styles = StyleSheet.create({
scrollView: {
backgroundColor: Colors.lighter,
},
body: {
backgroundColor: Colors.white,
},
});
export default App;
The issue here is that I get an Invariant Violation: Text strings must be rendered within a <Text> component error
If I change MyComponent to the following the application works
const MyComponent = () => {
return <Text>Anything</Text>;
};
So the issue here for me seems to be the useTranslation() hook.
What am I missing here?
LE
I was missing the namespace in the useTranslation()
I've added it useTranslations('translation') but still I have the same issue
The issue seems to be with the path for the translation files which cannot be parsed
i18next::backendConnector: loading namespace translation for language en failed failed parsing /translations/en/translation.json to json
In React the files would be public available via the public folder, in React-Native how should this be used? I think that the app cannot access that folder, where should the folder be placed?
LE2
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import Backend from 'i18next-xhr-backend';
i18n
.use(Backend)
.use(initReactI18next)
.init({
fallbackLng: 'en',
debug: true,
interpolation: {
escapeValue: false, // not needed for react as it escapes by default
},
backend: {
loadPath: '/translations/{{lng}}/{{ns}}.json',
},
});
export default i18n;
And the translations folder is placed in the root of the project
I am new to react/redux I little confused with server side rending in react/redux,
Yes i saw some example on the internet but when i tried with mock api with external server , server side rendering is not working .
cat.js
import React from 'react';
import {render} from 'react-dom';
import {connect} from 'react-redux';
import * as mockApi from '../Actions/mockActions';
class Cat extends React.Component{
componentWillMount(){
this.props.getMockApi();
}
render(){
return(
<div>
Hello Dude
{this.props.mock.data.map((data,i) => {
return <li key={i}>{data.email}</li>
})}
</div>
)
}
}
const mapStateToProps = (state) => {
return {
mock:state.mock
}
};
const mapDispatchToProps = (dispatch) => {
return {
getMockApi:() => dispatch(mockApi.getMockData())
}
};
export default connect(mapStateToProps,mapDispatchToProps)(Cat);
mockActions.js
import axios from 'axios';
import * as types from './actionTypes';
export function getMockData() {
return dispatch => {
return axios.get('http://jsonplaceholder.typicode.com/users').then(response => {
dispatch(setThisData(response.data))
})
}
}
export function setThisData(data) {
return {
type:types.MOCK_API,
payload:data
}
}
App.js
import React from 'react';
import {render} from 'react-dom';
import Cat from './components/cat'
import {Provider} from 'react-redux';
import configureStore from './Store/configureStore';
import { createStore ,applyMiddleware,compose} from 'redux';
import counterApp from './Reducers'
import thunk from 'redux-thunk';
if(typeof window !== 'undefined'){
// Grab the state from a global variable injected into the server-generated HTML
const preloadedState = window.__PRELOADED_STATE__
// Allow the passed state to be garbage-collected
delete window.__PRELOADED_STATE__
const store = createStore(counterApp, preloadedState, compose(applyMiddleware(thunk)))
render(
<Provider store={store} >
<Cat/>
</Provider>
,
document.getElementById('app')
)
}
devServer.js
import express from 'express';
import path from 'path';
import webpack from 'webpack';
import webpackMiddleware from 'webpack-dev-middleware'
import webpackHotMidleware from 'webpack-hot-middleware';
import bodyParser from 'body-parser';
import React from 'react'
import { createStore } from 'redux'
import { Provider } from 'react-redux';
import counterApp from '../../src/client/ReduxServer/Reducers';
import App from '../../src/client/ReduxServer/components/cat';
import { renderToString } from 'react-dom/server'
import webpackConfig from '../../webpack.config.dev';
let app = express();
app.use(bodyParser.json());
app.use(express.static('public'))
const compiler = webpack(webpackConfig);
app.use(webpackMiddleware(compiler, {
hot: true,
publicPath: webpackConfig.output.publicPath,
noInfo: true
}));
app.use(webpackHotMidleware(compiler));
// app.get('/*', (req, res) => {
// res.sendFile(path.join(__dirname, '../../index.html'))
// });
//Redux Start
app.use(handleRender);
function handleRender(req,res) {
const store = createStore(counterApp);
const html = renderToString(
<Provider store={store} >
<App/>
</Provider>
)
const preloadedState = store.getState();
// Send the rendered page back to the client
res.send(renderFullPage(html, preloadedState))
}
function renderFullPage(html, preloadedState) {
console.log(preloadedState)
return `
<!doctype html>
<html>
<head>
<title>Redux Universal Example</title>
</head>
<body>
<div id="app">${html}</div>
<script>
window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(/</g, '\\u003c')}
</script>
<script src="bundle.js"></script>
</body>
</html>
`
}
//Redux Ends
app.listen(3000, () => {
console.log('Listening')
});
Right now this will only server render the hello dude but not the mock Api call data .I know that missed to fetch the data from server side but the point is what will i do If ihave to render a two components and that component has 5 api reuqest ,And how to fecth the correct api Request
Right Now My client Side Prefecthed state will look like this
window.__PRELOADED_STATE__ = {"mock":{"data":[]}}
Ok, to make this clear, you've created the code to handle server rendering. However, it doesn't load the data that is supposed to be fetched right?
You've done the first step, great! The next step is to load the actual dynamic data to the store. Let's look at this code here
function handleRender(req,res) {
const store = createStore(counterApp);
const html = renderToString(
<Provider store={store} >
<App/>
</Provider>
)
const preloadedState = store.getState();
// Send the rendered page back to the client
res.send(renderFullPage(html, preloadedState))
}
What happened is that you created a store. The store is used to render the html into a string. Then you get the store state and put it into preloadedState.
This is great accept that renderToString will not call this.props.getMockApi(); as you would expect.
Instead, you have to fetch the state before you call renderToString();
In this case, what you could do is as following. (Note that this is just an example, you probably want to use something more general in production, especially if you use something like react-router.)
import * as mockApi from '../Actions/mockActions';
function handleRender(req, res) {
const store = createStore(counterApp);
store.dispatch(mockApi.getMockData())
// And since you used redux-thunk, it should return a promise
.then(() => {
const html = renderToString(
<Provider store={store}>
<App/>
</Provider>
)
const preloadedState = store.getState();
// Send the rendered page back to the client
res.send(renderFullPage(html, preloadedState))
});
}
Simple isn't it? ;D, nah just joking. This is one part of react where there's not really an exact solution to the problem yet.
Personally, if I had the choice to go back in time, I'd tell myself to learn other stuff other than server rendering. There are other techniques such as code splitting, lazy loading, etc that I could've used instead. With server rendering, if the javascript arrives long after the user has seen the initial page, they might get frustrated by other things that require js. For example in my case, some links are not working, some buttons don't do anything, etc.
I'm not saying that server rendering is not good. It's an interesting technique, just that there are other techniques that are more beneficial to learn first (Oh, and server rendering basically locks you to use nodejs for your backend). Good luck to you :)
I'm trying the new React Hot Loader 3 and I'm receiving an warning message:
warning.js:44 Warning: React.createElement: type should not be null,
undefined, boolean, or number. It should be a string (for DOM
elements) or a ReactClass (for composite components). Check the render
method of AppContainer.
This is the App file. What is wrong?
Ps: It's written the same way as on examples.
Ps2: The problem is not in the App since it renders on the render() outside the if statement
Ps3: The warning only appears when the browser tries to 'hot-reload' (when I make changes to any file)
import React from 'react';
import { render } from 'react-dom';
import { AppContainer } from 'react-hot-loader';
import a11y from 'react-a11y'
import Store from './stores/Store';
import App from './components/App/App';
const store = new Store();
if(process.env.NODE_ENV === 'development'){
a11y(React);
}
render(
<AppContainer
component={App}
props={{ store }}
/>,
document.getElementById('root')
);
if (module.hot) {
module.hot.accept('./components/App/App', () => {
render(
<AppContainer
component={require('./components/App/App').default}
props={{ store }}
/>,
document.getElementById('root')
);
});
}
Ok, the problem was with my .babelrc file. I had some other plugins, that I've removed, and it worked:
{
"presets": ["es2015-loose", "react", "stage-1"],
"plugins": [
"react-hot-loader/babel",
"transform-decorators-legacy"
],
}