From 4564e21ca8fd7488d07cdc83682082159a6975de Mon Sep 17 00:00:00 2001 From: XTsat <44708609+XTsat@users.noreply.github.com> Date: Mon, 29 Dec 2025 15:42:38 +0800 Subject: [PATCH 1/9] NuGet --- CompactGUI/CompactGUI.vbproj | 1 + 1 file changed, 1 insertion(+) diff --git a/CompactGUI/CompactGUI.vbproj b/CompactGUI/CompactGUI.vbproj index babeb9f..d069f3f 100644 --- a/CompactGUI/CompactGUI.vbproj +++ b/CompactGUI/CompactGUI.vbproj @@ -46,6 +46,7 @@ + From f30d368fa68e4272efa2be39261a974c2d1959bc Mon Sep 17 00:00:00 2001 From: XTsat <44708609+XTsat@users.noreply.github.com> Date: Tue, 30 Dec 2025 00:15:15 +0800 Subject: [PATCH 2/9] i18n support --- CompactGUI/Application.xaml.vb | 6 +- CompactGUI/CompactGUI.vbproj | 17 +- .../Components/Converters/IValueConverters.vb | 16 +- CompactGUI/LanguageHelper.vb | 181 ++++ .../Components/CompressionMode_Radio.xaml | 10 +- .../Views/Components/FolderWatcherCard.xaml | 24 +- .../Components/FolderWatcherCard.xaml.vb | 5 +- CompactGUI/Views/Pages/DatabasePage.xaml | 231 +++-- CompactGUI/Views/Pages/FolderView.xaml | 6 +- CompactGUI/Views/Pages/HomePage.xaml | 12 +- .../Views/Pages/PendingCompression.xaml | 50 +- CompactGUI/Views/Pages/ResultsTemplate.xaml | 24 +- CompactGUI/Views/Pages/WatcherPage.xaml | 5 +- CompactGUI/Views/SettingsPage.xaml | 106 ++- CompactGUI/Views/SettingsPage.xaml.vb | 57 +- CompactGUI/i18n/i18n.Designer.vb | 845 ++++++++++++++++++ CompactGUI/i18n/i18n.resx | 388 ++++++++ CompactGUI/i18n/i18n.zh-CN.resx | 367 ++++++++ ResXManager.config.xml | 4 + 19 files changed, 2123 insertions(+), 231 deletions(-) create mode 100644 CompactGUI/LanguageHelper.vb create mode 100644 CompactGUI/i18n/i18n.Designer.vb create mode 100644 CompactGUI/i18n/i18n.resx create mode 100644 CompactGUI/i18n/i18n.zh-CN.resx create mode 100644 ResXManager.config.xml diff --git a/CompactGUI/Application.xaml.vb b/CompactGUI/Application.xaml.vb index 9c46d71..e5c360c 100644 --- a/CompactGUI/Application.xaml.vb +++ b/CompactGUI/Application.xaml.vb @@ -1,4 +1,4 @@ -Imports System.IO +Imports System.IO Imports System.IO.Pipes Imports System.Threading Imports System.Windows.Threading @@ -31,7 +31,11 @@ Partial Public Class Application End Sub + Private Sub Application_Startup(sender As Object, e As StartupEventArgs) Handles Me.Startup + ' 启动时调用语言配置 + LanguageHelper.Initialize() + End Sub Private Shared Sub InitializeHost() _host = Host.CreateDefaultBuilder() _ diff --git a/CompactGUI/CompactGUI.vbproj b/CompactGUI/CompactGUI.vbproj index d069f3f..038ce5a 100644 --- a/CompactGUI/CompactGUI.vbproj +++ b/CompactGUI/CompactGUI.vbproj @@ -29,7 +29,6 @@ none - @@ -72,6 +71,22 @@ + + + True + True + i18n.resx + + + + + + i18n + PublicResXFileCodeGenerator + i18n.Designer.vb + + + diff --git a/CompactGUI/Components/Converters/IValueConverters.vb b/CompactGUI/Components/Converters/IValueConverters.vb index eef23bb..882398f 100644 --- a/CompactGUI/Components/Converters/IValueConverters.vb +++ b/CompactGUI/Components/Converters/IValueConverters.vb @@ -1,4 +1,4 @@ -Imports System.Globalization +Imports System.Globalization Public Class DecimalToPercentageConverter : Implements IValueConverter Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert @@ -88,20 +88,24 @@ End Class Public Class RelativeDateConverter : Implements IValueConverter Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert + If value Is Nothing Or Not TypeOf value Is DateTime Then + Return LanguageHelper.GetString("RelativeTimeUnknown") + End If + Dim dt = CType(value, DateTime) Dim ts As TimeSpan = DateTime.Now - dt If ts > TimeSpan.FromDays(19000) Then - Return String.Format("Unknown") + Return LanguageHelper.GetString("RelativeTimeUnknown") End If If ts > TimeSpan.FromDays(2) Then - Return String.Format("{0:0} days ago", ts.TotalDays) + Return String.Format(LanguageHelper.GetString("RelativeTimeDaysAgo"), ts.TotalDays) ElseIf ts > TimeSpan.FromHours(2) Then - Return String.Format("{0:0} hours ago", ts.TotalHours) + Return String.Format(LanguageHelper.GetString("RelativeTimeHoursAgo"), ts.TotalHours) ElseIf ts > TimeSpan.FromMinutes(2) Then - Return String.Format("{0:0} minutes ago", ts.TotalMinutes) + Return String.Format(LanguageHelper.GetString("RelativeTimeMinutesAgo"), ts.TotalMinutes) Else - Return "just now" + Return LanguageHelper.GetString("RelativeTimeJustNow") End If End Function diff --git a/CompactGUI/LanguageHelper.vb b/CompactGUI/LanguageHelper.vb new file mode 100644 index 0000000..7c90020 --- /dev/null +++ b/CompactGUI/LanguageHelper.vb @@ -0,0 +1,181 @@ +Imports System.Globalization +Imports System.Resources +Imports System.Threading +Imports System.Windows.Markup +Imports System.Windows.Data +Imports System.Reflection + +Public Class LanguageHelper + ' 支持的语言列表 + Private Shared ReadOnly SupportedCultures As String() = {"en-US", "zh-CN"} + Private Shared resourceManager As ResourceManager = i18n.i18n.ResourceManager + Private Shared currentCulture As CultureInfo = Nothing + + Public Shared Function GetText(key As String) As String + Return GetString(key) + End Function + + Public Shared Sub Initialize() + Dim savedLanguage As String = ReadAppConfig("language") + If Not String.IsNullOrEmpty(savedLanguage) AndAlso SupportedCultures.Contains(savedLanguage) Then + ApplyCulture(savedLanguage) + Else + SetDefaultLanguage() + End If + End Sub + + Public Shared Sub ChangeLanguage() + If currentCulture Is Nothing Then + currentCulture = Thread.CurrentThread.CurrentUICulture + End If + Dim currentLang As String = currentCulture.Name + Dim nextLang As String = GetNextLanguage(currentLang) + + ApplyCulture(nextLang) + WriteAppConfig("language", nextLang) + End Sub + + Public Shared Function GetString(key As String, ParamArray args As Object()) As String + Try + Dim cultureToUse = If(currentCulture, Thread.CurrentThread.CurrentUICulture) + Dim rawValue As String = resourceManager.GetString(key, cultureToUse) + + If String.IsNullOrEmpty(rawValue) Then + Return key + ElseIf args IsNot Nothing AndAlso args.Length > 0 Then + Return String.Format(cultureToUse, rawValue, args) + Else + Return rawValue + End If + Catch ex As Exception + Debug.WriteLine($"获取多语言文本失败:{key},错误:{ex.Message}") + Return key + End Try + End Function + + Public Shared Sub ApplyCulture(cultureName As String) + Try + Dim culture As New CultureInfo(cultureName) + Thread.CurrentThread.CurrentUICulture = culture + Thread.CurrentThread.CurrentCulture = culture + currentCulture = culture + + ' 额外:如果是WPF/WinForms,刷新界面(可选) + ' WinForms示例:Application.CurrentCulture = culture + ' WPF示例:FrameworkElement.LanguageProperty.OverrideMetadata(GetType(FrameworkElement), New FrameworkPropertyMetadata(XmlLanguage.GetLanguage(culture.IetfLanguageTag))) + Catch ex As Exception + Debug.WriteLine($"应用语言失败:{cultureName},错误:{ex.Message}") + SetDefaultLanguage() + End Try + End Sub + + Private Shared Function GetNextLanguage(currentLanguage As String) As String + Dim currentTwoLetter = New CultureInfo(currentLanguage).TwoLetterISOLanguageName + For i As Integer = 0 To SupportedCultures.Length - 1 + Dim langTwoLetter = New CultureInfo(SupportedCultures(i)).TwoLetterISOLanguageName + If langTwoLetter = currentTwoLetter Then + Return SupportedCultures((i + 1) Mod SupportedCultures.Length) + End If + Next + Return SupportedCultures(0) + End Function + + Private Shared Sub SetDefaultLanguage() + ' 根据系统语言设置默认语言 + Dim langMapping As New Dictionary(Of String, String) From { + {"en", "en-US"}, + {"zh", "zh-CN"} + } + '{"ja", "ja-JP"}, + '{"ko", "ko-KR"}, + '{"fr", "fr-FR"}, + '{"de", "de-DE"}, + '{"es", "es-ES"}, + '{"ru", "ru-RU"} + + Dim systemLang As String = Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName.ToLower() + Dim defaultLang As String = If(langMapping.ContainsKey(systemLang), langMapping(systemLang), "en-US") + + ' 特殊处理中文简/繁 + 'If systemLang = "zh" Then + ' If Thread.CurrentThread.CurrentUICulture.Name.StartsWith("zh-TW") Then + ' defaultLang = "zh-TW" + ' ElseIf Thread.CurrentThread.CurrentUICulture.Name.StartsWith("zh-HK") Then + ' defaultLang = "zh-HK" + ' End If + 'End If + + '@@@ + 'Dim systemLang = Thread.CurrentThread.CurrentUICulture.TwoLetterISOLanguageName + 'Dim defaultLang As String = "en-US" + + ''匹配多语言 + 'Select Case systemLang.ToLower() + ' Case "zh" ' 中文 + ' defaultLang = "zh-CN" + ' Case "en" ' 英文 + ' defaultLang = "en-US" + ' Case "ja" ' 日语 + ' defaultLang = "ja-JP" + ' Case "ko" ' 韩语 + ' defaultLang = "ko-KR" + ' Case "fr" ' 法语 + ' defaultLang = "fr-FR" + ' Case "de" ' 德语 + ' defaultLang = "de-DE" + ' Case "es" ' 西班牙语 + ' defaultLang = "es-ES" + ' Case "ru" ' 俄语 + ' defaultLang = "ru-RU" + ' Case Else ' 未匹配语言,默认英文 + ' defaultLang = "en-US" + 'End Select + + ApplyCulture(defaultLang) + WriteAppConfig("language", defaultLang) + End Sub + + Public Shared Function GetCurrentLanguage() As String + Return If(currentCulture, Thread.CurrentThread.CurrentUICulture).Name + End Function + + Public Shared Function ReadAppConfig(key As String) As String + Try + Dim config = System.Configuration.ConfigurationManager.OpenExeConfiguration(System.Configuration.ConfigurationUserLevel.None) + Return If(config.AppSettings.Settings(key)?.Value, String.Empty) + Catch ex As Exception + Debug.WriteLine($"读取配置失败:{key},错误:{ex.Message}") + Return String.Empty + End Try + End Function + + Public Shared Sub WriteAppConfig(key As String, value As String) + Try + Dim config = System.Configuration.ConfigurationManager.OpenExeConfiguration(System.Configuration.ConfigurationUserLevel.None) + If config.AppSettings.Settings(key) IsNot Nothing Then + config.AppSettings.Settings(key).Value = value + Else + config.AppSettings.Settings.Add(key, value) + End If + config.Save(System.Configuration.ConfigurationSaveMode.Modified) + System.Configuration.ConfigurationManager.RefreshSection("appSettings") + Catch ex As Exception + Debug.WriteLine($"写入配置失败:{key},错误:{ex.Message}") + End Try + End Sub +End Class + + +Public Class LocalizeExtension + Inherits MarkupExtension + + Private _key As String + + Public Sub New(key As String) + _key = key + End Sub + + Public Overrides Function ProvideValue(serviceProvider As IServiceProvider) As Object + Return LanguageHelper.GetString(_key) + End Function +End Class \ No newline at end of file diff --git a/CompactGUI/Views/Components/CompressionMode_Radio.xaml b/CompactGUI/Views/Components/CompressionMode_Radio.xaml index 9cbb4ea..a4d813f 100644 --- a/CompactGUI/Views/Components/CompressionMode_Radio.xaml +++ b/CompactGUI/Views/Components/CompressionMode_Radio.xaml @@ -1,4 +1,4 @@ - - diff --git a/CompactGUI/Views/Components/FolderWatcherCard.xaml b/CompactGUI/Views/Components/FolderWatcherCard.xaml index 287c234..0944e2d 100644 --- a/CompactGUI/Views/Components/FolderWatcherCard.xaml +++ b/CompactGUI/Views/Components/FolderWatcherCard.xaml @@ -1,4 +1,4 @@ - - - + - + + + + + + + + - diff --git a/CompactGUI/Views/SettingsPage.xaml b/CompactGUI/Views/SettingsPage.xaml index 07d2186..436b15a 100644 --- a/CompactGUI/Views/SettingsPage.xaml +++ b/CompactGUI/Views/SettingsPage.xaml @@ -439,6 +439,7 @@ + diff --git a/CompactGUI/i18n/i18n.Designer.vb b/CompactGUI/i18n/i18n.Designer.vb index 5ca7645..55f083f 100644 --- a/CompactGUI/i18n/i18n.Designer.vb +++ b/CompactGUI/i18n/i18n.Designer.vb @@ -91,6 +91,15 @@ Namespace i18n End Get End Property + ''' + ''' 查找类似 Last Fetched: {0:dd MMM yyyy HH:mm:ss} 的本地化字符串。 + ''' + Public Shared ReadOnly Property DatabaseLastFetched() As String + Get + Return ResourceManager.GetString("DatabaseLastFetched", resourceCulture) + End Get + End Property + ''' ''' 查找类似 Ascending 的本地化字符串。 ''' @@ -289,6 +298,15 @@ Namespace i18n End Get End Property + ''' + ''' 查找类似 select a folder 的本地化字符串。 + ''' + Public Shared ReadOnly Property HomePageSelectFolder() As String + Get + Return ResourceManager.GetString("HomePageSelectFolder", resourceCulture) + End Get + End Property + ''' ''' 查找类似 Working 的本地化字符串。 ''' @@ -307,6 +325,33 @@ Namespace i18n End Get End Property + ''' + ''' 查找类似 Compression DB 的本地化字符串。 + ''' + Public Shared ReadOnly Property NameMainWindowCompressionDB() As String + Get + Return ResourceManager.GetString("NameMainWindowCompressionDB", resourceCulture) + End Get + End Property + + ''' + ''' 查找类似 Home 的本地化字符串。 + ''' + Public Shared ReadOnly Property NameMainWindowHome() As String + Get + Return ResourceManager.GetString("NameMainWindowHome", resourceCulture) + End Get + End Property + + ''' + ''' 查找类似 Watcher 的本地化字符串。 + ''' + Public Shared ReadOnly Property NameMainWindowWatcher() As String + Get + Return ResourceManager.GetString("NameMainWindowWatcher", resourceCulture) + End Get + End Property + ''' ''' 查找类似 Database Results 的本地化字符串。 ''' @@ -898,6 +943,24 @@ Namespace i18n End Get End Property + ''' + ''' 查找类似 CompactGUI 的本地化字符串。 + ''' + Public Shared ReadOnly Property TitleCompactGUI() As String + Get + Return ResourceManager.GetString("TitleCompactGUI", resourceCulture) + End Get + End Property + + ''' + ''' 查找类似 Admin 的本地化字符串。 + ''' + Public Shared ReadOnly Property UniAdmin() As String + Get + Return ResourceManager.GetString("UniAdmin", resourceCulture) + End Get + End Property + ''' ''' 查找类似 edit 的本地化字符串。 ''' diff --git a/CompactGUI/i18n/i18n.resx b/CompactGUI/i18n/i18n.resx index fc62b80..18176f9 100644 --- a/CompactGUI/i18n/i18n.resx +++ b/CompactGUI/i18n/i18n.resx @@ -414,4 +414,25 @@ skips files based on compression estimate Next scheduled: {0:dd MMM yyyy \a\t HH:mm:ss} + + CompactGUI + + + select a folder + + + Admin + + + Compression DB + + + Watcher + + + Home + + + Last Fetched: {0:dd MMM yyyy HH:mm:ss} + \ No newline at end of file diff --git a/CompactGUI/i18n/i18n.zh-CN.resx b/CompactGUI/i18n/i18n.zh-CN.resx index eef09aa..d1dab4b 100644 --- a/CompactGUI/i18n/i18n.zh-CN.resx +++ b/CompactGUI/i18n/i18n.zh-CN.resx @@ -396,4 +396,25 @@ + + 管理员权限 + + + 选择文件夹 + + + CompactGUI + + + 压缩数据库 + + + 监控 + + + 主页 + + + 最后获取: {0:yyyy年 M月 d日 HH:mm:ss} + \ No newline at end of file From aa49e47f329b808dfb17a3d2bcaef93c3fc4b6ac Mon Sep 17 00:00:00 2001 From: XTsat <44708609+XTsat@users.noreply.github.com> Date: Thu, 1 Jan 2026 15:20:44 +0800 Subject: [PATCH 6/9] Optimize key value --- .gitignore | 1 + .../Components/Converters/IValueConverters.vb | 10 +- .../Settings/Settings_skiplistflyout.xaml | 2 +- CompactGUI/MainWindow.xaml | 8 +- .../Components/CompressionMode_Radio.xaml | 6 +- .../Views/Components/FolderWatcherCard.xaml | 10 +- CompactGUI/Views/Pages/DatabasePage.xaml | 38 +- CompactGUI/Views/Pages/FolderView.xaml | 4 +- CompactGUI/Views/Pages/HomePage.xaml | 12 +- .../Views/Pages/PendingCompression.xaml | 18 +- CompactGUI/Views/Pages/ResultsTemplate.xaml | 18 +- CompactGUI/Views/Pages/WatcherPage.xaml | 2 +- CompactGUI/Views/SettingsPage.xaml | 68 +- CompactGUI/Views/SettingsPage.xaml.vb | 8 +- CompactGUI/i18n/i18n.Designer.vb | 628 +++++++++--------- CompactGUI/i18n/i18n.resx | 198 +++--- CompactGUI/i18n/i18n.zh-CN.resx | 190 +++--- 17 files changed, 581 insertions(+), 640 deletions(-) diff --git a/.gitignore b/.gitignore index 6463666..f9a2ae7 100644 --- a/.gitignore +++ b/.gitignore @@ -367,3 +367,4 @@ FodyWeavers.xsd # IntelliJ .idea/ /CompactGUI.WatcherCS +/.history diff --git a/CompactGUI/Components/Converters/IValueConverters.vb b/CompactGUI/Components/Converters/IValueConverters.vb index d0ef602..9b59a73 100644 --- a/CompactGUI/Components/Converters/IValueConverters.vb +++ b/CompactGUI/Components/Converters/IValueConverters.vb @@ -93,16 +93,16 @@ Public Class RelativeDateConverter : Implements IValueConverter Dim ts As TimeSpan = DateTime.Now - dt If ts > TimeSpan.FromDays(19000) Then - Return LanguageHelper.GetString("RelativeTimeUnknown") + Return LanguageHelper.GetString("Time_Unknown") End If If ts > TimeSpan.FromDays(2) Then - Return String.Format(LanguageHelper.GetString("RelativeTimeDaysAgo"), ts.TotalDays) + Return String.Format(LanguageHelper.GetString("Time_DaysAgo"), ts.TotalDays) ElseIf ts > TimeSpan.FromHours(2) Then - Return String.Format(LanguageHelper.GetString("RelativeTimeHoursAgo"), ts.TotalHours) + Return String.Format(LanguageHelper.GetString("Time_HoursAgo"), ts.TotalHours) ElseIf ts > TimeSpan.FromMinutes(2) Then - Return String.Format(LanguageHelper.GetString("RelativeTimeMinutesAgo"), ts.TotalMinutes) + Return String.Format(LanguageHelper.GetString("Time_MinutesAgo"), ts.TotalMinutes) Else - Return LanguageHelper.GetString("RelativeTimeJustNow") + Return LanguageHelper.GetString("Time_Now") End If End Function diff --git a/CompactGUI/Components/Settings/Settings_skiplistflyout.xaml b/CompactGUI/Components/Settings/Settings_skiplistflyout.xaml index 67fefa6..cca0717 100644 --- a/CompactGUI/Components/Settings/Settings_skiplistflyout.xaml +++ b/CompactGUI/Components/Settings/Settings_skiplistflyout.xaml @@ -45,7 +45,7 @@ - diff --git a/CompactGUI/MainWindow.xaml b/CompactGUI/MainWindow.xaml index dbd059f..a3ae737 100644 --- a/CompactGUI/MainWindow.xaml +++ b/CompactGUI/MainWindow.xaml @@ -41,7 +41,7 @@ - - - - diff --git a/CompactGUI/Views/Components/CompressionMode_Radio.xaml b/CompactGUI/Views/Components/CompressionMode_Radio.xaml index a4d813f..51a8c68 100644 --- a/CompactGUI/Views/Components/CompressionMode_Radio.xaml +++ b/CompactGUI/Views/Components/CompressionMode_Radio.xaml @@ -41,7 +41,7 @@ - diff --git a/CompactGUI/Views/Components/FolderWatcherCard.xaml b/CompactGUI/Views/Components/FolderWatcherCard.xaml index 0944e2d..012b13c 100644 --- a/CompactGUI/Views/Components/FolderWatcherCard.xaml +++ b/CompactGUI/Views/Components/FolderWatcherCard.xaml @@ -36,7 +36,7 @@ - - + - + @@ -112,8 +112,8 @@ - @@ -175,7 +175,7 @@ Background="{StaticResource CardBackgroundFillColorSecondaryBrush}"> - diff --git a/CompactGUI/Views/Pages/PendingCompression.xaml b/CompactGUI/Views/Pages/PendingCompression.xaml index b889cc5..307ac62 100644 --- a/CompactGUI/Views/Pages/PendingCompression.xaml +++ b/CompactGUI/Views/Pages/PendingCompression.xaml @@ -20,7 +20,7 @@ - @@ -31,7 +31,7 @@ --> - @@ -130,13 +130,13 @@ FontSize="16" IsChecked="{Binding Folder.CompressionOptions.SkipUserSubmittedFiletypes, Mode=TwoWay}"> - + - @@ -160,7 +160,7 @@ - - - @@ -44,7 +44,7 @@ - @@ -55,7 +55,7 @@ - @@ -71,7 +71,7 @@ Margin="0,0,20,20" Padding="10,20,10,20" Background="#30FFFFFF" BorderThickness="0"> - - - - - - diff --git a/CompactGUI/Views/SettingsPage.xaml b/CompactGUI/Views/SettingsPage.xaml index 436b15a..2599257 100644 --- a/CompactGUI/Views/SettingsPage.xaml +++ b/CompactGUI/Views/SettingsPage.xaml @@ -11,7 +11,7 @@ mc:Ignorable="d"> - @@ -96,7 +96,7 @@ FlowDirection="RightToLeft" IsExpanded="True" Style="{StaticResource CustomCardExpanderStyle}"> -