Type-safe internationalization (i18n) for Next.js
MIT License
Bot releases are hidden (Show)
fallbackLocale
type for pages router by @QuiiBz in https://github.com/QuiiBz/next-international/pull/345
Full Changelog: https://github.com/QuiiBz/next-international/compare/1.2.3...1.2.4
Published by QuiiBz 9 months ago
Full Changelog: https://github.com/QuiiBz/next-international/compare/1.2.2...1.2.3
Published by QuiiBz 9 months ago
I18nProviderWrapper
interface by @ubinatus in https://github.com/QuiiBz/next-international/pull/331
Full Changelog: https://github.com/QuiiBz/next-international/compare/1.2.1...1.2.2
Published by QuiiBz 9 months ago
Full Changelog: https://github.com/QuiiBz/next-international/compare/1.2.0...1.2.1
Published by QuiiBz 9 months ago
@vercel/speed-insights
by @QuiiBz in https://github.com/QuiiBz/next-international/pull/318
Full Changelog: https://github.com/QuiiBz/next-international/compare/1.1.4...1.2.0
Published by QuiiBz 12 months ago
CONTRIBUTING.md
by @QuiiBz in https://github.com/QuiiBz/next-international/pull/280
Full Changelog: https://github.com/QuiiBz/next-international/compare/1.1.3...1.1.4
Published by QuiiBz about 1 year ago
Full Changelog: https://github.com/QuiiBz/next-international/compare/1.1.2...1.1.3
Published by QuiiBz about 1 year ago
String.prototype.split
param by @Yovach in https://github.com/QuiiBz/next-international/pull/238
Full Changelog: https://github.com/QuiiBz/next-international/compare/1.1.0...1.1.2
Published by QuiiBz about 1 year ago
next-international 1.1.0 includes new features and improvements for the App Router. Upgrade now by installing the latest version:
pnpm install next-international@latest
#zero
works with { count: 0 }
(App & Pages Router)rewriteDefault
strategy redirects to hide the default locale (App Router)#zero
works with { count: 0 }
(App & Pages Router)Previously, plurals using #zero
only worked with { count: 0 }
for some languages, because of how the Intl.PluralRules
API works. We extended it to make it available on any language, so this example now works as expected:
// locales/en.ts
export default {
'cows#zero': 'No cows',
'cows#one': 'A cow',
'cows#other': '{count} cows'
} as const
t('cows', { count: 0 }) // No cows
t('cows', { count: 1 }) // A cow
t('cows', { count: 3 }) // 3 cows
By default, next-international doesn't preserve search params when changing the locale. This is because useSearchParams()
will opt-out the page from Static Rendering if you don't wrap the component in a Suspense
boundary.
If you want to preserve search params, you can manually use the preserveSearchParams
option inside useChangeLocale
:
// Client Component
'use client'
import { useChangeLocale } from '../../locales/client'
export function ChangeLocaleButton() {
const changeLocale = useChangeLocale({ preserveSearchParams: true })
...
}
Then, don't forget to wrap the component in a Suspense
boundary to avoid opting out the entire page from Static Rendering:
// Client or Server Component
import { ChangeLocaleButton } from './change-locale-button'
export default function Page() {
return (
<Suspense>
<ChangeLocaleButton />
</Suspense>
)
}
rewriteDefault
strategy redirects to hide default locale (App Router)The rewriteDefault
strategy used to only show the locale segment in the URL when not using the default locale now redirects and hides the default locale to avoid having the same page twice.
Default locale: en
Before | After |
---|---|
/ → /
|
/ → /
|
/en → /en
|
/en → /
|
/fr → /fr
|
/fr → /fr
|
⚠️ BREAKING (App Router)
We had an issue that would show the keys instead of the translation when statically rendering a page that had Client Components. The correct translation would only be set during hydration.
The fallbackLocale
prop has been moved from I18nProviderClient
to createI18nClient
, to match createI18nServer
:
Before
// app/[locale]/client/layout.tsx
'use client'
import en from '../../locales/en'
export default function Layout({ children }: { children: ReactElement }) {
return (
<I18nProviderClient fallbackLocale={en}>
{children}
</I18nProviderClient>
)
}
// locales/client.ts
import en from './en'
export const {
...
} = createI18nClient({
...
})
After:
// app/[locale]/client/layout.tsx
'use client'
export default function Layout({ children, params: { locale } }: { children: ReactElement, params: { locale: string } }) {
return (
<I18nProviderClient locale={locale}>
{children}
</I18nProviderClient>
)
}
// locales/client.ts
import en from './en'
export const {
...
} = createI18nClient({
...
}, {
fallbackLocale: en
})
'use client'
annotation by @medyahyejoud in https://github.com/QuiiBz/next-international/pull/215
Full Changelog: https://github.com/QuiiBz/next-international/compare/1.0.1...1.1.0
Published by QuiiBz about 1 year ago
getLocaleProps
by @lindesvard in https://github.com/QuiiBz/next-international/pull/166
Full Changelog: https://github.com/QuiiBz/next-international/compare/1.0.0...1.0.1
Published by QuiiBz about 1 year ago
next-international 1.0.0 is the first production-ready release, with feature parity across App and Pages Router. We have a brand new documentation website, Static Rendering for the App Router, new options, and improved APIs!
Upgrade now by installing the latest version:
pnpm install next-international@latest
rewriteDefault
strategy (App Router)We now have a proper documentation website that you can browse at https://next-international.vercel.app! The documentation itself has also been improved to make it easier to understand and highlight code changes:
next-international now supports Static Rendering, meaning your pages can be rendered at build time and then be served statically from CDNs, resulting in faster TTFB.
Export getStaticParams
from createI18nServer
:
// locales/server.ts
export const {
getStaticParams,
...
} = createI18nServer({
...
})
Inside all pages that you want to be statically rendered, call this setStaticParamsLocale
function by giving it the locale
page param:
// app/[locale]/page.tsx and any other page
import { setStaticParamsLocale } from 'next-international/server'
export default function Page({ params: { locale } }: { params: { locale: string } }) {
setStaticParamsLocale(locale)
return (
...
)
}
And export a new generateStaticParams
function. If all your pages should be rendered statically, you can also move this to the root layout:
// app/[locale]/page.tsx and any other page, or in the root layout
import { getStaticParams } from '../../locales/server'
export function generateStaticParams() {
return getStaticParams()
}
rewriteDefault
strategy (App Router)You can now 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 new rewriteDefault
strategy:
const I18nMiddleware = createI18nMiddleware({
locales: ['en', 'fr'],
defaultLocale: 'en',
urlMappingStrategy: 'rewriteDefault'
})
This release adds missing support for fallback locales on the server with the App Router, similar to the fallbackLocale
prop of I18nProviderClient
. Navigate to locales/server.ts
and add a new fallbackLocale
option:
// locales/server.ts
import en from './en'
export const {
...
} = createI18nServer({
...
}, {
fallbackLocale: en
})
When a locale can't be found, we now use notFound()
instead of throwing an un-catchable error. This allows to render a not-found.ts
file easily.
⚠️ BREAKING (App Router)
Improve the middleware API for the App Router by using a single object argument and removing the need for as const
for the locales:
Before:
const I18nMiddleware = createI18nMiddleware(['en', 'fr'] as const, 'fr')
// With all options:
const I18nMiddleware = createI18nMiddleware(['en', 'fr'] as const, 'fr', {
urlMappingStrategy: 'rewrite',
resolveLocaleFromRequest: request => {
// Do your logic here to resolve the locale
return 'fr'
}
})
After:
const I18nMiddleware = createI18nMiddleware({
locales: ['en', 'fr'],
defaultLocale: 'en'
})
// With all options:
const I18nMiddleware = createI18nMiddleware({
locales: ['en', 'fr'],
defaultLocale: 'en',
urlMappingStrategy: 'rewrite',
resolveLocaleFromRequest: request => {
// Do your logic here to resolve the locale
return 'fr'
}
})
⚠️ BREAKING (App Router)
Improve the API for configuring the App Router behaviors by moving all configurations from specific functions to createI18n*
functions. This avoids duplicating multiple times the same configuration, and will allow for more configuration options in the future.
These changes are only affecting you if you were using these options.
basePath
configBefore:
// locales/client.ts
export const { useChangeLocale } = createI18nClient({
en: () => import('./en'),
fr: () => import('./fr')
})
// In a Client Component
const changeLocale = useChangeLocale({
basePath: '/base'
})
After:
// locales/client.ts
export const { useChangeLocale } = createI18nClient({
en: () => import('./en'),
fr: () => import('./fr')
}, {
basePath: '/base'
})
// In a Client Component
const changeLocale = useChangeLocale()
segmentName
configBefore:
// locales/client.ts
export const { useCurrentLocale } = createI18nClient({
en: () => import('./en'),
fr: () => import('./fr')
})
// in a Client Component
const currentLocale = useCurrentLocale({
segmentName: 'locale'
})
// locales/server.ts
export const { getStaticParams } = createI18nServer({
en: () => import('./en'),
fr: () => import('./fr')
})
// in a page
export function generateStaticParams() {
return getStaticParams({
segmentName: 'locale'
})
}
After:
// locales/client.ts
export const { useCurrentLocale } = createI18nClient({
en: () => import('./en'),
fr: () => import('./fr')
}, {
segmentName: 'locale'
})
// in a Client Component
const currentLocale = useCurrentLocale()
// locales/server.ts
export const { getStaticParams } = createI18nServer({
en: () => import('./en'),
fr: () => import('./fr')
}, {
segmentName: 'locale'
})
// in a page
export function generateStaticParams() {
return getStaticParams()
}
Full Changelog: https://github.com/QuiiBz/next-international/compare/0.9.5...1.0.0
Published by QuiiBz about 1 year ago
rewrite
strategy by @QuiiBz in https://github.com/QuiiBz/next-international/pull/146
Full Changelog: https://github.com/QuiiBz/next-international/compare/0.9.4...0.9.5
Published by QuiiBz about 1 year ago
changeLocale
with subsequent navigations by @QuiiBz in https://github.com/QuiiBz/next-international/pull/140
Full Changelog: https://github.com/QuiiBz/next-international/compare/0.9.3...0.9.4
Published by QuiiBz about 1 year ago
getStaticParams
by @QuiiBz in https://github.com/QuiiBz/next-international/pull/124
license
field to package.json
by @QuiiBz in https://github.com/QuiiBz/next-international/pull/130
useChangeLocale
with rewrite strate by @QuiiBz in https://github.com/QuiiBz/next-international/pull/137
Full Changelog: https://github.com/QuiiBz/next-international/compare/0.9.2...0.9.3
Published by QuiiBz about 1 year ago
useCurrentLocale
by @QuiiBz in https://github.com/QuiiBz/next-international/pull/123
Full Changelog: https://github.com/QuiiBz/next-international/compare/0.9.1...0.9.2
Published by QuiiBz about 1 year ago
Full Changelog: https://github.com/QuiiBz/next-international/compare/0.9.0...0.9.1
Published by QuiiBz about 1 year ago
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:
// middleware.ts
const I18nMiddleware = createI18nMiddleware(['en', 'fr'] as const, 'fr', {
resolveLocaleFromRequest: request => {
// Do your logic here to resolve the locale
return 'fr'
}
})
Full Changelog: https://github.com/QuiiBz/next-international/compare/0.8.2...0.9.0
Published by QuiiBz about 1 year ago
Full Changelog: https://github.com/QuiiBz/next-international/compare/0.8.0...0.8.2
Published by QuiiBz about 1 year ago
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
):
// middleware.ts
const I18nMiddleware = createI18nMiddleware(['en', 'fr'] as const, 'fr', {
urlMappingStrategy: 'rewrite'
})
useChangeLocale
with basePath
When using useChangeLocale
and if you have set a basePath
option inside next.config.js
, you'll also need to set it here:
const changeLocale = useChangeLocale({
basePath: '/your-base-path'
})
useParams
& rewrite
strategy to hide locale from URL by @EdmundKorley in https://github.com/QuiiBz/next-international/pull/83
useChangeLocale
with basePath
by @QuiiBz in https://github.com/QuiiBz/next-international/pull/90
Full Changelog: https://github.com/QuiiBz/next-international/compare/0.7.0...0.8.0
Published by QuiiBz about 1 year ago
Plural translations work out of the box without any external dependencies, using the 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
:
// 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. This works with the Pages Router, App Router in both Client and Server Components, and with scoped translations:
export default function Page() {
const t = useI18n()
return (
<div>
{/* Output: A cow */}
<p>{t('cows', { count: 1 })}</p>
{/* Output: 3 cows */}
<p>{t('cows', { count: 3 })}</p>
</div>
)
}
count
by @QuiiBz in https://github.com/QuiiBz/next-international/pull/78
Full Changelog: https://github.com/QuiiBz/next-international/compare/0.6.4...0.7.0