intlify / vue-i18n

Vue I18n for Vue 3
https://vue-i18n.intlify.dev/
MIT License
2.21k stars 336 forks source link

Resource Keys completion does not work with global messages and $t #1124

Open yannbriancon opened 2 years ago

yannbriancon commented 2 years ago

Reporting a bug?

When using global definitions and $t, key completion (and type checking) does not work.

Here is the declaration file I use:

import { DefineLocaleMessage } from 'vue-i18n'

declare module 'vue-i18n' {
    // define the locale messages schema
    export interface DefineLocaleMessage {
        test: string
    }
}

I set it up like this:

export const i18n = createI18n<false>({
    messages,
    numberFormats,
    legacy: false,
    locale: defaultLocale,
    fallbackLocale: defaultLocale
})

Then in a component I try to type in but nothing appears:

image

Expected behavior

Resource completion should work if I understood the doc correctly. Should type checking work too?

Reproduction

Enough information.

System Info

System:
    OS: macOS 12.4
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 16.13.1 - ~/.nvm/versions/node/v16.13.1/bin/node
    Yarn: 1.22.10 - /usr/local/bin/yarn
    npm: 8.1.2 - ~/.nvm/versions/node/v16.13.1/bin/npm
  Browsers:
    Chrome: 104.0.5112.79
    Firefox: 103.0.2
    Safari: 15.5
    Safari Technology Preview: 16.0
  npmPackages:
    @intlify/devtools-if: ^9.1.9 => 9.2.2 
    @intlify/vue-devtools: ^9.1.9 => 9.2.2 
    @vitejs/plugin-vue: ^1.9.4 => 1.9.4 
    vite: ^2.6.14 => 2.6.14 
    vue: ^3.2.22 => 3.2.22 
    vue-i18n: ^9.2.2 => 9.2.2 
    vue-tsc: ^0.29.5 => 0.29.5 

Screenshot

No response

Additional context

No response

Validations

kazupon commented 2 years ago

related #1113 #1025

The essential improvement is to use conditional exports or the volar plugin.

itpropro commented 1 year ago

Any updates on this @kazupon? Would really help the DX in nuxt-i18n :)

taras-turchenko-moc commented 6 months ago

Here is workaround to fix type autocomplete locally

// typing.d.ts

interface ITranslations {
  form: {
    labels: {
      email: string;
      password: string;
    };
    errors: {
      email: string;
      minLength: string;
      required: string;
    };
  };
  signIn: {
    heading: string;
    submit: string;
  };
}

type Primitive = string | number | bigint | boolean | undefined | symbol;

export type PropertyStringPath<T, Prefix = ''> = {
  [K in keyof T]: T[K] extends Primitive | Array<unknown>
    ? `${string & Prefix}${string & K}`
    : `${string & Prefix}${string & K}` | PropertyStringPath<T[K], `${string & Prefix}${string & K}.`>;
}[keyof T];

declare module 'vue-i18n' {
  export interface DefineLocaleMessage extends ITranslations {}
}

declare module '@vue/runtime-core' {
  import type { TranslateResult } from 'vue-i18n';

  export interface ComponentCustomProperties {
    $t<Key extends PropertyStringPath<ITranslations>>(key: Key): TranslateResult;
  }
}
itpropro commented 2 months ago

Here is workaround to fix type autocomplete locally

// typing.d.ts

interface ITranslations {
  form: {
    labels: {
      email: string;
      password: string;
    };
    errors: {
      email: string;
      minLength: string;
      required: string;
    };
  };
  signIn: {
    heading: string;
    submit: string;
  };
}

type Primitive = string | number | bigint | boolean | undefined | symbol;

export type PropertyStringPath<T, Prefix = ''> = {
  [K in keyof T]: T[K] extends Primitive | Array<unknown>
    ? `${string & Prefix}${string & K}`
    : `${string & Prefix}${string & K}` | PropertyStringPath<T[K], `${string & Prefix}${string & K}.`>;
}[keyof T];

declare module 'vue-i18n' {
  export interface DefineLocaleMessage extends ITranslations {}
}

declare module '@vue/runtime-core' {
  import type { TranslateResult } from 'vue-i18n';

  export interface ComponentCustomProperties {
    $t<Key extends PropertyStringPath<ITranslations>>(key: Key): TranslateResult;
  }
}

Thanks for that, I ended up doing exactly that just with a little bit less TS magic:

// types.d.ts

import {
  DefineLocaleMessage,
} from 'vue-i18n'
import type enUS from './locales/en-US.json'

type MessageSchema = typeof enUS

declare module 'vue-i18n' {
  export interface DefineLocaleMessage extends MessageSchema {}
}