diff --git a/v2rayN/AmazTool/AmazTool.csproj b/v2rayN/AmazTool/AmazTool.csproj
index 37193d62..7982f54f 100644
--- a/v2rayN/AmazTool/AmazTool.csproj
+++ b/v2rayN/AmazTool/AmazTool.csproj
@@ -3,10 +3,17 @@
Exe
net8.0
+ true
+ true
+ win-x64
enable
enable
- Copyright © 2017-2024 (GPLv3)
- 1.3.0
+ Copyright © 2017-2024 (GPLv3)
+ 1.3.0
+
+
+
+
\ No newline at end of file
diff --git a/v2rayN/AmazTool/LocalizationHelper.cs b/v2rayN/AmazTool/LocalizationHelper.cs
index 116fe465..eb6d4fe0 100644
--- a/v2rayN/AmazTool/LocalizationHelper.cs
+++ b/v2rayN/AmazTool/LocalizationHelper.cs
@@ -1,131 +1,83 @@
-using System.Collections.Generic;
+/**
+ * 该程序使用JSON文件对C#应用程序进行本地化。
+ * 程序根据系统当前的语言加载相应的语言文件。
+ * 如果当前语言不被支持,则默认使用英语。
+ *
+ * 库:
+ * - System.Collections.Generic
+ * - System.Globalization
+ * - System.IO
+ * - System.Text.Json
+ *
+ * 用法:
+ * - 为每种支持的语言创建JSON文件(例如,en.json,zh.json)。
+ * - 将JSON文件放置程序同目录中。
+ * - 运行程序,它将根据系统当前的语言加载翻译。
+ * - 调用方式: localization.Translate("Try_Terminate_Process") //返回一个 string 字符串
+ * 示例JSON文件(en.json):
+ * {
+ * "Restart_v2rayN": "Start v2rayN, please wait...",
+ * "Guidelines": "Please run it from the main application."
+ * }
+ *
+ * 示例JSON文件(zh.json):
+ * {
+ * "Restart_v2rayN": "正在重启,请等待...",
+ * "Guidelines": "请从主应用运行!"
+ * }
+ */
+
+using System;
+using System.Collections.Generic;
using System.Globalization;
+using System.IO;
+using System.Text.Json;
-namespace AmazTool
+public class Localization
{
- public class LocalizationHelper
+ private Dictionary translations;
+
+ public Localization()
{
- ///
- /// 获取系统当前语言的本地化字符串
- ///
- /// 要翻译的关键字
- /// 对应语言的本地化字符串,如果没有找到则返回关键字
- public static string GetLocalizedValue(string key)
+ // 获取当前系统的完整文化名称 例:zh-CN en-US
+ string currentLanguage = CultureInfo.CurrentCulture.Name;
+
+ // 如果当前语言不是"zh-CN"或"en-US",默认使用英文
+ if (currentLanguage != "zh-CN" && currentLanguage != "en-US")
{
- // 定义支持的语言
- HashSet supportedLanguages = ["zh", "en"];
-
- // 获取当前系统语言的 ISO 两字母代码
- string currentLanguage = CultureInfo.CurrentCulture.TwoLetterISOLanguageName;
-
- // 如果当前语言不在支持的语言列表中,默认使用英文
- if (!supportedLanguages.Contains(currentLanguage))
- {
- currentLanguage = "en";
- }
-
- // 尝试获取对应语言的翻译
- if (languageResources.TryGetValue(key, out var translations))
- {
- if (translations.TryGetValue(currentLanguage, out var translation))
- {
- return translation;
- }
- }
-
- // 如果未找到翻译,返回关键字本身
- return key;
+ currentLanguage = "en-US";
}
- ///
- /// 存储不同语言的本地化资源
- ///
- public static Dictionary> languageResources = new()
+ // 加载相应语言的JSON文件
+ string jsonFilePath = $"{currentLanguage}.json";
+ if (!LoadTranslations(jsonFilePath))
{
- {
- "Guidelines", new Dictionary
- {
- { "en", "Please run it from the main application." },
- { "zh", "请从主应用运行!" }
- }
- },
- {
- "Upgrade_File_Not_Found", new Dictionary
- {
- { "en", "Upgrade failed, file not found." },
- { "zh", "升级失败,文件不存在!" }
- }
- },
- {
- "In_Progress", new Dictionary
- {
- { "en", "In progress, please wait..." },
- { "zh", "正在进行中,请等待..." }
- }
- },
- {
- "Try_Terminate_Process", new Dictionary
- {
- { "en", "Try to terminate the v2rayN process." },
- { "zh", "尝试结束 v2rayN 进程..." }
- }
- },
- {
- "Failed_Terminate_Process", new Dictionary
- {
- { "en", "Failed to terminate the v2rayN.Close it manually,or the upgrade may fail." },
- { "zh", "请手动关闭正在运行的v2rayN,否则可能升级失败。" }
- }
- },
- {
- "Start_Unzipping", new Dictionary
- {
- { "en", "Start extracting the update package." },
- { "zh", "开始解压缩更新包..." }
- }
- },
- {
- "Success_Unzipping", new Dictionary
- {
- { "en", "Successfully extracted the update package!" },
- { "zh", "解压缩更新包成功!" }
- }
- },
- {
- "Failed_Unzipping", new Dictionary
- {
- { "en", "Failed to extract the update package!" },
- { "zh", "解压缩更新包失败!" }
- }
- },
- {
- "Failed_Upgrade", new Dictionary
- {
- { "en", "Upgrade failed!" },
- { "zh", "升级失败!" }
- }
- },
- {
- "Success_Upgrade", new Dictionary
- {
- { "en", "Upgrade success!" },
- { "zh", "升级成功!" }
- }
- },
- {
- "Information", new Dictionary
- {
- { "en", "Information" },
- { "zh", "提示" }
- }
- },
- {
- "Restart_v2rayN", new Dictionary
- {
- { "en", "Start v2rayN, please wait..." },
- { "zh", "正在重启,请等待..." }
- }
- }
- };
+ // 如果加载失败,则使用默认语言
+ jsonFilePath = "en-US.json";
+ LoadTranslations(jsonFilePath);
+ }
+ }
+
+ private bool LoadTranslations(string jsonFilePath)
+ {
+ try
+ {
+ // 读取JSON文件内容
+ var json = File.ReadAllText(jsonFilePath);
+ // 解析JSON内容
+ translations = JsonSerializer.Deserialize>(json);
+ return true; // 成功读取和解析JSON文件
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Failed to load JSON file: {ex.Message}");
+ Environment.Exit(1);
+ return false; // 读取或解析JSON文件失败
+ }
+ }
+
+ public string Translate(string key)
+ {
+ return translations != null && translations.TryGetValue(key, out string value) ? value : key;
}
}
diff --git a/v2rayN/AmazTool/Program.cs b/v2rayN/AmazTool/Program.cs
index 74725033..a5527486 100644
--- a/v2rayN/AmazTool/Program.cs
+++ b/v2rayN/AmazTool/Program.cs
@@ -1,4 +1,34 @@
-using System;
+/**
+ * 该程序使用JSON文件对C#应用程序进行本地化。
+ * 程序根据系统当前的语言加载相应的语言文件。
+ * 如果当前语言不被支持,则默认使用英语。
+ *
+ * 库:
+ * - System
+ * - System.Threading
+ *
+ * 用法:
+ * - 为每种支持的语言创建JSON文件(例如,en.json,zh.json)。
+ * - 将JSON文件放置程序同目录中。
+ * - 运行程序,它将根据系统当前的语言加载翻译。
+ * - 调用方式: localization.Translate("Try_Terminate_Process") //返回一个 string 字符串
+ * 示例JSON文件(en.json):
+ * {
+ * "Restart_v2rayN": "Start v2rayN, please wait...",
+ * "Guidelines": "Please run it from the main application."
+ * }
+ *
+ * 示例JSON文件(zh.json):
+ * {
+ * "Restart_v2rayN": "正在重启,请等待...",
+ * "Guidelines": "请从主应用运行!"
+ * }
+ *
+ * 注意:
+ * - 确保通过NuGet安装了Newtonsoft.Json库。
+ */
+
+using System;
using System.Threading;
namespace AmazTool
@@ -11,15 +41,20 @@ namespace AmazTool
[STAThread]
private static void Main(string[] args)
{
+ var localization = new Localization();
+
if (args.Length == 0)
{
- Console.WriteLine(LocalizationHelper.GetLocalizedValue("Guidelines"));
+ // 不能直接打开更新程序
+ Console.WriteLine(localization.Translate("Guidelines"));
Thread.Sleep(5000);
return;
}
+ // 解析并拼接命令行参数以获取文件名
var fileName = Uri.UnescapeDataString(string.Join(" ", args));
+ // 调用升级方法进行文件处理
UpgradeApp.Upgrade(fileName);
}
}
-}
\ No newline at end of file
+}
diff --git a/v2rayN/AmazTool/UpgradeApp.cs b/v2rayN/AmazTool/UpgradeApp.cs
index afab6cba..8f125149 100644
--- a/v2rayN/AmazTool/UpgradeApp.cs
+++ b/v2rayN/AmazTool/UpgradeApp.cs
@@ -1,4 +1,37 @@
-using System;
+/**
+ * 该程序使用JSON文件对C#应用程序进行本地化。
+ * 程序根据系统当前的语言加载相应的语言文件。
+ * 如果当前语言不被支持,则默认使用英语。
+ *
+ * 库:
+ * - System
+ * - System.Collections.Generic
+ * - System.Globalization
+ * - System.IO
+ * - Newtonsoft.Json
+ *
+ * 用法:
+ * - 为每种支持的语言创建JSON文件(例如,en.json,zh.json)。
+ * - 将JSON文件放置程序同目录中。
+ * - 运行程序,它将根据系统当前的语言加载翻译。
+ * - 调用方式: localization.Translate("Try_Terminate_Process") //返回一个 string 字符串
+ * 示例JSON文件(en.json):
+ * {
+ * "Restart_v2rayN": "Start v2rayN, please wait...",
+ * "Guidelines": "Please run it from the main application."
+ * }
+ *
+ * 示例JSON文件(zh.json):
+ * {
+ * "Restart_v2rayN": "正在重启,请等待...",
+ * "Guidelines": "请从主应用运行!"
+ * }
+ *
+ * 注意:
+ * - 确保通过NuGet安装了Newtonsoft.Json库。
+ */
+
+using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
@@ -9,41 +42,64 @@ namespace AmazTool
{
internal class UpgradeApp
{
+ // 定义常量
+ private static readonly string V2rayN = "v2rayN";
+ private static readonly string SplitKey = "/";
+
public static void Upgrade(string fileName)
{
- Console.WriteLine(fileName);
+ var localization = new Localization();
+ Console.WriteLine(fileName);
Thread.Sleep(9000);
if (!File.Exists(fileName))
{
- Console.WriteLine(LocalizationHelper.GetLocalizedValue("Upgrade_File_Not_Found"));
+ // 如果文件不存在,输出相应的本地化信息
+ Console.WriteLine(localization.Translate("Upgrade_File_Not_Found"));
return;
}
- Console.WriteLine(LocalizationHelper.GetLocalizedValue("Try_Terminate_Process"));
+ // 尝试终止进程
+ TerminateProcess(localization);
+
+ // 解压缩更新包
+ ExtractUpdatePackage(fileName, localization);
+
+ // 重启进程
+ Console.WriteLine(localization.Translate("Restart_v2rayN"));
+ Thread.Sleep(9000);
+ RestartProcess();
+ }
+
+ private static void TerminateProcess(Localization localization)
+ {
+ Console.WriteLine(localization.Translate("Try_Terminate_Process"));
try
{
- var existing = Process.GetProcessesByName(V2rayN);
- foreach (var pp in existing)
+ var processes = Process.GetProcessesByName(V2rayN);
+ foreach (var process in processes)
{
- pp?.Kill();
- pp?.WaitForExit(1000);
+ process?.Kill();
+ process?.WaitForExit(1000);
}
}
catch (Exception ex)
{
- // Access may be denied without admin right. The user may not be an administrator.
- Console.WriteLine(LocalizationHelper.GetLocalizedValue("Failed_Terminate_Process") + ex.StackTrace);
+ // 如果无法终止进程,输出相应的本地化信息和错误堆栈
+ Console.WriteLine(localization.Translate("Failed_Terminate_Process") + ex.StackTrace);
}
+ }
+
+ private static void ExtractUpdatePackage(string fileName, Localization localization)
+ {
+ Console.WriteLine(localization.Translate("Start_Unzipping"));
+ StringBuilder errorLog = new();
- Console.WriteLine(LocalizationHelper.GetLocalizedValue("Start_Unzipping"));
- StringBuilder sb = new();
try
{
- string thisAppOldFile = $"{GetExePath()}.tmp";
- File.Delete(thisAppOldFile);
- string splitKey = "/";
+ string backupFilePath = $"{GetExePath()}.tmp";
+ File.Delete(backupFilePath);
using ZipArchive archive = ZipFile.OpenRead(fileName);
foreach (ZipArchiveEntry entry in archive.Entries)
@@ -51,22 +107,14 @@ namespace AmazTool
try
{
if (entry.Length == 0)
- {
continue;
- }
Console.WriteLine(entry.FullName);
- var lst = entry.FullName.Split(splitKey);
- if (lst.Length == 1) continue;
- string fullName = string.Join(splitKey, lst[1..lst.Length]);
+ string fullPath = GetEntryFullPath(entry.FullName);
+ BackupExistingFile(fullPath, backupFilePath);
- if (string.Equals(GetExePath(), GetPath(fullName), StringComparison.OrdinalIgnoreCase))
- {
- File.Move(GetExePath(), thisAppOldFile);
- }
-
- string entryOutputPath = GetPath(fullName);
+ string entryOutputPath = GetPath(fullPath);
Directory.CreateDirectory(Path.GetDirectoryName(entryOutputPath)!);
entry.ExtractToFile(entryOutputPath, true);
@@ -74,23 +122,39 @@ namespace AmazTool
}
catch (Exception ex)
{
- sb.Append(ex.StackTrace);
+ errorLog.Append(ex.StackTrace);
}
}
}
catch (Exception ex)
{
- Console.WriteLine(LocalizationHelper.GetLocalizedValue("Failed_Upgrade") + ex.StackTrace);
- //return;
- }
- if (sb.Length > 0)
- {
- Console.WriteLine(LocalizationHelper.GetLocalizedValue("Failed_Upgrade") + sb.ToString());
- //return;
+ // 如果解压失败,输出相应的本地化信息和错误堆栈
+ Console.WriteLine(localization.Translate("Failed_Upgrade") + ex.StackTrace);
}
- Console.WriteLine(LocalizationHelper.GetLocalizedValue("Restart_v2rayN"));
- Thread.Sleep(9000);
+ if (errorLog.Length > 0)
+ {
+ // 如果有任何错误记录,输出相应的本地化信息和错误日志
+ Console.WriteLine(localization.Translate("Failed_Upgrade") + errorLog.ToString());
+ }
+ }
+
+ private static void BackupExistingFile(string fullPath, string backupFilePath)
+ {
+ if (string.Equals(GetExePath(), fullPath, StringComparison.OrdinalIgnoreCase))
+ {
+ File.Move(GetExePath(), backupFilePath);
+ }
+ }
+
+ private static string GetEntryFullPath(string entryName)
+ {
+ var parts = entryName.Split(SplitKey);
+ return parts.Length > 1 ? string.Join(SplitKey, parts[1..]) : entryName;
+ }
+
+ private static void RestartProcess()
+ {
Process process = new()
{
StartInfo = new()
@@ -115,14 +179,7 @@ namespace AmazTool
private static string GetPath(string fileName)
{
- string startupPath = StartupPath();
- if (string.IsNullOrEmpty(fileName))
- {
- return startupPath;
- }
- return Path.Combine(startupPath, fileName);
+ return string.IsNullOrEmpty(fileName) ? StartupPath() : Path.Combine(StartupPath(), fileName);
}
-
- private static string V2rayN => "v2rayN";
}
-}
\ No newline at end of file
+}
diff --git a/v2rayN/AmazTool/en-US.json b/v2rayN/AmazTool/en-US.json
new file mode 100644
index 00000000..f4c0f600
--- /dev/null
+++ b/v2rayN/AmazTool/en-US.json
@@ -0,0 +1,14 @@
+{
+ "Restart_v2rayN": "Start v2rayN, please wait...",
+ "Guidelines": "Please run it from the main application.",
+ "Upgrade_File_Not_Found": "Upgrade failed, file not found.",
+ "In_Progress": "In progress, please wait...",
+ "Try_Terminate_Process": "Try to terminate the v2rayN process.",
+ "Failed_Terminate_Process": "Failed to terminate the v2rayN.Close it manually,or the upgrade may fail.",
+ "Start_Unzipping": "Start extracting the update package.",
+ "Success_Unzipping": "Successfully extracted the update package!",
+ "Failed_Unzipping": "Failed to extract the update package!",
+ "Failed_Upgrade": "Upgrade failed!",
+ "Success_Upgrade": "Upgrade success!",
+ "Information": "Information"
+}
\ No newline at end of file
diff --git a/v2rayN/AmazTool/zh-CN.json b/v2rayN/AmazTool/zh-CN.json
new file mode 100644
index 00000000..a6b6a1b7
--- /dev/null
+++ b/v2rayN/AmazTool/zh-CN.json
@@ -0,0 +1,14 @@
+{
+ "Restart_v2rayN": "正在重启,请等待...",
+ "Guidelines": "请从主应用运行!",
+ "Upgrade_File_Not_Found": "升级失败,文件不存在!",
+ "In_Progress": "正在进行中,请等待...",
+ "Try_Terminate_Process": "尝试结束 v2rayN 进程...",
+ "Failed_Terminate_Process": "请手动关闭正在运行的v2rayN,否则可能升级失败。",
+ "Start_Unzipping": "开始解压缩更新包...",
+ "Success_Unzipping": "解压缩更新包成功!",
+ "Failed_Unzipping": "解压缩更新包失败!",
+ "Failed_Upgrade": "升级失败!",
+ "Success_Upgrade": "升级成功!",
+ "Information": "提示"
+}
\ No newline at end of file