mirror of
				https://github.com/TeaOSLab/EdgeCommon.git
				synced 2025-11-04 05:00:24 +08:00 
			
		
		
		
	添加多语言最基础代码
This commit is contained in:
		
							
								
								
									
										276
									
								
								cmd/langs/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										276
									
								
								cmd/langs/main.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,276 @@
 | 
			
		||||
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
			
		||||
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/langs"
 | 
			
		||||
	"github.com/iwind/TeaGo/Tea"
 | 
			
		||||
	_ "github.com/iwind/TeaGo/bootstrap"
 | 
			
		||||
	"github.com/iwind/TeaGo/lists"
 | 
			
		||||
	"github.com/iwind/TeaGo/types"
 | 
			
		||||
	"go/format"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	var args = os.Args
 | 
			
		||||
	if len(args) >= 2 {
 | 
			
		||||
		switch args[1] {
 | 
			
		||||
		case "generate":
 | 
			
		||||
			runGenerate()
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		fmt.Println("Usage: langs [generate]")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func runGenerate() {
 | 
			
		||||
	var rootDir = filepath.Clean(Tea.Root + "/../pkg/langs/protos")
 | 
			
		||||
	dir, err := os.Open(rootDir)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("[ERROR]read dir failed: " + err.Error())
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	defer func() {
 | 
			
		||||
		_ = dir.Close()
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	files, err := dir.Readdir(0)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("[ERROR]read dir failed: " + err.Error())
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var dirRegexp = regexp.MustCompile(`^[a-z]+-[a-z]+$`)
 | 
			
		||||
	var jsonFileNameRegexp = regexp.MustCompile(`^([a-zA-Z0-9]+)(_([a-zA-Z0-9]+))+\.json$`)
 | 
			
		||||
	var messageCodeRegexp = regexp.MustCompile(`^[a-zA-Z0-9_]+$`)
 | 
			
		||||
 | 
			
		||||
	var messageCodes = []string{}
 | 
			
		||||
	var messageMaps = map[string]map[string]string{} // lang => { K:V }
 | 
			
		||||
	var defaultLang = langs.DefaultManager().DefaultLang()
 | 
			
		||||
 | 
			
		||||
	for _, file := range files {
 | 
			
		||||
		var dirName = file.Name()
 | 
			
		||||
 | 
			
		||||
		if !file.IsDir() || !dirRegexp.MatchString(dirName) {
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		var langCode = dirName
 | 
			
		||||
		var isBaseLang = langCode == defaultLang
 | 
			
		||||
 | 
			
		||||
		func() {
 | 
			
		||||
			jsonFiles, err := filepath.Glob(rootDir + "/" + dirName + "/*.json")
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				fmt.Println("[ERROR]list json files failed: " + err.Error())
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			for _, jsonFile := range jsonFiles {
 | 
			
		||||
				var jsonFileName = filepath.Base(jsonFile)
 | 
			
		||||
				if len(jsonFileName) == 0 || !jsonFileNameRegexp.MatchString(jsonFileName) {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
				var module = strings.TrimSuffix(jsonFileName, ".json")
 | 
			
		||||
 | 
			
		||||
				data, err := os.ReadFile(jsonFile)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					fmt.Println("[ERROR]read json file '" + jsonFile + "' failed: " + err.Error())
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				var m = map[string]string{} // code => value
 | 
			
		||||
				err = json.Unmarshal(data, &m)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					fmt.Println("[ERROR]decode json file '" + jsonFile + "' failed: " + err.Error())
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				var newM = map[string]string{}
 | 
			
		||||
				for code, value := range m {
 | 
			
		||||
					if !messageCodeRegexp.MatchString(code) {
 | 
			
		||||
						fmt.Println("[ERROR]invalid message code '" + code + "'")
 | 
			
		||||
						return
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					var fullCode = module + "_" + code
 | 
			
		||||
					if isBaseLang {
 | 
			
		||||
						messageCodes = append(messageCodes, fullCode)
 | 
			
		||||
					}
 | 
			
		||||
					newM[fullCode] = value
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				finalMap, ok := messageMaps[langCode]
 | 
			
		||||
				if !ok {
 | 
			
		||||
					finalMap = map[string]string{}
 | 
			
		||||
					messageMaps[langCode] = finalMap
 | 
			
		||||
				}
 | 
			
		||||
				for code, value := range newM {
 | 
			
		||||
					finalMap[code] = value
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// check message codes
 | 
			
		||||
	fmt.Println("checking message codes ...")
 | 
			
		||||
	var defaultMessageMap = map[string]string{}
 | 
			
		||||
	for langCode, messageMap := range messageMaps {
 | 
			
		||||
		if langCode == defaultLang { // only check lang not equal to 'en-us'
 | 
			
		||||
			defaultMessageMap = messageMap
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for messageCode := range messageMap {
 | 
			
		||||
			if !lists.ContainsString(messageCodes, messageCode) {
 | 
			
		||||
				fmt.Println("[ERROR]message code '" + messageCode + "' in lang '" + langCode + "' not exist in default lang file ('" + defaultLang + "')")
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Println("found '" + types.String(len(messageCodes)) + "' message codes")
 | 
			
		||||
 | 
			
		||||
	// generate codes/codes.go
 | 
			
		||||
	sort.Strings(messageCodes)
 | 
			
		||||
	var codesSource = `
 | 
			
		||||
// generated by run 'langs generate'
 | 
			
		||||
 | 
			
		||||
package codes
 | 
			
		||||
 | 
			
		||||
import(
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/langs"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	`
 | 
			
		||||
 | 
			
		||||
	for _, messageCode := range messageCodes {
 | 
			
		||||
		// add comment to message code
 | 
			
		||||
		comment, _, _ := strings.Cut(defaultMessageMap[messageCode], "\n")
 | 
			
		||||
 | 
			
		||||
		codesSource += upperWords(messageCode) + " langs.MessageCode = " + strconv.Quote(messageCode) + " // " + comment + "\n"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	codesSource += `
 | 
			
		||||
)
 | 
			
		||||
`
 | 
			
		||||
 | 
			
		||||
	formattedCodesSource, err := format.Source([]byte(codesSource))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("[ERROR]format 'codes.go' failed: " + err.Error())
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Println("generating 'codes/codes.go' ...")
 | 
			
		||||
	err = os.WriteFile(Tea.Root+"/../pkg/langs/codes/codes.go", formattedCodesSource, 0666)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println("[ERROR]write to 'codes.go' failed: " + err.Error())
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// generate messages_LANG.go
 | 
			
		||||
	for langCode, messageMap := range messageMaps {
 | 
			
		||||
		var langFile = strings.ReplaceAll("messages/messages_"+langCode+".go", "-", "_")
 | 
			
		||||
 | 
			
		||||
		fmt.Println("generating '" + langFile + "' ...")
 | 
			
		||||
		var source = `
 | 
			
		||||
// generated by run 'langs generate'
 | 
			
		||||
 | 
			
		||||
package messages
 | 
			
		||||
 | 
			
		||||
import(
 | 
			
		||||
	"github.com/TeaOSLab/EdgeCommon/pkg/langs"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	langs.Load("` + langCode + `", map[string]string{
 | 
			
		||||
	`
 | 
			
		||||
 | 
			
		||||
		for code, value := range messageMap {
 | 
			
		||||
			source += strconv.Quote(code) + ": " + strconv.Quote(value) + ",\n"
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		source += `
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
`
 | 
			
		||||
 | 
			
		||||
		formattedSource, err := format.Source([]byte(source))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			fmt.Println("[ERROR]format '" + langFile + "' failed: " + err.Error())
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		err = os.WriteFile(Tea.Root+"/../pkg/langs/"+langFile, formattedSource, 0666)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			fmt.Println("[ERROR]write file '" + langFile + "' failed: " + err.Error())
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// generate language javascript files for EdgeAdmin
 | 
			
		||||
	for lang, messageMap := range messageMaps {
 | 
			
		||||
		if lang != defaultLang {
 | 
			
		||||
			// TODO merge messageMap with default message map
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for _, component := range []string{"EdgeAdmin", "EdgeUser"} {
 | 
			
		||||
			fmt.Println("generating '" + lang + ".js' for " + component + " ...")
 | 
			
		||||
			var targetFile = filepath.Clean(Tea.Root + "/../../" + component + "/web/public/js/langs/" + lang + ".js")
 | 
			
		||||
			var targetDir = filepath.Dir(targetFile)
 | 
			
		||||
			dirStat, _ := os.Stat(targetDir)
 | 
			
		||||
			if dirStat != nil {
 | 
			
		||||
				messageMapJSON, err := json.Marshal(messageMap)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					fmt.Println("[ERROR]marshal message map failed: " + err.Error())
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
				err = os.WriteFile(targetFile, []byte(`// generated by 'langs generate'
 | 
			
		||||
window.LANG_MESSAGES = `+string(messageMapJSON)+";\n"), 0666)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					fmt.Println("[ERROR]write file '" + targetFile + "' failed: " + err.Error())
 | 
			
		||||
					return
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Println("success")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func upperWords(s string) string {
 | 
			
		||||
	var words = strings.Split(s, "_")
 | 
			
		||||
	for index, word := range words {
 | 
			
		||||
		words[index] = upperWord(word)
 | 
			
		||||
	}
 | 
			
		||||
	return strings.Join(words, "")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func upperWord(word string) string {
 | 
			
		||||
	var l = len(word)
 | 
			
		||||
	if l == 0 {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if l == 1 {
 | 
			
		||||
		return strings.ToUpper(word)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// special words
 | 
			
		||||
	switch word {
 | 
			
		||||
	case "api", "http", "https", "tcp", "udp", "ip", "dns", "ns", "waf", "acme", "ssh", "toa":
 | 
			
		||||
		return strings.ToUpper(word)
 | 
			
		||||
	case "ipv6":
 | 
			
		||||
		return "IPv6"
 | 
			
		||||
	case "ddos":
 | 
			
		||||
		return "DDoS"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return strings.ToUpper(word[:1]) + word[1:]
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user