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

Vue 2 compatible TranslationComponent not working as expected #19

Closed echjordan0 closed 12 months ago

echjordan0 commented 12 months ago

🐛 Bug Report

Thank you so much for the clear migration documentation it has mostly been a beeze to migrate from @panter/vue-i18next.

I've discovered a couple of slightly unexpected behaviors.

  1. I think the migration docs may need to be updated. According to the docs the <i18next> component is deprecated. However, it seems it was added in V1 here
  2. The TranslationComponent doesn't seem to be working as expected -- the child value isn't interpolated. This seemingly is because the translation prop enters the component's render function with the template values stripped (see screenshot) Screenshot 2023-10-19 at 7 06 08 PM

To Reproduce

This is a private repository so I unfortunately cannot provide a reproduction but below is my i18next config:

import i18next from 'i18next';
import I18NextVue from 'i18next-vue';
import Vue from 'vue';

import english from '../locales/en/translation.json';
import spanish from '../locales/es/translation.json';

i18next.init({
  lng: 'en',
  nsSeparator: false,
  keySeparator: false,
  fallbackLng: false,
  resources: {
    en: { translation: english },
    es: { translation: spanish },
  },
  interpolation: {
    prefix: '{',
    suffix: '}',
  },
});

Vue.use(I18NextVue, { i18next });

export function setDefaultInterpolationVariables(variables: { [key: string]: string }) {
  i18next.options.interpolation!.defaultVariables = variables;
}

Expected behavior

The following snippet

<i18next :translation="$t('Need help with {processor}?')">
     <template #processor>{{ processor }}</template>
</i18next>

with the follow es translation file key/value pair "Need help with {processor}?": "¿Necesita ayuda con {processor}?",

Should render as

Screenshot 2023-10-19 at 7 08 58 PM

Instead it renders as

Screenshot 2023-10-19 at 7 08 48 PM

Your Environment

kkuegler commented 12 months ago

I'm happy to hear you found the migration docs helpful 😄

re 1: The 1.x documentation was indeed not up to date regarding the translation component. I've changed that to match what we have in the 2.x documentation.

re 2:

Why it is not working

I believe this problem is related to the Interpolation configuration you use with single curly braces:

interpolation: {
  prefix: '{',
  suffix: '}',
},

This is different from the default double curly {{/}} values. The translation component (always) uses single curly braces as well. This interferes with your config, because i18next itself will already try and interpolate all placeholders:

In your example you pass the result of $t('Need help with {processor}?') as the :translate prop. As you saw when debugging, the $t call has replaced {processor} with nothing. This is because $t is the "ordinary" $t, which tries to interpolate all values, including {processor} with given replacements. As there is no replacement in the $t call itself, it is just removed. After that, there is no {processor} left in the translation that the translation component can replace.

With the default double curly braces configuration, $t would just get the translation, but leave the single curly placeholder {processor} alone, so the translation component can do the interpolation.

Solution(s)

There is no simple solution in version 1.1.0 for this, assuming you can't just switch to double curly braces for i18next's interpolation.

Since version 2.2 the Vue 3 version of i18next-vue supports configuring something else than single curly braces to find what to interpolate in the translation component, see https://github.com/i18next/i18next-vue#custom-slot-values. You could e.g. use "Need help with {processor}?": "¿Necesita ayuda con <slot>processor</slot>?", or another start/end pattern that makes sense for you.

This is also available on the special i18next-vue@vue-27-next version, see https://github.com/i18next/i18next-vue/tree/vue-27-next. This is a backport of i18next-vue 3.0 to Vue 2.7 and needs the same additional migration that would otherwise be necessary when switching from i18next-vue 2.x to 3.0, see https://i18next.github.io/i18next-vue/migration-v3.html.

If you are willing to that additional changes to use the @vue-27-next version, that's great. If you'd rather have 1.x version with just configurable start/end patterns for the translation component, let me know. This is not super easy to do, but I'd then try and selectively bring back that functionality to 1.x.

P.S. I assume the translation component example is simplified and in reality uses some HTML. Otherwise, you would not need <i18next> at all and could just let $t interpolate the plaintext processor value {{ $t('Need help with {processor}?', {processor}) }}.

echjordan0 commented 12 months ago

Thanks so much for getting back to me. I went with the approach of installing the i18next-vue@vue-27-next version and using the <slot></slot> custom slot values. This fixed the interpolation! However, it seemed to cause some of my component units tests began failing that don't use the i18next component but do use Vue slot syntax (<template #foo>). I don't have as much time as I'd like to debug and it's entirely possible it's something to do with our set up not the library. I have a working shim of the @panter component so I'm going to go ahead and use that pending our upgrade to Vue 3. Thanks again for your time and clear explanation of my options.

P.S. Yes! It was indeed a simplification for the sake of example -- thanks for the tip!