Multi-Language Descriptions with the Translation Module
Your company sells the same products across several markets, and sales wants every product description to show up in the buyer's language. Adding one field per language does not scale — Business Central's System Application ships a Translation module that stores per-record, per-field, per-language values instead, and your job is to wire a small product table to it.
Requirements
The starter already contains a table named "Localized Product" with a "Code" field (Code[20], the primary key) and a Description field (Text[100]) — you only need to finish its OnDelete trigger.
Create a codeunit named "Product Translations" with three public procedures:
procedure SetDescription(ProductCode: Code[20]; LanguageId: Integer; Value: Text)
procedure GetDescription(ProductCode: Code[20]; LanguageId: Integer): Text
procedure DuplicateProduct(FromCode: Code[20]; NewCode: Code[20])Rules:
SetDescriptionstoresValueas the translation of the product'sDescriptionfield forLanguageId. Storing a value for a language that already has one replaces it.GetDescriptionreturns the value stored for exactlyLanguageId. When nothing is stored for that language, it returns the product'sDescriptionfield value instead.DuplicateProductcreates a new"Localized Product"withNewCode, the sameDescription, and a copy of every stored translation, in every language. The tests always pass an existingFromCodeand an unusedNewCode.- Deleting a
"Localized Product"record removes every translation stored for it — and only its own. Put the cleanup in the table'sOnDeletetrigger; the tests delete withDelete(true)so the trigger runs.
Use the System Application's Translation codeunit for the storage — that is the point of the task. Two things about it fail silently if missed: a record must be inserted before you attach translations (the module keys every row by the record's SystemId), and the two-argument Set/Get overloads work on the session language — only the overloads taking a LanguageId can satisfy the per-language rules above. The three-argument Get returns an empty string when nothing is stored for the requested language.
LanguageId is a Windows locale ID — an integer such as 1031 (German), 1036 (French) or 1030 (Danish). The tests pass several distinct IDs and never rely on the language the test session happens to run in.
Pick object IDs in the 50100–50199 range and reference other objects by name, never by ID.
What the tests check
The grading tests insert products and store generated description values for two languages, then read each language back; ask for a language with no stored value and expect the Description field value; store twice for the same language and expect the latest value; duplicate a product and expect the new record to carry the Description and both translations; and delete a product with Delete(true), using the module's own GetTranslations to assert that the product's two translations actually live in the Translation module before the deletion and zero rows remain after it, while a second product keeps its own translation.
Learn More
- Translation codeunit (System Application) — the full API you will build on:
Set,Get,Copy,Delete,GetTranslations. - OnDelete (table) trigger — where record cleanup belongs and when the trigger actually runs.
- Record.Delete method — why the
RunTriggerargument decides whether your cleanup fires. - Record.FieldNo method — how to hand the
Descriptionfield's number to the Translation API.
Translation is a per-record, per-field, per-language store. It keys every row by the record's SystemId, so a product must be inserted before you attach translations to it.Set(Rec, FieldId, LanguageId, Value) and read with the three-argument Get(Rec, FieldId, LanguageId) — it returns an empty string when nothing is stored for that language, which is your cue to return the Description field instead. Get the field number via FieldNo.Translation.Copy(FromRec, ToRec) carries every stored language to the duplicate in one call, and Translation.Delete(Rec) in the table's OnDelete trigger removes that record's rows. Note the overloads: Delete with a table ID would wipe every product's translations, not just the deleted one's.