Skip to content

Commit

Permalink
feat: 1.0.0 release (#126)
Browse files Browse the repository at this point in the history
Co-authored-by: Willem-Jaap <67187467+Willem-Jaap@users.noreply.github.com>
Co-authored-by: Tom Lienard <tom.lienrd@gmail.com>
Co-authored-by: Zack Reneau-Wedeen <z.reneau.wedeen@gmail.com>
  • Loading branch information
3 people authored Sep 13, 2023
1 parent 82b12a0 commit 2985fb7
Show file tree
Hide file tree
Showing 62 changed files with 7,536 additions and 3,236 deletions.
3 changes: 3 additions & 0 deletions docs/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}
35 changes: 35 additions & 0 deletions docs/.gitignore
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
2 changes: 2 additions & 0 deletions docs/components/icons/app.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions docs/components/icons/index.ts
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';
2 changes: 2 additions & 0 deletions docs/components/icons/pages.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 28 additions & 0 deletions docs/next.config.js
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);
28 changes: 28 additions & 0 deletions docs/package.json
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"
}
}
10 changes: 10 additions & 0 deletions docs/pages/_app.mdx
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 />
</>
)
}
10 changes: 10 additions & 0 deletions docs/pages/_meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"index": {
"title": "Home",
"type": "page"
},
"docs": {
"title": "Documentation",
"type": "page"
}
}
25 changes: 25 additions & 0 deletions docs/pages/docs/_meta.json
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"
}
68 changes: 68 additions & 0 deletions docs/pages/docs/app-get-change-locale.md
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'
})
```

46 changes: 46 additions & 0 deletions docs/pages/docs/app-middleware-configuration.md
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'
}
})
```

38 changes: 38 additions & 0 deletions docs/pages/docs/app-plurals.md
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>
)
}
```

68 changes: 68 additions & 0 deletions docs/pages/docs/app-scoped-translations.md
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>
)
}
```

Loading

0 comments on commit 2985fb7

Please sign in to comment.