Skip to content

Commit

Permalink
Merge pull request #1192 from fuma-nama/dev
Browse files Browse the repository at this point in the history
Sync
  • Loading branch information
fuma-nama authored Dec 27, 2024
2 parents 1bf985f + d0da3c8 commit 5f06e7a
Show file tree
Hide file tree
Showing 35 changed files with 361 additions and 244 deletions.
137 changes: 81 additions & 56 deletions apps/docs/content/docs/ui/internationalization.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -49,24 +49,6 @@ export const source = loader({
});
```

Update the usages to your source to include a locale code:

```ts
import { source } from '@/lib/source';

// get page tree
source.pageTree[params.lang];

// get page
source.getPage(params.slug, params.lang);

// get pages
source.getPages(params.lang);
```

Note that without providing a locale code, it uses your default locale instead.
You can see [Source API](/docs/headless/source-api) for other usages.

### Middleware

Create a middleware that redirects users to appropriate locale.
Expand All @@ -83,28 +65,57 @@ Create a middleware that redirects users to appropriate locale.

See [Middleware](/docs/headless/internationalization#middleware) for customisable options.

### Root Layout
### Routing

Create a dynamic route `/app/[lang]`, and move all special files from `/app` to
the folder.

A `I18nProvider` is needed for localization. Wrap the root provider inside your I18n provider.
A `I18nProvider` is needed for localization.
Wrap the root provider inside your I18n provider, and provide available languages & translations to it.

Note that only English translations are provided by default.

```tsx
import { RootProvider } from 'fumadocs-ui/provider';
import { I18nProvider } from 'fumadocs-ui/i18n';
import { I18nProvider, type Translations } from 'fumadocs-ui/i18n';

const cn: Translations = {
search: 'Translated Content',
// other props
};

export default function RootLayout({
// available languages that will be displayed on UI
// make sure `locale` is consistent with your i18n config
const locales = [
{
name: 'English',
locale: 'en',
},
{
name: 'Chinese',
locale: 'cn',
},
];

export default async function RootLayout({
params,
children,
}: {
params: { lang: string };
params: Promise<{ lang: string }>;
children: React.ReactNode;
}) {
return (
<html lang={params.lang}>
<html lang={(await params).lang}>
<body>
<I18nProvider locale={params.lang}>
<I18nProvider
locale={(await params).lang}
locales={locales}
translations={
{
cn,
}[(await params).lang]
}
>
<RootProvider>{children}</RootProvider>
</I18nProvider>
</body>
Expand All @@ -113,47 +124,61 @@ export default function RootLayout({
}
```

### Writing Documents
### Source

see [Page Conventions](/docs/ui/page-conventions#internationalization) to learn how to organize your documents.
Update the usages to your source to include a locale code:

### Search
```ts
import { source } from '@/lib/source';

Configure i18n on your search solution.
// get page tree
source.pageTree[params.lang];

You don't need further changes if you're using the `createFromSource` shortcut.
// get page
source.getPage(params.slug, params.lang);

For the built-in Orama search, see [Search I18n](/docs/headless/search/orama#internationalization).
// get pages
source.getPages(params.lang);
```

### Adding Translations
like:

We only provide English translation by default, you have to pass your translations to the provider.
```tsx title="app/[lang]/layout.tsx"
import { source } from '@/lib/source';
import { DocsLayout } from 'fumadocs-ui/docs';
import type { ReactNode } from 'react';

```tsx
import { I18nProvider } from 'fumadocs-ui/i18n';

<I18nProvider
locales={[
{
name: 'English',
locale: 'en',
},
{
name: 'Chinese',
locale: 'cn',
},
]}
translations={
{
cn: {
search: 'Translated Content',
},
}[locale]
}
// other props
/>;
export default async function Layout({
params,
children,
}: {
params: Promise<{ lang: string }>;
children: ReactNode;
}) {
const pageTree = source.pageTree[(await params).lang];

return <DocsLayout pageTree={pageTree}>{children}</DocsLayout>;
}
```

Note that without providing a locale code, it uses your default locale instead.
You can see [Source API](/docs/headless/source-api) for other usages.

### Writing Documents

see [Page Conventions](/docs/ui/page-conventions#internationalization) to learn how to organize your documents.

### Search

Configure i18n on your search solution.

- Built-in Search (Orama):
- For `createFromSource` and most languages, no further changes are needed.
- For special languages like Chinese & Japanese, they require additional config.
See [Orama I18n](/docs/headless/search/orama#internationalization) guide.
- Cloud Solutions (e.g. Algolia):
- They usually have official support for multilingual.

### Add Language Switch

To allow users changing their language, enable `i18n` on your layouts.
Expand Down
2 changes: 1 addition & 1 deletion examples/i18n/app/api/search/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { createFromSource } from 'fumadocs-core/search/server';
import { createTokenizer } from '@orama/tokenizers/mandarin';
import { stopwords } from '@orama/stopwords/mandarin';

export const { GET, search } = createFromSource(source, undefined, {
export const { GET } = createFromSource(source, undefined, {
localeMap: {
// the prop name should be its locale code in your i18n config, (e.g. `cn`)
cn: {
Expand Down
12 changes: 12 additions & 0 deletions packages/cli/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# fumadocs

## 0.0.6

### Patch Changes

- 969da26: Improve i18n api

## 0.0.5

### Patch Changes

- c8d9b08: support Next.js 15 i18n auto-config

## 0.0.4

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@fumadocs/cli",
"version": "0.0.4",
"version": "0.0.6",
"description": "The CLI tool for Fumadocs",
"keywords": [
"NextJs",
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/plugins/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ export const i18nPlugin: Plugin = {
type: 'code',
title: 'page.tsx',
code: `
export default function Page({
export default async function Page({
params,
}: {
${picocolors.underline(picocolors.bold('params: { lang: string; slug?: string[] };'))}
${picocolors.underline(picocolors.bold('params: Promise<{ lang: string; slug?: string[] }>'))}
})
`.trim(),
},
Expand Down
6 changes: 4 additions & 2 deletions packages/cli/src/utils/i18n/transform-root-layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export function runTransform(sourceFile: SourceFile): void {
.join('\n');

parent.setBodyText(
`<I18nProvider locale={params.lang} locales={[
`<I18nProvider locale={(await params).lang} locales={[
{ locale: 'en', name: 'English' }
]}>
${inner.trim()}
Expand All @@ -64,8 +64,10 @@ export function runTransform(sourceFile: SourceFile): void {
const func = sourceFile
.getDescendantsOfKind(SyntaxKind.FunctionDeclaration)
.find((v) => v.isDefaultExport());
func?.toggleModifier('async', true);

const param = func?.getParameters().at(0);
param?.setType(`{ params: { lang: string }, children: ReactNode }`);
param?.setType(`{ params: Promise<{ lang: string }>, children: ReactNode }`);
param?.set({
name: `{ params, children }`,
});
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/test/fixture/layout.out
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ const inter = Inter({
subsets: ['latin'],
});

export default function Layout({ params, children }: { params: { lang: string }, children: ReactNode }) {
export default async function Layout({ params, children }: { params: Promise<{ lang: string }>, children: ReactNode }) {
return (
<html lang="en" className={inter.className} suppressHydrationWarning>
<body>
<I18nProvider locale={params.lang} locales={[
<I18nProvider locale={(await params).lang} locales={[
{ locale: 'en', name: 'English' }
]}>
<RootProvider>{children}</RootProvider>
Expand Down
8 changes: 8 additions & 0 deletions packages/core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# next-docs-zeta

## 14.6.6

## 14.6.5

### Patch Changes

- 969da26: Improve i18n api

## 14.6.4

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fumadocs-core",
"version": "14.6.4",
"version": "14.6.6",
"description": "The library for building a documentation website in Next.js",
"keywords": [
"NextJs",
Expand Down
15 changes: 10 additions & 5 deletions packages/core/src/search/client/static.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import {
type RawData,
} from '@orama/orama';
import { type SortedResult } from '@/server';
import { searchSimple } from '@/search/search/simple';
import { searchAdvanced } from '@/search/search/advanced';
import { type advancedSchema } from '@/search/create-db';
import { type schema } from '@/search/create-db-simple';
import { searchSimple } from '@/search/orama/search/simple';
import { searchAdvanced } from '@/search/orama/search/advanced';
import {
type advancedSchema,
type simpleSchema,
} from '@/search/orama/create-db';

export interface StaticOptions {
/**
Expand Down Expand Up @@ -86,7 +88,10 @@ export function createStaticClient({

if (!cached) return [];
if (cached.type === 'simple')
return searchSimple(cached as unknown as Orama<typeof schema>, query);
return searchSimple(
cached as unknown as Orama<typeof simpleSchema>,
query,
);

return searchAdvanced(
cached.db as Orama<typeof advancedSchema>,
Expand Down
44 changes: 0 additions & 44 deletions packages/core/src/search/create-db-simple.ts

This file was deleted.

File renamed without changes.
Loading

0 comments on commit 5f06e7a

Please sign in to comment.