github.com/erda-project/erda-infra@v1.0.10-0.20240327085753-f3a249292aeb/providers/i18n/register.go (about)

     1  // Copyright (c) 2021 Terminus, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package i18n
    16  
    17  import (
    18  	"bytes"
    19  	"embed"
    20  	"fmt"
    21  	"io/fs"
    22  	"path/filepath"
    23  	"strings"
    24  
    25  	cfg "github.com/erda-project/erda-infra/pkg/config"
    26  	"github.com/erda-project/erda-infra/pkg/strutil"
    27  )
    28  
    29  type file struct {
    30  	isDir    bool
    31  	name     string
    32  	fullPath string
    33  	data     []byte
    34  }
    35  
    36  func newDir(fullPath string) *file {
    37  	return &file{isDir: true, name: filepath.Base(fullPath), fullPath: fullPath, data: nil}
    38  }
    39  func newFile(fullPath string, data []byte) *file {
    40  	return &file{isDir: false, name: filepath.Base(fullPath), fullPath: fullPath, data: data}
    41  }
    42  
    43  func (p *provider) RegisterFilesFromFS(fsPrefix string, rootFS embed.FS) error {
    44  	var err error
    45  	var filesItems []*file
    46  	var commonItems []*file
    47  	walkEmbedFS(rootFS, fmt.Sprintf("%s/common", fsPrefix), &commonItems)
    48  	walkEmbedFS(rootFS, fmt.Sprintf("%s/files", fsPrefix), &filesItems)
    49  	for _, file := range filesItems {
    50  		if file.isDir {
    51  			continue
    52  		}
    53  		if !strutil.HasSuffixes(file.name, ".yml", ".yaml") {
    54  			continue
    55  		}
    56  		err = p.loadI18nFileByte(file.fullPath, file.data)
    57  		if err != nil {
    58  			return err
    59  		}
    60  	}
    61  	for _, file := range commonItems {
    62  		if file.isDir {
    63  			continue
    64  		}
    65  		if !strutil.HasSuffixes(file.name, ".yml", ".yaml") {
    66  			continue
    67  		}
    68  		err = p.loadByteToDic(file.fullPath, file.data, p.common)
    69  		if err != nil {
    70  			return err
    71  		}
    72  	}
    73  	return nil
    74  }
    75  
    76  func walkEmbedFS(rootFS embed.FS, fullPath string, files *[]*file) {
    77  	entries, err := fs.ReadDir(rootFS, fullPath)
    78  	if err != nil {
    79  		panic(fmt.Errorf("fullPath: %s, err: %v", fullPath, err))
    80  	}
    81  	for _, entry := range entries {
    82  		entryPath := filepath.Join(fullPath, entry.Name())
    83  		if !entry.IsDir() {
    84  			data, err := rootFS.ReadFile(entryPath)
    85  			if err != nil {
    86  				panic(fmt.Errorf("failed to read file, filePath: %s, err: %v", entryPath, err))
    87  			}
    88  			*files = append(*files, newFile(entryPath, data))
    89  			continue
    90  		}
    91  		*files = append(*files, newDir(entryPath))
    92  		walkEmbedFS(rootFS, entryPath, files)
    93  	}
    94  }
    95  
    96  func (p *provider) loadByteToDic(path string, byte []byte, dic map[string]map[string]string) error {
    97  	m := make(map[string]interface{})
    98  	typ := filepath.Ext(path)
    99  	if len(typ) <= 0 {
   100  		return fmt.Errorf("%s unknown file extension", path)
   101  	}
   102  	err := cfg.UnmarshalToMap(bytes.NewReader(byte), typ[1:], m)
   103  	if err != nil {
   104  		return fmt.Errorf("fail to load i18n file: %s", err)
   105  	}
   106  	for lang, v := range m {
   107  		text := dic[lang]
   108  		if text == nil {
   109  			text = make(map[string]string)
   110  			dic[lang] = text
   111  		}
   112  		switch m := v.(type) {
   113  		case map[string]string:
   114  			for k, v := range m {
   115  				text[strings.ToLower(k)] = fmt.Sprint(v)
   116  			}
   117  		case map[string]interface{}:
   118  			for k, v := range m {
   119  				text[strings.ToLower(k)] = fmt.Sprint(v)
   120  			}
   121  		case map[interface{}]interface{}:
   122  			for k, v := range m {
   123  				text[strings.ToLower(fmt.Sprint(k))] = fmt.Sprint(v)
   124  			}
   125  		default:
   126  			return fmt.Errorf("invalid i18n file format: %s", path)
   127  		}
   128  	}
   129  	return nil
   130  }
   131  
   132  func (p *provider) loadI18nFileByte(file string, byte []byte) error {
   133  	base := filepath.Base(file)
   134  	name := base[0 : len(base)-len(filepath.Ext(base))]
   135  	dic := p.dic[name]
   136  	if dic == nil {
   137  		dic = make(map[string]map[string]string)
   138  		p.dic[name] = dic
   139  	}
   140  	err := p.loadByteToDic(file, byte, dic)
   141  	if err != nil {
   142  		return err
   143  	}
   144  	return nil
   145  }