Sep 142011
 

Do you have issues receiving request or information in various languages and need it translated to English (or another language)? I found the need to translate something from any language to english just so when someone submits a case or puts some notes in another language it can quickly be translated.

Here is what my bing translator integration looks like.

You can download an unmanaged solution to implement the bing translator for cases, letters, tasks, and emails, you can download it here: Translate_1_0.zip. It will not modify your forms, but if you have unmanaged ribbon buttons on those entities, it will remove them. So to avoid that problem you can install the unmanaged solution with the JScript (that you need to edit to set your bing api key) and the images, and then follow the RibbonDiff guide in the SDK to add the buttons, or install the managed solution to add the button to the ribbons for cases, letters, tasks, and emails.

To start, I created a JScript file to include as a web-resource that I could leverage when a button is clicked on the ribbon. This JScript file utilizes the Bing Translation WebServices to translate text.

YOU WILL NEED TO EDIT THE JSCRIPT FILE AND CHANGE ‘YOUR API KEY GOES HERE’ TO CONTAIN YOUR API KEY.

var bing = {};
bing.popup = {};
bing.language = {};

bing.appId = 'YOUR API KEY GOES HERE';
bing.language.text = '';
bing.language.from = '';
bing.language.to = 'en';

bing.language.detect = function (text,oncomplete)
{
  var src = "https://api.microsofttranslator.com/V2/Ajax.svc/Detect?oncomplete=" + 
      oncomplete + "&appId="+ bing.appId + "&text=" + text;
  var s = document.createElement("script");
  s.src = src;
  s.id = "bingdetect";
  document.getElementsByTagName("head")[0].appendChild(s);
}

bing.language.translate = function(from,to,text,oncomplete)
{
  var src = "https://api.microsofttranslator.com/V2/Ajax.svc/Translate?oncomplete=" + 
      oncomplete + "&appId=" + bing.appId + "&from=" + from + 
      "&to=" + to + "&text=" + text;

  var s = document.createElement("script");
  s.src = src;
  s.id = "bingtranslate";
  document.getElementsByTagName("head")[0].appendChild(s);
}

bing.popup.show = function(text)
{
  var idiv = document.createElement('div');
  idiv.id = "bingtext";
  idiv.style.height = "265px";
  idiv.style.width = "306px";
  idiv.style.align = "left";
  idiv.style.textAlign = "left";
  idiv.style.backgroundColor = "white";
  idiv.style.overflow = "auto";
  idiv.style.padding = "2px";
  idiv.style.margin = "2px";
  idiv.style.border = "1px solid black";
  idiv.innerHTML =  "<p>"+text+"</p>";
    
  var iurl = Xrm.Page.context.getServerUrl();
  iurl += "WebResources/tran_img/translatelogo.gif";
  
  var img = document.createElement('img');
  img.src = iurl;
  
  var div = document.createElement('div');
  div.id = "bingpopup";
  div.appendChild(img);
  div.appendChild(idiv);
  div.innerHTML += "<button style='text-align:center;width:60px;' onclick='bing.popup.copy();'>Copy</button>&nbsp;&nbsp;";
  div.innerHTML += "<button style='text-align:center;width:60px;' onclick='bing.popup.hide();'>Close</button>";
  div.style.position = "absolute";
  div.style.backgroundColor = "#20415F";
  div.style.border="1px solid black";
  div.style.left = "50%";
  div.style.top = "50%";
  div.style.color = "black";
  div.style.padding = "5px";
  div.style.width = "320px";
  div.style.height = "340px";
  div.style.marginLeft = "-160px"; 
  div.style.marginTop = "-170px";
  div.setAttribute("align","center");
  document.getElementsByTagName("body")[0].appendChild(div);
}

bing.popup.hide = function()
{
  var deleteElement = function(id) {
    var el = document.getElementById(id);
    el.parentNode.removeChild(el);
  }

  deleteElement("bingpopup");
  deleteElement("bingdetect");
  deleteElement("bingtranslate");
}

bing.popup.copy = function()
{
  var el = document.getElementById('bingtext');
  
  if (window.clipboardData && window.clipboardData.setData)
  {
    window.clipboardData.setData("Text", el.innerText);
  }
}

bing.getSelectedText = function (p)
{
  if (p.getSelection)
  {
    text = p.getSelection();
  }
  else if (p.selection)
  {
    text = p.selection.createRange().text;
  }
  return text;
}

// get current control
bing.language.toolbarClick = function (ctrl)
{
  var text = '';
  if (window.getSelection)
  {
    text = window.getSelection();
  }
  else {
    text = bing.getSelectedText(document);
  }

  if (text==null || text=='') {
    if (ctrl==null) {
      ctrl = Xrm.Page.ui.getCurrentControl();
    }

    var entityName = Xrm.Page.data.entity.getEntityName();
    if (ctrl==null && entityName.match(/letter|email|task/)) {
      ctrl = Xrm.Page.ui.controls.get('description');
    }

    if (ctrl==null) {
      alert('Please highlight the text to translate.');
      return;
    }
  
    if (ctrl.getControlType()!="standard") {
      return; // only standard
    }
  
    if (ctrl.getName()=="notescontrol") {
      text = bing.getSelectedText(document.frames['notescontrol'].document);
      if (text==null || text == "") {
        alert('Please highlight the text to translate.');
      }
    }
  
    if (text == null || text == "") {
      var attr = ctrl.getAttribute();
      if (attr!=null) {
        var t = attr.getAttributeType();
        if (t.match(/string|memo/))
        {
          text = attr.getValue();
        }
      }
    }
  }
  
  if (text == null || text == "") {
    // Nothing to translate
    return; 
  }  
  
  text = encodeURIComponent(text);
  bing.language.text = text;

  bing.language.from = '';
  bing.language.detect(text,"translate");
}

window.translate = function (response)
{
  bing.language.from = response;
  bing.language.translate(bing.language.from,bing.language.to,bing.language.text,"translated");
}

window.translated = function (response)
{
  bing.popup.show(response);
}

The JScript uses the Bing Translate logo image (WebResources/tran_img/translatelogo.gif – you may need to change the path in the JScript):

I added some images for Microsoft Translate button images:


16×16 image
tran_icontranslate_16x16.png

32×32 image
tran_icontranslate_32x32.png

Then I added the buttons to the ribbons on the entities I wanted to have bing translation capabilities by following the SDK guidelines to add a button. Here is the RibbonDiffXml for a case. You can follow the guide to change it to be on different entities.

<RibbonDiffXml>
  <CustomActions>
    <CustomAction Id="bing.incident.form.Bing.CustomAction" 
                  Location="Mscrm.Form.incident.MainTab.Groups._children" 
                  Sequence="110">
    <CommandUIDefinition>
      <Group Id="bing.incident.form.Bing.Group" 
             Command="bing.incident.form.Bing.Command" 
             Title="$LocLabels:bing.incident.Bing.Title" 
             Sequence="39" 
             Template="Mscrm.Templates.Flexible2" 
             Image32by32Popup="$webresource:tran_icon/translate_32x32.png">
      <Controls Id="bing.incident.form.Bing.Controls">
        <Button Id="bing.incident.form.Bing.Button.BingTranslator" 
                Command="bing.incident.Bing.Button.BingTranslator.Command" 
                Sequence="10" 
                LabelText="$LocLabels:bing.incident.Bing.Button.BingTranslator.LabelText" 
                ToolTipTitle="$LocLabels:bing.incident.Bing.Button.BingTranslator.LabelText" 
                ToolTipDescription="$LocLabels:bing.incident.Bing.Button.BingTranslator.Description" 
                TemplateAlias="isv" 
                Image16by16="$webresource:tran_icon/translate_16x16.png" 
                Image32by32="$webresource:tran_icon/translate_32x32.png" />
      </Controls>
      </Group>
    </CommandUIDefinition>
    </CustomAction>
    <CustomAction Id="bing.incident.form.Bing.Popup.CustomAction" 
                  Location="Mscrm.Form.incident.MainTab.Scaling._children" 
                  Sequence="140">
    <CommandUIDefinition>
      <Scale Id="bing.incident.form.Bing.Popup.1" 
             GroupId="bing.incident.form.Bing.Group" 
             Sequence="85" 
             Size="Popup" />
    </CommandUIDefinition>
    </CustomAction>
    <CustomAction Id="bing.incident.form.Bing.MaxSize.CustomAction" 
                  Location="Mscrm.Form.incident.MainTab.Scaling._children" 
                  Sequence="120">
    <CommandUIDefinition>
      <MaxSize Id="bing.incident.form.Bing.MaxSize" 
               GroupId="bing.incident.form.Bing.Group" 
               Sequence="21" 
               Size="LargeLarge" />
    </CommandUIDefinition>
    </CustomAction>
  </CustomActions>
  <Templates>
    <RibbonTemplates Id="Mscrm.Templates"></RibbonTemplates>
  </Templates>
  <CommandDefinitions>
    <CommandDefinition Id="bing.incident.Bing.Button.BingTranslator.Command">
    <EnableRules />
    <DisplayRules />
    <Actions>
      <JavaScriptFunction Library="$webresource:tran_js/bing.translate.js" 
                          FunctionName="bing.language.toolbarClick">
      <CrmParameter Value="SelectedControl" />
      </JavaScriptFunction>
    </Actions>
    </CommandDefinition>
    <CommandDefinition Id="bing.incident.form.Bing.Command">
    <EnableRules></EnableRules>
    <DisplayRules />
    <Actions />
    </CommandDefinition>
  </CommandDefinitions>
  <RuleDefinitions>
    <TabDisplayRules />
    <DisplayRules />
    <EnableRules />
  </RuleDefinitions>
  <LocLabels>
    <LocLabel Id="bing.incident.Bing.Title">
    <Titles>
      <Title languagecode="1033" 
             description="Bing" />
    </Titles>
    </LocLabel>
    <LocLabel Id="bing.incident.Bing.Button.BingTranslator.LabelText">
    <Titles>
      <Title languagecode="1033" 
             description="Translate" />
    </Titles>
    </LocLabel>
    <LocLabel Id="bing.incident.Bing.Button.BingTranslator.Description">
    <Titles>
      <Title languagecode="1033" 
             description="Translate text area with bing!" />
    </Titles>
    </LocLabel>
  </LocLabels>
</RibbonDiffXml>

Here are the files to download if you want to use it: