Hi I am following the docs from here: github docs
, but all URLs with locales return 404.
For the example:
localhost:3000/de/second-page = 404
localhost:3000/en/second-page = 404
localhost:3000/de = 404
localhost:3000/en = 404
same for the default locale.
localhost:3000/second-page = 200
localhost:3000 = 200
I guess, this is because there is no pages/de/second-page.js, for the example, but what's the purpose then of this library, if it doesn't solve this problem.
I have searched a lot and I know about localSubpaths, but seems that it doesn't work:
module.exports = new NextI18Next({
otherLanguages: ['fr'],
//localeSubpaths: localeSubpathVariations[localeSubpaths],
localeSubpaths: {
de: 'de',
en: 'en',
}
})
It doesn't work in my app, but it doesn't work in their sample, too: their sample
Have you checked these two steps ?
After creating and exporting your NextI18Next instance, you need to
take the following steps to get things working:
Create an _app.js file inside your pages directory, and wrap it with
the NextI18Next.appWithTranslation higher order component (HOC). You
can see this approach in the examples/simple/pages/_app.js. Your app
component must either extend App if it's a class component or define a
getInitialProps if it's a functional component (explanation here).
Create a next.config.js file inside your root directory if you want to
use locale subpaths. You can see this approach in the
examples/simple/next.config.js (Next.js 9.5+ required).
const { nextI18NextRewrites } = require('next-i18next/rewrites')
const localeSubpaths = {
de: 'de',
en: 'en',
};
module.exports = {
rewrites: async () => nextI18NextRewrites(localeSubpaths),
publicRuntimeConfig: {
localeSubpaths,
},
}
Related
So i'm using the Contentful API to get some content from my account and display it in my Next.Js app (i'm using next 9.4.4). Very basic here. Now to protect my credentials, i'd like to use environment variables (i've never used it before and i'm new to all of this so i'm a little bit losted).
I'm using the following to create the Contentful Client in my index.js file :
const client = require('contentful').createClient({
space: 'MYSPACEID',
accessToken: 'MYACCESSTOKEN',
});
MYSPACEID and MYACCESSTOKEN are hardcoded, so i'd like to put them in an .env file to protect it and don't make it public when deploying on Vercel.
I've created a .env file and filled it like this :
CONTENTFUL_SPACE_ID=MYSPACEID
CONTENTFUL_ACCESS_TOKEN=MYACCESSTOKEN
Of course, MYACCESSTOKEN and MYSPACEID contains the right keys.
Then in my index.js file, i do the following :
const client = require('contentful').createClient({
space: `${process.env.CONTENTFUL_SPACE_ID}`,
accessToken: `${process.env.CONTENTFUL_ACCESS_TOKEN}`,
});
But it doesn't work when i use yarn dev, i get the following console error :
{
sys: { type: 'Error', id: 'NotFound' },
message: 'The resource could not be found.',
requestId: 'c7340a45-a1ef-4171-93de-c606672b65c3'
}
Here is my Homepage and how i retrieve the content from Contentful and pass them as props to my components :
const client = require('contentful').createClient({
space: 'MYSPACEID',
accessToken: 'MYACCESSTOKEN',
});
function Home(props) {
return (
<div>
<Head>
<title>My Page</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main id="page-home">
<Modal />
<NavTwo />
<Hero item={props.myEntries[0]} />
<Footer />
</main>
</div>
);
}
Home.getInitialProps = async () => {
const myEntries = await client.getEntries({
content_type: 'mycontenttype',
});
return {
myEntries: myEntries.items
};
};
export default Home;
Where do you think my error comes from?
Researching about my issue, i've also tried to understand how api works in next.js as i've read it could be better to create api requests in pages/api/ but i don't understand how to get the content and then pass the response into my pages components like i did here..
Any help would be much appreciated!
EDIT :
So i've fixed this by adding my env variables to my next.config.js like so :
const withSass = require('#zeit/next-sass');
module.exports = withSass({
webpack(config, options) {
const rules = [
{
test: /\.scss$/,
use: [{ loader: 'sass-loader' }],
},
];
return {
...config,
module: { ...config.module, rules: [...config.module.rules, ...rules] },
};
},
env: {
CONTENTFUL_SPACE_ID: process.env.CONTENTFUL_SPACE_ID,
CONTENTFUL_ACCESS_TOKEN: process.env.CONTENTFUL_ACCESS_TOKEN,
},
});
if you are using latest version of nextJs ( above 9 )
then follow these steps :
Create a .env.local file in the root of the project.
Add the prefix NEXT_PUBLIC_ to all of your environment variables.
eg: NEXT_PUBLIC_SOMETHING=12345
use them in any JS file like with prefix process.env
eg: process.env.NEXT_PUBLIC_SOMETHING
You can't make this kind of request from the client-side without exposing your API credentials. You have to have a backend.
You can use Next.js /pages/api to make a request to Contentful and then pass it to your front-end.
Just create a .env file, add variables and reference it in your API route as following:
process.env.CONTENTFUL_SPACE_ID
Since Next.js 9.4 you don't need next.config.js for that.
By adding the variables to next.config.js you've exposed the secrets to client-side. Anyone can see these secrets.
New Environment Variables Support
Create a Next.js App with Contentful and Deploy It with Vercel
Blog example using Next.js and Contentful
I recomended to update at nextjs 9.4 and up, use this example:
.env.local
NEXT_PUBLIC_SECRET_KEY=i7z7GeS38r10orTRr1i
and in any part of your code you could use:
.js
const SECRET_KEY = process.env.NEXT_PUBLIC_SECRET_KEY
note that it must be the same name of the key "NEXT_PUBLIC_ SECRET_KEY" and not only "SECRET_KEY"
and when you run it make sure that in the log says
$ next dev
Loaded env from E:\awesome-project\client\.env.local
ready - started server on http://localhost:3000
...
To read more about environment variables see this link
Don't put sensitive things in next.config.js however in my case I have some env variables that aren't sensitive at all and I need them Server Side as well as Client side and then you can do:
// .env file:
VARIABLE_X=XYZ
// next.config.js
module.exports = {
env: {
VARIABLE_X: process.env.VARIABLE_X,
},
}
You have to make a simple change in next.config.js
const nextConfig = {
reactStrictMode: true,
env:{
MYACCESSTOKEN : process.env.MYACCESSTOKEN,
MYSPACEID: process.env.MYSPACEID,
}
}
module.exports = nextConfig
change it like this
Refer docs
You need to add a next.config.js file in your project. Define env variables in that file and those will be available inside your app.
npm i --save dotenv-webpack#2.0.0 // version 3.0.0 has a bug
create .env.development.local file in the root. and add your environment variables here:
AUTH0_COOKIE_SECRET=eirhg32urrroeroro9344u9832789327432894###
NODE_ENV=development
AUTH0_NAMESPACE=https:ilmrerino.auth0.com
create next.config.js in the root of your app.
const Dotenv = require("dotenv-webpack");
module.exports = {
webpack: (config) => {
config.resolve.alias["#"] = path.resolve(__dirname);
config.plugins.push(new Dotenv({ silent: true }));
return config;
},
};
However those env variables are gonna be accessed by the server. if you want to use any of the env variables you have to add one more configuration.
module.exports = {
webpack: (config) => {
config.resolve.alias["#"] = path.resolve(__dirname);
config.plugins.push(new Dotenv({ silent: true }));
return config;
},
env: {
AUTH0_NAMESPACE: process.env.AUTH0_NAMESPACE,
},
};
For me, the solution was simply restarting the local server :)
Gave me a headache and then fixed it on accident.
It did not occur to me that env variables are loaded when the server is starting.
I'm trying to implement client routes in Gatsby together with gatsby-plugin-react-i18next for two languages. I followed officel Gataby documentation and there is no client only path implementation explained.
Below is the code i implemeted.
gatsby-node.js
function langPrefix(page) {
return page.context.language === page.context.i18n.defaultLanguage &&
!page.context.i18n.generateDefaultLanguagePage
? ''
: `/${page.context.language}`
}
exports.onCreatePage = ({ page, actions }) => {
const { createPage } = actions
// Removing the ^ skips an optional /:lang prefix
if (page.path.match(/\/app/)) {
// adding lang if it's not the default page.
page.matchPath = `${langPrefix(page)}/app/*`
createPage(page)
}
}
Appjs
src/app/app.js
function App() {
return (
<>
<Router basepath="/:lang/app">
<PrivateRoute path="/accounthome" component={AccountHome} location=""/>
</Router>
<Router basepath="/app">
<PrivateRoute path="/accounthome" component={AccountHome} location=""/>
</Router>
</>)
}
export default App
Gatsby config
{
resolve: `gatsby-plugin-react-i18next`,
options: {
localeJsonSourceName: `locale`, // name given to `gatsby-source-filesystem` plugin.
languages: ["en", "fr"],
defaultLanguage: `en-us`,
fallbackLanguage: `en-us`,
// if you are using Helmet, you must include siteUrl, and make sure you add http:https
siteUrl: `https://my.costco.com/`,
ns: langTranslationConfig,
// you can pass any i18next options
i18nextOptions: {
interpolation: {
escapeValue: false // not needed for react as it escapes by default
},
nsSeparator: false
},
pages: [
{
matchPath: '/:lang/app/accounthome',
getLanguageFromPath: true,
excludeLanguages: ['en-ca']
},
{
matchPath: '/preview',
languages: ['en']
}
]
}
}
Router path : http://localhost:8000/en-us/app/accounthome
When am accessing this rote in browser This code show Gatsby.js development 404 page not found. Any pointer what am missing and am not sure how to access the translation contents in client only route page example account home page. Do i need to write the graph query in account home page or i dont need to ?
I think your regex is leaking your code. I guess it should look like:
if (page.path.match(/^\/app/)) {
page.matchPath = `${langPrefix(page)}/app/*`
createPage(page)
}
Either way, check the created page list by accessing the 404 page in development mode. By default, there should be a list of all created pages. Check the paths there to see if you can spot any mistakes or trailing slash issues.
The problem here is that your page is not being generated properly, that's why it throws a 404, so checking the created pages may help you to spot the mistake or at least, a thread to pull.
After a few research I've seen that you are basing your approach in: Gatsby can't find client routes when using gatsby-plugin-react-i18next
In their case, the langPrefix function is only prefixing the language to the page slug if it's the default one:
function langPrefix(page) {
return page.context.language === page.context.i18n.defaultLanguage &&
!page.context.i18n.generateDefaultLanguagePage
? ''
: `/${page.context.language}`
}
In your case, I'm not sure the plugin supports en-us (it's en-US according to https://github.com/microapps/gatsby-plugin-react-i18next/issues/100) and I think that's the reason why there's a leak in your page creation. Try using en instead of en-us or directly looking for en-US paths.
I have a doubt with nextjs..
I'm building my site like this
pages
[slug]
index.jsx
index.jsx
so in my slug/index I'm doing this
export async function getStaticPaths() {
const resProducts = await fetch(`${process.env.PRIVATE_ENDPOINT}/products`);
const products = await resProducts.json();
const paths = products.data.map((p) => ({
params: {
slugProduct: p.slug,
},
}));
return {
// this should be dynamic
paths,
fallback: true,
};
}
My question is what happend if I add a new product in my back office?
Do I have to rebuild with next build?
My question is what happend if I add a new product in my back office?
Do I have to rebuild with next build?
The short answer is NO. If the requested page have not been genereted at build time, Next.js will serve a "fallback" version of the page and will statically generate the requested path HTML and JSON on the background. When the statically generation completed, the browser receives the JSON for the generated path. Subsequent requests to the same path will serve the generated page, just like other pages pre-rendered at build time.
Don't forget to use router.isFallback to detect that request is on fallback.
You can see the good document here.
https://nextjs.org/docs/basic-features/data-fetching#getstaticpaths-static-generation
I am looking through next.js documentation and trying to understand what the suggested approach is for setting URLs that change in different environments. Mostly, I want to ensure that I'm pointing backend URLs correctly in development versus production.
I suppose you can create a constants configuration file, but is there a supported, best practice for this?
Open next.config.js and add publicRuntimeConfig config with your constants:
module.exports = {
publicRuntimeConfig: {
// Will be available on both server and client
yourKey: 'your-value'
},
}
you can call it from another .js file like this
import getConfig from 'next/config'
const { publicRuntimeConfig } = getConfig()
console.log(publicRuntimeConfig.yourKey)
or even call it from view like this
${publicRuntimeConfig.yourKey}
You can configure your next app using next-runtime-dotenv, it allows you to specify serverOnly / clientOnly values using next's runtime config.
Then in some component
import getConfig from 'next/config'
const {
publicRuntimeConfig: {MY_API_URL}, // Available both client and server side
serverRuntimeConfig: {GITHUB_TOKEN} // Only available server side
} = getConfig()
function HomePage() {
// Will display the variable on the server’s console
// Will display undefined into the browser’s console
console.log(GITHUB_TOKEN)
return (
<div>
My API URL is {MY_API_URL}
</div>
)
}
export default HomePage
If you don't need this separation, you can use dotenv lib to load your .env file, and configure Next's env property with it.
// next.config.js
require('dotenv').config()
module.exports = {
env: {
// Reference a variable that was defined in the .env file and make it available at Build Time
TEST_VAR: process.env.TEST_VAR,
},
}
Check this with-dotenv example.
I'm using koa-static to serve static file with root url localhost:3000/, and koa-router to serve RESTful api, like localhost:3000/api/account/login
Make a fakeBuild folder contain only one file index.html. All work fine. root url and api url show correct content.
// serve static file
const serve = require('koa-static')
const staticPath = path.join(__dirname,'..','Client','poker','fakeBuild')
log(staticPath)
app.use(serve(staticPath))
// router
const router = require('./router/Index.js')(app)
Then I try to connect Koa with React
I use yarn build to build React static files, React project is created by create-react-app, not modified.
Then I change the koa-static's target to build folder, just one line changed
const staticPath = path.join(__dirname,'..','Client','poker','build')
Then access localhost:3000/, chrome show React start page, works
Then access localhost:3000/api/account/login, chrome show React start page, what??
Use postman check localhost:3000/api/account/login, it response what I put in router, fine.
So I can use apis, just ignore chrome's result?
It must be React and Chrome doing something extra. I try to remove service-worker.js in React build folder, api url render correctly in chrome.
So anyone can give some documents or explain to help me understand what react done, to keep all the url render it.
And why my api localhost:3000/api/account/login not require service-worker.js (just return some text in response body), also got the js worked. Just because koa-static served the file?
====
Update: my router code, And project available on here
router/Index.js
const Router = require('koa-router');
const R = (app)=>{
const router = new Router();
const api = require('./Api.js');
router.use('/api', api.routes(), api.allowedMethods())
app.use(router.routes())
.use(router.allowedMethods());
};
module.exports = R;
router/Api.js
const Router = require('koa-router')
const log = require('../helper/Utils').log;
module.exports = (function () {
const Api = new Router();
Api.get('/account/login', async (ctx, next)=>{
log("hello");
ctx.status = 200;
ctx.body = `login`
});
Api.get('/account/register', async (ctx, next)=>{
ctx.status = 200;
ctx.body = `register`
});
return Api;
})();