I´m looking for way to load static texts into storybook via next-translate.
My code looks like this, but it´s loading my locale files, but not writing them properly.
This is storybook preview.js:
import '../src/styles/global/global.scss';
import CssBaseline from '#material-ui/core/CssBaseline';
import { ThemeProvider } from '#material-ui/core/styles';
import theme from '../src/utils/theme';
import I18nProvider from 'next-translate/I18nProvider';
import commonCS from '../locales/cs/common.json';
export const decorators = [(Story) => themeDecorator(Story)];
const themeDecorator = (Story) => {
console.log(commonCS.homepage_title);
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<I18nProvider lang={'cs-CS'} namespaces={{ commonCS }}>
<Story />
</I18nProvider>
</ThemeProvider>
);
};
export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: { expanded: true },
};
And this is my storybook storie:
import React from 'react';
import HeaderContact from './HeaderContact';
import I18nProvider from 'next-translate/I18nProvider';
import useTranslation from 'next-translate/useTranslation';
import commonCS from '../../../locales/cs/common.json';
export default {
title: 'HeaderContact',
component: HeaderContact,
};
export const Basic = () => {
const { t } = useTranslation('common');
return (
<HeaderContact
link="mailto:info#numisdeal.com"
text={t('homepage_title')}
/>
);
};
My local file common.json:
{
"homepage_title": "Blog in Next.js",
"homepage_description": "This example shows a multilingual blog built in Next.js with next-translate"
}
And my translate config i18n.json
{
"locales": ["cs", "en", "de"],
"defaultLocale": "cs",
"pages": {
"*": ["common"]
}
}
I would be very glad for some help.
Thanks!
Roman
Here is the solution.
preview.js
import '../src/styles/global/global.scss';
import CssBaseline from '#material-ui/core/CssBaseline';
import { ThemeProvider } from '#material-ui/core/styles';
import theme from '../src/utils/theme';
import I18nProvider from 'next-translate/I18nProvider';
import commonCS from '../locales/cs/common.json';
export const decorators = [(Story) => themeDecorator(Story)];
const themeDecorator = (Story) => {
console.log(commonCS.homepage_title);
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<I18nProvider lang={'cs'} namespaces={{ common: commonCS }}>
<Story />
</I18nProvider>
</ThemeProvider>
);
};
export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: { expanded: true },
};
Storie:
import React from 'react';
import HeaderContact from './HeaderContact';
export default {
title: 'HeaderContact',
component: HeaderContact,
};
export const Basic = () => {
return <HeaderContact link="mailto:info#numisdeal.com" />;
};
Component:
import React from 'react';
import AlternateEmailIcon from '#material-ui/icons/AlternateEmail';
import useTranslation from 'next-translate/useTranslation';
import styles from './HeaderContact.module.scss';
export interface IHeaderContact {
link: string;
text?: string;
}
export default function HeaderContact(props: IHeaderContact) {
const { link, text } = props;
const { t } = useTranslation('common');
const preklad = t('homepage_title');
return (
<a href={link} className={styles.headerLink}>
<AlternateEmailIcon fontSize="small" />
<span>
{/* {text} */}
{preklad}
</span>
</a>
);
}
Related
The point is to implement a dynamic SSR component can be re-rendered by a search input.
I solved this by creating a layout.tsx file on my specific router then import children which made me dynamic render ssr component by the client component:
Layout.tsx
import React, { Suspense } from "react";
import Search from "./Search";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="layout">
<Search />
{children}
</div>
);
}
Search.tsx
"use client";
import { FormEvent, useState } from "react";
import { useRouter } from "next/navigation";
export default function Search() {
const [text, setText] = useState<string>("")
const router: any = useRouter();
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
setText('')
router.push(`/definition/${text}`)
}
return (
<form onSubmit={handleSubmit} className='search'>
<input onChange={(e) => setText(e.target.value)}
value={text} type="text"
placeholder={"write to search"} />
</form>
);
} );
}
Need One Help i am trying to call api in nextjs using
redux(Here,SSR is not possible)
and getServerSideProps(Here, SSR is Possible but without redux) in both case API Called Successfully. If i used it individually bot are working well but now i want to merge it both and i have read about next-redux-wrapper but when i am integrate it.
API Called Using GetServerSideProps()
index.js
`
import Product from "./product-cart";
import React from "react";
import styles from "../styles/Product.module.css";
import axios from "axios";
const Home = ({ products, loading }) => {
return (
<>
{loading ? (
<h1>Loading...</h1>
) : (
<>
<div className={styles.banner}>
<p>Welcome to ecommerce!</p>
<h1>FIND AMAZING PRODUCT BELOW</h1>
<a href="#container">
<button>Scroll</button>
</a>
</div>
<h2 className={styles.homeHeading}>Featured Product</h2>
<div className={styles.container} id="container">
{products &&
products.map((products) => (
<Product key={products._id} products={products} />
))}
</div>
</>
)}
</>
);
};
export default Home;
export async function getServerSideProps(context) {
let link = `http://localhost:5000/api/v1/product`;
const { data } = await axios.get(link);
return { props: { products: data.product } };
}
`
API Called Using Redux
_app.js
`
import { Provider } from "react-redux";
import store, { wrapper } from "../redux/store";
import "../styles/globals.css";
function MyApp({ Component, pageProps }) {
return (
<>
<Provider store={store}>
<Component {...pageProps} />
</Provider>
</>
);
}
// export default wrapper.withRedux(MyApp);
export default MyApp;
`
index.js(GetProduct() Created In Action File)
`
import Product from "./product-cart";
import React from "react";
import styles from "../styles/Product.module.css";
import { clearErrors, getProduct } from "../redux/Actions/ProductAction";
import { useSelector, useDispatch, connect } from "react-redux";
import axios from "axios";
import { wrapper } from "../redux/store";
const Home = ({ products, loading }) => {
const { loading, error, products } = useSelector(
(state) => state.products || {}
);
const dispatch = useDispatch();
React.useEffect(() => {
if (error) {
dispatch(clearErrors());
}
dispatch(getProduct());
}, [dispatch]);
return (
<>
{loading ? (
<h1>Loading...</h1>
) : (
<>
<div className={styles.banner}>
<p>Welcome to ecommerce!</p>
<h1>FIND AMAZING PRODUCT BELOW</h1>
<a href="#container">
<button>Scroll</button>
</a>
</div>
<div suppressHydrationWarning>
{process.browser ? "browser" : "server"}
</div>
<h2 className={styles.homeHeading}>Featured Product</h2>
<div className={styles.container} id="container">
{products &&
products.map((products) => (
<Product key={products._id} products={products} />
))}
</div>
</>
)}
</>
);
};
export default Home;
`
If you need more information let me know
TypeError: makeStore is not a function
enter image description here
Try to Use Next-redux-wrapper but not able to find solution regarding that
_app.js
import { Provider } from "react-redux";
import store, { wrapper } from "../redux/store";
import "../styles/globals.css";
function MyApp({ Component, pageProps }) {
return (
<>
<Provider store={store}>
<Component {...pageProps} />
</Provider>
</>
);
}
export default wrapper.withRedux(MyApp);
store.js
import {
createStore,
combineReducers,
applyMiddleware,
legacy_createStore,
} from "redux";
import thunk from "redux-thunk";
// import { createStore } from "redux";
import { createWrapper, HYDRATE } from "next-redux-wrapper";
import { composeWithDevTools } from "redux-devtools-extension";
import {
adminProductEDReducer,
AdminProductReducer,
newProductReducer,
newReviewReducer,
productDetailReducer,
productReducer,
} from "./Reducers/ProductReducer";
import {
userReducer,
profileReducer,
forgotPasswordReducer,
allUserReducer,
userDetailsReducer,
} from "./Reducers/UserReducers";
const reducer = combineReducers({
products: productReducer,
productDetails: productDetailReducer,
adminProduct: AdminProductReducer,
newProduct: newProductReducer,
user: userReducer,
profile: profileReducer,
forgotPassword: forgotPasswordReducer,
newReview: newReviewReducer,
EditDelProduct: adminProductEDReducer,
allUser: allUserReducer,
userDetail: userDetailsReducer,
});
// if the value is in cart otherwise it will be blank and we can store cartitems in localstorage
let initialState = {};
const middleware = [thunk];
const store = legacy_createStore(
reducer,
initialState,
composeWithDevTools(applyMiddleware(...middleware))
);
// export an assembled wrapper
export const wrapper = createWrapper(store, { debug: true });
export default store;
I'm very new in RN and i was making simple app and got this error:
The action 'NAVIGATE' with payload {"name":"LoginScreen"} was not handled by any navigator.
Do you have a screen named 'LoginScreen'?
If you're trying to navigate to a screen in a nested navigator, see https://reactnavigation.org/docs/nesting-navigators#navigating-to-a-screen-in-a-nested-navigator.
My App.js:
import { StatusBar } from 'expo-status-bar';
import React from 'react'
import { StyleSheet, Text, View } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import LoginScreen from './screens/LoginScreen'
import HomeScreen from './screens/HomeScreen'
const Stack = createNativeStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen options={{headerShown: false}} name="Login" component={LoginScreen} />
<Stack.Screen name="Home" component={HomeScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
HomeScreen.js:
import { StackActions, useNavigation } from '#react-navigation/core'
import React from 'react'
import { StyleSheet, Text, TouchableOpacity, View, Button, SafeAreaView } from 'react-native'
import { auth } from '../firebase'
import { NavigationContainer } from '#react-navigation/native';
import { createNativeStackNavigator } from '#react-navigation/native-stack';
import AuditScreen from './AuditScreen';
import ReportAuditScreen from './ReportAuditScreen';
import LoginScreen from './LoginScreen';
const HomeScreen = () => {
const navigation = useNavigation()
const Stack = createNativeStackNavigator()
const handleSignOut = () => {
auth
.signOut()
.then(() => {
navigation.replace("Login")
})
.catch(error => alert(error.message))
}
return (
<SafeAreaView>
<View>
<Text>Siema Home</Text>
<Button title="Out" onPress={handleSignOut}/>
<Button title="Audit" onPress={() => navigation.navigate("AuditScreen")}/>
</View>
</SafeAreaView>
)
}
I want to go to AuditScreen after click Audit button.
Locale change works well in my next.js app, except for with dynamic routes. In the browser address bar I do get the transition from http://localhost:3000/client/home/profile to http://localhost:3000/de/client/home/profile, but the page gives a 404 error...
My dynamic page [tab].tsx
import router from 'next/router'
import dynamic from 'next/dynamic'
import styled from 'styled-components'
import {useTranslation, i18n} from 'next-i18next'
import {useEffect, useState, useContext} from 'react'
import {serverSideTranslations} from 'next-i18next/serverSideTranslations'
import Layout from 'layouts'
import {DB, PATH} from 'utils/constants'
import {GlobalContext} from 'utils/contexts'
import {Tabs, LanguageSelector} from 'components/ui'
import {ChartData, ChartDataPoint, UsageStats} from 'utils/types'
import {getData, toTitleCase, isClient, emailVerified} from 'utils/helpers'
const Docs = dynamic(() => import('components/client/docs'))
const Stats = dynamic(() => import('components/client/stats'))
const Profile = dynamic(() => import('components/client/profile'))
const Tab = ({tab}) => {
const {t} = useTranslation()
return (
<Layout>
<LanguageSelector />
<Tabs
basePath={'/client/home'}
tab={tab}
tabs={[
{
slug: 'stats',
label: t('client.home.stats'),
component: <Stats data={data} />
},
{
slug: 'profile',
label: t('client.home.profile'),
component: <Profile client={client} />
},
{
slug: 'docs',
label: t('client.home.docs'),
component: <Docs />
}
]}
/>
</Layout>
)
}
export const getStaticProps = async ({params, locale}) => ({
props: {
tab: params.tab,
...await serverSideTranslations(locale)
}
})
export const getStaticPaths = async () => {
return {
paths: [
{params: {tab: 'stats'}},
{params: {tab: 'profile'}},
{params: {tab: 'docs'}}
],
fallback: false
}
}
export default Tab
I do the locale switching in my LanguageSelector.tsx:
import router from 'next/router'
import {i18n} from 'next-i18next'
import {useState, useEffect} from 'react'
import {Select} from '.'
import {LANGUAGES} from 'utils/constants'
export const LanguageSelector = () => {
const [locale, setLocale] = useState(i18n.language)
useEffect(() => {
const {pathname, asPath, query} = router
router.push({pathname, query}, asPath, {locale})
}, [locale])
return (
<Select
borderless
isSearchable={false}
value={i18n.language}
options={LANGUAGES.filter(language => language !== i18n.language)}
onValueChange={setLocale}
/>
)
}
Any ideas where my mistake is?
If you are using getStaticPaths with in-build Next.js i18n routing then you also need to return locale key with your paths, like that:
export const getStaticPaths = ({ locales }) => {
return {
paths: [
{ params: { slug: 'post-1' }, locale: 'en-US' },
{ params: { slug: 'post-1' }, locale: 'fr' },
],
fallback: true,
}
}
More info in the docs
I upgraded meteor and I started receiving deprecation warning for createContainer(). As a result, I've tried to implement withTracker however now I'm getting Component(...): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.. I'm not sure what I'm missing here, can someone point out my error.
Path: App.jsx
import { Meteor } from 'meteor/meteor';
import React from 'react';
import PropTypes from 'prop-types';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { withTracker } from 'meteor/react-meteor-data';
// IsCandidate Spefic Routes
import TestContainer from '../../containers/candidate/TestContainer';
const App = appProps => (
<Router>
<ScrollToTop>
<div className="bgColor">
<NavBar {...appProps} />
<Grid className="main-page-container">
<Switch>
{/* candidate routes */}
<IsCandidate exact path="/candidate/testpage/:id" component={withTracker(TestContainer)} {...appProps} />
{/* IsPublic routes */}
<Route render={function () {
return <p>Page not found</p>;
}}
/>
</Switch>
</Grid>
</div>
</ScrollToTop>
</Router>
);
App.propTypes = {
loggingIn: PropTypes.bool,
isCandidate: PropTypes.bool
};
export default createContainer(() => {
const loggingIn = Meteor.loggingIn();
return {
loggingIn,
isCandidate: !loggingIn && !!Meteor.userId() && !!Roles.userIsInRole(Meteor.userId(), 'isCandidate'),
};
}, App);
Path: IsCandidate.jsx
import React from 'react';
import PropTypes from 'prop-types'; // ES6
import { Route, Redirect } from 'react-router-dom';
const IsCandidate = ({ loggingIn, isCandidate, component: Component, ...rest }) => (
<Route
{...rest}
render={(props) => {
if (loggingIn) return <div />;
return isCandidate ?
(<Component loggingIn={loggingIn} isCandidate={isCandidate} {...rest} {...props} />) :
(<Redirect to="/login" />);
}}
/>
);
IsCandidate.propTypes = {
loggingIn: PropTypes.bool,
isCandidate: PropTypes.bool,
component: PropTypes.func
};
export default IsCandidate;
Path: Testcontainer.jsx
import { Meteor } from 'meteor/meteor';
import { withTracker } from 'meteor/react-meteor-data';
import { Test } from '../../../api/test/test';
import TestPage from '../../pages/candidate/TestPage';
export default TestContainer = withTracker(({ match }) => {
const testHandle = Meteor.subscribe('test', match.params.id);
const loadingTest = !testHandle.ready();
const testCollection = Test.findOne(match.params.id);
const testExist = !loadingTest && !!testCollection;
return {
loadingTest,
testExist,
testCollection: testExist ? testCollection : {}
};
}, TestPage);
Update
export default withTracker(() => {
const loggingIn = Meteor.loggingIn();
return {
loggingIn,
isCandidate: !loggingIn && !!Meteor.userId() && !!Roles.userIsInRole(Meteor.userId(), 'isCandidate'),
isEmployer: !loggingIn && !!Meteor.userId() && !!Roles.userIsInRole(Meteor.userId(), 'isEmployer'),
isAdmin: !loggingIn && !!Meteor.userId() && !!Roles.userIsInRole(Meteor.userId(), 'isAdmin')
};
})(App);
In App.jsx you import withTracker but use createContainer.
withTracker takes only one argument (your reactive function) and wraps your child component where createContainer took 2 arguments (function and component).
createContainer(fn, C);
withTracker(fn)(C);
EDIT
Remove the withTracker call in App.js from this line:
<IsCandidate exact path="/candidate/testpage/:id" component={withTracker(TestContainer)} {...appProps} />
so it becomes
<IsCandidate exact path="/candidate/testpage/:id" component={TestContainer} {...appProps} />
How about it?