API
React API
Package
@foo-i18n/react
The React integration of the translation function.
This module includes both
@foo-i18n/t
and@foo-i18n/base
for conveniense.
Declarations
Provider
type TranslationProviderProps<M extends NamespaceMessages> = {
locale: Locale;
messages: M;
plural?: PluralRule;
children: React.ReactNode;
};
function TranslationProvider<M extends NamespaceMessages>({
locale,
messages,
plural = defaultPlural,
children,
}: TranslationProviderProps<M>): JSX:Element;
See translate API for
NamespaceMessages
, and plurals API forPluralRule
declarations.
Hooks
type UseTranslation<M extends NamespaceMessages> = <
NS extends StringKeys<M>,
S extends StringKeys<M[NS]>,
>(
ns: NS
) => {
readonly locale: Locale;
readonly plural: PluralRule;
readonly t: TranslateMessage<S>;
};
type UseLocale = () => Locale;
const useTranslation: UseTranslation<NamespaceMessages>;
const useLocale: UseLocale;
Usage
Building blocks
See fundamentals for more information about messages.
import type {
Locale,
ExpandedMessages,
UseTranslation,
} from '@foo-i18n/react/types';
// 1. Declare messages dictionary shape from JSON
export type AppMessages = ExpandedMessages<{
people: typeof import('../messages/en/people.json');
}>;
// 2. Define allowed application locales
export type AppLocale = Extract<Locale, 'en' | 'fr'>;
// 3. Typed translation hook
export type UseAppTranslation = UseTranslation<AppMessages>;
//import { en, fr } from "@foo-i18n/plurals";
import en from '@foo-i18n/plurals/en';
import fr from '@foo-i18n/plurals/en';
import type { AppLocale } from './types';
import type { PluralRule } from '@foo-i18n/react/types';
// 4. export only required plural rules
export const appPlurals: Record<AppLocale, PluralRule> = { en, fr };
'use server';
import type { AppLocale, AppMessages } from './types';
// This function uses type inference so that it's return
// value can be statically inspected.
export const loadMessages = async (locale: AppLocale) =>
({
people: (await import(`../messages/${locale}/people.json`))
.default as AppMessages['people'],
}) satisfies AppMessages;
'use client';
import { TranslationProvider } from '@foo-i18n/react';
import { appPlurals } from '@/i18n/plurals';
import type { AppLocale, AppMessages } from '@/i18n/types';
export type AppTranslationProviderProps = {
locale: AppLocale;
messages: AppMessages;
children: React.ReactNode;
};
const AppTranslationProvider = ({
locale,
messages,
children,
}: AppTranslationProviderProps) => {
// get the plural rules for the specified (allowed) locale
const plural = appPlurals[locale];
return (
<TranslationProvider locale={locale} messages={messages} plural={plural}>
{children}
</TranslationProvider>
);
};
export default AppTranslationProvider;
import { useTranslation } from '@foo-i18n/react';
import type { UseAppTranslation } from '@/i18n/types';
export const useAppTranslation = useTranslation as UseAppTranslation;
Putting it all together
The following example uses Next.js App Router, however the principle is quite straightforward from here.
import { loadMessages } from '@/i18n/messages';
import AppTranslationProvider from '@/components/TranslationProvider';
import PageContent from '@/components/pages/PageContent';
import type { AppLocale } from '@/i18n/types';
// React SSR component
export default async function Page() {
// get locale from route, or middleware, etc.
const locale: AppLocale = 'en';
const messages = await loadMessages(locale);
return (
<AppTranslationProvider locale={locale} messages={messages}>
<PageContent />
</AppTranslationProvider>
);
}
'use client';
// import typed hook
import { useAppTranslation } from '@/i18n/useAppTranslation';
const PageContent = () => {
const { locale, t, plural } = useAppTranslation('people');
const count = 123;
const plurality = plural.ordinal(count);
return (
<>
<div>Current locale: {locale}</div>
<div>{t('There are {count} people', { count, plurality })}</div>
</>
);
};
export default PageContent;
For components only needing the current
locale
value:'use client'; // import typed hook import { useLocale } from '@foo-i18n/react/useLocale'; const MyComponent = () => { const locale = useLocale(); return <div>Current locale: {locale}</div>; }; export default PageContent;