How to get locale in nextjs in document component? - next.js

I want to set locale in script google map like this:
<script defer src={`https://maps.googleapis.com/maps/api/js?key=key&libraries=places&language=${locale}`}/>
but how can i get to locale in Document nextJS?
useRouter doesnot work in Document component.
export default function Document() {
return (
<Html>
<Head>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<script defer src={`https://maps.googleapis.com/maps/api/js?key=key&libraries=places&language=${locale}`}/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}

You can access locale in this.props.locale.
In my project this locale uses in this case:
<Html lang={this.props.locale}>
/....
I use class component in _document.
In your variant you can access locale just in props.
import { Html, Head, Main, NextScript } from "next/document";
export default function Document(props: DocumentProps) {
return (
<Html lang={props.locale}>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
It works if you already add i18n config, and inject it to next config.
https://codesandbox.io/p/sandbox/musing-noether-7loye1?file=%2Fpages%2F_document.tsx&selection=%5B%7B%22endColumn%22%3A9%2C%22endLineNumber%22%3A11%2C%22startColumn%22%3A9%2C%22startLineNumber%22%3A11%7D%5D

Related

How to add a favicon to a nextjs app structure? - possible hydration issue

I'm trying to figure out how to add a favicon file to a next.js app (with react 18).
I have made a _document page that has a head tag as follows:
import * as React from "react"
// import {createRoot} from 'react-dom/client'
import { ColorModeScript } from "#chakra-ui/react"
import Document, { Head, Html, Main, NextScript } from "next/document"
import Favicon from "../components/Favicon"
export default class AppDocument extends Document {
static getInitialProps(ctx: any) {
return Document.getInitialProps(ctx)
}
render() {
return (
<Html lang="en">
<Head>
<meta name="theme-color" key="theme-color" content="#000000" />
<meta name="description" content="name" key="description" />
<meta property="og:title" content="title goes here" key="title" />
<meta property="og:description" content="description goes here" key="og:description" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" />
<Favicon />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
I then made a component called Favicon with:
import React from "react";
const Favicon = (): JSX.Element => {
return (
<React.Fragment>
<link rel="apple-touch-icon" sizes="76x76" href="/apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
<link rel="manifest" href="/site.webmanifest" />
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5" />
<meta name="msapplication-TileColor" content="#da532c" />
<meta name="theme-color" content="#ffffff" />
</React.Fragment>
)
}
export default Favicon;
I then made a root/packages/src/public folder (this folder is at the same level and place as the pages folder that has the _document.tsx file) and saved each of the assets to it.
I don't get an error, but the favicon does not populate in the browser tab.
How can I add a favicon in nextjs?
I also tried removing the Favicon component and moving the meta tags directly to app.tsx. It still doesnt render the favicon.
I can see from the console errors that the files are not found. They are all saved in the project at public/[file name]. Public is a folder at the same level as the pages directory.
I have working a working favicon in a Next.js 12 + React 18 app by adding the icon link directly to the <Head> and the images in public/[file name].
render() {
return (
<Html lang="en">
<Head>
<link rel="shortcut icon" href="/favicon.ico" />
I assume that your React component is not working because the browser is trying to load the favicon before the page has been hydrated with any Javascript that can generate your React component favicon.
I solved this problem. You need to add the image to the public directory. Next engine will detect this favicon automatically.
but if you need to add special image or etc, you must add image file into public/static folder. and your url should be start with static/*. like this:
<React.Fragment>
<link rel="icon" sizes="76x76" href="static/apple-touch-icon.png" />
</React.Fragment>
And finally, to display the icon in the browser tab, you must perform a hard refresh Ctrl+F5;
You should just add/replace the icon file with the name favicon.ico in the root of the public folder with your icon. If you want to do SEO consider using "next-seo" package
What I do, I create a component say Meta.tsx and use it inside my Pages
import { NextSeo } from "next-seo"
import type { OpenGraph } from "next-seo/lib/types"
import { useRouter } from "next/router"
import type { MetaProps } from "../../types/content"
export const Meta = ({
type = "website",
siteName = "My-site-name",
data,
}: MetaProps): React.ReactElement => {
const router = useRouter()
// TODO Make generator based on different data
const seoData = data
const locale = "en_EN"
const baseURL = process.env.BASE_URL || window.location.origin
const currentURL = baseURL + router.asPath
const seo = {
title: seoData.title,
titleTemplate: `%s - ${siteName}`,
defaultTitle: siteName,
canonical: currentURL,
}
const openGraph: OpenGraph = {
title: seoData.title,
type,
locale,
url: currentURL,
site_name: siteName,
images: seoData.images,
}
const metaLinks = [
{
rel: "icon",
type: "image/svg+xml",
href: "/favicon.svg",
},
{
rel: "apple-touch-icon",
href: "/touch-icon-ipad.jpg",
sizes: "180x180",
},
{
rel: "mask-icon",
type: "image/svg+xml",
color: "#0d2e41",
href: "/favicon.svg",
},
{
rel: "icon",
href: "/favicon.ico",
},
]
return (
<NextSeo
{...seo}
openGraph={openGraph}
additionalLinkTags={metaLinks}
noindex={data.requireAuth || data.noIndex}
/>
)
}
I think you are just missing the correct rel attribute. This works in my project:
import {Html, Head, Main, NextScript} from 'next/document';
export default function Document() {
return (
<Html lang="en">
<Head>
<link rel="shortcut icon" href="/site/images/favicon.ico" />
...
where /site from /site/images/favicon.ico is in the public folder.
import Head from "next/head";
<Head>
// If favicon path is public/images/
<link rel="icon" type="image/x-icon" href="/images/favicon.ico" />
</Head>
Then you can render this inside Header component or Lay out component. this
<link rel="icon" type="image/x-icon" href="/images/favicon.ico" /> should work also in _document page if you pass correct `href
The easiest way is to just put the <Head> in your layout component.
import Head from "next/head"
const Layout = ({ children, home }: Props) => {
return (
<>
<div className={styles.container}>
<Head>
<link rel="icon" type="image/svg" href="/icons/YOURICON.svg" />
....rest of your <meta> tags for SEO ....
</Head>
....rest of your html/jsx like page header/main-stage/footer/etc..
)}
Make sure that your icon is in a correct format, put in a folder the image named icon.png and use imagemagick to convert it to .icon format
brew install imagemagick
convert icon.png -scale 16 tmp/16.png
convert icon.png -scale 32 tmp/32.png
convert icon.png -scale 48 tmp/48.png
convert icon.png -scale 128 tmp/128.png
convert icon.png -scale 256 tmp/256.png
convert tmp/16.png tmp/32.png tmp/48.png tmp/128.png tmp/256.png icon.ico
Then i use to generate a component for the initial head content HeadContent.js
const HeadContent = () => (
<>
<link
rel="shortcut icon"
sizes="16x16 24x24 32x32 48x48 64x64"
href="/favicon.ico"
/>
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<meta content="yes" name="apple-mobile-web-app-capable" />
<meta
name="apple-mobile-web-app-status-bar-style"
content="black-translucent"
/>
</>
);
export default HeadContent;
Now in _document.js you can use the HeadContent.js:
import Document, { Html, Head, Main, NextScript } from "next/document";
import HeadContent from "#components/HeadContent";
export default class extends Document {
render() {
return (
<Html lang="es-co">
<Head>
<meta charSet="UTF-8" />
<HeadContent />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
inside pages/_app.tsx
import Head from "next/head";
<Head>
<link rel="icon" href="/favicon.ico" />
</Head>

Importing a css file for a different page in React

I am having an issue where when I try and import css onto each page, it will appear on all pages instead of just one. I have my CSS importing in _document.js
import { Html, Head, Main, NextScript } from 'next/document'
export default function Document() {
return (
<Html>
<Head>
<link rel="stylesheet" href="/styles/index.css" />
<link rel="stylesheet" href="index.css"/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/fontawesome.min.css" integrity="sha512-xX2rYBFJSj86W54Fyv1de80DWBq7zYLn2z0I9bIhQG+rxIF6XVJUpdGnsNHWRa6AvP89vtFupEPDP8eZAtu9qA==" crossOrigin="anonymous" referrerPolicy="no-referrer" />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
and I want to know how I can import this CSS on a per-page basis, instead of having all css files on all pages. I have tried importing the css inside of each JS file, but it seems to want to go to /pagehere/styles/settings.css instead of /styles/settings.css even when I put import '../styles/settings.css'. Thanks.
Remove the <Link>s and try using import '../../stryles/settings.css' instead.

Any nextjs example where I need to use _document over _app

It seems I can do everything that I need to do in both _app and _document for my application just in _app like
// _app.tsx
import Head from 'next/head';
export default function App({ Component, pageProps }) {
return (
<>
<Head>
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no"
/>
<title>Payment</title>
</Head>
<Component {...pageProps} />
</>
);
}
Then when should I use _document necessarily? I found _document pointless because:
I shouldn't place viewport meta tags in _document as nextjs compiler warnings about it. (I thought _document is a good place for markups in head because _document gets called only once on server-side and not on client-side) If I can't place everything of a kind like head markup in one place, I'd like to avoid using that way.
You'll need _document if you want to customize a page's <html> and <body> tags. For example...
Adding the global lang attribute:
<Html lang="en">
Adding custom styles:
<body className="bg-white">
_document is where you put third party links and scripts
import Document, { Html, Head, Main, NextScript } from 'next/document'
class MyDocument extends Document {
render() {
return (
<Html>
<Head>
<link
href="https://fonts.googleapis.com/css2?family=Inter&display=optional"
rel="stylesheet"
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument
If you are using styled components you need to configure it in _document.jsx file.
https://github.com/massaaki/nextjs-with-styled-component/blob/main/src/pages/_document.tsx

can't solve next-head-count is missing error

I know this is a duplicate, but I couldn't solve my problem with those answers. so here is my code:
//_document.tsx
import Document, { Html, Head, Main, NextScript } from "next/document";
export default class MyDocument extends Document {
render() {
return (
<Html>
<Head />
<body dir="rtl">
<Main />
<NextScript />
</body>
</Html>
);
}
}
//_app.tsx
import "../styles/globals.scss";
import Head from "next/head";
import type { AppProps } from "next/app";
function MyApp({ Component, pageProps }: AppProps) {
return (
<>
<Head>
<title>Bitbarg</title>
<meta name="description" content="Descriptions" />
<link rel="icon" href="/favicon.ico" />
<body dir="rtl" />
</Head>
<Component {...pageProps} />
</>
);
}
export default MyApp;
I'm still getting this error.
I tried taking all _app.tsx Head tag in _document.tsx, this removed the error but I'm getting new error as:
Titles should be defined at the page-level using next/head.
I tried only putting code bellow in _app.tsx, but it gives me the next-head-count error again.
<Head>
<title>Bitbarg</title>
</Head>
Resolved when I removed
from _app.js as I was using it already in _document.js

Head component from next/head renders into <body> instead of <head>

I am setting up a project in nextjs. I would like to add some global meta tags and title to the project. I used the Head component from next/head in _app.tsx but they are being rendered in the body instead of the head both on localhost and when deployed using vercel. I have used next before and can't remember running into this issue.
Here is my _app.tsx
import { AppProps } from 'next/app'
import Head from 'next/head'
import Footer from '../components/footer'
import MobileNavBar from '../components/mobileNavBar'
import NavBar from '../components/navBar'
import '../styles.scss'
const App = ({ Component, pageProps }: AppProps) => {
return (
<>
<Head>
<html lang="en" />
<title> Erika's Dog Training </title>
<meta
content="width=device-width, initial-scale=1, maximum-scale=5, shrink-to-fit=no"
name="viewport"
></meta>
<script type="text/javascript" src="https://assets.calendly.com/assets/external/widget.js"></script>
</Head>
<MobileNavBar />
<NavBar />
<Component {...pageProps} />
<Footer />
</>
)
}
export default App;
So the meta tag and title here are showing up on the page, but at the top of the <body> tag instead of in <head>
I had the same problem with next: "11.1.2". Removing <html lang="en" /> fixed the problem. I added the lang value back using: (https://melvingeorge.me/blog/set-html-lang-attribute-in-nextjs)
/* next.config.js */
module.exports = {
i18n: {
locales: ["en"],
defaultLocale: "en",
},
};
Consider the structure of this example from the nextjs documentation.
import Document, { Html, Head, Main, NextScript } from 'next/document'
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument
The main differences that I see, is that in the documentation they place both head and body as siblings within <Html> tags. I suspect that is your problem. I would also remove the empty <> and </> tags.
You have the line: <html lang="en" /> Inside the Head tag. This is going to make it challenging for next to generate the correct html as the html tag is generally above both Head and body tags.
Place <html lang="XX"/> as the last child of <Head>.
Example:
<Head>
<title> Erika's Dog Training</title>
<meta content="width=device-width, initial-scale=1, maximum-scale=5, shrink-to-fit=no" name="viewport" />
<html lang="en" />
</Head>

Resources