65.9K
CodeProject 正在变化。 阅读更多。
Home

Delphi:使用 Google 进行在线翻译

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.69/5 (10投票s)

2010年5月11日

CPOL

3分钟阅读

viewsIcon

29167

Google 提供了一个看起来很有希望且实用的翻译 API。因此,当我们在 Localizer 项目中决定使用它时,我感到非常兴奋。

引言

Google 提供了一个看起来很有希望且实用的翻译 API。因此,当我们在 Localizer 项目中决定使用它时,我感到非常兴奋。  

不幸的是,我不能说该 API 的文档写得很好。当然,也没有教程描述如何在 Delphi 2009 中使用它,因为我们需要这样做。  

我花了一些时间在网上搜索,找到了一些关于这项任务的文章,但没有一篇文章能给我一个解决方案。

我找到的所有文章都建议使用 http://google.com/translate URL 来访问翻译服务。这并不完全正确。首先,该 URL 用于通过浏览器进行最终用户请求。它的参数没有记录,并且可以随时更改。其次,响应是一个普通的网页,包含许多不必要的标签、文本等。从响应中提取结果是一种头痛。而且,与 URL 一样,响应布局也可能(甚至可以肯定地)在未来发生变化。 

解决方案

Google 描述了翻译 API,并给出了另一种解决任务的方法。正确的 URL 是:https://ajax.googleapis.ac.cn/ajax/services/language/translate。在这种情况下,响应格式是包含嵌入式状态代码的 JSON 编码结果。

我们所需要做的就是构造一个包含所有必要 CGI 参数的正确构造的 URL,发送一个准确标识我们应用程序的 HTTP referrer 标头(Google 使用条款 要求),并能够处理 JSON 编码的响应。

到目前为止一切顺利。让我们尝试编写一个 Delphi 函数来翻译一些输入字符串。我们将使用 Indy TidHttp 组件来发送 HTTP 请求。

正如我所定义的,在研究了参数部分之后,构造的 URL 应该转换为 UTF8 然后进行编码。正如 Google 所说,“CGI 参数的值必须正确转义(例如,通过 JavaScript 的 encodeURIComponent() 方法的功能等效物)”。我尝试使用一些标准的或第三方的 URL 编码函数,但没有一个函数在 Google 的期望方面正确执行。主要问题是,所有可用的函数都逐个字符地编码源字符串,而 Google 期望字符串逐字节地编码。所以我不得不自己做。 

function URLEncode(const S: RawByteString): RawByteString;
  const
    NoConversion = ['A'..'Z', 'a'..'z', '*', '@', '.', '_', '-', '/', ':', '=', '?'];
  var
    i, idx, len: Integer;

  function DigitToHex(Digit: Integer): AnsiChar;
  begin
    case Digit of
      0..9: Result := AnsiChar(Chr(Digit + Ord('0')));
      10..15: Result := AnsiChar(Chr(Digit - 10 + Ord('A')));
    else
      Result := '0';
    end;
  end; // DigitToHex

begin
  len := 0;
  for i := 1 to Length(S) do
    if S[i] in NoConversion then
      len := len + 1
    else
      len := len + 3;
  SetLength(Result, len);
  idx := 1;
  for i := 1 to Length(S) do
    if S[i] in NoConversion then
    begin
      Result[idx] := S[i];
      idx := idx + 1;
    end
    else
    begin
      Result[idx] := '%';
      Result[idx + 1] := DigitToHex(Ord(S[i]) div 16);
      Result[idx + 2] := DigitToHex(Ord(S[i]) mod 16);
      idx := idx + 3;
    end;
end; // URLEncode	

下一个问题是如何从我们获得的响应中提取翻译。在我们的例子中,响应格式是一个简单的 JSON 对象,类似于下面的片段: 

{
  "responseData" : {
    "translatedText" : the-translated-text,
  },
  "responseDetails" : null | string-on-error,
  "responseStatus" : 200 | error-code
}

最好的方法是使用一个处理 JSON 结构的库。例如,您可以下载并使用 uJson 单元。

为了演示目的,将响应作为常规字符串处理就足够了。我们需要提取响应的状态(200 = 成功),翻译文本以及如果状态 != 200 时的错误字符串。

// source - the string to be translated
// langpair - the string that defines the source and target language in special format, 
//     i.e. “en|ru”. The list of available languages and their abbreviations 
//     you may find in Translation API description
// resultString - the translation
// result - the error message if any. Empty result means that 
//     the function has been executed successfully
function googleTranslate(source : string; langpair : string; 
	var resultString : string) : string;
var
  url, s, status : String;
  utfs : UTF8String;
  http : TidHttp;

begin
  result := '';

  http := TidHttp.Create;

  try
    utfs := UTF8String(source);
    utfs := URLEncode(utfs);
    url := 'https://ajax.googleapis.ac.cn/ajax/services/language/translate?v=1.0&q=' + 
		String(utfs) + '&langpair=' + langpair;

    http.Request.Referer := 'http://oursite.com';
    http.Request.UserAgent := 'Our Application';
    s := http.Get(url);

    status := Copy(s, pos('"responseStatus":', s)+18, length(s));
    status := Copy(status, 0, pos('}', status)-1);

    if (status = '200') then begin //status is OK
      s := Copy(s, pos('"translatedText":', s)+18, length(s));
      resultString := Copy(s, 0, pos('"}, "responseDetails"', s)-1);
    end
    else begin //an error occurred
      s := Copy(s, pos('"responseDetails":', s)+20, length(s));
      resultString := '';
      result := Copy(s, 0, pos('", "responseStatus"', s)-1);
    end;

  finally
    http.Free;
  end;
end;

最后,我们可以尝试翻译一些内容。例如,我们要将“Hello world!”从英语翻译成乌克兰语。

var
  res, strValue : string;
…
res := googleTranslate('Hello world!', 'en|uk', strValue);
if (res = '') then //translation is OK
  ShowMessage('Translation: ' + strValue)
else //error
  ShowMessage('Error: ' + res);

历史

  • 2010 年 5 月 11 日:初始帖子
© . All rights reserved.