33

曾经有一些服务使用 Google Translate API V1 来自动翻译.po文件。

谷歌已经停止了他们的 V1 API,并且在 V2 中,他们对 1.000.000 字收取 20 美元。

我已经搜索但找不到任何提供 V2 版本翻译的工具。您会期望有人更新他们的工具并为 20.000 字收取 2 美元并获得可观的利润。

是否有任何付费或免费工具可以自动翻译.po文件?

4

4 回答 4

47

有点晚了,但谷歌现在提供了这个功能

http://translate.google.com/toolkit/list?hl=en#translations/active

谷歌翻译已关闭此服务:/

于 2012-06-06T23:29:27.390 回答
2

查看我的免费 PHP 工具 Potrans,它使用 Google Translator API 翻译 PO 文件

从这里的 repo 下载:https ://github.com/OzzyCzech/potrans

于 2014-03-22T22:28:33.807 回答
1

随意编辑这篇文章以进行更正或更好的错误处理。我不是.po文件格式方面的专家,但我认为这将满足我的 angular-gettext 需求。我认为我使用的唯一外部库是 Newtonsoft 的 Json.NET。我不隶属于 Fengly。它出现在谷歌上。如果您每 3 秒需要 1 次以上的翻译,我建议您使用不同的翻译 API。


输入文件:template.pot

msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

#: Comment
msgid "You do not have permission to view this application"
msgstr ""

msgid "You have permission to view this application"
msgstr ""

输入命令:> program.exe template.pot en es_VE fr_FR


输出文件 1:en.cache.json 创建它是为了让您使用的任何翻译实用程序都不必一遍又一遍地点击。

{
  "es_VE": {
    "You do not have permission to view this application": "Tu no la habana permiso que vista este aplicación",
    "You have permission to view this application": "Tu tienes permiso que vista este aplicación"
  },
  "fr_FR": {
    "You do not have permission to view this application": "Vous le faites pas as autorisation a vue cette une demande",
    "You have permission to view this application": "Tuas autorisation a vue cette une demande"
  }
}

输出文件 2:es_VE.po

msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

#: Comment
msgid "You do not have permission to view this application"
msgstr "Tu no la habana permiso que vista este aplicación"

msgid "You have permission to view this application"
msgstr "Tu tienes permiso que vista este aplicación"

输出文件 3:fr_FR.po

msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

#: Comment
msgid "You do not have permission to view this application"
msgstr "Vous le faites pas as autorisation a vue cette une demande"

msgid "You have permission to view this application"
msgstr "Tuas autorisation a vue cette une demande"

资源

public interface ICache
{
    void Add(string language, IEntry entry);

    IEntry Get(string language, string id);

    string GetSerialized();
}

public class JsonCache : ICache
{
    private Dictionary<string, Dictionary<string, string>> _cache;

    public JsonCache(string json)
    {
        this._cache = 
            json == null ?
            new Dictionary<string, Dictionary<string, string>>() :
            JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, string>>>(json);
    }

    public void Add(string language, IEntry entry)
    {
        if (!this._cache.ContainsKey(language))
        {
            this._cache.Add(language, new Dictionary<string, string>());
        }

        var languageCache = this._cache[language];

        languageCache.Add(entry.Id, entry.Value);
    }

    public IEntry Get(string language, string id)
    {
        if (!this._cache.ContainsKey(language))
        {
            return null;
        }

        var languageCache = this._cache[language];

        Entry result = null;

        if (languageCache.ContainsKey(id))
        {
            result = new Entry();
            result.Id = id;
            result.Value =  languageCache[id];
        }

        return result;
    }

    public string GetSerialized()
    {
        return JsonConvert.SerializeObject(this._cache, Formatting.Indented);
    }
}

public interface IReader : IDisposable
{
    IEntry Read();
}

public class PoReader : IReader
{
    private StreamReader _reader;

    public PoReader(string fileName)
    {
        this._reader = new StreamReader(fileName);
    }

    public void Dispose()
    {
        if (this._reader != null)
        {
            this._reader.Dispose();
        }
    }

    public IEntry Read()
    {
        var entry = new Entry();

        while (entry.Id == null || entry.Value == null)
        {
            var line = this._reader.ReadLine();
            if (line == null)
            {
                return null;
            }

            if (line.StartsWith(Constants.StartComment))
            {
                entry.Comment = line.Substring(Constants.StartComment.Length);
            }
            else if (line.StartsWith(Constants.StartId))
            {
                entry.Id = line.Substring(Constants.StartId.Length);
                // Remove the double quotes.
                entry.Id = entry.Id.Substring(1, entry.Id.Length - 2);
            }
            else if (line.StartsWith(Constants.StartValue))
            {
                entry.Value = line.Substring(Constants.StartValue.Length);
                // Remove the double quotes.
                entry.Value = entry.Value.Substring(1, entry.Value.Length - 2);
            }
        }

        // Skip the first entry
        if (entry.Id.Length == 0)
        {
            return this.Read();
        }

        return entry;
    }
}

public class CachedTranslator : ITranslator
{
    private ITranslator _translator;
    private ICache _cache;

    public CachedTranslator(ICache cache, ITranslator translator)
    {
        this._translator = translator;
        this._cache = cache;
    }

    public IEntry Translate(string language, IEntry entry)
    {
        var result = this._cache.Get(language, entry.Id);
        if (result == null)
        {
            result = this._translator.Translate(language, entry);
            this._cache.Add(language, result);
        }
        else
        {
            // We don't want to use the cached comment.
            var clone = new Entry();

            clone.Comment = entry.Comment;
            clone.Value = result.Value;
            clone.Id = result.Id;

            result = clone;
        }
        return result;
    }
}

public class FrenglyTranslator : ITranslator
{
    private string _password;
    private string _email;
    private string _inLanguage;

    public FrenglyTranslator(string email, string password, string inLanguage)
    {
        this._email = email;
        this._password = password;
        this._inLanguage = inLanguage;
    }

    public IEntry Translate(string language, IEntry entry)
    {
        var url = string.Format("http://syslang.com?src={4}&dest={0}&text={1}&email={2}&password={3}&outformat=json",
            language.Substring(0, 2),
            entry.Id,
            this._email,
            this._password,
            this._inLanguage);

        var result = new Entry();
        result.Id = entry.Id;
        result.Comment = entry.Comment;

        using (var client = new HttpClient())
        {
            var clientResult = client.GetStringAsync(url).Result;
            var jo = (JObject)JsonConvert.DeserializeObject(clientResult);               
            result.Value = jo.Property("translation").Value.Value<string>();
        }

        // Must wait 3 seconds between calls.
        Thread.Sleep(3001);

        return result;
    }
}

public interface ITranslator
{
    IEntry Translate(string language, IEntry entry);
}

public interface IWriter : IDisposable
{
    void Write(IEntry entry);
}

public class PoWriter : IWriter
{
    private StreamWriter _writer;

    public PoWriter(string fileName)
    {
        this._writer = new StreamWriter(fileName);

        var header = @"msgid """"
msgstr """"
""Content-Type: text/plain; charset=UTF-8\n""
""Content-Transfer-Encoding: 8bit\n""";

        this._writer.WriteLine(header);
    }

    public void Write(IEntry entry)
    {
        this._writer.WriteLine();

        if (entry.Comment != null && entry.Comment.Length > 0)
        {
            this._writer.WriteLine(Constants.StartComment + entry.Comment);
        }

        this._writer.WriteLine(string.Format("{0}\"{1}\"", Constants.StartId, entry.Id));
        this._writer.WriteLine(string.Format("{0}\"{1}\"", Constants.StartValue, entry.Value));
    }

    public void Dispose()
    {
        if (this._writer != null)
        {
            this._writer.Dispose();
        }
    }
}

public static class Constants
{
    public const string StartComment = "#: ";
    public const string StartId = "msgid ";
    public const string StartValue = "msgstr ";
}

public class Entry : IEntry
{
    public string Comment { get; set; }

    public string Value { get; set; }

    public string Id { get; set; }
}

public interface IEntry
{
    string Comment { get; }

    string Value { get; }

    string Id { get; }
}

class Program
{
    private const string cacheFileNameSuffix = ".cache.json";
    private const string frenglyEmail = "your.em@il.com";
    private const string frenglyPassword = "YourPassword";

    static void Main(string[] args)
    {
        //
        // INITIALIZE
        //
        var inFileName = args[0];
        var inLanguage = args[1];
        var outLanguages = args.Skip(2);

        // ICache
        var cacheFileName = inLanguage + cacheFileNameSuffix;
        var json = File.Exists(cacheFileName) ? File.ReadAllText(cacheFileName) : null;
        ICache cache = new JsonCache(json);

        // ITranslator
        ITranslator translator = new FrenglyTranslator(frenglyEmail, frenglyPassword, inLanguage);
        ITranslator cachedTranslator = new CachedTranslator(cache, translator);

        // IWriters
        var writers = new Dictionary<string, IWriter>();
        foreach (var language in outLanguages)
        {
            writers.Add(language, new PoWriter(language + ".po"));
        }

        try
        {
            using (IReader reader = new PoReader(inFileName))
            {
                //
                // RUN
                //
                IEntry entry = null;
                while (true)
                {
                    entry = reader.Read();
                    if (entry == null)
                    {
                        break;
                    }

                    foreach (var kv in writers)
                    {
                        var translated = cachedTranslator.Translate(kv.Key, entry);
                        kv.Value.Write(translated);
                    }
                }
            }
        }
        finally
        {
            // Store the cache.
            File.WriteAllText(cacheFileName, cache.GetSerialized());

            //
            // CLEANUP
            //

            // Dispose of the writers.
            foreach (var writer in writers.Values)
            {
                if (writer != null)
                {
                    writer.Dispose();
                }
            }
        }
    }
}
于 2014-08-13T00:32:13.967 回答
-2

http://sourceforge.net/projects/po-auto-tran/?source=dlp你去我刚刚下载并使用它,它工作得很好!!!我不知道这是否能回答你的问题,但它对我来说是一项工作

于 2014-04-21T17:01:44.920 回答