Language translation in PowerShell using PowerTab Part 1
In this 2 part series I will show how you can customize TabExpansion by adding your own functionality to PowerTab
I added on-the-fly language translation functionality to PowerShell to show the posibilities the "Custom User Function" functionality in PowerTab offers. I allready mentioned in this blogpost : PowerTab Version 0.98 Released and did show in the PowerTab demo I gave in the PowerShell Virtual User Group video meeting 1 .
I got the idea for this custom script functionality after reading this post : Translate with Google Dictionary Translation and PowerShell on the PowerShellers blog.This example uses Internet Explorer to show the results in a seperate window, I did not really like this and I changed the script to use the System.Net.WebClient class, so the result could be returned to the console session instead of shown in Internet Explorer Also as babelfish supports some languages that google translate does not I added that also but after this simple change and extra script for Baelfish I was still not fully satisfied with the ease of access and figured that it would be cool to add this to TabExpansion and be able to use a simple [Tab] to do a translation.
Powertab had allready the possibility to Invoke custom commands inline with the & shortcut, but that was not enough as I needed the current word as input not as the commandname, so I added a "custum function" option to make this possible, in this 2 part series I explain how this works, in this post you will find the functions to do the translations, in next post we add this to Powertab :
- First we create a set of functions to translate text using Google or BabelFish
- Second you can see how, using the Custom function option in added in PowerTab 0.98, can add this functionality to Tabcompletion
- After that we add another custom addition to PowerTab for changing the custom user function to be able to easily switch
Language translation Using Google Translate or BabelFish
when we are ready we have direct access to the translation functionality of google and babelfish from within the PowerShell console by using PowerTab tabcompletion and can do things like this :
PoSH> Suf^
PoSH> ╔═ uf^ ═════════════════════╗
PoSH> ║ BabelFish English-Dutch ║
PoSH> ║ BabelFish Dutch-English ║
PoSH> ║ Translate German-English ║
PoSH> ║ Translate English-German ║
PoSH> ║ Translate English-French ║
PoSH> ║ Translate English-Italian ║
PoSH> ║ Translate English-Korean ║
PoSH> ║ Translate English-Spanish ║
PoSH> ║ Translate French-English ║
PoSH> ║ Translate Italian-English ║
PoSH> ║ Translate Korean-English ║
PoSH> ║ Translate Spanish-English ║
PoSH> ╚═[4] 1-12 [12]═════════════╝
PoSH> Power#
PoSH> ╔═ Power ════════════════════════════╗
PoSH> ║ Kraft ║
PoSH> ║ Wucht ║
PoSH> ║ Kräfte ║
PoSH> ║ Macht ║
PoSH> ║ Gewalt ║
PoSH> ║ (Macht)Befugnis ║
PoSH> ║ (Handlungs-, Vertretungs)Vollmacht ║
PoSH> ║ höhere Macht ║
PoSH> ║ Potenz ║
PoSH> ║ Antriebskraft ║
PoSH> ║ mit ║
PoSH> ║ mechanische Kraft, Antriebskraft ║
PoSH> ║ Masse ║
PoSH> ║ Zugkraft ║
PoSH> ╚═[1] 1-14 (14/14)]══════════════════╝
PoSH>
first you see above we can select the language pair using suf^[tab] (the Switch User Function we make in step 3) and then how we can translate using a # behind a word or string and after that press [tab] .
You can also translate a piece of text and change the function on the fly like this by putting it in quotes:
PoSH> "Groeten uit Nederland" suf&
PoSH> ╔═ uf^ ═════════════════════╗
PoSH> ║ BabelFish English-Dutch ║
PoSH> ║ BabelFish Dutch-English ║
PoSH> ║ Translate German-English ║
PoSH> ║ Translate English-German ║
PoSH> ║ Translate English-French ║
PoSH> ║ Translate English-Italian ║
PoSH> ║ Translate English-Korean ║
PoSH> ║ Translate English-Spanish ║
PoSH> ║ Translate French-English ║
PoSH> ║ Translate Italian-English ║
PoSH> ║ Translate Korean-English ║
PoSH> ║ Translate Spanish-English ║
PoSH> ╚═[2] 1-12 [12]═════════════╝
PoSH> "Groeten uit Nederland"#
PoSH> "To greet from the Netherlands"
To greet from the Netherlands
PoSH>
But as you can see from the example the chance of success is a bit low ;-)
The Scripts
First we need to create the scripts we need to perform the translations, the adapted Translate with Google Dictionary Translation and PowerShell script :
Function Get-Translation {
param([string]$word="",[string]$dictionary="es")
switch($dictionary) {
ef {$langpair = "en%7Cfr"} # English-French
fe {$langpair = "fr%7Cen"} # French-English
ed {$langpair = "en%7Cde"} # English-German BETA
de {$langpair = "de%7Cen"} # German-English BETA
ei {$langpair = "en%7Cit"} # English-Italian
ie {$langpair = "it%7Cen"} # Italian-English
ek {$langpair = "en%7Cko"} # English-Korean
ke {$langpair = "ko%7Cen"} # Korean-English
es {$langpair = "en%7Ces"} # English-Spanish
se {$langpair = "es%7Cen"} # Spanish-English
}
$wc = New-Object System.Net.WebClient
$url = "http://translate.google.com/translate_dict?q=" + $word + "&sa=N&hl=en&langpair=" + $langpair
$RawResult = $wc.DownloadString($url)
$r = [regex]'bdo.*/bdo'
$m = $r.Matches($RawResult)
$r2 = [regex]'</b> (.*?)<'
$m2 = $r2.Matches($m)
$m2 |% {$_.groups[1].value.trim()}
}
As google translate does not support dutch I decided to look if I could do the same with Babelfish. This was a bit harder to do as I expected as did run into 2 challenges with this :
I got the following error
[PoSH]> Get-Babelfish en_es 'failed'
Exception calling "DownloadString" with "1" argument(s): "The server committed a protocol violation. Section=ResponseHeader Detail=CR must be followed by LF"
At line:5 char:34
+ $RawResult = $wc.DownloadString( <<<< $url)
[PoSH]>
After some searching I did find the cause of this problem, a security measure in the .NET framework, and the fix in the following KB article
A "ServerProtocolViolationException" WebException error occurs when you call the HttpWebRequest GetResponse method.
To help protect your computer from "HTTP Response Splitting" attacks, parsing is performed as it is described in the Request for Comments (RFC) 2616 document. Therefore, no control characters are permitted in names or in values. For example, the carriage return (CR) character and the linefeed (LF) character are not permitted. Additionally, many other characters are not permitted in names, and every response header must have a colon.
To work around this new behavior, you must add the useUnsafeHeaderParsing attribute to the <httpWebRequest> element in the Machine.config file.
As the headers as returned by babelfish do not seem to comply to this more strict parsing for this second script to work the following app.config file needs to be added to the PowerShell directory ( the location can be found in $pshome variable), to allow these results to be parsed.
PowerShell.exe.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.net>
<settings>
<httpWebRequest useUnsafeHeaderParsing = "true"/>
</settings>
</system.net>
</configuration>
After this fix I got this part working and was able to download the results.
The other challenge was to find out how to construct the URL for the search as Babelfish does not show the URL used for a translation in the addressbar as Google translate does, but I found out how to do it but looking in the resulting pages to the code behind the buttons in the HTML and managed to do it much the same way the script you can find below (I did not implement an enum but you can find the language codes on the babelfish page)
# Get-Babelfish
# /\/\o\/\/ 2007
# http://thePowerShellGuy.com
Function Get-Babelfish {
param([string]$word="",[string]$dictionary="en_es")
$wc = New-Object System.Net.WebClient
$url = "http://babelfish.altavista.com/babelfish/tr?doit=done&text=${word}&lp=$dictionary"
$RawResult = $wc.DownloadString($url)
$r = [regex]'"q" value="(.*?)">'
$m = $r.Matches($RawResult)
$m |% {$_.groups[1].value.trim()}
}
and now we are ready and we can use the functions like this :
[PoSH]> Get-Translation -word hello -dictionary ef
allô
bonjour
[PoSH]> Get-Babelfish hello
hola
[PoSH]>
And we are ready to add it to PowerTab so we can use it as show in the examples in the beginning of the post, how we do this I will discuss in the next post.
Enjoy,
Greetings /\/\o\/\/