Avalonia使用XAML资源实现动态多语言适配i18n

在WPF项目中,我们可以新建XAML,新建一个ResourceDictionary,存放字符串;XAML显示时使用{DynamicResource xxxx}的方式,来实现动态的多语言功能。(比如这篇文章就是这样做的)

Avalonia中,我们也可以使用类似的方法来实现这个功能。

准备工作

这里我们直接新建一个Avalonia MVVM的工程模板。

我们在Assets文件夹下新建一个Languages文件夹,然后在其中新建zh-CN.axamlen-US.axaml

new dir

我们在其中填入以下内容:

zh-CN.axaml

<ResourceDictionary
    xmlns="https://github.com/avaloniaui"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:system="clr-namespace:System;assembly=mscorlib">
    <system:String x:Key="JustTest">只是个测试</system:String>
</ResourceDictionary>

en-US.axaml

<ResourceDictionary
    xmlns="https://github.com/avaloniaui"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:system="clr-namespace:System;assembly=mscorlib">
    <system:String x:Key="JustTest">Just a test</system:String>
</ResourceDictionary>

使用ResourceDictionary里的内容

App.axaml中,我们在Application层级下添加一个Resources数据(如果已有Resources项,就加入其中),在其中放入一个ResourceDictionary数据:

<Application
...>
    ...
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceInclude Source="/Assets/Languages/zh-CN.axaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
    ...
</Application>

这是我们就可以在其他xaml中使用这个默认的资源了,比如我们在MainWindow.axaml里加上下面的内容:

...
    <TextBlock
        HorizontalAlignment="Center"
        VerticalAlignment="Center"
        Text="{DynamicResource JustTest}" />
...

这里的DynamicResource就可以直接调用ResourceDictionary中对应的数据

切换资源文件实现切换语言功能

切换语言资源文件十分简单,只需要把对应的Resources内容换掉就可以。

比如我们这里的语言文件是第一个Resources,那么可以直接用如下函数替换资源:

public static void ChangeLanguage(string language)
{
    var file = $"avares://TestLanguages/Assets/Languages/{language}.axaml";
    var data = new ResourceInclude(new Uri(file, UriKind.Absolute));
    data.Source = new Uri(file, UriKind.Absolute);
    Avalonia.Application.Current!.Resources.MergedDictionaries[0] = data;
}

我们可以在MainWindow.axaml里加上两个按钮测试一下功能是否正常:

...
    <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
        <TextBlock Text="{DynamicResource JustTest}" />
        <Button Click="ButtonClicked" Content="zh-CN" />
        <Button Click="ButtonClicked" Content="en-US" />
    </StackPanel>
...

MainWindow.axaml.cs里的按键事件:

private void ButtonClicked(object sender, Avalonia.Interactivity.RoutedEventArgs e)
{
    var language = ((Button)sender).Content.ToString();
    Utils.ChangeLanguage(language);
    //我把ChangeLanguage函数放进了Utils类里,这里按你实际的位置调用它即可
}

这样就可以实现动态的切换语言了

test gif

在C#中获取资源值

既然xaml里可以使用多语言,那么C#代码中也一定有获取这些值的需求,实际也很简单。

这些资源不一定都是字符串,所以我这里封装为泛型的接口,这样更通用,可以直接通过名称获取对应的值:

public static T GetLanguageResource<T>(string name)
{
    try
    {
        Avalonia.Application.Current!.TryFindResource(name, out object value);
        return (T)value;
    }
    catch
    {
        if (typeof(T) == typeof(string))
            return (T)(object)"??";
        else
            return default!;
    }
}

END

基本要用到的就是这些了,和WPF的逻辑区别不大,只是加载逻辑不太一样而已。

发表评论

您的电子邮箱地址不会被公开。