vue-i18n
vue-i18n copied to clipboard
TypeError: _normalize is not a function
Reporting a bug?
I'm migrating a Vue2 project from Webpack to Vite. We have been using vue-i18n extensively. We have a special folder structure, so after importing all translation files as modules with Vite's globEager, I am creating a messages object that should be used throughout the app (and it is the same structure that we have successfully used w/ Webpack). However, the translation strings in my object come back as a function, such as:
title: (ctx) => {const { normalize: _normalize } = ctx;return _normalize(["My Translated Title"])}
When I'm trying to use i18n in a component, I get the below message:
TypeError: _normalize is not a function
(and my component won't render).
Expected behavior
The above error message should not happen, component with vue-i18n based translation should render seamlessly.
Reproduction
Here's a link to a minimal reproducible example in codesandbox: https://codesandbox.io/s/mre-vue-i18n-normalize-is-not-a-function-duuxwt
i18n.js:
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import messages from '@intlify/vite-plugin-vue-i18n/messages'
//...
export default new VueI18n({
locale: import.meta.VITE_I18N_LOCALE || locale,
fallbackLocale: import.meta.VITE_I18N_FALLBACK_LOCALE || locale,
messages: getLocaleMessages() // this returns custom messages object
})
vite.config.js
import { defineConfig } from 'vite'
import { createVuePlugin as vue } from "vite-plugin-vue2"
import vueI18n from '@intlify/vite-plugin-vue-i18n'
import path from "path";
export default defineConfig({
define: {
'process.env': {}
},
plugins: [
vue(),
vueI18n({
compositionOnly: false, // set this to false to use Vue I18n Legacy API
include: path.resolve(__dirname, './src/locales/**')
})
],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src")
}
}
})
System Info
System:
OS: Windows 10 10.0.19044
CPU: (8) x64 Intel(R) Core(TM) i5-8265U CPU @ 1.60GHz
Memory: 2.28 GB / 15.77 GB
Binaries:
Node: 12.14.1 - C:\Program Files\nodejs\node.EXE
npm: 6.13.4 - C:\Program Files\nodejs\npm.CMD
Browsers:
Chrome: 100.0.4896.127
Edge: Spartan (44.19041.1266.0), Chromium (100.0.1185.44)
Internet Explorer: 11.0.19041.1566
Screenshot
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 Discussion
- [X] The provided reproduction is a minimal reproducible example of the bug.
EDIT: I added a link to a minimal reproducible example.
Hi, I have the exact same issue, any news?
You need to add vue-i18n-bridge package in your project. see the details: https://vue-i18n.intlify.dev/guide/migration/vue2.html#usage
If you do use it, note that there are some limitations.
vue-i18n-bridge has limitations: https://vue-i18n.intlify.dev/guide/migration/vue2.html#limitations
I've been experiencing this exact issue today, and took the above sandbox and added vue-i18n-bridge
following the instructions, and I still see the same error message...
Here's the updated sandbox:
https://codesandbox.io/s/mre-vue-i18n-normalize-is-not-a-function-forked-guqn1s
I've been experiencing this exact issue today, and took the above sandbox and added
vue-i18n-bridge
following the instructions, and I still see the same error message...Here's the updated sandbox:
https://codesandbox.io/s/mre-vue-i18n-normalize-is-not-a-function-forked-guqn1s
Exactly, I've also tried using vue-i18n-bridge
as per Kazupon's suggestion, but it unfortunately didn't solve the issue in my case either.
Ok, I managed to bypass this completely... my issue was that the our translations are on yaml files, so once I used a yaml transformer (even removed @intlify/vite-plugin-vue-i18n completely!), all issues were gone and everything started to work as expected!
Really important to say that adding that configuration of vue-i18n
to vite.config.js
doesn't solves this problem.
I'm also migrating a vue 2.7
app from webpack
to vite
.
I Have been stuck on this error for hours 😕. Any update? I followed the migration guide without success.
I'm still getting TypeError: _normalize is not a function
After we run npm run build
, this is very problematic.
I'm not sure if I'm not importing my messages correctly, but why are all of them functions? If I have this structure:
{
"en-EN": {
"test": "this is a test"
}
}
the return of importedTest['en-EN'].test
is not this is a test
. It is actually e=>{const{normalize:n}=e;return n(["this is a test])}
. Why this occurs? Am I doing something wrong?
Edit: here is an image of one of my imported JSON:
Nuxt3 with some trick nice work...
<!-- <i18n src="./menu.json"></i18n> -->
<i18n lang="json">
{
"id": {
"name": "Pertama",
"sub": [
{
"one": "Satu"
}
]
},
"en": {
"name": "2nd",
"sub": [
{
"one": "One"
}
]
}
}
</i18n>
<script setup lang="ts">
const { locale, t, getLocaleMessage } = useI18n()
const menu = getLocaleMessage(unref(locale))
function normalize([v]: string[]) {
return v
}
</script>
<template>
<div>
<div>
{{ t('name') }}
</div>
<div v-for="(item, i) in menu.sub" :key="i">
Sub: {{ item.one({ normalize }) }}
</div>
</div>
</template>
Nuxt3 with some trick nice work...
<!-- <i18n src="./menu.json"></i18n> --> <i18n lang="json"> { "id": { "name": "Pertama", "sub": [ { "one": "Satu" } ] }, "en": { "name": "2nd", "sub": [ { "one": "One" } ] } } </i18n> <script setup lang="ts"> const { locale, t, getLocaleMessage } = useI18n() const menu = getLocaleMessage(unref(locale)) function normalize([v]: string[]) { return v } </script> <template> <div> <div> {{ t('name') }} </div> <div v-for="(item, i) in menu.sub" :key="i"> Sub: {{ item.one({ normalize }) }} </div> </div> </template>
Use .js file instead of json, then getLocaleMessage
should works fine
Any update on this? Is there a solution to the problem?
I'm facing the same error (vue 2.7 migrating to vite)
None of the solutions here really solve my problem. Is this still being worked on?
@gazben @spectrachrome Please check this issue
I found a temporary hack to get around it, hoping for it to get solved one day
Facing same issue while migrating vite with Vue 2.7. :(
I found a hack to workaround this problem in vue 2.7. I'm using import.meta.glob()
to import my .js localization files. They export default an object containing all my translation messages. So they look like this:
export default {
ok: 'Ok',
....
};
This is how I import my localization .js files:
async function loadLocale(locale) {
let modules;
let resp = {};
if (locale === 'de') {
modules = import.meta.glob('../locales/de.js');
} else {
modules = import.meta.glob('../locales/en.js');
}
await modules[Object.keys(modules)[0]]().then((mod) => {
// console.log(Object.keys(modules)[0], mod.default);
resp = mod.default;
});
applySourcesHack(resp);
return resp;
}
Before applying the locale(s) to i18n, I have to apply the hack. The problem is, that some keys contain functions instead of strings. This is the hack:
function applySourcesHack(obj) {
const getSource = (func) => {
if (typeof func === 'function') {
return '' + func.source;
}
return 'not a function';
};
if (typeof obj === 'object') {
Object.keys(obj).forEach((key) => {
if (typeof obj[key] === 'object') {
applySourcesHack(obj[key]);
} else {
obj[key] = getSource(obj[key]);
}
});
}
}
I also had to use this bundler for the vite bridge:
vite.config.js
...
resolve: {
alias: {
'vue-i18n-bridge': 'vue-i18n-bridge/dist/vue-i18n-bridge.esm-bundler.js',
},
},
Hope this will help someone :)
Note: I'm only using vue 2.7 as an intermediate step to upgrade to vue 3.x so I'm fine with using hacks like this.
Ran into this today. We were trying to integrate a Vue3 web component (our component, running Vue3 with i18n) into a Magento store (running Vue Storefront with i18n). It seems that something in the Magento/Vue codebase is messing with the message compilation of our component.
A work around that we have now is to enable the JIT compilation, which forces a different message compiler and works. You can do this by setting the global __INTLIFY_JIT_COMPILATION__
flag to true before loading your code.