WPF或Avalonia使用tt模板和resx文件实现国际化

引言

之前发过一篇两种方法实现国际化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

  • 8
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值