QuiiBz / next-international

Type-safe internationalization (i18n) for Next.js
https://next-international.vercel.app
MIT License
1.28k stars 59 forks source link

Custom hook for parsed useScopedI18n & useI18n #367

Closed pavelsushkov closed 7 months ago

pavelsushkov commented 7 months ago

Hello, while #343 is currently not possible, I'm thinking of a workaround. Currently, I'm using this parser: https://www.npmjs.com/package/html-react-parser and wrap every entry of t or scopedT like this

parse(scopedT('specificKey', { specificKeyParam: 'paramValue' }

It's not clean and quite an unreliable approach, so I tried to make a custom hook. I want to return the same functions as useScopedI18n and useI18n, but parsed.

So far I got this and stuck with parameters of functions. What would be a proper way to declare them?

'use client';

import type {
  FlattenLocale,
  LocaleKeys,
  ParamsObject,
  Scopes,
} from 'international-types';

import { useCurrentLocale, useI18n, useScopedI18n } from '@/../locales/client';
import type en from '@/../locales/en';

import parse from 'html-react-parser';

export type DefaultLocale = FlattenLocale<typeof en>;
type Scope = Scopes<DefaultLocale>;
type Key = LocaleKeys<DefaultLocale, Scope>;

export const useTranslation = (scope: Scopes<DefaultLocale>) => {
  const locale = useCurrentLocale();
  const unparsedScopedT = useScopedI18n(scope);
  const unparsedT = useI18n();

  const scopedT = (key: ???, params?: ???): ReturnType<typeof parse> => {
    return params 
      ? parse(unparsedScopedT(key, params))
      : parse(unparsedScopedT(key));
  }

  const t = (key: ???, ???): ReturnType<typeof parse> => {
    return parse(unparsedT(...));
  }

  return {
    locale,
    scopedT,
    t,
  }
}
QuiiBz commented 7 months ago

You can take a look at some examples here: https://github.com/QuiiBz/next-international/tree/main/packages/international-types

Let me know if you're still stuck on this, but I believe it should be pretty much the same.

pavelsushkov commented 7 months ago

I saw these examples, but still no luck. I can't figure out what next-international object I should use inside these functions, how to pass these objects as an argument for the "parse" function, and how to return the result as functions but with parsed values.

The goal is to be able to use this custom hook somehow like this:

const { myT, myScopedT } = useMyTHook('Scope');
...
{myT('Key', { params })}
...
{myScopedT('Key', { params })}

Where myT and myScopedT are the same as standard const t = useI18n & const scopedT = useScopedI18n('Scope), accept all the same arguments, but return parsed JSX.

QuiiBz commented 7 months ago

Feel free to send a minimal reproduction (e.g. CodeSandbox) so I can try to help you with the types!