[Go 言語]Echo で validator のエラーを日本語に変換する方法

Go Blue Logo プログラミング

Go 言語validation するときに go-playground/validator を使っているんですが、普通に使うとバリデーションエラー時にフィールド名が構造体の名前のまま表示されてしまいます。

GitHub - go-playground/validator: :100:Go Struct and Field validation, including Cross Field, Cross Struct, Map, Slice and Array diving
:100:Go Struct and Field validation, including Cross Field, ...

日本語で表示、というよりは画面に表示されている項目名と一致させないと、ユーザーが何のエラーが出てるのか分からないので困ってしまいます。
今回は上手くフィールド名の日本語化ができたので、その実装方法を重要な部分だけ抜き出して説明していきたいと思います。

前提条件

  • Go言語 : 1.18.1
  • Echo : 4.7.2

カスタムバリーデータ作成

package infrastructure

import (
    "errors"
    "github.com/go-playground/locales/ja_JP"
    ut "github.com/go-playground/universal-translator"
    "github.com/go-playground/validator/v10"
    ja_translations "github.com/go-playground/validator/v10/translations/ja"
    "github.com/labstack/echo/v4"
    "log"
    "reflect"
)

type CustomValidator struct {
    trans     ut.Translator
    validator *validator.Validate
}

func (cv *CustomValidator) Validate(i interface{}) error {
    err := cv.validator.Struct(i)

    if err == nil {
        return err
    }

    errs := err.(validator.ValidationErrors)
    msg := ""
    for _, ve := range errs.Translate(cv.trans) {
        if msg != "" {
            msg += ", "
        }
        msg += ve
    }
    return errors.New(msg)
}

func NewValidator() echo.Validator {
    japanese := ja_JP.New()
    uni := ut.New(japanese, japanese)
    trans, _ := uni.GetTranslator("ja")

    validate := validator.New()

    validate.RegisterTagNameFunc(func(field reflect.StructField) string {
        fieldName := field.Tag.Get("ja")
        if fieldName == "-" {
            return ""
        }
        return fieldName
    })

    err := ja_translations.RegisterDefaultTranslations(validate, trans)
    if err != nil {
        log.Fatal(err)
    }
    return &CustomValidator{
        trans:     trans,
        validator: validate,
    }
}

このカスタムバリデータでバリデーションエラー時のフィールド名を日本語に変換しています。

構造体をカスタムする

type Admin struct {
    ID       int    `json:"id" gorm:"primary_key"`
    Name     string `json:"name" validate:"required" ja:"名前"`
    Username string `json:"username" validate:"required" db:"username" ja:"ユーザID"`
    Password string `json:"password" validate:"required" ja:"パスワード"`
}

構造体のフィールドにjaというタグを追加しフィールド名に対応する日本語を設定します。このjaというタグがカスタムバリデータのNewValidator関数で使用しているjaとなります。

ルーティング実装部でバリデータ設定

func accessible(c echo.Context) error {
    return c.String(http.StatusOK, "Accessible!!")
}

func NewRouting() {
    e := echo.New()
    e.Debug = true
    e.Logger.SetOutput(os.Stderr)

    e.Use(middleware.Logger())
    //e.Use(middleware.Recover())
    e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
        AllowCredentials: true,
        AllowOrigins:     []string{"*"},
        AllowHeaders: []string{
            echo.HeaderAuthorization,
            echo.HeaderContentType,
        },
        AllowMethods: []string{http.MethodOptions, http.MethodGet, http.MethodHead, http.MethodPut, http.MethodPatch, http.MethodPost, http.MethodDelete},
    }))

    e.Validator = infrastructure.NewValidator()

    e.GET("/", accessible)

    e.Logger.Fatal(e.Start(":8080"))
}

Go 言語 の Web アプリケーションフレームワークの Echo のバリデータにカスタムバリデータを設定しています。
これでフィールド名まで含めたバリデーションの日本語化が実装できます。

最後に

画面から入力された値のバリデーションはロジックの中に入れたくないので、今回のようにルーティング部分に実装するのが良いと思います。フィールド名を日本語に翻訳することはできましたが、多言語対応となると実装方法をもうちょっと考えなければいけないかもしれません。多言語への対応は今後の課題ですね。

スポンサーリンク
スポンサーリンク
プログラミング
スポンサーリンク

コメント

タイトルとURLをコピーしました