forked from shuyu-labs/WebCode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLanguageSwitcher.razor
More file actions
160 lines (141 loc) · 6.4 KB
/
LanguageSwitcher.razor
File metadata and controls
160 lines (141 loc) · 6.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
@namespace WebCodeCli.Components
@implements IDisposable
@inject WebCodeCli.Domain.Domain.Service.ILocalizationService LocalizationService
@inject IJSRuntime JSRuntime
@* 点击外部关闭下拉菜单的遮罩层 *@
@if (_isOpen)
{
<div class="fixed inset-0 z-40" @onclick="CloseDropdown" @onclick:stopPropagation="false"></div>
}
<div class="relative inline-block text-left z-50">
<button @onclick="ToggleDropdown"
@onclick:stopPropagation="true"
class="flex items-center gap-2 px-3 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500 transition-colors"
type="button">
<!-- Globe Icon -->
<svg class="w-5 h-5 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 5h12M9 3v2m1.048 9.5A18.022 18.022 0 016.412 9m6.088 9h7M11 21l5-10 5 10M12.751 5C11.783 10.77 8.07 15.61 3 18.129"></path>
</svg>
<span class="hidden sm:inline">@GetLanguageDisplayName(_currentLanguage)</span>
<!-- Dropdown Arrow -->
<svg class="w-4 h-4 text-gray-600 transition-transform duration-200 @(_isOpen ? "rotate-180" : "")" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
</svg>
</button>
@if (_isOpen)
{
<div class="absolute right-0 z-50 mt-2 w-48 origin-top-right rounded-lg bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none animate-in fade-in slide-in-from-top-2 duration-200"
@onclick:stopPropagation="true">
<div class="py-1" role="menu">
@foreach (var lang in _supportedLanguages)
{
<button @onclick="() => ChangeLanguage(lang.Code)"
@onclick:stopPropagation="true"
disabled="@_isChangingLanguage"
class="@GetLanguageItemClass(lang.Code) w-full text-left px-4 py-2 text-sm transition-colors disabled:opacity-50"
role="menuitem">
<div class="flex items-center justify-between">
<span>@lang.NativeName</span>
@if (_currentLanguage == lang.Code)
{
<!-- Checkmark Icon -->
<svg class="w-4 h-4 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
</svg>
}
else if (_isChangingLanguage && _targetLanguage == lang.Code)
{
<!-- Loading spinner -->
<svg class="w-4 h-4 text-blue-600 animate-spin" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
}
</div>
<div class="text-xs text-gray-500 mt-0.5">@lang.Name</div>
</button>
}
</div>
</div>
}
</div>
@code {
private bool _isOpen = false;
private bool _isChangingLanguage = false;
private string _currentLanguage = "zh-CN";
private string _targetLanguage = "";
private List<WebCodeCli.Domain.Domain.Service.LanguageInfo> _supportedLanguages = new();
[Parameter]
public EventCallback<string> OnLanguageChanged { get; set; }
protected override async Task OnInitializedAsync()
{
_supportedLanguages = LocalizationService.GetSupportedLanguages();
try
{
_currentLanguage = await LocalizationService.GetCurrentLanguageAsync();
}
catch (Exception ex)
{
Console.WriteLine($"获取当前语言失败: {ex.Message}");
_currentLanguage = "zh-CN";
}
}
private void ToggleDropdown()
{
_isOpen = !_isOpen;
}
private void CloseDropdown()
{
_isOpen = false;
}
private async Task ChangeLanguage(string languageCode)
{
if (_isChangingLanguage || _currentLanguage == languageCode)
{
_isOpen = false;
return;
}
_isChangingLanguage = true;
_targetLanguage = languageCode;
StateHasChanged();
try
{
// 先保存语言设置到本地存储
await LocalizationService.SetCurrentLanguageAsync(languageCode);
// 更新本地状态
_currentLanguage = languageCode;
// 关闭下拉菜单
_isOpen = false;
// 重新加载翻译缓存,避免旧资源残留
await LocalizationService.ReloadTranslationsAsync();
// 通知父组件语言已更改(刷新本地缓存+UI)
await OnLanguageChanged.InvokeAsync(languageCode);
_isChangingLanguage = false;
_targetLanguage = "";
StateHasChanged();
}
catch (Exception ex)
{
Console.WriteLine($"切换语言失败: {ex.Message}");
_isChangingLanguage = false;
_targetLanguage = "";
StateHasChanged();
}
}
private string GetLanguageDisplayName(string languageCode)
{
var lang = _supportedLanguages.FirstOrDefault(l => l.Code == languageCode);
return lang?.NativeName ?? languageCode;
}
private string GetLanguageItemClass(string languageCode)
{
var baseClass = "hover:bg-gray-100";
return _currentLanguage == languageCode
? $"{baseClass} bg-blue-50 font-semibold text-blue-700"
: $"{baseClass} text-gray-700";
}
public void Dispose()
{
// 清理资源(如果有的话)
}
}