The following items in Vendure can be translated:
Translatable interface.The following entities implement the Translatable interface:
To understand how translatable entities are implemented, let's take a look at a simplified version of the Facet entity:
All translatable entities have a translations field which is a relation to the translations. Any fields that are to be translated are of type , and . This is because the field here does not in fact exist in the database in the table. Instead, it belongs to the table, which brings us to the entity (again simplified for clarity):
LocaleString@Column() decoratornamefacetfacet_translationsFacetTranslationThus there is a one-to-many relation between Facet and FacetTranslation, which allows Vendure to handle multiple translations of the same entity. The FacetTranslation entity also implements the Translation interface, which requires the languageCode field and a reference to the base entity.
If your plugin needs to load a translatable entity, you will need to use the TranslatorService to hydrate all the LocaleString fields will the actual translated values from the correct translation.
For example, if you are loading a Facet entity, you would do the following:
See the Adding Admin UI Translations guide.
Let's say you've implemented some custom server-side functionality as part of a plugin. You may be returning custom errors or other messages. Here's how you can provide these messages in multiple languages.
Using addTranslation inside the onApplicationBootstrap (Nestjs lifecycle hooks) of a Plugin is the easiest way to add new translations.
While Vendure is only using the error, errorResult, message and configurableOperation resource keys you are free to use your own.
This example shows how to create a custom translatable error
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 });
The description of a ConfigurableOperationDef — a promotion condition, shipping calculator, collection filter and so on — as well as the label and description of each of its args, can be defined inline as an array of localized strings:
The same strings can also come from the message catalogs, under the configurableOperation namespace. This keeps the operation definition readable when you support many languages, and it lets you translate an operation defined by someone else without forking it.
The keys are derived from the operation, so there is nothing to register:
<type> is the registry the operation belongs to, such as ShippingCalculator or PromotionCondition. It forms part of the key because a code is only unique within its own registry — core itself uses buy_x_get_y_free for both a promotion condition and a promotion action.
So the German strings above could instead be registered like this:
When a string is resolved, each language in turn — the requested language, then the Channel's default language, then English — is looked up first in the catalogs and then in the inline array. A catalog entry therefore wins over an inline string for the same language, which is what allows a third-party operation's wording to be overridden. An operation which ships only inline strings still resolves to its own language rather than to somebody else's English catalog entry.
Select option labels behave slightly differently. The description and the arg labels arrive at the client already resolved to one string, but option labels are sent as the full array with the catalog translation merged in. This is because the Admin UI picks the option label matching the administrator's display language, which is a separate setting from the content language sent with the request, so the other languages have to survive the round trip.
A key which matches no operation is never read, so a mistyped key produces no error — the inline string is used instead and the mistake is silent. Call getTranslationKeys() on the operation, which returns the exact key paths it expects.
Several of core's descriptions are templates rather than sentences, for example Discount order by { discount }%. The admin UI substitutes the live argument values into these placeholders, so a translated string must reproduce them exactly, spaces inside the braces included.
Vendure uses the internationalization-framework i18next.
Therefore you are free to use the i18next translate function to access keys
i18next.t('error.any-message');
Architecture reviews, custom plugin work, migrations, ongoing support. Get a hand from the team that builds Vendure.
Talk to the team