amannn / next-intl

🌐 Internationalization (i18n) for Next.js
https://next-intl-docs.vercel.app
MIT License
2.58k stars 236 forks source link

feat!: Revamp augmented types and add support for typed `Locale` #1495

Closed amannn closed 2 weeks ago

amannn commented 2 weeks ago
// global.d.ts

import {routing} from '@/i18n/routing';
import {formats} from '@/i18n/request';
import en from './messages/en.json';

declare module 'next-intl' {
  interface AppConfig {
    Locale: (typeof routing.locales)[number];
    Formats: typeof formats;
    Messages: typeof en;
  }
}

Note that all entries in AppConfig are optional and can be added as necessary—if at all.

Features

Breaking changes

Proposed docs


Resolves https://github.com/amannn/next-intl/issues/1377

vercel[bot] commented 2 weeks ago

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
next-intl-docs ✅ Ready (Inspect) Visit Preview 💬 Add feedback Nov 1, 2024 8:49am
next-intl-example-app-router ✅ Ready (Inspect) Visit Preview 💬 Add feedback Nov 1, 2024 8:49am
next-intl-example-app-router-without-i18n-routing ✅ Ready (Inspect) Visit Preview 💬 Add feedback Nov 1, 2024 8:49am
amannn commented 2 weeks ago

Hey @dBianchii, as part of the upcoming v4 release of next-intl, I revamped the type augmentation a bit. The new API gets rid of previously needed globals and now also provides opt-in type-safety for locale.

Since this is closely related to PR #1346 that you've worked on, I was wondering if you're curious to have a look? The PR description has the relevant details. If you're up for it, would be cool if you could have a look at the updated TypeScript docs page to see if this sounds reasonable to you.

I was honestly a bit surprised that the strict typing of locale (along with the introduction of the Locale type) has some interesting implications, but seems to work really nicely if used consistently in apps :). I was also able to simplify i18n/request.ts a bit with a newly introduced hasLocale util (prev, now).

The PR is pretty much ready to go from my perspective, but I need to give it another look tomorrow—my head is already spinning a bit from the type wrestling today 😄.

Would be curious if you have an opinion here!

chertik77 commented 2 weeks ago

I'm waiting for that so much, great pr! 🙂

dBianchii commented 2 weeks ago

Hi @amannn, awesome! I'll try to take a look either today or tomorrow. Can't really promise it as I am quite busy, so please don't wait for me for release. By what I understand it's a more local type configuration only for next-intl instead of a declare global, as well as a new interface for type-safe Locales. In my project I was already setting a export const locales = ["en", "pt-BR"] as const somewhere and that was enough to get the types for it anywhere I needed, so I'll have to see how you decided to implement this and provide feedback when possible.

Thanks!

amannn commented 2 weeks ago

@dBianchii No worries, only if you have the time! The feature will be part of the upcoming v4 version, that will first have to go through a beta/RC phase—so no stress at all.

In my project I was already setting a export const locales = ["en", "pt-BR"] as const somewhere and that was enough to get the types for it anywhere I needed, so I'll have to see how you decided to implement this and provide feedback when possible.

Yep, I also did something similar like this before in projects:

export const locales = ["en", "pt-BR"] as const;
export type Locale = (typeof locales)[number];

(or based on routing.locales)

This can be used in userland-code, but the difference now is that next-intl will consider the Locale type where relevant (e.g. when returned from useLocale, when using <Link locale={…} />, etc.). It's a small quality-of-life improvement in those cases, but overall I think a cool aspect is that this nudges users to use the now-exported import {Locale} from 'next-intl' where relevant, instead of defaulting to string, generally enhancing the type-safety across your project.

Also, you can start with Locale defaulting to string, and later switch to a strictly-typed Locale if desired. I'm now suggesting the Locale type in the getting started with i18n routing docs, just as a quick hint that Locale exists. It's in fact not quite necessary there since the incoming locale is validated, it's more about providing some awareness for it in a subtle way. If you start out with using Locale where relevant in your app, you can easily make it strictly-typed later on if you like to do so.

dBianchii commented 2 weeks ago

Really great! Feels good being able to just import the type of Locales directly from next-intl. Also, feels better to define the types with declare module 'next-intl' { } instead of declaring a global like before.

Excited for v4 and for Next.JS 15 support :tada:

amannn commented 1 week ago

@dBianchii Awesome, thanks a lot for having a look! 🙌