package main import ( "encoding/csv" "errors" "fmt" "io/ioutil" "os" ) const ( langSource = "datagen/language/language_codes.csv" outputFileName = "language_code_info.go" ) type lang struct { code string nameEn string nameNat string } func decodeLang() *[]lang { // read the csv file csvfile, err := os.Open(langSource) if err != nil { fmt.Println(err) os.Exit(1) } defer csvfile.Close() // decode csv file reader := csv.NewReader(csvfile) // there are no empty fields reader.FieldsPerRecord = 3 rawCSVdata, err := reader.ReadAll() if err != nil { fmt.Println(err) os.Exit(1) } // move raw CSV data to struct var row lang var rows []lang for _, v := range rawCSVdata { row.code = v[0] row.nameEn = v[1] row.nameNat = v[2] rows = append(rows, row) } return &rows } func generateSwitch(d []lang) (string, error) { out := `// generated by "go generate"; DO NOT EDIT package langreg import ( "errors" "fmt" ) // LangCodeInfo returns the English and native language in its script for a // given string, and an error if any. If there are more than one official // names for the language (either English or native), they are separated by a // semi-colon (;) // Language codes should always be lowercase, and this is enforced. func LangCodeInfo(s string) (english, native string, err error) { // codes have to be two characters long if len(s) != 2 { return "", "", errors.New("ISO 639-1 language codes must be 2 characters long") } ` c1 := d[0].code[0] out += fmt.Sprintf("\nswitch s[0] {\n\ncase %q:\nswitch s[1]{\n", c1) for _, r := range d { // check that the code is exactly 2 characters long if !isCodeValid(r.code) { return "", fmt.Errorf("The code %q is not 2 characters long", r.code) } // new first letter of code if r.code[0] != c1 { // new first char c1 = r.code[0] out += fmt.Sprintf("}\n\ncase %q:\nswitch s[1]{\n", c1) } out += fmt.Sprintf("case %q:\nreturn %q, %q, nil\n", r.code[1], r.nameEn, r.nameNat) } out += `} } return "", "", fmt.Errorf("%q is not a valid ISO-639-1 language code", s) }` return out, nil } func isCodeValid(s string) bool { if len(s) != 2 { return false } if s[0] < 'a' || s[0] > 'z' || s[1] < 'a' || s[1] > 'z' { return false } return true } func writeFile(s, fileName string) error { b := []byte(s) err := ioutil.WriteFile(fileName, b, 0644) if err != nil { return errors.New("Couldn't write the file") } return nil } func main() { rows := decodeLang() res, _ := generateSwitch(*rows) err := writeFile(res, outputFileName) if err != nil { fmt.Println(err) } else { fmt.Println("language_code_info.go generated") } }