我是如何实现站点多语言?
9/19/2024 3

首先,站点默认语言使用英语(EN),支持(中文)CN->EN,EN->CN切换;所以我创建了一个枚举类,如下:

csharp 复制代码
public enum SupportLanguage
{
    /// <summary>
    /// 未设置
    /// </summary>
    NONE = 0,

    /// <summary>
    /// 中文简体
    /// </summary>
    [Description("中文")]
    [Label("中文")]
    CN = 1,

    /// <summary>
    /// 英文
    /// </summary>
    [Description("英文")]
    [Label("English")]
    EN = 2
}

站点默认语言也可以根据客户端地区来,这样是真正的全球化。可以通过请求的header中accept-language获取,也可以通过前端传客户端时区进行识别。

我通过客户端ip作为标识,将用户设置的语种写入缓存,每次多语言应用时调用索引器显示,这里有个本地化核心接口:

csharp 复制代码
/// <summary>
/// 单例模式注入
/// </summary>
public interface ILocalization
{
    /// <summary>
    /// 获取默认语种
    /// </summary>
    /// <param name="ip">客户端IP</param>
    /// <returns></returns>
    SupportLanguage GetDefaultLanguage(string? ip = default);

    /// <summary>
    /// 用户设置语言
    /// </summary>
    /// <param name="lan">语种value</param>
    /// <returns></returns>
    void SetUserLanguage(int lan);

    /// <summary>
    /// 获取当前语种对应翻译
    /// </summary>
    /// <param name="key">多语言KEY,唯一</param>
    /// <param name="defaultContent">默认内容</param>
    /// <param name="args">占位符参数</param>
    /// <returns></returns>
    string this[string key, string? defaultContent = default, params string[] args] { get; }

    /// <summary>
    /// 初始化
    /// </summary>
    void Initialization();
}

在程序一启动时,我使用后台服务,初始化了ILocalization.Initialization();,这个初始化方法将多语言配置json加载到冻结字典(FrozenDictionary)中,这样就能快速读取;代码:

csharp 复制代码
public void Initialization()
{
    if (_keyValuePairs == null)
    {
        lock (_lockObj)
        {
            _keyValuePairs ??= new ConcurrentDictionary<string, string>();
        }
    }
    var dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Localization");
    if (Directory.Exists(dir))
    {
        var strs = Directory.GetFiles(dir);
        foreach (var item in strs)
        {
            var file = new FileInfo(item);
            if (File.Exists(item))
            {
                var suffix = Path.GetExtension(item);
                var lan = file.Name.Replace(suffix, "").ToUpper();
                using var stream = file.OpenRead();
                try
                {
                    var map = JsonSerializer.Deserialize<Dictionary<string, string>>(stream);
                    if (map != null)
                    {
                        foreach (var mapItem in map)
                        {
                            var key = string.Concat(mapItem.Key, "_", lan);
                            _keyValuePairs.TryAdd(key, mapItem.Value);
                        }
                    }
                }
                catch (Exception) { }
            }
        }
        _readMap = _keyValuePairs.ToFrozenDictionary();
    }
}

多语言文件:

多语言示例:

EN.json

json 复制代码
{
  "Home": "Home",
  "Posts": "Posts",
  "Archive": "Archive",
  "About": "About",
  "Title": "Cracker"
}

CN.json

json 复制代码
{
  "Home": "首页",
  "Posts": "帖子",
  "Archive": "归档",
  "About": "关于",
  "Title": "潜心驿站"
}

json的key,value对应刚好是字典的key,value;只不过字典的key后面拼了语种"_CN"或"_EN"

翻译中可能需要占位符,所以我设计了读取方法有参数;避免key可能不存在导致的空显示,我还增加了默认内容

完全所有功能后,我们再去替换需要多语言的地方,如:

razor 复制代码
<h5 class="mb-4">@localization["MyProjects","My Projects"]</h5>

综上所述,适合适合个人网站,公司官网的多语言/全球化功能就轻松实现了;如果我们要新增语种,只需要新加枚举,新加语种json翻译文件即可,代码简单,性能好。


Comments