Skip to content

Commit

Permalink
Merge 169a7d9 into ad3f68f
Browse files Browse the repository at this point in the history
  • Loading branch information
mahziyar-es committed Jun 4, 2024
2 parents ad3f68f + 169a7d9 commit 5c6ab3f
Show file tree
Hide file tree
Showing 11 changed files with 305 additions and 5 deletions.
7 changes: 6 additions & 1 deletion docs/quick-start.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -326,11 +326,16 @@ import { I18nContext, I18nService } from 'nestjs-i18n';
export class AppService {
constructor(private readonly i18n: I18nService) {}
getHello(): string {
return this.i18n.t('test.HELLO',{ lang: I18nContext.current().lang });
return this.i18n.t('test.HELLO');
}

getHelloInSpecificLanguage(): string {
return this.i18n.t('test.HELLO',{ lang: "en" });
}
}
```


## Translate options

```typescript
Expand Down
9 changes: 7 additions & 2 deletions src/services/i18n.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ import {
take,
takeUntil,
} from 'rxjs';
import { I18nOptions, I18nTranslation, I18nValidationError } from '..';
import {
I18nContext,
I18nOptions,
I18nTranslation,
I18nValidationError,
} from '..';
import {
I18N_LANGUAGES,
I18N_LANGUAGES_SUBJECT,
Expand Down Expand Up @@ -75,7 +80,7 @@ export class I18nService<K = Record<string, unknown>>
options?: TranslateOptions,
): IfAnyOrNever<R, string, R> {
options = {
lang: this.i18nOptions.fallbackLanguage,
lang: I18nContext.current()?.lang || this.i18nOptions.fallbackLanguage,
...options,
};

Expand Down
8 changes: 8 additions & 0 deletions tests/app/cats/cat.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ export class CatResolver {
return cat;
}

@Query('catUsingService')
async getCatUsingService(@Args('id') id: number) {
const cat = await this.catService.findById(id);
// we manually overwrite this property to indicate a value that is translated!
cat.description = this.i18nService.translate('test.cat');
return cat;
}

@Mutation('createCat')
async create(@Args('createCatInput') args: CreateCatInput): Promise<any> {
await this.pubSub.publish('catAdded', { catAdded: args.name });
Expand Down
3 changes: 2 additions & 1 deletion tests/app/cats/cat.types.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ type Query {
cats: [Cat]
cat(id: Int!): Cat
catUsingContext(id: Int!): Cat
catUsingService(id: Int!): Cat
}

type Mutation {
Expand All @@ -23,4 +24,4 @@ type Subscription {
input CreateCatInput {
name: String
age: Int
}
}
29 changes: 28 additions & 1 deletion tests/app/controllers/hello.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ import { CreateUserDto } from '../dto/create-user.dto';
import { TestException, TestExceptionFilter } from '../filter/test.filter';
import { TestGuard } from '../guards/test.guard';
import { Hero, HeroById } from '../interfaces/hero.interface';
import { exampleErrorFormatter, exampleResponseBodyFormatter } from '../examples/example.functions';
import {
exampleErrorFormatter,
exampleResponseBodyFormatter,
} from '../examples/example.functions';
import { TestInterceptor } from '../interceptors/test.interceptor';

@Controller('hello')
Expand All @@ -35,6 +38,11 @@ export class HelloController {
return this.i18n.translate('test.HELLO', { lang });
}

@Get('/no-lang-for-service')
helloNoLangForService(): any {
return this.i18n.translate('test.HELLO');
}

@Get('/typed')
helloTyped(@I18nLang() lang: string): string {
return this.i18n.translate('test.HELLO', { lang });
Expand All @@ -59,6 +67,11 @@ export class HelloController {
return this.i18n.t('test.HELLO', { lang });
}

@Get('/short/no-lang-for-service')
helloShortNoLangForService(): any {
return this.i18n.t('test.HELLO');
}

@Get('/short/typed')
helloShortTyped(@I18nLang() lang: string): string {
return this.i18n.t('test.HELLO', { lang });
Expand Down Expand Up @@ -228,4 +241,18 @@ export class HelloController {
];
return items.find(({ id }) => id === data.id);
}

@GrpcMethod('HeroesService', 'FindOneTranslatedWithService')
findOneTranslatedWithService(@Payload() data: HeroById): Hero {
const items = [
{
id: 1,
name: this.i18n.t('test.set-up-password.heading', {
args: { username: 'John' },
}),
},
{ id: 2, name: 'Doe' },
];
return items.find(({ id }) => id === data.id);
}
}
1 change: 1 addition & 0 deletions tests/app/hero.proto
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package hero;

service HeroesService {
rpc FindOne (HeroById) returns (Hero) {}
rpc FindOneTranslatedWithService (HeroById) returns (Hero) {}
}

message HeroById {
Expand Down
4 changes: 4 additions & 0 deletions tests/app/interfaces/hero.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,8 @@ export interface HeroById {

export interface HeroService {
findOne(data: HeroById, metadata: Metadata): Observable<Hero>;
findOneTranslatedWithService(
data: HeroById,
metadata: Metadata,
): Observable<Hero>;
}
76 changes: 76 additions & 0 deletions tests/i18n-express.e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,82 @@ describe('i18n module e2e express', () => {
.expect({ lang: 'nl' });
});

it(`/GET hello/no-lang-for-service should return fallback language`, () => {
return request(app.getHttpServer())
.get('/hello/no-lang-for-service')
.expect(200)
.expect('Hello');
});

it(`/GET hello/no-lang-for-service should return translation when providing query resolver`, () => {
return request(app.getHttpServer())
.get('/hello/no-lang-for-service?lang=nl')
.expect(200)
.expect('Hallo');
});

it(`/GET hello/no-lang-for-service should return translation when providing x-custom-lang`, () => {
return request(app.getHttpServer())
.get('/hello/no-lang-for-service')
.set('x-custom-lang', 'nl')
.expect(200)
.expect('Hallo');
});

it(`/GET hello/no-lang-for-service should return translation when providing accept-language`, () => {
return request(app.getHttpServer())
.get('/hello/no-lang-for-service')
.set('accept-language', 'nl')
.expect(200)
.expect('Hallo');
});

it(`/GET hello/no-lang-for-service should return translation when providing cookie`, () => {
return request(app.getHttpServer())
.get('/hello/no-lang-for-service')
.set('Cookie', ['lang=nl'])
.expect(200)
.expect('Hallo');
});

it(`/GET hello/short/no-lang-for-service should return fallback language`, () => {
return request(app.getHttpServer())
.get('/hello/short/no-lang-for-service')
.expect(200)
.expect('Hello');
});

it(`/GET hello/short/no-lang-for-service should return translation when providing query resolver`, () => {
return request(app.getHttpServer())
.get('/hello/short/no-lang-for-service?lang=nl')
.expect(200)
.expect('Hallo');
});

it(`/GET hello/short/no-lang-for-service should return translation when providing x-custom-lang`, () => {
return request(app.getHttpServer())
.get('/hello/short/no-lang-for-service')
.set('x-custom-lang', 'nl')
.expect(200)
.expect('Hallo');
});

it(`/GET hello/short/no-lang-for-service should return translation when providing accept-language`, () => {
return request(app.getHttpServer())
.get('/hello/short/no-lang-for-service')
.set('accept-language', 'nl')
.expect(200)
.expect('Hallo');
});

it(`/GET hello/short/no-lang-for-service should return translation when providing cookie`, () => {
return request(app.getHttpServer())
.get('/hello/short/no-lang-for-service')
.set('Cookie', ['lang=nl'])
.expect(200)
.expect('Hallo');
});

it('/POST cats with age 2 should error', async () => {
await request(app.getHttpServer())
.post('/cats')
Expand Down
76 changes: 76 additions & 0 deletions tests/i18n-fastify.e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,82 @@ describe('i18n module e2e fastify', () => {
.expect({ lang: 'nl' });
});

it(`/GET hello/no-lang-for-service should return fallback language`, () => {
return request(app.getHttpServer())
.get('/hello/no-lang-for-service')
.expect(200)
.expect('Hello');
});

it(`/GET hello/no-lang-for-service should return translation when providing query resolver`, () => {
return request(app.getHttpServer())
.get('/hello/no-lang-for-service?lang=nl')
.expect(200)
.expect('Hallo');
});

it(`/GET hello/no-lang-for-service should return translation when providing x-custom-lang`, () => {
return request(app.getHttpServer())
.get('/hello/no-lang-for-service')
.set('x-custom-lang', 'nl')
.expect(200)
.expect('Hallo');
});

it(`/GET hello/no-lang-for-service should return translation when providing accept-language`, () => {
return request(app.getHttpServer())
.get('/hello/no-lang-for-service')
.set('accept-language', 'nl')
.expect(200)
.expect('Hallo');
});

it(`/GET hello/no-lang-for-service should return translation when providing cookie`, () => {
return request(app.getHttpServer())
.get('/hello/no-lang-for-service')
.set('Cookie', ['lang=nl'])
.expect(200)
.expect('Hallo');
});

it(`/GET hello/short/no-lang-for-service should return fallback language`, () => {
return request(app.getHttpServer())
.get('/hello/short/no-lang-for-service')
.expect(200)
.expect('Hello');
});

it(`/GET hello/short/no-lang-for-service should return translation when providing query resolver`, () => {
return request(app.getHttpServer())
.get('/hello/short/no-lang-for-service?lang=nl')
.expect(200)
.expect('Hallo');
});

it(`/GET hello/short/no-lang-for-service should return translation when providing x-custom-lang`, () => {
return request(app.getHttpServer())
.get('/hello/short/no-lang-for-service')
.set('x-custom-lang', 'nl')
.expect(200)
.expect('Hallo');
});

it(`/GET hello/short/no-lang-for-service should return translation when providing accept-language`, () => {
return request(app.getHttpServer())
.get('/hello/short/no-lang-for-service')
.set('accept-language', 'nl')
.expect(200)
.expect('Hallo');
});

it(`/GET hello/short/no-lang-for-service should return translation when providing cookie`, () => {
return request(app.getHttpServer())
.get('/hello/short/no-lang-for-service')
.set('Cookie', ['lang=nl'])
.expect(200)
.expect('Hallo');
});

it('/POST cats with age 2 should error', async () => {
await request(app.getHttpServer())
.post('/cats')
Expand Down
83 changes: 83 additions & 0 deletions tests/i18n-gql.e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,89 @@ describe('i18n module e2e graphql', () => {
});
});

it(`should query a particular cat (using injected I18nService) in fallback language`, () => {
return request(app.getHttpServer())
.post('/graphql')
.send({
operationName: null,
variables: {},
query: '{catUsingService(id:2){id,name,age,description}}',
})
.expect(200, {
data: {
catUsingService: {
id: 2,
name: 'bar',
age: 6,
description: 'Cat',
},
},
});
});

it(`should query a particular cat (using injected I18nService) in NL with x-custom-lang header`, () => {
return request(app.getHttpServer())
.post('/graphql')
.set('x-custom-lang', 'nl')
.send({
operationName: null,
variables: {},
query: '{catUsingService(id:2){id,name,age,description}}',
})
.expect(200, {
data: {
catUsingService: {
id: 2,
name: 'bar',
age: 6,
description: 'Kat',
},
},
});
});

it(`should query a particular cat (using injected I18nService) in NL with cookie`, () => {
return request(app.getHttpServer())
.post('/graphql')
.set('Cookie', ['lang=nl'])
.send({
operationName: null,
variables: {},
query: '{catUsingService(id:2){id,name,age,description}}',
})
.expect(200, {
data: {
catUsingService: {
id: 2,
name: 'bar',
age: 6,
description: 'Kat',
},
},
});
});

it(`should query a particular cat (using injected I18nService) in NL with accept-language header`, () => {
return request(app.getHttpServer())
.post('/graphql')
.set('accept-language', 'nl')
.send({
operationName: null,
variables: {},
query: '{catUsingService(id:2){id,name,age,description}}',
})
.expect(200, {
data: {
catUsingService: {
id: 2,
name: 'bar',
age: 6,
description: 'Kat',
},
},
});
});

afterAll(async () => {
apollo.stop();
await subscriptionClient.dispose();
Expand Down
Loading

0 comments on commit 5c6ab3f

Please sign in to comment.