mirror of
https://github.com/2dust/v2rayN.git
synced 2025-08-30 14:56:19 +00:00
应该完成了
This commit is contained in:
parent
936844f323
commit
bcaa4dacc2
3 changed files with 99 additions and 222 deletions
|
@ -1,71 +1,63 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
|
||||
public class Localization
|
||||
namespace AmazTool
|
||||
{
|
||||
// 使用 Lazy<T> 实现单例模式,确保 Localization 实例在需要时才会创建
|
||||
private static readonly Lazy<Localization> _instance = new(() => new Localization());
|
||||
private Dictionary<string, string> translations;
|
||||
|
||||
// 私有构造函数,防止外部实例化
|
||||
private Localization()
|
||||
public class LocalizationHelper
|
||||
{
|
||||
// 获取当前系统的完整文化名称,例如:zh-CN, en-US
|
||||
string currentLanguage = CultureInfo.CurrentCulture.Name;
|
||||
private static Dictionary<string, string> languageResources = new();
|
||||
|
||||
// 如果当前语言不是 "zh-CN" 或 "en-US",默认使用英语
|
||||
if (currentLanguage != "zh-CN" && currentLanguage != "en-US")
|
||||
static LocalizationHelper()
|
||||
{
|
||||
currentLanguage = "en-US";
|
||||
// 加载语言资源
|
||||
LoadLanguageResources();
|
||||
}
|
||||
|
||||
// 加载相应语言的 JSON 文件
|
||||
string jsonFilePath = $"{currentLanguage}.json";
|
||||
if (!LoadTranslations(jsonFilePath))
|
||||
/// <summary>
|
||||
/// 加载外部 JSON 文件中的语言资源
|
||||
/// </summary>
|
||||
private static void LoadLanguageResources()
|
||||
{
|
||||
// 如果加载失败,则使用默认语言的 JSON 文件
|
||||
jsonFilePath = "en-US.json";
|
||||
LoadTranslations(jsonFilePath);
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
string currentLanguage = CultureInfo.CurrentCulture.Name;
|
||||
if (currentLanguage != "zh-CN" && currentLanguage != "en-US")
|
||||
{
|
||||
currentLanguage = "en-US";
|
||||
}
|
||||
|
||||
// 公有静态属性用于获取单例实例
|
||||
public static Localization Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
return _instance.Value;
|
||||
}
|
||||
}
|
||||
string jsonFilePath = $"{currentLanguage}.json";
|
||||
if (!File.Exists(jsonFilePath))
|
||||
{
|
||||
jsonFilePath = "en-US.json";
|
||||
}
|
||||
|
||||
// 加载翻译文件,并将内容解析为字典
|
||||
private bool LoadTranslations(string jsonFilePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 读取 JSON 文件内容
|
||||
var json = File.ReadAllText(jsonFilePath);
|
||||
// 解析 JSON 内容并转换为字典
|
||||
translations = JsonSerializer.Deserialize<Dictionary<string, string>>(json);
|
||||
return true; // 成功读取并解析 JSON 文件
|
||||
var json = File.ReadAllText(jsonFilePath);
|
||||
if (!string.IsNullOrEmpty(json))
|
||||
{
|
||||
languageResources = JsonSerializer.Deserialize<Dictionary<string, string>>(json) ?? new Dictionary<string, string>();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Failed to load language resources: {ex.Message}");
|
||||
languageResources = []; // 初始化为空字典
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 处理读取或解析 JSON 文件时的异常
|
||||
Console.WriteLine($"Failed to load JSON file: {ex.Message}");
|
||||
Thread.Sleep(5000);
|
||||
Environment.Exit(1);
|
||||
return false; // 读取或解析 JSON 文件失败
|
||||
}
|
||||
}
|
||||
|
||||
// 根据键值返回相应的翻译,如果不存在则返回键值本身
|
||||
public string Translate(string key)
|
||||
{
|
||||
return translations != null && translations.TryGetValue(key, out string value) ? value : key;
|
||||
/// <summary>
|
||||
/// 获取系统当前语言的本地化字符串
|
||||
/// </summary>
|
||||
/// <param name="key">要翻译的关键字</param>
|
||||
/// <returns>对应语言的本地化字符串,如果没有找到则返回关键字</returns>
|
||||
public static string GetLocalizedValue(string key)
|
||||
{
|
||||
if (languageResources != null && languageResources.TryGetValue(key, out var translation))
|
||||
{
|
||||
return translation;
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,110 +1,22 @@
|
|||
/**
|
||||
* 使用JSON文件对C#应用程序进行本地化。
|
||||
* 根据系统当前的语言加载相应的语言文件。
|
||||
* 如果当前语言不被支持,则默认使用英语。
|
||||
*
|
||||
* 用法:
|
||||
* - 为每种支持的语言创建JSON文件(例如,en-US.json,zh-CN.json)。
|
||||
* - 将JSON文件放置程序同目录中。
|
||||
* - 运行程序,它将根据系统当前的语言加载翻译。
|
||||
* - 调用方式: localization.Translate("Try_Terminate_Process") //返回一个 string 字符串
|
||||
* 示例JSON文件(en-US.json):
|
||||
* {
|
||||
* "Restart_v2rayN": "Start v2rayN, please wait...",
|
||||
* "Guidelines": "Please run it from the main application."
|
||||
* }
|
||||
*
|
||||
* 示例JSON文件(zh-CN.json):
|
||||
* {
|
||||
* "Restart_v2rayN": "正在重启,请等待...",
|
||||
* "Guidelines": "请从主应用运行!"
|
||||
* }
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
|
||||
namespace AmazTool
|
||||
namespace AmazTool
|
||||
{
|
||||
public class Localization
|
||||
{
|
||||
private static readonly Lazy<Localization> _instance = new Lazy<Localization>(() => new Localization());
|
||||
private Dictionary<string, string> translations;
|
||||
|
||||
// 私有构造函数,防止外部实例化
|
||||
private Localization()
|
||||
{
|
||||
string currentLanguage = CultureInfo.CurrentCulture.Name;
|
||||
|
||||
if (currentLanguage != "zh-CN" && currentLanguage != "en-US")
|
||||
{
|
||||
currentLanguage = "en-US";
|
||||
}
|
||||
|
||||
string jsonFilePath = $"{currentLanguage}.json";
|
||||
if (!LoadTranslations(jsonFilePath))
|
||||
{
|
||||
jsonFilePath = "en-US.json";
|
||||
LoadTranslations(jsonFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
// 公有静态属性用于获取单例实例
|
||||
public static Localization Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
return _instance.Value;
|
||||
}
|
||||
}
|
||||
|
||||
private bool LoadTranslations(string jsonFilePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = File.ReadAllText(jsonFilePath);
|
||||
translations = JsonSerializer.Deserialize<Dictionary<string, string>>(json);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Failed to load JSON file: {ex.Message}");
|
||||
Thread.Sleep(5000);
|
||||
Environment.Exit(1);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public string Translate(string key)
|
||||
{
|
||||
return translations != null && translations.TryGetValue(key, out string value) ? value : key;
|
||||
}
|
||||
}
|
||||
|
||||
internal static class Program
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 应用程序的主入口点。
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
public static void Main(string[] args)
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
Localization localization = Localization.Instance;
|
||||
|
||||
if (args.Length == 0)
|
||||
{
|
||||
// 不能直接打开更新程序
|
||||
Console.WriteLine(localization.Translate("Guidelines"));
|
||||
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Guidelines"));
|
||||
Thread.Sleep(5000);
|
||||
return;
|
||||
}
|
||||
|
||||
// 解析并拼接命令行参数以获取文件名
|
||||
var fileName = Uri.UnescapeDataString(string.Join(" ", args));
|
||||
// 调用升级方法进行文件处理
|
||||
UpgradeApp.Upgrade(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,72 +1,46 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
using System.IO.Compression;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace AmazTool
|
||||
{
|
||||
internal class UpgradeApp
|
||||
{
|
||||
// 定义常量
|
||||
private static readonly string V2rayN = "v2rayN";
|
||||
private static readonly string SplitKey = "/";
|
||||
|
||||
public static void Upgrade(string fileName)
|
||||
{
|
||||
var localization = new Localization();
|
||||
|
||||
Console.WriteLine(fileName);
|
||||
Console.WriteLine($"{LocalizationHelper.GetLocalizedValue("Start_Unzipping")}\n{fileName}");
|
||||
|
||||
Thread.Sleep(9000);
|
||||
|
||||
if (!File.Exists(fileName))
|
||||
{
|
||||
// 如果文件不存在,输出相应的本地化信息
|
||||
Console.WriteLine(localization.Translate("Upgrade_File_Not_Found"));
|
||||
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Upgrade_File_Not_Found"));
|
||||
return;
|
||||
}
|
||||
|
||||
// 尝试终止进程
|
||||
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"));
|
||||
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Try_Terminate_Process"));
|
||||
try
|
||||
{
|
||||
var processes = Process.GetProcessesByName(V2rayN);
|
||||
foreach (var process in processes)
|
||||
var existing = Process.GetProcessesByName(V2rayN);
|
||||
foreach (var pp in existing)
|
||||
{
|
||||
process?.Kill();
|
||||
process?.WaitForExit(1000);
|
||||
pp?.Kill();
|
||||
pp?.WaitForExit(1000);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 如果无法终止进程,输出相应的本地化信息和错误堆栈
|
||||
Console.WriteLine(localization.Translate("Failed_Terminate_Process") + ex.StackTrace);
|
||||
// Access may be denied without admin right. The user may not be an administrator.
|
||||
Console.WriteLine(LocalizationHelper.GetLocalizedValue("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 backupFilePath = $"{GetExePath()}.tmp";
|
||||
File.Delete(backupFilePath);
|
||||
string thisAppOldFile = $"{GetExePath()}.tmp";
|
||||
File.Delete(thisAppOldFile);
|
||||
string splitKey = "/";
|
||||
|
||||
using ZipArchive archive = ZipFile.OpenRead(fileName);
|
||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||
|
@ -74,14 +48,22 @@ namespace AmazTool
|
|||
try
|
||||
{
|
||||
if (entry.Length == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Console.WriteLine(entry.FullName);
|
||||
|
||||
string fullPath = GetEntryFullPath(entry.FullName);
|
||||
BackupExistingFile(fullPath, backupFilePath);
|
||||
var lst = entry.FullName.Split(splitKey);
|
||||
if (lst.Length == 1) continue;
|
||||
string fullName = string.Join(splitKey, lst[1..lst.Length]);
|
||||
|
||||
string entryOutputPath = GetPath(fullPath);
|
||||
if (string.Equals(GetExePath(), GetPath(fullName), StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
File.Move(GetExePath(), thisAppOldFile);
|
||||
}
|
||||
|
||||
string entryOutputPath = GetPath(fullName);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(entryOutputPath)!);
|
||||
entry.ExtractToFile(entryOutputPath, true);
|
||||
|
||||
|
@ -89,39 +71,23 @@ namespace AmazTool
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
errorLog.Append(ex.StackTrace);
|
||||
sb.Append(ex.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 如果解压失败,输出相应的本地化信息和错误堆栈
|
||||
Console.WriteLine(localization.Translate("Failed_Upgrade") + ex.StackTrace);
|
||||
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Failed_Upgrade") + ex.StackTrace);
|
||||
//return;
|
||||
}
|
||||
|
||||
if (errorLog.Length > 0)
|
||||
if (sb.Length > 0)
|
||||
{
|
||||
// 如果有任何错误记录,输出相应的本地化信息和错误日志
|
||||
Console.WriteLine(localization.Translate("Failed_Upgrade") + errorLog.ToString());
|
||||
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Failed_Upgrade") + sb.ToString());
|
||||
//return;
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Restart_v2rayN"));
|
||||
Thread.Sleep(9000);
|
||||
Process process = new()
|
||||
{
|
||||
StartInfo = new()
|
||||
|
@ -146,7 +112,14 @@ namespace AmazTool
|
|||
|
||||
private static string GetPath(string fileName)
|
||||
{
|
||||
return string.IsNullOrEmpty(fileName) ? StartupPath() : Path.Combine(StartupPath(), fileName);
|
||||
string startupPath = StartupPath();
|
||||
if (string.IsNullOrEmpty(fileName))
|
||||
{
|
||||
return startupPath;
|
||||
}
|
||||
return Path.Combine(startupPath, fileName);
|
||||
}
|
||||
|
||||
private static string V2rayN => "v2rayN";
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue