SuperAPI AI 工具集

sfnext-i18n

前端与建站

查看项目

更新于 10-16 06:03

技能介绍

用途

sfnext-i18n 用于在 Storefront Next 中实现国际化(i18n),基于 i18next,采用服务端与客户端双实例架构。

主要能力

  • 双实例架构:服务端实例可访问所有语言的全部翻译;客户端实例以 JavaScript 分块方式动态导入翻译。
  • 双 API:组件中使用 useTranslation(),非组件代码中使用 getTranslation()。
  • 翻译文件按语言区域(locale)以命名空间文件组织,并编译为 TypeScript 索引。
  • 支持扩展(extension)翻译,使用由扩展目录名自动派生的 extPascalCase 命名空间。
  • 提供语言切换组件 LocaleSwitcher。

翻译文件结构

翻译按语言区域组织为命名空间文件,并编译为 TypeScript 索引:

src/locales/en-US/
├── index.ts              # Merges all namespace files + extensions
├── translations.json     # Default namespace (top-level keys become namespaces)
└── product.json          # "product" namespace (separate file)

src/locales/en-GB/
├── index.ts
├── translations.json
└── product.json

index.ts 导入所有命名空间文件与扩展翻译:

import translations from '@/locales/en-US/translations.json';
import product from '@/locales/en-US/product.json';
import extensionTranslations from '@/extensions/locales/en-US/';

const allTranslations = { ...translations, product, ...extensionTranslations };
export default allTranslations satisfies ResourceLanguage;

translations.json 中的命名空间结构:每个顶层键即为一个命名空间。

{
    "header": {
        "search": "Search",
        "account": "Account"
    },
    "footer": {
        "copyright": "© {{year}} Company"
    }
}

独立命名空间文件(product.json):

{
    "title": "Product Details",
    "addToCart": "Add to Cart",
    "greeting": "Hello, {{name}}!",
    "itemCount_one": "{{count}} item",
    "itemCount_other": "{{count}} items"
}

使用方式

在组件中使用

import { useTranslation } from 'react-i18next';

export function ProductCard() {
    const { t } = useTranslation('product');

    return (
        <div>
            <h1>{t('title')}</h1>
            <button>{t('addToCart')}</button>
            <p>{t('greeting', { name: 'John' })}</p>
            <p>{t('itemCount', { count: 5 })}</p>
        </div>
    );
}

关键:始终为 useTranslation() 传入命名空间。

// WRONG — missing namespace
const { t } = useTranslation();
t('title');  // Will not find the key

// CORRECT — with namespace
const { t } = useTranslation('product');
t('title');  // Works

在服务端代码中使用

import { getTranslation } from '@/lib/i18next';

// In loaders/actions (pass context)
export function loader(args: LoaderFunctionArgs) {
    const { t } = getTranslation(args.context);
    return { title: t('product:title') };
}

// Client-side utilities (no context)
const { t } = getTranslation();
const message = t('product:addToCart');

校验模式 — 工厂函数模式

关键:为带翻译消息的 Zod 模式使用工厂函数,以避免竞态条件。

// WRONG — Module-level schema (race condition: t() may not be initialized)
export const schema = z.object({
    email: z.string().email(t('validation:emailInvalid'))
});

// CORRECT — Factory function
import type { TFunction } from 'i18next';

export const createSchema = (t: TFunction) => {
    return z.object({
        email: z.string().email(t('validation:emailInvalid'))
    });
};

// Usage in component
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';

function MyForm() {
    const { t } = useTranslation();
    const schema = useMemo(() => createSchema(t), [t]);

    const form = useForm({ resolver: zodResolver(schema) });
}

语言切换

import LocaleSwitcher from '@/components/locale-switcher';

export function Footer() {
    return <footer><LocaleSwitcher /></footer>;
}

扩展翻译

扩展使用由扩展目录名自动派生的 extPascalCase 命名空间:

src/extensions/my-extension/locales/
├── en-US/translations.json
└── it-IT/translations.json
const { t } = useTranslation('extMyExtension');
t('welcome');

常见陷阱

陷阱 问题 解决方案
缺少命名空间 找不到键 始终传入命名空间:useTranslation('product')
模式中使用模块级 t() 初始化竞态条件 使用工厂模式:createSchema(t)
服务端忘记传 context 找不到翻译 在 loaders 中使用 getTranslation(args.context)
跨命名空间键重复 显示错误翻译 加命名空间前缀:t('product:title')

相关技能

  • storefront-next:sfnext-components — 在 UI 组件中使用翻译
  • storefront-next:sfnext-extensions — 扩展翻译命名空间
  • storefront-next:sfnext-configuration — 语言区域与站点配置

适用场景

适用于在 Storefront Next 项目中添加多语言支持、组织翻译文件、在组件与服务端代码中调用翻译、处理表单校验消息本地化、切换语言以及为扩展添加翻译等开发场景。

限制

资料未提供该技能的收费、价格、平台支持范围、性能效果等具体信息。