Skip to content

Commit

Permalink
Merge pull request #151 from willianfalbo/fallbacks
Browse files Browse the repository at this point in the history
add multiple fallbacks
  • Loading branch information
toonvanstrijp committed Jun 11, 2020
2 parents 714ea4b + 407cbf3 commit 0b1920b
Show file tree
Hide file tree
Showing 10 changed files with 929 additions and 3 deletions.
22 changes: 22 additions & 0 deletions README.md
Expand Up @@ -290,6 +290,28 @@ I18nModule.forRootAsync({
});
```

#### Using Fallbacks

To configure multiple fallbacks use `fallbacks` option. You could handle a single language or multiple ones.

> (note: In this example, the translations `en` `fr` and `pt-BR` are needed to work correctly.)
```typescript
I18nModule.forRoot({
fallbackLanguage: 'en',
fallbacks: {
'en-CA': 'fr',
'en-*': 'en',
'fr-*': 'fr',
'pt': 'pt-BR',
},
parser: I18nJsonParser,
parserOptions: {
path: path.join(__dirname, '/i18n/'),
},
});
```

### Translating with i18n module

#### `I18nLang` decorator and `I18nService`
Expand Down
2 changes: 2 additions & 0 deletions src/lib/interfaces/i18n-options.interface.ts
Expand Up @@ -20,6 +20,7 @@ export type I18nOptionResolver =

export interface I18nOptions {
fallbackLanguage: string;
fallbacks?: { [key: string]: string };
resolvers?: I18nOptionResolver[];
parser: Type<I18nParser>;
parserOptions: any;
Expand All @@ -30,6 +31,7 @@ export interface I18nOptionsFactory {
| Promise<I18nOptionsWithoutResolvers>
| I18nOptionsWithoutResolvers;
}

export interface I18nAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
name?: string;
useExisting?: Type<I18nOptionsFactory>;
Expand Down
22 changes: 21 additions & 1 deletion src/lib/services/i18n.service.ts
Expand Up @@ -34,7 +34,7 @@ export class I18nService {
private readonly languagesSubject: BehaviorSubject<string[]>,
@Inject(I18N_TRANSLATIONS_SUBJECT)
private readonly translationsSubject: BehaviorSubject<I18nTranslation>,
) {}
) { }

public async translate(
key: string,
Expand All @@ -53,6 +53,8 @@ export class I18nService {
? this.i18nOptions.fallbackLanguage
: lang;

lang = await this.handleFallbacks(lang);

const translationsByLanguage = (
await this.translations.pipe(take(1)).toPromise()
)[lang];
Expand Down Expand Up @@ -111,4 +113,22 @@ export class I18nService {
this.languagesSubject.next(languages);
}
}

private async handleFallbacks(lang: string) {
const supportedLanguages = await this.getSupportedLanguages();
if (this.i18nOptions.fallbacks && !supportedLanguages.includes(lang)) {
const sanitizedLang =
lang.includes('-')
? lang.substring(0, lang.indexOf('-')).concat('-*')
: lang;

for (const key in this.i18nOptions.fallbacks) {
if (key === lang || key === sanitizedLang) {
lang = this.i18nOptions.fallbacks[key];
break;
}
}
}
return lang;
}
}
64 changes: 64 additions & 0 deletions tests/i18n-async.spec.ts
Expand Up @@ -75,3 +75,67 @@ describe('i18n module without trailing slash in path', () => {
);
});
});

describe('i18n async module with fallbacks', () => {
let i18nService: I18nService;

beforeAll(async () => {
const module = await Test.createTestingModule({
imports: [
I18nModule.forRootAsync({
useFactory: () => {
return {
fallbackLanguage: 'en',
fallbacks: {
'en-CA': 'fr',
'en-*': 'en',
'fr-*': 'fr',
'pt': 'pt-BR',
},
parserOptions: {
path: path.join(__dirname, '/i18n/'),
},
};
},
parser: I18nJsonParser,
}),
],
}).compile();

i18nService = module.get(I18nService);
});

it('i18n service should be defined', async () => {
expect(i18nService).toBeTruthy();
});

it('i18n service should return correct translation', async () => {
expect(await i18nService.translate('test.HELLO')).toBe(
'Hello',
);
expect(await i18nService.translate('test.HELLO', { lang: 'en' })).toBe(
'Hello',
);
expect(await i18nService.translate('test.HELLO', { lang: 'en-US' })).toBe(
'Hello',
);
expect(await i18nService.translate('test.HELLO', { lang: 'en-CA' })).toBe(
'Bonjour',
);
expect(await i18nService.translate('test.HELLO', { lang: 'nl' })).toBe(
'Hallo',
);
expect(await i18nService.translate('test.HELLO', { lang: 'fr' })).toBe(
'Bonjour',
);
expect(await i18nService.translate('test.HELLO', { lang: 'fr-BE' })).toBe(
'Bonjour',
);
expect(await i18nService.translate('test.HELLO', { lang: 'pt' })).toBe(
'Olá',
);
expect(await i18nService.translate('test.HELLO', { lang: 'pt-BR' })).toBe(
'Olá',
);
});
});

0 comments on commit 0b1920b

Please sign in to comment.