vue-i18n icon indicating copy to clipboard operation
vue-i18n copied to clipboard

function "t" not reactive inside ref object

Open leonardospeca opened this issue 1 year ago • 12 comments

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

leonardospeca avatar May 09 '23 08:05 leonardospeca

This is why issue #536 is not the solution

leonardospeca avatar May 09 '23 09:05 leonardospeca

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'
})

MinatoHikari avatar Jul 13 '23 08:07 MinatoHikari

Yes I understand. So in your opinion, which one could be a valid solution to this scenario?

leonardospeca avatar Jul 13 '23 09:07 leonardospeca

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
}));

MinatoHikari avatar Jul 13 '23 09:07 MinatoHikari

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>

Myshkouski avatar Jul 26 '23 09:07 Myshkouski

reactive unwraps ref and computed. You can do something like:

const button = reactive({
  width: 100,
  height: 200,
  label: computed(() => t('submit'))
})

Maiquu avatar Sep 12 '23 17:09 Maiquu

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

leonardospeca avatar Sep 18 '23 09:09 leonardospeca

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>.

MinatoHikari avatar Sep 18 '23 09:09 MinatoHikari