..I have a Next.js application with multi-language support (English as the default language and German as the secondary one - English is on https://mywebsite.com and German on https://mywebsite.com/de).
I'm using next-sitemap to generate a sitemap for the page using alternate refs to link the English and German versions of the pages. The following is my next-sitemap config:
/** #type {import('next-sitemap').IConfig} */
module.exports = {
siteUrl: `https://mywebsite.com`,
generateRobotsTxt: true,
exclude: ['/app/*', '/social-redirect'],
robotsTxtOptions: {
policies: [
{
userAgent: '*',
[process.env.VERCEL_ENV !== 'preview' && process.env.VERCEL_ENV !== 'development'
? 'allow'
: 'disallow']: '/',
},
],
},
alternateRefs: [
{
href: 'https://mywebsite.com',
hreflang: 'en',
},
{
href: 'https://mywebsite.com/de',
hreflang: 'de',
},
],
};
In the generated sitemap the English entries of the sitemap look good. They have the correct alternate refs. But in the German entries of the sitemap, the alternate refs have the language in the path twice, so for example: https://mywebsite.com/de/de/blog. Is this an issue of next-sitemap or am I doing something wrong? I would be glad if someone could help me with that!
This is also happening to me. I think it is an issue of next-sitemap
In my case I have languages en and en-gb The urls generated are:
<xhtml:link rel="alternate" hreflang="en" href="http://localhost:3000/en/en-gb/blog/"/>
<xhtml:link rel="alternate" hreflang="en-gb" href="http://localhost:3000/en-gb/en-gb/blog/"/>
You can use transform prop of next-sitemap.config.js to configure a replacement
`transform: async (config, path) => {
return { ...config,
loc: path.replace('/en-gb/en-gb', '/en-gb')
}
}
Related
In a nextJS project, I want to use jsonplaceholder with /photos route.
When I try to insert image or thumbnails into Image component like bellow, I have an error.
import Image from 'next/image'
<Image src="https://via.placeholder.com/150/92c952" width={150} height={150} />
Server Error
Error: Invalid src prop (https://via.placeholder.com/150/92c952) on
next/image, hostname "via.placeholder.com" is not configured under
images in your next.config.js See more info:
https://nextjs.org/docs/messages/next-image-unconfigured-host
When I check documentation, for external sources, and considering I'm using recent version (13), I should convert my next.config.js like that :
/** #type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'via.placeholder.com',
port: '',
pathname: '/**',
},
],
},
}
module.exports = nextConfig
But I still have an error, maybe because of a null port. But I don't know which port via.placeholder.com is using :(
Trying old next version with code bellow doesn't work either:
images: {
domains: ['via.placeholder.com'],
},
Thanks in advance
You don't need to use curly braces when using a string literal for the image src. You can just do something like <Image src="https://cdn.architect.io/logo/horizontal.png" width={400} height={59.5} alt="Architect Logo" />. Also if you're loading the image from a server using https, the port should be 443. For more context, I added the following in my next.config.js in order to load the image that I referenced:
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'cdn.architect.io',
},
],
},
Also, when trying to load a .png from via.placeholder.com, be sure to include the file type. For example:
<Image src="https://via.placeholder.com/150/92c952.png" width={150} height={150} alt="Placeholder" />
Despite the settings mentioned in other answers (I tested new ones images. remotePatterns and legacy ones images.domains), none was working.
After upgrading from v13.0.7 to v13.1.6 it works now :)
I'm migrating my app to Next.js. Currently I have a url structure like this:
www.example.com/ <-- English
www.example.com/de <-- German
www.example.com/page <-- English
www.example.com/de/page <-- German
So my english website does not have the language in the url. If someone tries to access the website with "en" in the url he will be forwarded.
How would I achieve this in Next.js? Having always two files (i.e. "[language].js" and "index.js") in the /pages directory seems to be not the right solution.
As of Next.js 9.4 there is an experimental feature "Custom Routes". This provides a more elegent solution. See the discussion here: https://github.com/zeit/next.js/issues/9081
Example usage:
// next.config.js
module.exports = {
async rewrites() {
return [
// Basic `path-to-regexp` usage
// Query object shape: { id: string }
{ source: "/user/:id", destination: "/user_profile" },
// Optional Language
// Query object shape: { lang?: string }
{ source: "/:lang(en|es)?/about", destination: "/about" },
// Advanced rewrite
// Query object shape: { id: string } (in addition to dynamic route param)
{ source: "/u/:id", destination: "/user/:id" }
];
}
};
With NextJS 10 you can do this natively.
Your next.config.js would look like this:
module.exports = {
i18n: {
locales: ['en', 'de'],
defaultLocale: 'en',
},
}
The defaultLocale is the language for www.example.com/.
Then you can use a library like next-i18next to store the translations.
UPDATE: As nunorbatista said: With NextJS 10 you can do this natively. Your next.config.js would look like this:
module.exports = {
i18n: {
locales: ['en', 'de'],
defaultLocale: 'en',
},
}
Old answer:
The folder structure is correct, but you don’t need to write duplicate code inside [language] folder. Just import the page from ”main” folder. Multilingual is currenly a bit complex to setup with Next.js. Here is the situation at the moment.
If you want to use library
with serverless deployment you should watch this one.
https://github.com/vinissimus/next-translate
without serverless deployment you should watch this one.
https://github.com/isaachinman/next-i18next
If you want to do it on your own, you should modify them to match your needs.
Next.js version 9.3 or above
https://codesandbox.io/s/92ebn
Next.js version below 9.3
https://github.com/fwojciec/simple-i18n-example
When directly navigating to a child component in prod mode (ng serve --prod) it fails to load the CSS file, trying to fetch it from a nested path. For instance, navigating to "localhost:4200/doc/" the CSS Request URL is:
localhost:4200/doc/styles.6eab038f040a1c7c7ed6.css.
The error that is given:
Refused to apply style from 'http://localhost:4200/doc/styles.6eab038f040a1c7c7ed6.css' because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled.
When accessing the root (localhost:4200) the CSS is loaded correctly. If you then navigate to the child component through the app itself, the problem does not occur.
It only occurs in prod mode, not on the development server. Changed nothing to the regular settings regarding styles.css, it is situated in the default folder.
"styles": [
"src/styles.css"
],
Anyone has any idea how this problem could be caused?
Edit
Found out that the problem lies in navigating to nested routes (helped by the reply of mikegross).
On a route without a nested parameter the problem does not occur, but on a route with a nested parameter (for instance 'doc/:id') it does.
Router module:
const routes: Routes = [
{ path: '', redirectTo: 'list', pathMatch: "full"},
{ path: 'list', component: ListComponent},
{ path: 'doc/:id', component: DocumentComponent},
{ path: '**', redirectTo: ''},
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Update (feb. 28)
Since it was still a small project I generated a new angular project, installed same dependencies and literally copy pasted the code.
Although I have no idea why, in the new project the problem does not occur. The only difference lies in a minor version bump (ng 9.0 to 9.1).
I know this is an older post, but I got around this by using query parameters instead of route parameters. example:
const routes: Routes = [
{ path: '', redirectTo: 'list', pathMatch: "full"},
{ path: 'list', component: ListComponent},
{ path: 'doc', component: DocumentComponent},
{ path: '**', redirectTo: ''},
];
(I removed the :id from "doc/:id")
Navigate to the route:
route this._router.navigate(['/doc'],{queryParams: {id: id}});
Then retrieve the query parameter:
this._activatedRoute.snapshot.queryParamMap.get('id');
Coming late to the party. I had the same error with React in 2022.
Initially, I declared the CSS file with a relative path, as follows:
<link rel="preload" href="./style/Avenir-Light.woff2" as="font" type="font/woff2" crossorigin>
After changing it to an absolute path, it worked
<link rel="preload" href="/style/Avenir-Light.woff2" as="font" type="font/woff2" crossorigin>
Hope it helps future readers.
I am trying to generate a static website out of my (minimal) code with Nuxt. In that code, I integrate in particular the tailwindcss toolkit as well as vue2-leaflet. Upon
nuxt generate
I get two css files, one for the tailwindcss css and the other for the leaflet css. While the former file is fine and contains everything I need, the latter is pretty sparse:
.leaflet-tile-pane{z-index:200}#-webkit-keyframes leaflet-gestures-fadein{to{opacity:1}}#keyframes leaflet-gestures-fadein{0%{opacity:0}to{opacity:1}}
Of course, that makes my map render in a pretty strange way, because most of the css is missing. Here's my current nuxt.config.js:
module.exports = {
mode: 'universal',
head: {
title: pkg.name,
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: pkg.description }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
]
},
css: [
],
plugins: [
{ src: '~plugins/leaflet.js', mode: 'client' }
],
buildModules: [
'#nuxtjs/tailwindcss'
],
modules: ['#nuxtjs/apollo', 'nuxt-purgecss', ['nuxt-i18n', i18n]],
[...]
build: {
extractCSS: true,
}
}
Getting rid of the extractCSS ends up incorporating all the relevant css into the index.html. It works, but then I get the following error:
ERROR Webpack mode only works with build.extractCSS set to *true*. Either extract your CSS or use 'postcss' mode
I'm not sure I understand how that whole css extraction works. Could someone enlighten me? Why is it not working with extractCSS: true? How can I make it work? Why is it working in SPA mode but not in static mode?
You are using nuxt-purgecss which is using purgecss to strip unused CSS.
purgecss do scan HTML (or vue) files for CSS classes in use and then strip unused classes from final CSS bundle.
You can take a look at default purgecss configuration used by nuxt-purgecss here. The paths lists the paths purgecss will scan for CSS usage.
Because you are not using most of the leaflet css directly (in your components), its is necessary to configure purgecss to don't remove leaflet's css.
You can do that by whitelisting (btw not sure if "comment" method will work in Vue\Nuxt)
You can read more here and here
Not tested!!
// nuxt.config.js
{
purgeCSS: {
whitelistPatterns: [/leaflet/, /marker/]
}
}
Regarding the error message
Error message is from nuxt-purgecss module - it is clearly documented here
I don't have deep knowledge of Nuxt build process. So I just assume from the docs that extractCSS: true will use extract-css-chunks-webpack-plugin to extract all CSS to separate CSS file, while (default) extractCSS: false will use PostCSS to extract all CSS and put it directly into the <style> tag of rendered page.
All of that doesn't matter IMHO because the root problem is the use of purgecss and the solution is to configure it correctly to whitelist leaflet CSS classes....
I'm developing a Wordpress Plugin that allows users to add custom video playlists to their pages or posts, and for that I'm using Videojs and Videojs Playlist libraries.
I've successfully managed to add a single playlist into a page, but when a second one is created the first player is disabled.
First Player disabled
Other problem I'm facing is that, although the vjs-playlist div is added, it only shows in the first player created.
Code display in the browser
var options = {"techOrder": ["html5","youtube", "flash"]};
var myPlayer = videojs('my-playlist-player', {options, "autoplay": false, "controls": true, "fluid": true, "liveui": true});
myPlayer.playlist([{
name: 'Test item 1 type .m3u8',
description: 'Testing for videojs-playlist-ui integration',
duration: '45',
sources: [
{src: '//vjs.zencdn.net/v/oceans.mp4',type: 'video/mp4'}
],
thumbnail: [
{
srcset: '//bcvid.brightcove.com/players-example-content/clouds-1800.jpg',
type: 'image/jpeg',
style: 'max-height: 120px;'
}
]
},{
name: resTitle,
description: resDesc,
duration: resDuration,//'45',
sources: [
{src: resItemSrc, type: resMime}
],
thumbnail: [
{
srcset: resThumbnail,
type: resImgType,
style: thumbStyle//'max-height: 120px;'
}
]
}
}
]);
console.log(myPlayer.playlist());
myPlayer.playlistUi({el: document.getElementById('vjs-playlist'), horizontal: true});
myPlayer.playlist.autoadvance(1);
I believe my errors happen because videojs functions are detecting the same id in all elements, but if so how could I avoid this?
Any other ideas or opinions on why this errors might be happening, would be great.
Thanks in advance.
A bit more of information, I wanted to check how many players the script detected and so I printed in the console the window.videojs.players and only one player is detected even if more are created. Check result
Could this be because they have the same ID? If so how could it be fixed? HTML Result