Using the Extension
By using the Quetzal VSCode/Cursor extension, you should be able to wrap your strings with the t
function automatically. However, this page will document manual use.
Import the ‘t’ function
To translate strings in your app, they must be wrapped in Quetzal’s t
function.
The t
function is how Quetzal knows what to send for translation, and where to put the translated text.
import { useI18n } from "@quetzallabs/i18n";
import { getI18nUtils } from "@quetzallabs/i18n";
import { useI18n } from "@quetzallabs/i18n-react-native";
import { getI18nUtils } from "@quetzallabs/i18n-react-native";
export default function Page() {
const { t } = useI18n();
const { t } = await getI18nUtils();
}
The Quetzal t function is built on top of the next-intl t function, and
behaves similarly. Check out the next-intl
docs for t function
usage instructions.
Wrap Strings
Once you have imported and initialized the t function, you can begin marking strings for translation
import { useI18n } from "@quetzallabs/i18n";
export default function Page() {
const { t } = useI18n();
return <p>{t("Here is normal text")}</p>;
}
Output: Here is normal text
Special cases
Dynamic Text
Use placeholders to dynamically insert values into your translated text.
import { useI18n } from "@quetzallabs/i18n";
export default function Page() {
const { t } = useI18n();
return (
<p>
{t("Here's a {dynamic1} with a {dynamic2}", {
dynamic: 4,
dynamic2: "four",
})}
</p>
);
}
Output: Here’s a 4
Pluralization
Handle pluralization based on the value passed.
import { useI18n } from "@quetzallabs/i18n";
export default function Page() {
const { t } = useI18n();
return (
<p>
{t(
"You have {count, plural, =0 {no followers yet} =1 {one follower} other {# followers}}.",
{ count: 4 }
)}
</p>
);
}
Output: You have 4 followers.
Ordinal Numbers
Format ordinal numbers correctly in different languages.
import { useI18n } from "@quetzallabs/i18n";
export default function Page() {
const { t } = useI18n();
return (
<p>
{t(
"It's your {year, selectordinal, one {#st} two {#nd} few {#rd} other {#th}} birthday!",
{ year: 1 }
)}
</p>
);
}
Output: It’s your 1st birthday!
Multi-case Text
Handle multi-case selections, such as gender-based translations.
import { useI18n } from "@quetzallabs/i18n";
export default function Page() {
const { t } = useI18n();
return (
<p>
{t("{gender, select, female {She} male {He} other {They}} is online.", {
gender: "male",
})}
</p>
);
}
Output: He is online.
Escaping Curly Braces
Escape curly braces in your text by using single quotes.
import { useI18n } from "@quetzallabs/i18n";
export default function Page() {
const { t } = useI18n();
return <p>{t("Escape curly braces with single quotes (e.g. '{name'})")}</p>;
}
Output: Escape curly braces with single quotes (e.g. {name})
Rich Text Formatting
Embed rich text or HTML elements within your translations.
import { useI18n } from "@quetzallabs/i18n";
import { ReactNode } from "react";
export default function Page() {
const { t } = useI18n();
return (
<p>
{t("Please refer to <guidelines>the guidelines</guidelines>.", {
guidelines: (chunks: ReactNode) => <a href="/guidelines">{chunks}</a>,
})}
</p>
);
}
Output: Please refer to the guidelines.
Embedded HTML Elements
You can embed HTML elements directly within your translated strings.
import { useI18n } from "@quetzallabs/i18n";
import { ReactNode } from "react";
export default function Page() {
const { t } = useI18n();
return (
<p>
{t("This is <important>important</important>", {
important: (chunks: ReactNode) => <b>{chunks}</b>,
})}
</p>
);
}
Output: This is important
Regular Numbers
Format plain numbers according to the user’s locale.
import { useI18n } from "@quetzallabs/i18n";
export default function Page() {
const { t } = useI18n();
return <p>{t(1234.56)}</p>;
}
Output: 1,234.56 (in en-US locale)
Currencies
Format numbers as currencies.
import { useI18n } from "@quetzallabs/i18n";
export default function Page() {
const { t } = useI18n();
return <p>{t(499.9, { style: "currency", currency: "USD" })}</p>;
}
Output: $499.90
Percentages
Format numbers as percentages.
import { useI18n } from "@quetzallabs/i18n";
export default function Page() {
const { t } = useI18n();
return <p>{t(0.857, { style: "percent" })}</p>;
}
Output: 85.7%
Apply custom number formatting.
import { useI18n } from "@quetzallabs/i18n";
export default function Page() {
const { t } = useI18n();
return (
<p>{t(1234.56, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}</p>
);
}
Output: 1,234.56
ICU Syntax for Numbers
Utilize ICU syntax for formatting numbers within messages.
import { useI18n } from "@quetzallabs/i18n";
export default function Page() {
const { t } = useI18n();
return (
<p>
{t("This product costs {price, number, currency}", {
price: 32000.99,
number: {
currency: {
style: "currency",
currency: "EUR",
},
},
})}
</p>
);
}
Output: This product costs €32,000.99
Dates
Format dates according to the user’s locale.
import { useI18n } from "@quetzallabs/i18n";
export default function Page() {
const { t } = useI18n();
return (
<p>
{t(new Date(), {
year: "numeric",
month: "long",
day: "numeric",
})}
</p>
);
}
Output: August 12, 2024 (in en-US locale)
Date Ranges
Format a range of dates.
import { useI18n } from "@quetzallabs/i18n";
export default function Page() {
const { t } = useI18n();
return (
<p>
{t([new Date("2020-01-01"), new Date("2020-12-31")], {
year: "numeric",
month: "long",
day: "numeric",
})}
</p>
);
}
Output: January 1, 2020 – December 31, 2020 (in en-US locale)
Lists (Conjunctions)
Format lists using conjunctions.
import { useI18n } from "@quetzallabs/i18n";
export default function Page() {
const { t } = useI18n();
return (
<p>
{t(["HTML", "CSS", "JavaScript"], {
type: "conjunction",
})}
</p>
);
}
Output: HTML, CSS, and JavaScript
Lists (Disjunctions)
Format lists using disjunctions.
import { useI18n } from "@quetzallabs/i18n";
export default function Page() {
const { t } = useI18n();
return (
<p>
{t(["HTML", "CSS", "JavaScript"], {
type: "disjunction",
})}
</p>
);
}
Output: HTML, CSS, or JavaScript
Variable Lists
Format lists generated from variables.
import { useI18n } from "@quetzallabs/i18n";
export default function Page() {
const { t } = useI18n();
const users = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" },
{ id: 3, name: "Charlie" },
];
const items = users.map((user) => (
<a key={user.id} href={`/user/${user.id}`}>
{user.name}
</a>
));
return <p>{t(items)}</p>;
}
Output: Alice, Bob, and Charlie