-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(core): Add server translations via plugin application bootstrap
Co-authored-by: Kevin Mattutat <[email protected]> Closes #810
- Loading branch information
Showing
11 changed files
with
313 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
--- | ||
title: "Translation" | ||
showtoc: true | ||
--- | ||
|
||
# Translation | ||
|
||
Using [`addTranslation`]({{< relref "i18n-service" >}}#addtranslation) inside the `onApplicationBootstrap` ([Nestjs lifecycle hooks](https://docs.nestjs.com/fundamentals/lifecycle-events)) of a Plugin is the easiest way to add new translations. | ||
While vendure is only using `error`, `errorResult` and `message` resource keys you are free to use your own. | ||
|
||
## Translatable Error | ||
This example shows how to create a custom translatable error | ||
```typescript | ||
/** | ||
* Custom error class | ||
*/ | ||
class CustomError extends ErrorResult { | ||
readonly __typename = 'CustomError'; | ||
readonly errorCode = 'CUSTOM_ERROR'; | ||
readonly message = 'CUSTOM_ERROR'; //< looks up errorResult.CUSTOM_ERROR | ||
} | ||
|
||
@VendurePlugin({ | ||
imports: [PluginCommonModule], | ||
providers: [I18nService], | ||
// ... | ||
}) | ||
export class TranslationTestPlugin implements OnApplicationBootstrap { | ||
|
||
constructor(private i18nService: I18nService) { | ||
|
||
} | ||
|
||
onApplicationBootstrap(): any { | ||
this.i18nService.addTranslation('en', { | ||
errorResult: { | ||
CUSTOM_ERROR: 'A custom error message', | ||
}, | ||
anything: { | ||
foo: 'bar' | ||
} | ||
}); | ||
|
||
this.i18nService.addTranslation('de', { | ||
errorResult: { | ||
CUSTOM_ERROR: 'Eine eigene Fehlermeldung', | ||
}, | ||
anything: { | ||
foo: 'bar' | ||
} | ||
}); | ||
|
||
} | ||
} | ||
``` | ||
|
||
To receive an error in a specific language you need to use the `languageCode` query parameter | ||
`query(QUERY_WITH_ERROR_RESULT, { variables }, { languageCode: LanguageCode.de });` | ||
|
||
## Use translations | ||
|
||
Vendures uses the internationalization-framework [i18next](https://www.i18next.com/). | ||
|
||
Therefore you are free to use the i18next translate function to [access keys](https://www.i18next.com/translation-function/essentials#accessing-keys) \ | ||
`i18next.t('error.any-message');` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"errorResult": { | ||
"NEW_ERROR": "Neuer Fehler" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"errorResult": { | ||
"NEW_ERROR": "New Error" | ||
} | ||
} |
84 changes: 84 additions & 0 deletions
84
packages/core/e2e/fixtures/test-plugins/translation-test-plugin.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import { OnApplicationBootstrap } from '@nestjs/common'; | ||
import { Args, Query, Resolver } from '@nestjs/graphql'; | ||
import { Ctx, ErrorResult, I18nService, PluginCommonModule, RequestContext, VendurePlugin } from '@vendure/core'; | ||
import gql from 'graphql-tag'; | ||
import path from 'path'; | ||
|
||
class CustomError extends ErrorResult { | ||
readonly __typename = 'CustomError'; | ||
readonly errorCode = 'CUSTOM_ERROR'; | ||
readonly message = 'CUSTOM_ERROR'; | ||
} | ||
|
||
class NewError extends ErrorResult { | ||
readonly __typename = 'NewError'; | ||
readonly errorCode = 'NEW_ERROR'; | ||
readonly message = 'NEW_ERROR'; | ||
} | ||
|
||
@Resolver() | ||
class TestResolver { | ||
|
||
@Query() | ||
async customErrorMessage(@Ctx() ctx: RequestContext, @Args() args: any) { | ||
return new CustomError(); | ||
} | ||
|
||
@Query() | ||
async newErrorMessage(@Ctx() ctx: RequestContext, @Args() args: any) { | ||
return new NewError(); | ||
} | ||
|
||
} | ||
|
||
export const CUSTOM_ERROR_MESSAGE_TRANSLATION = 'A custom error message'; | ||
|
||
@VendurePlugin({ | ||
imports: [PluginCommonModule], | ||
providers: [I18nService], | ||
adminApiExtensions: { | ||
schema: gql` | ||
extend type Query { | ||
customErrorMessage: CustomResult | ||
newErrorMessage: CustomResult | ||
} | ||
type CustomError implements ErrorResult { | ||
errorCode: ErrorCode! | ||
message: String! | ||
} | ||
type NewError implements ErrorResult { | ||
errorCode: ErrorCode! | ||
message: String! | ||
} | ||
"Return anything and the error that should be thrown" | ||
union CustomResult = Product | CustomError | NewError | ||
`, | ||
resolvers: [TestResolver], | ||
}, | ||
}) | ||
export class TranslationTestPlugin implements OnApplicationBootstrap { | ||
|
||
constructor(private i18nService: I18nService) { | ||
|
||
} | ||
|
||
onApplicationBootstrap(): any { | ||
this.i18nService.addTranslation('en', { | ||
errorResult: { | ||
CUSTOM_ERROR: CUSTOM_ERROR_MESSAGE_TRANSLATION, | ||
}, | ||
}); | ||
|
||
this.i18nService.addTranslation('de', { | ||
errorResult: { | ||
CUSTOM_ERROR: 'DE_' + CUSTOM_ERROR_MESSAGE_TRANSLATION, | ||
}, | ||
}); | ||
|
||
this.i18nService.addTranslationFile('en', path.join(__dirname, '../i18n/en.json')) | ||
this.i18nService.addTranslationFile('de', path.join(__dirname, '../i18n/de.json')) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import { LanguageCode, mergeConfig } from '@vendure/core'; | ||
import { createTestEnvironment } from '@vendure/testing'; | ||
import gql from 'graphql-tag'; | ||
import path from 'path'; | ||
|
||
import { initialData } from '../../../e2e-common/e2e-initial-data'; | ||
import { testConfig, TEST_SETUP_TIMEOUT_MS } from '../../../e2e-common/test-config'; | ||
|
||
import * as DE from './fixtures/i18n/de.json'; | ||
import * as EN from './fixtures/i18n/en.json'; | ||
import { | ||
CUSTOM_ERROR_MESSAGE_TRANSLATION, | ||
TranslationTestPlugin, | ||
} from './fixtures/test-plugins/translation-test-plugin'; | ||
|
||
describe('Translation', () => { | ||
const { server, adminClient } = createTestEnvironment( | ||
mergeConfig(testConfig, { | ||
plugins: [TranslationTestPlugin], | ||
}), | ||
); | ||
|
||
beforeAll(async () => { | ||
await server.init({ | ||
initialData, | ||
productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-minimal.csv'), | ||
customerCount: 0, | ||
}); | ||
await adminClient.asSuperAdmin(); | ||
}, TEST_SETUP_TIMEOUT_MS); | ||
|
||
afterAll(async () => { | ||
await server.destroy(); | ||
}); | ||
|
||
describe('translations added manualy', () => { | ||
it('shall receive custom error message', async () => { | ||
const { customErrorMessage } = await adminClient.query(CUSTOM_ERROR); | ||
expect(customErrorMessage.errorCode).toBe('CUSTOM_ERROR'); | ||
expect(customErrorMessage.message).toBe(CUSTOM_ERROR_MESSAGE_TRANSLATION); | ||
}); | ||
|
||
it('shall receive german error message', async () => { | ||
const { customErrorMessage } = await adminClient.query(CUSTOM_ERROR, {}, { languageCode: LanguageCode.de }); | ||
expect(customErrorMessage.errorCode).toBe('CUSTOM_ERROR'); | ||
expect(customErrorMessage.message).toBe('DE_' + CUSTOM_ERROR_MESSAGE_TRANSLATION); | ||
}); | ||
}); | ||
|
||
describe('translation added by file', () => { | ||
it('shall receive custom error message', async () => { | ||
const { newErrorMessage } = await adminClient.query(NEW_ERROR); | ||
expect(newErrorMessage.errorCode).toBe('NEW_ERROR'); | ||
expect(newErrorMessage.message).toBe(EN.errorResult.NEW_ERROR); | ||
}); | ||
|
||
it('shall receive german error message', async () => { | ||
const { newErrorMessage } = await adminClient.query(NEW_ERROR, {}, { languageCode: LanguageCode.de }); | ||
expect(newErrorMessage.errorCode).toBe('NEW_ERROR'); | ||
expect(newErrorMessage.message).toBe(DE.errorResult.NEW_ERROR); | ||
}); | ||
}); | ||
|
||
}); | ||
|
||
const CUSTOM_ERROR = gql` | ||
query CustomError { | ||
customErrorMessage { | ||
... on ErrorResult { | ||
errorCode | ||
message | ||
} | ||
} | ||
} | ||
`; | ||
|
||
const NEW_ERROR = gql` | ||
query NewError { | ||
newErrorMessage { | ||
... on ErrorResult { | ||
errorCode | ||
message | ||
} | ||
} | ||
} | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './i18n.service'; | ||
export * from './i18n-error'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.