Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22eb993ebf | ||
|
|
b5e1a297ae | ||
|
|
499a16feae | ||
|
|
1866a59d12 | ||
|
|
10513e0f3b | ||
|
|
2e32de2fbb | ||
|
|
30a838df77 |
@@ -8,5 +8,10 @@
|
||||
<Copyright>Copyright © 2017-2024 (GPLv3)</Copyright>
|
||||
<FileVersion>1.3.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Assets\en-US.json" />
|
||||
<EmbeddedResource Include="Assets\zh-CN.json" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
14
v2rayN/AmazTool/Assets/en-US.json
Normal file
14
v2rayN/AmazTool/Assets/en-US.json
Normal file
@@ -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"
|
||||
}
|
||||
14
v2rayN/AmazTool/Assets/zh-CN.json
Normal file
14
v2rayN/AmazTool/Assets/zh-CN.json
Normal file
@@ -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": "提示"
|
||||
}
|
||||
@@ -1,131 +1,59 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace AmazTool
|
||||
{
|
||||
public class LocalizationHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取系统当前语言的本地化字符串
|
||||
/// </summary>
|
||||
/// <param name="key">要翻译的关键字</param>
|
||||
/// <returns>对应语言的本地化字符串,如果没有找到则返回关键字</returns>
|
||||
public static string GetLocalizedValue(string key)
|
||||
private static Dictionary<string, string> _languageResources = [];
|
||||
|
||||
static LocalizationHelper()
|
||||
{
|
||||
// 定义支持的语言
|
||||
HashSet<string> 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;
|
||||
// 加载语言资源
|
||||
LoadLanguageResources();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 存储不同语言的本地化资源
|
||||
/// </summary>
|
||||
public static Dictionary<string, Dictionary<string, string>> languageResources = new()
|
||||
private static void LoadLanguageResources()
|
||||
{
|
||||
try
|
||||
{
|
||||
"Guidelines", new Dictionary<string, string>
|
||||
var currentLanguage = CultureInfo.CurrentCulture.Name;
|
||||
if (currentLanguage != "zh-CN" && currentLanguage != "en-US")
|
||||
{
|
||||
{ "en", "Please run it from the main application." },
|
||||
{ "zh", "请从主应用运行!" }
|
||||
currentLanguage = "en-US";
|
||||
}
|
||||
},
|
||||
{
|
||||
"Upgrade_File_Not_Found", new Dictionary<string, string>
|
||||
|
||||
var resourceName = $"AmazTool.Assets.{currentLanguage}.json";
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
|
||||
using var stream = assembly.GetManifestResourceStream(resourceName);
|
||||
if (stream == null) return;
|
||||
|
||||
using StreamReader reader = new(stream);
|
||||
var json = reader.ReadToEnd();
|
||||
if (!string.IsNullOrEmpty(json))
|
||||
{
|
||||
{ "en", "Upgrade failed, file not found." },
|
||||
{ "zh", "升级失败,文件不存在!" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"In_Progress", new Dictionary<string, string>
|
||||
{
|
||||
{ "en", "In progress, please wait..." },
|
||||
{ "zh", "正在进行中,请等待..." }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Try_Terminate_Process", new Dictionary<string, string>
|
||||
{
|
||||
{ "en", "Try to terminate the v2rayN process." },
|
||||
{ "zh", "尝试结束 v2rayN 进程..." }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Failed_Terminate_Process", new Dictionary<string, string>
|
||||
{
|
||||
{ "en", "Failed to terminate the v2rayN.Close it manually,or the upgrade may fail." },
|
||||
{ "zh", "请手动关闭正在运行的v2rayN,否则可能升级失败。" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Start_Unzipping", new Dictionary<string, string>
|
||||
{
|
||||
{ "en", "Start extracting the update package." },
|
||||
{ "zh", "开始解压缩更新包..." }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Success_Unzipping", new Dictionary<string, string>
|
||||
{
|
||||
{ "en", "Successfully extracted the update package!" },
|
||||
{ "zh", "解压缩更新包成功!" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Failed_Unzipping", new Dictionary<string, string>
|
||||
{
|
||||
{ "en", "Failed to extract the update package!" },
|
||||
{ "zh", "解压缩更新包失败!" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Failed_Upgrade", new Dictionary<string, string>
|
||||
{
|
||||
{ "en", "Upgrade failed!" },
|
||||
{ "zh", "升级失败!" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Success_Upgrade", new Dictionary<string, string>
|
||||
{
|
||||
{ "en", "Upgrade success!" },
|
||||
{ "zh", "升级成功!" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Information", new Dictionary<string, string>
|
||||
{
|
||||
{ "en", "Information" },
|
||||
{ "zh", "提示" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"Restart_v2rayN", new Dictionary<string, string>
|
||||
{
|
||||
{ "en", "Start v2rayN, please wait..." },
|
||||
{ "zh", "正在重启,请等待..." }
|
||||
_languageResources = JsonSerializer.Deserialize<Dictionary<string, string>>(json) ?? new Dictionary<string, string>();
|
||||
}
|
||||
}
|
||||
};
|
||||
catch (IOException ex)
|
||||
{
|
||||
Console.WriteLine($"Failed to read language resource file: {ex.Message}");
|
||||
}
|
||||
catch (JsonException ex)
|
||||
{
|
||||
Console.WriteLine($"Failed to parse JSON data: {ex.Message}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Unexpected error occurred: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetLocalizedValue(string key)
|
||||
{
|
||||
return _languageResources.TryGetValue(key, out var translation) ? translation : key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace AmazTool
|
||||
namespace AmazTool
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
using System.IO.Compression;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace AmazTool
|
||||
{
|
||||
@@ -11,8 +8,8 @@ namespace AmazTool
|
||||
{
|
||||
public static void Upgrade(string fileName)
|
||||
{
|
||||
Console.WriteLine(fileName);
|
||||
|
||||
Console.WriteLine($"{LocalizationHelper.GetLocalizedValue("Start_Unzipping")}\n{fileName}");
|
||||
|
||||
Thread.Sleep(9000);
|
||||
|
||||
if (!File.Exists(fileName))
|
||||
|
||||
@@ -259,7 +259,7 @@ namespace ServiceLib.Handler
|
||||
return _config.TunModeItem.EnableTun
|
||||
&& eCoreType == ECoreType.sing_box
|
||||
&& Utils.IsLinux()
|
||||
&& _config.TunModeItem.LinuxSudoPwd.IsNotEmpty()
|
||||
//&& _config.TunModeItem.LinuxSudoPwd.IsNotEmpty()
|
||||
;
|
||||
}
|
||||
|
||||
@@ -275,7 +275,6 @@ namespace ServiceLib.Handler
|
||||
return null;
|
||||
}
|
||||
|
||||
var isNeedSudo = mayNeedSudo && IsNeedSudo(coreInfo.CoreType);
|
||||
try
|
||||
{
|
||||
Process proc = new()
|
||||
@@ -294,14 +293,10 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
};
|
||||
|
||||
var isNeedSudo = mayNeedSudo && IsNeedSudo(coreInfo.CoreType);
|
||||
if (isNeedSudo)
|
||||
{
|
||||
proc.StartInfo.FileName = $"/bin/sudo";
|
||||
proc.StartInfo.Arguments = $"-S {fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetConfigPath(configPath).AppendQuotes())}";
|
||||
proc.StartInfo.WorkingDirectory = null;
|
||||
proc.StartInfo.StandardInputEncoding = Encoding.UTF8;
|
||||
proc.StartInfo.RedirectStandardInput = true;
|
||||
Logging.SaveLog(proc.StartInfo.Arguments);
|
||||
await RunProcessAsLinuxRoot(proc, fileName, coreInfo, configPath);
|
||||
}
|
||||
|
||||
var startUpErrorMessage = new StringBuilder();
|
||||
@@ -326,7 +321,7 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
proc.Start();
|
||||
|
||||
if (isNeedSudo)
|
||||
if (isNeedSudo && _config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
|
||||
{
|
||||
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
|
||||
await Task.Delay(10);
|
||||
@@ -362,6 +357,37 @@ namespace ServiceLib.Handler
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RunProcessAsLinuxRoot(Process proc, string fileName, CoreInfo coreInfo, string configPath)
|
||||
{
|
||||
var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetConfigPath(configPath).AppendQuotes())}";
|
||||
|
||||
//Prefer shell scripts
|
||||
var shFilePath = Utils.GetBinPath("run_as_root.sh");
|
||||
File.Delete(shFilePath);
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine("#!/bin/sh");
|
||||
sb.AppendLine(cmdLine);
|
||||
await File.WriteAllTextAsync(shFilePath, sb.ToString());
|
||||
await Utils.SetLinuxChmod(shFilePath);
|
||||
|
||||
//Replace command
|
||||
var args = File.Exists(shFilePath) ? shFilePath : cmdLine;
|
||||
if (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
|
||||
{
|
||||
proc.StartInfo.FileName = $"/bin/sudo";
|
||||
proc.StartInfo.Arguments = $"-S {args}";
|
||||
}
|
||||
else
|
||||
{
|
||||
proc.StartInfo.FileName = $"/bin/pkexec";
|
||||
proc.StartInfo.Arguments = $"{args}";
|
||||
}
|
||||
proc.StartInfo.WorkingDirectory = null;
|
||||
proc.StartInfo.StandardInputEncoding = Encoding.UTF8;
|
||||
proc.StartInfo.RedirectStandardInput = true;
|
||||
Logging.SaveLog(proc.StartInfo.Arguments);
|
||||
}
|
||||
|
||||
private async Task KillProcess(Process? proc)
|
||||
{
|
||||
if (proc is null)
|
||||
|
||||
@@ -1370,7 +1370,7 @@
|
||||
<value>Linux系统的sudo密码</value>
|
||||
</data>
|
||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||
<value>密码已加密且只存储在本地文件中,无密码无法开启Tun</value>
|
||||
<value>密码已加密且只存储在本地文件中,无密码则每次都要输入</value>
|
||||
</data>
|
||||
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
||||
<value>请先在Tun模式设置中设置sudo密码</value>
|
||||
|
||||
@@ -1370,7 +1370,7 @@
|
||||
<value>Linux系統的sudo密碼</value>
|
||||
</data>
|
||||
<data name="TbSettingsLinuxSudoPasswordTip" xml:space="preserve">
|
||||
<value>密碼已加密且只儲存在本機檔案中,無密碼無法開啟Tun</value>
|
||||
<value>密碼已加密且只儲存在本機檔案中,無密碼則每次都要輸入</value>
|
||||
</data>
|
||||
<data name="TbSettingsLinuxSudoPasswordIsEmpty" xml:space="preserve">
|
||||
<value>請先在Tun模式設定中設定sudo密碼</value>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>7.1.2</Version>
|
||||
<Version>7.1.3</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -729,7 +729,7 @@ namespace ServiceLib.ViewModels
|
||||
{
|
||||
return;
|
||||
}
|
||||
var result = await CoreConfigHandler.GenerateClientConfig(item, null);
|
||||
var result = await CoreConfigHandler.GenerateClientConfig(item, fileName);
|
||||
if (result.Success != true)
|
||||
{
|
||||
NoticeHandler.Instance.Enqueue(result.Msg);
|
||||
|
||||
@@ -416,16 +416,16 @@ namespace ServiceLib.ViewModels
|
||||
// When running as a non-administrator, reboot to administrator mode
|
||||
if (EnableTun && AllowEnableTun() == false)
|
||||
{
|
||||
_config.TunModeItem.EnableTun = false;
|
||||
if (Utils.IsWindows())
|
||||
{
|
||||
_config.TunModeItem.EnableTun = false;
|
||||
Locator.Current.GetService<MainWindowViewModel>()?.RebootAsAdmin();
|
||||
return;
|
||||
}
|
||||
else if (Utils.IsLinux())
|
||||
{
|
||||
NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordIsEmpty);
|
||||
}
|
||||
return;
|
||||
//else if (Utils.IsLinux())
|
||||
//{
|
||||
// NoticeHandler.Instance.SendMessageAndEnqueue(ResUI.TbSettingsLinuxSudoPasswordIsEmpty);
|
||||
//}
|
||||
}
|
||||
await ConfigHandler.SaveConfig(_config);
|
||||
Locator.Current.GetService<MainWindowViewModel>()?.Reload();
|
||||
|
||||
@@ -356,7 +356,7 @@ namespace v2rayN.Desktop.Views
|
||||
item2.Width = new DataGridLength(item.Width, DataGridLengthUnitType.Pixel);
|
||||
item2.DisplayIndex = displayIndex++;
|
||||
}
|
||||
if (item.Name.StartsWith("to"))
|
||||
if (item.Name.ToLower().StartsWith("to"))
|
||||
{
|
||||
if (!_config.GuiItem.EnableStatistics)
|
||||
{
|
||||
|
||||
@@ -338,7 +338,7 @@ namespace v2rayN.Views
|
||||
item2.Width = item.Width;
|
||||
item2.DisplayIndex = displayIndex++;
|
||||
}
|
||||
if (item.Name.StartsWith("to"))
|
||||
if (item.Name.ToLower().StartsWith("to"))
|
||||
{
|
||||
if (!_config.GuiItem.EnableStatistics)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user