Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions CompactGUI/CompactGUI.vbproj
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,7 @@
<ProjectReference Include="..\CompactGUI.Core\CompactGUI.Core.csproj" />
<ProjectReference Include="..\CompactGUI.Logging\CompactGUI.Logging.csproj" />
<ProjectReference Include="..\CompactGUI.Watcher\CompactGUI.Watcher.vbproj" />
</ItemGroup>

<ItemGroup>
<Reference Include="FunctionalConverters">
<HintPath>..\..\FunctionalConverters\FunctionalConverters\bin\Release\net6.0-windows\FunctionalConverters.dll</HintPath>
</Reference>
<ProjectReference Include="..\FunctionalConverters\FunctionalConverters\FunctionalConverters.vbproj" />
</ItemGroup>

<Target Name="RenamePublishedExe" AfterTargets="Publish" Condition="'$(IsMonolithic)' == 'true'">
Expand All @@ -90,5 +85,10 @@
<Copy SourceFiles="@(PublishedFiles)" DestinationFolder="$(FinalPublishDir)" SkipUnchangedFiles="true" />
</Target>

<ItemGroup>
<None Update="i18n\**\*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
37 changes: 37 additions & 0 deletions CompactGUI/LanguageConfig.vb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
Imports System.IO
Imports System.Text.Json

Public Class LanguageConfig
Private Shared ConfigPath As String = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "language_config.json")

Public Class ConfigData
Public Property LanguageCode As String = "en-US"
End Class

Public Shared Sub SaveLanguage(langCode As String)
Try
Dim data As New ConfigData With {.LanguageCode = langCode}
Dim jsonString = JsonSerializer.Serialize(data)
File.WriteAllText(ConfigPath, jsonString)
Catch ex As Exception
End Try
End Sub

Public Shared Function GetLanguage() As String
Try
If File.Exists(ConfigPath) Then
Dim jsonString = File.ReadAllText(ConfigPath)
Dim data = JsonSerializer.Deserialize(Of ConfigData)(jsonString)
Return If(data IsNot Nothing AndAlso Not String.IsNullOrEmpty(data.LanguageCode), data.LanguageCode, "en-US")
Else
Dim sysLang = System.Globalization.CultureInfo.CurrentUICulture.Name
Dim i18nPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "i18n", $"{sysLang}.json")
If File.Exists(i18nPath) Then
Return sysLang
End If
End If
Catch ex As Exception
End Try
Return "en-US"
End Function
End Class
1 change: 1 addition & 0 deletions CompactGUI/MainWindow.xaml.vb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Class MainWindow : Implements INavigationWindow, INotifyPropertyChanged

' This call is required by the designer.
InitializeComponent()
TranslationHelper.StartAutoTranslate()
' Add any initialization after the InitializeComponent() call.

snackbarService.SetSnackbarPresenter(RootSnackbar)
Expand Down
160 changes: 160 additions & 0 deletions CompactGUI/TranslationHelper.vb
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
Imports System.IO
Imports System.Reflection
Imports System.Text.Json
Imports System.Text.RegularExpressions
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Documents
Imports System.Windows.Media
Imports System.Windows.Threading

Public Class TranslationHelper

Private Shared _isInitialized As Boolean = False
Public Shared Translations As New Dictionary(Of String, String)

Public Shared Sub StartAutoTranslate()
If _isInitialized Then Return
_isInitialized = True

Dim currentLang = LanguageConfig.GetLanguage()

If currentLang <> "en-US" Then
Dim langFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "i18n", $"{currentLang}.json")
If File.Exists(langFile) Then
LoadLanguageFile(langFile)

EventManager.RegisterClassHandler(GetType(FrameworkElement), FrameworkElement.LoadedEvent, New RoutedEventHandler(AddressOf OnElementLoaded))
EventManager.RegisterClassHandler(GetType(FrameworkContentElement), FrameworkContentElement.LoadedEvent, New RoutedEventHandler(AddressOf OnElementLoaded))
End If
End If
End Sub

Public Shared Sub LoadLanguageFile(filePath As String)
Try
Dim jsonContent = File.ReadAllText(filePath)
Dim newTranslations = JsonSerializer.Deserialize(Of Dictionary(Of String, String))(jsonContent)
If newTranslations IsNot Nothing Then
Translations = newTranslations
End If
Catch ex As Exception
System.Diagnostics.Debug.WriteLine($"Failed to load language file: {ex.Message}")
End Try
End Sub

Public Shared Sub TranslateWindow(obj As DependencyObject)
End Sub

Private Shared Sub OnElementLoaded(sender As Object, e As RoutedEventArgs)
Dim element As DependencyObject = TryCast(sender, DependencyObject)
If element Is Nothing Then Return

If TypeOf element Is DispatcherObject Then
DirectCast(element, DispatcherObject).Dispatcher.BeginInvoke(DispatcherPriority.ContextIdle, Sub()
Try
RecursiveTranslate(element)
Catch ex As Exception
End Try
End Sub)
End If
End Sub

Private Shared Function NormalizeText(input As String) As String
If String.IsNullOrEmpty(input) Then Return ""
Dim normalized As String = Regex.Replace(input, "\s+", " ")
Return normalized.Trim()
End Function

Public Shared Function GetString(key As String) As String
If Translations.ContainsKey(key) Then
Return Translations(key)
End If
Return key
End Function

Public Shared Function GetStringForLanguage(langCode As String, key As String) As String
Dim filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "i18n", $"{langCode}.json")
If File.Exists(filePath) Then
Try
Dim jsonContent = File.ReadAllText(filePath)
Dim tempDict = JsonSerializer.Deserialize(Of Dictionary(Of String, String))(jsonContent)
If tempDict IsNot Nothing AndAlso tempDict.ContainsKey(key) Then
Return tempDict(key)
End If
Catch
End Try
End If

If langCode = "en-US" Then Return key

Return GetString(key)
End Function

Private Shared Sub TryReplace(original As String, applyAction As Action(Of String))
If String.IsNullOrWhiteSpace(original) Then Return

Dim normalizedText As String = NormalizeText(original)
Dim found As Boolean = False

If Translations.ContainsKey(normalizedText) Then
applyAction(Translations(normalizedText))
found = True
Else
For Each kvp In Translations
If kvp.Key.Length > 3 AndAlso normalizedText.Contains(kvp.Key) Then
Dim translated As String = normalizedText.Replace(kvp.Key, kvp.Value)

If translated <> normalizedText Then
applyAction(translated)
found = True
Exit For
End If
End If
Next
End If
End Sub

Private Shared Sub RecursiveTranslate(element As Object)
If element Is Nothing Then Return

Dim targetProperties As String() = {"Text", "Content", "Header", "Title", "Description", "Label", "ToolTip", "PlaceholderText"}
Dim type As Type = element.GetType()

For Each propName In targetProperties
Dim prop = type.GetProperty(propName)
If prop IsNot Nothing AndAlso prop.CanRead AndAlso prop.CanWrite Then
Try
Dim val = prop.GetValue(element)
If TypeOf val Is String Then
TryReplace(CStr(val), Sub(newVal) prop.SetValue(element, newVal))
ElseIf val IsNot Nothing AndAlso Not TypeOf val Is ValueType Then
RecursiveTranslate(val)
End If
Catch ex As Exception
End Try
End If
Next

If TypeOf element Is TextBlock Then
Dim tb = DirectCast(element, TextBlock)
For Each inline In tb.Inlines
If TypeOf inline Is Run Then
RecursiveTranslate(inline)
End If
Next
End If

If TypeOf element Is DependencyObject Then
Dim depObj = DirectCast(element, DependencyObject)
If TypeOf depObj Is Visual OrElse TypeOf depObj Is System.Windows.Media.Media3D.Visual3D Then
Dim childCount = VisualTreeHelper.GetChildrenCount(depObj)
For i = 0 To childCount - 1
Dim child = VisualTreeHelper.GetChild(depObj, i)
RecursiveTranslate(child)
Next
End If
End If

End Sub

End Class
Loading