ค้นหาเว็บไซต์

typescript - ฉันสามารถสร้างเมตาดาต้าที่เปลี่ยนแปลงได้สำหรับแต่ละหน้าหลายภาษาโดยใช้ Next.js 13.4 และ next-intl ได้อย่างไร?


ฉันเพิ่งเริ่มเรียน nextjs ทีละเล็กทีละน้อย และฉันอยากทำหน้าเว็บหลายภาษา ฉันกำลังทำมันด้วย next-intl แต่ฉันไม่ค่อยเก่งในการสร้าง Metadata สิ่งที่ฉันอยากได้คือให้มันเป็นแบบไดนามิก ตอนนี้ด้วยโค้ดที่ฉันมี หากมันอัปเดต metadata ก็จะอัปเดตแค่ตอนโหลดหน้าเว็บเท่านั้น ตัวอย่างเช่น หากฉันอยากจะแชร์ลิงก์ของหน้าฉัน og และ twitter มันจะออกมาเป็นค่าเริ่มต้น และสิ่งที่ฉันอยากได้คือแต่ละหน้ามีชื่อเรื่องแตกต่างกันและโหลด og ได้อย่างถูกต้อง ใครช่วยฉันได้ไหม?

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>
  );
}

Page.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>
    </>
  );
}

คำตอบ #1

เพื่อทำให้เมตาดาต้าเป็นแบบไดนามิกใน Next.js ด้วย next-intl คุณสามารถอัปเดตแท็กเมตาดาต้าในคอมโพเนนต์ Page โดยใช้คอมโพเนนต์ Head จาก next/head และ hook useTranslations นี่คือตัวอย่างวิธีที่คุณสามารถอัปเดตเมตาดาต้าได้อย่างไดนามิก:

Page.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 */}
    </>
  );
}

ใน hook useEffect ฟังก์ชัน updateMetaTags มีหน้าที่ในการอัปเดตแท็กเมตาโดยการเลือกแท็กที่เหมาะสมตามชื่อหรือแอตทริบิวต์ property ของพวกมันและตั้งค่าแอตทริบิวต์ content ด้วยค่าที่แปลแล้วจาก t นอกจากนี้ document.title ยังได้รับการอัปเดตเพื่อตั้งชื่อหน้าด้วย

ตรวจสอบให้แน่ใจว่าคุณมีการแปลที่จำเป็นสำหรับ Articulos.Curiosidades_Secretos.id_1.PaginaHeader, Articulos.Curiosidades_Secretos.id_1.PaginaTitulo, และ Articulos.Curiosidades_Secretos.id_1.PaginaImage ในแฟ้มการแปลของคุณ

โดยการใช้วิธีนี้ เมทาดาต้าจะถูกอัปเดตแบบไดนามิกเมื่อหน้าเว็บโหลด ทำให้สามารถมีชื่อเรื่องที่แตกต่างกันและแท็ก Open Graph (og) และ Twitter ถูกโหลดอย่างถูกต้องเมื่อแชร์ลิงก์หน้าเว็บ