I have a problem with useI18n that I'm unable to solve. Whatever I do, I am unable to get i18n translation to work and in my console perpetually see this message:
Uncaught SyntaxError: Must be called at the top of a setup function
The stack-track reveals that it happens when invoking the useI18n() function despite it being within a function called setup. The next level up the stack trace reveals that within the ```useI18n()`` function that an exception is being raised due to it not detecting an instance of my app.
function useI18n(options = {}) {
const instance = getCurrentInstance();
if (instance == null) {
throw createI18nError(I18nErrorCodes.MUST_BE_CALL_SETUP_TOP);
}
...
My code is as follows:
main.js
// frontend/src/main.ts
import i18n from './i18n';
import Vue, { createApp } from 'vue';
import axios from 'axios';
import VueAxios from 'vue-axios';
import App from './App.vue';
//Vue.use(VueI18n);
const app = createApp(App);
app.use(VueAxios, axios, i18n);
app.provide('axios', app.config.globalProperties.axios);
app.mount('#i-english-editor');
console.log(app);
i18n.ts
import { createI18n } from "vue-i18n";
const i18n = createI18n({
legacy: false,
locale: "ja",
fallbackLocale: 'en',
globalInjection: true,
messages: {
en: {
message: {
language: "English",
greeting: "Hello !"
}
},
ar: {
message: {
language: "العربية",
greeting: "السلام عليكم"
}
},
es: {
message: {
language: "Español",
greeting: "Hola !"
}
}
}
});
export default i18n;
App.vue
<div>
{{ t('message.greeting') }}
</div>
...
<script lang="ts">
import {defineComponent, ref, inject} from "vue";
import { useI18n } from "vue-i18n";
export default defineComponent({
setup() {
const { t } = useI18n();
...
return {
...
{t},
}
}
});
</script>
As you can see, my code looks like the various examples online showing me how to get translations working. I've looked at various solutions and none of them are working for me. This includes trying an alternative method of setting globalInjection to true and using {{ $t('message.greeting') }} in a tag which reveals the error:
ctx.$t is not a function
I am literally at a dead end and can't figure out a solution that seems to work for most people. My version of Vue is Vue 3 and the version of i18n I'm using is vue-i18n#9.2.0-beta.36.
If anyone knows why this is happening to me but no-one else, I'd appreciate it if you have a solution.
UPDATE - I managed to solve it.
To start with, I got rid of the need to use the useI18n function and realised that $t was failing due to multiple imports within the same app.use(...) function.
I changed it to:
app.use(VueAxios, axios);
app.use(i18n as any);
app.use was throwing up loads more errors into the console as i18n wasn't an accepted type. To get around the issue, I found out from a solution from another post that adding as any to it is a way around this problem. As a result {{ $t(...) }} is now producing the desired result.
I am using react-i18next to have a multi lang app but I am not able to use constants when trying to build my vocabulary.
I am trying to export constants from a separate file and add these constants as keys in the language object on the translation (i18n) file. However, for some reason it does not let me do this and I get a compilation error.
It does not even recognize the other consts within the object. When I take it outside of the object, it works.
Is there a limitation I am not aware of?
Please see the en object in the index.js file as well as other relevant files:
Consts.js
import React from 'react'
export const Constants = {
USERNMAE : 'Username',
PASSWORD : 'Password',
LOGIN : 'Login',
}
index.js
import { initReactI18next } from "react-i18next";
import {Constants} from '../constants/Consts'
//Constants.USERNAME works perfectly fine here
const resources = {
en: {
translation: {
Constants.USERNAME: "Username", //doesn't work and doesn't recognize USERNAME at all
"Password":"Password",
"Login":"Login"
}
},
he: {
translation: {
"Username": "שם משתמש",
"Password": "סיסמא",
"Login": "התחבר"
}
}
};
i18n
.use(initReactI18next) // passes i18n down to react-i18next
.init({
resources,
lng: "he",
keySeparator: false, // we do not use keys in form messages.welcome
interpolation: {
escapeValue: false // react already safes from xss
}
});
export default i18n;
Nothing wrong with imports here, but you can't use object value as an object key in that way
Try out to use an object literal (surround by [] brackets)
const resources = {
en: {
translation: {
[Constants.USERNAME]: 'Username', // <---- now it works :)
Password: 'Password',
Login: 'Login',
},
},
he: {
translation: {
Username: 'שם משתמש',
Password: 'סיסמא',
Login: 'התחבר',
},
},
}
I can use $t in components:
:label="$t('sign-up.terms-label')"
and in javascript:
case 'email':
this.errors.push(this.$t('sign-up.email-exists')); break;
But I cannot use it in extend:
import { extend, localize, ValidationObserver } from 'vee-validate';
localize({
cs: {
names: {
email: $t('sign-up.email-label'),
EsLint says that the function is undefined.
I want to localize the field names for vee-validate as described here:
https://logaretm.github.io/vee-validate/guide/localization.html#using-the-default-i18n
I18N is defined this way:
Vue.use(VueI18n);
export default new VueI18n({
locale: process.env.VUE_APP_I18N_LOCALE || 'cs',
fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || 'cs',
messages: loadLocaleMessages(),
});
There's an error because $t isn't defined in this scope.
As the guide shows, $t should be referred as a method on vue-i18n instance outside Vue components.
If it's defined in another module, it should be imported from a module where vue-i18n instance was exported from:
import i18n from './i18n';
...
localize({
cs: {
names: {
email: i18n.$t('sign-up.email-label'),
...
You can call extend from the created() method, at which point you will have access to this.$t.
created() {
localize({
cs: {
names: {
email: this.$t('sign-up.email-label'),
//...
}
Actually, I am using react-test-render and jest for writing test cases in react-native? I have a component which I need to test and that component contains nested components which are connected component.
Below is the code which I have written to test the component:
import React from 'react';
import renderer from 'react-test-renderer';
import sinon from 'sinon';
import { clone } from 'lodash';
import { ProfileImageSelect } from
'../../../../components/settings/ProfileImageSelect';
const userInfo = {
first_name: 'test_first_name',
last_name: 'test_last_name'
};
describe('<ProfileImageSelect />', () => {
let onClose;
let onSelect;
let socialLogins;
beforeEach(() => {
socialLogins = {
facebook: {
id: '187416164',
identifier: 'adams_facebook',
full_name: 'Eric Adams',
profile_pic: 'profile_pic_facebook.jpeg',
expired: false
},
twitter: {
full_name: 'Eric Adams',
id: '187416164',
identifier: 'adams_ea',
profile_pic: 'https://pbs.twimg.com/profile_images/707586445427380226/5uETA8fs.jpg',
expired: false
},
linkedin: {
full_name: 'Eric Adams',
id: '8vN6Da_RJJ',
identifier: 'adams.ea#gmail.com',
profile_pic:
'https://media.licdn.com/dms/image/C5603AQFfn5Ko5IS1NQ/profile-displayphoto-shrink_100_100/0?e=1549497600&v=beta&t=11m5mirEr_R2gf3OOfh3zHTL3Xe2ImrxcZ7l7ebLDa0',
expired: false
}
};
onClose = sinon.stub();
onSelect = sinon.stub();
});
it('calls onClose on the props on click of cancel link ', () => {
const connected = clone(socialLogins, true);
const testRenderer = renderer.create(
<ProfileImageSelect
onSelect={onSelect}
onClose={onClose}
socialLogins={connected}
userInfo={userInfo}
/>
);
const root = testRenderer.root;
root.findByProps({ className: 'cancel' }).props.onPress();
expect(onClose.called).toEqual(true);
});
});
But it shows me an error saying :
Invariant Violation: Could not find "store" in either the context or props of "Connect(SocialServiceProfileImage)". Either wrap the root component in a , or explicitly pass "store" as a prop to "Connect(SocialServiceProfileImage)".
I know I can use 'react-test-renderer/shallow' for shallow render but it does not allow me to find any node from the DOM like Enzyme does.
Can anyone help me with this?. I do not have enzyme and neither I want to use to react-redux-mock-store.
You can define mock store manually and pass it as a prop to component. Unfortunately, it works only with specified component, if you want to go deeper, you have to use redux-mock-store or write your own context provider.
You can add an additional default export for
ProfileImageSelect (the class) that is not connected,
and import it as default:
import ProfileImageSelect from
'../../../../components/settings/ProfileImageSelect';
that way you are running a shallow unit test.
Other solutions will require you to provide some sort of store/mock-store since they are integration tests.
It is usually not best practice to add code or expose objects just for the sake of tests.
EDIT : Obviously this is outdated, now you provide your guard at the providers array in an NgModule. Watch other answers or official documentation for more information.
bootstrapping on a component is outdated
provideRouter() is outdated as well
I'm trying to setup Authentication in my project, using a login and AuthGuard from the Angular2 guide : https://angular.io/docs/ts/latest/guide/router.html
I'm using the release : "#angular/router": "3.0.0-beta.1".
I'll try to explain as much as possible, feel free to tell me if you need more details.
I have my main.ts file which boostraps the app with the following code :
bootstrap(MasterComponent, [
APP_ROUTER_PROVIDERS,
MenuService
])
.catch(err => console.error(err));
I load the MasterComponent, which loads a Header containing buttons that allow me to navigate through my app and it also contains my main for now.
I'm following the guide to make my app work the same way, with the following app.routes.ts :
export const routes: RouterConfig = [
...LoginRoutes,
...MasterRoutes
];
export const APP_ROUTER_PROVIDERS = [
provideRouter(routes),
AUTH_PROVIDERS
];
And the login.routes.ts from the guide, which defines my AuthGuard :
export const LoginRoutes = [
{ path: 'login', component: LoginComponent }
];
export const AUTH_PROVIDERS = [AuthGuard, AuthService];
my Master component has its own route definition, which also contains the guard I'm trying to setup. master.routes.ts :
export const MasterRoutes : RouterConfig = [
{ path: '', redirectTo: '/accueil', pathMatch: 'full' },
{
path: 'accueil',
component: AccueilComponent
},
{ path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] },
];
And I'm using the same files as the guide, which are auth.guard.ts, auth.service.ts, login.component.ts and login.routes.ts.
In my header.component.ts file, when I try to access any routes, it's working just fine, but when I try to access the guarded path (/dashboard), I get the No provider for AuthGuard! error.
I saw the recent post with the same issue as mine (NoProviderError using CanActivate in Angular 2), but to me the guard is bootstraped correctly up to the main.ts file, so my router should know which routes should be provided with the AuthGuard right ?
Any help or advice would be greatly appreciated.
Thanks !
I had this same issue after going through the Route Guards section of Routing and Authorization tutorial on the Angular website https://angular.io/docs/ts/latest/guide/router.html, it is section 5.
I am adding AuthGuard to one of my main routes and not to child routes like the tutorial shows.
I fixed it by added AuthGuard to my list of providers in my app.module.ts file, so that file now looks like this:
import { AppComponent } from './app.component';
import {AppRoutingModule} from './app-routing.module';
import {AuthGuard} from './auth-gaurd.service';
import { AnotherPageComponent } from './another-page/another-page.component';
import { LoginPageComponent } from './login-page/login-page.component';
#NgModule({
imports: [
BrowserModule,
FormsModule,
JsonpModule,
AppRoutingModule,
HttpModule
],
declarations: [
AppComponent,
LoginPageComponent,
AnotherPageComponent
],
providers: [AuthGuard],
bootstrap: [AppComponent]
})
export class AppModule { }
I have gone back through the tutorial and in their app.module.ts file, they do not add AuthGuard to the providers, not sure why.
Try to add
#Injectable({
providedIn: 'root'
})
no need to add to module provider.
Also, don't fall into the trap of using a literal for the guard class inside your routing configuration, just because some blog articles do:
{ path: 'whatever', component: WhatEverComponent, canActivate: ['WhatEverGuard'] }
is not going to work (No provider for...), instead, use the class directly:
{ path: 'whatever', component: WhatEverComponent, canActivate: [WhatEverGuard] }
Another hint, when lazy loading components, the guard is applied in the routing configuration of the parent component, not in the routing configuration of the lazy loaded component.
For those who still have this error - don't forget to include your AuthGuard service or class to main bootstrap function.
And don't forget to import this service before bootstrap runs.
import { bootstrap } from '#angular/platform-browser-dynamic';
import { AppComponent } from './app.component';
import { AuthGuard } from './shared/auth.service';
bootstrap(AppComponent, [
appRouterProviders,
AuthGuard
]);
Angular 2 team did not mention this in main router docs, and it took couple of hours for me to figure it out.
The answer is further down in the tutorial. See the file listings in the "Add the LoginComponent" topic under the "Component-less route:..." section in "Milestone 5: Route Guards". It shows AuthGuard and AuthService being imported and added to the providers array in login-routing.module.ts, and then that module being imported into app.module.ts.
login-routing.module.ts
...
import { AuthGuard } from './auth-guard.service';
import { AuthService } from './auth.service';
...
#NgModule({
...
providers: [
AuthGuard,
AuthService
]
})
export class LoginRoutingModule {}
app.module.ts
import { LoginRoutingModule } from './login-routing.module';
#NgModule({
imports: [
...
LoginRoutingModule,
...
],
...
providers: [
DialogService
],
...
Actually, it was only a typo in an import...
I was typing
import { AuthGuard } from './../Authentification/auth.guard';
instead of
import { AuthGuard } from './../authentification/auth.guard';
making it not working but at the same time not displaying me any error...
(sadface)
I encountered this issue when I was following a tutorial. I tried most of the answer here but not getting any success. Then I tried the silly way like putting the AuthGuard before the other services in the provider and it works.
// app.module.ts
..
providers: [
AuthGuard,
UserService,
ProjectService
]
Since you got the solution as it was due to syntax issue. I just wanted to share this info.
we need to provide the AuthGaudSerivce as provider in only that module that correspond to respective route. No need to provide in main module or root module as main module will automatically load all the given sub module.This helps in keeping the code modular and encapsulated.
for example, suppose we have below scenario
1. we have module m1
2. we have route m1r in module m1
3. route m1r has 2 route r1 and r2
4. we want to protect r1 using authGaurd
5. finally we have main module that is dependent on sub module m1
Below is just prototype, not the actual code for understanding purpose
//m1.ts
import {AuthGaurd} from './auth.gaurd.service'
import {m1r} from './m1r'
#NgModule(
imports: [m1r],
providers: [AuthGaurd]
)
export class m1{
}
//m1r.ts
import {AuthGaurd} from './auth.gaurd.service'
const authRoute = [
{path: '/r1', component: 'authComponent', canActivate: [AuthGaurd]},
{path: '/r2', component: 'other'}
]
export authRoute
//main.module.ts
import {m1} from ''
import {mainComponent} from ''
#NgModule({
imports: [m1],
bootstrap: [mainComponent]
})
export class MainModule{}
import { Injectable } from '#angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '#angular/router';
#Injectable()
export class AuthGuard implements CanActivate {
constructor(private router: Router) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
if (localStorage.getItem('currentUser')) {
// logged in so return true
return true;
}
// not logged in so redirect to login page with the return url
this.router.navigate(['/login'], { queryParams: { returnUrl: state.url }});
return false;
}
}
Importing both HttpModule and HttpClientModule helped me.
import { HttpClientModule } from '#angular/common/http';
import { HttpModule } from '#angular/http';
you can try import AuthGuard in provider of that module and then import it in the routing component-routing.module.ts file also
#NgModule({
providers: [
AuthGuard
],})
This happened to me when I had setup my Routes incorrectly:
WRONG
const routes: Routes =
[
{
path: 'my-path',
component: MyComponent,
resolve: { myList: MyListResolver, canActivate: [ AuthenticationGuard ] }
},
];
Note that in this case canActivate was accidentally made a part of the resolve object.
CORRECT
const routes: Routes =
[
{
path: 'my-path',
component: MyComponent,
resolve: { myList: MyListResolver },
canActivate: [ AuthenticationGuard ]
},
];