Closed2

i18nextのキーを型づけしたい

8686

Template string typesでやってみた

import { useTranslation as useI18NextTranslation } from 'react-i18next';

// ローカライズデータのJSON
import srcLang from '../locales/en';

// JSONからキーを再帰的に抽出。ネストされる度に"."で連結
type KeyPath<T> = keyof {
  [P in keyof T & string as T[P] extends string
    ? P
    : KeyPath<T[P]> extends string
    ? `${P}.${KeyPath<T[P]>}`
    : never]: T[P];
};

// 上とほぼ同じことをやるけど、トップレベルのキーは名前空間として":"で連結する必要があるので..
type KeyPathWithNameSpace<T> = keyof {
  [P in keyof T & string as T[P] extends string
    ? P
    : KeyPath<T[P]> extends string
    ? `${P}:${KeyPath<T[P]>}`
    : never]: T[P];
};

// 最終結果 => 例: "common:aaa.bbv.ccc | page1:eee.fff | page2:gg.ee"
type LocalizationKey = KeyPathWithNameSpace<typeof srcLang>;

// react-i18nextのラッパー。上で作成した LocalizationKey のみを受け付ける
export function useTranslation() {
  const nameSpaces = Object.keys(srcLang);
  const { t, ...rest } = useI18NextTranslation(nameSpaces);
  const typedT = (key: LocalizationKey, defaultValue?: Parameters<typeof t>[1], options?: Parameters<typeof t>[2]) =>
    t(key, defaultValue, options);
  return {
    t: typedT,
    ...rest
  };
}

もっとよいやり型あるかなー 🤔

このスクラップは2023/02/08にクローズされました