翻译共享字符串
如何对共享字符串进行国际化处理
概览
共享字符串是指在应用中多个位置复用的字符串或常量。
例如,你可能有一个在多个组件中使用的字符串,或一个在多个文件中复用的常量。
在传统的 i18n 库中,你需要为每个共享字符串创建一个字典。
本指南将带你了解如何使用 msg()
函数和 useMessages()
钩子,在 React 应用中轻松实现共享字符串的国际化。
我们将涵盖以下内容:
何时使用 msg()
函数
如何使用 msg()
函数和 useMessages()
钩子
使用变量
示例
常见陷阱
何时使用 msg()
函数
msg()
是一个用于标记待翻译字符串的简单函数。
先看一个包含字符串的共享对象示例:
export const navData = {
home: {
label: 'Home',
description: 'The home page',
icon: 'home',
href: '/',
},
about: {
label: 'About',
description: 'Information about the company',
icon: 'info',
href: '/about',
},
}
通常,要对这个对象进行国际化,你需要为每个字符串创建一个词典项,或者把对象重构为一个返回带有翻译数据的函数。
例如,你可以这样做:
export const getNavData = (t: (content: string) => string) => ({
home: {
label: t('Home'),
description: t('The home page'),
icon: 'home',
href: '/',
},
about: {
label: t('About'),
description: t('Information about the company'),
icon: 'info',
href: '/about',
},
})
在应用中其他导入了 navData
的地方,你都需要改为调用 getNavData(t)
。
import { getNavData } from '@/navData';
export default function Home() {
const t = useGT();
const navData = getNavData(t);
return <div>{navData.home.label}</div>;
}
这会带来不少工作。更好的办法是使用 msg()
函数。
如何使用 msg()
函数
要使用 msg()
函数,将字符串直接传入该函数。
该函数会返回一个特殊的编码字符串,可用于翻译。
import { msg } from 'gt-react';
export const navData = [
{
label: msg('Home'), // 输出的类型为 `string`
description: msg('The home page'),
icon: 'home',
href: '/',
},
{
label: msg('About'),
description: msg('Information about the company'),
icon: 'info',
href: '/about',
},
]
然后,只需将该编码字符串传递给 useMessages()
钩子。
import { useMessages } from 'gt-react';
import { navData } from '@/navData';
export default function Home() {
const m = useMessages();
return (
<div>
{navData.map((item) => (
<div key={item.label}>{m(item.label)}</div>
))}
</div>
);
}
注意:msg()
函数返回的是编码后的字符串,与原始输入字符串不同。
如果想要还原原始字符串,需要使用 decodeMsg()
进行解码。
使用变量
如果你的字符串是模板字符串并包含变量,你可以将变量传递给 msg()
函数。
只需将模板字符串中的 ${}
写法改为 {variable}
,并将一个对象作为第二个参数传给 msg()
,以变量名作为键。
const items = 100;
export const pricing = [
{
name: 'Basic',
price: 100,
description: `The basic plan includes ${items} items`
},
]
应当改为:
import { msg } from 'gt-react';
const items = 100;
export const pricing = [
{
name: 'Basic',
price: 100,
description: msg('The basic plan includes {items} items', { items })
},
]
{items}
占位符会被 items
变量的值替换。
这样你就可以在翻译中显示动态值。
有关 API 的更多信息,请参见 API 参考。
gt-react
支持 ICU 消息格式,你也可以用它来格式化变量。
const price = 100;
msg('There are {count, plural, =0 {no items} =1 {one item} other {{count} items}} in the cart', { count: 10 });
ICU 消息格式是格式化变量的强大方式。 更多信息请参见 ICU 消息格式文档。
示例
- 翻译共享的全局对象
import { msg } from 'gt-react';
export const llmData = [
{
name: 'GPT-4.1',
id: 'gpt-4.1',
description: msg('GPT-4.1 is a large language model developed by OpenAI'),
},
{
name: 'Claude 3.7 Sonnet',
id: 'claude-3-7-sonnet',
description: msg('Claude 3.7 Sonnet is a large language model developed by Anthropic'),
},
];
import { llmData } from '@/llms';
import { useMessages } from 'gt-react';
export default function MyComponent() {
const m = useMessages();
return (
<div>
{llmData.map((llm) => (
<div key={llm.id}>
<h1>{llm.name}</h1>
<p>{m(llm.description)}</p>
</div>
))}
</div>
)
}
export const llms = [
{
name: 'GPT-4.1',
id: 'gpt-4.1',
description: 'GPT-4.1 is a large language model developed by OpenAI',
},
{
name: 'Claude 3.7 Sonnet',
id: 'claude-3-7-sonnet',
description: 'Claude 3.7 Sonnet is a large language model developed by Anthropic',
},
]
import { llms } from '@/llms';
export default function MyComponent() {
return (
<div>
{llms.map((llm) => (
<div key={llm.id}>
<h1>{llm.name}</h1>
<p>{llm.description}</p>
</div>
))}
</div>
)
}
- 翻译函数的返回值
import { msg } from 'gt-react';
function mockData() {
return [
{
name: 'GPT-4.1',
id: 'gpt-4.1',
company: 'OpenAI',
},
{
name: 'Claude 3.7 Sonnet',
id: 'claude-3-7-sonnet',
company: 'Anthropic',
},
];
}
export function getData() {
const data = mockData();
const modifiedData = data.map((item) => ({
...item,
description: msg('{name} is a large language model developed by {company}', {
name: item.name,
company: item.company,
}),
}));
return modifiedData;
}
import { getData } from '@/llms';
import { useMessages } from 'gt-react';
export default function MyComponent() {
const m = useMessages();
const data = getData();
return (
<div>
{data.map((item) => (
<div key={item.id}>
<h1>{item.name}</h1>
<p>{m(item.description)}</p>
</div>
))}
</div>
)
}
import { msg } from 'gt-react';
function mockData() {
return [
{
name: 'GPT-4.1',
id: 'gpt-4.1',
company: 'OpenAI',
},
{
name: 'Claude 3.7 Sonnet',
id: 'claude-3-7-sonnet',
company: 'Anthropic',
},
];
}
export function getData() {
const data = mockData();
const modifiedData = data.map((item) => ({
...item,
description: `${item.name} is a large language model developed by ${item.company}`,
}));
return modifiedData;
}
import { getData } from '@/llms';
export default function MyComponent() {
const data = getData();
return (
<div>
{data.map((item) => (
<div key={item.id}>
<h1>{item.name}</h1>
<p>{item.description}</p>
</div>
))}
</div>
)
}
常见陷阱
忘记调用 useMessages()
msg()
会对输入字符串进行编码,因此不能直接在 JSX 或其他地方使用它。
如果你直接使用编码后的字符串,会得到类似下面这样的奇怪字符串:
const encodedString = msg('Hello, world!');
console.log(encodedString); // "Hello, world!:eyIkX2hhc2giOiJkMjA3MDliZGExNjNlZmM2In0="
要解决这个问题,需要使用 useMessages()
钩子获取翻译后的字符串。
import { useMessages } from 'gt-react';
const encodedString = msg('Hello, world!');
export default function MyComponent() {
const m = useMessages();
return <div>{m(encodedString)}</div>; // 当前语言中的“Hello, world!”
}
另外,如果你想还原原始字符串,可以使用 decodeMsg()
函数。
import { decodeMsg } from 'gt-react';
const encodedString = msg('Hello, world!');
const decodedString = decodeMsg(encodedString);
console.log(decodedString); // "Hello, world!"
用 msg()
包裹动态内容
所有字符串必须在构建时可知。这意味着不能用 msg()
包裹动态内容。
例如,下面是无效的:
const dynamicContent = msg(`Hello, ${name}`);
正确做法是将动态内容作为变量提供,再传递给 msg()
:
const dynamicContent = msg('Hello, {name}', { name });
如果你尝试用 msg()
包裹动态内容,CLI 工具会给出警告。
下一步
- 查看
msg()
的 API 参考。 - 查看
useMessages()
的 API 参考。 - 进一步了解
<T>
组件。
这份指南怎么样?