Nuxt i18n Types
24 okt 2024
Om volledige type-safety te garanderen en de ontwikkelervaring met Nuxt modules te verbeteren, heb ik een module ontwikkeld die automatisch types genereert voor @nuxtjs/i18n.
      const logger = useLogger("i18n-types");
const resolver = createResolver(import.meta.url);
export default defineNuxtModule({
  meta: {
    name: "i18n-types",
  },
  async setup(options, nuxt) {
    const locales = nuxt.options.i18n?.locales ?? [];
    const langDir = nuxt.options.i18n?.langDir ?? "lang";
    nuxt.hook("builder:watch", (event, path) => {
      if (path.includes(`app/${langDir}`)) {
        updateTemplates({
          filter: (t) => t.filename === "types/i18n-types.d.ts",
        });
      }
    });
    addTypeTemplate({
      filename: "types/i18n-types.d.ts",
      getContents() {
        const t0 = performance.now();
        const messages = locales.map((locale) => {
          const code = typeof locale === "string" ? locale : locale.code;
          const file = resolver.resolve(`../app/${langDir}/${code}.json`);
          const content = readFileSync(file, "utf-8");
          return JSON.parse(content);
        });
        const ids = intersection(messages.map(Object.keys));
        const template = dedent`
          import { DefineLocaleMessage } from "vue-i18n";
          declare module 'vue-i18n' {
            export type MessageId = 
              | ${ids.map((id) => `"${id}"`).join("\n    | ")};
    
            interface DefineLocaleMessage {
              ${ids.map((id) => `"${id}": string`).join("\n")}
            }
          }`;
        const t1 = performance.now();
        logger.success(`I18n types generated in ${Math.round(t1 - t0)}ms`);
        return template;
      },
    });
  },
});
function intersection(arrays: string[][]) {
  return arrays.reduce((a, b) => a.filter((c) => b.includes(c)));
}