Translating Shared Strings
How to internationalize shared strings
Overview
Shared strings are strings or constants that are used in multiple places in your app.
For example, you may have a string that is used in multiple components, or a constant that is used in multiple files.
In traditional i18n libraries, you would need to create a dictionary for each shared string.
This guide will walk you through how to easily internationalize shared strings in your React app using the msg()
function & useMessages()
hook.
We will cover the following:
When to use the msg()
function
How to use the msg()
function and useMessages()
hook
Using variables
Examples
Common pitfalls
When to use the msg()
function
The msg()
function is a simple function that is used to mark strings for translation.
Let's look at an example of a shared object containing strings:
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',
},
}
Normally, to internationalize this object, you would need to either create a dictionary entry for each string, or refactor your object into a function that returns the data with translations.
For example, you might have:
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',
},
})
Everywhere else in your app where navData
was imported, you would need to call getNavData(t)
instead.
import { getNavData } from '@/navData';
export default function Home() {
const t = useGT();
const navData = getNavData(t);
return <div>{navData.home.label}</div>;
}
This can lead to a lot of work. The solution is to use the msg()
function.
How to use the msg()
function
To use the msg()
function, pass the string directly to the function.
The function returns a special, encoded string that can be used for translations.
import { msg } from 'gt-react';
export const navData = [
{
label: msg('Home'), // Output has type `string`
description: msg('The home page'),
icon: 'home',
href: '/',
},
{
label: msg('About'),
description: msg('Information about the company'),
icon: 'info',
href: '/about',
},
]
Then, simply pass the encoded string to the useMessages()
hook.
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>
);
}
Beware! The string returned by the msg()
function is encoded and will be different from the original input string.
If want to get back the original string, you need to decode it with decodeMsg()
Using variables
If your string is a template string and contains variables, you can pass the variables to the msg()
function.
Simply change the ${}
notation in the template string to {variable}
, and pass an object as the second argument to msg()
with the variable name as the key.
const items = 100;
export const pricing = [
{
name: 'Basic',
price: 100,
description: `The basic plan includes ${items} items`
},
]
Should be turned into:
import { msg } from 'gt-react';
const items = 100;
export const pricing = [
{
name: 'Basic',
price: 100,
description: msg('The basic plan includes {items} items', { items })
},
]
The {items}
placeholder will be replaced with the value of the items
variable.
This allows you to display dynamic values in your translations.
For more information on the API, see the API reference.
gt-react
supports ICU message format, which allows you to also format your variables.
const price = 100;
msg('There are {count, plural, =0 {no items} =1 {one item} other {{count} items}} in the cart', { count: 10 });
ICU message format is a powerful way to format your variables. For more information, see the ICU message format documentation.
Examples
- Translating a shared global object
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>
)
}
- Translating a function's return value
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>
)
}
Common Pitfalls
Forgetting to call useMessages()
msg()
encodes the input string, so you cannot use it directly in JSX or elsewhere.
If you attempt to use the encoded string directly, you will get a weird string that looks something like this:
const encodedString = msg('Hello, world!');
console.log(encodedString); // "Hello, world!:eyIkX2hhc2giOiJkMjA3MDliZGExNjNlZmM2In0="
To fix this, you need to use the useMessages()
hook to get the translated string.
import { useMessages } from 'gt-react';
const encodedString = msg('Hello, world!');
export default function MyComponent() {
const m = useMessages();
return <div>{m(encodedString)}</div>; // 'Hello, world!' in the current language
}
Alternatively, if you want to recover the original string, you can use the decodeMsg()
function.
import { decodeMsg } from 'gt-react';
const encodedString = msg('Hello, world!');
const decodedString = decodeMsg(encodedString);
console.log(decodedString); // "Hello, world!"
Wrapping dynamic content in msg()
All strings must be known at build time. This means that you cannot wrap dynamic content in msg()
.
For example, this is invalid:
const dynamicContent = msg(`Hello, ${name}`);
To fix this, provide the dynamic content as a variable, and then pass it to msg()
.
const dynamicContent = msg('Hello, {name}', { name });
The CLI tool will warn you if you try to wrap dynamic content with msg()
.
Next Steps
- See the API reference for
msg()
. - See the API reference for
useMessages()
. - Learn more about the
<T>
component.
How is this guide?