-
Notifications
You must be signed in to change notification settings - Fork 103
/
i18n.middleware.ts
144 lines (118 loc) · 3.47 KB
/
i18n.middleware.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import { Inject, Injectable, NestMiddleware, Type } from '@nestjs/common';
import {
ArgumentsHost,
ContextType,
ExecutionContext,
HttpArgumentsHost,
RpcArgumentsHost,
WsArgumentsHost,
} from '@nestjs/common/interfaces';
import { ModuleRef } from '@nestjs/core';
import { shouldResolve } from '../utils';
import { I18N_OPTIONS, I18N_RESOLVERS } from '../i18n.constants';
import {
I18nContext,
I18nOptions,
I18nResolver,
ResolverWithOptions,
} from '../index';
import { I18nService } from '../services/i18n.service';
import { I18nOptionResolver } from '../interfaces';
import { I18nError } from '../i18n.error';
const ExecutionContextMethodNotImplemented = new I18nError(
"Method not implemented. nestjs-i18n creates a fake Http context since it's using middleware to resolve your language. Nestjs middlewares don't have access to the ExecutionContext.",
);
@Injectable()
export class I18nMiddleware implements NestMiddleware {
constructor(
@Inject(I18N_OPTIONS)
private readonly i18nOptions: I18nOptions,
@Inject(I18N_RESOLVERS)
private readonly i18nResolvers: I18nOptionResolver[],
private readonly i18nService: I18nService,
private readonly moduleRef: ModuleRef,
) {}
async use(req: any, res: any, next: any) {
let language = null;
// Skip middleware if language is already resolved
if (!!req.i18nLang) {
return next();
}
req.i18nService = this.i18nService;
for (const r of this.i18nResolvers) {
const resolver = await this.getResolver(r);
language = resolver.resolve(new MiddlewareHttpContext(req, res, next));
if (language instanceof Promise) {
language = await (language as Promise<string>);
}
if (language !== undefined) {
break;
}
}
req.i18nLang = language || this.i18nOptions.fallbackLanguage;
// Pass down language to handlebars
if (req.app) {
req.app.locals.i18nLang = req.i18nLang;
}
req.i18nContext = new I18nContext(req.i18nLang, this.i18nService);
if (this.i18nOptions.skipAsyncHook) {
next();
} else {
I18nContext.create(req.i18nContext, next);
}
}
private async getResolver(r: I18nOptionResolver): Promise<I18nResolver> {
if (shouldResolve(r)) {
if (r['use']) {
const resolver = r as ResolverWithOptions;
return this.moduleRef.get(resolver.use);
} else {
return this.moduleRef.get(r as Type<I18nResolver>);
}
} else {
return r as I18nResolver;
}
}
}
class MiddlewareHttpContext
implements ExecutionContext, ArgumentsHost, HttpArgumentsHost
{
constructor(
private req: any,
private res: any,
private next: any,
) {}
getClass<T = any>(): Type<T> {
throw ExecutionContextMethodNotImplemented;
}
getHandler(): any {
throw ExecutionContextMethodNotImplemented;
}
getArgs<T extends any[] = any[]>(): T {
throw ExecutionContextMethodNotImplemented;
}
getArgByIndex<T = any>(): T {
throw ExecutionContextMethodNotImplemented;
}
switchToRpc(): RpcArgumentsHost {
throw ExecutionContextMethodNotImplemented;
}
switchToHttp(): HttpArgumentsHost {
return this;
}
switchToWs(): WsArgumentsHost {
throw ExecutionContextMethodNotImplemented;
}
getType<TContext extends string = ContextType>(): TContext {
return 'http' as any;
}
getRequest<T = any>(): T {
return this.req;
}
getResponse<T = any>(): T {
return this.res;
}
getNext<T = any>(): T {
return this.next;
}
}