增加语言设置
This commit is contained in:
@@ -21,7 +21,6 @@ namespace Spine
|
||||
{
|
||||
[".skel"] = ".atlas",
|
||||
[".json"] = ".atlas",
|
||||
[".skel.bytes"] = ".atlas.bytes",
|
||||
}.ToFrozenDictionary();
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/SkinDefault.xaml"/>
|
||||
<ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/Theme.xaml"/>
|
||||
<ResourceDictionary Source="/Resources/Geometries.xaml"/>
|
||||
<ResourceDictionary Source="/Resources/Strings/zh-cn.xaml"/>
|
||||
<ResourceDictionary Source="/Resources/Strings/zh.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<Style x:Key="MyToggleButton" TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource ToggleButtonSwitch}">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using NLog;
|
||||
using SpineViewer.Views;
|
||||
using System.Collections.Frozen;
|
||||
using System.Configuration;
|
||||
using System.Data;
|
||||
using System.Diagnostics;
|
||||
@@ -7,8 +8,8 @@ using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
|
||||
namespace SpineViewer;
|
||||
|
||||
namespace SpineViewer
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
/// </summary>
|
||||
@@ -66,18 +67,9 @@ public partial class App : Application
|
||||
var uiCulture = CultureInfo.CurrentUICulture.Name.ToLowerInvariant();
|
||||
_logger.Info("Current UI Culture: {0}", uiCulture);
|
||||
|
||||
if (uiCulture.StartsWith("zh"))
|
||||
{
|
||||
; // 默认就是中文, 无需操作
|
||||
}
|
||||
else if (uiCulture.StartsWith("ja"))
|
||||
{
|
||||
dict.Source = new("Resources/Strings/ja-jp.xaml", UriKind.Relative);
|
||||
}
|
||||
else
|
||||
{
|
||||
dict.Source = new("Resources/Strings/en-us.xaml", UriKind.Relative);
|
||||
}
|
||||
if (uiCulture.StartsWith("zh")) { } // 默认就是中文, 无需操作
|
||||
else if (uiCulture.StartsWith("ja")) Language = AppLanguage.JA;
|
||||
else Language = AppLanguage.EN;
|
||||
|
||||
Resources.MergedDictionaries.Add(dict);
|
||||
}
|
||||
@@ -88,5 +80,36 @@ public partial class App : Application
|
||||
_logger.Error("Dispatcher unhandled exception: {0}", e.Exception.Message);
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 程序语言
|
||||
/// </summary>
|
||||
public AppLanguage Language
|
||||
{
|
||||
get => _language;
|
||||
set
|
||||
{
|
||||
var uri = $"Resources/Strings/{value.ToString().ToLower()}.xaml";
|
||||
try
|
||||
{
|
||||
Resources.MergedDictionaries.Add(new() { Source = new(uri, UriKind.Relative) });
|
||||
_language = value;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error("Failed to switch language to {0}, {1}", value, ex.Message);
|
||||
_logger.Trace(ex.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
private AppLanguage _language = AppLanguage.ZH;
|
||||
|
||||
}
|
||||
|
||||
public enum AppLanguage
|
||||
{
|
||||
ZH,
|
||||
EN,
|
||||
JA
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ namespace SpineViewer.Models
|
||||
/// </summary>
|
||||
public partial class PreferenceModel : ObservableObject
|
||||
{
|
||||
|
||||
#region 纹理加载首选项
|
||||
|
||||
[ObservableProperty]
|
||||
@@ -67,6 +68,13 @@ namespace SpineViewer.Models
|
||||
|
||||
#endregion
|
||||
|
||||
#region 程序选项
|
||||
|
||||
[ObservableProperty]
|
||||
private AppLanguage _appLanguage;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 序列化与反序列
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -205,4 +205,7 @@
|
||||
|
||||
<s:String x:Key="Str_SpineLoadPreference">Model Loading Options</s:String>
|
||||
|
||||
<s:String x:Key="Str_AppPreference">Application Options</s:String>
|
||||
<s:String x:Key="Str_Language">Language</s:String>
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -205,5 +205,8 @@
|
||||
|
||||
<s:String x:Key="Str_SpineLoadPreference">モデル読み込みオプション</s:String>
|
||||
|
||||
<s:String x:Key="Str_AppPreference">アプリケーションプション</s:String>
|
||||
<s:String x:Key="Str_Language">言語</s:String>
|
||||
|
||||
</ResourceDictionary>
|
||||
|
||||
@@ -205,4 +205,7 @@
|
||||
|
||||
<s:String x:Key="Str_SpineLoadPreference">模型加载选项</s:String>
|
||||
|
||||
<s:String x:Key="Str_AppPreference">应用程序选项</s:String>
|
||||
<s:String x:Key="Str_Language">语言</s:String>
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -18,7 +18,7 @@ namespace SpineViewer.ViewModels.Exporters
|
||||
{
|
||||
public class FFmpegVideoExporterViewModel(MainWindowViewModel vmMain) : VideoExporterViewModel(vmMain)
|
||||
{
|
||||
public ImmutableArray<FFmpegVideoExporter.VideoFormat> VideoFormats { get; } = Enum.GetValues<FFmpegVideoExporter.VideoFormat>().ToImmutableArray();
|
||||
public ImmutableArray<FFmpegVideoExporter.VideoFormat> VideoFormatOptions { get; } = Enum.GetValues<FFmpegVideoExporter.VideoFormat>().ToImmutableArray();
|
||||
|
||||
public FFmpegVideoExporter.VideoFormat Format { get => _format; set => SetProperty(ref _format, value); }
|
||||
protected FFmpegVideoExporter.VideoFormat _format = FFmpegVideoExporter.VideoFormat.Mp4;
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace SpineViewer.ViewModels.Exporters
|
||||
{
|
||||
public class FrameExporterViewModel(MainWindowViewModel vmMain) : BaseExporterViewModel(vmMain)
|
||||
{
|
||||
public ImmutableArray<SKEncodedImageFormat> FrameFormats { get; } = Enum.GetValues<SKEncodedImageFormat>().ToImmutableArray();
|
||||
public ImmutableArray<SKEncodedImageFormat> FrameFormatOptions { get; } = Enum.GetValues<SKEncodedImageFormat>().ToImmutableArray();
|
||||
|
||||
public SKEncodedImageFormat Format { get => _format; set => SetProperty(ref _format, value); }
|
||||
protected SKEncodedImageFormat _format = SKEncodedImageFormat.Png;
|
||||
|
||||
@@ -6,6 +6,7 @@ using SpineViewer.Models;
|
||||
using SpineViewer.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -105,7 +106,8 @@ namespace SpineViewer.ViewModels.MainWindow
|
||||
DebugBoundingBoxes = DebugBoundingBoxes,
|
||||
DebugPaths = DebugPaths,
|
||||
DebugPoints = DebugPoints,
|
||||
DebugClippings = DebugClippings
|
||||
DebugClippings = DebugClippings,
|
||||
AppLanguage = AppLanguage,
|
||||
};
|
||||
}
|
||||
set
|
||||
@@ -124,6 +126,7 @@ namespace SpineViewer.ViewModels.MainWindow
|
||||
DebugPaths = value.DebugPaths;
|
||||
DebugPoints = value.DebugPoints;
|
||||
DebugClippings = value.DebugClippings;
|
||||
AppLanguage = value.AppLanguage;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,42 +152,88 @@ namespace SpineViewer.ViewModels.MainWindow
|
||||
|
||||
#endregion
|
||||
|
||||
// TODO: 是否自动记忆模型参数
|
||||
|
||||
#region 模型加载首选项
|
||||
|
||||
public bool UsePma { get => _usePma; set => SetProperty(ref _usePma, value); }
|
||||
private bool _usePma;
|
||||
// TODO: 是否自动记忆模型参数
|
||||
|
||||
public bool DebugTexture { get => _debugTexture; set => SetProperty(ref _debugTexture, value); }
|
||||
private bool _debugTexture = true;
|
||||
public bool UsePma
|
||||
{
|
||||
get => SpineObjectListViewModel.LoadOptions.UsePma;
|
||||
set => SetProperty(SpineObjectListViewModel.LoadOptions.UsePma, value, v => SpineObjectListViewModel.LoadOptions.UsePma = v);
|
||||
}
|
||||
|
||||
public bool DebugBounds { get => _debugBounds; set => SetProperty(ref _debugBounds, value); }
|
||||
private bool _debugBounds;
|
||||
public bool DebugTexture
|
||||
{
|
||||
get => SpineObjectListViewModel.LoadOptions.DebugTexture;
|
||||
set => SetProperty(SpineObjectListViewModel.LoadOptions.DebugTexture, value, v => SpineObjectListViewModel.LoadOptions.DebugTexture = v);
|
||||
}
|
||||
|
||||
public bool DebugBones { get => _debugBones; set => SetProperty(ref _debugBones, value); }
|
||||
private bool _debugBones;
|
||||
public bool DebugBounds
|
||||
{
|
||||
get => SpineObjectListViewModel.LoadOptions.DebugBounds;
|
||||
set => SetProperty(SpineObjectListViewModel.LoadOptions.DebugBounds, value, v => SpineObjectListViewModel.LoadOptions.DebugBounds = v);
|
||||
}
|
||||
|
||||
public bool DebugRegions { get => _debugRegions; set => SetProperty(ref _debugRegions, value); }
|
||||
private bool _debugRegions;
|
||||
public bool DebugBones
|
||||
{
|
||||
get => SpineObjectListViewModel.LoadOptions.DebugBones;
|
||||
set => SetProperty(SpineObjectListViewModel.LoadOptions.DebugBones, value, v => SpineObjectListViewModel.LoadOptions.DebugBones = v);
|
||||
}
|
||||
|
||||
public bool DebugMeshHulls { get => _debugMeshHulls; set => SetProperty(ref _debugMeshHulls, value); }
|
||||
private bool _debugMeshHulls;
|
||||
public bool DebugRegions
|
||||
{
|
||||
get => SpineObjectListViewModel.LoadOptions.DebugRegions;
|
||||
set => SetProperty(SpineObjectListViewModel.LoadOptions.DebugRegions, value, v => SpineObjectListViewModel.LoadOptions.DebugRegions = v);
|
||||
}
|
||||
|
||||
public bool DebugMeshes { get => _debugMeshes; set => SetProperty(ref _debugMeshes, value); }
|
||||
private bool _debugMeshes;
|
||||
public bool DebugMeshHulls
|
||||
{
|
||||
get => SpineObjectListViewModel.LoadOptions.DebugMeshHulls;
|
||||
set => SetProperty(SpineObjectListViewModel.LoadOptions.DebugMeshHulls, value, v => SpineObjectListViewModel.LoadOptions.DebugMeshHulls = v);
|
||||
}
|
||||
|
||||
public bool DebugBoundingBoxes { get => _debugBoundingBoxes; set => SetProperty(ref _debugBoundingBoxes, value); }
|
||||
private bool _debugBoundingBoxes;
|
||||
public bool DebugMeshes
|
||||
{
|
||||
get => SpineObjectListViewModel.LoadOptions.DebugMeshes;
|
||||
set => SetProperty(SpineObjectListViewModel.LoadOptions.DebugMeshes, value, v => SpineObjectListViewModel.LoadOptions.DebugMeshes = v);
|
||||
}
|
||||
|
||||
public bool DebugPaths { get => _debugPaths; set => SetProperty(ref _debugPaths, value); }
|
||||
private bool _debugPaths;
|
||||
public bool DebugBoundingBoxes
|
||||
{
|
||||
get => SpineObjectListViewModel.LoadOptions.DebugBoundingBoxes;
|
||||
set => SetProperty(SpineObjectListViewModel.LoadOptions.DebugBoundingBoxes, value, v => SpineObjectListViewModel.LoadOptions.DebugBoundingBoxes = v);
|
||||
}
|
||||
|
||||
public bool DebugPoints { get => _debugPoints; set => SetProperty(ref _debugPoints, value); }
|
||||
private bool _debugPoints;
|
||||
public bool DebugPaths
|
||||
{
|
||||
get => SpineObjectListViewModel.LoadOptions.DebugPaths;
|
||||
set => SetProperty(SpineObjectListViewModel.LoadOptions.DebugPaths, value, v => SpineObjectListViewModel.LoadOptions.DebugPaths = v);
|
||||
}
|
||||
|
||||
public bool DebugClippings { get => _debugClippings; set => SetProperty(ref _debugClippings, value); }
|
||||
private bool _debugClippings;
|
||||
public bool DebugPoints
|
||||
{
|
||||
get => SpineObjectListViewModel.LoadOptions.DebugPoints;
|
||||
set => SetProperty(SpineObjectListViewModel.LoadOptions.DebugPoints, value, v => SpineObjectListViewModel.LoadOptions.DebugPoints = v);
|
||||
}
|
||||
|
||||
public bool DebugClippings
|
||||
{
|
||||
get => SpineObjectListViewModel.LoadOptions.DebugClippings;
|
||||
set => SetProperty(SpineObjectListViewModel.LoadOptions.DebugClippings, value, v => SpineObjectListViewModel.LoadOptions.DebugClippings = v);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 程序选项
|
||||
|
||||
public static ImmutableArray<AppLanguage> AppLanguageOptions { get; } = Enum.GetValues<AppLanguage>().ToImmutableArray();
|
||||
|
||||
public AppLanguage AppLanguage
|
||||
{
|
||||
get => ((App)App.Current).Language;
|
||||
set => SetProperty(((App)App.Current).Language, value, v => ((App)App.Current).Language = v);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -21,6 +21,12 @@ namespace SpineViewer.ViewModels.MainWindow
|
||||
{
|
||||
public class SpineObjectListViewModel : ObservableObject
|
||||
{
|
||||
/// <summary>
|
||||
/// 加载选项
|
||||
/// </summary>
|
||||
public static SpineLoadOptions LoadOptions => _loadOptions;
|
||||
private static readonly SpineLoadOptions _loadOptions = new();
|
||||
|
||||
private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
/// <summary>
|
||||
@@ -249,41 +255,6 @@ namespace SpineViewer.ViewModels.MainWindow
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 安全地在末尾添加一个模型, 发生错误会输出日志
|
||||
/// </summary>
|
||||
/// <returns>是否添加成功</returns>
|
||||
public bool AddSpineObject(string skelPath, string? atlasPath = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// TODO: 判断是否记忆参数
|
||||
var pre = _vmMain.PreferenceViewModel;
|
||||
var sp = new SpineObjectModel(skelPath, atlasPath)
|
||||
{
|
||||
UsePma = pre.UsePma,
|
||||
DebugTexture = pre.DebugTexture,
|
||||
DebugBounds = pre.DebugBounds,
|
||||
DebugRegions = pre.DebugRegions,
|
||||
DebugMeshHulls = pre.DebugMeshHulls,
|
||||
DebugMeshes = pre.DebugMeshes,
|
||||
DebugBoundingBoxes = pre.DebugBoundingBoxes,
|
||||
DebugPaths = pre.DebugPaths,
|
||||
DebugPoints = pre.DebugPoints,
|
||||
DebugClippings = pre.DebugClippings
|
||||
};
|
||||
|
||||
lock (_spineObjectModels.Lock) _spineObjectModels.Add(sp);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Trace(ex.ToString());
|
||||
_logger.Error("Failed to load: {0}, {1}", skelPath, ex.Message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从路径列表添加对象
|
||||
/// </summary>
|
||||
@@ -369,5 +340,54 @@ namespace SpineViewer.ViewModels.MainWindow
|
||||
|
||||
_logger.LogCurrentProcessMemoryUsage();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 安全地在末尾添加一个模型, 发生错误会输出日志
|
||||
/// </summary>
|
||||
/// <returns>是否添加成功</returns>
|
||||
public bool AddSpineObject(string skelPath, string? atlasPath = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var sp = new SpineObjectModel(skelPath, atlasPath)
|
||||
{
|
||||
UsePma = _loadOptions.UsePma,
|
||||
DebugTexture = _loadOptions.DebugTexture,
|
||||
DebugBounds = _loadOptions.DebugBounds,
|
||||
DebugRegions = _loadOptions.DebugRegions,
|
||||
DebugMeshHulls = _loadOptions.DebugMeshHulls,
|
||||
DebugMeshes = _loadOptions.DebugMeshes,
|
||||
DebugBoundingBoxes = _loadOptions.DebugBoundingBoxes,
|
||||
DebugPaths = _loadOptions.DebugPaths,
|
||||
DebugPoints = _loadOptions.DebugPoints,
|
||||
DebugClippings = _loadOptions.DebugClippings
|
||||
};
|
||||
|
||||
lock (_spineObjectModels.Lock) _spineObjectModels.Add(sp);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Trace(ex.ToString());
|
||||
_logger.Error("Failed to load: {0}, {1}", skelPath, ex.Message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public class SpineLoadOptions
|
||||
{
|
||||
// TODO: 判断是否记忆参数
|
||||
public bool UsePma { get; set; }
|
||||
public bool DebugTexture { get; set; } = true;
|
||||
public bool DebugBounds { get; set; }
|
||||
public bool DebugBones { get; set; }
|
||||
public bool DebugRegions { get; set; }
|
||||
public bool DebugMeshHulls { get; set; }
|
||||
public bool DebugMeshes { get; set; }
|
||||
public bool DebugBoundingBoxes { get; set; }
|
||||
public bool DebugPaths { get; set; }
|
||||
public bool DebugPoints { get; set; }
|
||||
public bool DebugClippings { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
|
||||
<!-- 视频格式 -->
|
||||
<Label Grid.Row="13" Grid.Column="0" Content="{DynamicResource Str_VideoFormat}"/>
|
||||
<ComboBox Grid.Row="13" Grid.Column="1" SelectedItem="{Binding Format}" ItemsSource="{Binding VideoFormats}"/>
|
||||
<ComboBox Grid.Row="13" Grid.Column="1" SelectedItem="{Binding Format}" ItemsSource="{Binding VideoFormatOptions}"/>
|
||||
|
||||
<!-- 动图是否循环 -->
|
||||
<Label Grid.Row="14" Grid.Column="0" Content="{DynamicResource Str_LoopPlay}" ToolTip="{DynamicResource Str_LoopPlayTooltip}"/>
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
|
||||
<!-- 图像格式 -->
|
||||
<Label Grid.Row="9" Grid.Column="0" Content="{DynamicResource Str_ImageFormat}"/>
|
||||
<ComboBox Grid.Row="9" Grid.Column="1" SelectedItem="{Binding Format}" ItemsSource="{Binding FrameFormats}"/>
|
||||
<ComboBox Grid.Row="9" Grid.Column="1" SelectedItem="{Binding Format}" ItemsSource="{Binding FrameFormatOptions}"/>
|
||||
|
||||
<!-- 图像质量 -->
|
||||
<Label Grid.Row="10" Grid.Column="0" Content="{DynamicResource Str_ImageQuality}" ToolTip="{DynamicResource Str_ImageQualityTooltip}"/>
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<Window xmlns:hc="https://handyorg.github.io/handycontrol" x:Class="SpineViewer.Views.PreferenceDialog"
|
||||
<Window x:Class="SpineViewer.Views.PreferenceDialog"
|
||||
xmlns:hc="https://handyorg.github.io/handycontrol"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:SpineViewer.Views"
|
||||
xmlns:models="clr-namespace:SpineViewer.Models"
|
||||
xmlns:vm="clr-namespace:SpineViewer.ViewModels.MainWindow"
|
||||
d:DataContext="{d:DesignInstance Type=models:PreferenceModel}"
|
||||
mc:Ignorable="d"
|
||||
Title="{DynamicResource Str_Preference}"
|
||||
@@ -125,6 +127,24 @@
|
||||
<ToggleButton Grid.Row="10" Grid.Column="1" IsChecked="{Binding DebugClippings}"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="{DynamicResource Str_AppPreference}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" SharedSizeGroup="Col1"/>
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Label Grid.Row="0" Grid.Column="0" Content="{DynamicResource Str_Language}"/>
|
||||
<ComboBox Grid.Row="0" Grid.Column="1"
|
||||
SelectedItem="{Binding AppLanguage}"
|
||||
ItemsSource="{x:Static vm:PreferenceViewModel.AppLanguageOptions}"/>
|
||||
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
|
||||
Reference in New Issue
Block a user