vue-i18n
vue-i18n copied to clipboard
function "t" not reactive inside ref object
Reporting a bug?
<script setup>
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const columns = ref([
{ name: 'code', title: t('code') },
{ name: 'name', title: t('name') },
{ name: 'description', title: t('description') },
]);
</script>
<template>
<custom-table :columns="columns"/>
</template>
Using i18n in this way, when you change language dinamically, does not update the translation with the new language.
If you replace ref
with computed
it works, but it not have the same behavior, because in this case, if inside the custom-table
you want to make something like column.width = 200
you cannot cause is a computed and not a reactive
Expected behavior
When change locale text should change
Reproduction
<script setup>
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const columns = ref([
{ name: 'code', title: t('code') },
{ name: 'name', title: t('name') },
{ name: 'description', title: t('description') },
]);
</script>
<template>
<custom-table :columns="columns"/>
</template>
System Info
System:
OS: Linux 5.19 Ubuntu 22.04.1 LTS 22.04.1 LTS (Jammy Jellyfish)
CPU: (16) x64 AMD Ryzen 7 4800H with Radeon Graphics
Memory: 611.41 MB / 15.00 GB
Container: Yes
Shell: 5.1.16 - /bin/bash
Binaries:
Node: 16.13.2 - /usr/local/bin/node
npm: 9.6.3 - ~/.local/bin/npm
Browsers:
Chrome: 109.0.5414.74
Firefox: 112.0.2
Screenshot
No response
Additional context
No response
Validations
- [X] Read the Contributing Guidelines
- [X] Read the Documentation
- [X] Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
- [X] Check that this is a concrete bug. For Q&A open a GitHub Discussions
This is why issue #536 is not the solution
t is a function which returns a string. It will be called when you declaring the ref, not in render function of component. That's mean,
const msg = ref({
title: t('title')
})
is something like
const msg = ref({
title: 'a string'
})
Yes I understand. So in your opinion, which one could be a valid solution to this scenario?
Yes I understand. So in your opinion, which one could be a valid solution to this scenario?
const arr = ref([
{ name: 'code' },
{ name: 'name' },
{ name: 'description' },
])
const columns = computed(() => arr.value.map(i => {
i.title = t(i.name)
return i
}));
Try this workaround:
~/composables/useT.ts
:
import { UseI18nOptions } from 'vue-i18n'
export const useT = (key: string | number, options: UseI18nOptions = {}) => {
const { t, locale: localeRef } = useI18n(options)
return computed(() => {
// just to trigger reactivity
unref(localeRef)
return t(key)
})
}
~/components/MyComponent.vue
:
<template>
<div>
<span>{{ textRef }}</span>
</div>
</template>
<i18n lang="yaml">
ru:
lorem_ipsum: Что такое Lorem Ipsum?
en:
lorem_ipsum: What is Lorem Ipsum?
</i18n>
<script setup lang="ts">
import { useT } from '~/composables/useT'
const textRef = useT('lorem_ipsum', { useScope: 'local' })
</script>
reactive
unwraps ref
and computed
.
You can do something like:
const button = reactive({
width: 100,
height: 200,
label: computed(() => t('submit'))
})
Yes, effectively i was able to resolve doing so:
const columns = ref([
{ name: 'code', title: computed(_ => t('code')) },
{ name: 'name', title: computed(_ => t('name')) },
{ name: 'description', title: computed(_ => t('description')) },
]);
Are there any contraindications to doing this? If not, thanks everyone
Yes, effectively i was able to resolve doing so:
const columns = ref([ { name: 'code', title: computed(_ => t('code')) }, { name: 'name', title: computed(_ => t('name')) }, { name: 'description', title: computed(_ => t('description')) }, ]);
Are there any contraindications to doing this? If not, thanks everyone
when you changing the value of ref, you must fully use computed again
columns.value = [
{ name: 'code', title: computed(_ => t('code')) },
{ name: 'name', title: computed(_ => t('name')) },
{ name: 'description', title: computed(_ => t('description')) },
]
// wrong
columns.value = [
{ name: 'code', title: t('code')) },
{ name: 'name', title: t('name') },
{ name: 'description', title: t('description') },
]
And the title will be a readonly property, which is not so good that even with typescript you can only know title is a string not a Readonly<string>.