Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

PetroGromovo's avatar

How to make multi language editor dynamic list of language?

On vuejs3 site I need to make multi language editor where list of language can be changed and I load it server's side into locales var. But using Fields from vee-validate library in v-for :

    <div v-for="locale in locales" :key="locale.id"> <!-- description FIELD DEFINITION -->
      <div >
        <label class="col-form-label" for="description">Description<span >{{locale}}</span></label>
      </div>
      <div >
        <Field
            name="description"
            as="textarea"
            rows="8"
            class="form-control editable_field"
            v-model="formDescription[locale]">
        </Field>
        <ErrorMessage name="description" as="p" class="validation_error"/>
      </div>
    </div>

I got error :

runtime-core.esm-bundler.js?d2dd:40 [Vue warn]: Unhandled error during execution of render function
  at <Form onSubmit=fn<onSubmit> validation-schema= ObjectSchema {type: 'object', _whitelist: ReferenceSet(0), _blacklist: ReferenceSet(0), internalTests: {…}, _typeCheck: ƒ, …} class="bannerEdit" >
  at <BannerEditPage onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy {…} > >
  at <RouterView>
  at <App>
warn @ runtime-core.esm-bundler.js?d2dd:40
logError @ runtime-core.esm-bundler.js?d2dd:230
handleError @ runtime-core.esm-bundler.js?d2dd:222
renderComponentRoot @ runtime-core.esm-bundler.js?d2dd:943
componentUpdateFn @ runtime-core.esm-bundler.js?d2dd:5720
run @ reactivity.esm-bundler.js?89dc:190
instance.update @ runtime-core.esm-bundler.js?d2dd:5763
callWithErrorHandling @ runtime-core.esm-bundler.js?d2dd:173
flushJobs @ runtime-core.esm-bundler.js?d2dd:406
Promise.then (async)
queueFlush @ runtime-core.esm-bundler.js?d2dd:298
queueJob @ runtime-core.esm-bundler.js?d2dd:292
eval @ runtime-core.esm-bundler.js?d2dd:5761
triggerEffect @ reactivity.esm-bundler.js?89dc:400
triggerEffects @ reactivity.esm-bundler.js?89dc:390
triggerRefValue @ reactivity.esm-bundler.js?89dc:1021
set value @ reactivity.esm-bundler.js?89dc:1066
eval @ Banner.vue?d3f2:596
Promise.then (async)
loadBanner @ Banner.vue?d3f2:556
eval @ Banner.vue?d3f2:420
callWithErrorHandling @ runtime-core.esm-bundler.js?d2dd:173
callWithAsyncErrorHandling @ runtime-core.esm-bundler.js?d2dd:182
job @ runtime-core.esm-bundler.js?d2dd:1812
callWithErrorHandling @ runtime-core.esm-bundler.js?d2dd:173
flushJobs @ runtime-core.esm-bundler.js?d2dd:406
Promise.then (async)
queueFlush @ runtime-core.esm-bundler.js?d2dd:298
queueJob @ runtime-core.esm-bundler.js?d2dd:292
scheduler @ runtime-core.esm-bundler.js?d2dd:1845
triggerEffect @ reactivity.esm-bundler.js?89dc:400
triggerEffects @ reactivity.esm-bundler.js?89dc:390
trigger @ reactivity.esm-bundler.js?89dc:373
set @ reactivity.esm-bundler.js?89dc:675
emit @ eventBus.js?3195:7
eval @ commonFuncs.js?a7a0:100
Promise.then (async)
retrieveAppDictionaries @ commonFuncs.js?a7a0:31
bannerEditOnMounted @ Banner.vue?d3f2:379
eval @ runtime-core.esm-bundler.js?d2dd:2756
callWithErrorHandling @ runtime-core.esm-bundler.js?d2dd:173
callWithAsyncErrorHandling @ runtime-core.esm-bundler.js?d2dd:182
hook.__weh.hook.__weh @ runtime-core.esm-bundler.js?d2dd:2731
flushPostFlushCbs @ runtime-core.esm-bundler.js?d2dd:359
flushJobs @ runtime-core.esm-bundler.js?d2dd:413
Promise.then (async)
queueFlush @ runtime-core.esm-bundler.js?d2dd:298
queueJob @ runtime-core.esm-bundler.js?d2dd:292
eval @ runtime-core.esm-bundler.js?d2dd:5761
triggerEffect @ reactivity.esm-bundler.js?89dc:400
triggerEffects @ reactivity.esm-bundler.js?89dc:390
triggerRefValue @ reactivity.esm-bundler.js?89dc:1021
eval @ reactivity.esm-bundler.js?89dc:1158
triggerEffect @ reactivity.esm-bundler.js?89dc:400
triggerEffects @ reactivity.esm-bundler.js?89dc:385
triggerRefValue @ reactivity.esm-bundler.js?89dc:1021
eval @ reactivity.esm-bundler.js?89dc:1158
triggerEffect @ reactivity.esm-bundler.js?89dc:400
triggerEffects @ reactivity.esm-bundler.js?89dc:385
triggerRefValue @ reactivity.esm-bundler.js?89dc:1021
eval @ reactivity.esm-bundler.js?89dc:1158
triggerEffect @ reactivity.esm-bundler.js?89dc:400
triggerEffects @ reactivity.esm-bundler.js?89dc:385
triggerRefValue @ reactivity.esm-bundler.js?89dc:1021
eval @ reactivity.esm-bundler.js?89dc:1158
triggerEffect @ reactivity.esm-bundler.js?89dc:400
triggerEffects @ reactivity.esm-bundler.js?89dc:385
triggerRefValue @ reactivity.esm-bundler.js?89dc:1021
set value @ reactivity.esm-bundler.js?89dc:1066
finalizeNavigation @ vue-router.mjs?f169:3334
eval @ vue-router.mjs?f169:3207
Promise.then (async)
pushWithRedirect @ vue-router.mjs?f169:3173
push @ vue-router.mjs?f169:3099
install @ vue-router.mjs?f169:3530
use @ runtime-core.esm-bundler.js?d2dd:4399
eval @ main.js?fbea:27
./src/main.js @ app.js:151
__webpack_require__ @ app.js:758
(anonymous) @ app.js:1950
__webpack_require__.O @ app.js:807
(anonymous) @ app.js:1951
(anonymous) @ app.js:1953
runtime-core.esm-bundler.js?d2dd:40 [Vue warn]: Unhandled error during execution of scheduler flush. This is likely a Vue internals bug. Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/core
  at <Form onSubmit=fn<onSubmit> validation-schema= ObjectSchema {type: 'object', _whitelist: ReferenceSet(0), _blacklist: ReferenceSet(0), internalTests: {…}, _typeCheck: ƒ, …} class="bannerEdit" >
  at <BannerEditPage onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< Proxy {…} > >
  at <RouterView>
  at <App>

Looks like this error was raised by code :

v-model="formDescription[locale]"

But code :

v-model="formDescription"

works ok.

in which way multi language editor can be done here?

In package.json:

"core-js": "^3.8.3",
"vee-validate": "^4.7.4",
"vue": "^3.2.13",

Thanks in advance!

0 likes
1 reply
LaryAI's avatar
Level 58

The issue seems to be with the v-model binding on the Field component. Since v-model is a shorthand for :value and @input bindings, it expects the formDescription object to have a property with the same name as the name attribute of the Field component. In this case, the name attribute is hardcoded as "description", so the v-model binding will always update the formDescription.description property, regardless of the current locale.

To make the v-model binding dynamic based on the current locale, you can use computed properties to generate the name and v-model bindings for each Field component. Here's an example:

<template>
  <div v-for="locale in locales" :key="locale.id">
    <div>
      <label class="col-form-label" :for="`description_${locale}`">Description <span>{{ locale }}</span></label>
    </div>
    <div>
      <Field
        :name="`description_${locale}`"
        as="textarea"
        rows="8"
        class="form-control editable_field"
        :value="formDescription[locale]"
        @input="value => formDescription[locale] = value"
      />
      <ErrorMessage :name="`description_${locale}`" as="p" class="validation_error" />
    </div>
  </div>
</template>

<script>
import { defineComponent } from 'vue'
import { Field, ErrorMessage } from 'vee-validate'

export default defineComponent({
  components: { Field, ErrorMessage },
  data() {
    return {
      locales: [], // populate this from server-side data
      formDescription: {}, // initialize with empty object
    }
  },
  computed: {
    fieldNames() {
      // generate dynamic field names based on locales
      return this.locales.reduce((names, locale) => {
        names[`description_${locale}`] = { type: String }
        return names
      }, {})
    },
    fieldValues() {
      // generate dynamic v-model bindings based on locales
      return this.locales.reduce((values, locale) => {
        values[locale] = {
          get: () => this.formDescription[locale],
          set: value => (this.formDescription[locale] = value),
        }
        return values
      }, {})
    },
  },
  created() {
    // initialize formDescription with dynamic field names
    this.formDescription = this.$validator.defineValidationSchema(this.fieldNames)
  },
})
</script>

In this example, we use two computed properties to generate the dynamic field names and v-model bindings based on the locales array. The fieldNames computed property generates an object with keys like "description_en", "description_fr", etc., and values that define the data type of each field (in this case, all fields are strings). We pass this object to the defineValidationSchema method of the $validator instance (which is provided by the vee-validate plugin) to initialize the formDescription object.

The fieldValues computed property generates an object with keys like "en", "fr", etc., and values that are getter/setter functions that read/write the corresponding property of the formDescription object. We use these functions as the value and @input bindings of the Field component, instead of the formDescription object directly.

With these changes, the v-model binding should update the correct property of the formDescription object based on the current locale.

1 like

Please or to participate in this conversation.