N
Nuxt2y ago
mpgalaxy

i18n in modal (nuxt3)

Hi, can anyone tell me how I can add i18n support to modals in nuxt3 ? I can use i18n at the base site, but I need a scoped i18n in my modal which was working perfectly fine with the i18n module for nuxt2. How can I do this in nuxt3 ? I use the options api wrapped by defineNuxtComponent(...)
2 Replies
warflash
warflash2y ago
you might want to give a little more context and code for your issue. I don't see why handling a modal would in any way be different than any other component tbh
mpgalaxy
mpgalaxyOP2y ago
thats what I thought, too, but it seems to be or maybe it is a bug 😉 some more context: my issue is with oruga modal. I'm on nuxt3 calling my modal from javascript (options api) like this:
import TestModal from ...
// this is in methods:
viewModal() {
this.$oruga.modal.open({
fullScreen: false,
component: TestModal,
props: {},
hasModalCard: false,
fullScreen: false,
height: "95%",
width: "75%",
canCancel: ["x"],
});
}
import TestModal from ...
// this is in methods:
viewModal() {
this.$oruga.modal.open({
fullScreen: false,
component: TestModal,
props: {},
hasModalCard: false,
fullScreen: false,
height: "95%",
width: "75%",
canCancel: ["x"],
});
}
The TestModal is very basic and I want to provide i18n functionality (also options api), but when I add useI18n the modal doesn't show, it just shows a black overlay. Modal:
<i18n>
{
"us": {
"head_title": "Head title in local i18n",
"my_test": "My test in modal"
},
"de": {
"head_title": "Head Title",
"my_test": "Ein Test"
}
}
</i18n>

<template>
<div class="modal is-active">
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">
{{ t("my_test") }} ... {{ t("head_title") }}
</p>
<o-button outlined variant="danger" @click="$emit('close')">
{{ t("close") }}
</o-button>
</header>
<section class="modal-card-body">
<div>BODY</div>
<br /><br />
</section>
<footer class="modal-card-foot">
<div>FOOTER</div>
</footer>
</div>
</div>
</template>

<script>
export default defineNuxtComponent({
setup() {
const { t } = useI18n({
useScope: "local",
});
return { t }
},
props: {},
methods: {},
});
</script>
<i18n>
{
"us": {
"head_title": "Head title in local i18n",
"my_test": "My test in modal"
},
"de": {
"head_title": "Head Title",
"my_test": "Ein Test"
}
}
</i18n>

<template>
<div class="modal is-active">
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">
{{ t("my_test") }} ... {{ t("head_title") }}
</p>
<o-button outlined variant="danger" @click="$emit('close')">
{{ t("close") }}
</o-button>
</header>
<section class="modal-card-body">
<div>BODY</div>
<br /><br />
</section>
<footer class="modal-card-foot">
<div>FOOTER</div>
</footer>
</div>
</div>
</template>

<script>
export default defineNuxtComponent({
setup() {
const { t } = useI18n({
useScope: "local",
});
return { t }
},
props: {},
methods: {},
});
</script>
The browser debug gives me:
[Vue warn]: Component <Anonymous>: setup function returned a promise, but no <Suspense> boundary was found in the parent component tree. A component with async setup() must be nested in a <Suspense> in order to be rendered.
at <TestModal key=0 onClose=fn<bound close> >
at <BaseTransition onAfterEnter=fn<bound afterEnter> onBeforeLeave=fn<bound beforeLeave> appear=false ... >
at <Transition name="zoom-out" onAfterEnter=fn<bound afterEnter> onBeforeLeave=fn<bound beforeLeave> ... >
at <OModal programmatic= {instances: InstanceRegistry, resolve: ƒ, reject: ƒ} fullScreen=false component= {__nuxt_component: true, _fetchKeyBase: '$5ACFfSjzdh', __i18n: Array(1), __hmrId: '650f97d4', setup: ƒ, …} ... >
[Vue warn]: Component <Anonymous>: setup function returned a promise, but no <Suspense> boundary was found in the parent component tree. A component with async setup() must be nested in a <Suspense> in order to be rendered.
at <TestModal key=0 onClose=fn<bound close> >
at <BaseTransition onAfterEnter=fn<bound afterEnter> onBeforeLeave=fn<bound beforeLeave> appear=false ... >
at <Transition name="zoom-out" onAfterEnter=fn<bound afterEnter> onBeforeLeave=fn<bound beforeLeave> ... >
at <OModal programmatic= {instances: InstanceRegistry, resolve: ƒ, reject: ƒ} fullScreen=false component= {__nuxt_component: true, _fetchKeyBase: '$5ACFfSjzdh', __i18n: Array(1), __hmrId: '650f97d4', setup: ƒ, …} ... >
I have no async setup and since I call this modal from javascript I don't have <Suspense> tags is this a bug ? how can I call this modal from javascript without having it pre rendered and shown by condition ? If I use composition api like this
<script setup>
const { t } = useI18n({
useScope: "local",
});
</script>
<script setup>
const { t } = useI18n({
useScope: "local",
});
</script>
everything works fine, but I need the options api, switch to composition api is a no go (migrating a very huge project from nuxt2 to nuxt3 with many modals and lots of logic inside these modals) I found the mistake...unbelievable! 😛 There seems to be a problem with the defineNuxtComponent method as a wrapper for the options api, it mainly seems to be aimed at async data which causes my error. So instead of doing a
export default defineNuxtComponent({
setup() {
const { t } = useI18n({
useScope: "local",
});
return({ t });
},
components: {},
props: {},
methods: {},
});
export default defineNuxtComponent({
setup() {
const { t } = useI18n({
useScope: "local",
});
return({ t });
},
components: {},
props: {},
methods: {},
});
you can use the native vue function defineComponent
export default defineComponent({
setup() {
const { t } = useI18n({
useScope: "local",
});
return({ t });
},
components: {},
props: {},
methods: {},
});
export default defineComponent({
setup() {
const { t } = useI18n({
useScope: "local",
});
return({ t });
},
components: {},
props: {},
methods: {},
});
and the modal works perfectly fine...omg! 😉

Did you find this page helpful?