How to configure i18n with withFonts() - internationalization

I am working on a Next.js project using Tailwind CSS for styling. I am stuck at the next.config file.
I've almost tried everything to make this code work but cannot.
const withPlugins = require("next-compose-plugins");
const withImages = require("next-images");
const withSass = require("#zeit/next-sass");
const withCSS = require("#zeit/next-css");
const withFonts = require("next-fonts");
const webpack = require("webpack");
const path = require("path");
module.exports = withFonts(
withCSS(
withImages(
withSass({
webpack(config, options) {
config.module.rules.push({
test: /\.(eot|ttf|woff|woff2)$/,
use: {
loader: "url-loader",
},
});
config.resolve.modules.push(path.resolve("./"));
return config;
},
})
)
)
);
module.exports = {
i18n: {
locales: ['en', 'fr'],
defaultLocale: 'en',
},
}
I'd like to know how to combine these two things.
Here is the code of the index.js i'm using.
import { useRouter } from 'next/router';
import fr from '../locales/fr';
import en from '../locales/en';
function sth () {
const router = useRouter();
const { locale } = router;
const t = locale === 'en' || 'undefined' ? en : fr;
console.log(locale);
return t;
}
export default function Index() {
const t = sth();
return (
<>
<IndexNavbar fixed />
<section className="header relative pt-16 items-center flex h-screen max-h-860-px">
<div className="container mx-auto items-center flex flex-wrap">
<div className="w-full md:w-8/12 lg:w-6/12 xl:w-6/12 px-4">
<div className="pt-32 sm:pt-0">
<h2 className="font-semibold text-4xl text-gray-700">
{t.homeMainTitle}
</h2>
</div>
</div>
</div>
</section>
</>
);}
The content of sth() function was inside the Index() and it doesn't work either way.

You can only have one module.exports per file/module. Your next.config.js should look like the following:
const withPlugins = require("next-compose-plugins");
const withImages = require("next-images");
const withSass = require("#zeit/next-sass");
const withCSS = require("#zeit/next-css");
const withFonts = require("next-fonts");
const webpack = require("webpack");
const path = require("path");
module.exports = withFonts(
withCSS(
withImages(
withSass({
i18n: {
locales: ['en', 'fr'],
defaultLocale: 'en',
},
webpack(config, options) {
config.module.rules.push({
test: /\.(eot|ttf|woff|woff2)$/,
use: {
loader: "url-loader",
},
});
config.resolve.modules.push(path.resolve("./"));
return config;
},
})
)
)
);
The object that you pass to the inner-most plugin (withSass() in this case) is your Next config object.
Edit: As for your component's code, you can't call a hook - in this case useRouter - from within a function like that. You'll need to move it to the component.
export default function Index() {
const router = useRouter();
const { locale } = router;
const t = locale === 'en' ? en : fr;
return (
// Your render code
);
}

Related

Why are the components not rerendering after Response?

Table with pinia store equipmentlist, fethced from usequipments but table does not rerender
VueTableComponent
<script setup lang="ts">
import { useEquipmentStore } from '~/store/equipmentStore'
import useEquipments from '~/composables/equipments'
const { getEquipmentList } = useEquipments()
onBeforeMount(() => { getEquipmentList() })
const state = useEquipmentStore()
const equipmentList: any = state.equipmentList
const loaded = state.loaded
</script>
<template>
<el-table :key="loaded" :data="equipmentList" style="width: 100%">
<el-table-column type="expand">
<template #default="props">
ID: {{ props.row.id }}
</template>
</el-table-column>
<el-table-column label="ID" prop="id" />
<el-table-column label="Name" prop="name" />
</el-table>
</template>
Typescript File for all CRUD Operations equipment.ts
import { useRouter } from 'vue-router'
import http from '../http-common'
import { useEquipmentStore } from '~/store/equipmentStore'
export default function useEquipments() {
const state = useEquipmentStore()
const errors = ref([]) // array of strings
const router = useRouter()
const getEquipmentList = async() => {
try {
console.log(state.equipmentList.length)
const response = await http.get('/equipment/list')
state.equipmentList = response.data
console.log(state.equipmentList.length)
console.log(state.equipmentList[0])
}
catch (error: any) {
console.log(error.message)
}
}
Equipment(Pinia)Store
import { defineStore } from 'pinia'
import type { Ref } from 'vue'
export const useEquipmentStore = defineStore('equipment', {
state: () => ({
equipment: ref({}) as any,
equipmentList: ref([]) as Ref<any[]>,
}),
actions: {
reset() {
this.equipment = {}
this.equipmentList = []
},
},
})
1. i called several times getEquipment list and it is faster done then i stored an initial equipment, 2. i clicked on the link on the left and fetched several times more and as u can see there is something fetchd but not displayed, 3. after repeating to home and again to Link the component is there and alll other next fetches do indeed function well
Main.ts
app.component('InputText', InputText)
app.mount('#app')
useEquipments().initDB()
}
same fetching class equipment.ts
const initDB = () => {
try {
if (state.equipmentList.length === 0) { storeEquipment({ id: 1, name: 'Firma' }) }
else {
for (const equipment of state.equipmentList) {
console.log(equipment)
if (equipment === 'Firma')
state.equipmentList.splice(state.equipmentList.indexOf(equipment), 1)
}
}
}
catch (error: any) {
console.log(error.message)
}
}

Cannot be used as a JSX component. Its return type 'Promise<Element>' is not a valid JSX element

I have an React Component Editor. I am trying to initialize the state using an async function. But I am unable to .
How we can do that in React.
const Editor = () => {
const { id } = useParams();
const [schemas, updateSchemas] = useAtom(bfsAtom);
const schema = id && _.get(schemas, id, {});
type InitialStateType = {
properties: KeyedProperty[];
validations: ValidationDataProperty[];
};
const getInitialState = async (): Promise<InitialStateType> => {
return {
properties: createPropertiesFromSchema(schema),
validations: initializeConditions(schema),
};
};
const initialState = await getInitialState();
const mainReducer = (
{ properties, validations }: InitialStateType,
action: Action
) => ({
properties: propertyReducer(properties, action),
validations: validationReducer(validations, action),
});
const [state, dispatch] = useReducer(mainReducer, initialState);
return (
<PropertyContext.Provider value={{ state, dispatch }}>
<SchemaEditor schema={schema} />
</PropertyContext.Provider>
);
};
TL;DR moving the async from top level to inside the component did the trick
Is not directly linked with your question but one thing that I was doing wrong is the following:
I had a component that looked like:
const MyComponent = async () => {
...
const apiResponse = await apiFunction();
return <div>
{apiResponse.success && (
<p>It was a success!</p>
)}
</div>
}
BUT you shouldn't use async in your components at top level. So to fix it I did this:
const MyComponent = () => {
...
const apiResponse = async () => {
return await apiFunction();
}
return <div>
{apiResponse().success && (
<p>It was a success!</p>
)}
</div>
}

mapDispatchToProps not updating store

I'm working on a personal project with redux. My mapStateToProps function seems to me properly written. but when I try to use it to send an object to my store nothing works.
Here's my function:
const mapDispatchToProps = dispatch => {
return {
addOrder: (item) => {
dispatch(addOrder(item));
}
}
}
<div className="recordOrder">
<button onclick={() => this.props.addOrder(this.state)}>Enregistrer et lancer la commande</button>
</div>
And my reducer:
const initialState = {
orderList : []
}
console.log(initialState);
export default function rootReducer ( state= initialState, action){
const orderList = [...state.orderList];
let position
switch (action.type){
case ADD_ORDER:
return {
orderList : [...state.orderList, action.payload]
};
case DELETE_ORDER:
position = orderList.indexOf(action.payload)
orderList.splice(position, 1)
return {
orderList
}
default:
return state;
}
console.log(state)
}
My entire component as requested:
import React, { Component } from 'react';
import { NavItem } from 'react-bootstrap';
import menu from './menu';
import { connect } from 'react-redux';
import { addOrder} from '../action'
class getOrder extends Component {
state = {
number: `CMD-${Date.now()}`,
order:[],
total: 0 ,
menu:menu,
isPaid: false
}
addItem = (index) => {
const order = [...this.state.order];
const menu = [...this.state.menu];
let total = this.state.total;
const pizza = menu[index];
console.log(pizza);
let ind = order.findIndex((item) =>
item.article == pizza.name
)
if (ind === -1){
order.push({article: pizza.name, price: pizza.price, volume:1})
total = total + order[order.length-1].price
} else if (ind != -1){
order[ind].volume++
total = total + order[ind].price
}
this.setState({
order:order,
total:total
})
console.log("youpiii");
console.log(this.state.total);
console.log(this.state.order);
}
render() {
const menuDisplay= menu.map( (item) => {
return (
<div>
<img onClick={() => this.addItem(item.number)} src={`${process.env.PUBLIC_URL}${item.picture}`} alt="picture" />
<div className="tagPrice">
<p>{item.name}</p>
<p>{item.price} €</p>
</div>
</div>
)
});
const currentOrder = [...this.state.order]
const orderDisplay = currentOrder.map((item) => {
let price = item.price*item.volume;
console.log(price);
return (
<div>
<h1>{item.volume} × {item.article}</h1>
<p>{price} €</p>
</div>
)
} );
return (
<div className="takeOrder">
<div className="orderban">
<h1>Pizza Reflex</h1>
</div>
<div>
<div className="menuDisplay">
{menuDisplay}
</div>
<div className="orderBoard">
<h1>Détail de la commande N°{this.state.number}</h1>
{orderDisplay}
<div className="total">
<h2>Soit un total de {this.state.total} € </h2>
</div>
<div className="recordOrder">
<button onclick={() => this.props.addOrder(this.state)}>Enregistrer et lancer la commande</button>
</div>
</div>
</div>
</div>
);
}
}
const mapDispatchToProps = dispatch => {
return {
addOrder: (item) => {
dispatch(addOrder(item));
}
}
}
export default connect ( mapDispatchToProps) (getOrder);
Can someone tell me what I've missed ?
Thanks for your help !
What you are missing is more of your code it can not be solved with what you have.
In more details what I need is the this.state , combinedReducer
The easiest fix you can do now is changing yow mapDispatchToProps works better if it is an obj
const mapStateToProps = (state) => {
return {
// here you specified the properties you want to pass yow component fom the state
}
};
const mapDispatchToProps = {action1, action2};
export default connect ( mapDispatchToProps) (getOrder);
connectreceives two params mapStateToProps and mapDispatchToProps,
mapDispatchToProps is optional, but mapStateToProps is mandatory, there for you need to specified, if your are not going to pass anything you need to pass a null value
export default connect (null, mapDispatchToProps) (getOrder);
also avoid exporting components without a name
example
function MyButton () {}
const MyButtonConnect = connect(state, dispatch)(MyButton);
export default MyButtonConnect

How to change the router history in a functional component using react-redux

I'm trying to migrate a code base from a class component to a functional component, but when I do that my history (browserHistory) and the redirects stop working.
I don't know if it's in the way I'm using useEffect, or forcing the history.push ? But I get a Warning: You cannot change <Router history> on Router and Connected Router. I get the right values from the state and redux and I can see the changes on the location when I console.log it is just that history.push that doesn't happen.
I'm using react-redux and connected-react-router.
What might the problem be?
Use case: Facebook API loads, when user signs in with Facebook, the user is redirected to another page.
This code works: class Component (old code)
class App extends Component {
constructor(props) {
super(props);
this.facebookInterval = undefined;
this.history = createBrowserHistory();
this.state = {
hasFB: false,
error: false,
};
}
/**
* Load the Facebook SDK
*
* #return {void}
*/
componentDidMount() {
this.facebookInterval = setInterval(() => {
if (window.FB !== undefined) {
this.setState({
hasFB: true,
});
clearInterval(this.facebookInterval);
}
}, 100);
window.fbAsyncInit = function () {
window.FB.init({
appId: process.env.REACT_APP_NEW_MESSENGER_APP_ID,
autoLogAppEvents: true,
xfbml: true,
version: 'v3.3',
});
};
(function (d, s, id) {
var js,
fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {
return;
}
js = d.createElement(s);
js.id = id;
js.src =
'https://connect.facebook.net/en_US/sdk.js?xfbml=1&version=v9.0&appId=' +
process.env.REACT_APP_NEW_MESSENGER_APP_ID;
fjs.parentNode.insertBefore(js, fjs);
})(document, 'script', 'facebook-jssdk');
}
// [NOTE]: This works when using the class component
// the redirect happens
componentWillUpdate = (nextProps, nextState) => {
console.log('nextProps.redirect', nextProps.redirect)
console.log('nextProps', nextProps)
console.log('nextState', nextState)
if (nextProps.redirect !== undefined && nextProps.redirect !== '/') {
this.history.push(nextProps.redirect);
}
};
render() {
const { t } = this.props;
if (this.state.hasFB) {
return (
<>
<Elements stripe={stripePromise}>
<ConnectedRouter history={this.history}>{routes}</ConnectedRouter>
</Elements>
</>
);
} else {
return null;
}
}
}
const mapStateToProps = (state) => {
let isLoading = state.siteR.isLoading ? 'open' : 'close';
let data = {
redirect: state.siteR.location,
isLoading: isLoading,
user: state.userR[state.userR.id],
id: state.userR.id,
};
if (state.userR[state.userR.id] !== undefined) {
data.models = state.userR[state.userR.id].models;
}
return data;
};
const mapDispatchToProps = (dispatch) => {
return {
// ommited_code
};
};
export default compose(
connect(mapStateToProps, mapDispatchToProps),
withTranslation(),
)(App);
Same code, but on a functional component (new code)
const App = (props) => {
console.log('props', props)
// console.log('props.redirect', props.redirect)
const [hasFB, setHasFB] = useState(false)
const [error, setError] = useState(false)
const [redirect, setRedirect] = useState(props.redirect)
const history = createBrowserHistory()
let facebookInterval = undefined
const {t} = useTranslation()
const initializeFacebook = () => {
facebookInterval = setInterval(() => {
if (window.FB !== undefined) {
setHasFB(true)
clearInterval(facebookInterval);
}
}, 100);
window.fbAsyncInit = function () {
window.FB.init({
appId: process.env.REACT_APP_NEW_MESSENGER_APP_ID,
autoLogAppEvents: true,
xfbml: true,
version: 'v3.3',
});
};
(function (d, s, id) {
var js,
fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {
return;
}
js = d.createElement(s);
js.id = id;
js.src =
'https://connect.facebook.net/en_US/sdk.js?xfbml=1&version=v9.0&appId=' +
process.env.REACT_APP_NEW_MESSENGER_APP_ID;
fjs.parentNode.insertBefore(js, fjs);
})(document, 'script', 'facebook-jssdk');
}
// [NOTE]: I get the right values from props.redirect
// and the state
// the redirect just doesnt happen
const handleRedirect = () => {
if (props.redirect !== undefined && props.redirect !== '/') {
console.log('redirect on setRedirect', redirect)
setRedirect(history.push(props.redirect))
}
}
useEffect(() => {
initializeFacebook()
handleRedirect()
console.log('redirect on setRedirect', redirect)
}, [])
if (hasFB) {
return (
<>
<Elements stripe={stripePromise}>
<ConnectedRouter history={history}>{routes}</ConnectedRouter>
</Elements>
</>
);
} else {
return null;
}
}
const mapStateToProps = (state) => {
let isLoading = state.siteR.isLoading ? 'open' : 'close';
let showModelSelect = state.modelR.showModelSelect ? 'open' : 'close';
let showModelAdd = state.modelR.showModelAdd ? 'open' : 'close';
let data = {
redirect: state.siteR.location,
isLoading: isLoading,
user: state.userR[state.userR.id],
id: state.userR.id,
};
if (state.userR[state.userR.id] !== undefined) {
data.models = state.userR[state.userR.id].models;
}
return data;
};
const mapDispatchToProps = (dispatch) => {
return {
// ommited_code
};
};
export default compose(
connect(mapStateToProps, mapDispatchToProps),
withTranslation(),
)(App);
The routes I'm trying to switch to/from
const routes = (
<div>
<Switch>
<SentryRoute exact path='/' component={UserLogin} />
<SentryRoute exact path='/user' component={Profile} />
{/* // omited_code */}
</Switch>
</div>
)
export default routes;
From the documentation, it looks like you might be able to use the additional params in the connect function.
import { push } from 'connected-react-router';
/* code stuffs */
props.push('/home');
export default connect(null, { push })(Component);
https://github.com/supasate/connected-react-router/blob/master/FAQ.md#with-react-redux

redirect dependent on ajax result using react

I would like to redirect to a component in case the data of the success has a certain value.
When ajax returns the data, depending on the value of the data redirected to the Contents class that I previously imported.
I've been looking for information about the push method
My error is: Error: Invariant failed: You should not use <Redirect> outside a <Router>
import React, { Component } from 'react';
import { Modal,Button } from 'react-bootstrap';
import $ from 'jquery';
import { Redirect } from 'react-router';
import Contents from './Contents';
class Login extends Component {
constructor(props, context) {
super(props, context);
this.handleShow = this.handleShow.bind(this);
this.handleClose = this.handleClose.bind(this);
this.handleloginClick = this.handleloginClick.bind(this);
this.handleUsernameChange = this.handleUsernameChange.bind(this);
this.handlePasswordChange = this.handlePasswordChange.bind(this);
this.state = {
show: true,
username: "",
password: "",
};
}
handleloginClick(event) {
var parametros = {
username: this.state.username,
password: this.state.password
}
const { history } = this.props;
$.ajax({
data: parametros,
url: "https://privada.mgsehijos.es/react/login.php",
type: "POST",
success: function (data) {
}
});
}
handleUsernameChange(event) {
this.setState({username: event.target.value});
}
handlePasswordChange(event) {
this.setState({password: event.target.value});
}
handleClose() {
this.setState({ show: false });
}
handleShow() {
this.setState({ show: true });
}
render() {
If(Condicion){
return (<Redirect to={'./Contents'} />);
}
return (
//Here my modal.
);
}
}
export default Login;
you can use Router dom to navigate.
My fiddle: https://jsfiddle.net/leolima/fLnh9z50/1/
const AboutUs = (props) => {
console.log(props.location.state)
console.log('Hi, you are in About page, redirecting with router dom in 3 seconds')
setTimeout(() => {
props.history.push('/')}, 3000);
return <h1>Now we're here at the about us page.</h1>;
};
Full Example:
// Select the node we wish to mount our React application to
const MOUNT_NODE = document.querySelector('#app');
// Grab components out of the ReactRouterDOM that we will be using
const { BrowserRouter, Route, Switch, NavLink, Link } = window.ReactRouterDOM;
// PropTypes is used for typechecking
const PropTypes = window.PropTypes;
// Home page component
const Home = () => {
return <h1>Here we are at the home page.</h1>;
};
// AboutUs page component
const AboutUs = (props) => {
console.log(props.location.state)
return <h1>Now we're here at the about us page.</h1>;
};
// NotFoundPage component
// props.match.url contains the current url route
const NotFoundPage = ({ match }) => {
const {url} = match;
return (
<div>
<h1>Whoops!</h1>
<p><strong>{url.replace('/','')}</strong> could not be located.</p>
</div>
);
};
// Header component is our page title and navigation menu
const Header = () => {
// This is just needed to set the Home route to active
// in jsFiddle based on the URI location. Ignore.
const checkActive = (match, location) => {
if(!location) return false;
const {pathname} = location;
return pathname.indexOf('/tophergates') !== -1 || pathname.indexOf('/_display/') !== -1;
}
return (
<header>
<h1>Basic React Routing</h1>
<nav>
<ul className='navLinks'>
{/* Your home route path would generally just be '/'' */}
<li><NavLink to="/tophergates" isActive={checkActive}>Home</NavLink></li>
<li><Link to={{
pathname: "/about",
state: { fromDashboard: true }
}}>About</Link></li>
</ul>
</nav>
</header>
);
};
// Out layout component which switches content based on the route
const Layout = ({children}) => {
return (
<div>
<Header />
<main>{children}</main>
</div>
);
};
// Ensure the 'children' prop has a value (required) and the value is an element.
Layout.propTypes = {
children: PropTypes.element.isRequired,
};
// The top level component is where our routing is taking place.
// We tell the Layout component which component to render based on the current route.
const App = () => {
return (
<BrowserRouter>
<Layout>
<Switch>
<Route path='/tophergates' component={Home} />
<Route path='/_display/' component={Home} />
<Route exact path='/' component={Home} />
<Route path='/about' component={AboutUs} />
<Route path='*' component={NotFoundPage} />
</Switch>
</Layout>
</BrowserRouter>
);
};
// Render the application
ReactDOM.render(
<App />,
MOUNT_NODE
);

Resources