feat: whyrating - initial project from turbostarter boilerplate
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
---
|
||||
title: Configuration
|
||||
description: Learn how to configure internationalization in TurboStarter.
|
||||
url: /docs/web/internationalization/configuration
|
||||
---
|
||||
|
||||
# Configuration
|
||||
|
||||
The default global configuration is defined in the `@turbostarter/i18n` package and shared across all applications. You can override it in each app to customize the internationalization setup for that specific app.
|
||||
|
||||
The configuration is defined in the `packages/i18n/src/config.ts` file:
|
||||
|
||||
```ts title="packages/i18n/src/config.ts"
|
||||
export const config = {
|
||||
locales: ["en", "es"],
|
||||
defaultLocale: "en",
|
||||
namespaces: [
|
||||
"common",
|
||||
"admin",
|
||||
"organization",
|
||||
"dashboard",
|
||||
"auth",
|
||||
"billing",
|
||||
"marketing",
|
||||
"validation",
|
||||
],
|
||||
cookie: "locale",
|
||||
} as const;
|
||||
```
|
||||
|
||||
Let's break down the configuration options:
|
||||
|
||||
* `locales`: An array of all supported locales.
|
||||
* `defaultLocale`: The default locale to use if no other locale is detected.
|
||||
* `namespaces`: An array of all namespaces used in the application.
|
||||
* `cookie`: The name of the cookie to store the detected locale (acts as a cache).
|
||||
|
||||
## Translation files
|
||||
|
||||
The core of the whole internationalization setup is the translation files. They are stored in the `packages/i18n/src/translations` directory and are used to store the translations for each locale and namespace.
|
||||
|
||||
Each directory represents a locale and contains a set of files, each corresponding to a specific namespace (e.g. `en/common.json`). Inside we define the keys and values for the translations.
|
||||
|
||||
```ts title="packages/i18n/src/translations/en/common.json"
|
||||
{
|
||||
"hello": "Hello, world!"
|
||||
}
|
||||
```
|
||||
|
||||
That way we can ensure that we have a single source of truth for the translations and we can use them consistently in all the applications.
|
||||
|
||||
## Locales
|
||||
|
||||
The `locales` array in the configuration defines the list of supported languages in your application. Each locale is represented by a string that uniquely identifies the language.
|
||||
|
||||
To add a new locale, you need to:
|
||||
|
||||
1. Add the new locale to the `locales` array in the configuration.
|
||||
2. Create a new directory in the `packages/i18n/src/translations` directory.
|
||||
3. Create a new file in the new directory for each namespace and add the translations for the new locale.
|
||||
|
||||
For example, if you want to add the `fr` locale, you need to:
|
||||
|
||||
1. Add `fr` to the `locales` array in the configuration.
|
||||
2. Create a new directory in the `packages/i18n/src/translations` directory.
|
||||
3. Create a new file for each namespace in the created directory and add the translations for the new locale.
|
||||
|
||||
### Fallback locale
|
||||
|
||||
The `defaultLocale` option in the configuration defines the fallback locale. If a translation is not found for a specific locale, the fallback locale will be used.
|
||||
|
||||
We can also override this setting in each [app configuration](/docs/web/configuration/app) by configuring the `locale` property.
|
||||
|
||||
## Namespaces
|
||||
|
||||
`namespaces` are used to group translations by feature or module. This helps in organizing the translations and makes it easier to maintain them.
|
||||
|
||||
### Why not one big namespace?
|
||||
|
||||
Using multiple namespaces instead of one large namespace helps with:
|
||||
|
||||
1. **Performance:** load translations on-demand instead of all at once, reducing the initial bundle size.
|
||||
2. **Organization:** group translations by feature (e.g., `auth`, `common`, `dashboard`).
|
||||
3. **Maintenance:** easier to update and manage smaller translation files.
|
||||
4. **Development:** better TypeScript support and team collaboration.
|
||||
|
||||
For example, you might structure your namespaces like this:
|
||||
|
||||
<Tabs items={["Common", "Auth", "Billing"]}>
|
||||
<Tab value="Common">
|
||||
```ts title="packages/i18n/src/translations/en/common.json"
|
||||
{
|
||||
"hello": "Hello, world!"
|
||||
}
|
||||
```
|
||||
</Tab>
|
||||
|
||||
<Tab value="Auth">
|
||||
```ts title="packages/i18n/src/translations/en/auth.json"
|
||||
{
|
||||
"login": "Login",
|
||||
"register": "Register"
|
||||
}
|
||||
```
|
||||
</Tab>
|
||||
|
||||
<Tab value="Billing">
|
||||
```ts title="packages/i18n/src/translations/en/billing.json"
|
||||
{
|
||||
"invoice": "Invoice",
|
||||
"payment": "Payment",
|
||||
"subscription": "Subscription"
|
||||
}
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
Remember that while you can create as many namespaces as needed, it's important to maintain a balance - too many namespaces can lead to unnecessary complexity, while too few might defeat the purpose of separation.
|
||||
|
||||
## Routing
|
||||
|
||||
TurboStarter implements locale-based routing by placing pages under the `[locale]` folder. However, the default locale (usually `en`) is not prefixed in the URL for better SEO and user experience.
|
||||
|
||||
For example, with English as the default locale and Polish as an additional language:
|
||||
|
||||
* `/dashboard` → English version (default locale)
|
||||
* `/pl/dashboard` → Polish version
|
||||
|
||||
The app also automatically detects the user's preferred language through cookies, HTML `lang` attribute, and browser's `Accept-Language` header.
|
||||
|
||||
This ensures a seamless experience where users get content in their preferred language while maintaining clean URLs for the default locale.
|
||||
|
||||
<Callout>
|
||||
You can override the locale by manually setting the cookie or by navigating to
|
||||
a URL with a different locale prefix.
|
||||
</Callout>
|
||||
@@ -0,0 +1,40 @@
|
||||
---
|
||||
title: Overview
|
||||
description: Get started with internationalization in TurboStarter.
|
||||
url: /docs/web/internationalization/overview
|
||||
---
|
||||
|
||||
# Overview
|
||||
|
||||
TurboStarter uses [i18next](https://www.i18next.com/) for internationalization, which is one of the most popular and mature (over 10 years of development!) i18n frameworks for JavaScript.
|
||||
|
||||
<Callout title="Why i18next?">
|
||||
With i18next, you can easily translate your application into multiple
|
||||
languages, handle complex pluralization rules, format dates and numbers
|
||||
according to locale, and much more. The framework is highly extensible through
|
||||
plugins and provides excellent TypeScript support out of the box.
|
||||
</Callout>
|
||||
|
||||
You can read more about `i18next` package in the [official documentation](https://www.i18next.com/overview/getting-started).
|
||||
|
||||

|
||||
|
||||
## Getting started
|
||||
|
||||
TurboStarter comes with `i18next` pre-configured and abstracted behind the `@turbostarter/i18n` package. This abstraction layer ensures that any future changes to the underlying translation library won't impact your application code. The internationalization setup is ready to use out of the box and includes:
|
||||
|
||||
* Multiple language support out of the box
|
||||
* Type-safe translations with generated types
|
||||
* Automatic language detection
|
||||
* Easy-to-use React hooks for translations
|
||||
* Built-in number and date formatting
|
||||
* Support for nested translation keys
|
||||
* Pluralization handling
|
||||
|
||||
To start using internationalization in your app, you'll need to:
|
||||
|
||||
1. Configure your supported languages
|
||||
2. Add translation files
|
||||
3. Use translation hooks in your components
|
||||
|
||||
Check out the following sections to learn more about each step:
|
||||
@@ -0,0 +1,147 @@
|
||||
---
|
||||
title: Translating app
|
||||
description: Learn how to translate your application to multiple languages.
|
||||
url: /docs/web/internationalization/translations
|
||||
---
|
||||
|
||||
# Translating app
|
||||
|
||||
TurboStarter provides a flexible and powerful translation system that works seamlessly across your entire application. Whether you're working with React Server Components (RSC), client-side components, or server-side rendering, you can easily integrate translations to create a fully internationalized experience.
|
||||
|
||||
The translation system supports:
|
||||
|
||||
* **Server components (RSC)** for efficient server-side translations
|
||||
* **Client components** for dynamic language switching
|
||||
* **Server-side rendering** for SEO-friendly translated content
|
||||
|
||||
## Server components (RSC)
|
||||
|
||||
To get the translations in a server component, you can use the `getTranslation` method:
|
||||
|
||||
```tsx
|
||||
import { getTranslation } from "@turbostarter/i18n";
|
||||
|
||||
export default async function MyComponent() {
|
||||
const { t } = await getTranslation();
|
||||
|
||||
return <div>{t("common:hello")}</div>;
|
||||
}
|
||||
```
|
||||
|
||||
There is also a possibility to use the [Trans](https://react.i18next.com/latest/trans-component) component, which could be useful e.g. for interpolating variables:
|
||||
|
||||
```tsx
|
||||
import { Trans } from "@turbostarter/i18n";
|
||||
import { withI18n } from "@turbostarter/i18n/with-i18n";
|
||||
|
||||
const Page = () => {
|
||||
return <Trans i18nKey="common:hello" components={{ bold: <b /> }} />;
|
||||
};
|
||||
|
||||
export default withI18n(Page);
|
||||
```
|
||||
|
||||
Although, to make it available in the server component, you need to wrap it with the `withI18n` HOC.
|
||||
|
||||
Given that server components are rendered in parallel, it's uncertain which one will render first. Therefore, it's crucial to initialize the translations before rendering the server component on each page/layout.
|
||||
|
||||
## Client components
|
||||
|
||||
For client components, you can use the `useTranslation` hook from the `@turbostarter/i18n` package:
|
||||
|
||||
```tsx
|
||||
"use client";
|
||||
|
||||
import { useTranslation } from "@turbostarter/i18n";
|
||||
|
||||
export default function MyComponent() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return <div>{t("common:hello")}</div>;
|
||||
}
|
||||
```
|
||||
|
||||
That's the simplest way to get the translations in a client component.
|
||||
|
||||
## Server-side
|
||||
|
||||
In all other places (e.g. metadata, API routes, sitemaps etc.) you can use the `getTranslation` method to get the translations server-side:
|
||||
|
||||
```ts
|
||||
import { getTranslation } from "@turbostarter/i18n";
|
||||
|
||||
export const generateMetadata = async () => {
|
||||
const { t } = await getTranslation();
|
||||
|
||||
return {
|
||||
title: t("common:title"),
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
It automatically checks the user's preferred locale and uses the correct translation.
|
||||
|
||||
## Language switcher
|
||||
|
||||
TurboStarter ships with a language customizer component that allows you to switch between languages. You can import and use the `LocaleCustomizer` component and drop it anywhere in your application to allow users to change the language seamlessly.
|
||||
|
||||
```tsx
|
||||
import { LocaleCustomizer } from "@turbostarter/ui-web/i18n";
|
||||
|
||||
export default function MyComponent() {
|
||||
return <LocaleCustomizer />;
|
||||
}
|
||||
```
|
||||
|
||||
The component automatically displays all languages configured in your i18n settings. When a user switches languages, it will:
|
||||
|
||||
1. Update the URL to include the new locale prefix (e.g. `/es/dashboard`)
|
||||
2. Store the selected locale in a cookie for persistence
|
||||
3. Refresh translations across the entire application
|
||||
4. Preserve the current page/route during the language switch
|
||||
|
||||
This provides a seamless localization experience without requiring any additional configuration.
|
||||
|
||||
## Best practices
|
||||
|
||||
Here are some recommended best practices for managing translations in your application:
|
||||
|
||||
* Use descriptive translation keys that follow a logical hierarchy
|
||||
|
||||
```ts
|
||||
// ✅ Good
|
||||
"auth.login.title";
|
||||
|
||||
// ❌ Bad
|
||||
"loginTitleForAuth";
|
||||
```
|
||||
|
||||
* Keep translations organized in separate namespaces/files based on features or sections
|
||||
|
||||
```
|
||||
translations/
|
||||
├── en/
|
||||
│ ├── auth.json
|
||||
│ └── common.json
|
||||
└── pl/
|
||||
├── auth.json
|
||||
└── billing.json
|
||||
```
|
||||
|
||||
* Avoid hardcoding text strings - always use translation keys even for seemingly static content
|
||||
|
||||
* Always provide a fallback language (usually English) for when translations are missing
|
||||
|
||||
* Use pluralization and interpolation features when dealing with dynamic content
|
||||
|
||||
```ts
|
||||
// Pluralization
|
||||
t("items", { count: 2 }); // "2 items"
|
||||
|
||||
// Interpolation
|
||||
t("welcome", { name: "John" }); // "Welcome, John!"
|
||||
```
|
||||
|
||||
* Regularly review and clean up unused translation keys to keep files maintainable
|
||||
|
||||
* Use TypeScript for type-safe translation keys
|
||||
Reference in New Issue
Block a user