start_time: 2024-04-25 10:26:35 +0800

golang validator参数校验 中文

96
darcyaf
IP属地: 天津
0.1 2020.04.05 20:36 字数 886

今天在改后台页面,参数校验错误时输出全是英文,使用着很难看懂到底时什么错了
故而决定去做i18n前端国际化. 改的时候踩了很多坑,故而记录一下,顺便记录以下查问题的方式。

效果

从原来的Title is required变为标题为必填字段

完成后的代码:

这里主要定义了初始化了一个中文的trans和Validate的变量,并对其做初始化
初始化主要做了以下事情:

  1. 注册了TagName函数
    // RegisterTagNameFunc registers a function to get alternate names for StructFields.
    这个方法主要就是提供一个tag的解析器,返回一个Field替代的字符串
    我自己是定义了一个label的tag用于替换
  2. 注册了validate的翻译函数
    直接使用了原来提供的中文转换,对required等标签做对应的国际化
package service

import (
    zhongwen "github.com/go-playground/locales/zh"
    ut "github.com/go-playground/universal-translator"
    "github.com/go-playground/validator/v10"
    zh_translations "github.com/go-playground/validator/v10/translations/zh"
    "reflect"
    "strings"
)

var Validate *validator.Validate
var trans ut.Translator

func init() {
    zh := zhongwen.New()
    uni := ut.New(zh, zh)
    trans, _ = uni.GetTranslator("zh")

    Validate = validator.New()
    Validate.RegisterTagNameFunc(func(field reflect.StructField) string {
        label := field.Tag.Get("label")
        if label == "" {
            return field.Name
        }
        return label
    })
    zh_translations.RegisterDefaultTranslations(Validate, trans)
}
func Translate(errs validator.ValidationErrors) string {
    var errList []string
    for _, e := range errs {
        // can translate each error one at a time.
        errList = append(errList,e.Translate(trans))
    }
    return strings.Join(errList,"|")
}

调用方式

type ArticlesPost struct {
    Title           string  `json:"title" validate:"required,max=32,min=4" label:"标题"`
}
var ap ArticlePost
err = service.Validate.Struct(ap)
if err!=nil{
  errStr =Translate(errs)
  fmt.Sprintln(errStr)
}

思路

  1. 最刚开始去百度查了,无果
  2. 查了iris的文档,也无果
  3. 去看了validate的文档,找到了universal-translator 这个包,可以初步将is required等样式改为必填字段
  4. 还是没法将字段名映射成中文,google搜索到了How can I translate fieldName? #364这个issue,评论里给出了en.Add("MyField", "Field", false)的方式添加字段的映射,最后在alidate.RegisterTranslation注册required的时候,通过T方法转换成对应的中文fld, _ := ut.T(fe.Field()),考虑到要每次都注册Struct的字段,而且全局的同一个key肯定没法定义不同的值,弃用
  5. 第一次想着是不是校验本身已经提供了对应的位置,看了interface,有些英文半知半解,没找到结果,放弃
  6. 继续,想到是不是可以自定义tag,然后重写type TranslationFunc func(ut ut.Translator, fe FieldError) string 函数,想在这个翻译阶段,去动态过去struct中那个tag的值,这样就不会重复了.
  7. 研究了这个函数的传参,FieldError中已经只剩下字段对应的数据了,无法获取到tag信息,差点已经想放弃了
  8. 再次研究validator关于tag的函数
    第一个是设置一个新的tag来替换validate,另一个的说明是注册一个方法来为结构体字段获取替换的名字
    仔细看看说明,果然就是这个,在看看TagNameFunc的签名,参数是reflect.StructField,能够拿到tag等一系列信息
// TagNameFunc allows for adding of a custom tag name parser
type TagNameFunc func(field reflect.StructField) string
// SetTagName allows for changing of the default tag name of 'validate'
func (v *Validate) SetTagName(name string) {
    v.tagName = name
}

// RegisterTagNameFunc registers a function to get alternate names for StructFields.
//
// eg. to use the names which have been specified for JSON representations of structs, rather than normal Go field names:
//
//    validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
//        name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
//        if name == "-" {
//            return ""
//        }
//        return name
//    })
func (v *Validate) RegisterTagNameFunc(fn TagNameFunc) {
    v.tagNameFunc = fn
    v.hasTagNameFunc = true
}

至此,终于找到了正确的解决方案

总结

在这里发现为了解决这个问题走了很多弯路,查了一大堆资料才发现甚至原来就有提供该功能。
发现自己的几个问题:

  1. 英文不是很好,偶尔有些单词不认识,阻止了进一步发现问题,这里也突然想到,英语好一些确实可以在学编程这个路子上受益匪浅
  2. 看文档不是很仔细,鄙人觉得大部分的编程问题都不是很高深,能读得懂错误是什么意思,然后去查查文档或者搜索引擎就能解决,另一个是大部分的编程文档还是英文好一些,细节性的东西在翻译的时候可能会被略掉。
最后编辑于 :2020-04-05 20:36:19
©著作权归作者所有,转载或内容合作请联系作者
序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
783c64db 45e5 48d7 82e4 95736f50533e 沈念sama 阅读 158560 评论 4 赞 361
序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
783c64db 45e5 48d7 82e4 95736f50533e 沈念sama 阅读 67104 评论 1 赞 291
文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
8 开封第一讲书人 阅读 108297 评论 0 赞 243
文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
8 开封第一讲书人 阅读 43869 评论 0 赞 204
正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
388e473c fe2f 40e0 9301 e357ae8f1b41 茶点故事 阅读 52275 评论 3 赞 287
文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
8 开封第一讲书人 阅读 40563 评论 1 赞 216
那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
783c64db 45e5 48d7 82e4 95736f50533e 沈念sama 阅读 31833 评论 2 赞 312
文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
8 开封第一讲书人 阅读 30543 评论 0 赞 197
序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
783c64db 45e5 48d7 82e4 95736f50533e 沈念sama 阅读 34245 评论 1 赞 241
正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
388e473c fe2f 40e0 9301 e357ae8f1b41 茶点故事 阅读 30512 评论 2 赞 244
正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
388e473c fe2f 40e0 9301 e357ae8f1b41 茶点故事 阅读 32011 评论 1 赞 258
序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
783c64db 45e5 48d7 82e4 95736f50533e 沈念sama 阅读 28359 评论 2 赞 253
正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
388e473c fe2f 40e0 9301 e357ae8f1b41 茶点故事 阅读 33006 评论 3 赞 235
文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
8 开封第一讲书人 阅读 26062 评论 0 赞 8
文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
8 开封第一讲书人 阅读 26825 评论 0 赞 194
我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
783c64db 45e5 48d7 82e4 95736f50533e 沈念sama 阅读 35590 评论 2 赞 273
正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
388e473c fe2f 40e0 9301 e357ae8f1b41 茶点故事 阅读 35501 评论 2 赞 268
end_time: 2024-04-25 10:26:35 +0800 Completed in 149.171884ms