Skip to content

Commit

Permalink
Introduce russian message file
Browse files Browse the repository at this point in the history
  • Loading branch information
nao1215 committed Sep 2, 2024
1 parent 6bb9e58 commit 570591a
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 10 deletions.
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,16 @@

The csv package is a library for performing validation when reading CSV or TSV files. Validation rules are specified using struct tags. The csv package read returns which columns of which rows do not adhere to the specified rules.

We are implementing internationalization (i18n) for error messages to make them easier for non-engineers to understand.
We are implementing internationalization (i18n) for error messages.

### Supported languages

- English
- Japanese
- Russian

If you want to add a new language, please create a pull request.
Ref. https://github.com/nao1215/csv/pull/8

## Why need csv package?

Expand Down
25 changes: 17 additions & 8 deletions csv.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,10 @@ func NewCSV(r io.Reader, opts ...Option) (*CSV, error) {
csv := &CSV{
reader: csv.NewReader(r),
}
csv.i18nBundle = i18n.NewBundle(language.English)
csv.i18nBundle.RegisterUnmarshalFunc("yaml", yaml.Unmarshal)
if _, err := csv.i18nBundle.LoadMessageFileFS(LocaleFS, "i18n/en.yaml"); err != nil {
return nil, NewError(csv.i18nLocalizer, "ErrLoadMessageFile", err.Error())
}
if _, err := csv.i18nBundle.LoadMessageFileFS(LocaleFS, "i18n/ja.yaml"); err != nil {
return nil, NewError(csv.i18nLocalizer, "ErrLoadMessageFile", err.Error())

if err := csv.newI18n(); err != nil {
return nil, err
}
csv.i18nLocalizer = i18n.NewLocalizer(csv.i18nBundle, "en")

for _, opt := range opts {
if err := opt(csv); err != nil {
Expand All @@ -70,6 +65,20 @@ func NewCSV(r io.Reader, opts ...Option) (*CSV, error) {
return csv, nil
}

// newI18n initializes the i18n bundle and localizer.
func (c *CSV) newI18n() error {
c.i18nBundle = i18n.NewBundle(language.English)
c.i18nBundle.RegisterUnmarshalFunc("yaml", yaml.Unmarshal)

for _, lang := range []string{"en", "ja", "ru"} {
if _, err := c.i18nBundle.LoadMessageFileFS(LocaleFS, fmt.Sprintf("i18n/%s.yaml", lang)); err != nil {
return NewError(c.i18nLocalizer, "ErrLoadMessageFile", err.Error())
}
}
c.i18nLocalizer = i18n.NewLocalizer(c.i18nBundle, "en")
return nil
}

// Decode reads the CSV and returns the columns that have syntax errors on a per-line basis.
// The strutSlicePointer is a pointer to structure slice where validation rules are set in struct tags.
func (c *CSV) Decode(structSlicePointer any) []error {
Expand Down
34 changes: 33 additions & 1 deletion example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ a,Yulia,25
// line:4 column name: target is not an alphabetic character: value=Den1s
}

func ExampleCSV_InJapanese() {
func ExampleWithJapaneseLanguage() {
input := `id,name,age
1,Gina,23
a,Yulia,25
Expand Down Expand Up @@ -72,3 +72,35 @@ a,Yulia,25
// line:3 column id: ターゲットが数字ではありません: value=a
// line:4 column name: ターゲットがアルファベット文字ではありません: value=Den1s
}

func ExampleWithRussianLanguage() {
input := `id,name,age
1,Gina,23
a,Yulia,25
3,Den1s,30
`
buf := bytes.NewBufferString(input)
c, err := csv.NewCSV(buf, csv.WithRussianLanguage())
if err != nil {
panic(err)
}

type person struct {
ID int `validate:"numeric"`
Name string `validate:"alpha"`
Age int `validate:"gt=24"`
}
people := make([]person, 0)

errs := c.Decode(&people)
if len(errs) != 0 {
for _, err := range errs {
fmt.Println(err.Error())
}
}

// Output:
// line:2 column age: целевое значение не больше порогового значения: threshold=24, value=23
// line:3 column id: целевое значение не является числовым символом: value=a
// line:4 column name: целевое значение не является алфавитным символом: value=Den1s
}
59 changes: 59 additions & 0 deletions i18n/ru.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
- id: "ErrStructSlicePointer"
translation: "значение не является указателем на срез структур"

- id: "ErrInvalidOneOfFormat"
translation: "целевое значение не является одним из допустимых значений"

- id: "ErrInvalidThresholdFormat"
translation: "неверный формат порогового значения"

- id: "ErrInvalidBoolean"
translation: "целевое значение не является булевым типом"

- id: "ErrInvalidAlphabet"
translation: "целевое значение не является алфавитным символом"

- id: "ErrInvalidNumeric"
translation: "целевое значение не является числовым символом"

- id: "ErrInvalidAlphanumeric"
translation: "целевое значение не является буквенно-цифровым символом"

- id: "ErrRequired"
translation: "целевое значение обязательно, но оно пустое"

- id: "ErrEqual"
translation: "целевое значение не равно пороговому значению"

- id: "ErrInvalidThreshold"
translation: "пороговое значение недействительно"

- id: "ErrNotEqual"
translation: "целевое значение равно пороговому значению"

- id: "ErrGreaterThan"
translation: "целевое значение не больше порогового значения"

- id: "ErrGreaterThanEqual"
translation: "целевое значение не больше или равно пороговому значению"

- id: "ErrLessThan"
translation: "целевое значение не меньше порогового значения"

- id: "ErrLessThanEqual"
translation: "целевое значение не меньше или равно пороговому значению"

- id: "ErrMin"
translation: "целевое значение меньше минимального значения"

- id: "ErrMax"
translation: "целевое значение больше максимального значения"

- id: "ErrLength"
translation: "длина целевого значения не равна пороговому значению"

- id: "ErrOneOf"
translation: "целевое значение не является одним из допустимых значений"

- id: "ErrLoadMessageFile"
translation: "не удалось загрузить файл сообщения"
8 changes: 8 additions & 0 deletions option.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,11 @@ func WithJapaneseLanguage() Option {
return nil
}
}

// WithRussianLanguage is an Option that sets the i18n bundle to Russian.
func WithRussianLanguage() Option {
return func(c *CSV) error {
c.i18nLocalizer = i18n.NewLocalizer(c.i18nBundle, "ru")
return nil
}
}

0 comments on commit 570591a

Please sign in to comment.