feat(cmd): add i18n command

This commit is contained in:
LinkinStars
2024-07-17 11:04:20 +08:00
parent f945ad20a3
commit 82e656821d
3 changed files with 201 additions and 9 deletions
+31 -1
View File
@@ -49,6 +49,10 @@ var (
upgradeVersion string
// The fields that need to be set to the default value
configFields []string
// i18nSourcePath i18n from path
i18nSourcePath string
// i18nTargetPath i18n to path
i18nTargetPath string
)
func init() {
@@ -68,7 +72,11 @@ func init() {
configCmd.Flags().StringSliceVarP(&configFields, "with", "w", []string{}, "the fields that need to be set to the default value, eg: -w allow_password_login")
for _, cmd := range []*cobra.Command{initCmd, checkCmd, runCmd, dumpCmd, upgradeCmd, buildCmd, pluginCmd, configCmd} {
i18nCmd.Flags().StringVarP(&i18nSourcePath, "source", "s", "", "i18n source path, eg: -f ./i18n/source")
i18nCmd.Flags().StringVarP(&i18nTargetPath, "target", "t", "", "i18n target path, eg: -t ./i18n/target")
for _, cmd := range []*cobra.Command{initCmd, checkCmd, runCmd, dumpCmd, upgradeCmd, buildCmd, pluginCmd, configCmd, i18nCmd} {
rootCmd.AddCommand(cmd)
}
}
@@ -271,6 +279,28 @@ To run answer, use:
}
},
}
// i18nCmd used to merge i18n files
i18nCmd = &cobra.Command{
Use: "i18n",
Short: "overwrite i18n files",
Long: `Merge i18n files from plugins to original i18n files. It will overwrite the original i18n files`,
Run: func(_ *cobra.Command, _ []string) {
if err := cli.ReplaceI18nFilesLocal(i18nTargetPath); err != nil {
fmt.Printf("replace i18n files failed %v", err)
} else {
fmt.Printf("replace i18n files successfully\n")
}
fmt.Printf("try to merge i18n files from %q to %q\n", i18nSourcePath, i18nTargetPath)
if err := cli.MergeI18nFilesLocal(i18nTargetPath, i18nSourcePath); err != nil {
fmt.Printf("merge i18n files failed %v", err)
} else {
fmt.Printf("merge i18n files successfully\n")
}
},
}
)
// Execute adds all child commands to the root command and sets flags appropriately.
+158
View File
@@ -0,0 +1,158 @@
package cli
import (
"fmt"
"github.com/apache/incubator-answer/i18n"
"github.com/apache/incubator-answer/pkg/dir"
"github.com/apache/incubator-answer/pkg/writer"
"gopkg.in/yaml.v3"
"os"
"path/filepath"
"strings"
)
type YamlPluginContent struct {
Plugin map[string]any `yaml:"plugin"`
}
// ReplaceI18nFilesLocal replace i18n files
func ReplaceI18nFilesLocal(i18nDir string) error {
i18nList, err := i18n.I18n.ReadDir(".")
if err != nil {
fmt.Println(err.Error())
return err
}
fmt.Printf("[i18n] find i18n bundle %d\n", len(i18nList))
for _, item := range i18nList {
path := filepath.Join(i18nDir, item.Name())
content, err := i18n.I18n.ReadFile(item.Name())
if err != nil {
continue
}
exist := dir.CheckFileExist(path)
if exist {
fmt.Printf("[i18n] install %s file exist, try to replace it\n", item.Name())
if err = os.Remove(path); err != nil {
fmt.Println(err)
}
}
fmt.Printf("[i18n] install %s bundle...\n", item.Name())
err = writer.WriteFile(path, string(content))
if err != nil {
fmt.Printf("[i18n] install %s bundle fail: %s\n", item.Name(), err.Error())
} else {
fmt.Printf("[i18n] install %s bundle success\n", item.Name())
}
}
return nil
}
// MergeI18nFilesLocal merge i18n files
func MergeI18nFilesLocal(originalI18nDir, targetI18nDir string) (err error) {
pluginAllTranslations := make(map[string]*YamlPluginContent)
err = findI18nFileInDir(pluginAllTranslations, targetI18nDir)
if err != nil {
return err
}
entries, err := os.ReadDir(originalI18nDir)
if err != nil {
return err
}
for _, file := range entries {
// ignore directory
if file.IsDir() {
continue
}
// ignore non-YAML file
filename := file.Name()
if filepath.Ext(filename) != ".yaml" && filename != "i18n.yaml" {
continue
}
// if plugin don't have this translation file, ignore it
if pluginAllTranslations[filename] == nil {
continue
}
out, _ := yaml.Marshal(pluginAllTranslations[filename])
buf, err := os.OpenFile(filepath.Join(originalI18nDir, filename), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
fmt.Printf("[i18n] read translation file failed: %s %s\n", filename, err)
continue
}
_, _ = buf.WriteString("\n")
_, _ = buf.Write(out)
_ = buf.Close()
fmt.Printf("[i18n] merge i18n file: %s success\n", filename)
}
return nil
}
// find i18n file in dir
func findI18nFileInDir(pluginAllTranslations map[string]*YamlPluginContent, i18nDir string) error {
// if i18n dir is not i18n, find deeper
dirBase := filepath.Base(i18nDir)
if dirBase != "i18n" {
if strings.HasPrefix(dirBase, ".") {
return nil
}
// find all i18n dir in target dir
targetDirs, err := os.ReadDir(i18nDir)
if err != nil {
return err
}
for _, targetDir := range targetDirs {
if targetDir.IsDir() {
if err := findI18nFileInDir(pluginAllTranslations, filepath.Join(i18nDir, targetDir.Name())); err != nil {
fmt.Printf("[i18n] find i18n file in dir failed: %s %s\n", targetDir.Name(), err)
}
}
}
return nil
}
fmt.Printf("[i18n] find i18n file in dir: %s\n", i18nDir)
// if i18nDir is i18n, find all yaml files
entries, err := os.ReadDir(i18nDir)
if err != nil {
return err
}
for _, file := range entries {
// ignore directory
if file.IsDir() {
continue
}
// ignore non-YAML file
if filepath.Ext(file.Name()) != ".yaml" {
continue
}
buf, err := os.ReadFile(filepath.Join(i18nDir, file.Name()))
if err != nil {
fmt.Printf("[i18n] read translation file failed: %s %s\n", file.Name(), err)
continue
}
translation := &YamlPluginContent{}
if err = yaml.Unmarshal(buf, translation); err != nil {
fmt.Printf("[i18n] unmarshal translation file failed: %s %s\n", file.Name(), err)
continue
}
if pluginAllTranslations[file.Name()] == nil {
pluginAllTranslations[file.Name()] = &YamlPluginContent{Plugin: make(map[string]any)}
}
for k, v := range translation.Plugin {
pluginAllTranslations[file.Name()].Plugin[k] = v
}
}
return nil
}
+12 -8
View File
@@ -23,6 +23,7 @@ import (
"fmt"
"os"
"path/filepath"
"sync"
"github.com/apache/incubator-answer/configs"
"github.com/apache/incubator-answer/i18n"
@@ -37,10 +38,11 @@ const (
)
var (
ConfigFileDir = "/conf/"
UploadFilePath = "/uploads/"
I18nPath = "/i18n/"
CacheDir = "/cache/"
ConfigFileDir = "/conf/"
UploadFilePath = "/uploads/"
I18nPath = "/i18n/"
CacheDir = "/cache/"
formatAllPathONCE sync.Once
)
// GetConfigFilePath get config file path
@@ -49,10 +51,12 @@ func GetConfigFilePath() string {
}
func FormatAllPath(dataDirPath string) {
ConfigFileDir = filepath.Join(dataDirPath, ConfigFileDir)
UploadFilePath = filepath.Join(dataDirPath, UploadFilePath)
I18nPath = filepath.Join(dataDirPath, I18nPath)
CacheDir = filepath.Join(dataDirPath, CacheDir)
formatAllPathONCE.Do(func() {
ConfigFileDir = filepath.Join(dataDirPath, ConfigFileDir)
UploadFilePath = filepath.Join(dataDirPath, UploadFilePath)
I18nPath = filepath.Join(dataDirPath, I18nPath)
CacheDir = filepath.Join(dataDirPath, CacheDir)
})
}
// InstallAllInitialEnvironment install all initial environment