如何最好地翻译大量的文本数据?

8
我有很多文本数据,想将其翻译成不同的语言。
我知道的可能方法有:
- Google Translate API - Bing Translator API
问题在于,所有这些服务都有文本长度限制、调用次数限制等,这使得它们使用起来不太方便。
你能推荐哪些服务/方法在这种情况下使用吗?
8个回答

2

当我将语言翻译与XMPP聊天服务器集成时,我不得不解决同样的问题。我将我的有效载荷(需要翻译的文本)分成了完整句子的较小子集。

我记不清确切的数字了,但使用Google基于REST的翻译URL,我翻译了一组完成的句子,这些句子总共少于(或等于)1024个字符,因此一个大段落会导致多次翻译服务调用。


1
是的,没错。但如果我们有 HTML 格式的数据呢?如果我们在 > 或 < 字符处进行分割,它将不会被视为 HTML。有什么帮助吗? - Vishal Sharma

1

将您的大文本分解为标记化字符串,然后通过循环将每个标记传递给翻译器。将翻译后的输出存储在数组中,一旦所有标记都被翻译并存储在数组中,将它们重新组合,您将拥有完全翻译的文档。

只是为了证明一点,我把这个东西凑在一起:) 它还有些粗糙,但它可以处理很多文本,并且它的翻译准确度与谷歌相当,因为它使用谷歌API。我用这段代码处理了苹果公司整个2005年的SEC 10-K备案,只需点击一个按钮(大约需要45分钟)。

结果基本上与您逐句复制和粘贴到Google翻译中得到的结果相同。它不是完美的(结束标点符号不准确,我没有按行写入文本文件),但它确实显示了一个概念证明。如果您进一步使用正则表达式,它可能会有更好的标点符号。

Imports System.IO
Imports System.Text.RegularExpressions

Public Class Form1

    Dim file As New String("Translate Me.txt")
    Dim lineCount As Integer = countLines()

    Private Function countLines()

        If IO.File.Exists(file) Then

            Dim reader As New StreamReader(file)
            Dim lineCount As Integer = Split(reader.ReadToEnd.Trim(), Environment.NewLine).Length
            reader.Close()
            Return lineCount

        Else

            MsgBox(file + " cannot be found anywhere!", 0, "Oops!")

        End If

        Return 1

    End Function

    Private Sub translateText()

        Dim lineLoop As Integer = 0
        Dim currentLine As String
        Dim currentLineSplit() As String
        Dim input1 As New StreamReader(file)
        Dim input2 As New StreamReader(file)
        Dim filePunctuation As Integer = 1
        Dim linePunctuation As Integer = 1

        Dim delimiters(3) As Char
        delimiters(0) = "."
        delimiters(1) = "!"
        delimiters(2) = "?"

        Dim entireFile As String
        entireFile = (input1.ReadToEnd)

        For i = 1 To Len(entireFile)
            If Mid$(entireFile, i, 1) = "." Then filePunctuation += 1
        Next

        For i = 1 To Len(entireFile)
            If Mid$(entireFile, i, 1) = "!" Then filePunctuation += 1
        Next

        For i = 1 To Len(entireFile)
            If Mid$(entireFile, i, 1) = "?" Then filePunctuation += 1
        Next

        Dim sentenceArraySize = filePunctuation + lineCount

        Dim sentenceArrayCount = 0
        Dim sentence(sentenceArraySize) As String
        Dim sentenceLoop As Integer

        While lineLoop < lineCount

            linePunctuation = 1

            currentLine = (input2.ReadLine)

            For i = 1 To Len(currentLine)
                If Mid$(currentLine, i, 1) = "." Then linePunctuation += 1
            Next

            For i = 1 To Len(currentLine)
                If Mid$(currentLine, i, 1) = "!" Then linePunctuation += 1
            Next

            For i = 1 To Len(currentLine)
                If Mid$(currentLine, i, 1) = "?" Then linePunctuation += 1
            Next

            currentLineSplit = currentLine.Split(delimiters)
            sentenceLoop = 0

            While linePunctuation > 0

                Try

                    Dim trans As New Google.API.Translate.TranslateClient("")
                    sentence(sentenceArrayCount) = trans.Translate(currentLineSplit(sentenceLoop), Google.API.Translate.Language.English, Google.API.Translate.Language.German, Google.API.Translate.TranslateFormat.Text)
                    sentenceLoop += 1
                    linePunctuation -= 1
                    sentenceArrayCount += 1

                Catch ex As Exception

                    sentenceLoop += 1
                    linePunctuation -= 1

                End Try

            End While

            lineLoop += 1

        End While

        Dim newFile As New String("Translated Text.txt")
        Dim outputLoopCount As Integer = 0

        Using output As StreamWriter = New StreamWriter(newFile)

            While outputLoopCount < sentenceArraySize

                output.Write(sentence(outputLoopCount) + ". ")

                outputLoopCount += 1

            End While

        End Using

        input1.Close()
        input2.Close()

    End Sub

    Private Sub translateButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles translateButton.Click

        translateText()

    End Sub

End Class

1
不错的猜测。但是在大多数情况下,这将导致难以理解和不连贯的结果。翻译非常依赖上下文。人类语言表达无法被分词和编译。 - Sky Sanders
你说得对,语言确实非常依赖上下文,但你可以解决这个问题。你甚至不需要在两种语言中寻找完美的同源词,只需基于类似标点符号的东西来构建字符串标记即可。我会说英语和糟糕的德语,我知道这对于英德或德英翻译器都适用,因为句子中的句号位置相同。你可以使用正则表达式,它既简单又强大。 - ubiquibacon
好的,用我给你的一行正则表达式替换那30行字符串操作,看看效果如何;-) - Sky Sanders
是的,我在评论中也指出了改进正则表达式会有所帮助,只是我没有时间去研究我不知道的函数,所以我使用了我知道的 :) 此外,它能够工作,这才是最重要的。如果他想的话,他可以对其进行优化。 - ubiquibacon
如果你满足于提供次标准的答案,而已经有更好的选择,那就由你自己决定吧。但是我可以帮助你,向你展示另一种回答问题的方式;-) - Sky Sanders

0

免责声明:虽然我确实认为令牌化作为翻译手段有些可疑,但是像后来 ubiquibacon所示 那样按句子拆分可能会产生符合您要求的结果。

我建议他通过将 30 多行字符串处理减少到他在 另一个问题 中请求的一行正则表达式来改进他的代码,但建议并未得到好评。

这里提供了使用 VB.NET 和 C# 中的 Google API for .NET 实现。

Program.cs 文件

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using Google.API.Translate;

namespace TokenizingTranslatorCS
{
    internal class Program
    {
        private static readonly TranslateClient Client =
            new TranslateClient("http://code.google.com/p/google-api-for-dotnet/");

        private static void Main(string[] args)
        {
            Language originalLanguage = Language.English;
            Language targetLanguage = Language.German;

            string filename = args[0];

            StringBuilder output = new StringBuilder();

            string[] input = File.ReadAllLines(filename);

            foreach (string line in input)
            {
                List<string> translatedSentences = new List<string>();
                string[] sentences = Regex.Split(line, "\\b(?<sentence>.*?[\\.!?](?:\\s|$))");
                foreach (string sentence in sentences)
                {
                    string sentenceToTranslate = sentence.Trim();

                    if (!string.IsNullOrEmpty(sentenceToTranslate))
                    {
                        translatedSentences.Add(TranslateSentence(sentence, originalLanguage, targetLanguage));
                    }
                }


                output.AppendLine(string.Format("{0}{1}", string.Join(" ", translatedSentences.ToArray()),
                                                Environment.NewLine));
            }

            Console.WriteLine("Translated:{0}{1}{0}", Environment.NewLine, string.Join(Environment.NewLine, input));
            Console.WriteLine("To:{0}{1}{0}", Environment.NewLine, output);
            Console.WriteLine("{0}Press any key{0}", Environment.NewLine);


            Console.ReadKey();
        }

        private static string TranslateSentence(string sentence, Language originalLanguage, Language targetLanguage)
        {
            string translatedSentence = Client.Translate(sentence, originalLanguage, targetLanguage);
            return translatedSentence;
        }
    }
}

文件 Module1.vb

Imports System.Text.RegularExpressions
Imports System.IO
Imports System.Text
Imports Google.API.Translate


Module Module1

    Private Client As TranslateClient = New TranslateClient("http://code.google.com/p/google-api-for-dotnet/")

    Sub Main(ByVal args As String())

        Dim originalLanguage As Language = Language.English
        Dim targetLanguage As Language = Language.German

        Dim filename As String = args(0)

        Dim output As New StringBuilder

        Dim input As String() = File.ReadAllLines(filename)

        For Each line As String In input
            Dim translatedSentences As New List(Of String)
            Dim sentences As String() = Regex.Split(line, "\b(?<sentence>.*?[\.!?](?:\s|$))")
            For Each sentence As String In sentences

                Dim sentenceToTranslate As String = sentence.Trim

                If Not String.IsNullOrEmpty(sentenceToTranslate) Then

                    translatedSentences.Add(TranslateSentence(sentence, originalLanguage, targetLanguage))

                End If

            Next

            output.AppendLine(String.Format("{0}{1}", String.Join(" ", translatedSentences.ToArray), Environment.NewLine))

        Next

        Console.WriteLine("Translated:{0}{1}{0}", Environment.NewLine, String.Join(Environment.NewLine, input))
        Console.WriteLine("To:{0}{1}{0}", Environment.NewLine, output)
        Console.WriteLine("{0}Press any key{0}", Environment.NewLine)
        Console.ReadKey()


    End Sub

    Private Function TranslateSentence(ByVal sentence As String, ByVal originalLanguage As Language, ByVal targetLanguage As Language) As String

        Dim translatedSentence As String = Client.Translate(sentence, originalLanguage, targetLanguage)
        Return translatedSentence
    End Function

End Module

输入(直接从ubiquibacon窃取)

为了证明一点,我把这个东西拼凑在一起 :) 它有些粗糙,但它可以处理大量的文本,并且它的翻译准确度与谷歌相当,因为它使用谷歌API。我用这段代码处理了苹果公司整个2005年的SEC 10-K备案申请,只需点击一个按钮(大约需要45分钟)。结果基本上与您逐句复制和粘贴到Google翻译器中所得到的结果相同。它并不完美(结束标点符号不准确,我没有逐行写入文本文件),但它确实证明了概念。如果您进一步使用正则表达式,它可能会有更好的标点符号。

结果(德语对typoking):

只是为了证明一个观点,我把这个东西拼凑在一起 :) 它有些粗糙,但它可以处理大量的文本,并且几乎像谷歌一样准确,因为它使用了谷歌API。我用这段代码处理了苹果公司2005年的SEC 10-K申报文件,并且只需要点击一下按钮(大约需要45分钟)。结果基本上与您将一个句子复制并粘贴到Google翻译中得到的结果相同。它不是完美的(结尾标点符号不正确,我不想逐行写入文本文件),但它证明了概念的可行性。如果您使用正则表达式进行更多的工作,它会有更好的标点符号。

我并不是在反对你关于正则表达式的观点,只是当时没有时间将其加入其中。我确实尝试了你从另一个问题中给我的代码片段,但当我复制粘贴后它并没有起作用,我也没有深究原因,虽然我相信这只是一些小问题。 - ubiquibacon
1
翻译质量太差了 :-) - tfeldmann
@Thomas - 是的,我怀疑是这样。这就是我试图阻止这种方法的原因,但在看到一些人发布低劣的建议和代码后,我的意图是展示一个干净的方式来完成肮脏的事情。 - Sky Sanders

0

使用MyGengo。他们提供免费的机器翻译API - 我不知道质量如何,但你也可以付费使用人工翻译。

我与他们没有关联,也没有使用过他们,但我听说过好评。


0

我们使用了http://www.berlitz.co.uk/translation/

我们会向他们发送一个包含英文内容和所需语言列表的数据库文件,然后他们会使用各种双语人员提供翻译。他们还使用配音演员为我们的电话界面提供WAV文件。

这显然不如自动翻译快,也不是免费的,但我认为这种服务是确保您的翻译有意义的唯一方法。


这是对问题非常字面的解释,但这可能是最好的答案!机器翻译的质量是...可笑的(甚至不包括习语)。 - Peter Mortensen

0

谷歌提供了一个有用的工具,谷歌翻译工具包,它允许您上传文件并一次性将它们翻译成谷歌翻译支持的任何语言。

如果您想使用自动翻译,它是免费的,但也有雇佣真人翻译您的文档的选项。

来自维基百科:

谷歌翻译工具包是一个网络应用程序,旨在允许翻译人员编辑谷歌翻译自动生成的翻译。通过谷歌翻译工具包,翻译人员可以组织他们的工作,并使用共享翻译、术语表和翻译记忆。他们可以上传和翻译 Microsoft Word 文档、OpenOffice.org、RTF、HTML、文本和维基百科文章。

链接


它运行正常!我已成功上传一本荷兰书,共153k字,并将其翻译成英语。 - im_chc
很遗憾,它已经不存在了 :'( - GregarityNow
Google Translator Toolkit在2019年12月已经关闭。 - Peter Mortensen

0

有很多不同的机器翻译 API:Google、Microsoft、Yandex、IBM、PROMT、Systran、Baidu、YeeCloud、DeepL、SDL和SAP。

其中一些支持批量请求(一次翻译文本数组)。我会逐句翻译,并正确处理403/429错误(通常用于响应超过配额)。

我可以参考我们最近的评估研究(2017年11月):机器翻译现状


他们的服务条款是否允许这样大规模的使用?你不担心被永久封禁吗? - Peter Mortensen

-1

这很简单,有几种方法:

  • 使用API并分块翻译数据(以符合限制)。
  • 编写自己的简单库来使用HttpWebRequest并将一些数据POST到它上面。

以下是一个例子(第二种方法):

方法:

private String TranslateTextEnglishSpanish(String textToTranslate)
{
        HttpWebRequest http = WebRequest.Create("http://translate.google.com/") as HttpWebRequest;
        http.Method = "POST";
        http.ContentType = "application/x-www-form-urlencoded";
        http.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2 (.NET CLR 3.5.30729)";
        http.Referer = "http://translate.google.com/";

        byte[] dataBytes = UTF8Encoding.UTF8.GetBytes(String.Format("js=y&prev=_t&hl=en&ie=UTF-8&layout=1&eotf=1&text={0}+&file=&sl=en&tl=es", textToTranslate);

        http.ContentLength = dataBytes.Length;

        using (Stream postStream = http.GetRequestStream())
        {
            postStream.Write(dataBytes, 0, dataBytes.Length);
        }

        HttpWebResponse httpResponse = http.GetResponse() as HttpWebResponse;
        if (httpResponse != null)
        {
            using (StreamReader reader = new StreamReader(httpResponse.GetResponseStream()))
            {
                //* Return translated Text
                return reader.ReadToEnd();
            }
        }

        return "";
}

方法调用:

String translatedText = TranslateTextEnglishSpanish("hello world");

结果:

translatedText == "hola mundo";

您只需要获取所有语言的参数,并按顺序使用它们以获取所需的翻译。

您可以使用Firefox浏览器的Live Http Headers插件来获取这些值。


“thousand values”指的是什么?“thousand of values”指的是什么?还是其他什么?请通过编辑(更改)您的答案来回复,而不是在评论中回复(不包括“Edit:”,“Update:”或类似内容 - 答案应该看起来像是今天写的)。 - Peter Mortensen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接