Skip to content

Instantly share code, notes, and snippets.

@konifar
Created December 11, 2023 00:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save konifar/b8bc780038bd28dfbf51e3b0795f7eb5 to your computer and use it in GitHub Desktop.
Save konifar/b8bc780038bd28dfbf51e3b0795f7eb5 to your computer and use it in GitHub Desktop.
package main
import (
"flag"
"fmt"
mapset "github.com/deckarep/golang-set/v2"
"log"
"os"
"path/filepath"
"regexp"
"strings"
"github.com/BurntSushi/toml"
)
var (
localeFileDir string
)
func init() {
flag.StringVar(&localeFileDir, "localeFileDir", ".", "Localeファイルのあるディレクトリ")
}
// go run scripts/i18n_locale_file_checker/main.go -localeFileDir=helpers/i18n
func main() {
flag.Parse()
jaFilePath := filepath.Join(localeFileDir, "ja.toml")
jaKeyMap, err := readLocaleKeyMap(jaFilePath)
if err != nil {
log.Fatal(err)
}
// 問題のあるファイルがあるかどうか
existInvalidFiles := false
fmt.Println("ja.tomlファイルのチェック開始...")
// mapのバリューに%s、%v、%q、%dが含まれていないかのチェック
existInvalidFiles = !checkTemplateString(jaKeyMap)
// ディレクトリ内の他のtomlファイルをひとつずつチェック
err = filepath.Walk(localeFileDir, func(path string, info os.FileInfo, err error) error {
if info.IsDir() || filepath.Ext(path) != ".toml" || path == jaFilePath {
return nil
}
lang := strings.TrimSuffix(filepath.Base(path), filepath.Ext(path)) // 拡張子(.toml)を除いたファイル名を言語コードとして取得
fmt.Printf("%s.tomlファイルのチェック開始...\n", lang)
foreignKeyMap, err := readLocaleKeyMap(path)
if err != nil {
log.Fatal(err)
}
// キーが過不足ないかどうかのチェック
existInvalidFiles = !checkKeysCount(jaKeyMap, foreignKeyMap)
// mapのバリューに%s、%v、%q、%dが含まれていないかのチェック
existInvalidFiles = !checkTemplateString(foreignKeyMap)
// テンプレート文字列 {{}} のキーが一致するかのチェック
existInvalidFiles = !checkTemplateKeys(jaKeyMap, foreignKeyMap, lang)
return nil
})
if err != nil {
log.Fatal(err)
}
if existInvalidFiles {
os.Exit(1)
}
}
// 2つのmapのキーが過不足ある場合にfalseを返す
func checkKeysCount(jaKeyMap map[string]string, foreignKeyMap map[string]string) bool {
jaKeySet := convertMapToSet(jaKeyMap)
foreignKeySet := convertMapToSet(foreignKeyMap)
missingKeys := foreignKeySet.Difference(jaKeySet).ToSlice() // 他の言語ファイルにのみ含まれるキー
extraKeys := jaKeySet.Difference(foreignKeySet).ToSlice() // ja.tomlにのみ含まれるキー
if len(missingKeys) > 0 {
fmt.Println(" 以下のキーが含まれていません")
for _, key := range missingKeys {
fmt.Printf(" - %s\n", key)
}
return false
}
if len(extraKeys) > 0 {
fmt.Println(" 以下のキーが余分に含まれています")
for _, key := range extraKeys {
fmt.Printf(" - %s\n", key)
}
return false
}
if len(missingKeys) == 0 && len(extraKeys) == 0 {
fmt.Println(" キーは過不足なく一致しています")
}
return true
}
// テンプレート文字列 {{}} のキー一覧を抽出する
func extractTemplateKeys(s string) mapset.Set[string] {
re := regexp.MustCompile(`{{\.(.*?)}}`)
matches := re.FindAllStringSubmatch(s, -1)
keys := mapset.NewSet[string]()
for _, match := range matches {
if len(match) > 1 {
keys.Add(strings.TrimSpace(match[1]))
}
}
return keys
}
// テンプレート文字列 {{}} のキーが一致するかをチェック
func checkTemplateKeys(jaKeyMap map[string]string, foreignKeyMap map[string]string, lang string) bool {
validTemplateKeys := true
for key, value := range jaKeyMap {
jaTemplateKeys := extractTemplateKeys(value)
foreignValue := foreignKeyMap[key]
foreignTemplateKeys := extractTemplateKeys(foreignValue)
if !jaTemplateKeys.Equal(foreignTemplateKeys) {
validTemplateKeys = false
fmt.Printf(" key:%s のテンプレート文字列が ja.toml と違います, ja: %v, %s: %v\n", key, jaTemplateKeys, lang, foreignTemplateKeys)
}
}
return validTemplateKeys
}
// mapのバリューに%s、%v、%q、%dが含まれていないかをチェック
func checkTemplateString(keyMap map[string]string) bool {
substrings := []string{"%s", "%v", "%q", "%d"}
validTemplateString := true
for key, value := range keyMap {
for _, sub := range substrings {
if strings.Contains(value, sub) {
validTemplateString = false
fmt.Printf(" key:%s に %s が含まれています, value: %s\n", key, sub, value)
}
}
}
return validTemplateString
}
// Localeファイルからキーと値の一覧を取得
func readLocaleKeyMap(filename string) (map[string]string, error) {
keys := make(map[string]string)
_, err := toml.DecodeFile(filename, &keys)
if err != nil {
return nil, err
}
return keys, nil
}
func convertMapToSet(stringMap map[string]string) mapset.Set[string] {
set := mapset.NewSet[string]()
for key := range stringMap {
set.Add(key)
}
return set
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment