77 lines
2.0 KiB
Go
77 lines
2.0 KiB
Go
package assets
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"os"
|
||
"path/filepath"
|
||
)
|
||
|
||
// Lang 语言表:指定语言覆盖层 + en_us 回退层(设计.md §2.4、UI与输入.md §5)。
|
||
type Lang struct {
|
||
keys map[string]string // 指定语言
|
||
fallback map[string]string // en_us 回退
|
||
}
|
||
|
||
// Get 取翻译;缺失回退 en_us,再缺失返回键名本身(便于发现缺失键)。
|
||
func (l *Lang) Get(key string) string {
|
||
if v, ok := l.keys[key]; ok {
|
||
return v
|
||
}
|
||
if v, ok := l.fallback[key]; ok {
|
||
return v
|
||
}
|
||
return key
|
||
}
|
||
|
||
// LoadLang 加载语言:先加载 en_us 作为回退层,再合并目标语言。
|
||
// 合并顺序:低优先级包 → 高优先级包(后者覆盖),与资源优先级链一致。
|
||
func (m *Manager) LoadLang(code string) (*Lang, error) {
|
||
fallback := make(map[string]string)
|
||
if code != "en_us" {
|
||
if err := m.loadLangInto("en_us", fallback); err != nil {
|
||
return nil, err
|
||
}
|
||
}
|
||
keys := make(map[string]string)
|
||
if err := m.loadLangInto(code, keys); err != nil {
|
||
return nil, err
|
||
}
|
||
return &Lang{keys: keys, fallback: fallback}, nil
|
||
}
|
||
|
||
// loadLangInto 按优先级从低到高合并所有包的 lang/<code>.json 到 dst。
|
||
func (m *Manager) loadLangInto(code string, dst map[string]string) error {
|
||
var paths []string
|
||
// 从低优先级到高优先级收集路径(逆序遍历包列表)
|
||
for i := len(m.packs) - 1; i >= 0; i-- {
|
||
p := m.packs[i]
|
||
for _, ns := range p.namespaces() {
|
||
path := filepath.Join(p.Root, "assets", ns, "lang", code+".json")
|
||
if fileExists(path) {
|
||
paths = append(paths, path)
|
||
}
|
||
}
|
||
}
|
||
if m.embeddedRoot != "" {
|
||
path := filepath.Join(m.embeddedRoot, "lang", code+".json")
|
||
if fileExists(path) {
|
||
paths = append(paths, path)
|
||
}
|
||
}
|
||
for _, path := range paths {
|
||
b, err := os.ReadFile(path)
|
||
if err != nil {
|
||
return fmt.Errorf("assets.loadLangInto %s: %w", code, err)
|
||
}
|
||
var kv map[string]string
|
||
if err := json.Unmarshal(b, &kv); err != nil {
|
||
return fmt.Errorf("assets.loadLangInto %s: %w", code, err)
|
||
}
|
||
for k, v := range kv {
|
||
dst[k] = v
|
||
}
|
||
}
|
||
return nil
|
||
}
|