Files
yoyo/internal/lang/lang.go
z.to 24ba405d55 feat: add language support and onboard configuration wizard (v0.2.0)
- Add language code intelligent parsing module (internal/lang)
- Support --lang parameter for target language specification
- Support multiple language code formats (BCP47, aliases, Chinese names)
- Implement interactive onboard configuration wizard
- Update Config struct with language fields
- Add survey library dependency for interactive UI
- Improve CLI command interface
- Add comprehensive unit tests for language module
- Update documentation (AGENTS.md, changelog.md, taolun.md, memory.md)

Supported language codes:
- Standard: zh-CN, zh-TW, en-US, en-GB, ja, ko, es, fr, de
- Aliases: cn, en, jp, kr, es, fr, de
- Chinese names: chinese, english, japanese

Commands:
- yoyo "Hello world" - basic translation
- yoyo --lang=cn "Hello world" - specify target language
- yoyo onboard - start configuration wizard
- yoyo onboard --force - force reconfiguration

Version: 0.2.0
2026-03-29 01:30:42 +08:00

318 lines
6.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package lang
import (
"fmt"
"sort"
"strings"
)
// 语言代码映射表
var languageMap = map[string]string{
// 中文变体
"cn": "zh-CN",
"zh": "zh-CN", // 默认简体中文
"zhcn": "zh-CN",
"zhtw": "zh-TW",
"zhhk": "zh-HK",
"zh-hans": "zh-CN",
"zh-hant": "zh-TW",
"chinese": "zh-CN",
"简体中文": "zh-CN",
"繁体中文": "zh-TW",
// 英语变体
"en": "en-US", // 默认美式英语
"us": "en-US",
"uk": "en-GB",
"gb": "en-GB",
"english": "en-US",
"美式英语": "en-US",
"英式英语": "en-GB",
// 日语
"jp": "ja",
"ja": "ja",
"japanese": "ja",
"日语": "ja",
// 韩语
"kr": "ko",
"ko": "ko",
"korean": "ko",
"韩语": "ko",
// 西班牙语
"es": "es-ES",
"spanish": "es-ES",
"西班牙语": "es-ES",
// 法语
"fr": "fr-FR",
"french": "fr-FR",
"法语": "fr-FR",
// 德语
"de": "de-DE",
"german": "de-DE",
"德语": "de-DE",
// 俄语
"ru": "ru-RU",
"russian": "ru-RU",
"俄语": "ru-RU",
// 葡萄牙语
"pt": "pt-PT",
"portuguese": "pt-PT",
"葡萄牙语": "pt-PT",
"br": "pt-BR", // 巴西葡萄牙语
// 意大利语
"it": "it-IT",
"italian": "it-IT",
"意大利语": "it-IT",
// 阿拉伯语
"ar": "ar-SA",
"arabic": "ar-SA",
"阿拉伯语": "ar-SA",
// 印地语
"hi": "hi-IN",
"hindi": "hi-IN",
"印地语": "hi-IN",
// 其他语言
"nl": "nl-NL", // 荷兰语
"dutch": "nl-NL",
"sv": "sv-SE", // 瑞典语
"swedish": "sv-SE",
"no": "nb-NO", // 挪威语
"norwegian": "nb-NO",
"da": "da-DK", // 丹麦语
"danish": "da-DK",
"fi": "fi-FI", // 芬兰语
"finnish": "fi-FI",
"pl": "pl-PL", // 波兰语
"polish": "pl-PL",
"tr": "tr-TR", // 土耳其语
"turkish": "tr-TR",
"th": "th-TH", // 泰语
"thai": "th-TH",
"vi": "vi-VN", // 越南语
"vietnamese": "vi-VN",
"id": "id-ID", // 印尼语
"indonesian": "id-ID",
"ms": "ms-MY", // 马来语
"malay": "ms-MY",
}
// 语言名称到代码的映射(用于显示)
var languageNames = map[string]string{
"zh-CN": "中文(简体)",
"zh-TW": "中文(繁体)",
"zh-HK": "中文(香港)",
"en-US": "English (US)",
"en-GB": "English (UK)",
"ja": "日本語",
"ko": "한국어",
"es-ES": "Español",
"fr-FR": "Français",
"de-DE": "Deutsch",
"ru-RU": "Русский",
"pt-PT": "Português",
"pt-BR": "Português (Brasil)",
"it-IT": "Italiano",
"ar-SA": "العربية",
"hi-IN": "हिन्दी",
"nl-NL": "Nederlands",
"sv-SE": "Svenska",
"nb-NO": "Norsk",
"da-DK": "Dansk",
"fi-FI": "Suomi",
"pl-PL": "Polski",
"tr-TR": "Türkçe",
"th-TH": "ไทย",
"vi-VN": "Tiếng Việt",
"id-ID": "Bahasa Indonesia",
"ms-MY": "Bahasa Melayu",
}
// ParseLanguageCode 解析语言代码
// 支持多种格式标准BCP47格式、别名、中文名称等
func ParseLanguageCode(input string) string {
if input == "" {
return ""
}
// 转换为小写进行匹配
lower := strings.ToLower(strings.TrimSpace(input))
// 直接匹配
if code, exists := languageMap[lower]; exists {
return code
}
// 尝试解析BCP47格式如 zh-CN, en-US
if isValidLanguageTag(input) {
return normalizeLanguageTag(input)
}
// 如果无法解析,返回原始输入
return input
}
// isValidLanguageTag 检查是否是有效的语言标签格式
func isValidLanguageTag(tag string) bool {
// 简单的格式检查:语言代码-地区代码
parts := strings.Split(tag, "-")
if len(parts) == 1 {
// 只有语言代码,如 "zh", "en"
return len(parts[0]) >= 2 && len(parts[0]) <= 3
}
if len(parts) == 2 {
// 语言代码-地区代码,如 "zh-CN", "en-US"
return len(parts[0]) >= 2 && len(parts[0]) <= 3 && len(parts[1]) == 2
}
return false
}
// normalizeLanguageTag 标准化语言标签
func normalizeLanguageTag(tag string) string {
parts := strings.Split(tag, "-")
if len(parts) == 1 {
// 只有语言代码,使用默认地区
defaultRegions := map[string]string{
"zh": "CN",
"en": "US",
"ja": "JP",
"ko": "KR",
"es": "ES",
"fr": "FR",
"de": "DE",
"ru": "RU",
"pt": "PT",
"it": "IT",
"ar": "SA",
"hi": "IN",
"nl": "NL",
"sv": "SE",
"no": "NO",
"da": "DK",
"fi": "FI",
"pl": "PL",
"tr": "TR",
"th": "TH",
"vi": "VN",
"id": "ID",
"ms": "MY",
}
if region, exists := defaultRegions[parts[0]]; exists {
return fmt.Sprintf("%s-%s", strings.ToLower(parts[0]), strings.ToUpper(region))
}
return tag
}
if len(parts) == 2 {
// 标准化格式:语言小写,地区大写
return fmt.Sprintf("%s-%s", strings.ToLower(parts[0]), strings.ToUpper(parts[1]))
}
return tag
}
// GetLanguageName 获取语言名称(用于显示)
func GetLanguageName(code string) string {
if name, exists := languageNames[code]; exists {
return name
}
return code
}
// GetLanguageNameOrDefault 获取语言名称,如果不存在则返回代码
func GetLanguageNameOrDefault(code string, defaultName string) string {
if name, exists := languageNames[code]; exists {
return name
}
return defaultName
}
// SupportedLanguages 获取支持的语言列表
func SupportedLanguages() []string {
codes := make([]string, 0, len(languageNames))
for code := range languageNames {
codes = append(codes, code)
}
sort.Strings(codes)
return codes
}
// GetLanguageSuggestions 获取语言建议(用于模糊匹配)
func GetLanguageSuggestions(input string, limit int) []string {
if input == "" {
return []string{}
}
lower := strings.ToLower(input)
suggestions := make([]string, 0)
for alias, code := range languageMap {
if strings.Contains(alias, lower) || strings.Contains(strings.ToLower(code), lower) {
// 避免重复
found := false
for _, s := range suggestions {
if s == code {
found = true
break
}
}
if !found {
suggestions = append(suggestions, code)
}
}
}
// 限制数量
if len(suggestions) > limit {
suggestions = suggestions[:limit]
}
return suggestions
}
// IsLanguageSupported 检查语言是否支持
func IsLanguageSupported(code string) bool {
normalized := ParseLanguageCode(code)
_, exists := languageNames[normalized]
return exists
}
// GetCommonLanguages 获取常用语言列表
func GetCommonLanguages() []string {
return []string{
"zh-CN", // 中文(简体)
"en-US", // 英语(美国)
"ja", // 日语
"ko", // 韩语
"es-ES", // 西班牙语
"fr-FR", // 法语
"de-DE", // 德语
"ru-RU", // 俄语
"pt-PT", // 葡萄牙语
"it-IT", // 意大利语
}
}
// GetLanguageDirection 获取语言方向(从左到右或从右到左)
func GetLanguageDirection(code string) string {
rtlLanguages := map[string]bool{
"ar-SA": true, // 阿拉伯语
"he-IL": true, // 希伯来语
"fa-IR": true, // 波斯语
"ur-PK": true, // 乌尔都语
}
if rtlLanguages[code] {
return "rtl"
}
return "ltr"
}