Использовать переводы на основе компонентов в дочерних компонентах в vue-i18n

#vue.js #vue-i18n

#vue.js #vue-i18n

Вопрос:

Я использую vue-i18n для перевода сообщений в моем приложении vue. У меня есть несколько глобальных переводов, которые добавлены в new VueI18n(...) , а также некоторые переводы на основе компонентов в компоненте с именем c-parent . Компонент содержит дочерние компоненты с именами c-child . Теперь я хотел бы использовать переводы на основе компонентов c-parent также в c-child .

Я привел небольшой пример в этом скрипте:https://jsfiddle.net/d80o7mpL /

Проблема в последней строке выходных данных: сообщение в c-child не переведено с использованием переводов на основе компонентов c-parent .

Поскольку глобальные переводы «наследуются» всеми компонентами, я бы ожидал того же от переводов на основе компонентов (в их соответствующем поддереве компонентов). Есть ли способ добиться этого в vue-i18n?

Ответ №1:

Ну, вам нужно передать текст дочернему компоненту, используя props.

Глобальные переводы «наследуются» всеми компонентами. Но вы используете локальный перевод в дочерних компонентах.

 const globalMessages = {
  en: { global: { title: 'Vue i18n: usage of component based translations' } }
}

const componentLocalMessages = {
	en: { local: {
    title: "I'm a translated title",
    text: "I'm a translated text"
  }}
}

Vue.component('c-parent', {
	i18n: {
  	messages: componentLocalMessages
  },
	template: `
    <div>
      <div>c-parent component based translation: {{ $t('local.title') }}</div>
      <c-child :text="$t('local.title')"></c-child>
    </div>
  `
})

Vue.component('c-child', {
  props: ['text'],
	template: `
		<div>c-child translation: {{ text }}</div>
	`
})

Vue.component('app', {
	template: '<c-parent />'
})

const i18n = new VueI18n({
	locale: 'en',
  messages: globalMessages
})

new Vue({
  i18n,
  el: "#app",
})  
 body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
}

h5 {
  margin: 1em 0 .5em 0;
}  
 <script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/vue-i18n"></script>

<div id="app">
  <h2>{{ $t('global.title') }}</h2>
  We define two Vue components: <code>amp;<c-child/amp;></code> contained in <code>amp;<c-parent/amp;></code>.
  <code>amp;<c-parent/amp;></code> defines some component based translations. We would like to use the
  parent's translations in the child but it does not work.
  
  <h5>Example:</h5>
  <app />
</div>  

Комментарии:

1. Это решение, но, боюсь, оно недостаточно хорошо масштабируется для более чем нескольких сообщений. Спасибо, что ответили так быстро!

2. Я думаю, чтобы хорошо масштабировать его, вы можете определить язык на корневом уровне и определить данные компонента сами по себе.

3. Ну, вы можете передавать несколько сообщений с объектом.

4. Я использую это в более крупном SPA, где каждая страница является компонентом верхнего уровня. Я надеялся, что смогу получить все переводы для страницы в этом компоненте верхнего уровня и использовать их во всех дочерних компонентах, составляющих страницу, без необходимости передавать переводы на несколько уровней ниже.

5. Что ж, в этом случае вы можете передать его как объект соответствующим дочерним элементам вместо того, чтобы передавать его отдельно. Я надеюсь, что это поможет вам принять ответ.

Ответ №2:

Что я делаю, так это использую i18n.mergeLocaleMessage в router.ts для объединения определенного .i18n.json файла перевода (путем установки meta.i18n свойства) для каждого маршрута:

 const router = new Router({
[...]
    {
      path: '/settings',
      name: 'settings',
      component: () => import('./views/Settings.vue'),
      meta: {
        i18n: require('./views/Settings.i18n.json'),
      },
    },
[...]
});

router.beforeEach((to, from, next) => {
    // load view-scoped translations?
    if (!!to.meta.i18n) {
      Object.keys(to.meta.i18n).forEach((lang) => i18n.mergeLocaleMessage(lang, to.meta.i18n[lang]));
    }
    next();
});
  

С Settings.i18n.json быть похожим:

 {
    "en": 
    {
        "Key": "Key"    
    },
    "es": 
    {
        "Key": "Clave"    
    }
}
  

Таким образом, все дочерние компоненты будут использовать один и тот же файл перевода.

В случае, если вы не можете использовать vue-router, возможно, вы можете сделать это с помощью хука родительского компонента mounted() (еще не пробовал)

Ответ №3:

У меня была такая же ситуация с i18n.

Допустим, у нас есть объект «card» prop, который включает в себя необходимый язык (был моим случаем), который мы будем использовать в компоненте CardModal.vue, который будет родительским. Итак, что я сделал, так это получил необходимый файл locale json (основанный на языке prop) и добавил эти сообщения в prop card.

Итак, в родительском компоненте мы будем иметь:

 <template>
  <div id="card-modal">
    <h1> {{ card.locales.title }} </h1>
    <ChildComponent card="card" />
  </div>
</template>

<script>
export default {
  name: 'CardModal',
  
  props: {

   card: {
    type: Object,
    required: true,
    }

  }

  data() {
    return {
      locale: this.card.language, //'en' or 'es'
      i18n: {
        en: require('@/locales/en'),
        es: require('@/locales/es'),
      },
    }
  },

  created() {
   this.card.locales = this.i18n[this.locale].card_modal
  }

}
</script>

  

Обратите внимание, что мы больше не полагаемся на функцию плагина ( $ t()), и мы только меняем локаль в текущем компоненте. Я сделал это таким образом, потому что я не хотел использовать тег «i18n» в каждом дочернем компоненте и хотел сохранить все сообщения о локали в одном файле json для каждого языка. Я уже использовал card prop во всех дочерних компонентах, поэтому я добавил локали к этому объекту.

Если вам нужен способ изменить языковой стандарт с помощью тега select в компоненте, мы можем использовать средство просмотра для свойства locale data, как показано в документах