Handle dynamic keys with variables
Aximem opened this issue · comments
We would like to use talkr with dynamic keys using variables.
e.g.:
{
exercises: {
1: '...',
2: '...',
...
}
}
{T(`exercises.${getExerciseId()}`)}
The following code displays a typescript error Argument of type 'exercise.${string}' is not assignable to parameter of ...
We don't want to end up doing this since we have hundred of exercises:
switch (exerciseId) {
case '1': return T('exercises.1');
...
}
What can we do ? Thanks
Hi @Aximem, I'm currently on vacation, I'll take a look when I get back next week.
I assume you are using Talkr's autocompletion to get such errors. You have two options:
Option 1
This is the option I would recommend. Modify your useAutocompleteT
hook like this:
import { useT, Autocomplete, TParams, tr } from "talkr";
import en from "./en.json";
type Key = Autocomplete<typeof en>;
export const useAutocompleteT = () => {
const { locale, setLocale, languages, defaultLanguage } = useT();
const _tr = (key: Key, params?: TParams) =>
tr({ locale, languages, defaultLanguage }, key, params);
return {
setLocale,
locale,
T: (key: Key, params?: TParams) => _tr(key, params),
TConcat: (key: Key | string, params?: TParams) => _tr(key as Key, params),
};
};
You now have two translation utilities: T
(will provide autocompletion and typescript errors), and TConcat
(name it whatever you want. It will allow template strings without providing auto-completion).
usage:
export default function App() {
const { T, TConcat, locale, setLocale } = useAutocompleteT();
return (
<>
<h1>{T("hello")}</h1>
<ul>
{["algebra", "geometry", "programming"].map((field) => {
return <li key={field}>{TConcat(`exercises.${field}`)}</li>;
})}
</ul>
</>
);
}
Option 2
Alternatively, you can mix Talkr's useT
and useAutocompleteT
hooks:
export default function App() {
const [count, setCount] = useState(0);
const { T: TConcat } = useT();
const { T, locale, setLocale } = useAutocompleteT();
return (
<>
<h1>{T("hello")}</h1>
<ul>
{["algebra", "geometry", "programming"].map((field) => {
return <li key={field}>{TConcat(`exercises.${field}`)}</li>;
})}
</ul>
</>
);
}
Thanks for your complete answer, I will go with option 1 👍
You could also cast the type of your dynamic key like this:
import { Key, useT } from "@i18n/useAutocompleteT" // export the type `Key` from your file
const getExerciseId = (exerciseId: string): Key => {
switch (exerciseId) {
case '1': return T('exercises.1');
default: break
}
}
(...)
{T(`exercises.${getExerciseId()}`)}
// or directly {T(`exercises.${getExerciseId() as Key}`)}
If you are using Talkr for a commercial product, feel free to sponsor it. I would put your company logo on NPM and on the repo.