diff --git a/LanMontainDesktop/LanMontainDesktop.csproj b/LanMontainDesktop/LanMontainDesktop.csproj index fe146e4..51db0a2 100644 --- a/LanMontainDesktop/LanMontainDesktop.csproj +++ b/LanMontainDesktop/LanMontainDesktop.csproj @@ -11,6 +11,7 @@ + diff --git a/LanMontainDesktop/Localization/en-US.json b/LanMontainDesktop/Localization/en-US.json new file mode 100644 index 0000000..0a0b78f --- /dev/null +++ b/LanMontainDesktop/Localization/en-US.json @@ -0,0 +1,84 @@ +{ + "app.title": "LanMontainDesktop", + "button.back_to_windows": "Back to Windows", + "tooltip.back_to_windows": "Back to Windows", + "tooltip.open_settings": "Settings", + "settings.title": "Settings", + "settings.back_to_desktop": "Back to Desktop", + "settings.nav_header": "Settings", + "settings.nav.wallpaper": "Wallpaper", + "settings.nav.grid": "Grid", + "settings.nav.color": "Color", + "settings.nav.status_bar": "Status Bar", + "settings.nav.region": "Region", + "settings.wallpaper.title": "Wallpaper", + "settings.wallpaper.description": "Pick an image or video to apply as the app window wallpaper immediately.", + "settings.wallpaper.current_label": "Current Wallpaper", + "settings.wallpaper.placement_label": "Placement", + "settings.wallpaper.pick_button": "Browse Files", + "settings.wallpaper.clear_button": "Reset to Solid Color", + "settings.wallpaper.no_selection": "No wallpaper selected.", + "settings.wallpaper.storage_unavailable": "Storage provider is unavailable.", + "settings.wallpaper.import_failed": "Failed to import wallpaper file.", + "settings.wallpaper.image_applied": "Image wallpaper applied.", + "settings.wallpaper.video_applied": "Video wallpaper applied.", + "settings.wallpaper.unsupported_file": "Selected file type is not supported.", + "settings.wallpaper.apply_failed_format": "Failed to apply wallpaper: {0}", + "settings.wallpaper.mode_format": "Wallpaper mode: {0}.", + "settings.wallpaper.video_mode": "Video wallpaper uses automatic fill mode.", + "settings.wallpaper.cleared": "Background reset to solid color.", + "settings.wallpaper.default_status": "Current background uses solid color.", + "settings.wallpaper.saved_not_found": "Saved wallpaper file was not found. Using solid color background.", + "settings.wallpaper.restored": "Wallpaper restored from saved settings.", + "settings.wallpaper.video_restored": "Video wallpaper restored from saved settings.", + "settings.wallpaper.restore_failed": "Failed to restore saved wallpaper. Using solid color background.", + "settings.wallpaper.video_not_found": "Video wallpaper file not found.", + "settings.wallpaper.video_player_unavailable": "Video player is unavailable.", + "settings.wallpaper.video_play_failed_format": "Failed to play video wallpaper: {0}", + "settings.grid.title": "Grid Layout", + "settings.grid.description": "Every component must occupy at least one cell (minimum 1x1).", + "settings.grid.short_side_label": "Short Side Cells", + "settings.grid.apply_button": "Apply", + "settings.grid.info_format": "Grid: {0} cols x {1} rows | cell {2:F1}px (1:1)", + "settings.color.title": "Color", + "settings.color.description": "Switch day/night mode and choose app accent colors.", + "settings.color.day_night_label": "Day/Night Mode", + "settings.color.day_night_on": "Night", + "settings.color.day_night_off": "Day", + "settings.color.recommended_label": "Recommended Colors", + "settings.color.system_monet_label": "System Monet Colors", + "settings.color.refresh_button": "Refresh", + "settings.color.mode_night": "Night mode enabled", + "settings.color.mode_day": "Day mode enabled", + "settings.color.mode_status_format": "Theme mode: {0}.", + "settings.color.monet_refreshed": "Monet colors refreshed.", + "settings.color.theme_ready_format": "Theme color ready: {0}.", + "settings.color.theme_applied_format": "{0} color applied: {1}.", + "settings.color.theme_updated_wallpaper": "Wallpaper updated. Monet colors refreshed.", + "settings.color.theme_updated_video": "Video wallpaper updated. Theme colors refreshed.", + "settings.color.theme_cleared_wallpaper": "Wallpaper cleared. Monet colors refreshed.", + "settings.status_bar.title": "Status Bar", + "settings.status_bar.description": "Choose which components appear on the top status bar.", + "settings.status_bar.clock_header": "Clock Component", + "settings.status_bar.clock_description": "Display a clock on the top status bar.", + "settings.region.title": "Region", + "settings.region.description": "Choose language and apply immediately to settings and key UI.", + "settings.region.language_header": "Language", + "settings.region.language_label": "Language", + "settings.region.language_zh": "Chinese", + "settings.region.language_en": "English", + "settings.region.applied_format": "Language switched to: {0}", + "settings.footer": "LanMontainDesktop Settings", + "filepicker.title": "Select wallpaper", + "filepicker.image_files": "Image files", + "filepicker.video_files": "Video files", + "common.day": "Day", + "common.night": "Night", + "common.recommended": "Recommended", + "common.monet": "Monet", + "placement.fill": "Fill", + "placement.fit": "Fit", + "placement.stretch": "Stretch", + "placement.center": "Center", + "placement.tile": "Tile" +} diff --git a/LanMontainDesktop/Localization/zh-CN.json b/LanMontainDesktop/Localization/zh-CN.json new file mode 100644 index 0000000..6f72fec --- /dev/null +++ b/LanMontainDesktop/Localization/zh-CN.json @@ -0,0 +1,84 @@ +{ + "app.title": "LanMontainDesktop", + "button.back_to_windows": "回到Windows", + "tooltip.back_to_windows": "回到Windows", + "tooltip.open_settings": "设置", + "settings.title": "设置", + "settings.back_to_desktop": "返回桌面", + "settings.nav_header": "设置选项", + "settings.nav.wallpaper": "壁纸", + "settings.nav.grid": "网格", + "settings.nav.color": "颜色", + "settings.nav.status_bar": "状态栏", + "settings.nav.region": "地区", + "settings.wallpaper.title": "壁纸", + "settings.wallpaper.description": "选择图片或视频后可立刻设为应用窗口壁纸。", + "settings.wallpaper.current_label": "当前壁纸", + "settings.wallpaper.placement_label": "显示方式", + "settings.wallpaper.pick_button": "浏览文件", + "settings.wallpaper.clear_button": "恢复纯色", + "settings.wallpaper.no_selection": "未选择壁纸。", + "settings.wallpaper.storage_unavailable": "存储提供器不可用。", + "settings.wallpaper.import_failed": "导入壁纸文件失败。", + "settings.wallpaper.image_applied": "图片壁纸已应用。", + "settings.wallpaper.video_applied": "视频壁纸已应用。", + "settings.wallpaper.unsupported_file": "所选文件类型不受支持。", + "settings.wallpaper.apply_failed_format": "应用壁纸失败:{0}", + "settings.wallpaper.mode_format": "壁纸模式:{0}。", + "settings.wallpaper.video_mode": "视频壁纸使用自动填充模式。", + "settings.wallpaper.cleared": "背景已恢复为纯色。", + "settings.wallpaper.default_status": "当前使用纯色背景。", + "settings.wallpaper.saved_not_found": "未找到已保存的壁纸文件,使用纯色背景。", + "settings.wallpaper.restored": "已恢复保存的壁纸。", + "settings.wallpaper.video_restored": "已恢复保存的视频壁纸。", + "settings.wallpaper.restore_failed": "恢复已保存壁纸失败,使用纯色背景。", + "settings.wallpaper.video_not_found": "未找到视频壁纸文件。", + "settings.wallpaper.video_player_unavailable": "视频播放器不可用。", + "settings.wallpaper.video_play_failed_format": "播放视频壁纸失败:{0}", + "settings.grid.title": "网格布局", + "settings.grid.description": "每个组件至少占用一个格子(最小 1x1)。", + "settings.grid.short_side_label": "短边格数", + "settings.grid.apply_button": "应用", + "settings.grid.info_format": "网格:{0} 列 x {1} 行 | 单元格 {2:F1}px(1:1)", + "settings.color.title": "颜色", + "settings.color.description": "切换日夜模式并选择应用主题色。", + "settings.color.day_night_label": "日夜模式", + "settings.color.day_night_on": "夜间", + "settings.color.day_night_off": "日间", + "settings.color.recommended_label": "推荐色", + "settings.color.system_monet_label": "系统莫奈色", + "settings.color.refresh_button": "刷新", + "settings.color.mode_night": "夜间模式已启用", + "settings.color.mode_day": "日间模式已启用", + "settings.color.mode_status_format": "主题模式:{0}。", + "settings.color.monet_refreshed": "莫奈色已刷新。", + "settings.color.theme_ready_format": "主题色已就绪:{0}。", + "settings.color.theme_applied_format": "{0}主题色已应用:{1}。", + "settings.color.theme_updated_wallpaper": "壁纸更新,莫奈色已刷新。", + "settings.color.theme_updated_video": "视频壁纸更新,主题色已刷新。", + "settings.color.theme_cleared_wallpaper": "壁纸已清除,莫奈色已刷新。", + "settings.status_bar.title": "状态栏", + "settings.status_bar.description": "选择顶部状态栏显示的组件。", + "settings.status_bar.clock_header": "时间组件", + "settings.status_bar.clock_description": "在顶部状态栏显示时钟。", + "settings.region.title": "地区", + "settings.region.description": "选择语言并立即应用到设置与主要界面。", + "settings.region.language_header": "语言", + "settings.region.language_label": "语言", + "settings.region.language_zh": "中文", + "settings.region.language_en": "英文", + "settings.region.applied_format": "语言已切换为:{0}", + "settings.footer": "LanMontainDesktop 设置", + "filepicker.title": "选择壁纸", + "filepicker.image_files": "图片文件", + "filepicker.video_files": "视频文件", + "common.day": "日间", + "common.night": "夜间", + "common.recommended": "推荐", + "common.monet": "莫奈", + "placement.fill": "填充", + "placement.fit": "适应", + "placement.stretch": "拉伸", + "placement.center": "居中", + "placement.tile": "平铺" +} diff --git a/LanMontainDesktop/Models/AppSettingsSnapshot.cs b/LanMontainDesktop/Models/AppSettingsSnapshot.cs index 10571ec..b027c37 100644 --- a/LanMontainDesktop/Models/AppSettingsSnapshot.cs +++ b/LanMontainDesktop/Models/AppSettingsSnapshot.cs @@ -16,6 +16,8 @@ public sealed class AppSettingsSnapshot public int SettingsTabIndex { get; set; } = 0; + public string LanguageCode { get; set; } = "zh-CN"; + public List TopStatusComponentIds { get; set; } = []; public List PinnedTaskbarActions { get; set; } = diff --git a/LanMontainDesktop/Models/TaskbarContext.cs b/LanMontainDesktop/Models/TaskbarContext.cs index 9ac18f9..3af8331 100644 --- a/LanMontainDesktop/Models/TaskbarContext.cs +++ b/LanMontainDesktop/Models/TaskbarContext.cs @@ -6,5 +6,6 @@ public enum TaskbarContext SettingsWallpaper, SettingsGrid, SettingsColor, - SettingsStatusBar + SettingsStatusBar, + SettingsRegion } diff --git a/LanMontainDesktop/Services/GlassEffectService.cs b/LanMontainDesktop/Services/GlassEffectService.cs index 47b04a5..0df5d16 100644 --- a/LanMontainDesktop/Services/GlassEffectService.cs +++ b/LanMontainDesktop/Services/GlassEffectService.cs @@ -15,36 +15,54 @@ public static class GlassEffectService public static void ApplyGlassResources(IResourceDictionary resources, ThemeColorContext context) { - var neutralBase = context.IsNightMode ? Color.Parse("#FF0B1220") : Color.Parse("#FFF8FAFC"); - var neutralElevated = context.IsNightMode ? Color.Parse("#FF1E293B") : Color.Parse("#FFFFFFFF"); - var tintMix = context.IsNightMode ? 0.15 : 0.08; - var panelTone = ColorMath.Blend(neutralElevated, context.AccentColor, tintMix); - var strongTone = ColorMath.Blend(neutralBase, context.AccentColor, context.IsNightMode ? 0.18 : 0.12); - var overlayTone = ColorMath.Blend(neutralBase, context.AccentColor, context.IsNightMode ? 0.25 : 0.15); - - resources["AdaptiveButtonBackgroundBrush"] = new SolidColorBrush( - ColorMath.WithAlpha(panelTone, context.IsNightMode ? (byte)0x66 : (byte)0x80)); - resources["AdaptiveButtonBorderBrush"] = new SolidColorBrush(ColorMath.WithAlpha(neutralElevated, 0x1A)); + // Mica 材质:不透明,但混合壁纸颜色 + // 提取壁纸颜色的透明度(0-1),用于控制 Mica 效果强度 + var wallpaperTintOpacity = 0.15; // 壁纸颜色混合比例 + + var neutralBase = context.IsNightMode ? Color.Parse("#FF202020") : Color.Parse("#FFF3F3F3"); + var neutralElevated = context.IsNightMode ? Color.Parse("#FF2C2C2C") : Color.Parse("#FFFAFAFA"); + + // Mica 效果:将壁纸颜色混合到中性基色中 + var micaBackground = ColorMath.Blend(neutralBase, context.AccentColor, wallpaperTintOpacity); + var micaElevated = ColorMath.Blend(neutralElevated, context.AccentColor, wallpaperTintOpacity * 0.8); + + // 按钮颜色 + var buttonBackground = context.IsNightMode ? + Color.FromArgb(0x33, micaBackground.R, micaBackground.G, micaBackground.B) : + Color.FromArgb(0x4D, micaBackground.R, micaBackground.G, micaBackground.B); + + resources["AdaptiveButtonBackgroundBrush"] = new SolidColorBrush(buttonBackground); + resources["AdaptiveButtonBorderBrush"] = new SolidColorBrush( + Color.FromArgb(0x1A, neutralElevated.R, neutralElevated.G, neutralElevated.B)); resources["AdaptiveButtonHoverBackgroundBrush"] = new SolidColorBrush( - ColorMath.WithAlpha(ColorMath.Blend(panelTone, context.AccentColor, 0.15), context.IsNightMode ? (byte)0x7A : (byte)0x99)); + ColorMath.WithAlpha(buttonBackground, context.IsNightMode ? (byte)0x4D : (byte)0x66)); resources["AdaptiveButtonPressedBackgroundBrush"] = new SolidColorBrush( - ColorMath.WithAlpha(ColorMath.Blend(panelTone, context.AccentColor, 0.28), context.IsNightMode ? (byte)0x8C : (byte)0xB3)); + ColorMath.WithAlpha(buttonBackground, context.IsNightMode ? (byte)0x66 : (byte)0x80)); + // 面板颜色 - 使用 Mica 材质 resources["AdaptiveGlassPanelBackgroundBrush"] = new SolidColorBrush( - ColorMath.WithAlpha(panelTone, context.IsNightMode ? (byte)0x4D : (byte)0x66)); - resources["AdaptiveGlassPanelBorderBrush"] = new SolidColorBrush(ColorMath.WithAlpha(neutralElevated, 0x26)); + Color.FromArgb(context.IsNightMode ? (byte)0xE6 : (byte)0xF2, + micaBackground.R, micaBackground.G, micaBackground.B)); + resources["AdaptiveGlassPanelBorderBrush"] = new SolidColorBrush( + Color.FromArgb(0x1F, neutralElevated.R, neutralElevated.G, neutralElevated.B)); resources["AdaptiveGlassStrongBackgroundBrush"] = new SolidColorBrush( - ColorMath.WithAlpha(strongTone, context.IsNightMode ? (byte)0x66 : (byte)0x80)); - resources["AdaptiveGlassStrongBorderBrush"] = new SolidColorBrush(ColorMath.WithAlpha(neutralElevated, 0x33)); + Color.FromArgb(context.IsNightMode ? (byte)0xE6 : (byte)0xF5, + micaElevated.R, micaElevated.G, micaElevated.B)); + resources["AdaptiveGlassStrongBorderBrush"] = new SolidColorBrush( + Color.FromArgb(0x29, neutralElevated.R, neutralElevated.G, neutralElevated.B)); resources["AdaptiveGlassOverlayBackgroundBrush"] = new SolidColorBrush( - ColorMath.WithAlpha(overlayTone, context.IsNightMode ? (byte)0x59 : (byte)0x73)); + Color.FromArgb(context.IsNightMode ? (byte)0xCC : (byte)0xE6, + micaBackground.R, micaBackground.G, micaBackground.B)); - resources["AdaptiveGlassPanelBlurRadius"] = context.IsNightMode ? NightPanelBlurRadius : DayPanelBlurRadius; - resources["AdaptiveGlassStrongBlurRadius"] = context.IsNightMode ? NightStrongBlurRadius : DayStrongBlurRadius; - resources["AdaptiveGlassOverlayBlurRadius"] = context.IsNightMode ? NightOverlayBlurRadius : DayOverlayBlurRadius; - resources["AdaptiveGlassPanelOpacity"] = context.IsNightMode ? 0.85 : 0.80; - resources["AdaptiveGlassStrongOpacity"] = context.IsNightMode ? 0.90 : 0.85; - resources["AdaptiveGlassOverlayOpacity"] = context.IsNightMode ? 0.75 : 0.70; - resources["AdaptiveGlassNoiseOpacity"] = context.IsNightMode ? 0.03 : 0.02; + // 模糊半径(Mica 不需要强模糊) + resources["AdaptiveGlassPanelBlurRadius"] = context.IsNightMode ? 20.0 : 30.0; + resources["AdaptiveGlassStrongBlurRadius"] = context.IsNightMode ? 25.0 : 35.0; + resources["AdaptiveGlassOverlayBlurRadius"] = context.IsNightMode ? 30.0 : 40.0; + + // 不透明度(Mica 材质接近不透明) + resources["AdaptiveGlassPanelOpacity"] = context.IsNightMode ? 0.95 : 0.98; + resources["AdaptiveGlassStrongOpacity"] = context.IsNightMode ? 0.97 : 0.99; + resources["AdaptiveGlassOverlayOpacity"] = context.IsNightMode ? 0.85 : 0.92; + resources["AdaptiveGlassNoiseOpacity"] = context.IsNightMode ? 0.01 : 0.008; } } diff --git a/LanMontainDesktop/Services/LocalizationService.cs b/LanMontainDesktop/Services/LocalizationService.cs new file mode 100644 index 0000000..d004be1 --- /dev/null +++ b/LanMontainDesktop/Services/LocalizationService.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.Json; + +namespace LanMontainDesktop.Services; + +public sealed class LocalizationService +{ + private static readonly JsonSerializerOptions JsonOptions = new() + { + ReadCommentHandling = JsonCommentHandling.Skip, + AllowTrailingCommas = true + }; + + private readonly Dictionary> _cache = + new(StringComparer.OrdinalIgnoreCase); + + public string NormalizeLanguageCode(string? languageCode) + { + return string.Equals(languageCode, "en-US", StringComparison.OrdinalIgnoreCase) + ? "en-US" + : "zh-CN"; + } + + public string GetString(string languageCode, string key, string fallback) + { + var normalizedLanguage = NormalizeLanguageCode(languageCode); + var table = LoadLanguageTable(normalizedLanguage); + return table.TryGetValue(key, out var value) && !string.IsNullOrWhiteSpace(value) + ? value + : fallback; + } + + private Dictionary LoadLanguageTable(string languageCode) + { + if (_cache.TryGetValue(languageCode, out var table)) + { + return table; + } + + var result = new Dictionary(StringComparer.OrdinalIgnoreCase); + try + { + var filePath = Path.Combine(AppContext.BaseDirectory, "Localization", $"{languageCode}.json"); + if (File.Exists(filePath)) + { + var json = File.ReadAllText(filePath); + var data = JsonSerializer.Deserialize>(json, JsonOptions); + if (data is not null) + { + result = new Dictionary(data, StringComparer.OrdinalIgnoreCase); + } + } + } + catch + { + // Keep empty table for resilience. + } + + _cache[languageCode] = result; + return result; + } +} + diff --git a/LanMontainDesktop/Styles/GlassModule.axaml b/LanMontainDesktop/Styles/GlassModule.axaml index 0880e0d..23888c9 100644 --- a/LanMontainDesktop/Styles/GlassModule.axaml +++ b/LanMontainDesktop/Styles/GlassModule.axaml @@ -10,24 +10,27 @@ - + + + - - + + +