How to use Vue i18n translation in .js file? - javascript

I'm working on VueCLI. I've created .js file that contains rules for inputs:
import Vue from 'vue'
export const $t = (sign) => Vue.prototype.$t(sign)
function checkMail(email) {
const re = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ // eslint-disable-line no-eval
return re.test(String(email).toLowerCase())
}
const rules = {
gdprRequired: (v) => !!v || $t('registerPage.gdprNotChecked'),
emailRules: [(v) => checkMail(v) || $t('registerPage.wrongMail')],
}
export default rules
I want to declare rules in external js file and then import it in other vue files. When I do this rule check value properly, but It don't show translated error messeage. I tried export const $t = (sign) => Vue.prototype.$t(sign), bcs similar code worked for nuxt, but here, in VueCLI I got error:
vue.runtime.esm.js?2b0e:619 [Vue warn]: Error in beforeMount hook: "ReferenceError: $t is not defined"
found in
---> <VTextField>
<VForm>
<Register>
<VMain>
<VApp>
<Session> at src/layouts/Session/Session.vue
<App> at src/App.vue
<Root>
and this:
vue.runtime.esm.js?2b0e:1888 ReferenceError: $t is not defined
at rules.emailRules (rules.js?d86d:21)
at VueComponent.validate (index.ts?91bf:254)
at VueComponent.beforeMount (index.ts?91bf:217)
at invokeWithErrorHandling (vue.runtime.esm.js?2b0e:1854)
at callHook (vue.runtime.esm.js?2b0e:4219)
at mountComponent (vue.runtime.esm.js?2b0e:4043)
at VueComponent.Vue.$mount (vue.runtime.esm.js?2b0e:8415)
at init (vue.runtime.esm.js?2b0e:3118)
at createComponent (vue.runtime.esm.js?2b0e:5978)
at createElm (vue.runtime.esm.js?2b0e:5925)
Here importing code in 'register.vue':
import rulesConstant from "#/constants/rules";
Computing exported rules to vue variable:
computed: {
rules() {
return rulesConstant;
},
},
Example use:
<v-checkbox
class="custom-checkbox"
:rules="[rules.gdprRequired]"
v-model="gdprCheck"
></v-checkbox>
Can You help me?

Most common way of using vue-i18n outside of Vue components is by importing the singleton instance of VueI18n class and using it directly:
#/i18n/index.js
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import locales from './locales'
Vue.use(VueI18n);
export default new VueI18n({
locale: 'en',
messages: locales,
});
#/constants/rules
import i18n from '#/i18n/index.js'
const rules = {
gdprRequired: (v) => !!v || i18n.t('registerPage.gdprNotChecked'),
emailRules: [(v) => checkMail(v) || i18n.t('registerPage.wrongMail')],
}
export default rules
This way you have all the instance methods at your disposal, not just t

Related

laravel-vue-pagination module not loading in app

After loading in the laravel-vue-pagination module, I added it to app.js and tried to use it. I was able to import the component and export as props with no issue, but using the element gives me this error:
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading '_c')
I also get a Vetur message in my app.js on hover.
Could not find a declaration file for module 'laravel-vue-pagination'. 'e:/Dev/repos/itgg-core/node_modules/laravel-vue-pagination/dist/laravel-vue-pagination.common.js' implicitly has an 'any' type.
Try `npm i --save-dev #types/laravel-vue-pagination` if it exists or add a new declaration (.d.ts) file containing `declare module 'laravel-vue-pagination';`Vetur(7016)
According to this, I added a laravel-vue-pagination.d.ts file at the root of my project:
declare module 'laravel-vue-pagination' { }
This doesn't seem to help in any way though.
app.js :
require('./bootstrap');
// Import modules...
import { createApp, h } from 'vue';
import { App as InertiaApp, plugin as InertiaPlugin } from '#inertiajs/inertia-vue3';
import { InertiaProgress } from '#inertiajs/progress';
const el = document.getElementById('app');
createApp({
render: () =>
h(InertiaApp, {
initialPage: JSON.parse(el.dataset.page),
resolveComponent: (name) => require(`./Pages/${name}`).default,
}),
})
.mixin({ methods: { route } })
.use(InertiaPlugin)
.mount(el);
InertiaProgress.init({ color: '#4B5563' });
require('chart.js');
require('laravel-vue-pagination');
I assume something is wrong with the require, or loading the module, but I am not sure. Any help is greatly appreciated.

Vue 3: Add global method via Plugin not working

I'm trying to build a method that can be used inside any template to automatically build local image urls.
The issue I'm facing is that when I try to build a plugin that adds a global property, it's not working!
Plugin code
// src/plugins/urlbuilder.js
export default {
install: (app) => {
app.config.globalProperties.buildImageUrl = imageName => require('#/assets/images/' + imageName);
}
}
Main.js file
// src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import urlbuilder from './plugins/urlbuilder.js'
createApp(App).use(router).use(urlbuilder).mount('#app')
Home view where I render the image
// src/views/Home.vue
<template>
<img :src="buildImageUrl('myimage.jpg')">
</template>
and I'm getting this error in my the dev console:
Uncaught (in promise) TypeError: _ctx.buildImageUrl is not a function
at Proxy.render (cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/vue-loader-v16/dist/templateLoader.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader-v16/dist/index.js?!./src/views/Home.vue?vue&type=template&id=fae5bece&scoped=true:57)
at renderComponentRoot (runtime-core.esm-bundler.js:922)
at ReactiveEffect.componentUpdateFn [as fn] (runtime-core.esm-bundler.js:4667)
at ReactiveEffect.run (reactivity.esm-bundler.js:195)
at setupRenderEffect (runtime-core.esm-bundler.js:4793)
at mountComponent (runtime-core.esm-bundler.js:4576)
at processComponent (runtime-core.esm-bundler.js:4534)
at patch (runtime-core.esm-bundler.js:4138)
at ReactiveEffect.componentUpdateFn [as fn] (runtime-core.esm-bundler.js:4744)
at ReactiveEffect.run (reactivity.esm-bundler.js:195)
Note: This works when I add purely a global property, but I read the best way to do this was via plugin.
It works when I do this:
app = createApp(App)
app.config.globalProperties.buildImageUrl = imageName => require('#/assets/images/' + imageName)
app.use(router).mount('#app')
What am I doing wrong?
A better way would be to use provide and inject
import urlbuilder from './plugins/urlbuilder.js'
app.provide('$urlbuilder', urlbuilder);
Read more about provide and inject
You should get global properties by this:
const instance = getCurrentInstance()
const globalProperties = instance.appContext.config.globalProperties
console.log(globalProperties)
Recommand use provide and inject.
Or use a hook:
useGlobalProps.ts
import { getCurrentInstance } from 'vue'
import type { ComponentInternalInstance } from 'vue'
function useGlobalProps() {
const { appContext } = getCurrentInstance() as ComponentInternalInstance
const globalProps = appContext.config.globalProperties
return { ...globalProps }
}
export default useGlobalProps
use it in component:
import useGlobalProps from '#/hooks/useGlobalProps'
const { testFn, globalFn } = useGlobalProps()
testFn()
globalFn('global function in main.js')
Register globalFn in main.js
app.config.globalProperties.globalFn = function testGlobal(name: string) {
console.log(name)
}
Register testFn by plugin:
myPlugin.js
export default function (app: App<HTMLElement>) {
app.config.globalProperties.testFn = () => {
console.log('install global properties')
}
return app
}
use plugin in main.js
import myPlugin from './myPlugin.js'
// ...
app.use(myPlugin)

mochapack Cannot assign to read only property 'exports' of object

I would like to create a vuejs unit test for components.
I follow this official tutorial vuejs : Vuejs component unit test
I have created those file :
setup.js (main script for all test) :
require('jsdom-global')()
global.expect = require('expect')
// import jsdomGlobal from 'jsdom-global'
// export const jsdonGlobal = require('jsdom-global')
home.spec.js (unit test component file) :
import Vue from 'vue'
import { shallowMount } from '#vue/test-utils'
import Home from '../../src/page/Home.vue'
// import Home from '#/components/Home'
describe('Home.vue', () => {
it('test the test', async () => {
const wrapper = shallowMount(Home)
let divContainer = wrapper.find('div.container')
expect(divContainer.children()).to.have.length(12)
})
})
my babel.config.js :
module.exports = {
presets: [
'#vue/app',
'#babel/preset-env'
],
}
and this my 'npm run test' command :
"mochapack --webpack-config webpack.config.js --require test/setup.js test/**/*.spec.js"
All of this generate a 'Cannot assign to read only property 'exports' of object '#' error
others informations :
if a comment all line into setup.js and Home.spec.js file the behavior is identic (very strange behavior which difficult to understand where is the error)
I already try this preset Babel ('#babel/preset-env') for transpiling
I don't have a export instruction into my setup.js file and Home.spec.js file
Can you help me to understand why I have to error and how I can resolve this ?
The all others questions don't help me to resolve this because I don't have export instruction into my test code...

Error in Vue i18n with TypeScript: "Property '$t' does not exist on type 'VueConstructor'. " . How can I fix it?

In project some common function are in separate .ts files.
How can I use i18 in that cases:
// for i18n
import Vue from 'vue'
declare module 'vue/types/vue' {
interface VueConstructor {
$t: any
}
}
declare module 'vue/types/options' {
interface ComponentOptions<V extends Vue> {
t?: any
}
}
(()=>{
const test = Vue.$t('auth.title');
console.log( test )
})()
Return an error:
Property '$t' does not exist on type 'VueConstructor<Vue>"
How can I fix it?
we can achieve the same like below
Step 1: create a separate index.ts file inside a i18n folder (you can do it your own way - root level or any where in your app)
i18n/index.ts
import Vue from 'vue';
import VueI18n from 'vue-i18n';
// register i18n module
Vue.use(VueI18n);
const i18n = new VueI18n({
locale: 'nb-NO', //if you need get the browser language use following "window.navigator.language"
fallbackLocale: 'en',
messages: {en, no},
silentTranslationWarn: true
})
const translate = (key: string) => {
if (!key) {
return '';
}
return i18n.t(key);
};
export { i18n, translate}; //export above method
Step 2: make sure to use(import) above in main.ts
main.ts
import { i18n } from '#/i18n';
new Vue({ i18n, render: h => h(app) }).$mount('#app')
after above configuration we should be able to use translation in any place that we want in our application
Step 3: How to use it in .ts and .vue files
// first import it into the file
import { translate, i18n } from '#/i18n';
//this is how we can use translation inside a html if we need
<template>
<h1>{{'sample text' | translate}}</h1>
</template>
//this is how we can use translation inside a .ts or .vue files
<script lang='ts'>
//normal scenario
testFunc(){
let test = `${translate('sample text')}`;
console.log(test );
}
//in your case it should be like below
(()=>{
const test = `${translate('auth.title')}`;
console.log( test )
})()
</script>
I hope that this will help you to resolve your issue.

vue.runtime.common.js: "Cannot read property '_transitionClasses' of undefined" when this.errors is not used

I have this strange error when I'm running a test on a component that's using vee-validate. What's even weirder is that it doesn't happen when I actually use this.errors in that component (even putting console.log(this.errors) is making it disappear).
Test code:
import { mount } from '#vue/test-utils';
import { renderToString } from '#vue/server-test-utils';
import Vue from 'vue';
import VeeValidate from 'vee-validate';
import VeeValidateConfig from '#/vee-validate-config';
Vue.use(VeeValidate, VeeValidateConfig);
import FolderSelect from '#/components/FolderSelect';
describe('FolderSelect', () => {
let propsData, wrapperDeep;
beforeEach(() => {
wrapperDeep = mount(FolderSelect);
});
it('renders select box if option "existing folder" is selected', () => {
// this code is forcing component to use vee-validate:
wrapperDeep.setData({folder: 'existing'});
});
Output from yarn test:unit:
[Vue warn]: Error in directive validate bind hook:
"TypeError: Cannot read property '_transitionClasses' of undefined"
It's coming from node_modules/vue/dist/vue.runtime.common.js, line 1739 and 589.
After I add to tested component:
created () {
console.log(this.errors);
},
The error is gone! Why the error appears otherwise? Is Vue clearing vee-validate if it's not used? (this.errors is an ErrorBag added by vee-validate). Doesn't help if I add {{ errors }} to the template, though.
I'm injecting vee-validate like this:
export default {
inject: ['$validator'],
(...)
I had the same problem try adding {sync: false} after mounting the component
beforeEach(() => {
wrapperDeep = mount(FolderSelect,{sync: false});
});
This worked for me.
We hit this at work with #vue/test-utils#1.0.0-beta.25, and it got resolved by updating to #vue/test-utils#1.0.0-beta.29, without using sync: false.

Categories