This project is designed to be used in SPAs (Single page applications) with no server side rendering.
If you're not using either Vite or Create-React-App, i18nifty is probably not the best choice for you.
yarnadd--devi18nifty
npminstall--save-devi18nifty
bunadd--devi18nifty
pnpmadd--save-devi18nifty
Before diving into the thick of things let's make sure you can do local imports relative to your src directory. It will prevent you from having to write imports like:
import { useTranslations } from "../../../../i18n";
If you are using Vite (If you're using CRA you don't need the vite-tsconfig-paths plugin):
yarnadd--devvite-tsconfig-paths
npminstall--save-devvite-tsconfig-paths
bunadd--devvite-tsconfig-paths
pnpmadd--save-devvite-tsconfig-paths
vite.config.ts
import { defineConfig } from "vite"; import tsconfigPaths from "vite-tsconfig-paths"; import react from "@vitejs/plugin-react"; // https://vitejs.dev/config/ export default defineConfig({ "plugins": [ react(),+ tsconfigPaths() ] });
Start by declaring the text keys you'll need in each component.
src/components/MyComponent.tsx
src/components/MyOtherComponent.tsx
then create your src/i18n.tsx file:
Now go back to your component and use the translation function:
And so forth for your other components.
Now this setup is great if you're supporting only a few languages and you're app does not contain a lot of text. As you app grow however, you probably want to enable only only the resources for a specific language to be dowloaded.
import {
createI18nApi,
declareComponentKeys,
type LocalizedString as LocalizedString_base
} from "i18nifty";
export { declareComponentKeys };
//List the languages you with to support
export const languages = ["en", "fr"] as const;
//If the user's browser language doesn't match any
//of the languages above specify the language to fallback to:
export const fallbackLanguage = "en";
export type Language = typeof languages[number];
export type LocalizedString = LocalizedString_base<Language>;
export const {
useTranslation,
resolveLocalizedString,
useLang,
$lang,
useResolveLocalizedString,
/** For use outside of React */
getTranslation
} = createI18nApi<
| import ("components/MyComponent").I18n
| import ("components/MyOtherComponent").I18n
>()(
{
languages,
fallbackLanguage
},
{
"en": {
"MyComponent": {
"greating": ({ who })=> `Hello ${who}`,
"how are you": "How are you feeling today?",
"learn more": ({ href }) => (
<>
Learn more about
<a href={href}>this website</a>.
</>
)
},
"MyOtherComponent": {
"open": "Open",
"delete": "Delete",
"unread messages": ({ howMany })=> {
switch(howMany){
case 0: return `You don't have any new message`;
case 1: return `You have a new message`;
default: return `You have ${howMany} new messages`;
}
}
},
},
/* spell-checker: disable */
"fr": {
"MyComponent": {
"greating": ({ who })=> `Bonjour ${who}`,
"how are you": "Comment vous sentez vous au jour d'hui?",
"learn more": ({ href }) => (
<>
En savoir plus à propos de
<a href={href}>ce site web</a>.
</>
)
},
"MyOtherComponent": {
"open": "Ouvrir",
"delete": "Supprimer",
//We will translate this later, for now, fallback to english
"unread messages": undefined
},
}
/* spell-checker: enable */
}
);
MyComponent.ts
+import { useTranslation, declareComponentKeys } from "i18n"; //You can import it like that thanks to baseUrl
type Props = {
name: string;
};
export function MyComponent(props: Props) {
const { name } = props;
+ const { t } = useTranslation({ MyComponent });
return (
<>
- <h1>Hello {name}</h1>
+ <h1>{t("greeting", { who: name })}</h1>
- <h3>How are you feeling today?</h3>
+ <h3>{t("how are you")}</h3>
- <p>
- Click <a href="https://example.com">hrere</a> to
- learn more about this website
- </p>
+ <p>{t("learn more", { href: "https://example.com" })}</p>
</>
);
}
const { i18n } = declareComponentKeys<
| { K: "greating"; P: { who: string; } }
| "how are you"
| { K: "learn more"; P: { href: string; }; R: JSX.Element }
>()({ MyComponent });
export type I18n = typeof i18n;