i18n

package
v0.19.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 1, 2026 License: Apache-2.0, Apache-2.0 Imports: 11 Imported by: 0

README

go-toolbox/pkg/i18n — 零依赖高性能 Go 国际化库

主包不引入任何第三方依赖,翻译热路径无锁、零分配 只有真的把语言文件存成 YAML 时,才需要额外引一个 YAML 解析器

⚡ 核心特性

特性 说明
零依赖 主包构建闭包里 0 个外部包,只用标准库
无锁读 消息表以原子指针 copy-on-write 持有,翻译不加锁
零分配 GetMessage 命中路径 0 B/op、0 allocs/op
四种占位符 %s 位置参数、{key}、{{key}}、{{.key}},单趟扫描同时识别
语言回退 标准映射 + 遗留映射两段解析,缺键回退默认语言
多种来源 内存 map、JSON 字符串、JSON 文件;YAML 走独立子包
可替换 格式化器与日志器均为接口,可自带实现

📊 性能

Apple M4,-benchtime=500ms -count=3 -cpu=10,三次运行离散度 < 2%:

基准 ns/op B/op allocs/op
GetMessage(命中,无模板) 14.2 0 0
GetMessage 并发 10 核 3.47 0 0
GetMessage 回退默认语言 29.6 0 0
GetMessageWithMap(3 个占位符) 102 96 2
FormatWithTemplateData(无占位符) 6.34 0 0
FormatWithTemplateData(1 个占位符) 41.1 64 2
NormalizeLanguage("zh-hans-cn") 21.7 16 1
ParseAcceptLanguage(4 个候选) 97.4 80 3

并发 3.47 ns 低于串行 14.2 ns,说明读路径确实在多核上并行展开——这是无锁读的直接结果 自行复现:

go test -run='^$' -bench=. -benchmem -benchtime=500ms -count=3 -cpu=10 .

⚠️ 重要设计取舍

读之前先知道三件事,省得踩坑

YAML 加载器为什么单独成包

Go 的依赖粒度是包,不是函数 只要主包里有一个文件 import "gopkg.in/yaml.v3",所有使用者——包括只用 MapLoader 的——都得下载并编译 YAML 解析器

所以 YAML 加载器放在 yamlloader/:

import "github.com/HitGameAI/apex-toolbox/pkg/i18n/yamlloader"

loader := yamlloader.New("./locales")

用 JSON 或内存 map 的人完全不会碰到 yaml.v3 反过来,FileLoader/JSONLoader/MapLoader 只用 os 与 encoding/json(都是标准库),没有依赖需要隔离,因此跟核心放在一起

Config 只收本库真正会读的字段

以下字段刻意不提供,它们不属于翻译引擎:

不提供 原因 该放哪
module-name 配置库用来标识配置段 你的配置层
detection-order、language-param、language-header、cookie-name "从请求的哪里取语言"是 HTTP 中间件的事,本库一行 HTTP 代码都没有 你的中间件,取到语言后交给 Config.ParseAcceptLanguage 或 ResolveLanguage
custom-message-paths 按语言分别指定路径是加载器策略 自己实现一个 Loader

字段 tag 与既有 i18n.yaml / i18n.json 保持一致,同一份文件可以继续反序列化进来,多出来的键会被忽略

日志器默认静默

本库只在一处记日志(预加载映射目标语言失败) 不传日志器就静默——库不该替使用方决定日志去向:

// 任何实现了 Warn(string, ...any) 的 logger 都能传入
manager, err := i18n.NewManagerWithLogger(config, myLogger)

🏗️ 项目结构

go-toolbox/pkg/i18n/
├── manager.go      国际化管理器:加载、解析、翻译(原子指针 + copy-on-write)
├── config.go       配置与语言解析(标准/遗留两段映射、Accept-Language 协商)
├── loader.go       Loader 接口、嵌套扁平化、三个零依赖加载器
├── format.go       Formatter 接口与单趟扫描的占位符替换
├── language.go     语言代码标准化与 Accept-Language 解析
├── errors.go       错误类型注册表与本库全部错误类型
├── context.go      Translator 接口与 context 存取
├── translate.go    全局快捷函数 T / TWithMap / GetMsgByKey
├── logger.go       最小日志接口
└── yamlloader/     YAML 加载器(唯一需要第三方解析器的地方)

📦 安装

go get github.com/HitGameAI/apex-toolbox/pkg/i18n

需要 YAML 支持时再额外:

go get github.com/HitGameAI/apex-toolbox/pkg/i18n/yamlloader

🚀 使用示例

内存 Map
config := &i18n.Config{
    Enabled:            true,
    DefaultLanguage:    "en",
    SupportedLanguages: []string{"en", "zh"},
    EnableFallback:     true,
    MessageLoader: i18n.NewMapLoader(map[string]map[string]string{
        "en": {"hello": "Hello", "greeting": "Hello {name}"},
        "zh": {"hello": "你好", "greeting": "你好 {name}"},
    }),
}

manager, err := i18n.NewManager(config)
if err != nil {
    log.Fatalf("创建国际化管理器失败: %v", err)
}

manager.GetMessage("en", "hello")  // "Hello"
manager.GetMessage("zh", "hello")  // "你好"
manager.GetMessageWithMap("en", "greeting", map[string]any{"name": "John"}) // "Hello John"
JSON 文件

目录下按 {语言}.json 命名,嵌套结构自动展平成点号键:

// locales/zh.json
{
  "error": { "internal": "内部错误", "not_found": "资源未找到" },
  "hello": "你好"
}
config := i18n.DefaultConfig().
    WithSupportedLanguages([]string{"en", "zh"}).
    WithMessageLoader(i18n.NewFileLoader("./locales")).
    Enable()

manager, _ := i18n.NewManager(config)
manager.GetMessage("zh", "error.internal") // "内部错误"

只写路径、让库自己建 JSON 文件加载器也可以:

config := i18n.DefaultConfig().WithMessagesPath("./locales").Enable()
JSON 字符串
loader, err := i18n.NewJSONLoader(`{
    "en": {"hello": "Hello"},
    "zh": {"hello": "你好"}
}`)
if err != nil {
    log.Fatalf("解析翻译 JSON 失败: %v", err)
}

config := i18n.DefaultConfig().WithMessageLoader(loader).Enable()
YAML(独立子包)
import "github.com/HitGameAI/apex-toolbox/pkg/i18n/yamlloader"

// 目录下的 {语言}.yaml 或 {语言}.yml
config := i18n.DefaultConfig().
    WithMessageLoader(yamlloader.New("./locales")).
    Enable()

// 或直接给 YAML 字符串
loader, err := yamlloader.NewString(`
zh:
  hello: 你好
en:
  hello: Hello
`)
四种占位符格式
// %s 位置参数(走 fmt.Sprintf)
manager.GetMessage("en", "greeting", "John")

// 以下三种都用 GetMessageWithMap,同一次扫描全部识别
// 消息 "Hello {name}"
// 消息 "Hello {{name}}"
// 消息 "Hello {{.name}}"
manager.GetMessageWithMap("en", "greeting", map[string]any{"name": "John"})

占位符的值不会被二次展开:值里恰好含有 {other} 时不会被当成占位符继续替换

语言回退与映射
config := i18n.DefaultConfig().
    AddLanguageMapping("zh-tw", "zh").       // 标准映射:地区变体收敛
    AddLegacyLanguageMapping("cn", "zh").    // 遗留映射:纠正历史上用错的代码
    Enable()

manager, _ := i18n.NewManager(config)

manager.GetMessage("cn", "hello")    // 遗留映射 -> zh -> "你好"
manager.GetMessage("zh-tw", "hello") // 标准映射 -> zh -> "你好"
manager.GetMessage("fr", "hello")    // 不支持 -> 回退默认语言 -> "Hello"
manager.GetMessage("en", "nope")     // 键不存在 -> 返回键本身 "nope"
Accept-Language 协商
lang := config.ParseAcceptLanguage("zh-CN,zh;q=0.9,en;q=0.8") // "zh"

// 标准化单个语言代码
i18n.NormalizeLanguage("zh_cn")      // "zh-CN"
i18n.NormalizeLanguage("zh-hans-cn") // "zh-Hans-CN"
通过 context 翻译
// 在中间件里把语言与翻译器放进 context
ctx = i18n.NewContext(ctx, "zh", manager)

// 业务代码直接用全局快捷函数
i18n.T(ctx, "greeting", "John")
i18n.TWithMap(ctx, "greeting", map[string]any{"name": "John"})
i18n.GetMsgByKey(ctx, "hello")
i18n.GetLanguage(ctx)

T / TWithMap 在 context 里没有 i18n 上下文时返回键本身,不会 panic

自定义格式化器
type myFormatter struct{}

func (myFormatter) Format(message string, args []any, templateData map[string]any) string {
    // 你的模板引擎
    return message
}

manager, _ := i18n.NewManagerWithFormatter(config, myFormatter{})
运行期重载
// 重新读取某个语言的文件,并发安全:读者始终看到一份完整快照
if err := manager.ReloadLanguage("zh"); err != nil {
    log.Printf("重载 zh 失败: %v", err)
}

🔁 从旧版本迁移

旧 新
&gci18n.I18N{...}(来自 go-config) &i18n.Config{...}(本包自有)
gci18n.Default() i18n.DefaultConfig()
i18n.NewYAMLLoader(path) yamlloader.New(path)
i18n.NewYAMLStringLoader(s) yamlloader.NewString(s)
logger.ILogger(来自 go-toolbox/pkg/logger) i18n.Logger(一个 Warn 方法,任何 logger 都满足)
i18n.AsMessageLoader(l) 不再需要,MessageLoader 现在是 Loader 的别名

字段名注意:配置里是 Enabled,不是 Enable(Enable() 是链式方法)

🧪 测试

go test ./...              # 全部测试
go test -race ./...        # 竞态检测(copy-on-write 必跑)
go test -cover ./...       # 覆盖率

📚 文档

文档 说明
docs/API.md API 参考
docs/Loaders.md 消息加载器

Documentation

Index

Constants

View Source
const (
	// ContextKey i18n 上下文键
	ContextKey contextKey = "i18n"
)

Variables

This section is empty.

Functions

func ErrorTemplate

func ErrorTemplate(errType ErrorType) (string, bool)

ErrorTemplate 查询已注册的模板,便于测试与排查 [EN] Looks up a registered template; useful in tests.

func ExtractLanguage

func ExtractLanguage(r interface{}) string

ExtractLanguage 从 HTTP 请求中提取语言信息

注意:此函数通过鸭子类型探测 GetHTTPRequest/Extract 方法,标准 *http.Request 并不满足,因此实际总是返回 "en" 保留它仅为兼容既有调用方;需要真正的请求语言 协商请用 Config.ParseAcceptLanguage 配合你自己的 Header/Query/Cookie 读取 [EN] Duck-types for GetHTTPRequest/Extract, which *http.Request does not satisfy, so this returns "en" in practice. Kept for API compatibility; for real negotiation use Config.ParseAcceptLanguage with your own header/query/cookie read.

func FlattenToMessages

func FlattenToMessages(data map[string]any) map[string]string

FlattenToMessages 将嵌套 map 扁平化为点号分隔的消息映射 例如: {"error": {"internal": "错误"}} -> {"error.internal": "错误"}

单趟递归直接写入结果 map,并复用一个 []byte 拼接前缀,避免原先 mathx.FlattenMap + TransformMapValues 两趟遍历与中间 map 的开销 [EN] One recursive pass writing straight into the result map, reusing a byte buffer for the key prefix; the previous version walked twice through an intermediate map.

func FormatMessage

func FormatMessage(message string, args []any, templateData map[string]any) string

FormatMessage 便捷函数:使用默认格式化器格式化消息

func FormatWithTemplateData

func FormatWithTemplateData(message string, templateData map[string]any) string

FormatWithTemplateData 使用模板数据格式化消息,一次扫描同时识别三种占位符格式

原实现对每个键做 4 次 fmt.Sprintf(1 次取值 + 3 次拼占位符)再做 3 次 strings.ReplaceAll, 即键数的 3 倍全串扫描与约 4 倍分配;这里改为单趟扫描 + 一个输出缓冲

行为差异(更安全):占位符的值不再被后续键二次替换,即值里恰好含有 {other} 时 不会被当成占位符继续展开 [EN] One pass recognizing all three placeholder forms, instead of 4 Sprintf and 3 whole-string ReplaceAll per key. Behavioral difference, deliberately safer: a substituted value is no longer rescanned, so a value containing {other} is not expanded again.

func GetLanguage

func GetLanguage(ctx context.Context) string

GetLanguage 全局获取语言函数

func GetMsgByKey

func GetMsgByKey(ctx context.Context, key string) string

GetMsgByKey 通过键获取消息(业务层级函数)

func GetMsgWithMap

func GetMsgWithMap(ctx context.Context, key string, data map[string]any) string

GetMsgWithMap 使用 map 模板数据获取消息(业务层级函数)

func NewContext

func NewContext(ctx stdcontext.Context, language string, translator Translator) stdcontext.Context

NewContext 创建带有 i18n 上下文的新 stdlib context.Context

func NormalizeLanguage

func NormalizeLanguage(lang string) string

NormalizeLanguage 标准化语言代码

例如: "zh-cn" -> "zh-CN", "zh_CN" -> "zh-CN", "EN" -> "en", "zh-hans-cn" -> "zh-Hans-CN"

这两个函数原先转发给 go-toolbox/pkg/metadata,而那个包是 HTTP 元数据提取器, 会带入 netx/useragent 等 23 个包;语言代码解析本就属于 i18n 的领域,故收回本包

实现上单趟扫描直接写入一个预分配缓冲:原先 strings.Split 要为子串切片分配, 再加 ToUpper/ToLower 与末尾拼接,一次调用约 4 次分配;现在固定 1 次 [EN] These used to delegate to the toolbox metadata package, an HTTP metadata extractor pulling in ~23 packages; language-code parsing is i18n's own domain. The implementation now scans once into a pre-sized buffer: the previous strings.Split plus ToUpper/ToLower plus concatenation cost about 4 allocations per call, this costs exactly one.

func ParseAcceptLanguage

func ParseAcceptLanguage(acceptLang string) (language, region, fullTag string)

ParseAcceptLanguage 解析 Accept-Language 头,取优先级最高的那个语言标签

返回: 语言代码(如 "zh")、地区代码(如 "CN")、完整标签(如 "zh-CN") [EN] Returns language, region and full tag of the highest-priority entry.

func RegisterError

func RegisterError(errType ErrorType, template string)

RegisterError 注册错误类型及其消息模板(后注册覆盖先注册) [EN] Registers a message template for an error type; later wins.

func SetLanguage

func SetLanguage(ctx context.Context, language string) context.Context

SetLanguage 全局设置语言函数

func T

func T(ctx context.Context, key string, args ...any) string

T 全局翻译函数(位置参数)

func TWithMap

func TWithMap(ctx context.Context, key string, templateData map[string]any) string

TWithMap 全局翻译函数(命名模板数据)

Types

type Config

type Config struct {
	// Enabled 是否启用国际化(供调用方在装配阶段判断,本库不据此改变翻译行为)
	Enabled bool `mapstructure:"enabled" yaml:"enabled" json:"enabled"`
	// DefaultLanguage 默认语言,解析失败与回退时使用
	DefaultLanguage string `mapstructure:"default-language" yaml:"default-language" json:"defaultLanguage"`
	// SupportedLanguages 支持的语言列表,启动时逐个预加载
	SupportedLanguages []string `mapstructure:"supported-languages" yaml:"supported-languages" json:"supportedLanguages"`
	// LanguageMapping 标准映射(如 zh-cn -> zh)
	LanguageMapping map[string]string `mapstructure:"language-mapping" yaml:"language-mapping" json:"languageMapping"`
	// LegacyLanguageMapping 遗留映射(如 cn -> zh)
	LegacyLanguageMapping map[string]string `mapstructure:"legacy-language-mapping" yaml:"legacy-language-mapping" json:"legacyLanguageMapping"`
	// ResolutionOrder 映射应用顺序,默认先 legacy 再 standard
	ResolutionOrder []MappingType `mapstructure:"resolution-order" yaml:"resolution-order" json:"resolutionOrder"`
	// MessagesPath 翻译文件目录;未显式提供 MessageLoader 时据此建一个 JSON 文件加载器
	MessagesPath string `mapstructure:"messages-path" yaml:"messages-path" json:"messagesPath"`
	// EnableFallback 指定语言缺失该键时是否回退默认语言
	EnableFallback bool `mapstructure:"enable-fallback" yaml:"enable-fallback" json:"enableFallback"`
	// MessageLoader 自定义消息加载器,优先于 MessagesPath
	MessageLoader MessageLoader `mapstructure:"-" yaml:"-" json:"-"`
}

Config 国际化配置

这里只收本库真正会读的字段 被刻意排除的几类,以及它们该归谁:

  • module-name:配置库用来标识配置段的,翻译引擎用不到;
  • detection-order / language-param / language-header / cookie-name: "从请求的哪里取语言" 是 HTTP 中间件的职责,本库不含任何 HTTP 代码, 它只接收一个语言字符串并返回译文 请在中间件侧读取请求,再把结果交给 Config.ParseAcceptLanguage 或 Config.ResolveLanguage;
  • custom-message-paths:按语言分别指定路径属于加载器的策略, 想要就自己实现一个 Loader,比往配置里塞一张表清楚

字段 tag 与既有 i18n.yaml / i18n.json 保持一致,同一份文件可继续反序列化到这里, 多出来的键会被忽略

[EN] Only the fields this library actually reads. Deliberately excluded: module-name (a configuration-registry concern); detection-order, language-param, language-header and cookie-name (where a request's language is read from is the HTTP middleware's job — this library holds no HTTP code, it takes a language string and returns a translation); custom-message-paths (per-language paths are a loader policy — implement a Loader instead). Tags still match the existing i18n.yaml/json, so the same file unmarshals here and the extra keys are simply ignored.

func DefaultConfig

func DefaultConfig() *Config

DefaultConfig 创建默认国际化配置

func (*Config) AddLanguageMapping

func (c *Config) AddLanguageMapping(from, to string) *Config

AddLanguageMapping 添加标准语言映射(如 zh-tw -> zh)

func (*Config) AddLanguageMappings

func (c *Config) AddLanguageMappings(mappings map[string]string) *Config

AddLanguageMappings 批量添加标准语言映射

func (*Config) AddLegacyLanguageMapping

func (c *Config) AddLegacyLanguageMapping(from, to string) *Config

AddLegacyLanguageMapping 添加遗留语言映射(如 cn -> zh)

func (*Config) AddLegacyLanguageMappings

func (c *Config) AddLegacyLanguageMappings(mappings map[string]string) *Config

AddLegacyLanguageMappings 批量添加遗留语言映射

func (*Config) Disable

func (c *Config) Disable() *Config

Disable 关闭国际化

func (*Config) Enable

func (c *Config) Enable() *Config

Enable 启用国际化

func (*Config) GetMappedLanguage

func (c *Config) GetMappedLanguage(lang string) string

GetMappedLanguage 获取标准映射后的语言代码,无映射则原样返回

func (*Config) IsEnabled

func (c *Config) IsEnabled() bool

IsEnabled 国际化是否启用(nil 安全)

func (*Config) IsSupportedLanguage

func (c *Config) IsSupportedLanguage(lang string) bool

IsSupportedLanguage 检查语言是否在支持列表中

func (*Config) ParseAcceptLanguage

func (c *Config) ParseAcceptLanguage(acceptLang string) string

ParseAcceptLanguage 解析 Accept-Language 头(支持多语言与权重),返回首个受支持的语言; 都不支持时返回默认语言 [EN] Returns the first supported language in the header, else the default.

func (*Config) ResolveLanguage

func (c *Config) ResolveLanguage(lang string) string

ResolveLanguage 解析语言代码:按 ResolutionOrder 依次映射,再校验是否受支持, 不受支持则回退默认语言 [EN] Applies each mapping in ResolutionOrder, then falls back to the default language when the result is not in SupportedLanguages.

func (*Config) WithDefaultLanguage

func (c *Config) WithDefaultLanguage(lang string) *Config

WithDefaultLanguage 设置默认语言

func (*Config) WithFallback

func (c *Config) WithFallback(enabled bool) *Config

WithFallback 设置是否回退默认语言

func (*Config) WithMessageLoader

func (c *Config) WithMessageLoader(l MessageLoader) *Config

WithMessageLoader 设置自定义消息加载器

func (*Config) WithMessagesPath

func (c *Config) WithMessagesPath(path string) *Config

WithMessagesPath 设置翻译文件目录

func (*Config) WithResolutionOrder

func (c *Config) WithResolutionOrder(order []MappingType) *Config

WithResolutionOrder 设置映射应用顺序

func (*Config) WithSupportedLanguages

func (c *Config) WithSupportedLanguages(langs []string) *Config

WithSupportedLanguages 设置支持的语言列表

type Context

type Context struct {
	// Language 当前语言代码
	Language string
	// Translator 翻译器实例
	Translator Translator
}

Context 国际化上下文 携带当前语言和翻译器,支持链式翻译操作

func FromContext

func FromContext(ctx stdcontext.Context) *Context

FromContext 从 stdlib context.Context 中获取 i18n 上下文

func (*Context) GetLanguage

func (ctx *Context) GetLanguage() string

GetLanguage 获取当前语言

func (*Context) SetLanguage

func (ctx *Context) SetLanguage(language string)

SetLanguage 设置当前语言(仅支持已注册的语言)

func (*Context) T

func (ctx *Context) T(key string, args ...any) string

T 翻译函数(简化调用)

func (*Context) TWithMap

func (ctx *Context) TWithMap(key string, templateData map[string]any) string

TWithMap 使用 map 模板数据翻译

type DefaultFormatter

type DefaultFormatter struct{}

DefaultFormatter 默认消息格式化器 支持四种占位符格式:

  • fmt.Sprintf 风格(%s, %d 等)→ 位置参数
  • {key} → 推荐的命名参数
  • {{key}} → 简化模板风格
  • {{.key}} → Go template 风格

func (*DefaultFormatter) Format

func (f *DefaultFormatter) Format(message string, args []any, templateData map[string]any) string

Format 格式化消息,优先使用 templateData(命名参数),其次使用 args(位置参数)

type Error

type Error struct {
	Type    ErrorType
	Message string
}

Error 带类型的错误 [EN] A typed error carrying its ErrorType.

func NewError

func NewError(errType ErrorType, args ...any) Error

NewError 按已注册模板构造错误;模板含占位符时用 args 填充, 未注册的类型退化为类型编号本身,保证错误永远可读 [EN] Builds an error from the registered template; an unregistered type degrades to its numeric id so the error is never empty.

func (Error) Error

func (e Error) Error() string

Error 实现 error 接口

func (Error) GetType

func (e Error) GetType() ErrorType

GetType 返回错误类型

type ErrorType

type ErrorType int

ErrorType 错误类型编号 [EN] Numeric error type.

const (
	// ErrTypeLanguageLoadFailed 语言加载失败
	ErrTypeLanguageLoadFailed ErrorType = 6000 + iota
	// ErrTypeLanguageNotFound 语言未找到
	ErrTypeLanguageNotFound
	// ErrTypeJSONParseFailed JSON 解析失败
	ErrTypeJSONParseFailed
	// ErrTypeMessageLoaderRequired 消息加载器未设置
	ErrTypeMessageLoaderRequired
	// ErrTypeConfigInvalid 配置无效
	ErrTypeConfigInvalid
	// ErrTypeTranslationFailed 翻译失败
	ErrTypeTranslationFailed
)
const (
	// ErrTypeLoaderFileNotFound 加载器文件未找到
	ErrTypeLoaderFileNotFound ErrorType = 6100 + iota
	// ErrTypeLoaderReadFailed 加载器读取失败
	ErrTypeLoaderReadFailed
	// ErrTypeLoaderParseFailed 加载器解析失败
	ErrTypeLoaderParseFailed
	// ErrTypeLoaderLanguageNotFound 加载器语言未找到
	ErrTypeLoaderLanguageNotFound
)

type FileLoader

type FileLoader struct {
	// contains filtered or unexported fields
}

FileLoader 文件系统消息加载器 从指定目录下的 JSON 文件加载翻译消息,支持嵌套 JSON 自动扁平化 文件命名规则: {localesPath}/{language}.json,如 ./locales/zh.json

func NewFileLoader

func NewFileLoader(localesPath string) *FileLoader

NewFileLoader 创建文件系统消息加载器 localesPath: 翻译文件所在目录路径,如 "./locales" 或 "resources/locales"

func (*FileLoader) LoadMessages

func (f *FileLoader) LoadMessages(language string) (map[string]string, error)

LoadMessages 加载指定语言的消息 读取 {localesPath}/{language}.json 文件,支持嵌套 JSON 自动扁平化为点号格式 language: 语言代码,如 "zh", "en", "ja" 等

type Formatter

type Formatter interface {
	// Format 格式化消息
	// message: 消息模板
	// args: 位置参数(如 fmt.Sprintf 风格)
	// templateData: 命名模板数据(如 {key} 风格)
	Format(message string, args []any, templateData map[string]any) string
}

Formatter 消息格式化器接口 定义消息格式化的标准契约,支持位置参数和命名模板数据

type JSONLoader

type JSONLoader struct {
	// contains filtered or unexported fields
}

JSONLoader JSON 消息加载器 从 JSON 字符串直接解析翻译消息,适用于配置文件内嵌或动态生成的场景 JSON 格式为: {"zh": {"key": "值"}, "en": {"key": "value"}}

func NewJSONLoader

func NewJSONLoader(messagesJSON string) (*JSONLoader, error)

NewJSONLoader 创建 JSON 消息加载器 messagesJSON: JSON 格式的翻译消息字符串 格式示例: {"zh": {"hello": "你好"}, "en": {"hello": "Hello"}}

func (*JSONLoader) LoadMessages

func (j *JSONLoader) LoadMessages(language string) (map[string]string, error)

LoadMessages 加载指定语言的消息

type Loader

type Loader interface {
	// LoadMessages 加载指定语言的翻译消息
	// language: 语言代码,如 "zh", "en", "ja" 等
	// 返回该语言的消息映射(键为消息标识,值为翻译文本)
	LoadMessages(language string) (map[string]string, error)
}

Loader 消息加载器接口 定义从不同数据源加载国际化翻译消息的标准契约 与 go-config/pkg/i18n.MessageLoader 接口兼容,所有实现均同时满足两个接口

type Logger

type Logger interface {
	Warn(format string, args ...any)
}

Logger 最小日志接口

本包只在"预加载映射目标语言失败"这一处记录日志,因此接口只要一个方法 任何实现了 Warn(string, ...any) 的 logger(含 go-toolbox/pkg/logger)都能直接传入, 不传则静默——库不应该替使用方决定日志去向 [EN] The package logs in exactly one place, so one method is enough. Any logger with Warn(string, ...any) satisfies it; nil means silence, because a library should not pick a log destination for its caller.

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager 国际化管理器 核心翻译引擎,负责消息加载、语言解析和翻译

func NewManager

func NewManager(config *Config) (*Manager, error)

NewManager 创建国际化管理器 config: i18n 配置,为 nil 时使用 DefaultConfig()

func NewManagerWith

func NewManagerWith(config *Config, log Logger, formatter Formatter) (*Manager, error)

NewManagerWith 创建同时指定日志与格式化器的国际化管理器 log / formatter 为 nil 时各自使用默认值

func NewManagerWithFormatter

func NewManagerWithFormatter(config *Config, formatter Formatter) (*Manager, error)

NewManagerWithFormatter 创建带自定义格式化器的国际化管理器

func NewManagerWithLogger

func NewManagerWithLogger(config *Config, log Logger) (*Manager, error)

NewManagerWithLogger 创建带自定义日志的国际化管理器

func (*Manager) GetConfig

func (m *Manager) GetConfig() *Config

GetConfig 获取当前配置

func (*Manager) GetDefaultLanguage

func (m *Manager) GetDefaultLanguage() string

GetDefaultLanguage 获取默认语言

func (*Manager) GetLoadedLanguages

func (m *Manager) GetLoadedLanguages() []string

GetLoadedLanguages 获取已加载的语言列表

func (*Manager) GetMessage

func (m *Manager) GetMessage(language, key string, args ...any) string

GetMessage 获取翻译消息(实现 Translator 接口)

func (*Manager) GetMessageKeys

func (m *Manager) GetMessageKeys(language string) []string

GetMessageKeys 获取指定语言的所有消息键

func (*Manager) GetMessageWithMap

func (m *Manager) GetMessageWithMap(language, key string, templateData map[string]any) string

GetMessageWithMap 使用 map 模板数据获取翻译消息(实现 Translator 接口)

func (*Manager) GetSupportedLanguages

func (m *Manager) GetSupportedLanguages() []string

GetSupportedLanguages 获取支持的语言列表

func (*Manager) HasLanguage

func (m *Manager) HasLanguage(language string) bool

HasLanguage 检查指定语言的消息是否已加载

func (*Manager) IsEnabled

func (m *Manager) IsEnabled() bool

IsEnabled 检查国际化是否启用

func (*Manager) IsLanguageSupported

func (m *Manager) IsLanguageSupported(language string) bool

IsLanguageSupported 检查语言是否被支持(实现 Translator 接口)

func (*Manager) ReloadLanguage

func (m *Manager) ReloadLanguage(language string) error

ReloadLanguage 重新加载指定语言的消息

func (*Manager) ResolveLanguage

func (m *Manager) ResolveLanguage(lang string) string

ResolveLanguage 解析语言代码(委托给 Config.ResolveLanguage)

type MapLoader

type MapLoader struct {
	// contains filtered or unexported fields
}

MapLoader 内存 Map 消息加载器 直接从内存中的 map 数据结构加载翻译消息 适用于程序启动时硬编码或动态构建的翻译数据

func NewMapLoader

func NewMapLoader(messages map[string]map[string]string) *MapLoader

NewMapLoader 创建内存 Map 消息加载器 messages: 语言消息映射,格式为 map[语言代码]map[消息键]翻译文本 示例: map[string]map[string]string{"zh": {"hello": "你好"}, "en": {"hello": "Hello"}}

func (*MapLoader) LoadMessages

func (m *MapLoader) LoadMessages(language string) (map[string]string, error)

LoadMessages 加载指定语言的消息

type MappingType

type MappingType string

MappingType 语言映射策略

const (
	// LegacyMapping 遗留映射:把历史上用错的代码纠正为正确代码(如 cn -> zh)
	LegacyMapping MappingType = "legacy"
	// StandardMapping 标准映射:把地区变体收敛到基础语言(如 zh-cn -> zh)
	StandardMapping MappingType = "standard"
)

func (MappingType) String

func (m MappingType) String() string

String 返回映射类型的字符串表示

type MessageLoader

type MessageLoader = Loader

MessageLoader 消息加载器(Loader 的别名,便于配置层按此名对接) [EN] Alias of Loader, kept under this name for configuration-layer interop.

func AsMessageLoader

func AsMessageLoader(l Loader) MessageLoader

AsMessageLoader 将 Loader 视作 MessageLoader MessageLoader 现在是 Loader 的类型别名,故直接返回即可;保留此函数仅为兼容既有调用方 [EN] MessageLoader is now an alias of Loader, so this is the identity function; kept only for API compatibility.

type Translator

type Translator interface {
	// GetMessage 获取翻译消息(位置参数)
	GetMessage(language, key string, args ...any) string
	// GetMessageWithMap 获取翻译消息(命名模板数据)
	GetMessageWithMap(language, key string, templateData map[string]any) string
	// IsLanguageSupported 检查语言是否被支持
	IsLanguageSupported(language string) bool
}

Translator 翻译器接口 解耦 Context 与具体 Manager 实现,避免循环依赖

Directories

Path Synopsis
Package yamlloader 提供从 YAML 文件或字符串加载翻译消息的加载器
Package yamlloader 提供从 YAML 文件或字符串加载翻译消息的加载器

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL