You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET本地化扩展:资源未找到时即时翻译实现咨询

实现Blazor .NET 6服务器端SQL本地化+即时翻译方案

核心思路是扩展ASP.NET本地化体系中的IStringLocalizer接口,在获取本地化字符串的环节捕获资源未找到的情况,触发即时翻译逻辑。以下是具体实现步骤:


1. 封装翻译API服务

先把Google/Deepl的翻译API封装成独立服务,便于复用和维护:

public interface ITranslationService
{
    // text: 待翻译文本;sourceLang: 源语言代码;targetLang: 目标语言代码
    Task<string> TranslateAsync(string text, string sourceLang, string targetLang);
}

// Google翻译API实现示例
public class GoogleTranslationService : ITranslationService
{
    private readonly HttpClient _httpClient;
    private readonly string _apiKey = "你的Google API密钥";

    public GoogleTranslationService(HttpClient httpClient) => _httpClient = httpClient;

    public async Task<string> TranslateAsync(string text, string sourceLang, string targetLang)
    {
        try
        {
            var url = $"https://translation.googleapis.com/language/translate/v2?q={Uri.EscapeDataString(text)}&source={sourceLang}&target={targetLang}&key={_apiKey}";
            var response = await _httpClient.GetAsync(url);
            response.EnsureSuccessStatusCode();
            
            var result = await response.Content.ReadFromJsonAsync<GoogleTranslationResponse>();
            return result?.Data?.Translations?.FirstOrDefault()?.TranslatedText ?? text;
        }
        catch (Exception ex)
        {
            // 翻译失败时返回原文本,避免影响业务
            return text;
        }
    }
}

// 对应Google API的响应模型
public class GoogleTranslationResponse
{
    public TranslationData Data { get; set; }
}
public class TranslationData
{
    public List<Translation> Translations { get; set; }
}
public class Translation
{
    public string TranslatedText { get; set; }
}

2. 实现带 fallback 翻译的自定义StringLocalizer

继承或包装你现有的SQL本地化IStringLocalizer实现,在获取字符串时检查资源是否存在,不存在则调用翻译API:

public class SqlWithFallbackTranslateLocalizer : IStringLocalizer
{
    private readonly IStringLocalizer _sqlLocalizer;
    private readonly ITranslationService _translationService;
    private readonly IMemoryCache _cache;
    private readonly ILogger<SqlWithFallbackTranslateLocalizer> _logger;

    public SqlWithFallbackTranslateLocalizer(
        IStringLocalizer sqlLocalizer,
        ITranslationService translationService,
        IMemoryCache cache,
        ILogger<SqlWithFallbackTranslateLocalizer> logger)
    {
        _sqlLocalizer = sqlLocalizer;
        _translationService = translationService;
        _cache = cache;
        _logger = logger;
    }

    // 处理无参数的本地化字符串
    public LocalizedString this[string name]
    {
        get
        {
            var localizedString = _sqlLocalizer[name];
            if (!localizedString.ResourceNotFound)
                return localizedString;

            // 尝试从缓存获取翻译结果
            var cacheKey = $"translation_{name}_{CultureInfo.CurrentUICulture.Name}";
            if (_cache.TryGetValue(cacheKey, out string cachedText))
                return new LocalizedString(name, cachedText, false);

            // 调用翻译API(注意:Blazor同步上下文需避免死锁,这里用ConfigureAwait(false))
            var targetLang = CultureInfo.CurrentUICulture.Name;
            var translatedText = _translationService.TranslateAsync(name, "zh-CN", targetLang)
                .ConfigureAwait(false).GetAwaiter().GetResult();

            // 缓存翻译结果,有效期1小时
            _cache.Set(cacheKey, translatedText, TimeSpan.FromHours(1));
            _logger.LogInformation($"自动翻译资源:{name} -> {targetLang}");

            // 可选:将翻译结果存入SQL表,避免后续重复调用API
            // _sqlLocalizer.SaveTranslation(name, targetLang, translatedText);

            return new LocalizedString(name, translatedText, false);
        }
    }

    // 处理带参数的本地化字符串
    public LocalizedString this[string name, params object[] arguments]
    {
        get
        {
            var localizedString = _sqlLocalizer[name, arguments];
            if (!localizedString.ResourceNotFound)
                return localizedString;

            var cacheKey = $"translation_{name}_{CultureInfo.CurrentUICulture.Name}";
            if (!_cache.TryGetValue(cacheKey, out string cachedText))
            {
                var targetLang = CultureInfo.CurrentUICulture.Name;
                cachedText = _translationService.TranslateAsync(name, "zh-CN", targetLang)
                    .ConfigureAwait(false).GetAwaiter().GetResult();
                _cache.Set(cacheKey, cachedText, TimeSpan.FromHours(1));
            }

            var formattedText = string.Format(cachedText, arguments);
            return new LocalizedString(name, formattedText, false);
        }
    }

    // 实现接口其他方法,直接委托给原SQL Localizer
    public IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures)
        => _sqlLocalizer.GetAllStrings(includeParentCultures);

    public IStringLocalizer WithCulture(CultureInfo culture)
    {
        var sqlLocalizerWithCulture = _sqlLocalizer.WithCulture(culture);
        return new SqlWithFallbackTranslateLocalizer(sqlLocalizerWithCulture, _translationService, _cache, _logger);
    }
}

3. 注册自定义本地化组件

在Program.cs中替换原有的SQL本地化服务,注入自定义Localizer和翻译服务:

var builder = WebApplication.CreateBuilder(args);

// 添加本地化基础配置
builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");

// 注册翻译服务
builder.Services.AddHttpClient<ITranslationService, GoogleTranslationService>();

// 注册自定义Localizer(假设你原有的SQL Localizer类型是SqlStringLocalizer)
builder.Services.AddScoped<IStringLocalizer>(sp =>
{
    var sqlLocalizer = sp.GetRequiredService<SqlStringLocalizer>();
    var translationService = sp.GetRequiredService<ITranslationService>();
    var cache = sp.GetRequiredService<IMemoryCache>();
    var logger = sp.GetRequiredService<ILogger<SqlWithFallbackTranslateLocalizer>>();
    return new SqlWithFallbackTranslateLocalizer(sqlLocalizer, translationService, cache, logger);
});

// 其他服务注册...

var app = builder.Build();

// 配置本地化中间件
var supportedCultures = new[] { "zh-CN", "en-US", "ja-JP" };
var localizationOptions = new RequestLocalizationOptions()
    .SetDefaultCulture(supportedCultures[0])
    .AddSupportedCultures(supportedCultures)
    .AddSupportedUICultures(supportedCultures);

app.UseRequestLocalization(localizationOptions);

// 其他中间件配置...

app.Run();

关键注意事项

  1. 异步处理优化:由于Blazor服务器端的同步调用限制,翻译API调用使用ConfigureAwait(false).GetAwaiter().GetResult()避免死锁,同时建议对高频翻译内容添加缓存。
  2. 成本控制:添加内存缓存或分布式缓存,减少API调用次数;可选将翻译结果持久化到SQL表,后续请求直接从SQL读取。
  3. 错误容错:翻译API调用失败时返回原文本,避免影响业务流程;添加日志记录翻译失败情况。

内容的提问来源于stack exchange,提问作者Dr. Lee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 20:55:20