Table of Contents

TMS FNC Cloud Translation Guides

TTMSFNCCloudTranslation translates text and detects languages through a cloud translation provider. One component covers every supported provider: you set Service and APIKey, and Translate, Detect and GetSupportedLanguages behave the same way regardless of which one is selected. That makes the provider a configuration choice rather than a code choice — useful when pricing, regional data residency or language coverage decides it. This page covers selecting and authenticating a provider, the Microsoft-specific endpoint and region settings, translating and detecting, and combining the two.

Supported services

Service takes a TTMSFNCCloudTranslationService value:

Value Provider Credentials
tsGoogle Google Cloud Translation APIKey
tsMicrosoft Microsoft Translator APIKey, plus ServiceEndPoint / ServiceRegion for a regional resource
tsDeepL DeepL APIKey
Important

The IBM Translator service API was removed. There is no longer an IBM value in TTMSFNCCloudTranslationService, so code or a stored setting that selected it must be migrated to one of the three services above, with that provider's own API key. See Release notes for the version this happened in.

Because the provider is usually a stored setting rather than a literal, map it in one place and handle the retired IBM value explicitly instead of letting it fall through to a default:

function TForm1.ApplyTranslationService(const AConfiguredService: string): Boolean;
begin
  Result := True;

  // ServiceEndPoint and ServiceRegion are Microsoft-only, so clear them
  // before selecting another provider.
  TMSFNCCloudTranslation1.ServiceEndPoint := '';
  TMSFNCCloudTranslation1.ServiceRegion := '';

  if SameText(AConfiguredService, 'Google') then
    TMSFNCCloudTranslation1.Service := tsGoogle
  else if SameText(AConfiguredService, 'DeepL') then
    TMSFNCCloudTranslation1.Service := tsDeepL
  else if SameText(AConfiguredService, 'Microsoft') then
  begin
    TMSFNCCloudTranslation1.Service := tsMicrosoft;
    TMSFNCCloudTranslation1.ServiceRegion := 'westeurope';
  end
  else if SameText(AConfiguredService, 'IBM') then
  begin
    // The IBM Translator service API was removed, so
    // TTMSFNCCloudTranslationService no longer has an IBM value: an old
    // stored setting has to be migrated to a supported service, with its
    // own APIKey.
    TMSFNCCloudTranslation1.Service := tsGoogle;
    TMSFNCCloudTranslation1.APIKey := '';
    ShowMessage('The IBM translation service is no longer available. ' +
      'Select another provider and enter its API key.');
    Result := False;
  end
  else
    Result := False;
end;

Microsoft Translator endpoints and regions

Google and DeepL are reached on a single global host, but a Microsoft Translator resource may be global or regional, and a regional one rejects requests that do not name its region. Two properties cover this:

Property Effect when set Effect when empty
ServiceEndPoint Used as the request host, for a custom or regional resource Falls back to the global https://api.cognitive.microsofttranslator.com
ServiceRegion Sent as the Ocp-Apim-Subscription-Region header The header is omitted entirely

Both apply to Translate, Detect and GetSupportedLanguages alike. A regional key used without ServiceRegion typically fails authentication, so set the region whenever the resource was not created as global.

procedure TForm1.ConfigureMicrosoftTranslator;
begin
  TMSFNCCloudTranslation1.Service := tsMicrosoft;
  TMSFNCCloudTranslation1.APIKey := 'your-translator-subscription-key';

  // ServiceEndPoint replaces the global host. Leave it empty to use
  // https://api.cognitive.microsofttranslator.com; set it when the resource
  // was created with a custom or regional endpoint.
  TMSFNCCloudTranslation1.ServiceEndPoint := 'https://my-translator.cognitiveservices.azure.com';
  // ServiceRegion is sent as the Ocp-Apim-Subscription-Region header, which a
  // regional (non-global) resource requires. An empty value omits the header.
  TMSFNCCloudTranslation1.ServiceRegion := 'westeurope';

  TMSFNCCloudTranslation1.OnTranslate := TranslationDone;
  TMSFNCCloudTranslation1.Translate('Good morning', 'nl');
end;

procedure TForm1.TranslationDone(Sender: TObject;
  const ARequest: TTMSFNCCloudTranslationRequest;
  const ARequestResult: TTMSFNCCloudBaseRequestResult);
begin
  if not ARequestResult.Success then
  begin
    // A 401 here usually means the key is regional but ServiceRegion is empty.
    ShowMessage('Translation failed: ' + ARequestResult.ResultString);
    Exit;
  end;

  if ARequest.Translations.Count > 0 then
    Edit1.Text := ARequest.Translations[0].TranslatedText;
end;

Translating and detecting

Translate accepts a single string or a TStringList for a batch, plus the target language code. Detect reports the language of a string without translating it. GetSupportedLanguages fills SupportedLanguages with the codes the selected provider accepts, named in the language you pass.

Each method reports either through its event — OnTranslate, OnDetect, OnGetSupportedLanguages — or through an optional callback argument, which keeps a multi-step flow in one place. Results arrive on the TTMSFNCCloudTranslationRequest: Translations[i].TranslatedText alongside SourceText and SourceLanguage, and Detections[i].SourceLanguage. Always check ARequestResult.Success first, and read ARequestResult.ResultString for the provider's error detail.

Combining detection and translation

Detecting first lets you skip the translation call when the text is already in the target language, which saves a request per item on a large batch. The callback overloads chain the two steps without splitting the logic across two event handlers:

{ FPendingText is a private string field on the form, holding the text
  between the Detect and the Translate step. }
procedure TForm1.TranslateIfNeeded(const AText: string);
begin
  // A regional Microsoft resource needs both the endpoint and the region, and
  // both apply to the Detect call as much as to Translate.
  TMSFNCCloudTranslation1.Service := tsMicrosoft;
  TMSFNCCloudTranslation1.APIKey := 'your-translator-subscription-key';
  TMSFNCCloudTranslation1.ServiceEndPoint := 'https://my-translator.cognitiveservices.azure.com';
  TMSFNCCloudTranslation1.ServiceRegion := 'westeurope';

  FPendingText := AText;

  // The callback overload keeps the two steps together instead of splitting
  // them across OnDetect and OnTranslate.
  TMSFNCCloudTranslation1.Detect(AText,
    procedure(const ARequest: TTMSFNCCloudTranslationRequest;
      const ARequestResult: TTMSFNCCloudBaseRequestResult)
    begin
      if not ARequestResult.Success or (ARequest.Detections.Count = 0) then
        Exit;

      Label1.Text := 'Detected: ' + ARequest.Detections[0].SourceLanguage;

      // Nothing to do when the text is already in the target language.
      if SameText(ARequest.Detections[0].SourceLanguage, 'nl') then
      begin
        Edit1.Text := FPendingText;
        Exit;
      end;

      TMSFNCCloudTranslation1.Translate(FPendingText, 'nl',
        procedure(const ATransRequest: TTMSFNCCloudTranslationRequest;
          const ATransResult: TTMSFNCCloudBaseRequestResult)
        begin
          if ATransResult.Success and (ATransRequest.Translations.Count > 0) then
            Edit1.Text := ATransRequest.Translations[0].TranslatedText;
        end);
    end);
end;

Common mistakes

  • Selecting a retired provider. IBM Translator is gone; a stored 'IBM' setting must be migrated rather than defaulted silently.
  • Leaving ServiceRegion empty for a regional Microsoft key. The Ocp-Apim-Subscription-Region header is then omitted and the request fails authentication.
  • Leaving ServiceEndPoint or ServiceRegion set after switching provider. They are Microsoft-only; clear them when selecting tsGoogle or tsDeepL.
  • Reading the result after the method returns. Translate and Detect return before the provider answers, so the data is only available in the event or callback. The TStringList you pass is copied internally, so freeing it right after the call is safe — the result is not.
  • Assuming every provider accepts the same language codes. Call GetSupportedLanguages and validate the target code against SupportedLanguages after changing Service.

See also