├── .gitignore
├── README.md
└── src
├── .vs
└── XmlContentTranslator
│ └── v16
│ └── .suo
├── XmlContentTranslator.sln
└── XmlContentTranslator
├── Find.Designer.cs
├── Find.cs
├── Find.resx
├── ListViewItemComparer.cs
├── Main.Designer.cs
├── Main.cs
├── Main.resx
├── Program.cs
├── Properties
├── AssemblyInfo.cs
├── Resources.Designer.cs
├── Resources.resx
├── Settings.Designer.cs
└── Settings.settings
├── StringUtils.cs
├── Translator
├── Configuration.cs
├── Formatting.cs
├── GoogleTranslator1.cs
├── HtmlUtil.cs
├── ITranslator.cs
├── Json.cs
├── StringExtensions.cs
├── TranslationHelper.cs
├── TranslationPair.cs
└── Utilities.cs
├── XmlContentTranslator.csproj
├── XmlContentTranslator.csproj.user
├── XmlUtils.cs
├── app.config
├── file.ico
├── xct.ico
└── xct2.ico
/.gitignore:
--------------------------------------------------------------------------------
1 | bin
2 | obj
3 | /src/XmlContentTranslator/XmlContentTranslator.csproj.DotSettings
4 | /src/XmlContentTranslator/XmlContentTranslator.zip
5 | /src/.vs/XmlContentTranslator/v15
6 | /src/.vs/XmlContentTranslator
7 | /xct.pdn
8 | /xct.png
9 | /xct2.ico
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Xml Content Translator
2 |
3 | A tool for editing Subtitle Edit translations (or other xml files)
4 |
--------------------------------------------------------------------------------
/src/.vs/XmlContentTranslator/v16/.suo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubtitleEdit/XmlContentTranslator/1941f23b4abfbe64956f34b6b7b1c9e9f1f1c43a/src/.vs/XmlContentTranslator/v16/.suo
--------------------------------------------------------------------------------
/src/XmlContentTranslator.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 11.00
3 | # Visual Studio 2010
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XmlContentTranslator", "XmlContentTranslator\XmlContentTranslator.csproj", "{79BA7CB6-5613-4527-89C3-A4FF42810390}"
5 | EndProject
6 | Global
7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
8 | Debug|Any CPU = Debug|Any CPU
9 | Release|Any CPU = Release|Any CPU
10 | EndGlobalSection
11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
12 | {79BA7CB6-5613-4527-89C3-A4FF42810390}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
13 | {79BA7CB6-5613-4527-89C3-A4FF42810390}.Debug|Any CPU.Build.0 = Debug|Any CPU
14 | {79BA7CB6-5613-4527-89C3-A4FF42810390}.Release|Any CPU.ActiveCfg = Release|Any CPU
15 | {79BA7CB6-5613-4527-89C3-A4FF42810390}.Release|Any CPU.Build.0 = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(SolutionProperties) = preSolution
18 | HideSolutionNode = FALSE
19 | EndGlobalSection
20 | EndGlobal
21 |
--------------------------------------------------------------------------------
/src/XmlContentTranslator/Find.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace XmlContentTranslator
2 | {
3 | partial class Find
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.buttonFind = new System.Windows.Forms.Button();
32 | this.label1 = new System.Windows.Forms.Label();
33 | this.textBox1 = new System.Windows.Forms.TextBox();
34 | this.radioButtonTags = new System.Windows.Forms.RadioButton();
35 | this.groupBoxSearchIn = new System.Windows.Forms.GroupBox();
36 | this.radioButtonText = new System.Windows.Forms.RadioButton();
37 | this.button1 = new System.Windows.Forms.Button();
38 | this.groupBoxSearchIn.SuspendLayout();
39 | this.SuspendLayout();
40 | //
41 | // buttonFind
42 | //
43 | this.buttonFind.Location = new System.Drawing.Point(244, 25);
44 | this.buttonFind.Name = "buttonFind";
45 | this.buttonFind.Size = new System.Drawing.Size(98, 23);
46 | this.buttonFind.TabIndex = 3;
47 | this.buttonFind.Text = "&Find";
48 | this.buttonFind.UseVisualStyleBackColor = true;
49 | this.buttonFind.Click += new System.EventHandler(this.buttonFind_Click);
50 | //
51 | // label1
52 | //
53 | this.label1.AutoSize = true;
54 | this.label1.Location = new System.Drawing.Point(12, 9);
55 | this.label1.Name = "label1";
56 | this.label1.Size = new System.Drawing.Size(56, 13);
57 | this.label1.TabIndex = 0;
58 | this.label1.Text = "Find what:";
59 | //
60 | // textBox1
61 | //
62 | this.textBox1.Location = new System.Drawing.Point(12, 25);
63 | this.textBox1.Name = "textBox1";
64 | this.textBox1.Size = new System.Drawing.Size(226, 20);
65 | this.textBox1.TabIndex = 1;
66 | //
67 | // radioButtonTags
68 | //
69 | this.radioButtonTags.AutoSize = true;
70 | this.radioButtonTags.Location = new System.Drawing.Point(19, 19);
71 | this.radioButtonTags.Name = "radioButtonTags";
72 | this.radioButtonTags.Size = new System.Drawing.Size(49, 17);
73 | this.radioButtonTags.TabIndex = 0;
74 | this.radioButtonTags.TabStop = true;
75 | this.radioButtonTags.Text = "Tags";
76 | this.radioButtonTags.UseVisualStyleBackColor = true;
77 | //
78 | // groupBoxSearchIn
79 | //
80 | this.groupBoxSearchIn.Controls.Add(this.radioButtonText);
81 | this.groupBoxSearchIn.Controls.Add(this.radioButtonTags);
82 | this.groupBoxSearchIn.Location = new System.Drawing.Point(15, 54);
83 | this.groupBoxSearchIn.Name = "groupBoxSearchIn";
84 | this.groupBoxSearchIn.Size = new System.Drawing.Size(223, 51);
85 | this.groupBoxSearchIn.TabIndex = 2;
86 | this.groupBoxSearchIn.TabStop = false;
87 | this.groupBoxSearchIn.Text = "Search in";
88 | //
89 | // radioButtonText
90 | //
91 | this.radioButtonText.AutoSize = true;
92 | this.radioButtonText.Location = new System.Drawing.Point(86, 19);
93 | this.radioButtonText.Name = "radioButtonText";
94 | this.radioButtonText.Size = new System.Drawing.Size(46, 17);
95 | this.radioButtonText.TabIndex = 1;
96 | this.radioButtonText.TabStop = true;
97 | this.radioButtonText.Text = "Text";
98 | this.radioButtonText.UseVisualStyleBackColor = true;
99 | //
100 | // button1
101 | //
102 | this.button1.Location = new System.Drawing.Point(244, 54);
103 | this.button1.Name = "button1";
104 | this.button1.Size = new System.Drawing.Size(98, 23);
105 | this.button1.TabIndex = 4;
106 | this.button1.Text = "C&ancel";
107 | this.button1.UseVisualStyleBackColor = true;
108 | this.button1.Click += new System.EventHandler(this.button1_Click);
109 | //
110 | // Find
111 | //
112 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
113 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
114 | this.ClientSize = new System.Drawing.Size(354, 125);
115 | this.Controls.Add(this.button1);
116 | this.Controls.Add(this.groupBoxSearchIn);
117 | this.Controls.Add(this.textBox1);
118 | this.Controls.Add(this.label1);
119 | this.Controls.Add(this.buttonFind);
120 | this.KeyPreview = true;
121 | this.MaximizeBox = false;
122 | this.MinimizeBox = false;
123 | this.Name = "Find";
124 | this.ShowIcon = false;
125 | this.ShowInTaskbar = false;
126 | this.Text = "Find";
127 | this.Shown += new System.EventHandler(this.Find_Shown);
128 | this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Find_KeyDown);
129 | this.groupBoxSearchIn.ResumeLayout(false);
130 | this.groupBoxSearchIn.PerformLayout();
131 | this.ResumeLayout(false);
132 | this.PerformLayout();
133 |
134 | }
135 |
136 | #endregion
137 |
138 | private System.Windows.Forms.Button buttonFind;
139 | private System.Windows.Forms.Label label1;
140 | private System.Windows.Forms.TextBox textBox1;
141 | private System.Windows.Forms.RadioButton radioButtonTags;
142 | private System.Windows.Forms.GroupBox groupBoxSearchIn;
143 | private System.Windows.Forms.RadioButton radioButtonText;
144 | private System.Windows.Forms.Button button1;
145 | }
146 | }
--------------------------------------------------------------------------------
/src/XmlContentTranslator/Find.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Forms;
3 |
4 | namespace XmlContentTranslator
5 | {
6 | public partial class Find : Form
7 | {
8 | public bool SearchTags { get; set; }
9 | public string SearchText { get; set; }
10 |
11 | public Find()
12 | {
13 | InitializeComponent();
14 | radioButtonText.Checked = true;
15 | }
16 |
17 | private void Find_KeyDown(object sender, KeyEventArgs e)
18 | {
19 | if (e.KeyCode == Keys.Escape)
20 | {
21 | DialogResult = DialogResult.Cancel;
22 | }
23 | else if (e.KeyCode == Keys.Enter)
24 | {
25 | buttonFind_Click(sender, e);
26 | }
27 | }
28 |
29 | private void button1_Click(object sender, EventArgs e)
30 | {
31 | DialogResult = DialogResult.Cancel;
32 | }
33 |
34 | private void buttonFind_Click(object sender, EventArgs e)
35 | {
36 | SearchTags = radioButtonTags.Checked;
37 | SearchText = textBox1.Text;
38 | DialogResult = DialogResult.OK;
39 | }
40 |
41 | private void Find_Shown(object sender, EventArgs e)
42 | {
43 | textBox1.Focus();
44 | textBox1.SelectAll();
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/XmlContentTranslator/Find.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
--------------------------------------------------------------------------------
/src/XmlContentTranslator/ListViewItemComparer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Windows.Forms;
5 |
6 | namespace XmlContentTranslator
7 | {
8 | public class ListViewItemComparer : IComparer
9 | {
10 | public static Dictionary NoSortOrder = new Dictionary();
11 |
12 | public int ColumnIndex { get; set; }
13 |
14 | public SortOrder SortDirection { get; set; }
15 |
16 | public TypeCode ColumnType { get; set; }
17 |
18 | public ListViewItemComparer()
19 | {
20 | SortDirection = SortOrder.None;
21 | }
22 |
23 | public int Compare(object x, object y)
24 | {
25 | var lviX = x as ListViewItem;
26 | var lviY = y as ListViewItem;
27 |
28 | if (SortDirection == SortOrder.None)
29 | {
30 | return decimal.Compare(NoSortOrder[lviX], NoSortOrder[lviY]);
31 | }
32 |
33 | if (lviX == null && lviY == null)
34 | {
35 | return CompareResult(0);
36 | }
37 |
38 | if (lviX == null)
39 | {
40 | return CompareResult(-1); ;
41 | }
42 |
43 | if (lviY == null)
44 | {
45 | return CompareResult(1);
46 | }
47 |
48 | switch (ColumnType)
49 | {
50 | case TypeCode.Decimal:
51 | decimal xD = 0;
52 | if (decimal.TryParse(lviX.SubItems[ColumnIndex].Text, out var dx))
53 | {
54 | xD = dx;
55 | }
56 |
57 | decimal yD = 0;
58 | if (decimal.TryParse(lviY.SubItems[ColumnIndex].Text, out var dy))
59 | {
60 | yD = dy;
61 | }
62 |
63 | return CompareResult(decimal.Compare(xD, yD));
64 |
65 | default:
66 | return CompareResult(string.Compare(
67 | lviX.SubItems[ColumnIndex].Text,
68 | lviY.SubItems[ColumnIndex].Text));
69 | }
70 | }
71 |
72 | private int CompareResult(int result)
73 | {
74 | if (SortDirection == SortOrder.Descending)
75 | {
76 | return -result;
77 | }
78 |
79 | return result;
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/XmlContentTranslator/Main.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace XmlContentTranslator
2 | {
3 | partial class Main
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.components = new System.ComponentModel.Container();
32 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Main));
33 | this.listViewLanguageTags = new System.Windows.Forms.ListView();
34 | this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
35 | this.translateViaGoogleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
36 | this.setValueFromMasterToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
37 | this.menuStrip1 = new System.Windows.Forms.MenuStrip();
38 | this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
39 | this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
40 | this.openToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
41 | this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripMenuItem();
42 | this.saveToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
43 | this.saveAsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
44 | this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
45 | this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
46 | this.editToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
47 | this.findToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
48 | this.toolsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
49 | this.googleTranslateSelectedLinesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
50 | this.textBoxCurrentText = new System.Windows.Forms.TextBox();
51 | this.treeView1 = new System.Windows.Forms.TreeView();
52 | this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
53 | this.saveFileDialog1 = new System.Windows.Forms.SaveFileDialog();
54 | this.statusStrip1 = new System.Windows.Forms.StatusStrip();
55 | this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel();
56 | this.toolStripStatusLabel2 = new System.Windows.Forms.ToolStripStatusLabel();
57 | this.labelTo = new System.Windows.Forms.Label();
58 | this.comboBoxTo = new System.Windows.Forms.ComboBox();
59 | this.labelFrom = new System.Windows.Forms.Label();
60 | this.comboBoxFrom = new System.Windows.Forms.ComboBox();
61 | this.buttonGoToNextBlankLine = new System.Windows.Forms.Button();
62 | this.contextMenuStrip1.SuspendLayout();
63 | this.menuStrip1.SuspendLayout();
64 | this.statusStrip1.SuspendLayout();
65 | this.SuspendLayout();
66 | //
67 | // listViewLanguageTags
68 | //
69 | this.listViewLanguageTags.AllowDrop = true;
70 | this.listViewLanguageTags.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
71 | | System.Windows.Forms.AnchorStyles.Left)
72 | | System.Windows.Forms.AnchorStyles.Right)));
73 | this.listViewLanguageTags.ContextMenuStrip = this.contextMenuStrip1;
74 | this.listViewLanguageTags.FullRowSelect = true;
75 | this.listViewLanguageTags.HideSelection = false;
76 | this.listViewLanguageTags.Location = new System.Drawing.Point(255, 60);
77 | this.listViewLanguageTags.Name = "listViewLanguageTags";
78 | this.listViewLanguageTags.Size = new System.Drawing.Size(652, 421);
79 | this.listViewLanguageTags.TabIndex = 10;
80 | this.listViewLanguageTags.UseCompatibleStateImageBehavior = false;
81 | this.listViewLanguageTags.View = System.Windows.Forms.View.Details;
82 | this.listViewLanguageTags.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.listViewLanguageTags_ColumnClick);
83 | this.listViewLanguageTags.SelectedIndexChanged += new System.EventHandler(this.ListViewLanguageTagsSelectedIndexChanged);
84 | this.listViewLanguageTags.DragDrop += new System.Windows.Forms.DragEventHandler(this.ListViewLanguageTagsDragDrop);
85 | this.listViewLanguageTags.DragEnter += new System.Windows.Forms.DragEventHandler(this.ListViewLanguageTagsDragEnter);
86 | this.listViewLanguageTags.DoubleClick += new System.EventHandler(this.listViewLanguageTags_DoubleClick);
87 | //
88 | // contextMenuStrip1
89 | //
90 | this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
91 | this.translateViaGoogleToolStripMenuItem,
92 | this.setValueFromMasterToolStripMenuItem});
93 | this.contextMenuStrip1.Name = "contextMenuStrip1";
94 | this.contextMenuStrip1.Size = new System.Drawing.Size(215, 48);
95 | //
96 | // translateViaGoogleToolStripMenuItem
97 | //
98 | this.translateViaGoogleToolStripMenuItem.Name = "translateViaGoogleToolStripMenuItem";
99 | this.translateViaGoogleToolStripMenuItem.Size = new System.Drawing.Size(214, 22);
100 | this.translateViaGoogleToolStripMenuItem.Text = "Translate via google";
101 | this.translateViaGoogleToolStripMenuItem.Click += new System.EventHandler(this.translateViaGoogleToolStripMenuItem_Click);
102 | //
103 | // setValueFromMasterToolStripMenuItem
104 | //
105 | this.setValueFromMasterToolStripMenuItem.Name = "setValueFromMasterToolStripMenuItem";
106 | this.setValueFromMasterToolStripMenuItem.Size = new System.Drawing.Size(214, 22);
107 | this.setValueFromMasterToolStripMenuItem.Text = "Transfer value from master";
108 | this.setValueFromMasterToolStripMenuItem.Click += new System.EventHandler(this.setValueFromMasterToolStripMenuItem_Click);
109 | //
110 | // menuStrip1
111 | //
112 | this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
113 | this.fileToolStripMenuItem,
114 | this.editToolStripMenuItem,
115 | this.toolsToolStripMenuItem});
116 | this.menuStrip1.Location = new System.Drawing.Point(0, 0);
117 | this.menuStrip1.Name = "menuStrip1";
118 | this.menuStrip1.Size = new System.Drawing.Size(919, 24);
119 | this.menuStrip1.TabIndex = 11;
120 | this.menuStrip1.Text = "menuStrip1";
121 | //
122 | // fileToolStripMenuItem
123 | //
124 | this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
125 | this.toolStripMenuItem1,
126 | this.openToolStripMenuItem,
127 | this.toolStripMenuItem2,
128 | this.saveToolStripMenuItem,
129 | this.saveAsToolStripMenuItem,
130 | this.toolStripSeparator1,
131 | this.exitToolStripMenuItem});
132 | this.fileToolStripMenuItem.Name = "fileToolStripMenuItem";
133 | this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20);
134 | this.fileToolStripMenuItem.Text = "&File";
135 | //
136 | // toolStripMenuItem1
137 | //
138 | this.toolStripMenuItem1.Name = "toolStripMenuItem1";
139 | this.toolStripMenuItem1.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.N)));
140 | this.toolStripMenuItem1.Size = new System.Drawing.Size(341, 22);
141 | this.toolStripMenuItem1.Text = "&New";
142 | this.toolStripMenuItem1.Click += new System.EventHandler(this.ToolStripMenuItem1Click);
143 | //
144 | // openToolStripMenuItem
145 | //
146 | this.openToolStripMenuItem.Name = "openToolStripMenuItem";
147 | this.openToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.O)));
148 | this.openToolStripMenuItem.Size = new System.Drawing.Size(341, 22);
149 | this.openToolStripMenuItem.Text = "&Open";
150 | this.openToolStripMenuItem.Click += new System.EventHandler(this.OpenToolStripMenuItemClick);
151 | //
152 | // toolStripMenuItem2
153 | //
154 | this.toolStripMenuItem2.Name = "toolStripMenuItem2";
155 | this.toolStripMenuItem2.Size = new System.Drawing.Size(341, 22);
156 | this.toolStripMenuItem2.Text = "Open Subtitle Edit English translation base online...";
157 | this.toolStripMenuItem2.Click += new System.EventHandler(this.toolStripMenuItem2_Click);
158 | //
159 | // saveToolStripMenuItem
160 | //
161 | this.saveToolStripMenuItem.Name = "saveToolStripMenuItem";
162 | this.saveToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.S)));
163 | this.saveToolStripMenuItem.Size = new System.Drawing.Size(341, 22);
164 | this.saveToolStripMenuItem.Text = "&Save";
165 | this.saveToolStripMenuItem.Click += new System.EventHandler(this.SaveToolStripMenuItemClick);
166 | //
167 | // saveAsToolStripMenuItem
168 | //
169 | this.saveAsToolStripMenuItem.Name = "saveAsToolStripMenuItem";
170 | this.saveAsToolStripMenuItem.Size = new System.Drawing.Size(341, 22);
171 | this.saveAsToolStripMenuItem.Text = "Save &as...";
172 | this.saveAsToolStripMenuItem.Click += new System.EventHandler(this.SaveAsToolStripMenuItemClick);
173 | //
174 | // toolStripSeparator1
175 | //
176 | this.toolStripSeparator1.Name = "toolStripSeparator1";
177 | this.toolStripSeparator1.Size = new System.Drawing.Size(338, 6);
178 | //
179 | // exitToolStripMenuItem
180 | //
181 | this.exitToolStripMenuItem.Name = "exitToolStripMenuItem";
182 | this.exitToolStripMenuItem.Size = new System.Drawing.Size(341, 22);
183 | this.exitToolStripMenuItem.Text = "E&xit";
184 | this.exitToolStripMenuItem.Click += new System.EventHandler(this.ExitToolStripMenuItemClick);
185 | //
186 | // editToolStripMenuItem
187 | //
188 | this.editToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
189 | this.findToolStripMenuItem});
190 | this.editToolStripMenuItem.Name = "editToolStripMenuItem";
191 | this.editToolStripMenuItem.Size = new System.Drawing.Size(39, 20);
192 | this.editToolStripMenuItem.Text = "&Edit";
193 | //
194 | // findToolStripMenuItem
195 | //
196 | this.findToolStripMenuItem.Name = "findToolStripMenuItem";
197 | this.findToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.F)));
198 | this.findToolStripMenuItem.Size = new System.Drawing.Size(137, 22);
199 | this.findToolStripMenuItem.Text = "&Find";
200 | this.findToolStripMenuItem.Click += new System.EventHandler(this.findToolStripMenuItem_Click);
201 | //
202 | // toolsToolStripMenuItem
203 | //
204 | this.toolsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
205 | this.googleTranslateSelectedLinesToolStripMenuItem});
206 | this.toolsToolStripMenuItem.Name = "toolsToolStripMenuItem";
207 | this.toolsToolStripMenuItem.Size = new System.Drawing.Size(46, 20);
208 | this.toolsToolStripMenuItem.Text = "&Tools";
209 | //
210 | // googleTranslateSelectedLinesToolStripMenuItem
211 | //
212 | this.googleTranslateSelectedLinesToolStripMenuItem.Name = "googleTranslateSelectedLinesToolStripMenuItem";
213 | this.googleTranslateSelectedLinesToolStripMenuItem.Size = new System.Drawing.Size(233, 22);
214 | this.googleTranslateSelectedLinesToolStripMenuItem.Text = "Google &translate selected lines";
215 | this.googleTranslateSelectedLinesToolStripMenuItem.Click += new System.EventHandler(this.GoogleTranslateSelectedLinesToolStripMenuItemClick);
216 | //
217 | // textBoxCurrentText
218 | //
219 | this.textBoxCurrentText.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
220 | | System.Windows.Forms.AnchorStyles.Right)));
221 | this.textBoxCurrentText.Location = new System.Drawing.Point(255, 487);
222 | this.textBoxCurrentText.Multiline = true;
223 | this.textBoxCurrentText.Name = "textBoxCurrentText";
224 | this.textBoxCurrentText.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
225 | this.textBoxCurrentText.Size = new System.Drawing.Size(652, 80);
226 | this.textBoxCurrentText.TabIndex = 12;
227 | this.textBoxCurrentText.TextChanged += new System.EventHandler(this.TextBoxCurrentTextTextChanged);
228 | this.textBoxCurrentText.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TextBoxCurrentTextKeyDown);
229 | //
230 | // treeView1
231 | //
232 | this.treeView1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
233 | | System.Windows.Forms.AnchorStyles.Left)));
234 | this.treeView1.HideSelection = false;
235 | this.treeView1.Location = new System.Drawing.Point(13, 60);
236 | this.treeView1.Name = "treeView1";
237 | this.treeView1.Size = new System.Drawing.Size(236, 507);
238 | this.treeView1.TabIndex = 13;
239 | this.treeView1.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.TreeView1AfterSelect);
240 | //
241 | // openFileDialog1
242 | //
243 | this.openFileDialog1.FileName = "openFileDialog1";
244 | //
245 | // statusStrip1
246 | //
247 | this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
248 | this.toolStripStatusLabel1,
249 | this.toolStripStatusLabel2});
250 | this.statusStrip1.Location = new System.Drawing.Point(0, 570);
251 | this.statusStrip1.Name = "statusStrip1";
252 | this.statusStrip1.Size = new System.Drawing.Size(919, 22);
253 | this.statusStrip1.TabIndex = 14;
254 | this.statusStrip1.Text = "statusStrip1";
255 | //
256 | // toolStripStatusLabel1
257 | //
258 | this.toolStripStatusLabel1.Name = "toolStripStatusLabel1";
259 | this.toolStripStatusLabel1.Size = new System.Drawing.Size(118, 17);
260 | this.toolStripStatusLabel1.Text = "toolStripStatusLabel1";
261 | //
262 | // toolStripStatusLabel2
263 | //
264 | this.toolStripStatusLabel2.Name = "toolStripStatusLabel2";
265 | this.toolStripStatusLabel2.Size = new System.Drawing.Size(786, 17);
266 | this.toolStripStatusLabel2.Spring = true;
267 | this.toolStripStatusLabel2.Text = "toolStripStatusLabel2";
268 | this.toolStripStatusLabel2.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
269 | //
270 | // labelTo
271 | //
272 | this.labelTo.AutoSize = true;
273 | this.labelTo.Location = new System.Drawing.Point(639, 36);
274 | this.labelTo.Name = "labelTo";
275 | this.labelTo.Size = new System.Drawing.Size(23, 13);
276 | this.labelTo.TabIndex = 19;
277 | this.labelTo.Text = "To:";
278 | //
279 | // comboBoxTo
280 | //
281 | this.comboBoxTo.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
282 | this.comboBoxTo.FormattingEnabled = true;
283 | this.comboBoxTo.Location = new System.Drawing.Point(665, 33);
284 | this.comboBoxTo.Name = "comboBoxTo";
285 | this.comboBoxTo.Size = new System.Drawing.Size(121, 21);
286 | this.comboBoxTo.TabIndex = 18;
287 | //
288 | // labelFrom
289 | //
290 | this.labelFrom.AutoSize = true;
291 | this.labelFrom.Location = new System.Drawing.Point(450, 36);
292 | this.labelFrom.Name = "labelFrom";
293 | this.labelFrom.Size = new System.Drawing.Size(33, 13);
294 | this.labelFrom.TabIndex = 17;
295 | this.labelFrom.Text = "From:";
296 | //
297 | // comboBoxFrom
298 | //
299 | this.comboBoxFrom.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
300 | this.comboBoxFrom.FormattingEnabled = true;
301 | this.comboBoxFrom.Location = new System.Drawing.Point(486, 33);
302 | this.comboBoxFrom.Name = "comboBoxFrom";
303 | this.comboBoxFrom.Size = new System.Drawing.Size(121, 21);
304 | this.comboBoxFrom.TabIndex = 16;
305 | //
306 | // buttonGoToNextBlankLine
307 | //
308 | this.buttonGoToNextBlankLine.Location = new System.Drawing.Point(256, 31);
309 | this.buttonGoToNextBlankLine.Name = "buttonGoToNextBlankLine";
310 | this.buttonGoToNextBlankLine.Size = new System.Drawing.Size(156, 23);
311 | this.buttonGoToNextBlankLine.TabIndex = 20;
312 | this.buttonGoToNextBlankLine.Text = "Go to next blank line (F6)";
313 | this.buttonGoToNextBlankLine.UseVisualStyleBackColor = true;
314 | this.buttonGoToNextBlankLine.Click += new System.EventHandler(this.ButtonGoToNextBlankLineClick);
315 | //
316 | // Main
317 | //
318 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
319 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
320 | this.ClientSize = new System.Drawing.Size(919, 592);
321 | this.Controls.Add(this.buttonGoToNextBlankLine);
322 | this.Controls.Add(this.labelTo);
323 | this.Controls.Add(this.comboBoxTo);
324 | this.Controls.Add(this.labelFrom);
325 | this.Controls.Add(this.comboBoxFrom);
326 | this.Controls.Add(this.statusStrip1);
327 | this.Controls.Add(this.treeView1);
328 | this.Controls.Add(this.textBoxCurrentText);
329 | this.Controls.Add(this.listViewLanguageTags);
330 | this.Controls.Add(this.menuStrip1);
331 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
332 | this.KeyPreview = true;
333 | this.MainMenuStrip = this.menuStrip1;
334 | this.MinimumSize = new System.Drawing.Size(820, 350);
335 | this.Name = "Main";
336 | this.Text = "XML Content Translator 1.12";
337 | this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1FormClosing);
338 | this.Load += new System.EventHandler(this.Form1Load);
339 | this.ResizeEnd += new System.EventHandler(this.Main_ResizeEnd);
340 | this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1KeyDown);
341 | this.Resize += new System.EventHandler(this.Main_Resize);
342 | this.contextMenuStrip1.ResumeLayout(false);
343 | this.menuStrip1.ResumeLayout(false);
344 | this.menuStrip1.PerformLayout();
345 | this.statusStrip1.ResumeLayout(false);
346 | this.statusStrip1.PerformLayout();
347 | this.ResumeLayout(false);
348 | this.PerformLayout();
349 |
350 | }
351 |
352 | #endregion
353 |
354 | private System.Windows.Forms.ListView listViewLanguageTags;
355 | private System.Windows.Forms.MenuStrip menuStrip1;
356 | private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem;
357 | private System.Windows.Forms.ToolStripMenuItem openToolStripMenuItem;
358 | private System.Windows.Forms.TextBox textBoxCurrentText;
359 | private System.Windows.Forms.TreeView treeView1;
360 | private System.Windows.Forms.ToolStripMenuItem saveToolStripMenuItem;
361 | private System.Windows.Forms.ToolStripMenuItem saveAsToolStripMenuItem;
362 | private System.Windows.Forms.ToolStripMenuItem toolsToolStripMenuItem;
363 | private System.Windows.Forms.ToolStripMenuItem googleTranslateSelectedLinesToolStripMenuItem;
364 | private System.Windows.Forms.OpenFileDialog openFileDialog1;
365 | private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem1;
366 | private System.Windows.Forms.ToolStripSeparator toolStripSeparator1;
367 | private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem;
368 | private System.Windows.Forms.SaveFileDialog saveFileDialog1;
369 | private System.Windows.Forms.StatusStrip statusStrip1;
370 | private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1;
371 | private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel2;
372 | private System.Windows.Forms.ContextMenuStrip contextMenuStrip1;
373 | private System.Windows.Forms.ToolStripMenuItem setValueFromMasterToolStripMenuItem;
374 | private System.Windows.Forms.ToolStripMenuItem translateViaGoogleToolStripMenuItem;
375 | private System.Windows.Forms.Label labelTo;
376 | private System.Windows.Forms.ComboBox comboBoxTo;
377 | private System.Windows.Forms.Label labelFrom;
378 | private System.Windows.Forms.ComboBox comboBoxFrom;
379 | private System.Windows.Forms.Button buttonGoToNextBlankLine;
380 | private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem2;
381 | private System.Windows.Forms.ToolStripMenuItem editToolStripMenuItem;
382 | private System.Windows.Forms.ToolStripMenuItem findToolStripMenuItem;
383 | }
384 | }
385 |
386 |
--------------------------------------------------------------------------------
/src/XmlContentTranslator/Main.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Drawing;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Net;
8 | using System.Text;
9 | using System.Web;
10 | using System.Windows.Forms;
11 | using System.Xml;
12 | using XmlContentTranslator.Translator;
13 |
14 | namespace XmlContentTranslator
15 | {
16 | public partial class Main : Form
17 | {
18 | public class ComboBoxItem
19 | {
20 | private string Text { get; }
21 | public string Value { get; }
22 |
23 | public ComboBoxItem(string text, string value)
24 | {
25 | if (text.Length > 1)
26 | {
27 | text = text.Substring(0, 1).ToUpper() + text.Substring(1).ToLower();
28 | }
29 |
30 | Text = text;
31 | Value = value;
32 | }
33 |
34 | public override string ToString()
35 | {
36 | return Text;
37 | }
38 | }
39 |
40 | private Hashtable _treeNodesHashtable = new Hashtable();
41 | private Hashtable _listViewItemHashtable = new Hashtable();
42 | private XmlDocument _originalDocument;
43 | private string _secondLanguageFileName;
44 | private bool _change;
45 | private Find _formFind;
46 |
47 | public Main()
48 | {
49 | InitializeComponent();
50 | toolStripStatusLabel1.Text = string.Empty;
51 | toolStripStatusLabel2.Text = string.Empty;
52 |
53 | FillComboWithLanguages(comboBoxFrom);
54 | FillComboWithLanguages(comboBoxTo);
55 | }
56 |
57 | private void listViewLanguageTags_ColumnClick(object sender, ColumnClickEventArgs e)
58 | {
59 | var sorter = GetListViewSorter(e.Column);
60 | listViewLanguageTags.ListViewItemSorter = sorter;
61 | listViewLanguageTags.Sort();
62 | }
63 |
64 | private ListViewItemComparer GetListViewSorter(int columnIndex)
65 | {
66 | var sorter = (ListViewItemComparer)listViewLanguageTags.ListViewItemSorter;
67 | if (sorter == null)
68 | {
69 | sorter = new ListViewItemComparer();
70 | }
71 |
72 | sorter.ColumnIndex = columnIndex;
73 |
74 | var columnName = listViewLanguageTags.Columns[columnIndex].Name;
75 | switch (columnName)
76 | {
77 | default:
78 | sorter.ColumnType = TypeCode.String;
79 | break;
80 | }
81 |
82 | for (var i = 0; i < listViewLanguageTags.Columns.Count; i++)
83 | {
84 | listViewLanguageTags.Columns[i].Text = listViewLanguageTags.Columns[i].Text.TrimEnd(' ', '↑', '↓');
85 | }
86 |
87 | if (sorter.SortDirection == SortOrder.Ascending)
88 | {
89 | sorter.SortDirection = SortOrder.Descending;
90 | listViewLanguageTags.Columns[columnIndex].Text += " ↑";
91 | }
92 | else if (sorter.SortDirection == SortOrder.Descending)
93 | {
94 | sorter.SortDirection = SortOrder.None;
95 | }
96 | else
97 | {
98 | sorter.SortDirection = SortOrder.Ascending;
99 | listViewLanguageTags.Columns[columnIndex].Text += " ↓";
100 | }
101 |
102 | return sorter;
103 | }
104 |
105 | private void OpenToolStripMenuItemClick(object sender, EventArgs e)
106 | {
107 | if (_change && listViewLanguageTags.Columns.Count == 3 &&
108 | MessageBox.Show("Changes will be lost. Continue?", "Continue", MessageBoxButtons.YesNo) == DialogResult.No)
109 | {
110 | return;
111 | }
112 |
113 | openFileDialog1.FileName = string.Empty;
114 | openFileDialog1.DefaultExt = ".xml";
115 | openFileDialog1.Filter = "Xml files|*.xml" + "|All files|*.*";
116 | openFileDialog1.Title = "Open language master file";
117 | if (openFileDialog1.ShowDialog() == DialogResult.OK)
118 | {
119 | MakeNew();
120 | if (OpenFirstFile(openFileDialog1.FileName))
121 | {
122 | OpenSecondFile();
123 | }
124 | }
125 | }
126 |
127 | private bool OpenFirstFile(string fileName)
128 | {
129 | toolStripStatusLabel1.Text = "Opening " + fileName + "...";
130 | var doc = new XmlDocument();
131 | try
132 | {
133 | doc.Load(fileName);
134 | }
135 | catch
136 | {
137 | MessageBox.Show("Not a valid xml file: " + fileName);
138 | return false;
139 | }
140 |
141 | return OpenFirstXmlDocument(doc);
142 | }
143 |
144 | private bool OpenFirstXmlDocument(XmlDocument doc)
145 | {
146 | listViewLanguageTags.Columns.Add("Tag", 150);
147 | TryGetLanguageNameAttribute(doc, comboBoxFrom);
148 |
149 | AddAttributes(doc.DocumentElement);
150 | if (doc.DocumentElement != null)
151 | {
152 | foreach (XmlNode childNode in doc.DocumentElement.ChildNodes)
153 | {
154 | if (childNode.NodeType != XmlNodeType.Attribute)
155 | {
156 | var treeNode = new TreeNode(childNode.Name);
157 | treeNode.Tag = childNode;
158 | treeView1.Nodes.Add(treeNode);
159 | if (childNode.ChildNodes.Count > 0 && !XmlUtils.IsTextNode(childNode))
160 | {
161 | ExpandNode(treeNode, childNode);
162 | }
163 | else
164 | {
165 | _treeNodesHashtable.Add(treeNode, childNode);
166 | AddListViewItem(childNode);
167 | }
168 | }
169 | }
170 | }
171 | _originalDocument = doc;
172 | toolStripStatusLabel1.Text = "Done reading " + openFileDialog1.FileName;
173 | return true;
174 | }
175 |
176 | private void SetLanguage(ComboBox comboBox, XmlDocument doc)
177 | {
178 | int index = 0;
179 | comboBox.SelectedIndex = -1;
180 | int defaultIndex = -1;
181 | bool isDefaultSet = false;
182 | if (doc != null && doc.DocumentElement != null && doc.DocumentElement.SelectSingleNode("General/CultureName") != null)
183 | {
184 | string culture = doc.DocumentElement.SelectSingleNode("General/CultureName").InnerText;
185 | foreach (ComboBoxItem item in comboBox.Items)
186 | {
187 | if (item.Value == culture)
188 | {
189 | comboBox.SelectedIndex = index;
190 | return;
191 | }
192 | if (isDefaultSet == false && item.Value == "en")
193 | {
194 | defaultIndex = index;
195 | isDefaultSet = true;
196 | }
197 | index++;
198 | }
199 |
200 | culture = culture.Substring(0, 2);
201 | index = 0;
202 | foreach (ComboBoxItem item in comboBox.Items)
203 | {
204 | if (item.Value == culture)
205 | {
206 | comboBox.SelectedIndex = index;
207 | return;
208 | }
209 | index++;
210 | }
211 | }
212 | if (defaultIndex >= 0)
213 | comboBox.SelectedIndex = defaultIndex;
214 | }
215 |
216 | private void OpenSecondFile()
217 | {
218 | _secondLanguageFileName = string.Empty;
219 | Text = "XML Content Translator - New";
220 | openFileDialog1.Title = "Open file to translate/correct";
221 | if (openFileDialog1.ShowDialog() == DialogResult.OK)
222 | {
223 | OpenSecondFile(openFileDialog1.FileName);
224 | }
225 | else
226 | {
227 | listViewLanguageTags.Columns.Add("Language 2", 200);
228 | SetLanguage(comboBoxTo, null);
229 | CreateEmptyLanguage();
230 | }
231 | HighLightLinesWithSameText();
232 | }
233 |
234 | private void OpenSecondFile(string fileName)
235 | {
236 | toolStripStatusLabel1.Text = "Opening " + fileName + "...";
237 | _secondLanguageFileName = fileName;
238 | Text = "XML Content Translator - " + _secondLanguageFileName;
239 |
240 | Cursor = Cursors.WaitCursor;
241 | listViewLanguageTags.BeginUpdate();
242 | var doc = new XmlDocument();
243 | try
244 | {
245 | doc.Load(_secondLanguageFileName);
246 | }
247 | catch
248 | {
249 | MessageBox.Show("Not a valid xml file: " + _secondLanguageFileName);
250 | }
251 |
252 | TryGetLanguageNameAttribute(doc, comboBoxTo);
253 |
254 | AddAttributes(doc.DocumentElement);
255 | if (doc.DocumentElement != null)
256 | {
257 | foreach (XmlNode childNode in doc.DocumentElement.ChildNodes)
258 | {
259 | if (childNode.ChildNodes.Count > 0 && !XmlUtils.IsTextNode(childNode))
260 | {
261 | ExpandNode(null, childNode);
262 | }
263 | else
264 | {
265 | AddListViewItem(childNode);
266 | AddAttributes(doc.DocumentElement);
267 | }
268 | }
269 | }
270 |
271 | CreateEmptyLanguage();
272 |
273 | listViewLanguageTags.EndUpdate();
274 | Cursor = Cursors.Default;
275 | toolStripStatusLabel1.Text = "Done reading " + _secondLanguageFileName;
276 | }
277 |
278 | private void TryGetLanguageNameAttribute(XmlDocument doc, ComboBox cb)
279 | {
280 | if (doc.DocumentElement != null && doc.DocumentElement.Attributes["Name"] != null)
281 | {
282 | listViewLanguageTags.Columns.Add(doc.DocumentElement.Attributes["Name"].InnerText, 200);
283 | }
284 | else if (doc.DocumentElement != null && doc.DocumentElement.Attributes["name"] != null)
285 | {
286 | listViewLanguageTags.Columns.Add(doc.DocumentElement.Attributes["name"].InnerText, 200);
287 | }
288 | else
289 | {
290 | string language = "Language1";
291 | if (cb.Name == "comboBoxTo")
292 | {
293 | language = "Language2";
294 | }
295 | listViewLanguageTags.Columns.Add(language, 200);
296 | }
297 | SetLanguage(cb, doc);
298 | }
299 |
300 | private void CreateEmptyLanguage()
301 | {
302 | foreach (ListViewItem lvi in listViewLanguageTags.Items)
303 | {
304 | if (lvi.SubItems.Count == 2)
305 | {
306 | lvi.SubItems.Add(string.Empty);
307 | }
308 | }
309 | }
310 |
311 | private void AddListViewItem(XmlNode node)
312 | {
313 | if (listViewLanguageTags.Columns.Count == 2)
314 | {
315 | if (node.NodeType == XmlNodeType.Comment || node.NodeType == XmlNodeType.CDATA)
316 | {
317 | return;
318 | }
319 |
320 | ListViewItem item;
321 | if (node.NodeType == XmlNodeType.Attribute)
322 | {
323 | item = new ListViewItem("@" + node.Name);
324 | item.SubItems.Add(node.InnerText);
325 | }
326 | else if (XmlUtils.ContainsText(node))
327 | {
328 | item = new ListViewItem(node.Name);
329 | item.SubItems.Add(node.InnerXml);
330 | }
331 | else
332 | {
333 | item = new ListViewItem(node.Name);
334 | item.SubItems.Add(node.InnerText);
335 | }
336 |
337 |
338 | item.Tag = node;
339 | listViewLanguageTags.Items.Add(item);
340 | ListViewItemComparer.NoSortOrder.Add(item, listViewLanguageTags.Items.Count);
341 |
342 | _listViewItemHashtable.Add(XmlUtils.BuildNodePath(node), item); // fails on some attributes!!
343 | }
344 | else if (listViewLanguageTags.Columns.Count == 3)
345 | {
346 | if (_listViewItemHashtable[XmlUtils.BuildNodePath(node)] is ListViewItem item && item.SubItems.Count < 4096)
347 | {
348 | item.SubItems.Add(XmlUtils.ContainsText(node) ? node.InnerXml : node.InnerText);
349 | }
350 | }
351 | }
352 |
353 | private void MakeNew()
354 | {
355 | _treeNodesHashtable = new Hashtable();
356 | _listViewItemHashtable = new Hashtable();
357 | treeView1.Nodes.Clear();
358 | listViewLanguageTags.Items.Clear();
359 | listViewLanguageTags.Clear();
360 |
361 | _secondLanguageFileName = string.Empty;
362 | Text = "XML Content Translator";
363 |
364 | _change = false;
365 | }
366 |
367 | private void ExpandNode(TreeNode parentNode, XmlNode node)
368 | {
369 | if (listViewLanguageTags.Columns.Count == 2)
370 | {
371 | AddAttributes(node);
372 | foreach (XmlNode childNode in node.ChildNodes)
373 | {
374 | var treeNode = new TreeNode(childNode.Name);
375 | treeNode.Tag = childNode;
376 | if (parentNode == null)
377 | {
378 | treeView1.Nodes.Add(treeNode);
379 | }
380 | else
381 | {
382 | parentNode.Nodes.Add(treeNode);
383 | }
384 |
385 | if (XmlUtils.IsParentElement(childNode))
386 | {
387 | ExpandNode(treeNode, childNode);
388 | }
389 | else
390 | {
391 | _treeNodesHashtable.Add(treeNode, childNode);
392 | AddListViewItem(childNode);
393 | AddAttributes(childNode);
394 | }
395 | }
396 | }
397 | else if (listViewLanguageTags.Columns.Count == 3)
398 | {
399 | AddAttributes(node);
400 | foreach (XmlNode childNode in node.ChildNodes)
401 | {
402 | if (XmlUtils.IsParentElement(childNode))
403 | {
404 | ExpandNode(null, childNode);
405 | }
406 | else
407 | {
408 | AddListViewItem(childNode);
409 | AddAttributes(childNode);
410 | }
411 | }
412 | }
413 | }
414 |
415 | private void AddAttributes(XmlNode node)
416 | {
417 | if (node.Attributes == null || node.Attributes.Count == 0)
418 | {
419 | return;
420 | }
421 |
422 | foreach (XmlNode childNode in node.Attributes)
423 | {
424 | AddListViewItem(childNode);
425 | }
426 | }
427 |
428 | private void ExitToolStripMenuItemClick(object sender, EventArgs e)
429 | {
430 | if (_change && listViewLanguageTags.Columns.Count == 3 &&
431 | MessageBox.Show("Changes will be lost. Continue?", "Continue", MessageBoxButtons.YesNo) == DialogResult.No)
432 | {
433 | return;
434 | }
435 |
436 | _change = false;
437 | Close();
438 | }
439 |
440 | private void TreeView1AfterSelect(object sender, TreeViewEventArgs e)
441 | {
442 | var node = _treeNodesHashtable[e.Node] as XmlNode;
443 | if (node != null)
444 | {
445 | DeSelectListViewItems();
446 |
447 | var item = _listViewItemHashtable[XmlUtils.BuildNodePath(node)] as ListViewItem;
448 | if (item != null)
449 | {
450 | item.Selected = true;
451 | listViewLanguageTags.EnsureVisible(item.Index);
452 | }
453 | }
454 | }
455 |
456 | private void DeSelectListViewItems()
457 | {
458 | var selectedItems = new List();
459 | foreach (ListViewItem lvi in listViewLanguageTags.SelectedItems)
460 | {
461 | selectedItems.Add(lvi);
462 | }
463 | foreach (ListViewItem lvi in selectedItems)
464 | {
465 | lvi.Selected = false;
466 | }
467 | }
468 |
469 | private void ListViewLanguageTagsSelectedIndexChanged(object sender, EventArgs e)
470 | {
471 | if (listViewLanguageTags.SelectedItems.Count == 1 && listViewLanguageTags.SelectedItems[0].SubItems.Count > 2)
472 | {
473 | textBoxCurrentText.Enabled = true;
474 | textBoxCurrentText.Text = listViewLanguageTags.SelectedItems[0].SubItems[2].Text;
475 |
476 | if (listViewLanguageTags.SelectedItems[0].Tag is XmlNode node)
477 | {
478 | toolStripStatusLabel2.Text = $"{XmlUtils.BuildNodePath(node).Replace("#document/", "")} {listViewLanguageTags.SelectedItems[0].Index + 1} / {listViewLanguageTags.Items.Count}";
479 | }
480 | else
481 | {
482 | toolStripStatusLabel2.Text = $"{listViewLanguageTags.SelectedItems[0].Index + 1} / {listViewLanguageTags.Items.Count}";
483 | }
484 | }
485 | else
486 | {
487 | textBoxCurrentText.Text = string.Empty;
488 | textBoxCurrentText.Enabled = false;
489 | toolStripStatusLabel2.Text = $"{listViewLanguageTags.SelectedItems.Count} items selected";
490 | }
491 | HighLightLinesWithSameText();
492 | }
493 |
494 | private void TextBoxCurrentTextTextChanged(object sender, EventArgs e)
495 | {
496 | if (listViewLanguageTags.SelectedItems.Count == 1)
497 | {
498 | listViewLanguageTags.SelectedItems[0].SubItems[2].Text = textBoxCurrentText.Text;
499 | }
500 | }
501 |
502 | private void FillOriginalDocumentFromSecondLanguage()
503 | {
504 | FillAttributes(_originalDocument.DocumentElement);
505 | if (_originalDocument.DocumentElement != null)
506 | {
507 | foreach (XmlNode childNode in _originalDocument.DocumentElement.ChildNodes)
508 | {
509 | if (childNode.ChildNodes.Count > 0 && !XmlUtils.IsTextNode(childNode))
510 | {
511 | FillOriginalDocumentExpandNode(childNode);
512 | }
513 | else
514 | {
515 | var item = _listViewItemHashtable[XmlUtils.BuildNodePath(childNode)] as ListViewItem;
516 | if (item != null)
517 | {
518 | childNode.InnerText = item.SubItems[2].Text;
519 | }
520 | FillAttributes(_originalDocument.DocumentElement);
521 | }
522 | }
523 | }
524 | }
525 |
526 | private void FillOriginalDocumentExpandNode(XmlNode node)
527 | {
528 | FillAttributes(node);
529 | foreach (XmlNode childNode in node.ChildNodes)
530 | {
531 | if (childNode.ChildNodes.Count > 0 && !XmlUtils.IsTextNode(childNode))
532 | {
533 | FillOriginalDocumentExpandNode(childNode);
534 | }
535 | else
536 | {
537 | if (_listViewItemHashtable[XmlUtils.BuildNodePath(childNode)] is ListViewItem item)
538 | {
539 | if (XmlUtils.ContainsText(childNode))
540 | {
541 | try
542 | {
543 | childNode.InnerXml = item.SubItems[2].Text;
544 | }
545 | catch
546 | {
547 | childNode.InnerText = item.SubItems[2].Text;
548 | }
549 | }
550 | else
551 | {
552 | childNode.InnerText = item.SubItems[2].Text;
553 | }
554 | }
555 | FillAttributes(childNode);
556 | }
557 | }
558 | }
559 |
560 | private void FillAttributes(XmlNode node)
561 | {
562 | if (node.Attributes == null)
563 | return;
564 |
565 | foreach (XmlNode attribute in node.Attributes)
566 | {
567 | var item = _listViewItemHashtable[XmlUtils.BuildNodePath(attribute)] as ListViewItem;
568 | if (item != null)
569 | {
570 | attribute.InnerText = item.SubItems[2].Text;
571 | }
572 | }
573 | }
574 |
575 | private void Form1KeyDown(object sender, KeyEventArgs e)
576 | {
577 | if (listViewLanguageTags.Items.Count == 0)
578 | return;
579 |
580 | if (e.Control && e.KeyCode == Keys.Down)
581 | {
582 | if (listViewLanguageTags.SelectedItems.Count == 0)
583 | listViewLanguageTags.Items[0].Selected = true;
584 |
585 | int index = listViewLanguageTags.SelectedItems[0].Index + 1;
586 | if (index < listViewLanguageTags.Items.Count)
587 | {
588 | DeSelectListViewItems();
589 | listViewLanguageTags.Items[index].Selected = true;
590 | listViewLanguageTags.EnsureVisible(index);
591 | }
592 |
593 | e.Handled = true;
594 | e.SuppressKeyPress = true;
595 | ActiveControl = textBoxCurrentText;
596 | }
597 | else if (e.Control && e.KeyCode == Keys.Up)
598 | {
599 | if (listViewLanguageTags.SelectedItems.Count == 0)
600 | listViewLanguageTags.Items[0].Selected = true;
601 |
602 | int index = listViewLanguageTags.SelectedItems[0].Index - 1;
603 | if (index >= 0)
604 | {
605 | DeSelectListViewItems();
606 | listViewLanguageTags.Items[index].Selected = true;
607 | listViewLanguageTags.EnsureVisible(index);
608 | }
609 | e.Handled = true;
610 | e.SuppressKeyPress = true;
611 | ActiveControl = textBoxCurrentText;
612 | }
613 | else if (e.KeyCode == Keys.F6)
614 | {
615 | ButtonGoToNextBlankLineClick(null, null);
616 | }
617 | else if (e.KeyCode == Keys.F3 && !e.Control && !e.Alt)
618 | {
619 | if (_formFind == null || _formFind.SearchText.Length == 0)
620 | {
621 | findToolStripMenuItem_Click(this, null);
622 | }
623 | else
624 | {
625 | FindNext();
626 | }
627 | e.Handled = true;
628 | e.SuppressKeyPress = true;
629 | }
630 | }
631 |
632 | private void GoogleTranslateSelectedLinesToolStripMenuItemClick(object sender, EventArgs e)
633 | {
634 | GoogleTranslateSelectedLines();
635 | }
636 |
637 | ///
638 | /// Translate Text using Google Translate API's
639 | /// Google URL - https://www.google.com/translate_t?hl=en&ie=UTF8&text={0}&langpair={1}
640 | ///
641 | /// Input string
642 | /// 2 letter Language Pair, delimited by "|".
643 | /// E.g. "ar|en" language pair means to translate from Arabic to English
644 | /// Translated to String
645 | public static string TranslateTextViaScreenScraping(string input, string languagePair)
646 | {
647 | input = input.Replace(Environment.NewLine, "
").Trim();
648 | input = input.Replace("'", "'");
649 |
650 | //string url = String.Format("https://www.google.com/translate_t?hl=en&ie=UTF8&text={0}&langpair={1}", HttpUtility.UrlEncode(input), languagePair);
651 | var url = $"https://translate.google.com/?hl=en&eotf=1&sl={languagePair.Substring(0, 2)}&tl={languagePair.Substring(3)}&q={HttpUtility.UrlEncode(input)}";
652 |
653 | var webClient = new WebClient { Encoding = Encoding.Default };
654 | var result = webClient.DownloadString(url);
655 | var startIndex = result.IndexOf(" 0)
658 | {
659 | startIndex = result.IndexOf("", startIndex, StringComparison.Ordinal);
663 | if (startIndex > 0)
664 | {
665 | startIndex++;
666 | int endIndex = result.IndexOf("", startIndex, StringComparison.Ordinal);
667 | string translatedText = result.Substring(startIndex, endIndex - startIndex);
668 | string test = HttpUtility.HtmlDecode(translatedText);
669 | sb.Append(test);
670 | startIndex = result.IndexOf("", Environment.NewLine);
676 | res = res.Replace("
", Environment.NewLine);
677 | res = res.Replace("< BR />", Environment.NewLine);
678 | res = res.Replace("
", Environment.NewLine);
679 | res = res.Replace("
", Environment.NewLine);
680 | res = res.Replace("
", Environment.NewLine);
681 | return res.Trim();
682 | }
683 |
684 | private void GoogleTranslateSelectedLines()
685 | {
686 | if (string.IsNullOrEmpty(_secondLanguageFileName))
687 | return;
688 |
689 | if (comboBoxFrom.SelectedItem == null || comboBoxTo.SelectedItem == null)
690 | {
691 | MessageBox.Show("From/to language not selected");
692 | return;
693 | }
694 |
695 | int skipped = 0;
696 | int translated = 0;
697 | string oldText = string.Empty;
698 | string newText = string.Empty;
699 |
700 | toolStripStatusLabel1.Text = "Translating via Google Translate. Please wait...";
701 | Refresh();
702 |
703 | var translator = new GoogleTranslator1();
704 | Cursor = Cursors.WaitCursor;
705 | var sb = new StringBuilder();
706 | var res = new StringBuilder();
707 | var oldLines = new List();
708 | var list = new List();
709 | foreach (ListViewItem item in listViewLanguageTags.SelectedItems)
710 | {
711 | oldText = item.SubItems[1].Text;
712 | oldText = string.Join(Environment.NewLine, oldText.SplitToLines());
713 | oldLines.Add(oldText);
714 | var urlEncode = HttpUtility.UrlEncode(sb + newText);
715 | if (urlEncode.Length >= 1000)
716 | {
717 | res.Append(TranslateTextViaScreenScraping(sb.ToString(), (comboBoxFrom.SelectedItem as ComboBoxItem).Value + "|" + (comboBoxTo.SelectedItem as ComboBoxItem).Value));
718 | sb = new StringBuilder();
719 | }
720 | list.Add(oldText);
721 | sb.Append("== " + oldText + " ");
722 | }
723 | var log = new StringBuilder();
724 | var lines = translator.Translate(((ComboBoxItem)comboBoxFrom.SelectedItem).Value, ((ComboBoxItem)comboBoxTo.SelectedItem).Value, list, log).ToList();
725 | if (listViewLanguageTags.SelectedItems.Count != lines.Count)
726 | {
727 | MessageBox.Show("Error getting/decoding translation from google!");
728 | Cursor = Cursors.Default;
729 | return;
730 | }
731 |
732 | int index = 0;
733 | foreach (ListViewItem item in listViewLanguageTags.SelectedItems)
734 | {
735 | string s = lines[index];
736 | string cleanText = s.Replace("
", string.Empty).Trim();
737 | cleanText = cleanText.Replace(" ...", "...");
738 | cleanText = cleanText.Replace("
", Environment.NewLine);
739 | cleanText = cleanText.Replace("
", Environment.NewLine);
740 | cleanText = cleanText.Replace("
", Environment.NewLine);
741 | cleanText = cleanText.Replace(Environment.NewLine + " ", Environment.NewLine);
742 | newText = cleanText;
743 |
744 | oldText = oldLines[index];
745 | if (oldText.Contains("{0:"))
746 | {
747 | newText = oldText;
748 | }
749 | else
750 | {
751 | if (!oldText.Contains(" / "))
752 | newText = newText.Replace(" / ", "/");
753 |
754 | if (!oldText.Contains(" ..."))
755 | newText = newText.Replace(" ...", "...");
756 |
757 | if (!oldText.Contains("& "))
758 | newText = newText.Replace("& ", "&");
759 |
760 | if (!oldText.Contains("# "))
761 | newText = newText.Replace("# ", "#");
762 |
763 | if (!oldText.Contains("@ "))
764 | newText = newText.Replace("@ ", "@");
765 |
766 | if (oldText.Contains("{0}"))
767 | {
768 | for (int i = 0; i < 50; i++)
769 | newText = newText.Replace("(" + i + ")", "{" + i + "}");
770 | }
771 | translated++;
772 | }
773 | item.SubItems[2].Text = newText;
774 | _change = true;
775 | index++;
776 | }
777 |
778 |
779 | Cursor = Cursors.Default;
780 | if (translated == 1 && skipped == 0)
781 | {
782 | toolStripStatusLabel1.Text = "One line translated: '" + StringUtils.Max50(oldText) + "' => '" + StringUtils.Max50(newText) + "'";
783 | }
784 | else
785 | {
786 | if (translated == 1)
787 | toolStripStatusLabel1.Text = "One line translated";
788 | else
789 | toolStripStatusLabel1.Text = translated + " lines translated";
790 | if (skipped > 0)
791 | toolStripStatusLabel1.Text += ", " + skipped + " line(s) skipped";
792 | }
793 | ListViewLanguageTagsSelectedIndexChanged(null, null);
794 | }
795 |
796 | private void translateViaGoogleToolStripMenuItem_Click(object sender, EventArgs e)
797 | {
798 | GoogleTranslateSelectedLines();
799 | }
800 |
801 | private void setValueFromMasterToolStripMenuItem_Click(object sender, EventArgs e)
802 | {
803 | if (string.IsNullOrEmpty(_secondLanguageFileName))
804 | {
805 | return;
806 | }
807 |
808 | var transferred = 0;
809 | var oldText = string.Empty;
810 | var newText = string.Empty;
811 | foreach (ListViewItem item in listViewLanguageTags.SelectedItems)
812 | {
813 | oldText = item.SubItems[2].Text;
814 | newText = item.SubItems[1].Text;
815 | transferred++;
816 | item.SubItems[2].Text = newText;
817 | _change = true;
818 | }
819 |
820 | if (transferred == 1)
821 | {
822 | toolStripStatusLabel1.Text = "One line transfered from master: '" + oldText + "' => '" + newText + "'";
823 | }
824 | else
825 | {
826 | toolStripStatusLabel1.Text = transferred + " line(s) transfered from master";
827 | }
828 |
829 | ListViewLanguageTagsSelectedIndexChanged(null, null);
830 | }
831 |
832 | public static void FillComboWithLanguages(ComboBox comboBox)
833 | {
834 | foreach (var pair in new GoogleTranslator1().GetTranslationPairs())
835 | {
836 | comboBox.Items.Add(new ComboBoxItem(pair.Name, pair.Code));
837 | }
838 | }
839 |
840 | private void ToolStripMenuItem1Click(object sender, EventArgs e)
841 | {
842 | if (_change && listViewLanguageTags.Columns.Count == 3 &&
843 | MessageBox.Show("Changes will be lost. Continue?", "Continue", MessageBoxButtons.YesNo) == DialogResult.No)
844 | {
845 | return;
846 | }
847 |
848 | MakeNew();
849 | toolStripStatusLabel1.Text = "New";
850 | }
851 |
852 | private void SaveAsToolStripMenuItemClick(object sender, EventArgs e)
853 | {
854 | if (_originalDocument == null)
855 | {
856 | return;
857 | }
858 |
859 | saveFileDialog1.Title = "Save language file as...";
860 | saveFileDialog1.DefaultExt = ".xml";
861 | saveFileDialog1.Filter = "Xml files|*.xml" + "|All files|*.*";
862 | saveFileDialog1.Title = "Open language master file";
863 | if (saveFileDialog1.ShowDialog() == DialogResult.OK)
864 | {
865 | _secondLanguageFileName = saveFileDialog1.FileName;
866 | FillOriginalDocumentFromSecondLanguage();
867 | _originalDocument.Save(saveFileDialog1.FileName);
868 | _change = false;
869 | toolStripStatusLabel1.Text = "File saved as " + _secondLanguageFileName;
870 | }
871 | }
872 |
873 | private void TextBoxCurrentTextKeyDown(object sender, KeyEventArgs e)
874 | {
875 | if (!e.Control && !e.Alt)
876 | {
877 | _change = true;
878 | }
879 | }
880 |
881 | private void SaveToolStripMenuItemClick(object sender, EventArgs e)
882 | {
883 | if (string.IsNullOrEmpty(_secondLanguageFileName))
884 | {
885 | SaveAsToolStripMenuItemClick(null, null);
886 | }
887 | else
888 | {
889 | FillOriginalDocumentFromSecondLanguage();
890 |
891 | using (var sw = new StringWriter())
892 | {
893 | using (var xw = XmlWriter.Create(sw, new XmlWriterSettings { Indent = true, Encoding = Encoding.UTF8 }))
894 | {
895 | _originalDocument.Save(xw);
896 | var s = sw.ToString();
897 | if (s.Contains("Subtitle Edit"))
898 | {
899 | s = s.Replace("", "");
900 | }
901 | s = s.Replace("encoding=\"utf-16\"?", "encoding=\"utf-8\"?");
902 | File.WriteAllText(_secondLanguageFileName, s, Encoding.UTF8);
903 | }
904 | }
905 | _change = false;
906 | toolStripStatusLabel1.Text = "File saved - " + _secondLanguageFileName;
907 | }
908 | }
909 |
910 | private void Form1FormClosing(object sender, FormClosingEventArgs e)
911 | {
912 | if (_change && listViewLanguageTags.Columns.Count == 3 &&
913 | MessageBox.Show("Changes will be lost. Continue?", "Continue", MessageBoxButtons.YesNo) == DialogResult.No)
914 | {
915 | e.Cancel = true;
916 | }
917 | }
918 |
919 | private void ListViewLanguageTagsDragEnter(object sender, DragEventArgs e)
920 | { // make sure they're actually dropping files (not text or anything else)
921 | if (e.Data.GetDataPresent(DataFormats.FileDrop, false))
922 | {
923 | e.Effect = DragDropEffects.All;
924 | }
925 | }
926 |
927 | private void ListViewLanguageTagsDragDrop(object sender, DragEventArgs e)
928 | {
929 | var files = (string[])e.Data.GetData(DataFormats.FileDrop);
930 |
931 | if (!string.IsNullOrEmpty(_secondLanguageFileName))
932 | {
933 | MessageBox.Show("Two files already loaded");
934 | return;
935 | }
936 |
937 | if (files.Length == 1)
938 | {
939 |
940 | var fileName = files[0];
941 | var fi = new FileInfo(fileName);
942 | if (fi.Length < 1024 * 1024 * 20) // max 20 mb
943 | {
944 | if (treeView1.Nodes.Count == 0)
945 | {
946 | OpenFirstFile(fileName);
947 | }
948 | else
949 | {
950 | OpenSecondFile(fileName);
951 | }
952 | }
953 | else
954 | {
955 | MessageBox.Show(fileName + " is too large (max 20 mb)");
956 | }
957 | }
958 | else
959 | {
960 | MessageBox.Show("Only file drop supported");
961 | }
962 |
963 | }
964 |
965 | private void Form1Load(object sender, EventArgs e)
966 | {
967 | var args = Environment.GetCommandLineArgs();
968 | if (args.Length > 1)
969 | {
970 | if (File.Exists(args[1]))
971 | {
972 | OpenFirstFile(args[1]);
973 | }
974 |
975 | if (args.Length > 2 && File.Exists(args[2]))
976 | {
977 | OpenSecondFile(args[2]);
978 | }
979 | }
980 |
981 | }
982 |
983 | private void ButtonGoToNextBlankLineClick(object sender, EventArgs e)
984 | {
985 | var index = 0;
986 | if (listViewLanguageTags.SelectedItems.Count > 0)
987 | {
988 | index = listViewLanguageTags.SelectedItems[0].Index + 1;
989 | }
990 |
991 | for (; index < listViewLanguageTags.Items.Count; index++)
992 | {
993 | if (listViewLanguageTags.Items[index].SubItems.Count > 1 && string.IsNullOrEmpty(listViewLanguageTags.Items[index].SubItems[2].Text))
994 | {
995 | foreach (ListViewItem item in listViewLanguageTags.SelectedItems)
996 | {
997 | item.Selected = false;
998 | }
999 |
1000 | listViewLanguageTags.Items[index].Selected = true;
1001 | listViewLanguageTags.Items[index].EnsureVisible();
1002 | return;
1003 | }
1004 | }
1005 | }
1006 |
1007 | private void HighLightLinesWithSameText()
1008 | {
1009 | foreach (ListViewItem item in listViewLanguageTags.Items)
1010 | {
1011 | if (item.SubItems.Count == 3)
1012 | {
1013 | if (item.SubItems[1].Text.Trim() == item.SubItems[2].Text.Trim())
1014 | {
1015 | item.BackColor = Color.LightYellow;
1016 | item.UseItemStyleForSubItems = true;
1017 | }
1018 | else if (item.SubItems[2].Text.Trim().Length == 0)
1019 | {
1020 | item.BackColor = Color.LightPink;
1021 | item.UseItemStyleForSubItems = true;
1022 | }
1023 | else
1024 | {
1025 | item.BackColor = listViewLanguageTags.BackColor;
1026 | item.UseItemStyleForSubItems = true;
1027 | }
1028 | }
1029 | }
1030 | }
1031 |
1032 | private void toolStripMenuItem2_Click(object sender, EventArgs e)
1033 | {
1034 | openFileDialog1.FileName = string.Empty;
1035 | openFileDialog1.DefaultExt = ".xml";
1036 | openFileDialog1.Filter = "Xml files|*.xml" + "|All files|*.*";
1037 | openFileDialog1.Title = "Open English translation base file";
1038 |
1039 | var doc = new XmlDocument();
1040 | try
1041 | {
1042 | const string url = "https://raw.githubusercontent.com/SubtitleEdit/subtitleedit/main/LanguageBaseEnglish.xml";
1043 | var wc = new WebClient();
1044 | var xml = wc.DownloadString(url);
1045 | MakeNew();
1046 | doc.LoadXml(xml);
1047 | OpenFirstXmlDocument(doc);
1048 | }
1049 | catch (Exception ex)
1050 | {
1051 | MessageBox.Show("Error: " + ex.Message);
1052 | return;
1053 | }
1054 |
1055 | OpenSecondFile();
1056 | }
1057 |
1058 | private void findToolStripMenuItem_Click(object sender, EventArgs e)
1059 | {
1060 | if (_formFind == null)
1061 | {
1062 | _formFind = new Find();
1063 | }
1064 |
1065 | if (_formFind.ShowDialog(this) == DialogResult.OK)
1066 | {
1067 | FindNext();
1068 | }
1069 | }
1070 |
1071 | private void FindNext()
1072 | {
1073 | if (_formFind.SearchText.Length == 0)
1074 | return;
1075 |
1076 | var index = 0;
1077 | if (listViewLanguageTags.SelectedItems.Count > 0)
1078 | {
1079 | index = listViewLanguageTags.SelectedItems[0].Index + 1;
1080 | }
1081 | while (index < listViewLanguageTags.Items.Count)
1082 | {
1083 | if (_formFind.SearchTags)
1084 | {
1085 | if (listViewLanguageTags.Items[index].Text.ToLower().Contains(_formFind.SearchText.ToLower()))
1086 | {
1087 | SelectOnlyThis(index);
1088 | return;
1089 | }
1090 | }
1091 | else
1092 | {
1093 | if (listViewLanguageTags.Items[index].SubItems[0].Text.ToLower().Contains(_formFind.SearchText) ||
1094 | listViewLanguageTags.Items[index].SubItems[1].Text.ToLower().Contains(_formFind.SearchText))
1095 | {
1096 | SelectOnlyThis(index);
1097 | return;
1098 | }
1099 | }
1100 | index++;
1101 | }
1102 | }
1103 |
1104 | private void SelectOnlyThis(int index)
1105 | {
1106 | foreach (ListViewItem selectedItem in listViewLanguageTags.SelectedItems)
1107 | {
1108 | selectedItem.Selected = false;
1109 | }
1110 | listViewLanguageTags.Items[index].Selected = true;
1111 | listViewLanguageTags.Items[index].EnsureVisible();
1112 | listViewLanguageTags.Items[index].Focused = true;
1113 | }
1114 |
1115 | private void listViewLanguageTags_DoubleClick(object sender, EventArgs e)
1116 | {
1117 | if (listViewLanguageTags.SelectedItems.Count != 1)
1118 | {
1119 | return;
1120 | }
1121 |
1122 | var node = listViewLanguageTags.SelectedItems[0].Tag as XmlNode;
1123 | if (node == null)
1124 | {
1125 | return;
1126 | }
1127 |
1128 | foreach (TreeNode treeNode in treeView1.Nodes)
1129 | {
1130 | if (treeNode.Tag == node)
1131 | {
1132 | treeView1.SelectedNode = treeNode;
1133 | return;
1134 | }
1135 | foreach (TreeNode subTreeNode in treeNode.Nodes)
1136 | {
1137 | if (subTreeNode.Tag == node)
1138 | {
1139 | treeView1.SelectedNode = subTreeNode;
1140 | return;
1141 | }
1142 | }
1143 | }
1144 | }
1145 |
1146 | private void Main_Resize(object sender, EventArgs e)
1147 | {
1148 | Main_ResizeEnd(null, null);
1149 | }
1150 |
1151 | private void Main_ResizeEnd(object sender, EventArgs e)
1152 | {
1153 | if (listViewLanguageTags.Columns.Count > 0)
1154 | {
1155 | var w = 0;
1156 | for (var i = 0; i < listViewLanguageTags.Columns.Count - 1; i++)
1157 | {
1158 | w += listViewLanguageTags.Columns[i].Width;
1159 | }
1160 |
1161 | listViewLanguageTags.Columns[listViewLanguageTags.Columns.Count - 1].Width = listViewLanguageTags.Width - 25 - w;
1162 | }
1163 | }
1164 | }
1165 | }
--------------------------------------------------------------------------------
/src/XmlContentTranslator/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Windows.Forms;
4 |
5 | namespace XmlContentTranslator
6 | {
7 | static class Program
8 | {
9 | ///
10 | /// The main entry point for the application.
11 | ///
12 | [STAThread]
13 | static void Main()
14 | {
15 | Application.EnableVisualStyles();
16 | Application.SetCompatibleTextRenderingDefault(false);
17 | Application.Run(new Main());
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/XmlContentTranslator/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Xml Content Translator")]
9 | [assembly: AssemblyDescription("Translate content of xml files")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Nikse.dk")]
12 | [assembly: AssemblyProduct("Xml Content Translator")]
13 | [assembly: AssemblyCopyright("Copyright © 2022")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("cbc25f85-5713-4ba7-a42f-c653265a192f")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.12.0.0")]
36 | [assembly: AssemblyFileVersion("1.12.0.0")]
37 |
--------------------------------------------------------------------------------
/src/XmlContentTranslator/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace XmlContentTranslator.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("XmlContentTranslator.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/XmlContentTranslator/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/src/XmlContentTranslator/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace XmlContentTranslator.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.3.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/XmlContentTranslator/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/XmlContentTranslator/StringUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace XmlContentTranslator
7 | {
8 | public static class StringUtils
9 | {
10 | public static string Max50(string text)
11 | {
12 | if (text.Length > 50)
13 | return text.Substring(0, 50).Trim() + "...";
14 | return text;
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/XmlContentTranslator/Translator/Configuration.cs:
--------------------------------------------------------------------------------
1 | namespace XmlContentTranslator.Translator
2 | {
3 | internal static class Configuration
4 | {
5 | public static double CurrentFrameRate = 23.976;
6 | public static string ListViewLineSeparatorString = "
";
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/XmlContentTranslator/Translator/Formatting.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace XmlContentTranslator.Translator
6 | {
7 | public class Formatting
8 | {
9 | private bool Italic { get; set; }
10 | private bool ItalicTwoLines { get; set; }
11 | private string StartTags { get; set; }
12 | private bool AutoBreak { get; set; }
13 | private bool SquareBrackets { get; set; }
14 | private bool SquareBracketsUppercase { get; set; }
15 |
16 | public string SetTagsAndReturnTrimmed(string text, string source)
17 | {
18 | text = text.Trim();
19 |
20 | // SSA/ASS tags
21 | if (text.StartsWith("{\\"))
22 | {
23 | var endIndex = text.IndexOf('}');
24 | if (endIndex > 0)
25 | {
26 | StartTags = text.Substring(0, endIndex + 1);
27 | text = text.Remove(0, endIndex + 1).Trim();
28 | }
29 | }
30 |
31 | // Italic tags
32 | if (text.StartsWith("", StringComparison.Ordinal) && text.EndsWith("", StringComparison.Ordinal) && text.Contains("" + Environment.NewLine + "") && Utilities.GetNumberOfLines(text) == 2 && Utilities.CountTagInText(text, "") == 1)
33 | {
34 | ItalicTwoLines = true;
35 | text = HtmlUtil.RemoveOpenCloseTags(text, HtmlUtil.TagItalic);
36 | }
37 | else if (text.StartsWith("", StringComparison.Ordinal) && text.EndsWith("", StringComparison.Ordinal) && Utilities.CountTagInText(text, "") == 1)
38 | {
39 | Italic = true;
40 | text = text.Substring(3, text.Length - 7);
41 | }
42 |
43 | // Un-break line
44 | var allowedLanguages = new List { "en", "da", "nl", "de", "sv", "nb", "fr", "it" };
45 | if (allowedLanguages.Contains(source))
46 | {
47 | var lines = HtmlUtil.RemoveHtmlTags(text).SplitToLines();
48 | if (lines.Length == 2 && !string.IsNullOrEmpty(lines[0]) && !string.IsNullOrEmpty(lines[1]) &&
49 | char.IsLetterOrDigit(lines[0][lines[0].Length - 1]) &&
50 | char.IsLower(lines[1][0]))
51 | {
52 | text = string.Join(" ", text.SplitToLines()).Replace(" ", " ");
53 | AutoBreak = true;
54 | }
55 | }
56 |
57 | // Square brackets
58 | if (text.StartsWith("[", StringComparison.Ordinal) && text.EndsWith("]", StringComparison.Ordinal) &&
59 | Utilities.GetNumberOfLines(text) == 1 && Utilities.CountTagInText(text, "[") == 1 &&
60 | Utilities.GetNumberOfLines(text) == 1 && Utilities.CountTagInText(text, "]") == 1)
61 | {
62 | if (text == text.ToUpperInvariant())
63 | SquareBracketsUppercase = true;
64 | else
65 | SquareBrackets = true;
66 | text = text.Replace("[", string.Empty).Replace("]", string.Empty);
67 | }
68 |
69 | return text.Trim();
70 | }
71 |
72 | public string ReAddFormatting(string text)
73 | {
74 | // Auto-break line
75 | if (AutoBreak)
76 | {
77 | text = Utilities.AutoBreakLine(text);
78 | }
79 |
80 | // Square brackets
81 | if (SquareBracketsUppercase)
82 | {
83 | text = "[" + text.ToUpperInvariant().Trim() + "]";
84 | }
85 | else if (SquareBrackets)
86 | {
87 | text = "[" + text.Trim() + "]";
88 | }
89 |
90 | // Italic tags
91 | if (ItalicTwoLines)
92 | {
93 | var sb = new StringBuilder();
94 | foreach (var line in text.SplitToLines())
95 | {
96 | sb.AppendLine("" + line + "");
97 | }
98 | text = sb.ToString().Trim();
99 | }
100 | else if (Italic)
101 | {
102 | text = "" + text + "";
103 | }
104 |
105 | // SSA/ASS tags
106 | text = StartTags + text;
107 |
108 | return text;
109 | }
110 |
111 |
112 | private int NumberOfLines { get; set; }
113 |
114 | public string Unbreak(string text, string source)
115 | {
116 | NumberOfLines = source.SplitToLines().Length;
117 | return text.Replace(Environment.NewLine, " ").Replace(" ", " ");
118 | }
119 |
120 | public string Rebreak(string text)
121 | {
122 | if (NumberOfLines == 1)
123 | return text;
124 | return Utilities.AutoBreakLine(text);
125 | }
126 |
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/XmlContentTranslator/Translator/GoogleTranslator1.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Text;
6 | using System.Text.RegularExpressions;
7 |
8 | namespace XmlContentTranslator.Translator
9 | {
10 | ///
11 | /// Google translate via Google V1 API - see https://cloud.google.com/translate/
12 | ///
13 | public class GoogleTranslator1 : ITranslator
14 | {
15 | private const char SplitChar = '\n';
16 |
17 | public List GetTranslationPairs()
18 | {
19 | return new List
20 | {
21 | new TranslationPair("AFRIKAANS", "af"),
22 | new TranslationPair("ALBANIAN", "sq"),
23 | new TranslationPair("AMHARIC", "am"),
24 | new TranslationPair("ARABIC", "ar"),
25 | new TranslationPair("ARMENIAN", "hy"),
26 | new TranslationPair("AZERBAIJANI", "az"),
27 | new TranslationPair("BASQUE", "eu"),
28 | new TranslationPair("BELARUSIAN", "be"),
29 | new TranslationPair("BENGALI", "bn"),
30 | new TranslationPair("BOSNIAN", "bs"),
31 | new TranslationPair("BULGARIAN", "bg"),
32 | new TranslationPair("BURMESE", "my"),
33 | new TranslationPair("CATALAN", "ca"),
34 | new TranslationPair("CEBUANO", "ceb"),
35 | new TranslationPair("CHICHEWA", "ny"),
36 | new TranslationPair("CHINESE", "zh"),
37 | new TranslationPair("CHINESE_SIMPLIFIED", "zh-CN"),
38 | new TranslationPair("CHINESE_TRADITIONAL", "zh-TW"),
39 | new TranslationPair("CORSICAN", "co"),
40 | new TranslationPair("CROATIAN", "hr"),
41 | new TranslationPair("CZECH", "cs"),
42 | new TranslationPair("DANISH", "da"),
43 | new TranslationPair("DUTCH", "nl"),
44 | new TranslationPair("ENGLISH", "en"),
45 | new TranslationPair("ESPERANTO", "eo"),
46 | new TranslationPair("ESTONIAN", "et"),
47 | new TranslationPair("FILIPINO", "tl"),
48 | new TranslationPair("FINNISH", "fi"),
49 | new TranslationPair("FRENCH", "fr"),
50 | new TranslationPair("FRISIAN", "fy"),
51 | new TranslationPair("GALICIAN", "gl"),
52 | new TranslationPair("GEORGIAN", "ka"),
53 | new TranslationPair("GERMAN", "de"),
54 | new TranslationPair("GREEK", "el"),
55 | new TranslationPair("GUJARATI", "gu"),
56 | new TranslationPair("HAITIAN CREOLE", "ht"),
57 | new TranslationPair("HAUSA", "ha"),
58 | new TranslationPair("HAWAIIAN", "haw"),
59 | new TranslationPair("HEBREW", "iw"),
60 | new TranslationPair("HINDI", "hi"),
61 | new TranslationPair("HMOUNG", "hmn"),
62 | new TranslationPair("HUNGARIAN", "hu"),
63 | new TranslationPair("ICELANDIC", "is"),
64 | new TranslationPair("IGBO", "ig"),
65 | new TranslationPair("INDONESIAN", "id"),
66 | new TranslationPair("IRISH", "ga"),
67 | new TranslationPair("ITALIAN", "it"),
68 | new TranslationPair("JAPANESE", "ja"),
69 | new TranslationPair("JAVANESE", "jw"),
70 | new TranslationPair("KANNADA", "kn"),
71 | new TranslationPair("KAZAKH", "kk"),
72 | new TranslationPair("KHMER", "km"),
73 | new TranslationPair("KOREAN", "ko"),
74 | new TranslationPair("KURDISH", "ku"),
75 | new TranslationPair("KYRGYZ", "ky"),
76 | new TranslationPair("LAO", "lo"),
77 | new TranslationPair("LATIN", "la"),
78 | new TranslationPair("LATVIAN", "lv"),
79 | new TranslationPair("LITHUANIAN", "lt"),
80 | new TranslationPair("LUXEMBOURGISH", "lb"),
81 | new TranslationPair("MACEDONIAN", "mk"),
82 | new TranslationPair("MALAY", "ms"),
83 | new TranslationPair("MALAGASY", "mg"),
84 | new TranslationPair("MALAYALAM", "ml"),
85 | new TranslationPair("MALTESE", "mt"),
86 | new TranslationPair("MAORI", "mi"),
87 | new TranslationPair("MARATHI", "mr"),
88 | new TranslationPair("MONGOLIAN", "mn"),
89 | new TranslationPair("MYANMAR", "my"),
90 | new TranslationPair("NEPALI", "ne"),
91 | new TranslationPair("NORWEGIAN", "no"),
92 | new TranslationPair("PASHTO", "ps"),
93 | new TranslationPair("PERSIAN", "fa"),
94 | new TranslationPair("POLISH", "pl"),
95 | new TranslationPair("PORTUGUESE", "pt"),
96 | new TranslationPair("PUNJABI", "pa"),
97 | new TranslationPair("ROMANIAN", "ro"),
98 | new TranslationPair("ROMANJI", "romanji"),
99 | new TranslationPair("RUSSIAN", "ru"),
100 | new TranslationPair("SAMOAN", "sm"),
101 | new TranslationPair("SCOTS GAELIC", "gd"),
102 | new TranslationPair("SERBIAN", "sr"),
103 | new TranslationPair("SESOTHO", "st"),
104 | new TranslationPair("SHONA", "sn"),
105 | new TranslationPair("SINDHI", "sd"),
106 | new TranslationPair("SINHALA", "si"),
107 | new TranslationPair("SLOVAK", "sk"),
108 | new TranslationPair("SLOVENIAN", "sl"),
109 | new TranslationPair("SOMALI", "so"),
110 | new TranslationPair("SPANISH", "es"),
111 | new TranslationPair("SUNDANESE", "su"),
112 | new TranslationPair("SWAHILI", "sw"),
113 | new TranslationPair("SWEDISH", "sv"),
114 | new TranslationPair("TAJIK", "tg"),
115 | new TranslationPair("TAMIL", "ta"),
116 | new TranslationPair("TELUGU", "te"),
117 | new TranslationPair("THAI", "th"),
118 | new TranslationPair("TURKISH", "tr"),
119 | new TranslationPair("UKRAINIAN", "uk"),
120 | new TranslationPair("URDU", "ur"),
121 | new TranslationPair("UZBEK", "uz"),
122 | new TranslationPair("VIETNAMESE", "vi"),
123 | new TranslationPair("WELSH", "cy"),
124 | new TranslationPair("XHOSA", "xh"),
125 | new TranslationPair("YIDDISH", "yi"),
126 | new TranslationPair("YORUBA", "yo"),
127 | new TranslationPair("ZULU", "zu"),
128 | };
129 | }
130 |
131 | public string GetName()
132 | {
133 | return "Google translate (old)";
134 | }
135 |
136 | public string GetUrl()
137 | {
138 | return "https://translate.google.com/";
139 | }
140 |
141 | public List Translate(string sourceLanguage, string targetLanguage, List paragraphs, StringBuilder log)
142 | {
143 | string result;
144 | var input = new StringBuilder();
145 | var formattings = new Formatting[paragraphs.Count];
146 | for (var index = 0; index < paragraphs.Count; index++)
147 | {
148 | var p = paragraphs[index];
149 | var f = new Formatting();
150 | formattings[index] = f;
151 | if (input.Length > 0)
152 | {
153 | input.Append(" " + SplitChar + " ");
154 | }
155 | var text = f.SetTagsAndReturnTrimmed(TranslationHelper.PreTranslate(p.Replace(SplitChar.ToString(), string.Empty), sourceLanguage), sourceLanguage);
156 | text = f.Unbreak(text, p);
157 | input.Append(text);
158 | }
159 |
160 | using (var wc = new WebClient())
161 | {
162 | string url = $"https://translate.googleapis.com/translate_a/single?client=gtx&sl={sourceLanguage}&tl={targetLanguage}&dt=t&q={Uri.EscapeDataString(input.ToString())}";
163 | wc.Encoding = Encoding.UTF8;
164 | wc.Headers.Add("user-agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36");
165 | result = wc.DownloadString(url).Trim();
166 | }
167 |
168 | var sbAll = new StringBuilder();
169 | int count = 0;
170 | int i = 1;
171 | int level = result.StartsWith('[') ? 1 : 0;
172 | while (i < result.Length - 1)
173 | {
174 | var sb = new StringBuilder();
175 | var start = false;
176 | for (; i < result.Length - 1; i++)
177 | {
178 | var c = result[i];
179 | if (start)
180 | {
181 | if (c == '"' && result[i - 1] != '\\')
182 | {
183 | count++;
184 | if (count % 2 == 1 && level > 2 && level < 5) // even numbers are original text, level 3 is translation
185 | sbAll.Append(" " + sb);
186 | i++;
187 | break;
188 | }
189 | sb.Append(c);
190 | }
191 | else if (c == '"')
192 | {
193 | start = true;
194 | }
195 | else if (c == '[')
196 | {
197 | level++;
198 | }
199 | else if (c == ']')
200 | {
201 | level--;
202 | }
203 | }
204 | }
205 |
206 | var res = sbAll.ToString().Trim();
207 | res = Regex.Unescape(res);
208 | var lines = res.SplitToLines().ToList();
209 | var resultList = new List();
210 | for (var index = 0; index < lines.Count; index++)
211 | {
212 | var line = lines[index];
213 | var s = Json.DecodeJsonText(line);
214 | s = string.Join(Environment.NewLine, s.SplitToLines());
215 | s = TranslationHelper.PostTranslate(s, targetLanguage);
216 | s = s.Replace(Environment.NewLine + Environment.NewLine, Environment.NewLine);
217 | s = s.Replace(Environment.NewLine + " ", Environment.NewLine);
218 | s = s.Replace(Environment.NewLine + " ", Environment.NewLine);
219 | s = s.Replace(" " + Environment.NewLine, Environment.NewLine);
220 | s = s.Replace(" " + Environment.NewLine, Environment.NewLine).Trim();
221 | if (formattings.Length > index)
222 | {
223 | s = formattings[index].ReAddFormatting(s);
224 | s = formattings[index].Rebreak(s);
225 | }
226 |
227 | resultList.Add(s);
228 | }
229 |
230 | if (resultList.Count > paragraphs.Count)
231 | {
232 | var timmedList = resultList.Where(p => !string.IsNullOrEmpty(p)).ToList();
233 | if (timmedList.Count == paragraphs.Count)
234 | return timmedList;
235 | }
236 |
237 | if (resultList.Count < paragraphs.Count)
238 | {
239 | var splitList = SplitMergedLines(resultList, paragraphs);
240 | if (splitList.Count == paragraphs.Count)
241 | return splitList;
242 | }
243 |
244 | return resultList;
245 | }
246 |
247 | private static List SplitMergedLines(List input, List paragraphs)
248 | {
249 | var hits = 0;
250 | var results = new List();
251 | for (var index = 0; index < input.Count; index++)
252 | {
253 | var line = input[index];
254 | var text = paragraphs[index];
255 | var badPoints = 0;
256 | if (text.StartsWith("[") && !line.StartsWith("["))
257 | badPoints++;
258 | if (text.StartsWith("-") && !line.StartsWith("-"))
259 | badPoints++;
260 | if (text.Length > 0 && char.IsUpper(text[0]) && line.Length > 0 && !char.IsUpper(line[0]))
261 | badPoints++;
262 | if (text.EndsWith(".") && !line.EndsWith("."))
263 | badPoints++;
264 | if (text.EndsWith("!") && !line.EndsWith("!"))
265 | badPoints++;
266 | if (text.EndsWith("?") && !line.EndsWith("?"))
267 | badPoints++;
268 | if (text.EndsWith(",") && !line.EndsWith(","))
269 | badPoints++;
270 | if (text.EndsWith(":") && !line.EndsWith(":"))
271 | badPoints++;
272 | var added = false;
273 | if (badPoints > 0 && hits + input.Count < paragraphs.Count)
274 | {
275 | var percent = line.Length * 100.0 / text.Length;
276 | if (percent > 150)
277 | {
278 | var temp = Utilities.AutoBreakLine(line).SplitToLines();
279 | if (temp.Length == 2)
280 | {
281 | hits++;
282 | results.Add(temp[0]);
283 | results.Add(temp[1]);
284 | added = true;
285 | }
286 | }
287 | }
288 | if (!added)
289 | {
290 | results.Add(line);
291 | }
292 | }
293 |
294 | if (results.Count == paragraphs.Count)
295 | return results;
296 |
297 | return input;
298 | }
299 |
300 | }
301 | }
302 |
--------------------------------------------------------------------------------
/src/XmlContentTranslator/Translator/HtmlUtil.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Text;
4 | using System.Text.RegularExpressions;
5 |
6 | namespace XmlContentTranslator.Translator
7 | {
8 | ///
9 | /// HTML specific string manipulations.
10 | ///
11 | public static class HtmlUtil
12 | {
13 | public const string TagItalic = "i";
14 | public const string TagBold = "b";
15 | public const string TagUnderline = "u";
16 | public const string TagParagraph = "p";
17 | public const string TagFont = "font";
18 | public const string TagCyrillicI = "\u0456"; // Cyrillic Small Letter Byelorussian-Ukrainian i (http://graphemica.com/%D1%96)
19 |
20 | private static readonly Regex TagOpenRegex = new Regex(@"<\s*(?:/\s*)?(\w+)[^>]*>", RegexOptions.Compiled);
21 |
22 | ///
23 | /// Remove all of the specified opening and closing tags from the source HTML string.
24 | ///
25 | /// The source string to search for specified HTML tags.
26 | /// The HTML tags to remove.
27 | /// A new string without the specified opening and closing tags.
28 | public static string RemoveOpenCloseTags(string source, params string[] tags)
29 | {
30 | // This pattern matches these tag formats:
31 | //
32 | // < tag*>
33 | //
34 | // < /tag*>
35 | // tag*>
36 | // < / tag*>
37 | return TagOpenRegex.Replace(
38 | source,
39 | m => tags.Contains(m.Groups[1].Value, StringComparer.OrdinalIgnoreCase) ? string.Empty : m.Value);
40 | }
41 |
42 | ///
43 | /// Converts a string to an HTML-encoded string using named character references.
44 | ///
45 | /// The string to encode.
46 | /// An encoded string.
47 | public static string EncodeNamed(string source)
48 | {
49 | if (string.IsNullOrEmpty(source))
50 | return string.Empty;
51 |
52 | var encoded = new StringBuilder(source.Length);
53 | foreach (var ch in source)
54 | {
55 | switch (ch)
56 | {
57 | case '<':
58 | encoded.Append("<");
59 | break;
60 | case '>':
61 | encoded.Append(">");
62 | break;
63 | case '"':
64 | encoded.Append(""");
65 | break;
66 | case '&':
67 | encoded.Append("&");
68 | break;
69 | case '\'':
70 | encoded.Append("'");
71 | break;
72 | case ' ':
73 | encoded.Append(" ");
74 | break;
75 | case '–':
76 | encoded.Append("–");
77 | break;
78 | case '—':
79 | encoded.Append("—");
80 | break;
81 | case '¡':
82 | encoded.Append("¡");
83 | break;
84 | case '¿':
85 | encoded.Append("¿");
86 | break;
87 | case '“':
88 | encoded.Append("“");
89 | break;
90 | case '”':
91 | encoded.Append("”");
92 | break;
93 | case '‘':
94 | encoded.Append("‘");
95 | break;
96 | case '’':
97 | encoded.Append("’");
98 | break;
99 | case '«':
100 | encoded.Append("«");
101 | break;
102 | case '»':
103 | encoded.Append("»");
104 | break;
105 | case '¢':
106 | encoded.Append("¢");
107 | break;
108 | case '©':
109 | encoded.Append("©");
110 | break;
111 | case '÷':
112 | encoded.Append("÷");
113 | break;
114 | case 'µ':
115 | encoded.Append("µ");
116 | break;
117 | case '·':
118 | encoded.Append("·");
119 | break;
120 | case '¶':
121 | encoded.Append("¶");
122 | break;
123 | case '±':
124 | encoded.Append("±");
125 | break;
126 | case '€':
127 | encoded.Append("€");
128 | break;
129 | case '£':
130 | encoded.Append("£");
131 | break;
132 | case '®':
133 | encoded.Append("®");
134 | break;
135 | case '§':
136 | encoded.Append("§");
137 | break;
138 | case '™':
139 | encoded.Append("™");
140 | break;
141 | case '¥':
142 | encoded.Append("¥");
143 | break;
144 | case 'á':
145 | encoded.Append("á");
146 | break;
147 | case 'Á':
148 | encoded.Append("Á");
149 | break;
150 | case 'à':
151 | encoded.Append("à");
152 | break;
153 | case 'À':
154 | encoded.Append("À");
155 | break;
156 | case 'â':
157 | encoded.Append("â");
158 | break;
159 | case 'Â':
160 | encoded.Append("Â");
161 | break;
162 | case 'å':
163 | encoded.Append("å");
164 | break;
165 | case 'Å':
166 | encoded.Append("Å");
167 | break;
168 | case 'ã':
169 | encoded.Append("ã");
170 | break;
171 | case 'Ã':
172 | encoded.Append("Ã");
173 | break;
174 | case 'ä':
175 | encoded.Append("ä");
176 | break;
177 | case 'Ä':
178 | encoded.Append("Ä");
179 | break;
180 | case 'æ':
181 | encoded.Append("æ");
182 | break;
183 | case 'Æ':
184 | encoded.Append("Æ");
185 | break;
186 | case 'ç':
187 | encoded.Append("ç");
188 | break;
189 | case 'Ç':
190 | encoded.Append("Ç");
191 | break;
192 | case 'é':
193 | encoded.Append("é");
194 | break;
195 | case 'É':
196 | encoded.Append("É");
197 | break;
198 | case 'è':
199 | encoded.Append("è");
200 | break;
201 | case 'È':
202 | encoded.Append("È");
203 | break;
204 | case 'ê':
205 | encoded.Append("ê");
206 | break;
207 | case 'Ê':
208 | encoded.Append("Ê");
209 | break;
210 | case 'ë':
211 | encoded.Append("ë");
212 | break;
213 | case 'Ë':
214 | encoded.Append("Ë");
215 | break;
216 | case 'í':
217 | encoded.Append("í");
218 | break;
219 | case 'Í':
220 | encoded.Append("Í");
221 | break;
222 | case 'ì':
223 | encoded.Append("ì");
224 | break;
225 | case 'Ì':
226 | encoded.Append("Ì");
227 | break;
228 | case 'î':
229 | encoded.Append("î");
230 | break;
231 | case 'Î':
232 | encoded.Append("Î");
233 | break;
234 | case 'ï':
235 | encoded.Append("ï");
236 | break;
237 | case 'Ï':
238 | encoded.Append("Ï");
239 | break;
240 | case 'ñ':
241 | encoded.Append("ñ");
242 | break;
243 | case 'Ñ':
244 | encoded.Append("Ñ");
245 | break;
246 | case 'ó':
247 | encoded.Append("ó");
248 | break;
249 | case 'Ó':
250 | encoded.Append("Ó");
251 | break;
252 | case 'ò':
253 | encoded.Append("ò");
254 | break;
255 | case 'Ò':
256 | encoded.Append("Ò");
257 | break;
258 | case 'ô':
259 | encoded.Append("ô");
260 | break;
261 | case 'Ô':
262 | encoded.Append("Ô");
263 | break;
264 | case 'ø':
265 | encoded.Append("ø");
266 | break;
267 | case 'Ø':
268 | encoded.Append("Ø");
269 | break;
270 | case 'õ':
271 | encoded.Append("õ");
272 | break;
273 | case 'Õ':
274 | encoded.Append("Õ");
275 | break;
276 | case 'ö':
277 | encoded.Append("ö");
278 | break;
279 | case 'Ö':
280 | encoded.Append("Ö");
281 | break;
282 | case 'ß':
283 | encoded.Append("ß");
284 | break;
285 | case 'ú':
286 | encoded.Append("ú");
287 | break;
288 | case 'Ú':
289 | encoded.Append("Ú");
290 | break;
291 | case 'ù':
292 | encoded.Append("ù");
293 | break;
294 | case 'Ù':
295 | encoded.Append("Ù");
296 | break;
297 | case 'û':
298 | encoded.Append("û");
299 | break;
300 | case 'Û':
301 | encoded.Append("Û");
302 | break;
303 | case 'ü':
304 | encoded.Append("ü");
305 | break;
306 | case 'Ü':
307 | encoded.Append("Ü");
308 | break;
309 | case 'ÿ':
310 | encoded.Append("ÿ");
311 | break;
312 | default:
313 | if (ch > 127)
314 | encoded.Append("" + (int)ch + ";");
315 | else
316 | encoded.Append(ch);
317 | break;
318 | }
319 | }
320 | return encoded.ToString();
321 | }
322 |
323 | ///
324 | /// Converts a string to an HTML-encoded string using numeric character references.
325 | ///
326 | /// The string to encode.
327 | /// An encoded string.
328 | public static string EncodeNumeric(string source)
329 | {
330 | if (string.IsNullOrEmpty(source))
331 | return string.Empty;
332 |
333 | var encoded = new StringBuilder(source.Length);
334 | foreach (var ch in source)
335 | {
336 | if (ch == ' ')
337 | {
338 | encoded.Append("");
339 | encoded.Append(160); //
340 | encoded.Append(';');
341 | }
342 | else if (ch > 127 || ch == '<' || ch == '>' || ch == '"' || ch == '&' || ch == '\'')
343 | {
344 | encoded.Append("");
345 | encoded.Append((int)ch);
346 | encoded.Append(';');
347 | }
348 | else
349 | {
350 | encoded.Append(ch);
351 | }
352 | }
353 | return encoded.ToString();
354 | }
355 |
356 | public static string RemoveHtmlTags(string s, bool alsoSsaTags = false)
357 | {
358 | if (s == null || s.Length < 3)
359 | return s;
360 |
361 | if (alsoSsaTags)
362 | s = Utilities.RemoveSsaTags(s);
363 |
364 | if (!Utilities.Contains(s, '<'))
365 | return s;
366 |
367 | if (s.Contains("< "))
368 | s = FixInvalidItalicTags(s);
369 |
370 | return RemoveOpenCloseTags(s, TagItalic, TagBold, TagUnderline, TagParagraph, TagFont, TagCyrillicI);
371 | }
372 |
373 | public static bool IsUrl(string text)
374 | {
375 | if (string.IsNullOrWhiteSpace(text) || text.Length < 6 || !Utilities.Contains(text, '.') || Utilities.Contains(text, ' '))
376 | return false;
377 |
378 | var allLower = text.ToLower();
379 | if (allLower.StartsWith("http://", StringComparison.Ordinal) || allLower.StartsWith("https://", StringComparison.Ordinal) ||
380 | allLower.StartsWith("www.", StringComparison.Ordinal) || allLower.EndsWith(".org", StringComparison.Ordinal) ||
381 | allLower.EndsWith(".com", StringComparison.Ordinal) || allLower.EndsWith(".net", StringComparison.Ordinal))
382 | return true;
383 |
384 | if (allLower.Contains(".org/") || allLower.Contains(".com/") || allLower.Contains(".net/"))
385 | return true;
386 |
387 | return false;
388 | }
389 |
390 | public static bool StartsWithUrl(string text)
391 | {
392 | if (string.IsNullOrWhiteSpace(text))
393 | return false;
394 |
395 | var arr = text.Trim().TrimEnd('.').TrimEnd().Split();
396 | if (arr.Length == 0)
397 | return false;
398 |
399 | return IsUrl(arr[0]);
400 | }
401 |
402 | private static readonly string[] UppercaseTags = { "", "", "", "", "", "", "" };
403 |
404 | public static string FixUpperTags(string text)
405 | {
406 | if (string.IsNullOrEmpty(text) || !Utilities.Contains(text, '<'))
407 | return text;
408 | var idx = text.IndexOfAny(UppercaseTags, StringComparison.Ordinal);
409 | while (idx >= 0)
410 | {
411 | var endIdx = text.IndexOf('>', idx + 2);
412 | if (endIdx < idx)
413 | break;
414 | var tag = text.Substring(idx, endIdx - idx).ToLowerInvariant();
415 | text = text.Remove(idx, endIdx - idx).Insert(idx, tag);
416 | idx = text.IndexOfAny(UppercaseTags, StringComparison.Ordinal);
417 | }
418 | return text;
419 | }
420 |
421 | public static string FixInvalidItalicTags(string text)
422 | {
423 | const string beginTag = "";
424 | const string endTag = "";
425 |
426 | text = text.Replace("< i >", beginTag);
427 | text = text.Replace("< i>", beginTag);
428 | text = text.Replace("", beginTag);
429 | text = text.Replace("", beginTag);
430 | text = text.Replace("< I >", beginTag);
431 | text = text.Replace("< I>", beginTag);
432 | text = text.Replace("", beginTag);
433 |
434 | text = text.Replace("< / i >", endTag);
435 | text = text.Replace("< /i>", endTag);
436 | text = text.Replace(" i>", endTag);
437 | text = text.Replace("< /i >", endTag);
438 | text = text.Replace("", endTag);
439 | text = text.Replace(" i >", endTag);
440 | text = text.Replace("< / i>", endTag);
441 | text = text.Replace("", endTag);
442 | text = text.Replace("< / I >", endTag);
443 | text = text.Replace("< /I>", endTag);
444 | text = text.Replace(" I>", endTag);
445 | text = text.Replace("< /I >", endTag);
446 | text = text.Replace("", endTag);
447 | text = text.Replace(" I >", endTag);
448 | text = text.Replace("< / I>", endTag);
449 |
450 | text = text.Replace(" ", "_@_");
451 | text = text.Replace(" _@_", "_@_");
452 | text = text.Replace(" _@_ ", "_@_");
453 | text = text.Replace("_@_", " ");
454 |
455 | if (text.Contains(beginTag))
456 | {
457 | text = text.Replace("", endTag);
458 | text = text.Replace("", endTag);
459 | }
460 | else
461 | {
462 | text = text.Replace("", string.Empty);
463 | text = text.Replace("", string.Empty);
464 | }
465 |
466 | text = text.Replace(beginTag + beginTag, beginTag);
467 | text = text.Replace(endTag + endTag, endTag);
468 |
469 | int italicBeginTagCount = Utilities.CountTagInText(text, beginTag);
470 | int italicEndTagCount = Utilities.CountTagInText(text, endTag);
471 | int noOfLines = Utilities.GetNumberOfLines(text);
472 | if (italicBeginTagCount + italicEndTagCount > 0)
473 | {
474 | if (italicBeginTagCount == 1 && italicEndTagCount == 1 && text.IndexOf(beginTag, StringComparison.Ordinal) > text.IndexOf(endTag, StringComparison.Ordinal))
475 | {
476 | const string pattern = "___________@";
477 | text = text.Replace(beginTag, pattern);
478 | text = text.Replace(endTag, beginTag);
479 | text = text.Replace(pattern, endTag);
480 | }
481 |
482 | if (italicBeginTagCount == 2 && italicEndTagCount == 0)
483 | {
484 | int firstIndex = text.IndexOf(beginTag, StringComparison.Ordinal);
485 | int lastIndex = text.LastIndexOf(beginTag, StringComparison.Ordinal);
486 | int lastIndexWithNewLine = text.LastIndexOf(Environment.NewLine + beginTag, StringComparison.Ordinal) + Environment.NewLine.Length;
487 | if (noOfLines == 2 && lastIndex == lastIndexWithNewLine && firstIndex < 2)
488 | text = text.Replace(Environment.NewLine, endTag + Environment.NewLine) + endTag;
489 | else
490 | text = text.Remove(lastIndex, beginTag.Length).Insert(lastIndex, endTag);
491 | }
492 |
493 | if (italicBeginTagCount == 1 && italicEndTagCount == 2)
494 | {
495 | int firstIndex = text.IndexOf(endTag, StringComparison.Ordinal);
496 | if (text.StartsWith("--", StringComparison.Ordinal) ||
497 | text.StartsWith("- -", StringComparison.Ordinal) ||
498 | text.StartsWith("- -", StringComparison.Ordinal) ||
499 | text.StartsWith("- -", StringComparison.Ordinal))
500 | text = text.Remove(0, 5);
501 | else if (firstIndex == 0)
502 | text = text.Remove(0, 4);
503 | else
504 | text = text.Substring(0, firstIndex) + text.Substring(firstIndex + endTag.Length);
505 | }
506 |
507 | if (italicBeginTagCount == 2 && italicEndTagCount == 1)
508 | {
509 | var lines = text.SplitToLines();
510 | if (lines.Length == 2 && lines[0].StartsWith(beginTag, StringComparison.Ordinal) && lines[0].EndsWith(endTag, StringComparison.Ordinal) &&
511 | lines[1].StartsWith(beginTag, StringComparison.Ordinal))
512 | {
513 | text = text.TrimEnd() + endTag;
514 | }
515 | else
516 | {
517 | int lastIndex = text.LastIndexOf(beginTag, StringComparison.Ordinal);
518 | if (text.Length > lastIndex + endTag.Length)
519 | text = text.Substring(0, lastIndex) + text.Substring(lastIndex - 1 + endTag.Length);
520 | else
521 | text = text.Substring(0, lastIndex - 1) + endTag;
522 | }
523 | if (text.StartsWith(beginTag, StringComparison.Ordinal) && text.EndsWith(endTag, StringComparison.Ordinal) && text.Contains(endTag + Environment.NewLine + beginTag))
524 | {
525 | text = text.Replace(endTag + Environment.NewLine + beginTag, Environment.NewLine);
526 | }
527 | }
528 |
529 | if (italicBeginTagCount == 1 && italicEndTagCount == 0)
530 | {
531 | int lastIndexWithNewLine = text.LastIndexOf(Environment.NewLine + beginTag, StringComparison.Ordinal) + Environment.NewLine.Length;
532 | int lastIndex = text.LastIndexOf(beginTag, StringComparison.Ordinal);
533 |
534 | if (text.StartsWith(beginTag, StringComparison.Ordinal))
535 | text += endTag;
536 | else if (noOfLines == 2 && lastIndex == lastIndexWithNewLine)
537 | text += endTag;
538 | else
539 | text = text.Replace(beginTag, string.Empty);
540 | }
541 |
542 | if (italicBeginTagCount == 0 && italicEndTagCount == 1)
543 | {
544 | var cleanText = RemoveOpenCloseTags(text, TagItalic, TagBold, TagUnderline, TagCyrillicI);
545 | bool isFixed = false;
546 |
547 | // Foo.
548 | if (text.EndsWith(endTag, StringComparison.Ordinal) && !cleanText.StartsWith("-") && !cleanText.Contains(Environment.NewLine + "-"))
549 | {
550 | text = beginTag + text;
551 | isFixed = true;
552 | }
553 |
554 | // - Foo | - Foo.
555 | // - Bar. | - Foo.
556 | if (!isFixed && Utilities.GetNumberOfLines(cleanText) == 2)
557 | {
558 | int newLineIndex = text.IndexOf(Environment.NewLine, StringComparison.Ordinal);
559 | if (newLineIndex > 0)
560 | {
561 | var firstLine = text.Substring(0, newLineIndex).Trim();
562 | var secondLine = text.Substring(newLineIndex + 2).Trim();
563 | if (firstLine.EndsWith(endTag, StringComparison.Ordinal))
564 | {
565 | firstLine = beginTag + firstLine;
566 | isFixed = true;
567 | }
568 | if (secondLine.EndsWith(endTag, StringComparison.Ordinal))
569 | {
570 | secondLine = beginTag + secondLine;
571 | isFixed = true;
572 | }
573 | text = firstLine + Environment.NewLine + secondLine;
574 | }
575 | }
576 | if (!isFixed)
577 | text = text.Replace(endTag, string.Empty);
578 | }
579 |
580 | // - foo.
581 | // - bar.
582 | if (italicBeginTagCount == 0 && italicEndTagCount == 2 && text.Contains(endTag + Environment.NewLine, StringComparison.Ordinal) && text.EndsWith(endTag, StringComparison.Ordinal))
583 | {
584 | text = text.Replace(endTag, string.Empty);
585 | text = beginTag + text + endTag;
586 | }
587 |
588 | if (italicBeginTagCount == 0 && italicEndTagCount == 2 && text.StartsWith(endTag, StringComparison.Ordinal) && text.EndsWith(endTag, StringComparison.Ordinal))
589 | {
590 | int firstIndex = text.IndexOf(endTag, StringComparison.Ordinal);
591 | text = text.Remove(firstIndex, endTag.Length).Insert(firstIndex, beginTag);
592 | }
593 |
594 | // Foo
595 | // Bar
596 | if (italicBeginTagCount == 2 && italicEndTagCount == 2 && noOfLines == 2)
597 | {
598 | int index = text.IndexOf(Environment.NewLine, StringComparison.Ordinal);
599 | if (index > 0 && text.Length > index + (beginTag.Length + endTag.Length))
600 | {
601 | var firstLine = text.Substring(0, index).Trim();
602 | var secondLine = text.Substring(index + Environment.NewLine.Length).Trim();
603 |
604 | if (firstLine.Length > 10 && firstLine.StartsWith("- ", StringComparison.Ordinal) && firstLine.EndsWith(endTag, StringComparison.Ordinal))
605 | {
606 | text = "- " + firstLine.Remove(0, 5) + Environment.NewLine + secondLine;
607 | text = text.Replace("- ", "- ");
608 | index = text.IndexOf(Environment.NewLine, StringComparison.Ordinal);
609 | firstLine = text.Substring(0, index).Trim();
610 | secondLine = text.Substring(index + Environment.NewLine.Length).Trim();
611 | }
612 | if (secondLine.Length > 10 && secondLine.StartsWith("- ", StringComparison.Ordinal) && secondLine.EndsWith(endTag, StringComparison.Ordinal))
613 | {
614 | text = firstLine + Environment.NewLine + "- " + secondLine.Remove(0, 5);
615 | text = text.Replace("- ", "- ");
616 | index = text.IndexOf(Environment.NewLine, StringComparison.Ordinal);
617 | firstLine = text.Substring(0, index).Trim();
618 | secondLine = text.Substring(index + Environment.NewLine.Length).Trim();
619 | }
620 |
621 | if (Utilities.StartsAndEndsWithTag(firstLine, beginTag, endTag) && Utilities.StartsAndEndsWithTag(secondLine, beginTag, endTag))
622 | {
623 | text = text.Replace(beginTag, string.Empty).Replace(endTag, string.Empty).Trim();
624 | text = beginTag + text + endTag;
625 | }
626 | }
627 |
628 | //FALCONE: I didn't think
it was going to be you,
629 | var colIdx = text.IndexOf(':');
630 | if (colIdx >= 0 && Utilities.CountTagInText(text, beginTag) + Utilities.CountTagInText(text, endTag) == 4 && text.Length > colIdx + 1 && !char.IsDigit(text[colIdx + 1]))
631 | {
632 | var firstLine = text.Substring(0, index);
633 | var secondLine = text.Substring(index).TrimStart();
634 |
635 | var secIdxCol = secondLine.IndexOf(':');
636 | if (secIdxCol < 0 || !Utilities.IsBetweenNumbers(secondLine, secIdxCol))
637 | {
638 | var idx = firstLine.IndexOf(':');
639 | if (idx > 1)
640 | {
641 | var pre = text.Substring(0, idx + 1).TrimStart();
642 | text = text.Remove(0, idx + 1);
643 | text = FixInvalidItalicTags(text).Trim();
644 | if (text.StartsWith(" ", StringComparison.OrdinalIgnoreCase))
645 | text = Utilities.RemoveSpaceBeforeAfterTag(text, beginTag);
646 | text = pre + " " + text;
647 | }
648 | }
649 | }
650 | }
651 |
652 | //- You think they're they gone?
653 | //- That can't be.
654 | if (italicBeginTagCount == 3 && italicEndTagCount == 1 && noOfLines == 2)
655 | {
656 | var newLineIdx = text.IndexOf(Environment.NewLine, StringComparison.Ordinal);
657 | var firstLine = text.Substring(0, newLineIdx).Trim();
658 | var secondLine = text.Substring(newLineIdx).Trim();
659 |
660 | if ((Utilities.StartsAndEndsWithTag(firstLine, beginTag, beginTag) && Utilities.StartsAndEndsWithTag(secondLine, beginTag, endTag)) ||
661 | (Utilities.StartsAndEndsWithTag(secondLine, beginTag, beginTag) && Utilities.StartsAndEndsWithTag(firstLine, beginTag, endTag)))
662 | {
663 | text = text.Replace(beginTag, string.Empty);
664 | text = text.Replace(endTag, string.Empty);
665 | text = text.Replace(" ", " ").Trim();
666 | text = beginTag + text + endTag;
667 | }
668 | }
669 |
670 | if (noOfLines == 3)
671 | {
672 | var lines = text.SplitToLines();
673 | if (italicBeginTagCount == 3 && italicEndTagCount == 2 || italicBeginTagCount == 2 && italicEndTagCount == 3)
674 | {
675 | int numberOfItalics = 0;
676 | foreach (var line in lines)
677 | {
678 | if (line.StartsWith(beginTag, StringComparison.Ordinal))
679 | numberOfItalics++;
680 | if (line.EndsWith(endTag, StringComparison.Ordinal))
681 | numberOfItalics++;
682 | }
683 | if (numberOfItalics == 5)
684 | { // fix missing tag
685 | text = "" + text.Replace("", string.Empty).Replace("", string.Empty) + "";
686 | }
687 | }
688 | }
689 |
690 | text = text.Replace("", string.Empty);
691 | text = text.Replace(" ", string.Empty);
692 | text = text.Replace(" ", string.Empty);
693 | }
694 | return text;
695 | }
696 |
697 | public static string ToggleTag(string text, string tag)
698 | {
699 | if (text.IndexOf("<" + tag + ">", StringComparison.OrdinalIgnoreCase) >= 0 ||
700 | text.IndexOf("" + tag + ">", StringComparison.OrdinalIgnoreCase) >= 0)
701 | {
702 | text = text.Replace("<" + tag + ">", string.Empty);
703 | text = text.Replace("" + tag + ">", string.Empty);
704 | text = text.Replace("<" + tag.ToUpper() + ">", string.Empty);
705 | text = text.Replace("" + tag.ToUpper() + ">", string.Empty);
706 | }
707 | else
708 | {
709 | int indexOfEndBracket = text.IndexOf('}');
710 | if (text.StartsWith("{\\", StringComparison.Ordinal) && indexOfEndBracket > 1 && indexOfEndBracket < 6)
711 | {
712 | text = $"{text.Substring(0, indexOfEndBracket + 1)}<{tag}>{text.Remove(0, indexOfEndBracket + 1)}{tag}>";
713 | }
714 | else
715 | {
716 | text = $"<{tag}>{text}{tag}>";
717 | }
718 | }
719 | return text;
720 | }
721 |
722 | }
723 | }
724 |
--------------------------------------------------------------------------------
/src/XmlContentTranslator/Translator/ITranslator.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Text;
3 |
4 | namespace XmlContentTranslator.Translator
5 | {
6 | public interface ITranslator
7 | {
8 | List GetTranslationPairs();
9 | string GetName();
10 | string GetUrl();
11 | List Translate(string sourceLanguage, string targetLanguage, List paragraphs, StringBuilder log);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/XmlContentTranslator/Translator/Json.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 |
4 | namespace XmlContentTranslator.Translator
5 | {
6 | public class Json
7 | {
8 | public static string EncodeJsonText(string text)
9 | {
10 | var sb = new StringBuilder(text.Length);
11 | foreach (var c in text)
12 | {
13 | switch (c)
14 | {
15 | case '\\':
16 | sb.Append("\\\\");
17 | break;
18 | case '"':
19 | sb.Append("\\\"");
20 | break;
21 | default:
22 | sb.Append(c);
23 | break;
24 | }
25 | }
26 | return sb.ToString().Replace(Environment.NewLine, "
");
27 | }
28 |
29 | public static string DecodeJsonText(string text)
30 | {
31 | text = text.Replace("
", Environment.NewLine);
32 | text = text.Replace("
", Environment.NewLine);
33 | text = text.Replace("
", Environment.NewLine);
34 | text = text.Replace("\\n", Environment.NewLine);
35 | bool keepNext = false;
36 | var sb = new StringBuilder(text.Length);
37 | foreach (var c in text)
38 | {
39 | if (c == '\\' && !keepNext)
40 | {
41 | keepNext = true;
42 | }
43 | else
44 | {
45 | sb.Append(c);
46 | keepNext = false;
47 | }
48 | }
49 | return sb.ToString();
50 | }
51 |
52 |
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/XmlContentTranslator/Translator/StringExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Text;
4 |
5 | namespace XmlContentTranslator.Translator
6 | {
7 | public static class StringExtensions
8 | {
9 | public static bool LineStartsWithHtmlTag(this string text, bool threeLengthTag, bool includeFont = false)
10 | {
11 | if (text == null || (!threeLengthTag && !includeFont))
12 | return false;
13 | return StartsWithHtmlTag(text, threeLengthTag, includeFont);
14 | }
15 |
16 | public static bool LineEndsWithHtmlTag(this string text, bool threeLengthTag, bool includeFont = false)
17 | {
18 | if (text == null)
19 | return false;
20 |
21 | var len = text.Length;
22 | if (len < 6 || text[len - 1] != '>')
23 | return false;
24 |
25 | //
26 | if (threeLengthTag && len > 3 && text[len - 4] == '<' && text[len - 3] == '/')
27 | return true;
28 | if (includeFont && len > 8 && text[len - 7] == '<' && text[len - 6] == '/')
29 | return true;
30 | return false;
31 | }
32 |
33 | public static bool LineBreakStartsWithHtmlTag(this string text, bool threeLengthTag, bool includeFont = false)
34 | {
35 | if (text == null || (!threeLengthTag && !includeFont))
36 | return false;
37 | var newLineIdx = text.IndexOf(Environment.NewLine, StringComparison.Ordinal);
38 | if (newLineIdx < 0 || text.Length < newLineIdx + 5)
39 | return false;
40 | text = text.Substring(newLineIdx + 2);
41 | return StartsWithHtmlTag(text, threeLengthTag, includeFont);
42 | }
43 |
44 | private static bool StartsWithHtmlTag(string text, bool threeLengthTag, bool includeFont)
45 | {
46 | if (threeLengthTag && text.Length >= 3 && text[0] == '<' && text[2] == '>' && (text[1] == 'i' || text[1] == 'I' || text[1] == 'u' || text[1] == 'U' || text[1] == 'b' || text[1] == 'B'))
47 | return true;
48 | if (includeFont && text.Length > 5 && text.StartsWith("', 5) >= 5; // or
50 | return false;
51 | }
52 |
53 | public static bool StartsWith(this string s, char c)
54 | {
55 | return s.Length > 0 && s[0] == c;
56 | }
57 |
58 | public static bool StartsWith(this StringBuilder sb, char c)
59 | {
60 | return sb.Length > 0 && sb[0] == c;
61 | }
62 |
63 | public static bool EndsWith(this string s, char c)
64 | {
65 | return s.Length > 0 && s[s.Length - 1] == c;
66 | }
67 |
68 | public static bool EndsWith(this StringBuilder sb, char c)
69 | {
70 | return sb.Length > 0 && sb[sb.Length - 1] == c;
71 | }
72 |
73 | public static bool Contains(this string source, char value)
74 | {
75 | return source.IndexOf(value) >= 0;
76 | }
77 |
78 | public static bool Contains(this string source, char[] value)
79 | {
80 | return source.IndexOfAny(value) >= 0;
81 | }
82 |
83 | public static bool Contains(this string source, string value, StringComparison comparisonType)
84 | {
85 | return source.IndexOf(value, comparisonType) >= 0;
86 | }
87 |
88 | public static string[] SplitToLines(this string source)
89 | {
90 | return source.Replace("\r\r\n", "\n").Replace("\r\n", "\n").Replace('\r', '\n').Replace('\u2028', '\n').Split('\n');
91 | }
92 |
93 | public static int CountWords(this string source)
94 | {
95 | return HtmlUtil.RemoveHtmlTags(source, true).Split(new[] { ' ', '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries).Length;
96 | }
97 |
98 | // http://www.codeproject.com/Articles/43726/Optimizing-string-operations-in-C
99 | public static int FastIndexOf(this string source, string pattern)
100 | {
101 | if (pattern == null) throw new ArgumentNullException();
102 | if (pattern.Length == 0) return 0;
103 | if (pattern.Length == 1) return source.IndexOf(pattern[0]);
104 | int limit = source.Length - pattern.Length + 1;
105 | if (limit < 1) return -1;
106 | // Store the first 2 characters of "pattern"
107 | char c0 = pattern[0];
108 | char c1 = pattern[1];
109 | // Find the first occurrence of the first character
110 | int first = source.IndexOf(c0, 0, limit);
111 | while (first != -1)
112 | {
113 | // Check if the following character is the same like
114 | // the 2nd character of "pattern"
115 | if (source[first + 1] != c1)
116 | {
117 | first = source.IndexOf(c0, ++first, limit - first);
118 | continue;
119 | }
120 | // Check the rest of "pattern" (starting with the 3rd character)
121 | bool found = true;
122 | for (var j = 2; j < pattern.Length; j++)
123 | if (source[first + j] != pattern[j])
124 | {
125 | found = false;
126 | break;
127 | }
128 | // If the whole word was found, return its index, otherwise try again
129 | if (found) return first;
130 | first = source.IndexOf(c0, ++first, limit - first);
131 | }
132 | return -1;
133 | }
134 |
135 | public static int IndexOfAny(this string s, string[] words, StringComparison comparisonType)
136 | {
137 | if (words == null || string.IsNullOrEmpty(s))
138 | return -1;
139 | for (int i = 0; i < words.Length; i++)
140 | {
141 | var idx = s.IndexOf(words[i], comparisonType);
142 | if (idx >= 0)
143 | return idx;
144 | }
145 | return -1;
146 | }
147 |
148 | public static string FixExtraSpaces(this string s)
149 | {
150 | if (string.IsNullOrEmpty(s))
151 | return s;
152 | int len = s.Length;
153 | int k = -1;
154 | for (int i = len - 1; i >= 0; i--)
155 | {
156 | char ch = s[i];
157 | if (k < 2)
158 | {
159 | if (ch == 0x20)
160 | {
161 | k = i + 1;
162 | }
163 | }
164 | else if (ch != 0x20)
165 | {
166 | // Two or more white-spaces found!
167 | if (k - (i + 1) > 1)
168 | {
169 | // Keep only one white-space.
170 | s = s.Remove(i + 1, k - (i + 2));
171 | }
172 |
173 | // No white-space after/before line break.
174 | if ((ch == '\n' || ch == '\r') && i + 1 < s.Length && s[i + 1] == 0x20)
175 | {
176 | s = s.Remove(i + 1, 1);
177 | }
178 | // Reset remove length.
179 | k = -1;
180 | }
181 | if (ch == 0x20 && i + 1 < s.Length && (s[i + 1] == '\n' || s[i + 1] == '\r'))
182 | {
183 | s = s.Remove(i, 1);
184 | }
185 | }
186 | return s;
187 | }
188 |
189 | public static bool ContainsLetter(this string s)
190 | {
191 | if (s != null)
192 | {
193 | foreach (var index in StringInfo.ParseCombiningCharacters(s))
194 | {
195 | var uc = CharUnicodeInfo.GetUnicodeCategory(s, index);
196 | if (uc == UnicodeCategory.LowercaseLetter || uc == UnicodeCategory.UppercaseLetter || uc == UnicodeCategory.TitlecaseLetter || uc == UnicodeCategory.ModifierLetter || uc == UnicodeCategory.OtherLetter)
197 | return true;
198 | }
199 | }
200 | return false;
201 | }
202 |
203 | public static string RemoveControlCharacters(this string s)
204 | {
205 | int max = s.Length;
206 | var newStr = new char[max];
207 | int newIdx = 0;
208 | for (int index = 0; index < max; index++)
209 | {
210 | var ch = s[index];
211 | if (!char.IsControl(ch))
212 | {
213 | newStr[newIdx++] = ch;
214 | }
215 | }
216 | return new string(newStr, 0, newIdx);
217 | }
218 |
219 | public static string RemoveControlCharactersButWhiteSpace(this string s)
220 | {
221 | int max = s.Length;
222 | var newStr = new char[max];
223 | int newIdx = 0;
224 | for (int index = 0; index < max; index++)
225 | {
226 | var ch = s[index];
227 | if (!char.IsControl(ch) || ch == '\u000d' || ch == '\u000a' || ch == '\u0009')
228 | {
229 | newStr[newIdx++] = ch;
230 | }
231 | }
232 | return new string(newStr, 0, newIdx);
233 | }
234 |
235 | public static string CapitalizeFirstLetter(this string s, CultureInfo ci = null)
236 | {
237 | var si = new StringInfo(s);
238 | if (ci == null)
239 | ci = CultureInfo.CurrentCulture;
240 | if (si.LengthInTextElements > 0)
241 | s = si.SubstringByTextElements(0, 1).ToUpper(ci);
242 | if (si.LengthInTextElements > 1)
243 | s += si.SubstringByTextElements(1);
244 | return s;
245 | }
246 |
247 | public static string ToRtf(this string value)
248 | {
249 | return @"{\rtf1\ansi\ansicpg1252\deff0{\fonttbl\f0\fswiss Helvetica;}\f0\pard " + value.ToRtfPart() + @"\par" + Environment.NewLine + "}";
250 | }
251 |
252 | public static string ToRtfPart(this string value)
253 | {
254 | // special RTF chars
255 | var backslashed = new StringBuilder(value);
256 | backslashed.Replace(@"\", @"\\");
257 | backslashed.Replace(@"{", @"\{");
258 | backslashed.Replace(@"}", @"\}");
259 | backslashed.Replace(Environment.NewLine, @"\par" + Environment.NewLine);
260 |
261 | // convert string char by char
262 | var sb = new StringBuilder();
263 | foreach (char character in backslashed.ToString())
264 | {
265 | if (character <= 0x7f)
266 | sb.Append(character);
267 | else
268 | sb.Append("\\u" + Convert.ToUInt32(character) + "?");
269 | }
270 | return sb.ToString();
271 | }
272 |
273 | }
274 | }
275 |
--------------------------------------------------------------------------------
/src/XmlContentTranslator/Translator/TranslationHelper.cs:
--------------------------------------------------------------------------------
1 | using System.Text.RegularExpressions;
2 |
3 | namespace XmlContentTranslator.Translator
4 | {
5 | public static class TranslationHelper
6 | {
7 | public static string PostTranslate(string s, string target)
8 | {
9 | if (target == "da")
10 | {
11 | s = s.Replace("Jeg ved.", "Jeg ved det.");
12 | s = s.Replace(", jeg ved.", ", jeg ved det.");
13 |
14 | s = s.Replace("Jeg er ked af.", "Jeg er ked af det.");
15 | s = s.Replace(", jeg er ked af.", ", jeg er ked af det.");
16 |
17 | s = s.Replace("Come on.", "Kom nu.");
18 | s = s.Replace(", come on.", ", kom nu.");
19 | s = s.Replace("Come on,", "Kom nu,");
20 |
21 | s = s.Replace("Hey ", "Hej ");
22 | s = s.Replace("Hey,", "Hej,");
23 |
24 | s = s.Replace(" gonna ", " ville ");
25 | s = s.Replace("Gonna ", "Vil ");
26 |
27 | s = s.Replace("Ked af.", "Undskyld.");
28 | }
29 | return s;
30 | }
31 |
32 | public static string PreTranslate(string s, string source)
33 | {
34 | if (source == "en")
35 | {
36 | s = Regex.Replace(s, @"\bI'm ", "I am ");
37 | s = Regex.Replace(s, @"\bI've ", "I have ");
38 | s = Regex.Replace(s, @"\bI'll ", "I will ");
39 | // s = Regex.Replace(s, @"\bI'd ", "I would "); // had or would???
40 | s = Regex.Replace(s, @"\b(I|i)t's ", "$1t is ");
41 | s = Regex.Replace(s, @"\b(Y|y)ou're ", "$1ou are ");
42 | s = Regex.Replace(s, @"\b(Y|y)ou've ", "$1ou have ");
43 | s = Regex.Replace(s, @"\b(Y|y)ou'll ", "$1ou will ");
44 | // s = Regex.Replace(s, @"\b(Y|y)ou'd ", "$1ou would "); // had or would???
45 | s = Regex.Replace(s, @"\b(H|h)e's ", "$1e is ");
46 | s = Regex.Replace(s, @"\b(S|s)he's ", "$1he is ");
47 | s = Regex.Replace(s, @"\b(W|w)e're ", "$1e are ");
48 | s = Regex.Replace(s, @"\bwon't ", "will not ");
49 | s = Regex.Replace(s, @"\bdon't ", "do not ");
50 | s = Regex.Replace(s, @"\bDon't ", "Do not ");
51 | s = Regex.Replace(s, @"\b(W|w)e're ", "$1e are ");
52 | s = Regex.Replace(s, @"\b(T|t)hey're ", "$1hey are ");
53 | s = Regex.Replace(s, @"\b(W|w)ho's ", "$1ho is ");
54 | s = Regex.Replace(s, @"\b(T|t)hat's ", "$1hat is ");
55 | s = Regex.Replace(s, @"\b(W|w)hat's ", "$1hat is ");
56 | s = Regex.Replace(s, @"\b(W|w)here's ", "$1here is ");
57 | s = Regex.Replace(s, @"\b(W|w)ho's ", "$1ho is ");
58 | s = Regex.Replace(s, @"\B'(C|c)ause ", "$1ecause "); // \b (word boundry) does not workig with '
59 | }
60 | return s;
61 | }
62 |
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/XmlContentTranslator/Translator/TranslationPair.cs:
--------------------------------------------------------------------------------
1 | namespace XmlContentTranslator.Translator
2 | {
3 | public class TranslationPair
4 | {
5 | public string Name { get; set; }
6 | public string Code { get; set; }
7 |
8 | public TranslationPair()
9 | {
10 |
11 | }
12 |
13 | public TranslationPair(string name, string code)
14 | {
15 | Name = name;
16 | Code = code;
17 | }
18 |
19 | public override string ToString()
20 | {
21 | return Name;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/XmlContentTranslator/Translator/Utilities.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Reflection;
4 | using System.Text;
5 | using System.Text.RegularExpressions;
6 |
7 | namespace XmlContentTranslator.Translator
8 | {
9 | public static class Utilities
10 | {
11 |
12 | public static readonly string UppercaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWZYXÆØÃÅÄÖÉÈÁÂÀÇÊÍÓÔÕÚŁАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯĞİŞÜÙÁÌÑÎ";
13 | public static readonly string LowercaseLetters = UppercaseLetters.ToLower();
14 | public static readonly string LowercaseLettersWithNumbers = LowercaseLetters + "0123456789";
15 | public static readonly string AllLetters = UppercaseLetters + LowercaseLetters;
16 | public static readonly string AllLettersAndNumbers = UppercaseLetters + LowercaseLettersWithNumbers;
17 |
18 | //#region StringExtension
19 | public static bool Contains(this string s, char c)
20 | {
21 | return s.Length > 0 && s.IndexOf(c) > 0;
22 | }
23 | //public static string[] SplitToLines(this string s)
24 | //{
25 | // return s.Replace(Environment.NewLine, "\n").Replace('\r', '\n').Split('\n');
26 | //}
27 | //#endregion
28 | internal static string AssemblyVersion
29 | {
30 | get
31 | {
32 | return Assembly.GetExecutingAssembly().GetName().Version.ToString();
33 | }
34 | }
35 |
36 | public static bool IsInteger(string s)
37 | {
38 | int i;
39 | return int.TryParse(s, out i);
40 | }
41 |
42 | public static string RemoveHtmlTags(string s, bool alsoSSA = false)
43 | {
44 | if (string.IsNullOrEmpty(s))
45 | return string.Empty;
46 |
47 | if (alsoSSA)
48 | s = RemoveSsaTags(s);
49 |
50 | if (!Contains(s, '<'))
51 | return s;
52 | s = Regex.Replace(s, "(?i)?[ibu]>", string.Empty);
53 | while (s.Contains(" ")) s = s.Replace(" ", " ");
54 | return RemoveHtmlFontTag(s).Trim();
55 | }
56 |
57 | public static string RemoveSsaTags(string s)
58 | {
59 | const string tag = "{\\";
60 | var idx = s.IndexOf(tag, StringComparison.Ordinal);
61 | while (idx >= 0)
62 | {
63 | var endIdx = s.IndexOf('}');
64 | if (endIdx < idx)
65 | break;
66 | s = s.Remove(idx, endIdx - idx + 1);
67 | idx = s.IndexOf(tag, StringComparison.Ordinal);
68 | }
69 | return s;
70 | }
71 |
72 | public static string RemoveHtmlFontTag(string s)
73 | {
74 | s = Regex.Replace(s, "(?i)?font>", string.Empty);
75 | var idx = s.IndexOf("= 0)
77 | {
78 | var endIdx = s.IndexOf('>', idx + 5);
79 | if (endIdx < idx) break;
80 | s = s.Remove(idx, endIdx - idx + 1);
81 | idx = s.IndexOf("= 0)
91 | {
92 | count++;
93 | index = index + tag.Length;
94 | if (index >= text.Length)
95 | return count;
96 | index = text.IndexOf(tag, index, StringComparison.Ordinal);
97 | }
98 | return count;
99 | }
100 |
101 | public static string FixExtraSpaces(this string s)
102 | {
103 | if (string.IsNullOrEmpty(s))
104 | return s;
105 | int len = s.Length;
106 | int k = -1;
107 | for (int i = len - 1; i >= 0; i--)
108 | {
109 | char ch = s[i];
110 | if (k < 2)
111 | {
112 | if (ch == 0x20)
113 | {
114 | k = i + 1;
115 | }
116 | }
117 | else if (ch != 0x20)
118 | {
119 | // Two or more white-spaces found!
120 | if (k - (i + 1) > 1)
121 | {
122 | // Keep only one white-space.
123 | s = s.Remove(i + 1, k - (i + 2));
124 | }
125 |
126 | // No white-space after/before line break.
127 | if ((ch == '\n' || ch == '\r') && i + 1 < s.Length && s[i + 1] == 0x20)
128 | {
129 | s = s.Remove(i + 1, 1);
130 | }
131 | // Reset remove length.
132 | k = -1;
133 | }
134 | if (ch == 0x20 && i + 1 < s.Length && (s[i + 1] == '\n' || s[i + 1] == '\r'))
135 | {
136 | s = s.Remove(i, 1);
137 | }
138 | }
139 | return s;
140 | }
141 |
142 | public static int GetNumberOfLines(string text)
143 | {
144 | if (string.IsNullOrEmpty(text))
145 | return 0;
146 |
147 | int lines = 1;
148 | int idx = text.IndexOf('\n');
149 | while (idx >= 0)
150 | {
151 | lines++;
152 | idx = text.IndexOf('\n', idx + 1);
153 | }
154 | return lines;
155 | }
156 |
157 | public static bool StartsAndEndsWithTag(string text, string startTag, string endTag)
158 | {
159 | if (string.IsNullOrWhiteSpace(text))
160 | return false;
161 | if (!text.Contains(startTag) || !text.Contains(endTag))
162 | return false;
163 |
164 | while (text.Contains(" "))
165 | text = text.Replace(" ", " ");
166 |
167 | var s1 = "- " + startTag;
168 | var s2 = "-" + startTag;
169 | var s3 = "- ..." + startTag;
170 | var s4 = "- " + startTag + "..."; // - ...
171 |
172 | var e1 = endTag + ".";
173 | var e2 = endTag + "!";
174 | var e3 = endTag + "?";
175 | var e4 = endTag + "...";
176 | var e5 = endTag + "-";
177 |
178 | bool isStart = false;
179 | bool isEnd = false;
180 | if (text.StartsWith(startTag, StringComparison.Ordinal) || text.StartsWith(s1, StringComparison.Ordinal) || text.StartsWith(s2, StringComparison.Ordinal) || text.StartsWith(s3, StringComparison.Ordinal) || text.StartsWith(s4, StringComparison.Ordinal))
181 | isStart = true;
182 | if (text.EndsWith(endTag, StringComparison.Ordinal) || text.EndsWith(e1, StringComparison.Ordinal) || text.EndsWith(e2, StringComparison.Ordinal) || text.EndsWith(e3, StringComparison.Ordinal) || text.EndsWith(e4, StringComparison.Ordinal) || text.EndsWith(e5, StringComparison.Ordinal))
183 | isEnd = true;
184 | return isStart && isEnd;
185 | }
186 |
187 | public static bool IsBetweenNumbers(string s, int position)
188 | {
189 | if (string.IsNullOrEmpty(s) || position < 1 || position + 2 > s.Length)
190 | return false;
191 | return char.IsDigit(s[position - 1]) && char.IsDigit(s[position + 1]);
192 | }
193 |
194 | public static string RemoveSpaceBeforeAfterTag(string text, string openTag)
195 | {
196 | text = HtmlUtil.FixUpperTags(text);
197 | var closeTag = string.Empty;
198 | switch (openTag)
199 | {
200 | case "":
201 | closeTag = "";
202 | break;
203 | case "":
204 | closeTag = "";
205 | break;
206 | case "":
207 | closeTag = "";
208 | break;
209 | }
210 |
211 | if (closeTag.Length == 0 && openTag.Contains("
Foobar
239 | if (text.StartsWith(open1, StringComparison.Ordinal))
240 | text = openTag + text.Substring(open1.Length);
241 |
242 | // e.g.: \r\n
243 | if (text.StartsWith(open3, StringComparison.Ordinal))
244 | text = text.Remove(openTag.Length, Environment.NewLine.Length);
245 |
246 | // e.g.: \r\n
247 | if (text.EndsWith(close5, StringComparison.Ordinal))
248 | text = text.Remove(text.Length - openTag.Length - Environment.NewLine.Length - 1, Environment.NewLine.Length);
249 |
250 | if (text.Contains(open2, StringComparison.Ordinal))
251 | text = text.Replace(open2, Environment.NewLine + openTag);
252 |
253 | // Hi bad man! -> Hi bad man!
254 | text = text.Replace(" " + openTag + " ", " " + openTag);
255 | text = text.Replace(Environment.NewLine + openTag + " ", Environment.NewLine + openTag);
256 |
257 | // Hi bad man! -> Hi bad man!
258 | text = text.Replace(" " + closeTag + " ", closeTag + " ");
259 | text = text.Replace(" " + closeTag + Environment.NewLine, closeTag + Environment.NewLine);
260 |
261 | text = text.Trim();
262 | if (text.StartsWith(open1, StringComparison.Ordinal))
263 | text = openTag + text.Substring(open1.Length);
264 |
265 | return text;
266 | }
267 |
268 |
269 |
270 | public static string AutoBreakLine(string text, string language)
271 | {
272 | return AutoBreakLine(text, 43, 22, language);
273 | }
274 |
275 | public static string AutoBreakLine(string text)
276 | {
277 | return AutoBreakLine(text, string.Empty); // no language
278 | }
279 |
280 | private static bool CanBreak(string s, int index, string language)
281 | {
282 | char nextChar;
283 | if (index >= 0 && index < s.Length)
284 | nextChar = s[index];
285 | else
286 | return false;
287 | if (!Contains("\r\n\t ", nextChar))
288 | return false;
289 |
290 | // Some words we don't like breaking after
291 | string s2 = s.Substring(0, index);
292 | if (s2.EndsWith("? -", StringComparison.Ordinal) || s2.EndsWith("! -", StringComparison.Ordinal) || s2.EndsWith(". -", StringComparison.Ordinal))
293 | return false;
294 |
295 | return true;
296 | }
297 |
298 | public static string AutoBreakLineMoreThanTwoLines(string text, int maximumLineLength, string language)
299 | {
300 | if (text == null || text.Length < 3)
301 | return text;
302 |
303 | string s = AutoBreakLine(text, 0, 0, language);
304 |
305 | var arr = s.SplitToLines();
306 | if ((arr.Length < 2 && arr[0].Length <= maximumLineLength) || (arr[0].Length <= maximumLineLength && arr[1].Length <= maximumLineLength))
307 | return s;
308 |
309 | s = RemoveLineBreaks(s);
310 |
311 | var htmlTags = new Dictionary();
312 | var sb = new StringBuilder(s.Length);
313 | int six = 0;
314 | while (six < s.Length)
315 | {
316 | var letter = s[six];
317 | var tagFound = letter == '<' && (s.Substring(six).StartsWith("', six + 1);
328 |
329 | if (tagFound && endIndex > 0)
330 | {
331 | string tag = s.Substring(six, endIndex - six + 1);
332 | s = s.Remove(six, tag.Length);
333 | if (htmlTags.ContainsKey(six))
334 | htmlTags[six] = htmlTags[six] + tag;
335 | else
336 | htmlTags.Add(six, tag);
337 | }
338 | else
339 | {
340 | sb.Append(letter);
341 | six++;
342 | }
343 | }
344 | s = sb.ToString();
345 |
346 | var words = s.Split(' ');
347 | for (int numberOfLines = 3; numberOfLines < 9999; numberOfLines++)
348 | {
349 | int average = s.Length / numberOfLines + 1;
350 | for (int len = average; len < maximumLineLength; len++)
351 | {
352 | List list = SplitToX(words, numberOfLines, len);
353 | bool allOk = true;
354 | foreach (var lineLength in list)
355 | {
356 | if (lineLength > maximumLineLength)
357 | allOk = false;
358 | }
359 | if (allOk)
360 | {
361 | int index = 0;
362 | foreach (var item in list)
363 | {
364 | index += item;
365 | htmlTags.Add(index, Environment.NewLine);
366 | }
367 | s = ReInsertHtmlTags(s, htmlTags);
368 | s = s.Replace(" " + Environment.NewLine, Environment.NewLine);
369 | s = s.Replace(Environment.NewLine + " ", Environment.NewLine);
370 | s = s.Replace(Environment.NewLine + "", "" + Environment.NewLine);
371 | s = s.Replace(Environment.NewLine + "", "" + Environment.NewLine);
372 | s = s.Replace(Environment.NewLine + "", "" + Environment.NewLine);
373 | s = s.Replace(Environment.NewLine + "", "" + Environment.NewLine);
374 | return s.TrimEnd();
375 | }
376 | }
377 | }
378 |
379 | return text;
380 | }
381 |
382 | private static List SplitToX(string[] words, int count, int average)
383 | {
384 | var list = new List();
385 | int currentIdx = 0;
386 | int currentCount = 0;
387 | foreach (string word in words)
388 | {
389 | if (currentCount + word.Length + 3 > average && currentIdx < count)
390 | {
391 | list.Add(currentCount);
392 | currentIdx++;
393 | currentCount = 0;
394 | }
395 | currentCount += word.Length + 1;
396 | }
397 | if (currentIdx < count)
398 | list.Add(currentCount);
399 | else
400 | list[list.Count - 1] += currentCount;
401 | return list;
402 | }
403 |
404 | public static string AutoBreakLine(string text, int maximumLength, int mergeLinesShorterThan, string language)
405 | {
406 | if (text == null || text.Length < 3)
407 | return text;
408 |
409 | // do not autobreak dialogs
410 | if (Contains(text, '-') && text.Contains(Environment.NewLine))
411 | {
412 | var noTagLines = HtmlUtil.RemoveHtmlTags(text, true).SplitToLines();
413 | if (noTagLines.Length == 2)
414 | {
415 | var arr0 = noTagLines[0].Trim().TrimEnd('"', '\'').TrimEnd();
416 | if (arr0.StartsWith('-') && noTagLines[1].TrimStart().StartsWith('-') && arr0.Length > 1 && (Contains(".?!)]", arr0[arr0.Length - 1]) || arr0.EndsWith("--", StringComparison.Ordinal) || arr0.EndsWith('–')))
417 | return text;
418 | }
419 | }
420 |
421 | string s = RemoveLineBreaks(text);
422 | if (HtmlUtil.RemoveHtmlTags(s, true).Length < mergeLinesShorterThan)
423 | {
424 | return s;
425 | }
426 |
427 | var htmlTags = new Dictionary();
428 | var sb = new StringBuilder();
429 | int six = 0;
430 | while (six < s.Length)
431 | {
432 | var letter = s[six];
433 | bool tagFound = false;
434 | if (letter == '<')
435 | {
436 | string tagString = s.Substring(six);
437 | tagFound = tagString.StartsWith("', six + 1);
450 |
451 | if (tagFound && endIndex > 0)
452 | {
453 | string tag = s.Substring(six, endIndex - six + 1);
454 | s = s.Remove(six, tag.Length);
455 | if (htmlTags.ContainsKey(six))
456 | htmlTags[six] = htmlTags[six] + tag;
457 | else
458 | htmlTags.Add(six, tag);
459 | }
460 | else
461 | {
462 | sb.Append(letter);
463 | six++;
464 | }
465 | }
466 | s = sb.ToString();
467 |
468 | int splitPos = -1;
469 | int mid = s.Length / 2;
470 |
471 | // try to find " - " with uppercase letter after (dialog)
472 | if (s.Contains(" - "))
473 | {
474 | for (int j = 0; j <= (maximumLength / 2) + 5; j++)
475 | {
476 | if (mid + j + 4 < s.Length)
477 | {
478 | if (s[mid + j] == '-' && s[mid + j + 1] == ' ' && s[mid + j - 1] == ' ')
479 | {
480 | string rest = s.Substring(mid + j + 1).TrimStart();
481 | if (rest.Length > 0 && char.IsUpper(rest[0]))
482 | {
483 | splitPos = mid + j;
484 | break;
485 | }
486 | }
487 | }
488 | if (mid - (j + 1) > 4)
489 | {
490 | if (s[mid - j] == '-' && s[mid - j + 1] == ' ' && s[mid - j - 1] == ' ')
491 | {
492 | string rest = s.Substring(mid - j + 1).TrimStart();
493 | if (rest.Length > 0 && char.IsUpper(rest[0]))
494 | {
495 | if (mid - j > 5 && s[mid - j - 1] == ' ')
496 | {
497 | if (Contains("!?.", s[mid - j - 2]))
498 | {
499 | splitPos = mid - j;
500 | break;
501 | }
502 | var first = s.Substring(0, mid - j - 1);
503 | if (first.EndsWith(".\"", StringComparison.Ordinal) || first.EndsWith("!\"", StringComparison.Ordinal) || first.EndsWith("?\"", StringComparison.Ordinal))
504 | {
505 | splitPos = mid - j;
506 | break;
507 | }
508 | }
509 | }
510 | }
511 | }
512 | }
513 | }
514 |
515 | if (splitPos == maximumLength + 1 && s[maximumLength] != ' ') // only allow space for last char (as it does not count)
516 | splitPos = -1;
517 |
518 | if (splitPos < 0)
519 | {
520 | const string expectedChars1 = ".!?0123456789";
521 | const string expectedChars2 = ".!?";
522 | for (int j = 0; j < 15; j++)
523 | {
524 | if (mid + j + 1 < s.Length && mid + j > 0)
525 | {
526 | if (Contains(expectedChars2, s[mid + j]) && !IsPartOfNumber(s, mid + j) && CanBreak(s, mid + j + 1, language))
527 | {
528 | splitPos = mid + j + 1;
529 | if (Contains(expectedChars1, s[splitPos]))
530 | { // do not break double/tripple end lines like "!!!" or "..."
531 | splitPos++;
532 | if (Contains(expectedChars1, s[mid + j + 1]))
533 | splitPos++;
534 | }
535 | break;
536 | }
537 | if (Contains(expectedChars2, s[mid - j]) && !IsPartOfNumber(s, mid - j) && CanBreak(s, mid - j, language))
538 | {
539 | splitPos = mid - j;
540 | splitPos++;
541 | break;
542 | }
543 | }
544 | }
545 | }
546 |
547 | if (splitPos > maximumLength) // too long first line
548 | {
549 | if (splitPos != maximumLength + 1 || s[maximumLength] != ' ') // allow for maxlength+1 char to be space (does not count)
550 | splitPos = -1;
551 | }
552 | else if (splitPos >= 0 && s.Length - splitPos > maximumLength) // too long second line
553 | {
554 | splitPos = -1;
555 | }
556 |
557 | if (splitPos < 0)
558 | {
559 | const string expectedChars1 = ".!?, ";
560 | const string expectedChars2 = " .!?";
561 | const string expectedChars3 = ".!?";
562 | for (int j = 0; j < 25; j++)
563 | {
564 | if (mid + j + 1 < s.Length && mid + j > 0)
565 | {
566 | if (Contains(expectedChars1, s[mid + j]) && !IsPartOfNumber(s, mid + j) && s.Length > mid + j + 2 && CanBreak(s, mid + j, language))
567 | {
568 | splitPos = mid + j;
569 | if (Contains(expectedChars2, s[mid + j + 1]))
570 | {
571 | splitPos++;
572 | if (Contains(expectedChars2, s[mid + j + 2]))
573 | splitPos++;
574 | }
575 | break;
576 | }
577 | if (Contains(expectedChars1, s[mid - j]) && !IsPartOfNumber(s, mid - j) && s.Length > mid + j + 2 && CanBreak(s, mid - j, language))
578 | {
579 | splitPos = mid - j;
580 | if (Contains(expectedChars3, s[splitPos]))
581 | splitPos--;
582 | if (Contains(expectedChars3, s[splitPos]))
583 | splitPos--;
584 | if (Contains(expectedChars3, s[splitPos]))
585 | splitPos--;
586 | break;
587 | }
588 | }
589 | }
590 | }
591 |
592 | if (splitPos < 0)
593 | {
594 | splitPos = mid;
595 | s = s.Insert(mid - 1, Environment.NewLine);
596 | s = ReInsertHtmlTags(s, htmlTags);
597 | htmlTags = new Dictionary();
598 | s = s.Replace(Environment.NewLine, "-");
599 | }
600 | if (splitPos < s.Length - 2)
601 | s = s.Substring(0, splitPos) + Environment.NewLine + s.Substring(splitPos);
602 |
603 | s = ReInsertHtmlTags(s, htmlTags);
604 | var idx = s.IndexOf(Environment.NewLine + "", StringComparison.Ordinal);
605 | if (idx > 2)
606 | {
607 | var endIdx = s.IndexOf('>', idx + 2);
608 | if (endIdx > idx)
609 | {
610 | var tag = s.Substring(idx + Environment.NewLine.Length, endIdx - (idx + Environment.NewLine.Length) + 1);
611 | s = s.Insert(idx, tag);
612 | s = s.Remove(idx + tag.Length + Environment.NewLine.Length, tag.Length);
613 | }
614 | }
615 | s = s.Replace(" " + Environment.NewLine, Environment.NewLine);
616 | s = s.Replace(Environment.NewLine + " ", Environment.NewLine);
617 | return s.TrimEnd();
618 | }
619 |
620 | public static string RemoveLineBreaks(string s)
621 | {
622 | s = HtmlUtil.FixUpperTags(s);
623 | s = s.Replace(Environment.NewLine + "", "" + Environment.NewLine);
624 | s = s.Replace(Environment.NewLine + "", "" + Environment.NewLine);
625 | s = s.Replace(Environment.NewLine + "", "" + Environment.NewLine);
626 | s = s.Replace(Environment.NewLine + "", "" + Environment.NewLine);
627 | s = s.Replace(" " + Environment.NewLine + "", " ");
628 | s = s.Replace("" + Environment.NewLine + " ", " ");
629 | s = s.Replace("" + Environment.NewLine + "", " ");
630 | s = s.Replace(Environment.NewLine, " ");
631 | s = s.Replace(" ", " ");
632 | s = s.Replace(" ", " ");
633 | s = s.Replace(" ", " ");
634 | s = s.Replace(" ", " ");
635 | s = FixExtraSpaces(s);
636 | return s.Trim();
637 | }
638 |
639 | private static string ReInsertHtmlTags(string s, Dictionary htmlTags)
640 | {
641 | if (htmlTags.Count > 0)
642 | {
643 | var sb = new StringBuilder(s.Length);
644 | int six = 0;
645 | foreach (var letter in s)
646 | {
647 | if (Contains(Environment.NewLine, letter))
648 | {
649 | sb.Append(letter);
650 | }
651 | else
652 | {
653 | if (htmlTags.ContainsKey(six))
654 | {
655 | sb.Append(htmlTags[six]);
656 | }
657 | sb.Append(letter);
658 | six++;
659 | }
660 | }
661 | if (htmlTags.ContainsKey(six))
662 | {
663 | sb.Append(htmlTags[six]);
664 | }
665 | return sb.ToString();
666 | }
667 | return s;
668 | }
669 |
670 | private static bool IsPartOfNumber(string s, int position)
671 | {
672 | if (string.IsNullOrWhiteSpace(s) || position + 1 >= s.Length)
673 | return false;
674 |
675 | if (position > 0 && Contains(@",.", s[position]))
676 | {
677 | return char.IsDigit(s[position - 1]) && char.IsDigit(s[position + 1]);
678 | }
679 | return false;
680 | }
681 |
682 | }
683 | }
--------------------------------------------------------------------------------
/src/XmlContentTranslator/XmlContentTranslator.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 9.0.21022
7 | 2.0
8 | {79BA7CB6-5613-4527-89C3-A4FF42810390}
9 | WinExe
10 | Properties
11 | XmlContentTranslator
12 | XmlContentTranslator
13 | v4.8
14 | 512
15 | xct2.ico
16 |
17 |
18 |
19 |
20 | 3.5
21 |
22 |
23 |
24 | true
25 | full
26 | false
27 | bin\Debug\
28 | DEBUG;TRACE
29 | prompt
30 | 4
31 | false
32 |
33 |
34 | pdbonly
35 | true
36 | bin\Release\
37 | TRACE
38 | prompt
39 | 4
40 | false
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | Form
54 |
55 |
56 | Find.cs
57 |
58 |
59 |
60 | Form
61 |
62 |
63 | Main.cs
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | Find.cs
81 |
82 |
83 | Main.cs
84 | Designer
85 |
86 |
87 | ResXFileCodeGenerator
88 | Resources.Designer.cs
89 | Designer
90 |
91 |
92 | True
93 | Resources.resx
94 | True
95 |
96 |
97 |
98 | SettingsSingleFileGenerator
99 | Settings.Designer.cs
100 |
101 |
102 | True
103 | Settings.settings
104 | True
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
120 |
--------------------------------------------------------------------------------
/src/XmlContentTranslator/XmlContentTranslator.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ProjectFiles
5 |
6 |
--------------------------------------------------------------------------------
/src/XmlContentTranslator/XmlUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Xml;
6 |
7 | namespace XmlContentTranslator
8 | {
9 | public static class XmlUtils
10 | {
11 | private static readonly StringBuilder Sb = new StringBuilder();
12 |
13 | public static bool ContainsText(XmlNode node)
14 | {
15 | foreach (XmlNode childNode in node.ChildNodes)
16 | {
17 | if (childNode.NodeType == XmlNodeType.Text)
18 | {
19 | return true;
20 | }
21 | }
22 |
23 | return false;
24 | }
25 |
26 | public static bool IsTextNode(XmlNode node)
27 | {
28 | if (node.ChildNodes.Count == 1 && node.ChildNodes[0].NodeType == XmlNodeType.Text)
29 | {
30 | return true;
31 | }
32 |
33 | return ContainsText(node);
34 | }
35 |
36 | public static string BuildNodePath(XmlNode node)
37 | {
38 | Sb.Clear();
39 | Sb.Append(node.Name);
40 | if (node.NodeType == XmlNodeType.Attribute)
41 | {
42 | XmlNode old = node;
43 | node = (node as XmlAttribute).OwnerElement; // use OwnerElement for attributes as ParentNode is null
44 | Sb.Insert(0, node.Name + "@" + GetAttributeIndex(node, old));
45 | // node = node.ParentNode;
46 | }
47 | while (node.ParentNode != null)
48 | {
49 | Sb.Insert(0, node.ParentNode.Name + GetNodeIndex(node) + "/");
50 | node = node.ParentNode;
51 | }
52 | return Sb.ToString();
53 | }
54 |
55 | public static string GetAttributeIndex(XmlNode node, XmlNode child)
56 | {
57 | if (node.Attributes == null)
58 | return string.Empty;
59 |
60 | int nameCount = 0;
61 | foreach (XmlAttribute x in node.Attributes)
62 | {
63 | if (x.Name == child.Name)
64 | nameCount++;
65 | }
66 |
67 | int i = 0;
68 | foreach (XmlAttribute x in node.Attributes)
69 | {
70 | if (x == node)
71 | break;
72 | i++;
73 | }
74 | if (i == 0 || nameCount < 2)
75 | return string.Empty;
76 | return string.Format("[{0}]", i);
77 | }
78 |
79 | public static string GetNodeIndex(XmlNode node)
80 | {
81 | int i = 0;
82 | if (node.NodeType == XmlNodeType.Comment || node.NodeType == XmlNodeType.CDATA)
83 | return string.Empty;
84 |
85 | if (!string.IsNullOrEmpty(node.NamespaceURI))
86 | {
87 | var man = new XmlNamespaceManager(node.OwnerDocument.NameTable);
88 | man.AddNamespace(node.Prefix, node.NamespaceURI);
89 |
90 | foreach (var x in node.ParentNode.SelectNodes(node.Name, man))
91 | {
92 | if (x == node)
93 | break;
94 | i++;
95 | }
96 |
97 | }
98 | else if (node.NodeType != XmlNodeType.Text)
99 | {
100 | foreach (var x in node.ParentNode.SelectNodes(node.Name))
101 | {
102 | if (x == node)
103 | break;
104 | i++;
105 | }
106 | }
107 |
108 | if (i == 0)
109 | return string.Empty;
110 | return string.Format("[{0}]", i);
111 | }
112 |
113 | public static bool IsParentElement(XmlNode xnode)
114 | {
115 | return xnode.ChildNodes.Count > 0 && !IsTextNode(xnode) &&
116 | xnode.NodeType != XmlNodeType.Comment && xnode.NodeType != XmlNodeType.CDATA;
117 | }
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/src/XmlContentTranslator/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/XmlContentTranslator/file.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubtitleEdit/XmlContentTranslator/1941f23b4abfbe64956f34b6b7b1c9e9f1f1c43a/src/XmlContentTranslator/file.ico
--------------------------------------------------------------------------------
/src/XmlContentTranslator/xct.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubtitleEdit/XmlContentTranslator/1941f23b4abfbe64956f34b6b7b1c9e9f1f1c43a/src/XmlContentTranslator/xct.ico
--------------------------------------------------------------------------------
/src/XmlContentTranslator/xct2.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SubtitleEdit/XmlContentTranslator/1941f23b4abfbe64956f34b6b7b1c9e9f1f1c43a/src/XmlContentTranslator/xct2.ico
--------------------------------------------------------------------------------