typescript - Làm thế nào tôi có thể tạo metadata động thay đổi cho từng trang đa ngôn ngữ sử dụng Next.js 13.4 và next-intl?
Tôi chỉ đang học Next.js từng chút một, và tôi muốn tạo một trang đa ngôn ngữ, tôi đang làm điều đó với next-intl, nhưng tôi không giỏi lắm về việc tạo Metadata, những gì tôi muốn là nó có thể thay đổi động, hiện tại với đoạn mã tôi có, nếu nó cập nhật metadata, nhưng chỉ khi trang tải, ví dụ, nếu tôi muốn chia sẻ liên kết của trang của mình, og và twitter, nó sẽ hiển thị theo mặc định và những gì tôi muốn là mỗi trang sẽ có tiêu đề khác nhau và tải og đúng, có ai có thể giúp tôi không?
Layout.tsx:
import { NextIntlClientProvider } from "next-intl";
import { notFound } from "next/navigation";
import { createTranslator } from "next-intl";
import { Footer } from "@/components/Footer";
import { Nav } from "@/components/Nav";
import { Analytics } from "@vercel/analytics/react";
import "./globals.css";
interface LocaleLayoutProps {
children: React.ReactNode;
params: { locale: string };
}
export function generateStaticParams() {
return [
{ locale: "es" },
{ locale: "en" },
{ locale: "zh" },
{ locale: "hi" },
{ locale: "bn" },
{ locale: "pt" },
{ locale: "ru" },
{ locale: "ja" },
];
}
export async function generateMetadata({ params: { locale } }: LocaleLayoutProps) {
const messages = (await import(`../../messages/${locale}.json`)).default;
const t = createTranslator({ locale, messages });
return {
generator: "Next.js",
title: t("Metadata.title"),
description: t("Metadata.description"),
keywords: t("Metadata.keywords"),
applicationName: t("Metadata.title"),
type: "website",
icons: {
icon: "/logo.png",
shortcut: "/logo.png",
apple: "/logo.png",
},
twitter: {
card: "summary_large_image",
title: t("Metadata.title"),
description: t("Metadata.description"),
images: {
url: t("Metadata.image"),
},
app: {
name: "twitter_app",
id: {
iphone: "twitter_app://iphone",
ipad: "twitter_app://ipad",
googleplay: "twitter_app://googleplay",
},
url: {
iphone: "https://iphone_url",
ipad: "https://ipad_url",
},
},
},
openGraph: {
title: t("Metadata.title"),
description: t("Metadata.description"),
},
robots: {
index: false,
follow: true,
nocache: true,
googleBot: {
index: true,
follow: false,
noimageindex: true,
"max-video-preview": -1,
"max-image-preview": "large",
"max-snippet": -1,
},
},
};
}
export default async function LocaleLayout({ children, params: { locale } }: LocaleLayoutProps) {
let messages;
try {
messages = (await import(`../../messages/${locale}.json`)).default;
} catch (error) {
notFound();
}
return (
<html lang={locale}>
<body>
<NextIntlClientProvider locale={locale} messages={messages}>
<Analytics />
<Nav />
<div className='flex-grow'>{children}</div>
<Footer />
</NextIntlClientProvider>
</body>
</html>
);
}
Trang.tsx:
"use client";
import { useTranslations } from "next-intl";
import Head from "next/head";
import { useEffect } from "react";
export default function Page() {
const t = useTranslations("Articulos.Curiosidades_Secretos.id_1");
useEffect(() => {
const updateMetaTags = () => {
const metaTags = [
{ name: "description", content: t("PaginaHeader") },
{ property: "og:title", content: t("PaginaTitulo") },
{ property: "og:description", content: t("PaginaHeader") },
{ property: "og:image", content: t("PagineImage") },
{ name: "twitter:title", content: t("PaginaTitulo") },
{ name: "twitter:description", content: t("PaginaHeader") },
{ name: "twitter:image", content: t("PagineImage") },
];
metaTags.forEach(({ name, property, content }) => {
const tag = document.querySelector(`meta[name="${name}"], meta[property="${property}"]`);
if (tag) {
tag.setAttribute("content", content);
}
});
};
updateMetaTags();
document.title = t("PaginaTitulo");
}, [t]);
return (
<>
<main className='w-4/5 mx-auto flex flex-col'>
...
</main>
</>
);
}
Câu trả lời #1
Để làm cho metadata trở nên động trong Next.js với next-intl, bạn có thể cập nhật các thẻ metadata trong component Page bằng cách sử dụng component Head từ next/head và hook useTranslations. Dưới đây là một ví dụ về cách bạn có thể cập nhật metadata một cách động:
Trang.tsx:
import { useTranslations } from "next-intl";
import Head from "next/head";
import { useEffect } from "react";
export default function Page() {
const t = useTranslations("Articulos.Curiosidades_Secretos.id_1");
useEffect(() => {
const updateMetaTags = () => {
const metaTags = [
{ name: "description", content: t("PaginaHeader") },
{ property: "og:title", content: t("PaginaTitulo") },
{ property: "og:description", content: t("PaginaHeader") },
{ property: "og:image", content: t("PagineImage") },
{ name: "twitter:title", content: t("PaginaTitulo") },
{ name: "twitter:description", content: t("PaginaHeader") },
{ name: "twitter:image", content: t("PagineImage") },
];
metaTags.forEach(({ name, property, content }) => {
const tag = document.querySelector(`meta[name="${name}"], meta[property="${property}"]`);
if (tag) {
tag.setAttribute("content", content);
}
});
};
updateMetaTags();
document.title = t("PaginaTitulo");
}, [t]);
return (
<>
<Head>
<title>{t("PaginaTitulo")}</title>
</Head>
{/* Rest of your page content */}
</>
);
}
Trong hook useEffect, hàm updateMetaTags chịu trách nhiệm cập nhật các thẻ metadata bằng cách chọn các thẻ phù hợp dựa trên thuộc tính name hoặc property của chúng và thiết lập thuộc tính content của chúng với các giá trị đã được dịch từ t. document.title cũng được cập nhật để thiết lập tiêu đề trang.
Đảm bảo rằng bạn có các bản dịch cần thiết cho Articulos.Curiosidades_Secretos.id_1.PaginaHeader, Articulos.Curiosidades_Secretos.id_1.PaginaTitulo, và Articulos.Curiosidades_Secretos.id_1.PaginaImage trong các tệp dịch của bạn.
Bằng cách sử dụng phương pháp này, siêu dữ liệu sẽ được cập nhật một cách động khi trang tải, cho phép có các tiêu đề khác nhau và các thẻ Open Graph (og) và Twitter được tải chính xác khi chia sẻ liên kết trang.
