next-international
next-international copied to clipboard
Lot of potential but too strongly bounded by nextjs.
I want to use it in a react native project but just because it's using GetStaticProps
and Router
from next
hence it can't be used anywhere except the next js
project.
I see a lot of potential in this library if it was not strongly bounded to one library. This can easily work in any react based project.
U can provide optional "no configuration" and "automatic binding" for the next js as an extension for this library.
Thoughts?
There are a few reasons why this library currently only works with Next.js:
-
getStaticProps
allows to serve content in multiple languages while having good Web Vitals and SEO, although I think crawlers can execute JavaScript and so load the right locale client-side; but that means higher Cumulative Layout Shift / First Input Delay. - Next.js already offers a very good i18n routing with almost no configuration, and this library uses the same configuration to make developers' life easier.
I've been already thinking about how this could be ported to be framework agnostic, but that's kinda hard to achieve right now. We'll have to split the library into a "core" package, then another package for each framework to allow SSR / plug to the framework's i18n routing (and what happens if a framework doesn't provide i18n routing?). That's definitely something I want to implement in the future.
I feel like the core functionality that is providing a type-safe utility to manage language bundles in react project
can be easily extracted and quickly made framework agnostic by just exposing the useI18n
hook independently and exposing some functions from inside it like changeLocale
I did use some of your types to extend the https://www.npmjs.com/package/i18n-js/v/next
library to introduce strict type checking and extracting parameters out of strings (awesome work on that thou 🎉).
I'm glad u were thinking of making this framework agnostic anyways good luck on that.
Keeping this thread open for now. If you ever work on this feature. Feel free to update this thread for others to follow.
Agree that I18nProvider
& useI18n
can be easily extracted into a standalone package. But one of the goals of this library is to have everything ready-to-go, with minimal/no extra configuration. I'll update the issue when we start working on making next-international
framework agnostic!
I believe the idea behind this package is really nice, and thanks to your trick for parameter extraction I was able to fill in the gaps for my own implementation.
I'd highly suggest separating the types, helpers, etc. into a separate package and build next-international on top of it. This way people would be able to use your ts magic in a standalone way.
Below I'm sharing some types that I wrote for my own needs, as an experiment, you might find it useful. I've learned parameter extraction from your library - thanks for that!
type SourceKey = string | number
type Source = Record<SourceKey, any>
type InferSourceKeys<TSource extends Source> = Exclude<
Extract<keyof TSource, SourceKey>,
keyof any[]
>
type InferSourceNestedKeys<
TSource extends Source,
TKey extends SourceKey = InferSourceKeys<TSource>
> = TKey extends SourceKey
? TSource[TKey] extends Source
? `${TKey}` | `${TKey}.${InferSourceNestedKeys<TSource[TKey]>}`
: `${TKey}`
: `${TKey}`
type InferSourceValue<
TSource extends Source,
TKey extends InferSourceNestedKeys<TSource>
> = TKey extends InferSourceKeys<TSource>
? TSource[TKey]
: TKey extends `${infer TFirst}.${infer TRest}`
? TRest extends InferSourceNestedKeys<TSource[TFirst]>
? InferSourceValue<TSource[TFirst], TRest>
: never
: never
type InferSourceValuePlaceholderNames<TValue> = TValue extends string
? TValue extends ""
? []
: TValue extends `${infer TStart}{${infer TPlaceholder}}${infer TRest}`
? [TPlaceholder, ...InferSourceValuePlaceholderNames<TRest>]
: []
: []
type InferSourceValuePlaceholders<
TValue,
TReplacement = string | number | boolean | symbol
> = Record<InferSourceValuePlaceholderNames<TValue>[number], TReplacement>
type SourceReaderFunction = <
TSource extends Source,
TKey extends InferSourceNestedKeys<TSource> = InferSourceNestedKeys<TSource>,
TPlaceholderNames = InferSourceValuePlaceholderNames<
InferSourceValue<TSource, TKey>
>
>(
source: TSource,
path: TKey,
...placeholders: TPlaceholderNames extends any[]
? TPlaceholderNames["length"] extends 0
? []
: [InferSourceValuePlaceholders<InferSourceValue<TSource, TKey>>]
: []
) => InferSourceValue<TSource, TKey>
type SourceReader<TSource extends Source> = <
TKey extends InferSourceNestedKeys<TSource> = InferSourceNestedKeys<TSource>,
TPlaceholderNames = InferSourceValuePlaceholderNames<
InferSourceValue<TSource, TKey>
>
>(
path: TKey,
...placeholders: TPlaceholderNames extends any[]
? TPlaceholderNames["length"] extends 0
? []
: [InferSourceValuePlaceholders<InferSourceValue<TSource, TKey>>]
: []
) => InferSourceValue<TSource, TKey>
const read: SourceReaderFunction = (source, key, ...placeholders) => {
const parts = key.split(".")
let result: any = source
for (let i = 0; i < parts.length; i++) {
result = result[parts[i]]
if (result === undefined && i === parts.length - 1) {
return key
}
}
const replacements = placeholders[0]
if (replacements) {
Object.entries(replacements).map(
([key, value]) =>
(result = result
.toString()
.replace(`{${key}}`, (value as any).toString()))
)
}
return result
}
Thanks for the kind words!
Yeah, splitting the types into a separate package is something that I want to do, so anyone can use them with the library they want. I think this will be part of the 1.0.0 version, along with multiple "adapters" for each React framework. Non-react frameworks are outside of the scope of this library, which strictly focuses on low-configuration and uses framework features to enhance users' experience.
Started working on a type-specific package:
- https://github.com/QuiiBz/next-international/pull/20
Update: international-types
released on NPM and used by next-international
starting 0.1.1
Closing this issue as stale, feel free to re-open if needed.