Skip to content

Releases: QuiiBz/next-international

1.1.0

06 Oct 14:37
fdd717a
Compare
Choose a tag to compare

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
  • 🎉 New features
    • Plurals with #zero works with { count: 0 } (App & Pages Router)
    • Preserve search params (App Router)
    • rewriteDefault strategy redirects to hide the default locale (App Router)
  • ⚠️ Breaking changes
    • Support Static Rendering in nested Client Components (App Router)

 Plurals with #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

Preserve search params (App Router)

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

Support Static Rendering in nested Client Components (App Router)

⚠️ 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:

See changes

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
})

What's Changed

New Contributors

  • @medyahyejoud made their first contribution in #215

Full Changelog: 1.0.1...1.1.0

1.0.1

15 Sep 06:06
Compare
Choose a tag to compare

What's Changed

  • fix(next-international): flatten locale in getLocaleProps by @lindesvard in #166
  • chore(docs): add bun installation support by @poypoydev in #167
  • fix(next-international): remove unintended log in middleware by @zackrw in #168
  • chore: update sponsors by @QuiiBz in #169
  • fix(next-international): fallbackLocale with dot-notation TS error by @QuiiBz in #174
  • fix(next-international): respect rewriteDefault strategy when changing locale by @QuiiBz in #175

New Contributors

  • @lindesvard made their first contribution in #166
  • @poypoydev made their first contribution in #167

Full Changelog: 1.0.0...1.0.1

1.0.0

13 Sep 14:06
2985fb7
Compare
Choose a tag to compare

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
  • 🎉 New features
    • New documentation and website (App & Pages Router)
    • Static Rendering / Static Export support (App Router)
    • New rewriteDefault strategy (App Router)
    • Fallback locale on the server (App Router)
    • Allow catching not found locale errors (App Router)
  • ⚠️ Breaking changes
    • Improved Middleware API (App Router)
    • Improved config API (App Router)

New documentation and website (App & Pages 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:

Screenshot 2023-08-21 at 08 33 20

Static Rendering / Static Export support (App Router)

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.

See setup

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()
}

New 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'
})

Fallback locale on the server (App Router)

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
})

Allow catching not found locale errors (App Router)

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.

Improved Middleware API (App Router)

⚠️ 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:

See changes

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'
  }
})

Improved config API (App Router)

⚠️ 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.

See changes for basePath and segmentName

basePath config

Before:

// 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 config

Before:

// 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()
}

What's Changed

Full Changelog: 0.9.5...1.0.0

0.9.5

02 Sep 07:43
Compare
Choose a tag to compare

What's Changed

  • fix(next-international): infinite redirect with rewrite strategy by @QuiiBz in #146

Full Changelog: 0.9.4...0.9.5

0.9.4

30 Aug 06:34
Compare
Choose a tag to compare

What's Changed

  • fix(next-international): changeLocale with subsequent navigations by @QuiiBz in #140

Full Changelog: 0.9.3...0.9.4

0.9.3

23 Aug 15:41
Compare
Choose a tag to compare

What's Changed

  • feat(next-international): allow configuring segment name in getStaticParams by @QuiiBz in #124
  • feat: add license field to package.json by @QuiiBz in #130
  • chore: remove minify on build by @QuiiBz in #135
  • feat(next-international): remove locale for useChangeLocale with rewrite strate by @QuiiBz in #137

Full Changelog: 0.9.2...0.9.3

0.9.2

18 Aug 16:37
Compare
Choose a tag to compare

What's Changed

  • chore: update deps by @QuiiBz in #116
  • fix(next-international): update middleware matcher to work with images by @QuiiBz in #119
  • fix(next-international): type of useCurrentLocale by @QuiiBz in #123

Full Changelog: 0.9.1...0.9.2

0.9.1

13 Aug 07:43
Compare
Choose a tag to compare

What's Changed

  • chore: add codesandbox example by @QuiiBz in #112
  • fix(next-international): pathname starting with locale error by @QuiiBz in #113

Full Changelog: 0.9.0...0.9.1

0.9.0

12 Aug 06:49
Compare
Choose a tag to compare

App Router

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:

// middleware.ts
const I18nMiddleware = createI18nMiddleware(['en', 'fr'] as const, 'fr', {
  resolveLocaleFromRequest: request => {
    // Do your logic here to resolve the locale
    return 'fr'
  }
})

What's Changed

  • chore(international-types): update examples by @QuiiBz in #105
  • chore: add sponsors to readme by @QuiiBz in #107
  • feat(next-international): override locale resolution by @QuiiBz in #111

Full Changelog: 0.8.2...0.9.0

0.8.2

07 Aug 16:24
Compare
Choose a tag to compare

What's Changed

  • chore: update middleware regex by @QuiiBz in #98
  • fix(next-international): use default locale when Accept-Language is unknown by @QuiiBz in #101

Full Changelog: 0.8.0...0.8.2