From e7ec15683b7f1990d855b46b7018b3fdc0612811 Mon Sep 17 00:00:00 2001 From: mengwei Date: Thu, 2 Nov 2023 17:01:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=89=8B=E5=8A=A8=E5=90=88=E5=B9=B6gitignore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 - Program.cs | 123 +++++++++++++++++++++++++++++++++++++ Properties/AssemblyInfo.cs | 36 +++++++++++ ResxHelper.cs | 60 ++++++++++++++++++ i18n_formatter.csproj | 50 +++++++++++++++ i18n_formatter.sln | 25 ++++++++ 6 files changed, 294 insertions(+), 1 deletion(-) create mode 100644 Program.cs create mode 100644 Properties/AssemblyInfo.cs create mode 100644 ResxHelper.cs create mode 100644 i18n_formatter.csproj create mode 100644 i18n_formatter.sln diff --git a/.gitignore b/.gitignore index 61c5d57..d7d9af1 100644 --- a/.gitignore +++ b/.gitignore @@ -387,4 +387,3 @@ FodyWeavers.xsd # JetBrains Rider .idea/ *.sln.iml - diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..0ce5082 --- /dev/null +++ b/Program.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.RegularExpressions; + + +// 通过正则提取所有代码中的中文字符串 +// 将中文字符串分行写入到文件 +// 通过有道翻译进行翻译(https://fanyi.youdao.com/index.html#/),可每次复制不多于5000的内容进行翻译 +// 翻译内容保存在translation.xx.txt中,xx即语言选项 +// 通过resxhelper将中文及对应翻译写入到对应资源文件 + +namespace i18n_formatter +{ + class Program + { + static HashSet needI18n = new HashSet(); + static void Main() + { + ResxHelper.GenerateResxFileForTranslationsInCurrentDirectory(); + } + + // call this first + static void ExtractChineseStrings() + { + string directory = "samples"; + + // 遍历给定目录,提取代码文件中所有中文字符串,并保存到HashSet中 + WalkDirectory(new DirectoryInfo(directory)); + + // 将HashSet写入到json文件 + //string json = CreateJsonFromHashSet(needI18n); + + //File.WriteAllText("i18n.json", json); + string result = CreateRawTextFromHashSet(needI18n); + + File.WriteAllText("raw.text", result); + // 之后要手动进行翻译了 + // 读取翻译结果,将翻译结果写入到对应的资源文件中 + } + + static string CreateJsonFromHashSet(HashSet set) + { + string json = "["; + foreach (var item in set) + { + json += "\"" + item + "\","; + } + json = json.TrimEnd(',') + "]"; + return json; + } + + static string CreateRawTextFromHashSet(HashSet set) + { + string result = ""; + string splitter = ""; + foreach (var item in set) + { + result += splitter + item; + splitter = "\r\n"; + } + return result; + } + + static HashSet ReadHardedcodedStrings(string fileContent, string filePath) + { + HashSet result = new HashSet(); + + // Define a regular expression to match string literals + Regex stringLiteralRegex = new Regex("\"(.*?)\"", RegexOptions.Compiled); + + // Find all matches of string literals in the file content + MatchCollection matches = stringLiteralRegex.Matches(fileContent); + + Console.WriteLine(filePath); + // Display all the matched string literals + foreach (Match match in matches) + { + if (!CheckChineses(match.Groups[1].Value)) continue; + needI18n.Add(match.Groups[1].Value); + result.Add(match.Groups[1].Value); + //Console.WriteLine(match.Groups[1].Value); + } + return result; + } + + static bool CheckChineses(string sample) + { + string pattern = @"[\u4E00-\u9FFF]"; // The pattern to match Chinese characters + + // Create a Regex object with the pattern and check if there is a match + Regex regex = new Regex(pattern); + Match match = regex.Match(sample); + return match.Success; + } + + static void WalkDirectory(DirectoryInfo directory) + { + // Process files in the current directory + foreach (FileInfo file in directory.GetFiles("*.cs")) + { + if (file.Name.ToUpper().Contains(".DESIGNER.")) + continue; + string fileContent = File.ReadAllText(file.FullName); + HashSet hardcodedChineseStrings = ReadHardedcodedStrings(fileContent, file.FullName); + foreach(string hcString in hardcodedChineseStrings) + { + Console.WriteLine("replacing" + hcString); + Console.WriteLine(fileContent.Contains(hcString)); + fileContent = fileContent.Replace("\"" + hcString + "\"", "LocalizationManager.GetString(" + "\"" + hcString + "\"" + ")"); + } + File.WriteAllText("D:/DevWorkspace/i18n_formatter/bin/Debug/output/"+ file.Name, fileContent); + } + + // Recursively process subdirectories + foreach (DirectoryInfo subdirectory in directory.GetDirectories()) + { + WalkDirectory(subdirectory); + } + } + } +} + diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..ea6e971 --- /dev/null +++ b/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("i18n_formatter")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("i18n_formatter")] +[assembly: AssemblyCopyright("Copyright © 2023")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("b11eb3db-e4b1-4176-9ef1-c836707c245c")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 +//通过使用 "*",如下所示: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/ResxHelper.cs b/ResxHelper.cs new file mode 100644 index 0000000..7c73a42 --- /dev/null +++ b/ResxHelper.cs @@ -0,0 +1,60 @@ +using System; +using System.IO; +using System.Resources; + +namespace i18n_formatter +{ + class ResxHelper + { + static string rawFilePath = "raw.text"; + static string translationFileContains = "translation"; + + + // call this second + public static void GenerateResxFileForTranslationsInCurrentDirectory() + { + WalkDirectory(new DirectoryInfo(Directory.GetCurrentDirectory())); + + } + + static void WalkDirectory(DirectoryInfo directory) + { + // Process files in the current directory + foreach (FileInfo file in directory.GetFiles("*.txt")) + { + if (!file.Name.ToLower().Contains(translationFileContains)) + continue; + CreateTranslationResx(file.FullName); + } + } + + static void CreateTranslationResx(string filePath) + { + string fileContent = File.ReadAllText(filePath); + string rawContent = File.ReadAllText(rawFilePath); + string resxFileName = filePath.Replace(".txt", ".resx"); + //GenerateStringResxFile(rawContent.Split(new string[] { Environment.NewLine }, StringSplitOptions.None), fileContent.Split(new string[] { Environment.NewLine }, StringSplitOptions.None), resxFileName); + GenerateStringResxFile(rawContent.Split(new string[] { Environment.NewLine }, StringSplitOptions.None), rawContent.Split(new string[] { Environment.NewLine }, StringSplitOptions.None), "D:/DevWorkspace/i18n_formatter/bin/Debug/Resources.zh.resx"); + } + + static void GenerateStringResxFile(string[] key, string[] value, string filePath) + { + int d = key.Length; + int z = value.Length; + if (d != z) + { + Console.WriteLine("key length != value length"); + return; + } + using (ResXResourceWriter resxWriter = new ResXResourceWriter(filePath)) + { + for (int i = 0; i < d; i++) + { + resxWriter.AddResource(key[i], value[i]); + } + resxWriter.Generate(); + } + + } + } +} diff --git a/i18n_formatter.csproj b/i18n_formatter.csproj new file mode 100644 index 0000000..32f44d5 --- /dev/null +++ b/i18n_formatter.csproj @@ -0,0 +1,50 @@ + + + + + Debug + AnyCPU + {B11EB3DB-E4B1-4176-9EF1-C836707C245C} + Exe + i18n_formatter + i18n_formatter + v4.0 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/i18n_formatter.sln b/i18n_formatter.sln new file mode 100644 index 0000000..514cbe1 --- /dev/null +++ b/i18n_formatter.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.6.33815.320 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "i18n_formatter", "i18n_formatter.csproj", "{B11EB3DB-E4B1-4176-9EF1-C836707C245C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B11EB3DB-E4B1-4176-9EF1-C836707C245C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B11EB3DB-E4B1-4176-9EF1-C836707C245C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B11EB3DB-E4B1-4176-9EF1-C836707C245C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B11EB3DB-E4B1-4176-9EF1-C836707C245C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {8EE2D5A6-06D3-42AF-8FE6-393A40F3C542} + EndGlobalSection +EndGlobal