i18next / i18next-vue

Internationalization for Vue 2 & 3 using the i18next ecosystem
https://i18next.github.io/i18next-vue/
MIT License
74 stars 8 forks source link

importing i18next-vue breaks type checking a basic nuxt app #12

Closed WickyNilliams closed 1 year ago

WickyNilliams commented 1 year ago

🐛 Bug Report

In a fresh nuxt 3 app, if you add a util function, and import i18next-vue in a component, then type checking breaks for the util function.

It's possible this is more of a nuxt issue, but i thought i would report it here first since adding/removing this specific import causes/fixes the issue.

To Reproduce

Here's a minimal reproduction: https://stackblitz.com/edit/github-zn8swb?file=package.json&terminal=typecheck

If you run npm run typecheck in the stackblitz console, you will get errors. If you comment out the import of i18next-vue then typechecking passes.

Expected behavior

Should not cause typescript issues

Your Environment

kkuegler commented 1 year ago

This seems to be related to i18next-vue providing the global $t and $i18next properties in Vue templates. We do this by augmenting Vue's ComponentCustomProperties like so:

declare module 'vue' {
    interface ComponentCustomProperties {
        $t: TFunction;
        $i18next: i18n;
    }
}

Nuxt uses the same type to expose the utility functions.

When you remove that definition from i18next-vue's index.d.ts (or just rename ComponentCustomProperties to something else), your test case will work.

The test case still fails, if you replace the complete content of i18next-vue's index.d.ts with a very simple

declare module 'vue' {
    interface ComponentCustomProperties {
        $t: Function;
    }
}
export function useTranslation(): any;

One could assume that something is wrong with the declaration, but it follows Vue's docs and it also works if imported in a .ts file, as you can see in the forked version at https://stackblitz.com/edit/github-zn8swb-jecevj?file=utils/test.ts

Hovering over test1 and test2 in utils/test.ts you can see, that both the capitalize and the $t definitions have been nicely merged and can be used.

However, if you add one of the 'i18next-vue' imports in app.vue again, the types break the Vue template.

Re-exporting useTranslation from test.ts works and it is automatically available in the Vue template. So this seems like a nice workaround for this problem. This way no 'i18next-vue' import is required in the template.

Unfortunately I have no idea, what type magic happens in Nuxt Vue templates, so I think we would need Nuxt developers to understand what is going on with the imports in the Vue file. As there is an easy workaround, I think we can also live with the current situation.

WickyNilliams commented 1 year ago

@kkuegler thanks for reporting back. perhaps i will raise an issue with in the nuxt repo linking through to this.

for now the workaround is doing just fine.

slight tangent: is there some reason the t() function returned from useTranslation is type SimpleTFunction instead of TFunction? i've patched this in my app to provide better types, but wondering if i'm going to run into issues with that

kkuegler commented 1 year ago

The returned t() from useTranslation internally is a TFunction when you use it in a Composition API component. So it is totally fine to patch that to actually have that type.

I initially exposed this as SimpleTFunction through useTranslation, because it was quite unclear what options useTranslation should have in the future and how that would affect the returned t(). So I went with this simpler type.

With the namespace and TS-suggestion support of #4 I'll change the type to actually be TFunction. As the i18next types - especially TFunction - are still in quite a flux, I have no clear time-frame when I'll fix #4 and publish this. This will probably be a new major version, as this change might break the types of existing users.

kkuegler commented 1 year ago

Closing this for now, as it seems we did look at all we could from the i18next-vue side.