How do I translate the text of an HTML page?

The application parses the HTML page. An HTML page has text, images, tables, and other content. The language of the text on the page is "language_1".

Assumed:
- click on the site link (the sites will be different);
- save the page in the DB (field_1)(Save the first page of the site);
- translate the page(to the language "yazyk_2");
- save the page in the DB (field_2).

And how to make sure that the structure of the page is preserved?
How to do it so that the application returns an HTML page in the language "language_2"?

I.e., do something similar to the translation function of GoogleChrome: go to any site, and translate the page into Russian..

Author: MSDN.WhiteKnight, 2018-10-18

1 answers

The simplest thing that comes to mind is to recursively go through all the elements, go down to the level of text nodes, translate each of them separately and replace its contents with a translation. Let's say we have this code for line feed via the Yandex API (taken from here):

using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http;
using Newtonsoft.Json;
//Reference: System.Net.Http, Newtonsoft.Json

namespace TranslateTest
{
    class Translator
    {
        public static async Task<string> Translate(string s, string lang)
        {
            if (s.Length > 0)
            {                

                string content = "text=" + WebUtility.UrlEncode(s);
                var cnt = new StringContent(content, Encoding.UTF8, "application/x-www-form-urlencoded");

                HttpClient client = new HttpClient();
                var response = await client.PostAsync(
                    "https://translate.yandex.net/api/v1.5/tr.json/translate?lang=" + lang
                    + "&key=APIKEY",
                    cnt
                    );
                var stream = await response.Content.ReadAsStreamAsync();                

                using (var sr = new StreamReader(stream))
                {
                    string line;

                    if ((line = sr.ReadLine()) != null)
                    {
                        if ((int)response.StatusCode != 200) throw new Exception(line);

                        Translation translation;

                        translation = JsonConvert.DeserializeObject<Translation>(line);    

                        s = "";

                        foreach (string str in translation.text)
                        {
                            s += str;
                        }
                    }
                }


                return s;
            }
            else
                return "";
        }
    }

    class Translation
    {
        public string code { get; set; }
        public string lang { get; set; }
        public string[] text { get; set; }
    }
}

Then the code for translating the HTML document will look like this (I use MSHTML):

using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows.Forms;
//Reference: COM -> Microsoft HTML Object Library

namespace TranslateTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }        

        private async void button1_Click(object sender, EventArgs e)
        {   
            string html;                
            html = System.IO.File.ReadAllText("c:\\test\\test.html");

            textBox2.Text = await TranslateDocument(html);

        }

        string lang = "en-ru";

        public async Task<string> TranslateDocument(string html)
        {                
            mshtml.HTMLDocument doc = null;
            mshtml.IHTMLDocument2 d2 = null;
            mshtml.IHTMLDocument3 d = null;
            mshtml.IHTMLElementCollection body = null;
            mshtml.IHTMLElement bodyelem = null;
            mshtml.IHTMLDOMNode bodynode = null;

            try
            {
                //грузим документ в парсер
                doc = new mshtml.HTMLDocument();
                d2 = (mshtml.IHTMLDocument2)doc;
                d2.write(html);

                //находим body
                d = (mshtml.IHTMLDocument3)doc;
                body = d.getElementsByTagName("body");
                if (body.length == 0) throw new Exception("Fatal error: HTML has no BODY tag!");

                bodyelem = body.item(0);                
                bodynode = bodyelem as mshtml.IHTMLDOMNode;

                //рекурсивно переводим все узлы элемента body
                foreach (var node in bodynode.childNodes)
                {
                    await TranslateNode(node);
                }

                return bodyelem.innerHTML;
            }
            finally
            {
                //освобождение ресурсов
                if (doc != null) Marshal.ReleaseComObject(doc);
                if (d2 != null) Marshal.ReleaseComObject(d2);
                if (d != null) Marshal.ReleaseComObject(d);
                if (body != null) Marshal.ReleaseComObject(body);
                if (bodyelem != null) Marshal.ReleaseComObject(bodyelem);
                if (bodynode != null) Marshal.ReleaseComObject(bodynode);
            }

        }  

        public async Task TranslateNode(mshtml.IHTMLDOMNode node)
        {
            string val = "";

            if (node.nodeType == 3) //text node
            {
                val = node.nodeValue;
                if (val.Trim().Length == 0) return; //пусто - нечего переводить

                var res = await Translator.Translate(val, lang); //переводим содержимое узла           
                node.nodeValue = res; //меняем содержимое на перевод
            }
            else //element node
            {
                //не переводим скрипты и CSS
                if (node.nodeName.ToLower() == "script" || node.nodeName.ToLower() == "style") return;

                //обход дочерних узлов
                foreach (mshtml.IHTMLDOMNode x in node.childNodes)
                {
                    await TranslateNode(x);
                }
            }                

        }
    }
}

Example of the source text and translation:

<p><b>The Antarctic</b> is a polar region around the Earth's South Pole, opposite the Arctic region around the North Pole. The Antarctic comprises the continent of Antarctica and the island territories located on the Antarctic Plate. The Antarctic region include the ice shelves, waters, and island territories in the <i>Southern Ocean</i> situated south of the Antarctic Convergence, a zone approximately 32 to 48 km (20 to 30 mi) wide varying in latitude seasonally. The region covers some 20 percent of the Southern Hemisphere, of which 5.5 percent (14 million km2) is the surface area of the Antarctic continent itself. All of the land and ice shelves south of 60°S latitude are administered under the Antarctic Treaty System. Biogeographically, the Antarctic ecozone is one of eight ecozones of the Earth's land surface.</p>

<h2>Geography</h2>
<div>
<p>
The maritime part of the region constitutes the area of application of the international Convention for the Conservation of Antarctic Marine Living Resources (CCAMLR), where for technical reasons the Convention uses an approximation of the Convergence line by means of a line joining specified points along parallels of latitude and meridians of longitude. The implementation of the Convention is managed through an international Commission headquartered in Hobart, Australia, by an efficient system of annual fishing quotas, licenses and international inspectors on the fishing vessels, as well as satellite surveillance.</p>

<p>Most of the Antarctic region is situated south of 60°S latitude parallel, and is governed in accordance with the international legal regime of the Antarctic Treaty System. The Treaty area covers the continent itself and its immediately adjacent islands, as well as the archipelagos of the South Orkney Islands, South Shetland Islands, Peter I Island, Scott Island and Balleny Islands.</p>

<p>The islands situated between 60°S latitude parallel to the south and the Antarctic Convergence to the north, and their respective 200-nautical-mile (370 km) exclusive economic zones fall under the national jurisdiction of the countries that possess them: South Georgia and the South Sandwich Islands (United Kingdom; also an EU Overseas territory), Bouvet Island (Norway), and Heard and McDonald Islands (Australia).</p>

<p><b>Kerguelen Islands</b> (France; also an EU Overseas territory) are situated in the Antarctic Convergence area, while the Falkland Islands, Isla de los Estados, Hornos Island with Cape Horn, Diego Ramírez Islands, Campbell Island, Macquarie Island, Amsterdam and Saint Paul Islands, Crozet Islands, Prince Edward Islands, and Gough Island and Tristan da Cunha group remain north of the Convergence and thus outside the Antarctic region.</p>
</div>

<P><B>Антарктике</B> это полярные области вокруг Южного полюса Земли, противоположная Арктике, вокруг Северного полюса. Карта состоит из антарктического материка и островных территорий, расположенных на антарктической плиты. Антарктический регион включает шельфовые ледники, воды и островных территорий в <I>Южный Океан</I> расположенный к югу от антарктической конвергенции, зона примерно от 32 до 48 км (от 20 до 30 ми) широкий различающихся по широте сезонно. Регион охватывает около 20 процентов из Южного полушария, из которых 5,5 процента (14 млн. км2) площади Антарктического континента. Все земли и шельфовые ледники к югу от 60°южной широты применяются в рамках системы Договора об Антарктике. Биогеографически, экозона в Антарктике является одним из восьми экозонам земельных участков земной поверхности.</P>
<H2>География</H2>
<DIV>
<P>В морской части региона является область применения Международной конвенции по сохранению морских живых ресурсов Антарктики (АНТКОМ), где по техническим причинам в Конвенции используется аппроксимация сходимость линии с помощью линии, соединяющей указанные точки вдоль параллелей широты и меридианов долготы. Реализация конвенции осуществляется через международную комиссию со штаб-квартирой в Хобарте, Австралия, с помощью эффективной системы ежегодных квот, лицензий и международных инспекторов на рыболовных судах, а также спутниковое наблюдение.</P>
<P>Большинство Антарктический регион расположен к югу от 60°южной широты параллельно, и управляется в соответствии с международно-правовым режимом системы Договора об Антарктике. Области договора распространяется на континенте и прилегающих островах, а также архипелаги Южно-Оркнейские острова, Южные Шетландские острова, остров Петра I, Скотт островов и островов Баллени.</P>
<P>Острова, расположенные между 60°ю. ш параллельно Южной и Антарктической конвергенции на север, и их 200-мильной (370 км) исключительной экономической зоны находятся под национальной юрисдикцией стран, которые ими обладают: Южная Георгия и Южные Сандвичевы острова (Великобритания; также ЕС заморская территория), Остров Буве (Норвегия) и Острова Херд и Макдональд (Австралия).</P>
<P><B>Кергелен </B> (Франция; также ЕС заморская территория) находятся в антарктической конвергенции зона, а Фолклендские острова, Исла де лос Эстадос, Орнос на острове с мыса Горн, Диего-Рамирес острова, Кэмпбелл остров, остров Маккуори, Амстердам и Сен-Поль острова Крозе, Принс-Эдуард острова, и остров Гоф и Тристан-да-Кунья группы остаются Северная сходимости и, следовательно, за пределами Антарктики.</P></DIV>

But the downside is that this method generates too many small API requests, so translating a large document will take a very long time. In addition, the quality of the translation suffers, as the sentences will be divided into parts and translated separately. To improve this method, you need to figure out how to aggregate queries. Most likely, an element containing only inline subelements (b, span, etc.) should be translated as a whole piece, but how to do this while preserving the formatting is quite a task. complicated.

 1
Author: MSDN.WhiteKnight, 2018-10-19 07:46:25