DoneDeal0 / Talkr

Talkr is the lightest i18n provider for React applications. It supports Typescript, provides autocompletion, has 0 dependencies, and is very easy to use.

Home Page:https://talkr-documentation.netlify.app/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

The hook should also expose the `tr` function for the current context.

misha opened this issue · comments

First of all, great library! I particularly like the lack of dependencies and total size.

I have a small feature request. The talkr package exposes a handy trfunction for producing a string rather than a component, but using it is inconvenient because you need to pass the values from useT for every call.

Is it possible to also expose tr from useT as well, and then automatically fill in the arguments (locale, languages, and defaultLanguage) using the current context?

My use case is validation using yup and zod. Their APIs require string-based errors, and I need that to happen at validation time rather than render time. Many errors have parameters as well, so it's impossible to just propagate the translation key.

Hi Misha,

Why don't you just use T() instead of tr()? Maybe I don't really see the problem here, could you please send me a codesandbox that demonstrates your issue in a simple and clear manner?

Here is a Talkr template so you can you focus on adding your usecase: https://codesandbox.io/s/talkr-base-example-dvwfio?file=/src/App.tsx

tr() is only exposed to allow certain users to create their own autocompletion wrapper. T() also returns a string but already knows your app context (locale, languages, etc.). I think you should be ok with it.

Thanks for your prompt response!

I've created a sandbox showing the exact location I'd like to use Talkr here:

https://codesandbox.io/s/talkr-uset-tr-use-case-wvypyu

I'm not sure why you say that T()returns a string. Here is the definition from models.d.ts:

export interface UseT extends TContext {
    T: <Key extends string, Params extends TParams>(key: Key, params?: Params) => React.ReactNode;

It's returning a node, which can be many other things besides a string.

Edit: If T() does return a string at all times, I could absolutely use it for this. Is there a design decision for that typing?

I was able to cast the output of T() to a string to solve my problem using a hook:

type ZodSchemaBuilder<SCHEMA extends zod.Schema> =
  (resources: {
    /**
     * Translation function for validation error messages.
     */
    T: <Key extends string, Params extends TParams>(key: Key, params?: Params) => string
  }) => SCHEMA

/**
 * Provides resources for Zod schema generation.
 */
export function useZodSchema<SCHEMA extends zod.Schema>(builder: ZodSchemaBuilder<SCHEMA>) {
  const { T } = useT()

  return useMemo(() => {
    return builder({
      // Talkr's API outputs React.ReactNode, but actually, they're just strings!
      T: (key, params) => T(key, params) as string,
    })
  }, [T, builder])
}

Now my schemas don't need to cast to string when supplying error messages.

I didn't realize they were just strings after all. It would be great if you could narrow the type for future users, but since I was able to accomplish my own use case, feel free to close this issue.

Thanks again for the excellent library!

It's a mistake of mine. I can't believe I've let this ReactNode type instead of string... Anyways, I've pushed a new version 3.3.7 on npm. Please let me know if it works for you. Normally, you won't need the hacky wrapper anymore. Also note that in case a key doesn't exist, Talkr will now return an empty string instead of null.

Thanks, if you enjoy the lib, feel free to spread the word around (article about your usecase, twitter and whatnot ;)).

Have a great day!

That works for me, thank you!