Sdl Sdk Project Automation Use Template and PreTranslateFiles using Server Based Translation Memories

How is it possible to run AutomaticTask.PreTranslateFiles, using server based Translation Memories?

MainTranslationProviderItem Uri="sdltm.gsdemo.gs.sdlproducts.com/ Global Solution Consultants%2FBC Translation Productivity%2FSDL EMEA LSP%2FSDL LSP Trials%2F{CompanyName}&tmName={TmName}" Enabled="true
private void RunAutomaticTask(FileBasedProject ThisSdlProject, string TargetLanguageCode){
    ProjectFile[] targetFiles = ThisSdlProject.GetTargetLanguageFiles(new Language(CultureInfo.GetCultureInfo(TargetLanguageCode)));
    AutomaticTask preTranslate = ThisSdlProject.RunAutomaticTask(targetFiles.GetIds(), AutomaticTaskTemplateIds.PreTranslateFiles);
}

I get the error: "The current parameters are not compatible with the Translation Provider Uri Schema"

  • Hi ,

    Can you please give me more details about what you are trying to achieve and the steps you are doing? 

    What I've tried:

    1. On the active project I have set a server based tm
    2. I get the project programatically and I ran the pre-translate
    3. No error appear using code bellow

    var projectsController = SdlTradosStudio.Application.GetController<ProjectsController>();
    var activeProject = projectsController?.CurrentProject;
    var targetFiles = activeProject.GetTargetLanguageFiles(new Language(new CultureInfo("de-de")));
    var result = activeProject.RunAutomaticTask(targetFiles.GetIds(), AutomaticTaskTemplateIds.PreTranslateFiles);

    Kind reagrds,

    Andrea Ghisa

  • This is my code:

    namespace Sdl.Sdk.ProjectGroupShareAssets
    {
        using System;
        using System.Globalization;
        using Sdl.Core.Globalization;
        using Sdl.ProjectAutomation.Core;
        using Sdl.ProjectAutomation.FileBased;
        using System.Xml;
    
        public class ProjectCreator
        {
            public void Create(
                string SourceFiles,
                string SdlProjectPath,
                string SdlTemplateFile
            )
            {
                ProjectTemplateReference SdlTemplateReference = new ProjectTemplateReference(SdlTemplateFile);
    
                XmlDocument XmlTemplateFile = new XmlDocument();
                XmlTemplateFile.Load(SdlTemplateFile);
                XmlNode LanguageDirectionNode = XmlTemplateFile.DocumentElement.SelectSingleNode("/ProjectTemplate/LanguageDirections/LanguageDirection");
                string SourceLanguageCode = LanguageDirectionNode.Attributes["SourceLanguageCode"].InnerText;
                string TargetLanguageCode = LanguageDirectionNode.Attributes["TargetLanguageCode"].InnerText;
    
                FileBasedProject NewSdlProject = new FileBasedProject(this.GetProjectInformation(SourceLanguageCode, TargetLanguageCode, SdlProjectPath), SdlTemplateReference);
    
                this.AddFilesToProject(NewSdlProject, SourceFiles);
                this.ConvertFiles(NewSdlProject);
                this.RunAutomaticTask(NewSdlProject, TargetLanguageCode, "PrepareWithoutProjectTm");
                NewSdlProject.Save();
            }
    
            private ProjectInfo GetProjectInformation(string SourceLanguageCode, string TargetLanguageCode, string SdlProjectPath)
            {
                ProjectInfo info = new ProjectInfo();
                info.Name = "TestProject";
                string[] DateArray = "2020-02-28".Split('-');
                int year = Convert.ToInt32(DateArray[0]);
                int month = Convert.ToInt32(DateArray[1]);
                int day = Convert.ToInt32(DateArray[2]);
                info.DueDate = new DateTime(year, month, day, 12, 0, 0, 0);
                string localProjectFolder = @"" + SdlProjectPath;
                info.LocalProjectFolder = localProjectFolder;
                Language srcLang = new Language(CultureInfo.GetCultureInfo(SourceLanguageCode));
                info.SourceLanguage = srcLang;
                Language[] trgLang = new Language[] { new Language(CultureInfo.GetCultureInfo(TargetLanguageCode)) };
                info.TargetLanguages = trgLang;
                return info;
            }
    
            private void AddFilesToProject(FileBasedProject ThisSdlProject, string folder)
            {
                ThisSdlProject.AddFolderWithFiles(folder, true);
                ProjectFile[] projectFiles = ThisSdlProject.GetSourceLanguageFiles();
                AutomaticTask scan = ThisSdlProject.RunAutomaticTask(
                    projectFiles.GetIds(),
                    AutomaticTaskTemplateIds.Scan
                );
                ProjectFile[] files = ThisSdlProject.GetSourceLanguageFiles();
                for (int i = 0; i < ThisSdlProject.GetSourceLanguageFiles().Length; i++)
                {
                    Guid[] currentFileId = { files[i].Id };
                    string currentFileName = files[i].Name;
                    ThisSdlProject.SetFileRole(currentFileId, FileRole.Translatable);
                }
                AutomaticTask pre_scan = ThisSdlProject.RunAutomaticTask(
                    projectFiles.GetIds(),
                    AutomaticTaskTemplateIds.Scan
                );
            }
    
            private void ConvertFiles(FileBasedProject ThisSdlProject)
            {
                ProjectFile[] files = ThisSdlProject.GetSourceLanguageFiles();
    
                for (int i = 0; i < ThisSdlProject.GetSourceLanguageFiles().Length; i++)
                {
                    if (files[i].Role == FileRole.Translatable)
                    {
                        Guid[] currentFileId = { files[i].Id };
                        AutomaticTask convertTask = ThisSdlProject.RunAutomaticTask(
                            currentFileId,
                            AutomaticTaskTemplateIds.ConvertToTranslatableFormat
                        );
                        AutomaticTask copyTask = ThisSdlProject.RunAutomaticTask(
                            currentFileId,
                            AutomaticTaskTemplateIds.CopyToTargetLanguages
                        );
                    }
                }
            }
    
            private void RunAutomaticTask(FileBasedProject ThisSdlProject, string TargetLanguageCode, string AutomaticTaskOption)
            {
                ProjectFile[] targetFiles = ThisSdlProject.GetTargetLanguageFiles(new Language(CultureInfo.GetCultureInfo(TargetLanguageCode)));
                AutomaticTask preTranslate = ThisSdlProject.RunAutomaticTask(targetFiles.GetIds(), AutomaticTaskTemplateIds.PreTranslateFiles);
            }
        }
    }

    This is my error (within the sdlproj file):

    <Messages Level="Error" Message="Unexpected exception when configuring file multiFileConverter for task 'Pre-translate Files': Failed to create an instance of translation provider 'sdltm.gsdemo.gs.sdlproducts.com/ Global Solution Consultants%2FBC Translation Productivity%2FSDL EMEA LSP%2FSDL LSP Trials%2F{COMPANY}&amp;tmName=Fruits TM'.." Source="Pre-translate Files">
  • Hi,

    The format of the Uri is wrong and you shouldn't create it manually. 

    I've created a code sample here in which you'll see how to properly create a TranslationProviderCascadeEntry containig a serverTM reference and adding it to a project.

    Best regards,

    Emanuel

  • Hi Emanuel,

    I didn't create the Uri manually, the example in my post is what is exactly in the Sdl Project Template file.

    So I don't want to add a server Tm as it is already defined within the template.

    I am currently getting errors when using the template that already contains references to server Tms.

    Is it just a case then of adding the server credentials?..:

    project.Credentials.AddCredential(new Uri(serverAddress),
    	$"user={username};password={password};type={(useWindowsSecurity ? "WindowsUser" : "CustomUser")}");
    project.UpdateTranslationProviderConfiguration(config);

    Thanks for your advice

  • If it would be a credential problem, Studio would just hang... I tested this by creating a template which had a serverTM set and programatically running a pretranslate. It doesn't throw any exceptions, just hangs.

    By the way, here's another post of a user who had the same issue and fixed it (maybe it'll work for you too)

    From the error that you said you get, "the current parameters are not compatible with the Translation Provider Uri Schema", it would seem like the URI is not in the correct format (and it's not, if I look at other URIs in templates/projects I can see clear differences from the URI you provided). That's why I thought that maybe you've tried to write it manually and suggested that you should use the classes provided by the API to form it. 

    Can you provide the template you used?

    How did you create it?

    What version of Studio?

    Was it done programatically?

  • The SdlTemplate was created within "Trados Studio 2019 SR2 15.2.5.2145"; from project; and adding a server-based translation memory. So it is studio that is adding this to the template, not me.

    Either way, from Andrea's suggestion, I was able to create a project from the template and am no longer getting the Uri schema error.

    But I am still not able to programmatically pre-translate using the template/server Tm.

    My reply above shows my current code and the error that appears in the SDLProj file -> Reports:

    <Messages Level="Error" Message="Unexpected exception when configuring file multiFileConverter for task 'Pre-translate Files': Failed to create an instance of translation provider 'sdltm.gsdemo.gs.sdlproducts.com/ Global Solution Consultants%2FBC Translation Productivity%2FSDL EMEA LSP%2FSDL LSP Trials%2F{COMPANY}&amp;tmName=Fruits TM'.." Source="Pre-translate Files">

    Any thoughts?

    Thanks

  • Ok, good. Can you provide me the template?

    I tried to reproduce the issue but I cannot... for me everything works as it should. 

    You can send it to my work mail, ealbu@sdl.com

  • Also, does this happen when using another project as the template's base? It could be that the project's settings entry regarding the TM is broken...

  • Hi ,

    Thank you for reporting this issue.

    I have been able to diagnose two potential issues with the project automation API and will report them to the dedicated team so that they can address them appropriately.

    In the mean time I have a possible workaround that should be sufficient in getting you past this exception thrown by the plugin framework.

    The issue you reported is basically associated with how the credentials are recovered from the Studio instance.  There have been some changes to how we manage the credential identity since the initial release of the ‘ProjectCreator’ code example, to demonstrate how to automate the creation of an SDL project, which includes, adding both server and file based translation resources.

    The solution is to provide Studio with some additional information to ensure the credentials provided are associated correctly in the language platform, adding them to temporary identity cache that is required by the content processor in communicating with the server based resource in the background.
    Simply add the prefix ‘ps.’ to the server address; ‘ps’ denotes the URI as a project server.  So, if the URI saved in your project template resembles (sdltm.http://gs2017dev.sdl.com), then use (ps.http://gs2017dev.sdl.com) when adding the project credential.

    Example:
    <MainTranslationProviderItem Uri="sdltm.http://gs2017dev.sdl.com/?orgPath=%2FTest%20API%2FJonckers&amp;tmName=TM%20API_en-US_de-DE" Enabled="true" />
    Note: You don't need to change this.  The URI in the template is correct with the prefix 'sdltm'.  The credential identity requires the host part of the URI http://gs2017dev.sdl.com; (i.e. without the schema)

    You would add the following credential to the automation API, ensuring Studio can access and communicate with the server based resource correctly.

    var serverAddress = "ps.http://gs2017dev.sdl.com"
    var userName = "MyUserName";

    var password = "MyPassword";

    project.Credentials.AddCredential(new Uri(serverAddress), false, userName, password);

    I have provided here and more complete example; let me know how it goes.


    Full Example

    using Sdl.Core.Globalization;
    using Sdl.ProjectAutomation.Core;
    using Sdl.ProjectAutomation.FileBased;
    using System;
    using System.Globalization;
    using System.Xml;

    namespace ProjectAutomation_UseTemplate
    {
        public class ProjectCreator
        {
            public void Create(string sourceFilesDirectory, string projectDirectory, string projectReportDiectory, string projectTemplateFile)
            {
                GetLanguageDirectionFromTemplate(projectTemplateFile, out var sourceLanguage, out var targetLanguage);
                if (sourceLanguage == null || targetLanguage == null)
                {
                    return;
                }

                var projectInfo = GetProjectInformation(sourceLanguage, targetLanguage, projectDirectory);
                var templateReference = new ProjectTemplateReference(projectTemplateFile);
                var project = new FileBasedProject(projectInfo, templateReference);

                AddFilesToProject(project, sourceFilesDirectory);
               

                                // Example of how you would need to construct the URI when adding the credential (e.g. ps.[host])
                var serverAddress = "ps.http://gs2017dev.sdl.com";
                var userName = "MyUserName";
                var password = "MyPassword";

                project.Credentials.AddCredential(new Uri(serverAddress), false, userName, password);
                project.Save();

                ConvertFiles(project);
                RunPreTranslateFiles(project, targetLanguage);

                project.Save();
            }


            private static void GetLanguageDirectionFromTemplate(string projectTemplateFile, out string sourceLanguage, out string targetLanguage)
            {
                var xmlTemplateFile = new XmlDocument();
                xmlTemplateFile.Load(projectTemplateFile);

                var languageDirectionPath = "/ProjectTemplate/LanguageDirections/LanguageDirection";
                var languageDirectionNode = xmlTemplateFile.DocumentElement?.SelectSingleNode(languageDirectionPath);
                if (languageDirectionNode?.Attributes != null)
                {
                    sourceLanguage = languageDirectionNode.Attributes["SourceLanguageCode"].InnerText;
                    targetLanguage = languageDirectionNode.Attributes["TargetLanguageCode"].InnerText;
                    return;
                }

                sourceLanguage = null;
                targetLanguage = null;
            }

            private static ProjectInfo GetProjectInformation(string sourceLanguage, string targetLanguage, string projectDirectory)
            {
                var info = new ProjectInfo
                {
                    Name = "TestProject",
                    LocalProjectFolder = projectDirectory
                };

                var srcLang = new Language(CultureInfo.GetCultureInfo(sourceLanguage));
                info.SourceLanguage = srcLang;

                var trgLang = new[] { new Language(CultureInfo.GetCultureInfo(targetLanguage)) };
                info.TargetLanguages = trgLang;

                return info;
            }

            private static void AddFilesToProject(IProject project, string sourceFilesDirectory)
            {
                project.AddFolderWithFiles(sourceFilesDirectory, true);

                var projectFiles = project.GetSourceLanguageFiles();

                var scanResult = project.RunAutomaticTask(
                    projectFiles.GetIds(),
                    AutomaticTaskTemplateIds.Scan
                );

                var files = project.GetSourceLanguageFiles();

                for (var i = 0; i < project.GetSourceLanguageFiles().Length; i++)
                {
                    Guid[] currentFileId = { files[i].Id };

                    var currentFileName = files[i].Name;
                    project.SetFileRole(currentFileId, FileRole.Translatable);
                }

                var preScan = project.RunAutomaticTask(
                    projectFiles.GetIds(),
                    AutomaticTaskTemplateIds.Scan
                );
            }

            private static void ConvertFiles(IProject project)
            {
                var files = project.GetSourceLanguageFiles();

                for (var i = 0; i < project.GetSourceLanguageFiles().Length; i++)
                {
                    if (files[i].Role == FileRole.Translatable)
                    {
                        Guid[] currentFileId = { files[i].Id };
                        var convertTask = project.RunAutomaticTask(
                            currentFileId,
                            AutomaticTaskTemplateIds.ConvertToTranslatableFormat
                        );

                        var copyTask = project.RunAutomaticTask(
                            currentFileId,
                            AutomaticTaskTemplateIds.CopyToTargetLanguages
                        );
                    }
                }
            }

            private static void RunPreTranslateFiles(IProject project, string targetLanguage)
            {
                var targetFiles = project.GetTargetLanguageFiles(new Language(CultureInfo.GetCultureInfo(targetLanguage)));

                var preTranslate = project.RunAutomaticTask(
                    targetFiles.GetIds(),
                    AutomaticTaskTemplateIds.PreTranslateFiles);
            }
        }
    }

  • Hmmm, I would expect properly generic example, i.e. including the part for extracting the server address from the project template.

    Your example uses hardcoded server address, but in real life one doesn't know this; it's exactly the thing which is hidden inside the project template and needs to be obtained programmatically.

    Moreover, how does one obtain the username and password? These also cannot be hardcoded - these need to be obtained somehow from the user (or the user's machine) where the code is actually running.
    The programmer won't know these...