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

如何在TagHelper中获取所属标签的子元素实现本地化字符串参数替换

ASP.NET Core 自定义TagHelper实现本地化字符串参数替换方案

核心原理

你无法在TagHelperContext/TagHelperOutput中直接读取子元素,是因为父TagHelper执行时,子节点的Razor渲染、子TagHelper处理逻辑都还未执行,需要主动调用output.GetChildContentAsync()触发子内容的全流程渲染。
我们采用「父TagHelper注册参数容器 -> 子ParameterTagHelper填充参数 -> 父TagHelper替换占位符」的逻辑实现,天然支持嵌套递归场景。


完整实现代码

1. LocaleKeyTagHelper(父标签处理逻辑)

using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Localization;
using Microsoft.AspNetCore.Razor.TagHelpers;
using System.Text.RegularExpressions;

[HtmlTargetElement(Attributes = "locale-key")]
public class LocaleKeyTagHelper : TagHelper
{
    private readonly IStringLocalizer _localizer;
    // 注入项目中使用的本地化服务即可
    public LocaleKeyTagHelper(IStringLocalizer localizer)
    {
        _localizer = localizer;
    }

    [HtmlAttributeName("locale-key")]
    public string LocaleKey { get; set; }
    // 保证父TagHelper晚于子ParameterTagHelper执行
    public override int Order => 1000;

    public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
    {
        // 移除locale-key属性,不在最终HTML中输出
        output.Attributes.RemoveAll("locale-key");

        // 初始化参数字典,通过上下文共享给子TagHelper
        var paramDict = new Dictionary<int, IHtmlContent>();
        context.Items[typeof(LocaleKeyTagHelper)] = paramDict;

        // 触发子元素全流程渲染,子ParameterTagHelper会自动填充参数字典
        _ = await output.GetChildContentAsync(true);

        // 读取本地化字符串
        string localizedText = _localizer[LocaleKey];
        var outputContent = new DefaultHtmlContentBuilder();
        var placeholderRegex = new Regex(@"%(\d+)");
        var matches = placeholderRegex.Matches(localizedText);
        int lastCutIndex = 0;

        // 替换所有参数占位符
        foreach (Match match in matches)
        {
            if (int.TryParse(match.Groups[1].Value, out int paramIndex) 
                && paramDict.TryGetValue(paramIndex, out var paramHtml))
            {
                // 追加占位符之前的纯文本
                outputContent.AppendHtml(localizedText[lastCutIndex..match.Index]);
                // 追加参数对应的HTML内容
                outputContent.AppendHtml(paramHtml);
                lastCutIndex = match.Index + match.Length;
            }
        }
        // 追加最后一段剩余文本
        outputContent.AppendHtml(localizedText[lastCutIndex..]);

        // 设置最终输出内容
        output.Content.SetHtmlContent(outputContent);
    }
}

2. LocaleParameterTagHelper(子参数标签处理逻辑)

using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Razor.TagHelpers;

[HtmlTargetElement(Attributes = "locale-parameter")]
public class LocaleParameterTagHelper : TagHelper
{
    [HtmlAttributeName("locale-parameter")]
    public int ParameterIndex { get; set; }
    // 保证子ParameterTagHelper早于父TagHelper执行
    public override int Order => -1000;

    public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
    {
        // 移除locale-parameter属性,不在最终HTML中输出
        output.Attributes.RemoveAll("locale-parameter");

        // 读取父TagHelper注册的参数字典
        if (context.Items.TryGetValue(typeof(LocaleKeyTagHelper), out var dictObj) 
            && dictObj is Dictionary<int, IHtmlContent> paramDict)
        {
            // 渲染当前标签的完整内容(包含标签自身属性、子内容)存入字典
            paramDict[ParameterIndex] = await output.RenderFullTagAsync();
        }
    }
}

// 扩展方法:将TagHelperOutput渲染为完整的HTML内容
public static class TagHelperOutputExtensions
{
    public static async Task<IHtmlContent> RenderFullTagAsync(this TagHelperOutput output)
    {
        var builder = new DefaultHtmlContentBuilder();
        // 渲染开始标签和属性
        builder.AppendHtml($"<{output.TagName}");
        foreach (var attr in output.Attributes)
        {
            builder.AppendHtml($" {attr.Name}=\"{attr.Value}\"");
        }
        builder.AppendHtml(">");
        // 渲染子内容
        var childContent = await output.GetChildContentAsync(true);
        builder.AppendHtml(childContent);
        // 渲染结束标签
        builder.AppendHtml($"</{output.TagName}>");
        return builder;
    }
}

效果验证

你给出的示例代码:

<h2 locale-key="Hello, %1!">
    <span class="bold" locale-parameter="1">@userName</span>
</h2>

会直接输出预期结果:

<h2>Hello, <span class="bold">Lázár Zsolt</span>!</h2>

如果子span标签也带有locale-key属性,会先完成自身的本地化渲染,再作为参数代入父级字符串,自动支持递归场景。


内容的提问来源于stack exchange,提问作者Lázár Zsolt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 00:21:03