WPF-实现多语言的静态(需重启)与动态切换(不用重启)
目录
一、多语言切换(需重启)
1、配置文件添加Key
2、新增附加属性当前选择语言
3、创建资源文件
4、初始化多语言集合
5、切换多语言并更新配置文件
6、应用程序启动根据配置切换多语言
7、使用
二、多语言切换(无需重启)
1、创建多语言标记扩展基类
2、添加资源转换器
3、创建资源文件
4、继承基类创建指定资源文件扩展
5、添加资源文件管理
6、切换语言
7、使用
8、后台使用多语言
①获取多语言资源字符串
②后台绑定
一、多语言切换(需重启)
1、配置文件添加Key
<appSettings>
<add key="language" value="zh-CN"/>
</appSettings>
2、新增附加属性当前选择语言
public CultureInfo SelectLanguage
{
get => (CultureInfo)GetValue(SelectLanguageProperty);
set => SetValue(SelectLanguageProperty, value);
}
public static readonly DependencyProperty SelectLanguageProperty =
DependencyProperty.Register("SelectLanguage", typeof(CultureInfo), typeof(MainWindow));
3、创建资源文件
4、初始化多语言集合
public ObservableCollection<CultureInfo> CultureInfos { get; private set; } = new ObservableCollection<CultureInfo>();
private void Window_Loaded(object sender, RoutedEventArgs e)
{
var dir =Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
var curs = CultureInfo.GetCultures(CultureTypes.AllCultures);
foreach (CultureInfo cur in curs)
{
if (string.IsNullOrWhiteSpace(cur.Name)) continue;
string landir = Path.Combine(dir, cur.Name);
if (Directory.Exists(landir)) CultureInfos.Add(cur);
}
if (CultureInfos.Any(cur => cur.Name.Equals("zh-CN", StringComparison.OrdinalIgnoreCase)) is false)
{
var cur = curs.FirstOrDefault(c => c.Name.Equals("zh-CN", StringComparison.OrdinalIgnoreCase));
if (cur != null) CultureInfos.Add(cur);
}
SelectLanguage = Thread.CurrentThread.CurrentCulture;
}
5、切换多语言并更新配置文件
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
base.OnPropertyChanged(e);
if (e.Property == SelectLanguageProperty)
{
if (SelectLanguage == Thread.CurrentThread.CurrentCulture) return;
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
if (ConfigurationManager.AppSettings["language"] is null)
config.AppSettings.Settings.Add("language", SelectLanguage.Name);
else
config.AppSettings.Settings["language"].Value = SelectLanguage.Name;
config.Save();
ConfigurationManager.RefreshSection("appSettings");
}
}
6、应用程序启动根据配置切换多语言
/// <summary>
/// App.xaml 的交互逻辑
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var lan= ConfigurationManager.AppSettings["language"];
if (!string.IsNullOrWhiteSpace(lan))
{
CultureInfo culture = new CultureInfo(lan);
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
}
}
}
7、使用
①映射命名空间
xmlns:rs="clr-namespace:WpfApp8.Resources"
②示例
<Grid>
<GroupBox x:Name="gbox">
<Grid>
<Button Width="100"
Height="80"
Background="LightGray"
Content="{x:Static rs:SRS.TestLan}" />
<ComboBox Width="150"
Height="50"
HorizontalAlignment="Left"
VerticalContentAlignment="Center"
DisplayMemberPath="NativeName"
ItemsSource="{Binding Path=CultureInfos, ElementName=MW}"
SelectedItem="{Binding Path=SelectLanguage, ElementName=MW}" />
</Grid>
</GroupBox>
</Grid>
二、多语言切换(无需重启)
安装Nuget包:WpfExtensions.Xaml
1、创建多语言标记扩展基类
/// <summary>
/// 多语言绑定扩展基类
/// </summary>
/// <typeparam name="T">多语言文件资源类</typeparam>
[MarkupExtensionReturnType(typeof(object))]
public class LanguageExtensionBase<T> : MarkupExtension where T : class
{
private static readonly ResourceConverter ResourceConverter = new ResourceConverter();
[ConstructorArgument("Key")]
public ComponentResourceKey Key { get; set; }
public LanguageExtensionBase(string key)
{
Key = new ComponentResourceKey(typeof(T), key);
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (Key == null)
{
throw new NullReferenceException("Key cannot be null at the same time.");
}
IProvideValueTarget provideValueTarget = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
if (provideValueTarget == null)
{
throw new ArgumentException("The serviceProvider must implement IProvideValueTarget interface.");
}
if (provideValueTarget.TargetObject?.GetType().FullName == "System.Windows.SharedDp")
{
return this;
}
return new Binding("Value")
{
Source = new I18nSource(Key, provideValueTarget.TargetObject),
Mode = BindingMode.OneWay,
Converter = ResourceConverter
}.ProvideValue(serviceProvider);
}
}
2、添加资源转换器
/// <summary>
/// 资源转换器
/// </summary>
public class ResourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Bitmap val = (Bitmap)((value is Bitmap) ? value : null);
if (val == null)
{
Icon val2 = (Icon)((value is Icon) ? value : null);
if (val2 != null)
{
return ToBitmapSource(val2.ToBitmap());
}
return value;
}
return ToBitmapSource(val);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
[DllImport("gdi32")]
private static extern int DeleteObject(IntPtr o);
public ImageSource ToBitmapSource(Bitmap bitmap)
{
IntPtr ptr = bitmap.GetHbitmap(); //obtain the Hbitmap
BitmapSource bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(ptr, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
DeleteObject(ptr); //release the HBitmap
return bitmapSource;
}
}
3、创建资源文件
4、继承基类创建指定资源文件扩展
/// <summary>
/// 多语言绑定扩展
/// </summary>
[MarkupExtensionReturnType(typeof(object))]
internal class LanguageExtension : LanguageExtensionBase<DefaultLanguage>
{
public LanguageExtension(string key) : base(key)
{
}
}
5、添加资源文件管理
try
{
I18nManager.Instance.Add(Resource.ResourceManager);
}
catch (ArgumentException)
{
}
6、切换语言
var culture = new CultureInfo("en-US");
I18nManager.Instance.CurrentUICulture = culture;
System.Threading.Thread.CurrentThread.CurrentCulture = culture;
7、使用
①映射命名空间到XAML
xmlns:Lan="clr-namespace:SqlSugarTest.Lan"
②资源文件中添加多语言资源
③示例
<GroupBox Header="多语言测试">
<Menu Height="NaN" HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="{x:Null}"
FontSize="12" FontWeight="Bold">
<MenuItem Margin="3" Padding="10,8"
HorizontalAlignment="Center"
HorizontalContentAlignment="Center"
Header="{Lan:Language MultiLanguage}">
<MenuItem Margin="3" Padding="10,5"
Click="MenuItem_Click_CN" Header="CN-中" />
<MenuItem Margin="3" Padding="10,5"
Click="Button_Click_EN" Header="US-英" />
<MenuItem Margin="3" Padding="10,5"
Header="Test">
<MenuItem Margin="3" Padding="10,5"
Header="111" />
<MenuItem Margin="3" Padding="10,5"
Header="222" />
</MenuItem>
</MenuItem>
</Menu>
</GroupBox>
8、后台使用多语言
①获取多语言资源字符串
/// <summary>
/// 获取Key资源
/// </summary>
/// <param name="key"></param>
/// <param name="resource"></param>
/// <returns></returns>
public static string GetString(string key, ResourceManager resource = null)
{
if (resource == null)
return DefaultLanguage.ResourceManager.GetString(key, I18nManager.Instance.CurrentUICulture);
else
return resource.GetString(key, I18nManager.Instance.CurrentUICulture);
}
MessageBox.Show(GetString(nameof(DefaultLanguage.Test)));
②后台绑定
static readonly ResourceConverter converter = new ResourceConverter();
/// <summary>
/// 按自定义数据绑定多语言
/// </summary>
/// <typeparam name="T">自定义数据源</typeparam>
/// <param name="key">数据关键字</param>
/// <returns></returns>
public static BindingBase GetBinding<T>(string key, object element = null)
{
var Key = new ComponentResourceKey(typeof(T), key);
return new Binding("Value")
{
Source = new I18nSource(Key, element),
Mode = BindingMode.OneWay,
Converter = converter
};
}
menu_Test.SetBinding(MenuItem.HeaderProperty, GetBinding<DefaultLanguage>(nameof(DefaultLanguage.Test)));