jhipster / jhipster-lite

JHipster Lite ⚡ is a development platform to generate, develop & deploy modern web applications & microservices architecture, step by step - using Hexagonal Architecture :gem:
https://lite.jhipster.tech
Apache License 2.0
468 stars 215 forks source link

Vue internationalization choices? #11111

Open DamnClin opened 1 month ago

DamnClin commented 1 month ago

Playing with vue-i18next module I have some questions on the choices that were made:

I was expecting something to just drop json files somewhere in context to get translations for the context and I'm confused with the tradeoffs :D. cc @fabienpuissant

fabienpuissant commented 1 month ago

At first, I made a version with only multiple json files but the tradeoff doing that is you need to specify the namespace each time you want to translate (eg the name of the json file). https://www.i18next.com/principles/namespaces i18next.t('myKey', { ns: 'common' })

So after discussions with @Gnuk, we found that using namespace was too verbose.

Plus with typescript files, you declare you translation scoped to the context. You don't need to get the json file from the assets when you export the context.

Both solutions are working just need to decide the better for our needs.

DamnClin commented 1 month ago

At first, I made a version with only multiple json files but the tradeoff doing that is you need to specify the namespace each time you want to translate (eg the name of the json file). https://www.i18next.com/principles/namespaces i18next.t('myKey', { ns: 'common' })

So after discussions with @Gnuk, we found that using namespace was too verbose.

Plus with typescript files, you declare you translation scoped to the context. You don't need to get the json file from the assets when you export the context.

Both solutions are working just need to decide the better for our needs.

I think you can merge multiple json files without namespace

const I18N_ERROR = 'I18n Error'

type File = Record<string, unknown>
type Source = Record<string, unknown>
type Sources = Record<string, Source>

const sources: Sources = {
  en: import.meta.glob(['@/**/locales/**/*.i18n.en.json'], {
    eager: true,
    import: 'default',
  }),
  fr: import.meta.glob(['@/**/locales/**/*.i18n.fr.json'], {
    eager: true,
    import: 'default',
  }),
}

const messages = Object.keys(sources).reduce(
  (messages, locale: string) => ({
    ...messages,
    [locale]: Object.keys(sources[locale]).reduce((message, file: string) => {
      if (Object.prototype.toString.call(sources[locale][file]) !== '[object Object]') {
        throw new Error(`${I18N_ERROR} : "${file}" file must be an object`)
      }

      const current = sources[locale][file] as File

      Object.keys(current).forEach((key) => {
        if (Object.prototype.toString.call(current[key]) !== '[object Object]') {
          throw new Error(`${I18N_ERROR} : ${file} : "${key}" value must be an object`)
        }
      })

      return { ...((message as object) ?? {}), ...((current as object) ?? {}) }
    }, {}),
  }),
  {}
)
Gnuk commented 1 month ago

Yes, I think it's possible, maybe also using ts instead of JSON with something like import meta glob or async import.

I think that the first proposition used explicit import because the use case was without a lot of files to import.

I think there is an interesting idea with ts if we can be able to get type form a default translation file to force other translations to respect the type (using things like as const)