How to setup the middleware Service in nestJs application in nestjs-i18n package to get accept-language header without error? - localization

Hey In my nestjs application, I have installed the nestjs-i18n npm package of version 10.2.6 . I have configured this I18nModule in the appModule as below :
app.module.ts :
import { MiddlewareConsumer, Module, NestModule } from '#nestjs/common';
import { ConfigModule } from '#nestjs/config';
import { PrismaModule } from './config/database';
import { SessionModule } from './modules/session/session.module';
import {
I18nModule,
QueryResolver,
AcceptLanguageResolver,
HeaderResolver,
} from 'nestjs-i18n';
import * as path from 'path';
import { I18nMiddleware } from './common/hooks/i18n/i18n.middleware';
#Module({
imports: [
PrismaModule,
SessionModule,
ConfigModule.forRoot({ isGlobal: true }),
I18nModule.forRoot({
fallbackLanguage: 'en',
fallbacks: {
'en-CA': 'fr',
'en-*': 'en',
'fr-*': 'fr',
pt: 'pt-BR',
},
loaderOptions: {
path: path.join(__dirname, '/i18n/'),
watch: true,
},
resolvers: [
{
use: QueryResolver,
options: ['lang'],
},
new HeaderResolver(['x-content-lang']),
AcceptLanguageResolver,
],
}),
],
controllers: [],
providers: [],
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer.apply(I18nMiddleware).forRoutes('*');
}
}
I have also have the json files for multiple languages as below structure :
src Folder
|
|-i18n Folder
|
|--en Folder
|
|--en.json
| --fr Folder
|
| -- fr.json
| --etc
I have configured it in nest-cli.json as below :
nest-cli.json :
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "#nestjs/schematics",
"sourceRoot": "src",
"compilerOptions": {
"assets": [
{
"include": "i18n/**/*",
"watchAssets":true
}
]
}
}
Problem :
I want to use the accept-language header to get the user-preferred language for translating the variables accordingly. So i have decided to implement the middleware to achieve it. But I don't know how to do it in the nestjs-i18n package .Please someone help me do this :
I hereby share the middleware i have written :
i18nMiddleware.ts :
import { Injectable, NestMiddleware } from '#nestjs/common';
import { FastifyRequest, FastifyReply } from 'fastify';
#Injectable()
export class I18nMiddleware implements NestMiddleware {
constructor() {}
async use(req: FastifyRequest, res: FastifyReply, next: () => void) {
const lang = req.headers['accept-language']?.toString();
console.log('............lang', lang);
if (lang) {
**// I want to what to write here to make the language received from the header**
}
next();
}
}
So please help me. Thanks in advance .

Related

NestJS / TypeOrm / Neo4j : Nest can't resolve dependencies of the NEO4J_DRIVER

I try to run my NestJs/TypeOrm with Neo4j db but i've got an error :
Nest can't resolve dependencies of the NEO4J_DRIVER (?). Please make sure that the argument NEO4J_OPTIONS at index [0] is available in the Neo4jModule context.
I don't understand where it come from.
This is my app.module
import { Module } from '#nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { Neo4jModule } from 'nest-neo4j'
import { PersonModule } from './person/person.module';
#Module({
imports: [
Neo4jModule.forRootAsync({
scheme: "neo4j+s",
host: "db-sp8xxaunnz13icv892y5.graphenedb.com",
port: 24786,
username: 'neo4j',
password: 'ingrid-ticket-capital-spirit-reform-6035'
}),
PersonModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
This is my person.module.ts
import { Module } from '#nestjs/common';
import { PersonService } from './person.service';
import { PersonController } from './person.controller';
import { TypeOrmModule } from '#nestjs/typeorm';
import { Person } from './person.entity';
import { Neo4jModule } from 'nest-neo4j/dist';
import { PersonRepository } from './person.entityrepository';
#Module({
imports: [
TypeOrmModule.forFeature([PersonRepository]),
,
],
providers: [
PersonService
],
controllers: [
PersonController
]
})
export class PersonModule {}
Thanks for helping me !
I think you missed driver to install.
Try this npm i neo4j-driver.
From my perspective, you're using wrong method, instead of forRootAsync you should use forRoot on Neo4jModule

What's the purpose of a dynamic database module and the CONNECTION injection token?

I struggle with understanding what is the purpose of the dynamic database module providing a 'CONNECTION' dependency injection token to the TypeOrmModule in AppModule.
Is it so that we can reuse the TypeOrmModule from AppModule but with a different config? Why can't we simply import the TypeOrmModule directly wherever we need it with a different config?
This is from the nestjs fundamentals course.
TypeOrmModule configuration in AppModule (
https://github.com/jstrother/iluvcoffee/blob/5a34b0d98841f9d33d2490e7186648928303eedb/src/app.module.ts#L21-L34):
import * as Joi from '#hapi/joi';
import { Module } from '#nestjs/common';
import { ConfigModule, ConfigService } from '#nestjs/config';
import { TypeOrmModule } from '#nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { CoffeesModule } from './coffees/coffees.module';
import { CoffeeRatingModule } from './coffee-rating/coffee-rating.module';
import { DatabaseModule } from './database/database.module';
import { CommonModule } from './common/common.module';
#Module({
imports: [
CoffeesModule,
ConfigModule.forRoot({
validationSchema: Joi.object({
DATABASE_HOST: Joi.required(),
DATABASE_PORT: Joi.number().default(5432),
}),
}),
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
useFactory: (configService: ConfigService) => ({
type: 'postgres',
host: configService.get('DATABASE_HOST'),
port: +configService.get<number>('DATABASE_PORT'),
username: configService.get('DATABASE_USER'),
password: configService.get('DATABASE_PASSWORD'),
database: configService.get('DATABASE_NAME'),
autoLoadEntities: true,
synchronize: true,
}),
inject: [ConfigService],
}),
CoffeeRatingModule,
DatabaseModule,
CommonModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
DatabaseModule (https://github.com/jstrother/iluvcoffee/blob/5a34b0d98841f9d33d2490e7186648928303eedb/src/database/database.module.ts):
import { DynamicModule, Module } from '#nestjs/common';
import { createConnection, ConnectionOptions } from 'typeorm';
#Module({})
export class DatabaseModule {
static register(options: ConnectionOptions): DynamicModule {
return {
module: DatabaseModule,
providers: [
{
provide: 'CONNECTION',
useValue: createConnection(options),
}
]
};
}
}
Using the DatabaseModule in another module (https://github.com/jstrother/iluvcoffee/blob/5a34b0d98841f9d33d2490e7186648928303eedb/src/coffee-rating/coffee-rating.module.ts):
import { Module } from '#nestjs/common';
import { CoffeesModule } from '../coffees/coffees.module';
import { DatabaseModule } from '../database/database.module';
import { CoffeeRatingService } from './coffee-rating.service';
#Module({
imports: [
DatabaseModule.register(
{
type: 'postgres',
host: process.env.DATABASE_HOST,
username: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD,
port: +process.env.DATABASE_PORT,
}
),
CoffeesModule
],
providers: [CoffeeRatingService]
})
export class CoffeeRatingModule {}
It just seems that using the DatabaseModule in that CoffeeRatingModule is kinda moot because we already have a database connection with the same config from the AppModule... What am I missing?
I believe the core course shows you two different ways to do it (just like the docs do). One already built by NestJS (the #nestjs/typeorm package), and one built by you (using the DatabaseModule). The DatabaseModule approach gives you more freedom because it's made by you, but it also means you'd be responsible for managing the connection yourself, all the dependency tokens, everything, whereas the #nestjs/typeorm package does most of that for you, but extending it can be a bit difficult at times.

getting error `Property 'initializeData' does not exist on type of AppConfig` on `useFactory`

I am fetching data from service on APP_INITIALIZER, but getting error as
Property 'initializeData' does not exist on type of AppConfig
don't know what is the exact issue here. any one help me?
here is my module file:
import { AppConfig } from "./shared-components/auth/AdalService";
import { AppComponent } from './app.component';
import { RoutesModule } from './routes/routes.module';
import { SignInComponent } from './shared-components/user/sign-in/sign-in.component';
export function initializeApp() {
return () => AppConfig.initializeData(); //getting error here
}
#NgModule({
declarations: [
AppComponent,
SignInComponent
],
imports: [
BrowserModule,
AngularFontAwesomeModule,
MsAdalAngular6Module,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: (createTranslateLoader),
deps: [HttpClient]
},
isolate: true
}),
SharedModule,
HttpClientModule,
iboCalendarModule,
RoutesModule,
// HttpClientInMemoryWebApiModule.forRoot(EventData),
StoreModule.forRoot({}),
EffectsModule.forRoot([]),
StoreDevtoolsModule.instrument({
name:'IBO App',
maxAge:25
})
],
providers: [
{
provide: APP_INITIALIZER,
useFactory: initializeApp,
multi: true,
deps: [AppConfig, SignInComponent ]
},
MsAdalAngular6Service,
{
provide: 'adalConfig',
useFactory: getAdalConfig,
deps: []
},
{
provide: HTTP_INTERCEPTORS,
useClass: InsertAuthTokenInterceptor,
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule { }
Here is my service.ts:
import { Injectable, OnInit } from '#angular/core';
import { ShareOption } from "./../user/sign-in/sign-in.component";
import { Store, select } from '#ngrx/store';
import { StateShared } from "./../models/models";
#Injectable({
providedIn: 'root'
})
export class AppConfig {
constructor(){}
initializeData() {
return new Promise((resolve, reject) => resolve(true));
}
}
I bought the service in parameter, got issue fixed. my updated chunk is:
export function initializeApp(service:AppConfig) { //getting service object in param
return () => service.initializeData();
}

NullInjectorError: No provider for HttpClient! Angular 5

I, am using the Angular template in visual studio 2017. Then I updated to angular 5.2. I, tried to find the solution. But didn't got exact solution.
The service class is calling the http call.However I, am getting an error as
Service.TS
import { Injectable } from '#angular/core';
import { LoginViewModel as loginVM } from "../../viewmodel/app.viewmodel"
import { HttpClient, HttpHeaders } from "#angular/common/http";
#Injectable()
export class LoginService {
private loginUrl = "Account/Authentication";
private _httpClientModule: HttpClient;
constructor(httpClientModule: HttpClient) {
this._httpClientModule = httpClientModule;
}
public LoginHttpCall(_loginVM: loginVM) {
const headers = new HttpHeaders().set('Content-Type', 'application/json; charset=utf-8');
this._httpClientModule.post(this.loginUrl, _loginVM, { headers }).
subscribe(data => {
console.log(data);
},
err => {
console.log("Error occured.");
});
}
}
Here is my Component class
import { Component } from '#angular/core';
import { AppComponent } from "../app/app.component";
import { LoginService } from "../../service/account/app.service.account.login";
import { LoginViewModel } from "../../viewmodel/app.viewmodel";
declare var componentHandler: any;
#Component({
selector: 'login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css'],
providers: [LoginViewModel, LoginService]
})
export class LoginComponent {
private _appComponent: AppComponent;
private _loginService: LoginService;
constructor(private appComponent: AppComponent, loginService: LoginService) {
this._appComponent = appComponent;
this._appComponent.menulist = false;
this._loginService = loginService;
}
}
app.shared.module.ts
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { FormsModule } from '#angular/forms';
import { HttpModule } from '#angular/http';
import { RouterModule } from '#angular/router';
import { AppComponent } from './components/app/app.component';
import { HomeComponent } from './components/home/home.component';
import { LoginComponent } from './components/login/login.component';
import { MobileComponent } from './components/mobile/mobile.component';
#NgModule({
declarations: [
AppComponent,
HomeComponent,
LoginComponent,
MobileComponent
],
imports: [
CommonModule,
HttpModule,
FormsModule,
RouterModule.forRoot([
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{ path: 'home', component: HomeComponent },
{ path: 'login', component: LoginComponent },
{ path: 'mobile', component: MobileComponent },
{ path: '**', redirectTo: 'home' }
])
]
})
export class AppModuleShared {
}
I, don't know where I, am doing mistake. Since I , am new in angular. I tried to add HttpClient under #NgModule but gives some other error . Since As per my knowledge I don't need to add in app.shared.module.ts file. Since HttpClient is used in service and component level.
Can anyone please tell me where I, am doing wrong .
HttpClient needs for the module HttpClientModule instead of HttpModule to be imported and added in the imports of the module.
For more see Documentation
import { HttpClientModule } from '#angular/common/http';
#NgModule({
declarations: [
...
],
imports: [
...
HttpClientModule,
...
]
})
export class AppModuleShared { }
npm clear cache
npm update
rm -rf /node_modules
npm i --save
Then import same module into app root module.
Hope it works for you.

Karma not recognizing Angular2 modules and components with Rails Webpacker

My team updated the Rails version of our application to 5.1 so we could use Webpacker, a wrapper to use Webpack with Rails and then use Angular 2 properly.
We started setting up the test suite for the Angular 2 modules using Karma + Jasmine + Webpack following this article.
If I write simple test cases, without Angular Component, TestBed and ComponentFixture, everything looks fine. However, if I try to import Angular modules and test some components, Karma raises the following error message for every component and module:
ERROR in ./app/javascript/app/app.module.ts
Module parse failed: /[application path omitted]/app/javascript/app/app.module.ts Unexpected character '#' (17:0)
You may need an appropriate loader to handle this file type.
| import { AppRoutingModule } from './app-routing.module';
|
| #NgModule({
| imports: [
| BrowserModule,
The project structure is:
- app
-- ...
-- javascript (webpacker create this folder in the first time running)
---- app (where all modules are stored)
------ ...
------ app.routing.module.ts
------ app.component.ts
------ app.module.ts
------ echo.pipe.ts (a file created just to test the Karma suite)
---- packs
---- test
------ echo.pipe.spec.ts
------ main.js (entry point of tests)
------ main.spec.ts
The karma.conf.js file:
module.exports = function(config) {
config.set({
basePath: '',
frameworks: ['jasmine'],
files: [
{ pattern: './app/javascript/app/**/*.ts', watched: false, served: true },
{ pattern: './app/javascript/test/main.js', watched: false }
],
plugins: [
require('karma-webpack'),
require('karma-jasmine'),
require('karma-phantomjs-launcher'),
require('karma-chrome-launcher'),
require('karma-sourcemap-loader'),
require('karma-babel-preprocessor'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter')
],
exclude: [
],
preprocessors: {
'app/javascript/**/*.ts': ['webpack', 'sourcemap'],
'app/javascript/test/main.js': ['webpack', 'sourcemap']
},
mime: { 'text/x-typescript': ['ts','tsx'] },
reporters: ['progress'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: false,
browsers: ['Chrome'],
singleRun: true,
concurrency: Infinity
})
}
The echo.pipe.ts file:
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'echo'
})
export class EchoPipe implements PipeTransform {
transform(value: any): any {
return value;
}
}
The main.js file:
describe('Meaningful Test', () => {
it('1 + 1 => 2', () => {
expect(1 + 1).toBe(2);
});
});
require('./main.spec.ts');
The main.spec.ts file:
import 'core-js/es6';
import 'core-js/es7/reflect';
import 'zone.js/dist/zone';
import 'zone.js/dist/proxy';
import 'zone.js/dist/sync-test';
import 'zone.js/dist/async-test';
import 'zone.js/dist/fake-async-test';
import 'zone.js/dist/jasmine-patch';
import 'rxjs/Rx';
import { TestBed } from '#angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting,
} from '#angular/platform-browser-dynamic/testing';
TestBed.initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
describe('Meaningful Test 2', () => {
it('1 + 1 => 2', () => {
expect(1 + 1).toBe(2);
});
});
The echo.pipe.spec.ts file:
import { Component } from '#angular/core';
import { TestBed, ComponentFixture, async } from '#angular/core/testing';
import { By } from '#angular/platform-browser';
import { DebugElement } from '#angular/core';
import { EchoPipe } from '../app/echo.pipe';
describe('EchoPipe', () => {
let comp: EchoPipe;
let fixture: ComponentFixture<EchoPipe>;
let de: DebugElement;
let el: HTMLElement;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ EchoPipe ],
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(EchoPipe);
comp = fixture.componentInstance;
comp.name = 'foo';
});
it('works well', () => {
fixture.detectChanges();
el = fixture.debugElement.nativeElement as HTMLElement;
expect(el.querySelector('p').textContent).toBe('foo');
});
});
const context = require.context('./', true, /\.spec\.ts$/);
context.keys().map(context);

Resources