@nestbolt/translatable
Reading Translations
Read translations from entities -- get by locale with fallback, list all translations, check existence, and track translation completeness.
This page covers all the methods available for reading translations from your entities. These methods are provided by the TranslatableMixin and are available on any entity that extends it.
getTranslation
Get the translation value for a specific field and locale. Returns string | null.
const product = new Product();
product.setTranslations("name", {
en: "Laptop",
ar: "حاسوب محمول",
fr: "Ordinateur portable",
});
product.getTranslation("name", "en");
// → "Laptop"
product.getTranslation("name", "ar");
// → "حاسوب محمول"Signature:
getTranslation(key: string, locale?: string, useFallback?: boolean): string | null| Parameter | Type | Default | Description |
|---|---|---|---|
key | string | -- | The translatable field name. |
locale | string | Current locale | The locale to retrieve. If omitted, uses the locale from AsyncLocalStorage (set by the middleware) or the configured defaultLocale. |
useFallback | boolean | true | Whether to use the fallback chain when the requested locale is not available. |
Implicit Locale Resolution
When you omit the locale parameter, the method uses the current request locale (set by TranslatableMiddleware) or the configured defaultLocale:
// Inside a request handler where Accept-Language: ar was sent
product.getTranslation("name");
// → "حاسوب محمول" (uses the request's locale)
// Outside a request context (e.g., a cron job)
product.getTranslation("name");
// → "Laptop" (uses defaultLocale, typically "en")Fallback Behavior
When useFallback is true (the default), the method searches for a translation in this order:
- The requested locale
- Each locale in
fallbackLocalesin order - Any available locale (if
fallbackAny: trueis configured) - Returns
nullif no translation is found
// Configuration: fallbackLocales: ["en", "fr"]
const product = new Product();
product.setTranslations("name", {
fr: "Ordinateur portable",
ar: "حاسوب محمول",
});
// Request German -- not available, falls back through chain
product.getTranslation("name", "de");
// → "Ordinateur portable" (skipped "en", found "fr")
// Disable fallback
product.getTranslation("name", "de", false);
// → null (strict -- only returns "de" or nothing)Standalone Usage
Without TranslatableModule registered (for example, in unit tests or scripts), locale resolution defaults to "en" and the fallback chain is not available. Direct locale arguments still work:
const entity = new Product();
entity.setTranslation("name", "en", "Laptop");
entity.getTranslation("name", "en");
// → "Laptop"getTranslations
Get all translations for a field, or all translations for all translatable fields. Returns a TranslationMap (when a key is provided) or a Record<string, TranslationMap> (when no key is provided).
For a Single Field
product.getTranslations("name");
// → { en: "Laptop", ar: "حاسوب محمول", fr: "Ordinateur portable" }For All Fields
product.getTranslations();
// → {
// name: { en: "Laptop", ar: "حاسوب محمول", fr: "Ordinateur portable" },
// description: { en: "A powerful laptop", ar: "حاسوب محمول قوي" }
// }Filtering by Allowed Locales
You can pass an array of allowed locales to filter the returned translations:
product.getTranslations("name", ["en", "fr"]);
// → { en: "Laptop", fr: "Ordinateur portable" }
// The "ar" translation is excludedSignature:
getTranslations(key?: string, allowedLocales?: string[]): TranslationMap | Record<string, TranslationMap>| Parameter | Type | Description |
|---|---|---|
key | string (optional) | The translatable field name. If omitted, returns translations for all fields. |
allowedLocales | string[] (optional) | Only include translations for these locales. |
Empty or null values are excluded from the result.
hasTranslation
Check if a translation exists for a field in a specific locale. Returns boolean.
product.hasTranslation("name", "en");
// → true
product.hasTranslation("name", "de");
// → falseWhen the locale parameter is omitted, it uses the current request locale or the default locale:
// Inside a request where Accept-Language: ar was sent
product.hasTranslation("name");
// → true (checks "ar")Signature:
hasTranslation(key: string, locale?: string): boolean| Parameter | Type | Default | Description |
|---|---|---|---|
key | string | -- | The translatable field name. |
locale | string | Current locale | The locale to check. |
A translation is considered to "exist" if its value is not null and not an empty string.
getTranslatedLocales
Get an array of all locale codes that have a translation for a specific field.
product.setTranslations("name", {
en: "Laptop",
ar: "حاسوب محمول",
fr: "Ordinateur portable",
});
product.getTranslatedLocales("name");
// → ["en", "ar", "fr"]Signature:
getTranslatedLocales(key: string): string[]Empty and null values are excluded. Only locales with actual non-empty translations are returned.
locales
Get all unique locale codes that have translations across all translatable fields on the entity.
product.setTranslations("name", { en: "Laptop", ar: "حاسوب محمول" });
product.setTranslations("description", { en: "A laptop", fr: "Un ordinateur" });
product.locales();
// → ["en", "ar", "fr"]Signature:
locales(): string[]This aggregates locales from all translatable fields and returns a deduplicated array.
getTranslatableAttributes
Get the names of all fields marked with @Translatable() on the entity.
product.getTranslatableAttributes();
// → ["name", "description"]Signature:
getTranslatableAttributes(): string[]isTranslatableAttribute
Check whether a specific field is marked with @Translatable().
product.isTranslatableAttribute("name");
// → true
product.isTranslatableAttribute("slug");
// → falseSignature:
isTranslatableAttribute(key: string): booleanTranslation Completeness
These methods help you track which locales are missing translations. They are particularly useful for admin dashboards, CI checks, or content management workflows.
getMissingLocales
Get the locales that are missing a translation for a specific field, given a set of expected locales.
product.setTranslations("name", { en: "Laptop", ar: "حاسوب محمول" });
product.getMissingLocales("name", ["en", "ar", "fr", "de"]);
// → ["fr", "de"]Signature:
getMissingLocales(key: string, locales: string[]): string[]| Parameter | Type | Description |
|---|---|---|
key | string | The translatable field name. |
locales | string[] | The set of expected locales. |
isFullyTranslated
Check whether all translatable fields have translations for every locale in the provided list.
product.setTranslations("name", { en: "Laptop", ar: "حاسوب محمول" });
product.setTranslations("description", { en: "A laptop" });
product.isFullyTranslated(["en"]);
// → true (both fields have "en")
product.isFullyTranslated(["en", "ar"]);
// → false (description is missing "ar")Signature:
isFullyTranslated(locales: string[]): booleangetTranslationCompleteness
Get a detailed completeness report for all translatable fields across a set of locales. Returns a nested object mapping each field to each locale with a boolean indicating presence.
product.setTranslations("name", { en: "Laptop", ar: "حاسوب محمول" });
product.setTranslations("description", { en: "A laptop" });
product.getTranslationCompleteness(["en", "ar", "fr"]);
// → {
// name: {
// en: true,
// ar: true,
// fr: false
// },
// description: {
// en: true,
// ar: false,
// fr: false
// }
// }Signature:
getTranslationCompleteness(locales: string[]): Record<string, Record<string, boolean>>This is useful for rendering translation completeness indicators in admin interfaces or for generating reports on content translation status across your application.
Example: Admin Dashboard Completeness Check
@Injectable()
export class TranslationReportService {
constructor(
@InjectRepository(Product)
private readonly repo: Repository<Product>,
) {}
async getIncompleteProducts(requiredLocales: string[]) {
const products = await this.repo.find();
return products
.filter((p) => !p.isFullyTranslated(requiredLocales))
.map((p) => ({
id: p.id,
slug: p.slug,
completeness: p.getTranslationCompleteness(requiredLocales),
missingName: p.getMissingLocales("name", requiredLocales),
missingDescription: p.getMissingLocales("description", requiredLocales),
}));
}
}Translatable Entities
Create translatable entities with @Translatable() decorator and TranslatableMixin -- set, replace, and remove translations.
API Locale Resolution
Automatic locale-aware API responses with TranslatableMiddleware, TranslatableInterceptor, Accept-Language header, @SkipTranslation, and GraphQL support.