-
-
Notifications
You must be signed in to change notification settings - Fork 59
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Willem-Jaap <[email protected]> Co-authored-by: Tom Lienard <[email protected]> Co-authored-by: Zack Reneau-Wedeen <[email protected]>
- Loading branch information
1 parent
82b12a0
commit 2985fb7
Showing
62 changed files
with
7,536 additions
and
3,236 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"extends": "next/core-web-vitals" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||
|
||
# dependencies | ||
/node_modules | ||
/.pnp | ||
.pnp.js | ||
|
||
# testing | ||
/coverage | ||
|
||
# next.js | ||
/.next/ | ||
/out/ | ||
|
||
# production | ||
/build | ||
|
||
# misc | ||
.DS_Store | ||
*.pem | ||
|
||
# debug | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
|
||
# local env files | ||
.env*.local | ||
|
||
# vercel | ||
.vercel | ||
|
||
# typescript | ||
*.tsbuildinfo | ||
next-env.d.ts |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { default as AppIcon } from './app.svg'; | ||
export { default as PagesIcon } from './pages.svg'; |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/** @type {import('next').NextConfig} */ | ||
const nextConfig = { | ||
reactStrictMode: true, | ||
webpack(config) { | ||
const allowedSvgRegex = /components\/icons\/.+\.svg$/; | ||
|
||
const fileLoaderRule = config.module.rules.find(rule => rule.test?.test('.svg')); | ||
fileLoaderRule.exclude = allowedSvgRegex; | ||
|
||
config.module.rules.push({ | ||
test: allowedSvgRegex, | ||
use: ['@svgr/webpack'], | ||
}); | ||
|
||
return config; | ||
}, | ||
}; | ||
|
||
const withNextra = require('nextra')({ | ||
theme: 'nextra-theme-docs', | ||
themeConfig: './theme.config.jsx', | ||
flexsearch: { | ||
codeblocks: false, | ||
}, | ||
defaultShowCopyCode: true, | ||
}); | ||
|
||
module.exports = withNextra(nextConfig); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
{ | ||
"name": "docs", | ||
"version": "0.1.0", | ||
"private": true, | ||
"scripts": { | ||
"dev": "next dev", | ||
"build": "next build", | ||
"start": "next start", | ||
"lint": "next lint" | ||
}, | ||
"dependencies": { | ||
"@types/node": "^18.0.4", | ||
"@types/react": "^18.2.9", | ||
"@types/react-dom": "18.2.4", | ||
"@vercel/analytics": "^1.0.2", | ||
"eslint": "8.47.0", | ||
"eslint-config-next": "13.4.13", | ||
"next": "13.4.13", | ||
"nextra": "^2.11.0", | ||
"nextra-theme-docs": "^2.11.0", | ||
"react": "18.2.0", | ||
"react-dom": "18.2.0", | ||
"typescript": "^5.1.6" | ||
}, | ||
"devDependencies": { | ||
"@svgr/webpack": "^8.1.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { Analytics } from '@vercel/analytics/react'; | ||
|
||
export default function App({ Component, pageProps }) { | ||
return ( | ||
<> | ||
<Component {...pageProps} /> | ||
<Analytics /> | ||
</> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"index": { | ||
"title": "Home", | ||
"type": "page" | ||
}, | ||
"docs": { | ||
"title": "Documentation", | ||
"type": "page" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
{ | ||
"index": "Get Started", | ||
"writing-locales": "Writing locales", | ||
"testing": "Testing", | ||
"examples": "Examples", | ||
"-- App Router": { | ||
"type": "separator", | ||
"title": "App Router" | ||
}, | ||
"app-setup": "Setup", | ||
"app-plurals": "Plurals", | ||
"app-scoped-translations": "Scoped translations", | ||
"app-get-change-locale": "Get and change the locale", | ||
"app-middleware-configuration": "Middleware configuration", | ||
"app-static-rendering": "Static Rendering", | ||
"-- Pages Router": { | ||
"type": "separator", | ||
"title": "Pages Router" | ||
}, | ||
"pages-setup": "Setup", | ||
"pages-plurals": "Plurals", | ||
"pages-scoped-translations": "Scoped translations", | ||
"pages-get-change-locale": "Get and change the locale", | ||
"pages-static-site-generation": "Static Site Generation" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# Get and change the locale | ||
|
||
You can only change the current locale from a Client Component. Export `useChangeLocale` and `useCurrentLocale` from `createI18nClient`, and export `getCurrentLocale` from `createI18nServer`: | ||
|
||
```ts {3,4,12} | ||
// locales/client.ts | ||
export const { | ||
useChangeLocale, | ||
useCurrentLocale, | ||
... | ||
} = createI18nClient({ | ||
... | ||
}) | ||
|
||
// locales/server.ts | ||
export const { | ||
getCurrentLocale, | ||
... | ||
} = createI18nServer({ | ||
... | ||
}) | ||
``` | ||
|
||
Then use these hooks: | ||
|
||
```tsx {6,7,11-13,22,25} | ||
// Client Component | ||
'use client' | ||
import { useChangeLocale, useCurrentLocale } from '../../locales/client' | ||
|
||
export default function Page() { | ||
const changeLocale = useChangeLocale() | ||
const locale = useCurrentLocale() | ||
|
||
return ( | ||
<> | ||
<p>Current locale: {locale}</p> | ||
<button onClick={() => changeLocale('en')}>English</button> | ||
<button onClick={() => changeLocale('fr')}>French</button> | ||
</> | ||
) | ||
} | ||
|
||
// Server Component | ||
import { getCurrentLocale } from '../../locales/server' | ||
|
||
export default function Page() { | ||
const locale = getCurrentLocale() | ||
|
||
return ( | ||
<p>Current locale: {locale}</p> | ||
) | ||
} | ||
``` | ||
|
||
If you have set a [`basePath`](https://nextjs.org/docs/app/api-reference/next-config-js/basePath) option inside `next.config.js`, you'll also need to set it inside `createI18nClient`: | ||
|
||
```ts {7} | ||
// locales/client.ts | ||
export const { | ||
... | ||
} = createI18nClient({ | ||
... | ||
}, { | ||
basePath: '/base' | ||
}) | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# Middleware configuration | ||
|
||
## Rewrite the URL to hide the locale | ||
|
||
You might have noticed that by default, next-international redirects and shows the locale in the URL (e.g `/en/products`). This is helpful for users, but you can transparently rewrite the URL to hide the locale (e.g `/products`). | ||
|
||
Navigate to the `middleware.ts` file and set the `urlMappingStrategy` to `rewrite` (the default is `redirect`): | ||
|
||
```ts {5} | ||
// middleware.ts | ||
const I18nMiddleware = createI18nMiddleware({ | ||
locales: ['en', 'fr'], | ||
defaultLocale: 'en', | ||
urlMappingStrategy: 'rewrite' | ||
}) | ||
``` | ||
|
||
You can also choose to only rewrite the URL for the default locale, and keep others locale in the URL (e.g use `/products` instead of `/en/products`, but keep `/fr/products`) using the `rewriteDefault` strategy: | ||
|
||
```ts {5} | ||
// middleware.ts | ||
const I18nMiddleware = createI18nMiddleware({ | ||
locales: ['en', 'fr'], | ||
defaultLocale: 'en', | ||
urlMappingStrategy: 'rewriteDefault' | ||
}) | ||
``` | ||
|
||
## Override the user's locale resolution | ||
|
||
If needed, you can override the resolution of a locale from a `Request`, which by default will try to extract it from the `Accept-Language` header. This can be useful to force the use of a specific locale regardless of the `Accept-Language` header. Note that this function will only be called if the user doesn't already have a `Next-Locale` cookie. | ||
|
||
Navigate to the `middleware.ts` file and implement a new `resolveLocaleFromRequest` function: | ||
|
||
```ts {5-8} | ||
// middleware.ts | ||
const I18nMiddleware = createI18nMiddleware({ | ||
locales: ['en', 'fr'], | ||
defaultLocale: 'en', | ||
resolveLocaleFromRequest: request => { | ||
// Do your logic here to resolve the locale | ||
return 'fr' | ||
} | ||
}) | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# Plurals | ||
|
||
Plural translations work out of the box without any external dependencies, using the [`Intl.PluralRules`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/PluralRules) API, which is supported in all browsers and Node.js. | ||
|
||
To declare plural translations, append `#` followed by `zero`, `one`, `two`, `few`, `many` or `other`: | ||
|
||
```ts {3-4} | ||
// locales/en.ts | ||
export default { | ||
'cows#one': 'A cow', | ||
'cows#other': '{count} cows' | ||
} as const | ||
``` | ||
|
||
The correct translation will then be determined automatically using a mandatory `count` parameter. The value of `count` is determined by the union of all suffixes, enabling type safety: | ||
|
||
- `zero` allows 0 | ||
- `one` autocompletes 1, 21, 31, 41... but allows any number | ||
- `two` autocompletes 2, 22, 32, 42... but allows any number | ||
- `few`, `many` and `other` allow any number | ||
|
||
This works in both Client and Server Components, and with [scoped translations](/docs/app-scoped-translations): | ||
|
||
```tsx {7,9} | ||
export default function Page() { | ||
const t = useI18n() // or `getI18n()` in Server Components | ||
|
||
return ( | ||
<div> | ||
{/* Output: A cow */} | ||
<p>{t('cows', { count: 1 })}</p> | ||
{/* Output: 3 cows */} | ||
<p>{t('cows', { count: 3 })}</p> | ||
</div> | ||
) | ||
} | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# Scoped translations | ||
|
||
When you have a lot of keys, you may notice in a file that you always use and duplicate the same scope: | ||
|
||
```ts | ||
// We always repeat `pages.settings` | ||
t('pages.settings.title') | ||
t('pages.settings.description', { identifier }) | ||
t('pages.settings.cta') | ||
``` | ||
|
||
We can avoid this using the `useScopedI18n` hook / `getScopedI18n` method. And of course, the scoped key, subsequent keys and params will still be 100% type-safe. | ||
|
||
Export `useScopedI18n` from `createI18nClient` and `getScopedI18n` from `createI18nServer`: | ||
|
||
```ts {3,11} | ||
// locales/client.ts | ||
export const { | ||
useScopedI18n, | ||
... | ||
} = createI18nClient({ | ||
... | ||
}) | ||
|
||
// locales/server.ts | ||
export const { | ||
getScopedI18n, | ||
... | ||
} = createI18nServer({ | ||
... | ||
}) | ||
``` | ||
|
||
Then use it in your components: | ||
|
||
```tsx {6,10-12,21,25-27} | ||
// Client Component | ||
'use client' | ||
import { useScopedI18n } from '../../locales/client' | ||
|
||
export default function Page() { | ||
const t = useScopedI18n('pages.settings') | ||
|
||
return ( | ||
<div> | ||
<p>{t('title')}</p> | ||
<p>{t('description', { identifier })}</p> | ||
<p>{t('cta')}</p> | ||
</div> | ||
) | ||
} | ||
|
||
// Server Component | ||
import { getScopedI18n } from '../../locales/server' | ||
|
||
export default async function Page() { | ||
const t = await getScopedI18n('pages.settings') | ||
|
||
return ( | ||
<div> | ||
<p>{t('title')}</p> | ||
<p>{t('description', { identifier })}</p> | ||
<p>{t('cta')}</p> | ||
</div> | ||
) | ||
} | ||
``` | ||
|
Oops, something went wrong.