Editing translations
The editor is where translation actually happens. It presents the strings a Collector gathered as an editable grid, lets you add and manage the application's languages, adjust the collection rules, and translate — by hand or with an AI service. It also does the housekeeping for you: it analyzes the application when it opens and saves the translations when it closes, so you never call analyze or save around it. Most teams use it at design time (open it from the IDE on the dropped component), but the same editor can be launched at runtime with Execute, for example to let end users or translators edit translations in a running tool. This guide covers opening the editor, reading its result, saving, and the non-blocking callback overload. If your collector is not gathering strings yet, start with the Collector guide.
Opening the editor
Simply call Execute. On opening, the editor analyzes the running application through the collector so the grid reflects the current UI — you do not call AnalyzeApplication first. It then shows the collected strings and settings across its tabs.
Translation tab
The Translations tab is the central place for applying translations for gathered strings. It contains the model treeview and the editable grid of strings per language. You can apply several filters for the grid, and it supports multi selection and context menus to allow batch handling of items.
Languages tab
The Languages tab defines which languages the project targets and which one is the source. A language can be included or excluded, and excluding one does not throw away translations already made for it, it only stops the ComboBox and Localizer making it available as a selectable language.
The set of included languages is also what decides which plural slots a number snippet needs, so adding a language with a different plural system will make new slots appear for translation.
Rules tab
The Rules tab controls what the collector considers worth translating in the first place, by class and property name. Rules are how Name, StyleLookup and similar structural properties stay out of the tree. You can add your own for your own components.
Read-only properties are excluded automatically: a property with no setter cannot receive a translation, so the collector does not offer it.
AI Settings tab
The AI Settings tab allows you to select an AI service and fill in the necessary API key or localhost settings. It is not mandatory to use this in case of a manual or XLIFF-based translations.
Exchange tab
The Exchange tab moves work in and out of the project for translators who work in their own tools.
Export writes one bilingual XLIFF 1.2 document per target language, filtered by translation status, and tells you the unit count before the save dialog opens.
Import shows you what a file would do before it does anything. Every unit is classified — New, Updated, Unchanged, Source changed, Protected, Placeholder, Not matched — with the reason, and only New and Updated can be selected. Apply is labelled with its count and refuses the batch if the model changed after the file was read.
Source drift is caught either by comparing the source the tool returned, or, for tools that strip the source, by a hash written into the file.
XLIFF is an exchange format, not a project format. An .xlf cannot be loaded as your model, deliberately.
Saving is automatic
You do not save the translations yourself. On VCL and FMX the editor writes them back to the collector's configured translation folder (or files) when it closes; on TMS WEB Core — where the browser cannot write files silently — the editor offers a Download button to save instead. Either way, calling Collector.SaveToFile after Execute is unnecessary.
Execute returns no result — the Modified property is what reports whether the translations actually changed. Use it to react — refresh a running UI, re-apply the active language, mark a project dirty — not to trigger a save:
procedure TForm1.EditTranslations;
begin
{ Open the editor. It analyzes the application when it opens, lets the user
translate, and (on VCL and FMX) saves the translations to the collector's
folder when it closes - no manual analyze or save is required. }
Editor.Execute;
end;
When does Execute return?
Whether Execute blocks depends on where it runs:
| Context | The editor is shown | Execute returns |
|---|---|---|
| Design time (opened from the IDE) | modally | after the editor closes |
| Run time | non-modally | immediately, while the editor is still open |
| TMS WEB Core | never modally | immediately |
So outside a design-time host, put your "after close" logic in the callback rather than after the call. The callback's shape follows the framework, so the two are not interchangeable: a TNotifyEvent — a method pointer, so the handler must be a method of your form — receiving the editor as Sender; or, on TMS WEB Core, a TModalResultProc, which accepts an anonymous procedure and receives the modal result the dialog was closed with. Read Modified from the handler either way:
{$IFNDEF WEBLIB}
{ The callback is a TNotifyEvent - a method pointer - so the handler is a method
of your form, not an anonymous procedure. }
procedure TForm1.EditorClosed(Sender: TObject);
begin
RefreshUI;
end;
{$ENDIF}
procedure TForm1.EditTranslationsAsync;
begin
{ At run time Execute returns while the editor is still open, so the "after
close" work belongs in the callback. The translations are already persisted
by then - use it only to react, for example to refresh the UI. }
{$IFDEF WEBLIB}
{ On TMS WEB Core the callback is a TModalResultProc, so an anonymous
procedure works and it receives the result the dialog closed with. }
Editor.Execute(
procedure(AResult: TModalResult)
begin
RefreshUI;
end);
{$ELSE}
Editor.Execute(EditorClosed);
{$ENDIF}
end;
Putting it together: collector and editor
The collector and the editor cover the whole gather-edit-save loop between them, with almost no code of your own. The collector's LocalizationFolder decides where the translations live; the editor analyzes the application, edits the strings, and saves them back to that folder — so the setup is just "point the collector at a folder, hand it to the editor, and open it":
procedure TForm1.EditTranslations;
begin
{ The collector defines where the translations live. }
Collector.LocalizationFolder := 'Translations';
{ The editor analyzes the application, edits the strings, and (on VCL and FMX)
saves them back to that folder on close - the collector and editor handle
the whole gather-edit-save loop between them. }
Editor.Execute;
end;
Common pitfalls
- Do not analyze or save around
Execute. The editor analyzes the application on open and saves on close by itself — callingCollector.AnalyzeApplicationbeforeExecuteorCollector.SaveToFileafter it is redundant (and on the web, saving is done from the editor's Download button).