Skip to content

Commit f312f5a

Browse files
committed
i18n support and settings menu add
1 parent 1de6baf commit f312f5a

File tree

10 files changed

+294
-37
lines changed

10 files changed

+294
-37
lines changed

config.go

Lines changed: 107 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,67 @@ package main
22

33
import (
44
"encoding/json"
5+
"golang.org/x/sys/windows"
6+
"golang.org/x/text/language"
7+
"golang.org/x/text/language/display"
58
"os"
69
"path/filepath"
10+
"syscall"
11+
"unsafe"
712
)
813

14+
type Config struct {
15+
CustomDirs []CustomDir `json:"customDirs"`
16+
Language string `json:"language"`
17+
}
18+
19+
var config Config
20+
921
func LoadConfig() {
1022
configPath := filepath.Join(getUserHome(), ".hidell", "config.json")
1123
data, err := os.ReadFile(configPath)
1224
if err != nil {
1325
if os.IsNotExist(err) {
14-
customDirs = []CustomDir{}
26+
config = Config{
27+
CustomDirs: []CustomDir{},
28+
Language: getDefaultLanguage(),
29+
}
30+
saveConfig()
1531
return
1632
}
1733
panic(err)
1834
}
1935

20-
err = json.Unmarshal(data, &customDirs)
21-
if err != nil {
22-
panic(err)
36+
// 首先尝试解析完整的新配置
37+
err = json.Unmarshal(data, &config)
38+
if err == nil {
39+
// 成功解析新配置
40+
if config.Language == "" {
41+
config.Language = getDefaultLanguage()
42+
saveConfig()
43+
}
44+
} else {
45+
// 如果解析失败,尝试解析旧版本的配置文件
46+
var oldConfig []CustomDir
47+
err = json.Unmarshal(data, &oldConfig)
48+
if err != nil {
49+
panic(err)
50+
}
51+
// 使用旧配置并创建新的配置结构
52+
config = Config{
53+
CustomDirs: oldConfig,
54+
Language: getDefaultLanguage(),
55+
}
56+
// 保存更新后的配置
57+
saveConfig()
2358
}
59+
60+
customDirs = config.CustomDirs
2461
}
2562

2663
func saveConfig() {
2764
configPath := filepath.Join(getUserHome(), ".hidell", "config.json")
28-
data, err := json.MarshalIndent(customDirs, "", " ")
65+
data, err := json.MarshalIndent(config, "", " ")
2966
if err != nil {
3067
panic(err)
3168
}
@@ -40,3 +77,68 @@ func saveConfig() {
4077
panic(err)
4178
}
4279
}
80+
81+
func getDefaultLanguage() string {
82+
// 获取用户界面语言
83+
k32 := windows.NewLazySystemDLL("kernel32.dll")
84+
getUserDefaultUILanguage := k32.NewProc("GetUserDefaultUILanguage")
85+
if getUserDefaultUILanguage.Find() == nil {
86+
ret, _, _ := getUserDefaultUILanguage.Call()
87+
langID := uint16(ret)
88+
userLang := windowsLangIDToISO639(langID)
89+
if userLang != "" {
90+
return mapLanguage(userLang)
91+
}
92+
}
93+
94+
// 如果无法获取用户界面语言,尝试获取系统区域设置
95+
systemLang := getSystemLocale()
96+
return mapLanguage(systemLang)
97+
}
98+
99+
func windowsLangIDToISO639(langID uint16) string {
100+
// 这里只处理了英语和中文,您可以根据需要添加更多语言
101+
switch langID {
102+
case 0x0409: // English (United States)
103+
return "en"
104+
case 0x0804: // Chinese (Simplified, PRC)
105+
return "zh"
106+
case 0x0C04: // Chinese (Traditional, Hong Kong S.A.R.)
107+
return "zh"
108+
case 0x1004: // Chinese (Simplified, Singapore)
109+
return "zh"
110+
case 0x0404: // Chinese (Traditional, Taiwan)
111+
return "zh"
112+
default:
113+
return ""
114+
}
115+
}
116+
117+
func getSystemLocale() string {
118+
kernel32 := syscall.NewLazyDLL("kernel32.dll")
119+
getSystemDefaultLocaleName := kernel32.NewProc("GetSystemDefaultLocaleName")
120+
121+
buf := make([]uint16, 85) // LOCALE_NAME_MAX_LENGTH = 85
122+
r, _, _ := getSystemDefaultLocaleName.Call(uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)))
123+
if r == 0 {
124+
return "en" // 默认返回英语
125+
}
126+
127+
return syscall.UTF16ToString(buf)
128+
}
129+
130+
func mapLanguage(lang string) string {
131+
tag := language.Make(lang)
132+
base, _ := tag.Base()
133+
langName := display.English.Languages().Name(base)
134+
135+
switch langName {
136+
case "English":
137+
return "en"
138+
case "Chinese":
139+
return "zh"
140+
// 添加其他支持的语言
141+
default:
142+
return "en"
143+
}
144+
}

custom_dir.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ func addCustomDirMenu(dir *CustomDir, parentMenu *systray.MenuItem) {
2525
menuName = dir.Path
2626
}
2727
dirMenu := parentMenu.AddSubMenuItem(menuName, "")
28-
mActivate := dirMenu.AddSubMenuItem("激活", "")
29-
mShow := dirMenu.AddSubMenuItem("显示", "")
30-
mHide := dirMenu.AddSubMenuItem("隐藏", "")
31-
mRemove := dirMenu.AddSubMenuItem("移除", "")
28+
mActivate := dirMenu.AddSubMenuItem(t("activate"), "")
29+
mShow := dirMenu.AddSubMenuItem(t("show"), "")
30+
mHide := dirMenu.AddSubMenuItem(t("hide"), "")
31+
mRemove := dirMenu.AddSubMenuItem(t("remove"), "")
3232

3333
if dir.Active {
3434
mActivate.Check()

file_operations.go

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ import (
66
"path/filepath"
77
"strings"
88
"syscall"
9+
"unsafe"
10+
)
11+
12+
var (
13+
kernel32 = syscall.NewLazyDLL("kernel32.dll")
14+
setFileAttributes = kernel32.NewProc("SetFileAttributesW")
915
)
1016

1117
func hideDotFiles(dir string) {
@@ -41,7 +47,11 @@ func hideFile(path string) {
4147
if err != nil {
4248
panic(err)
4349
}
44-
_ = syscall.SetFileAttributes(ptr, attrs|syscall.FILE_ATTRIBUTE_HIDDEN)
50+
// 设置隐藏属性和系统属性
51+
_, _, err = setFileAttributes.Call(uintptr(unsafe.Pointer(ptr)), uintptr(attrs|syscall.FILE_ATTRIBUTE_HIDDEN|syscall.FILE_ATTRIBUTE_SYSTEM))
52+
if err != nil && err != syscall.Errno(0) {
53+
panic(err)
54+
}
4555
}
4656

4757
func unhideFile(path string) {
@@ -53,17 +63,15 @@ func unhideFile(path string) {
5363
if err != nil {
5464
panic(err)
5565
}
56-
_ = syscall.SetFileAttributes(ptr, attrs&^syscall.FILE_ATTRIBUTE_HIDDEN)
57-
}
58-
59-
func watchDir(dir string, done chan struct{}) {
60-
watcher, err := fsnotify.NewWatcher()
61-
if err != nil {
66+
// 移除隐藏属性和系统属性
67+
_, _, err = setFileAttributes.Call(uintptr(unsafe.Pointer(ptr)), uintptr(attrs&^(syscall.FILE_ATTRIBUTE_HIDDEN|syscall.FILE_ATTRIBUTE_SYSTEM)))
68+
if err != nil && err != syscall.Errno(0) {
6269
panic(err)
6370
}
64-
defer watcher.Close()
71+
}
6572

66-
err = watcher.Add(dir)
73+
func watchDir(dir string, done chan struct{}) {
74+
err := watcher.Add(dir)
6775
if err != nil {
6876
panic(err)
6977
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ require (
88
github.com/ncruces/zenity v0.10.14
99
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
1010
golang.org/x/sys v0.25.0
11+
golang.org/x/text v0.18.0
1112
)
1213

1314
require (

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7w
4848
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
4949
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
5050
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
51+
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
52+
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
5153
gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E=
5254
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
5355
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=

i18n.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package main
2+
3+
import (
4+
"encoding/json"
5+
"io/ioutil"
6+
)
7+
8+
var translations map[string]map[string]string
9+
10+
func loadTranslations() {
11+
translations = make(map[string]map[string]string)
12+
13+
languages := []string{"en", "zh"}
14+
for _, lang := range languages {
15+
file, err := ioutil.ReadFile("locales/" + lang + ".json")
16+
if err != nil {
17+
panic(err)
18+
}
19+
20+
var langTranslations map[string]string
21+
err = json.Unmarshal(file, &langTranslations)
22+
if err != nil {
23+
panic(err)
24+
}
25+
26+
translations[lang] = langTranslations
27+
}
28+
}
29+
30+
func t(key string) string {
31+
lang := config.Language
32+
if _, ok := translations[lang]; !ok {
33+
lang = "en" // 默认语言
34+
}
35+
36+
if translation, ok := translations[lang][key]; ok {
37+
return translation
38+
}
39+
return key
40+
}

locales/en.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"activate": "Activate",
3+
"show": "Show",
4+
"hide": "Hide",
5+
"remove": "Remove",
6+
"auto_hide_new_dot_files": "Automatically hide new dot files/folders",
7+
"hide_existing_dot_files": "Hide existing dot files/folders",
8+
"show_existing_dot_files": "Show existing dot files/folders",
9+
"custom": "Custom",
10+
"add_custom_directory": "Add custom directory",
11+
"about_hidell": "About HIDELL",
12+
"language": "Language",
13+
"auto_start": "Auto Start",
14+
"set_auto_start": "Set program to auto start",
15+
"quit": "Quit",
16+
"add_directory": "Add Directory",
17+
"add_new_directory": "Add new directory",
18+
"settings": "Settings"
19+
}

locales/zh.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"activate": "激活",
3+
"show": "显示",
4+
"hide": "隐藏",
5+
"remove": "移除",
6+
"auto_hide_new_dot_files": "自动隐藏新生成的点文件/点文件夹",
7+
"hide_existing_dot_files": "隐藏已存在的点文件/点文件夹",
8+
"show_existing_dot_files": "显示已存在的点文件/点文件夹",
9+
"custom": "自定义",
10+
"add_custom_directory": "添加自定义目录",
11+
"about_hidell": "关于HIDELL",
12+
"language": "语言",
13+
"auto_start": "开机自启",
14+
"set_auto_start": "设置程序开机自启",
15+
"quit": "退出",
16+
"add_directory": "添加目录",
17+
"add_new_directory": "添加新的目录",
18+
"settings": "设置"
19+
}
20+

main.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
_ "embed"
5+
"github.com/fsnotify/fsnotify"
56
"github.com/getlantern/systray"
67
"os"
78
)
@@ -12,9 +13,21 @@ var logo []byte
1213
// 控制 watchDir goroutine 的通道
1314
var watcherDone chan struct{}
1415

16+
// 全局 watcher 对象
17+
var watcher *fsnotify.Watcher
18+
1519
func main() {
1620
LoadConfig()
21+
loadTranslations()
1722
watcherDone = make(chan struct{})
23+
24+
// 初始化全局 watcher
25+
var err error
26+
watcher, err = fsnotify.NewWatcher()
27+
if err != nil {
28+
panic(err)
29+
}
30+
1831
go watchDir(getUserHome(), watcherDone)
1932
systray.Run(onReady, onExit)
2033
}
@@ -24,6 +37,9 @@ func onExit() {
2437
if watcherDone != nil {
2538
close(watcherDone)
2639
}
40+
if watcher != nil {
41+
watcher.Close()
42+
}
2743
}
2844

2945
func getUserHome() string {

0 commit comments

Comments
 (0)