You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js客户端渲染:如何用next-intl实现映射数据的动态翻译

Next.js next-intl 动态卡片数据国际化翻译实现方案

我是Next.js新手,使用客户端渲染结合next-intl做国际化,目前已完成静态文本(如标题、按钮)的翻译,但在遍历apartmentData生成卡片组件时,不知道如何动态翻译card.title、card.rating、card.locationText等字段。

现有组件代码

"use client";

import { useState } from "react";
import Slider from "react-slick";
import "slick-carousel/slick/slick.css";
import "slick-carousel/slick/slick-theme.css";
import { useTranslations } from "next-intl";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
  faDollarSign,
  faStar,
  faLocationDot,
  faChevronLeft,
  faChevronRight,
} from "@fortawesome/free-solid-svg-icons";
import apartmentData from "../apartmentData";

export default function CardSlider() {
  const [sliderRef, setSliderRef] = useState(null);

  const t = useTranslations("Popular Apartments");

  const sliderSettings = {
    arrows: false,
    slidesToShow: 3,
    responsive: [
      {
        breakpoint: 1280,
        settings: {
          slidesToShow: 2,
        },
      },
      {
        breakpoint: 900,
        settings: {
          slidesToShow: 1,
        },
      },
    ],
  };

  const cards = apartmentData;

  return (
    <div>
      <div>
        <div>
          <h2>{t("section title")}</h2>
          <div>
            <button onClick={sliderRef?.slickPrev}>
              <FontAwesomeIcon icon={faChevronLeft} color="white" />
            </button>
            <button onClick={sliderRef?.slickNext}>
              <FontAwesomeIcon icon={faChevronRight} color="white" />
            </button>
          </div>
        </div>
        <Slider ref={setSliderRef} {...sliderSettings}>
          {cards.map((card, index) => (
            <div key={index}>
              <div style={{ backgroundImage: `url(${card.imageSrc})` }}></div>
              <div>
                <div>
                  <h5>{card.title}</h5>
                  <div>
                    <FontAwesomeIcon icon={faStar} />
                    <span className="ml-2 font-bold">{card.rating}</span>
                  </div>
                </div>
                <div>
                  <div>
                    <div>
                      <FontAwesomeIcon icon={faLocationDot} />
                    </div>
                    <div>{card.locationText}</div>
                  </div>
                  <div>
                    <div>
                      <FontAwesomeIcon
                        icon={faDollarSign}
                        className="h-3 w-6"
                      />
                    </div>
                    <div>{card.pricingText}</div>
                  </div>
                </div>
                <p>{card.description}</p>
              </div>
              <button>{t("btn")}</button>
            </div>
          ))}
        </Slider>
      </div>
    </div>
  );
}

已完成的静态翻译

<h2>{t("section title")}</h2>
<button>{t("btn")}</button>

现有bhs.json翻译文件

{
  "Popular Apartments": {
    "section title": "Popularni Apartmani",
    "btn": "Rezervišite",
    "cards": [
      {
        "title": "Soho Paradise",
        "rating": "4.9",
        "locationText": "Ibiza, Španija",
        "pricingText": "USD 50/dan",
        "description": "fantastičan pogled na more"
      },
      {
        "title": "Hotel Baja",
        "rating": "5.0",
        "locationText": "Palo Alto, CA",
        "pricingText": "USD 19/dan",
        "description": "najbolje ocenjen smeštaj"
      },
      {
        "title": "Hudak Homes",
        "rating": "4.5",
        "locationText": "Arizoa, RAK",
        "pricingText": "USD 99/dan",
        "description": "cela vila za one sa dubokim džepom"
      },
      {
        "title": "Wyatt Residency",
        "rating": "4.8",
        "locationText": "Rim, Italija",
        "pricingText": "USD 39/dan",
        "description": "sakriven dragulj u srcu Rima"
      }
    ]
  }
}

解决方案

方案1:通过数组索引匹配翻译(快速适配现有结构)

利用next-intl的路径访问语法,直接通过遍历的index定位到翻译文件中对应位置的卡片内容:

修改卡片遍历的代码片段:

{cards.map((card, index) => (
  <div key={index}>
    <div style={{ backgroundImage: `url(${card.imageSrc})` }}></div>
    <div>
      <div>
        <h5>{t(`cards[${index}].title`)}</h5>
        <div>
          <FontAwesomeIcon icon={faStar} />
          <span className="ml-2 font-bold">{t(`cards[${index}].rating`)}</span>
        </div>
      </div>
      <div>
        <div>
          <div>
            <FontAwesomeIcon icon={faLocationDot} />
          </div>
          <div>{t(`cards[${index}].locationText`)}</div>
        </div>
        <div>
          <div>
            <FontAwesomeIcon
              icon={faDollarSign}
              className="h-3 w-6"
            />
          </div>
          <div>{t(`cards[${index}].pricingText`)}</div>
        </div>
      </div>
      <p>{t(`cards[${index}].description`)}</p>
    </div>
    <button>{t("btn")}</button>
  </div>
))}

注意:此方案依赖apartmentData和翻译文件中cards数组的顺序完全一致,若后续数据顺序调整,翻译会对应错误。


方案2:通过唯一ID匹配翻译(更可靠)

为了避免顺序依赖问题,给每个卡片添加唯一标识,修改数据结构和翻译文件:

  1. 更新apartmentData.js,给每个卡片对象添加id字段:
export default [
  {
    id: "soho-paradise",
    imageSrc: "your-image-url",
    title: "Soho Paradise",
    // ...其他原有字段
  },
  {
    id: "hotel-baja",
    imageSrc: "your-image-url",
    title: "Hotel Baja",
    // ...其他原有字段
  },
  // ...剩余卡片
];
  1. 修改bhs.json,将cards从数组改为对象,用id作为键:
{
  "Popular Apartments": {
    "section title": "Popularni Apartmani",
    "btn": "Rezervišite",
    "cards": {
      "soho-paradise": {
        "title": "Soho Paradise",
        "rating": "4.9",
        "locationText": "Ibiza, Španija",
        "pricingText": "USD 50/dan",
        "description": "fantastičan pogled na more"
      },
      "hotel-baja": {
        "title": "Hotel Baja",
        "rating": "5.0",
        "locationText": "Palo Alto, CA",
        "pricingText": "USD 19/dan",
        "description": "najbolje ocenjen smeštaj"
      },
      // ...剩余卡片翻译
    }
  }
}
  1. 修改组件中的遍历代码:
{cards.map((card) => (
  <div key={card.id}>
    <div style={{ backgroundImage: `url(${card.imageSrc})` }}></div>
    <div>
      <div>
        <h5>{t(`cards.${card.id}.title`)}</h5>
        <div>
          <FontAwesomeIcon icon={faStar} />
          <span className="ml-2 font-bold">{t(`cards.${card.id}.rating`)}</span>
        </div>
      </div>
      <div>
        <div>
          <div>
            <FontAwesomeIcon icon={faLocationDot} />
          </div>
          <div>{t(`cards.${card.id}.locationText`)}</div>
        </div>
        <div>
          <div>
            <FontAwesomeIcon
              icon={faDollarSign}
              className="h-3 w-6"
            />
          </div>
          <div>{t(`cards.${card.id}.pricingText`)}</div>
        </div>
      </div>
      <p>{t(`cards.${card.id}.description`)}</p>
    </div>
    <button>{t("btn")}</button>
  </div>
))}

此方案不受数据顺序影响,更适合长期维护。


内容的提问来源于stack exchange,提问作者IvanaS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 10:24:54