引言
之前发过一篇两种方法实现国际化WPF国际化的实现方法,后来使用下来感觉使用都不方便,第一种使用xaml资源文件有时候写代码的时候无法预览。
第二种要引用WpfExtensions.Xaml这个第三方库,每个页面都要引入同样的库,写代码的时候一样无法预览。
最近的项目又要做国际化,回看过去的代码,忽然灵机一动,想到可以用文本模板就可以直接实现国际化,又不需要引用第三方库,又不影响写代码时预览。
实现
1.按照之前文章WPF国际化的实现方法的步骤,新建resx文件。
这里推荐使用resxManager这个扩展。
2.创建一个文本模板,并编辑其内容。
模板代码:
<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Xml" #>
<#@ assembly name="System.Xml.Linq" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Xml.Linq" #>
<#@ import namespace="System.IO" #>
<#@ output extension=".cs" #>
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 对此文件的更改可能会导致不正确的行为,
// 并且如果重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
<#
const string ResourceFileName = "I18nResource.resx";
#>
namespace <#=System.Runtime.Remoting.Messaging.CallContext.LogicalGetData("NamespaceHint").ToString()#>;
public class StringResourceProvider : INotifyPropertyChanged
{
public StringResourceProvider()
{
porpertyNames = GetType().GetProperties().Select(p => p.Name);
}
public CultureInfo Culture
{
get => I18nResource.Culture;
set
{
I18nResource.Culture = value;
foreach (var name in porpertyNames)
{
OnPropertyChanged(name);
}
}
}
IEnumerable<string> porpertyNames;
public event PropertyChangedEventHandler? PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public static string? FindResource(string key)
{
return I18nResource.ResourceManager.GetString(key, I18nResource.Culture);
}
public static StringResourceProvider Instance
{
get;
} = new StringResourceProvider();
<#
var resourceKeys = XElement.Load(this.Host.ResolvePath(ResourceFileName))
.Elements("data")
.Select(item => item.Attribute("name")?.Value)
.Where(item => item != null);
var resourceDesignerName = Path.GetFileNameWithoutExtension(ResourceFileName);
foreach (string resourceKey in resourceKeys)
{
#>
public string <#= resourceKey #> => <#= resourceDesignerName #>.<#= resourceKey #>;
<#
}
#>
}
实际内容可根据你自己的资源文件和命名习惯修改。
编辑好文本模板之后保存,visual studio 会问你是否生成代码,点确定即可。
vs会生成一个同名的cs代码。
生成的代码:
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
namespace Eyu.I18nDEMO.I18nResource;
public class StringResourceProvider : INotifyPropertyChanged
{
public StringResourceProvider()
{
porpertyNames = GetType().GetProperties().Select(p => p.Name);
}
public CultureInfo Culture
{
get => I18nResource.Culture;
set
{
I18nResource.Culture = value;
foreach (var name in porpertyNames)
{
OnPropertyChanged(name);
}
}
}
IEnumerable<string> porpertyNames;
public event PropertyChangedEventHandler? PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public static string? FindResource(string key)
{
return I18nResource.ResourceManager.GetString(key, I18nResource.Culture);
}
public static StringResourceProvider Instance
{
get;
} = new StringResourceProvider();
public string hello => I18nResource.hello;
public string Title => I18nResource.Title;
}
3.在wpf或avalonia工程中使用Binding绑定。
4. 每次添加新的资源之后,记得使用文本模板生成一下代码,即可更新。
5. 切换语言
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Button? button = sender as Button;
if (button == null) return;
string? tag = button.Tag.ToString();
if (tag == null) return;
StringResourceProvider.Instance.Culture = new CultureInfo(tag);
}
6. 源代码
https://gitee.com/eyupaopao/wpfi18n-demo.git