Take the community feedback survey now.

Deepmala S
Sep 3, 2025
  943
(0 votes)

Custom Deepl Glossary Translation in Optimizely CMS

Introduction in this post, I have created a custom DeepL glossary translation for specific words. For example, when translating from English to German, the standard translation for "Hello" is "Hallo." However, using my custom DeepL glossary, I want "Hello" to be translated as a custom word like "Ollha." This custom translation will override the normal Optimizely auto-translation and ensure that the glossary-defined terms are used instead.

Repository link for reference

https://github.com/mattpallatt/MP.LanguageManager.DeepLTranslate

 

1)      Install nuget package MP.LanguageManager.DeepLTranslate

 dotnet add package MP.LanguageManager.DeepLTranslate --version 1.0.9

2) Create DeepLTranslateProvider class

 
public class DeepLTranslateProvider : IMachineTranslatorProvider
    {
        private readonly Injected<IOptions<DeepLOptions>> _options;

        public string DisplayName => "DeepL Web Translator";

        public DeepL.Formality DLFormality = DeepL.Formality.Default;
        public string EnglishType = "";
        public string authkey = "";
        public string AutoGlossary = "";
        public string GlossaryList = "";

        public bool Initialize(ITranslatorProviderConfig config)
        {
            var languageManagerOptions = new LanguageManagerOptions();
            var languageManagerConfig = new LanguageManagerConfig(languageManagerOptions);
            authkey = languageManagerConfig.ActiveTranslatorProvider.SubscriptionKey;
            var options = _options.Service.Value;
            var dlfv = "default";

            try
            {
                dlfv = (options.Formality.ToLower() == "default" || options.Formality.ToLower() == "more" || options.Formality.ToLower() == "less" || options.Formality.ToLower() == "preferless" || options.Formality.ToLower() == "prefermore") ? options.Formality.ToLower() : dlfv;
                EnglishType = (options.English.ToLower() == "en-gb" || options.English.ToLower() == "en-us") ? options.English.ToLower() : "en-gb";
                AutoGlossary = (options.AutoGlossary == "0" || options.AutoGlossary == "1") ? options.AutoGlossary : AutoGlossary;
                GlossaryList = options.GlossaryList;
            }
            catch { }

            // free API authorisation keys end in :fx...
            if (authkey.EndsWith(":fx"))
            {
                // ...set the formality to Default, as this is a Pro feature
                DLFormality = DeepL.Formality.Default;
            }
            else
            {
                DLFormality = dlfv.ToLower() switch
                {
                    "less" => DeepL.Formality.Less,
                    "more" => DeepL.Formality.More,
                    "preferless" => DeepL.Formality.PreferLess,
                    "prefermore" => DeepL.Formality.PreferMore,
                    _ => DeepL.Formality.Default,
                };
            }
            return true;
        }

        public TranslateTextResult Translate(string inputText, string sourceLanguage, string targetLanguage)
        {
            var translateTextResult = new TranslateTextResult
            {
                IsSuccess = true,
                Text = ""
            };

            if (string.IsNullOrWhiteSpace(inputText))
            {
                return translateTextResult;
            }

            try
            {
                var n = DoTranslate(inputText, sourceLanguage, targetLanguage);
                n.Wait();

                translateTextResult.Text = n.Result.ToString();
                translateTextResult.IsSuccess = true;
            }
            catch (Exception ex)
            {
                translateTextResult.IsSuccess = false;
                translateTextResult.Text = "An unexpected error occurred: " + ex.Message + ex.InnerException;
            }

            return translateTextResult;
        }
        public async Task<TextResult> DoTranslate(string inputText, string sourceLanguage, string targetLanguage)
        {

            var slci = new CultureInfo(sourceLanguage);
            var tlci = new CultureInfo(targetLanguage);
            string tl = tlci.TwoLetterISOLanguageName.ToString();

            // deal with PT, ZH (xx-xx) language codes
            if (tl == "pt" || tl == "zh")
            {
                tl = targetLanguage;
            }
            // dealing with depreciated "en" target language code using default EN code
            else if (tl == "en")
            {
                tl = EnglishType;
            }
            // reset the glossary ID
            string glossaryID = "";

            var translator = new DeepL.Translator(authkey);

            if ((AutoGlossary == "1") || (GlossaryList.Contains($"[{slci}>{tlci}]")))
            {
                System.Threading.Tasks.Task<GlossaryInfo[]> n = translator.ListGlossariesAsync();
                n.Wait();
                List<GlossaryInfo> GI = n.Result.ToList();
                glossaryID = GI.FirstOrDefault(item => item.SourceLanguageCode == slci.ToString() && item.TargetLanguageCode == tlci.ToString())?.GlossaryId;
            }

            var translatedText = await translator.TranslateTextAsync(
                inputText,
                slci.TwoLetterISOLanguageName.ToUpper(),
                tl.ToUpper(),
                new TextTranslateOptions { Formality = DLFormality, TagHandling = "html", GlossaryId = glossaryID }
                );

            return translatedText;
        }
    }
     public class DeepLOptions
    {
        public string Formality { get; set; }
        public string English { get; set; }
        public string AutoGlossary { get; set; }
        public string GlossaryList { get; set; }
        public string ignoreExistingPages { get; set; }
    }

3) Create API Controller

 [HttpPost]
 [Route("/api/v1/glossary/create")]
 public async Task<ActionResult> Create([FromBody] GlossaryDTO glossaryDTO)
 {
     var timer = Stopwatch.StartNew();
     GlossaryInfo glossaryInfo = null;

     try
     {
          if (glossaryDTO != null)

         {
             glossaryInfo = await _glossary.CreateGlossaryAsync(glossaryDTO.Name, glossaryDTO.SourceLang, glossaryDTO.TargetLang, glossaryDTO.GlossaryEntries);
         }

     }
     catch (Exception ex)
     {
         _logger.LogError(nameof(Index), ex, "Error GlossaryController getting GlossaryController");
         return StatusCode(500, new { message = ex.Message });
     }

     timer.Stop();

     _logger.LogInformation(nameof(Index), $"Timer took {timer.ElapsedMilliseconds}ms");

     return new JsonResult(new { message = glossaryInfo != null ? "Glossary has been created" : "Glossary is not created", glossary = glossaryInfo });

 }

4)  Do App setting configurations

5)   Set up Deepl Web Translator in Language manager plug in.

        To use the DeepL Translator to perform automated translations make sure it's selected as Translator Provider in the settings of the Language Manager

6)   Create Glossary block and on view create glossaries. Set access right on block hide from visitors. 

6)    Do auto translation from Language gadget.




 

 

Sep 03, 2025

Comments

Please login to comment.
Latest blogs
Optimizely: Multi-Step Form Creation Through Submission

I have been exploring Optimizely Forms recently and created a multi-step Customer Support Request Form with File Upload Functionality.  Let’s get...

Madhu | Oct 25, 2025 |

How to Add Multiple Authentication Providers to an Optimizely CMS 12 Site (Entra ID, Google, Facebook, and Local Identity)

Modern websites often need to let users sign in with their corporate account (Entra ID), their social identity (Google, Facebook), or a simple...

Francisco Quintanilla | Oct 22, 2025 |

Connecting the Dots Between Research and Specification to Implementation using NotebookLM

Overview As part of my day to day role as a solution architect I overlap with many clients, partners, solutions and technologies. I am often...

Scott Reed | Oct 22, 2025

MimeKit Vulnerability and EPiServer.CMS.Core Dependency Update

Hi everyone, We want to inform you about a critical security vulnerability affecting older versions of the EPiServer.CMS.Core  package due to its...

Bien Nguyen | Oct 21, 2025

Speeding Up Local Development with a Fake OpenID Authentication Handler

When working with OpenID authentication, local development often grinds to a halt waiting for identity servers, clients, and users to be configured...

Eric Herlitz | Oct 20, 2025 |

How Optimizely MCP Learns Your CMS (and Remembers It)

In Part 1, I introduced the “discovery-first” idea—an MCP that can plug into any SaaS CMS and learn how it’s structured on its own. This post gets...

Johnny Mullaney | Oct 20, 2025 |