Skip to content

Commit 9b790ed

Browse files
author
coolbyte
committed
添加 -e 标志参数,支持是否对JSON翻译结果文件的Unicode字符编码。重构Translator类,使其变为抽象类,现在添加其它文件格式的翻译支持只需要实现这个类,然后在主方法中根据源文件格式创建这个实现类就可以了,并添加了对 Php数组定义的语言资源列表的翻译支持。使用了https的翻译接口链接。
1 parent aa21e22 commit 9b790ed

File tree

4 files changed

+269
-62
lines changed

4 files changed

+269
-62
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
using System.Text.Encodings.Web;
2+
using System.Text.Json;
3+
using System.Text.Json.Nodes;
4+
using System.Text.Unicode;
5+
6+
namespace I18nResourceTranslator;
7+
8+
public class JsonTranslator : Translator
9+
{
10+
private readonly JsonNode _rootNode;
11+
12+
public JsonTranslator(string from, string to, string content) : base(from, to, content)
13+
{
14+
_rootNode = JsonNode.Parse(content)!;
15+
}
16+
17+
private async Task EditJson(JsonNode doc)
18+
{
19+
var json = doc.AsObject();
20+
var dic = new Dictionary<string, JsonNode>();
21+
foreach (var pro in json)
22+
{
23+
switch (pro.Value)
24+
{
25+
case null:
26+
continue;
27+
case JsonObject or JsonArray:
28+
EditTasks.Add(EditJson(pro.Value));
29+
break;
30+
case JsonValue value:
31+
dic.Add(pro.Key, JsonValue.Create(await Translate(value.GetValue<string>()))!);
32+
break;
33+
}
34+
}
35+
36+
foreach (var node in dic)
37+
{
38+
json[node.Key] = node.Value;
39+
}
40+
}
41+
42+
protected override async Task DoEditAndTranslation()
43+
{
44+
await EditJson(_rootNode);
45+
}
46+
47+
protected override Task<string> GetStringResult(bool encode)
48+
{
49+
return Task.FromResult(_rootNode.ToJsonString(new JsonSerializerOptions
50+
{
51+
WriteIndented = true,
52+
Encoder = encode
53+
? null
54+
: JavaScriptEncoder.Create(UnicodeRanges.All)
55+
}));
56+
}
57+
}
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
using System.Text;
2+
3+
namespace I18nResourceTranslator;
4+
5+
/// <summary>
6+
/// php 文件内容为PHP 数组,将寻找到 => 出现的第一个字符串进行翻译
7+
/// </summary>
8+
public class PhpTranslator : Translator
9+
{
10+
private readonly IList<ToTranStrInfo> _toTranStrPosList;
11+
12+
public PhpTranslator(string from, string to, string content) : base(from, to, content)
13+
{
14+
_toTranStrPosList = new List<ToTranStrInfo>();
15+
}
16+
17+
private class ToTranStrInfo
18+
{
19+
public int Line;
20+
public int Start;
21+
public int End;
22+
public char Quote;
23+
public string LineStr = default!;
24+
25+
/// <summary>
26+
/// 要进行翻译的值
27+
/// </summary>
28+
public string Key = default!;
29+
30+
public string Transed = default!;
31+
}
32+
33+
protected override async Task DoEditAndTranslation()
34+
{
35+
_toTranStrPosList.Clear();
36+
await FindKeys();
37+
TransKeys();
38+
}
39+
40+
private void TransKeys()
41+
{
42+
foreach (var info in _toTranStrPosList)
43+
{
44+
EditTasks.Add(TransKey(info));
45+
}
46+
}
47+
48+
private async Task TransKey(ToTranStrInfo info)
49+
{
50+
info.Transed = await Translate(info.Key);
51+
}
52+
53+
private async Task FindKeys()
54+
{
55+
using var reader = new StringReader(Content);
56+
using var lineReader = new StringReader(Content);
57+
var c = -1;
58+
var equalFlag = false;
59+
var greaterFlag = false;
60+
var quoteFlag = false;
61+
var lineNumber = 0;
62+
var columnNumber = 0;
63+
var quote = '\'';
64+
var line = "";
65+
ToTranStrInfo? pos = null;
66+
while ((c = reader.Read()) > -1)
67+
{
68+
if (columnNumber == 0)
69+
{
70+
line = await lineReader.ReadLineAsync();
71+
}
72+
73+
columnNumber++;
74+
if (c == '=' && !quoteFlag)
75+
{
76+
equalFlag = true;
77+
continue;
78+
}
79+
80+
if (c == '>' && !quoteFlag && equalFlag)
81+
{
82+
greaterFlag = true;
83+
continue;
84+
}
85+
86+
if (c == '\n' && !quoteFlag)
87+
{
88+
lineNumber++;
89+
columnNumber = 0;
90+
continue;
91+
}
92+
93+
if (equalFlag && greaterFlag && c != ' ' && c != '\t' && c != '\'' && c != '"')
94+
{
95+
equalFlag = false;
96+
greaterFlag = false;
97+
continue;
98+
}
99+
100+
if (equalFlag && greaterFlag && c is '\'' or '"')
101+
{
102+
//quote start
103+
quote = (char)c;
104+
pos = new ToTranStrInfo();
105+
pos.Quote = quote;
106+
quoteFlag = true;
107+
equalFlag = false;
108+
greaterFlag = false;
109+
pos.Line = lineNumber;
110+
pos.Start = columnNumber;
111+
pos.LineStr = line!;
112+
continue;
113+
}
114+
115+
if (quoteFlag && c == quote)
116+
{
117+
//quote end
118+
quoteFlag = false;
119+
if (pos == null)
120+
{
121+
throw new InvalidOperationException("未记录到翻译信息,翻译失败。");
122+
}
123+
124+
pos.End = columnNumber;
125+
//取出不包括quote的字符串
126+
pos.Key = line!.Substring(pos.Start, pos.End - pos.Start - 1);
127+
_toTranStrPosList.Add(pos);
128+
pos = null;
129+
}
130+
}
131+
}
132+
133+
protected override Task<string> GetStringResult(bool encode)
134+
{
135+
var sb = new StringBuilder(Content);
136+
foreach (var info in _toTranStrPosList)
137+
{
138+
sb.Replace(info.Quote + info.Key + info.Quote, info.Quote + info.Transed + info.Quote);
139+
}
140+
141+
return Task.FromResult(sb.ToString());
142+
}
143+
}

I18nResourceTranslator/Program.cs

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
11
// See https://aka.ms/new-console-template for more information
22

33
using System.CommandLine;
4-
using System.Text.Json;
5-
using System.Text.Json.Nodes;
64

75
namespace I18nResourceTranslator;
86

97
public static class Program
108
{
119
public static int Main(string[] args)
1210
{
13-
var fromOption = new Option<string>(new[] {"--from", "-f"}, "谷歌语言编码,指定输入文件的语言")
11+
var fromOption = new Option<string>(new[] { "--from", "-f" }, "谷歌语言编码,指定输入文件的语言")
1412
{
1513
IsRequired = true
1614
};
17-
var toOption = new Option<string>(new[] {"--to", "-t"}, "谷歌语言编码,要翻译的目标语言")
15+
var toOption = new Option<string>(new[] { "--to", "-t" }, "谷歌语言编码,要翻译的目标语言")
1816
{
1917
IsRequired = true
2018
};
21-
var sourceOption = new Option<string>(new[] {"--source-path", "-sp"}, "源文件路径")
19+
var sourceOption = new Option<string>(new[] { "--source-path", "-sp" }, "源文件路径")
2220
{
2321
IsRequired = true,
2422
};
23+
24+
var encoderOption = new Option<bool>(new[] { "-e" }, "指定该标志,结果将转义Unicode字符,否则不转义,此标志对PHP文件无效");
25+
2526
sourceOption.AddValidator(result =>
2627
{
2728
if (!File.Exists(result.GetValueForOption(sourceOption)))
@@ -33,7 +34,8 @@ public static int Main(string[] args)
3334
{
3435
fromOption,
3536
toOption,
36-
sourceOption
37+
sourceOption,
38+
encoderOption
3739
};
3840
rootCommand.SetHandler(async (context) =>
3941
{
@@ -49,16 +51,26 @@ public static int Main(string[] args)
4951
context.ExitCode = -1;
5052
return;
5153
}
54+
55+
var fileInfo = new FileInfo(source);
56+
var ext = fileInfo.Extension;
5257
Console.WriteLine("正在翻译...");
53-
var jsonNode = JsonNode.Parse(content)!;
54-
var translator = new Translator(from, to);
55-
await translator.StartEditJsonAndTranslation(jsonNode);
56-
await File.WriteAllTextAsync($"./{to}.json", jsonNode.ToJsonString(new JsonSerializerOptions(){WriteIndented = true}));
57-
Console.WriteLine($"翻译完成,结果已经保存到:{Path.GetFullPath($"./{to}.json")}");
58+
var translator = CreateTranslator(from, to, content, ext);
59+
var rePath = $"./{fileInfo.Name}.{to}{ext}";
60+
await File.WriteAllTextAsync(rePath,
61+
await translator.GetResult(context.ParseResult.GetValueForOption(encoderOption)));
62+
Console.WriteLine($"翻译完成,结果已经保存到:{Path.GetFullPath(rePath)}");
5863
context.ExitCode = 0;
5964
});
60-
return rootCommand.InvokeAsync(args).Result;
65+
return rootCommand.InvokeAsync(args).Result;
6166
}
6267

63-
68+
private static Translator CreateTranslator(string from, string to, string content, string ext)
69+
{
70+
return ext switch
71+
{
72+
".php" => new PhpTranslator(from, to, content),
73+
_ => new JsonTranslator(from, to, content) //默认为Json格式
74+
};
75+
}
6476
}

0 commit comments

Comments
 (0)