Editor language
The Localization Editor is localized itself. Its tabs, buttons, grid headers, status lines, and messages ship translated into English, German, French and Japanese, so the people who translate your application can work in a language they are comfortable with. This page explains how the editor picks its language, at design time and at run time. It also covers what to do when your translators need a language that is not built in. Choose between the two approaches like this. Use the built-in locales when one of the four languages is good enough, because it needs no setup at all. Use custom translation when you want the editor in another language or with your own terminology. In that case you translate the editor's UI with the same workflow you use for your own forms.
At design time: follows the IDE
When you open the editor from the IDE, it uses the language of the IDE. A German RAD Studio shows a German editor, and a Japanese RAD Studio shows a Japanese one, without any setting on your part. The editor reads the IDE's UI language from the same registry entry RAD Studio uses (Software\Embarcadero\Locales). When no language is configured, or the IDE runs in a language the editor does not ship, it falls back to English.
At run time: choose a built-in locale
At run time there is no IDE to follow, so the editor opens in English. To pick one of the built-in languages, call the Execute overload that takes a locale as its first parameter. Pass 'en', 'de', 'fr' or 'ja'. The value is case-insensitive:
procedure TFormMain.btnTranslateGermanClick(Sender: TObject);
begin
{ Opens the editor UI in German. 'en', 'de', 'fr' and 'ja' are built in;
any other value is ignored and the default language is used. }
LocalizationEditor.Execute('de');
end;
procedure TFormMain.btnTranslateFrenchClick(Sender: TObject);
begin
{ The close callback works the same as with the plain Execute overload. }
LocalizationEditor.Execute('fr', EditorClosed);
end;
procedure TFormMain.EditorClosed(Sender: TObject);
begin
{ The translations are already saved; refresh text your code builds. }
UpdateStatus;
end;
void __fastcall TFormMain::btnTranslateGermanClick(TObject *Sender)
{
// Opens the editor UI in German. "en", "de", "fr" and "ja" are built in;
// any other value is ignored and the default language is used.
LocalizationEditor->Execute("de");
}
void __fastcall TFormMain::btnTranslateFrenchClick(TObject *Sender)
{
// The close callback works the same as with the plain Execute overload.
LocalizationEditor->Execute("fr", EditorClosed);
}
void __fastcall TFormMain::EditorClosed(TObject *Sender)
{
// The translations are already saved; refresh text your code builds.
UpdateStatus();
}
The overload behaves exactly like the plain Execute, including the optional close callback. It is non-blocking at run time, so put "after close" work in the callback. Some details are worth knowing:
- The choice is per call. The locale applies to the editor you are opening and is reset when it closes. The next plain
Executeuses the default again. - Unknown locales are ignored, not rejected. Any value other than the four built-in ones is ignored, and the editor opens in its default language. No exception is raised, so a value taken straight from your application's active language is safe to pass.
- It does not change your application's language. The editor's own translations are kept apart from your application's translation file and from the localizer's active language.
- Desktop only. The built-in locale selection applies to VCL and FMX applications.
Custom translation: translate the editor yourself
When your translators need the editor in a language that is not built in, such as Dutch, Polish, or Italian, or you want to adjust its wording, set the public property AllowCustomTranslation to True before calling Execute. The editor then stops using its built-in translations and treats its own UI like any other part of your application:
- The editor window is no longer excluded from collection, so its controls are gathered under Forms like your own forms.
- Its messages and status texts are registered as snippets under the
Editor.prefix, for exampleEditor.StatusReady. - Collection rules are added so that the editor's list columns and its AI settings component are picked up as well.
You translate these entries with the editor, in the same way as the rest of your application, and they are saved to your translations.json. From then on, the editor follows your application's active language, as set by the localizer or a TTMSFNCLocalizationComboBox, instead of a built-in locale:
procedure TFormMain.btnTranslateClick(Sender: TObject);
begin
{ Skip the built-in editor translations: the editor's controls and its
Editor.* message snippets are collected into the application's
translation file and translated like any other string. }
LocalizationEditor.AllowCustomTranslation := True;
{ The editor now follows the application's active language, for example
Dutch, once its entries are translated and approved. }
LocalizationEditor.Execute;
end;
void __fastcall TFormMain::btnTranslateClick(TObject *Sender)
{
// Skip the built-in editor translations: the editor's controls and its
// Editor.* message snippets are collected into the application's
// translation file and translated like any other string.
LocalizationEditor->AllowCustomTranslation = true;
// The editor now follows the application's active language, for example
// Dutch, once its entries are translated and approved.
LocalizationEditor->Execute();
}
AllowCustomTranslation is public, not published, so set it in code. It defaults to False. While it is True, the locale parameter of Execute has no effect, because the editor's language comes from your own translations.
Putting it together: a translator tool
An in-house translation tool often needs both approaches. Translators who are happy with a built-in language get it directly. Everyone else gets the editor in the application's own language. The handler below opens the editor in the application's active language when that is one of the built-in four. Otherwise it switches to custom translation, so the strings you translated for the editor are used:
procedure TFormMain.SwitchLanguage(const ALocale: string);
begin
{ Track the active application language where you switch it. }
if DM.Localizer.TrySetLocale(ALocale) then
FLocale := LowerCase(ALocale);
end;
procedure TFormMain.btnTranslateClick(Sender: TObject);
const
BuiltInLocales: array[0..3] of string = ('en', 'de', 'fr', 'ja');
var
vBuiltIn: Boolean;
vLocale: string;
begin
vBuiltIn := False;
for vLocale in BuiltInLocales do
if vLocale = FLocale then
vBuiltIn := True;
{ Built-in language available: no setup needed. Otherwise use the
translations made for the editor in the application's own file. }
LocalizationEditor.AllowCustomTranslation := not vBuiltIn;
if vBuiltIn then
LocalizationEditor.Execute(FLocale)
else
LocalizationEditor.Execute;
end;
void __fastcall TFormMain::SwitchLanguage(const System::UnicodeString ALocale)
{
// Track the active application language where you switch it.
if (DM->Localizer->TrySetLocale(ALocale))
FLocale = LowerCase(ALocale);
}
void __fastcall TFormMain::btnTranslateClick(TObject *Sender)
{
const System::UnicodeString BuiltInLocales[] = {"en", "de", "fr", "ja"};
bool vBuiltIn = false;
for (const System::UnicodeString &vLocale : BuiltInLocales)
if (vLocale == FLocale)
vBuiltIn = true;
// Built-in language available: no setup needed. Otherwise use the
// translations made for the editor in the application's own file.
LocalizationEditor->AllowCustomTranslation = !vBuiltIn;
if (vBuiltIn)
LocalizationEditor->Execute(FLocale);
else
LocalizationEditor->Execute();
}
Common pitfalls
- Set
AllowCustomTranslationbeforeExecute. It is read when the editor opens. Changing it while the editor is open has no effect until the nextExecute. - Custom translation adds the editor's strings to your translation file. The editor form and the
Editor.*snippets become part oftranslations.jsonand ship with it. Enable custom translation only in builds that actually open the editor, such as a translator edition, if you want to keep the shipped file lean. - The first run shows the editor untranslated. With custom translation on, the editor's UI is collected the first time it opens, so it appears in the source language until you translate and approve its entries.
- Approve the editor's translations too. Like every other string, an editor translation that is still Proposed is not applied.
- Only four locales are built in.
Execute('nl')silently opens the default language. Use custom translation for any other language.