Skip to content

Commit a645719

Browse files
authored
feat: i18n (#27)
* feat: i18n * feat: update license to PolyForm Noncommercial License 1.0.0 in README files * feat: add internationalization support and user preference management
1 parent 26b048c commit a645719

39 files changed

+2804
-799
lines changed

LICENSE

Lines changed: 95 additions & 359 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
- **Multiple AI Providers**: Integrated with OpenAI, Claude, and Gemini
1717
- **Local Asset Management**: Built-in asset library with local file storage
1818
- **Project Management**: Save, load, and manage multiple workflow projects
19+
- **Multilingual Interface**: Built-in internationalization support
1920
- **Cross-Platform**: Native desktop app for macOS, Windows, and Linux
2021

2122
## 📸 Screenshots
@@ -47,6 +48,7 @@
4748
- ReactFlow (@xyflow/react) - Visual Canvas
4849
- Tailwind CSS 4 - Styling
4950
- shadcn/ui - UI Component Library
51+
- Lingui - Internationalization (i18n)
5052

5153
## 🚀 Quick Start
5254

@@ -182,7 +184,9 @@ Contributions are welcome! Feel free to submit a Pull Request.
182184

183185
## 📄 License
184186

185-
This project is licensed under the Creative Commons Attribution 4.0 International License - see the [LICENSE](LICENSE) file for details.
187+
This project is licensed under the PolyForm Noncommercial License 1.0.0 - see the [LICENSE](LICENSE) file for details.
188+
189+
This is a noncommercial license that allows personal use, research, and use by noncommercial organizations, but does not permit commercial use.
186190

187191
## 🙏 Acknowledgments
188192

README.zh-CN.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
- **多 AI 提供商**:集成 OpenAI、Claude 和 Gemini
1717
- **本地资源管理**:内置资源库,本地文件存储
1818
- **项目管理**:保存、加载和管理多个工作流项目
19+
- **多语言界面**:内置国际化支持
1920
- **跨平台**:支持 macOS、Windows 和 Linux 的原生桌面应用
2021

2122
## 📸 截图
@@ -47,6 +48,7 @@
4748
- ReactFlow(@xyflow/react)- 可视化画布
4849
- Tailwind CSS 4 - 样式
4950
- shadcn/ui - UI 组件库
51+
- Lingui - 国际化(i18n)
5052

5153
## 🚀 快速开始
5254

@@ -182,7 +184,9 @@ visionflow/
182184

183185
## 📄 许可证
184186

185-
本项目采用 Creative Commons Attribution 4.0 International License 许可 - 详见 [LICENSE](LICENSE) 文件。
187+
本项目采用 PolyForm Noncommercial License 1.0.0 许可 - 详见 [LICENSE](LICENSE) 文件。
188+
189+
这是一个非商业许可证,允许个人使用、研究和非商业组织使用,但不允许商业用途。
186190

187191
## 🙏 致谢
188192

binding/app/service.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"net/http"
88
"strconv"
99
"strings"
10+
"visionflow/database"
1011
)
1112

1213
type Service struct {
@@ -69,7 +70,7 @@ func (s *Service) CheckUpdate() UpdateInfo {
6970
if err != nil {
7071
return UpdateInfo{CurrentVersion: currentVersion, Error: "Failed to create request: " + err.Error()}
7172
}
72-
73+
7374
// Add User-Agent header which is often required by GitHub API
7475
req.Header.Set("User-Agent", "VisionFlow-Updater")
7576

@@ -115,7 +116,7 @@ func (s *Service) CheckUpdate() UpdateInfo {
115116

116117
// 3. Compare versions
117118
latestVersionTag := strings.TrimPrefix(latestRelease.TagName, "v")
118-
119+
119120
hasUpdate := compareVersions(latestVersionTag, currentVersion) > 0
120121

121122
return UpdateInfo{
@@ -159,3 +160,13 @@ func compareVersions(v1, v2 string) int {
159160
}
160161
return 0
161162
}
163+
164+
// GetUserPreference retrieves a user preference value by key
165+
func (s *Service) GetUserPreference(key string) (string, error) {
166+
return database.GetUserPreference(key)
167+
}
168+
169+
// SetUserPreference sets or updates a user preference
170+
func (s *Service) SetUserPreference(key, value string) error {
171+
return database.SetUserPreference(key, value)
172+
}

database/db.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ func InitDB() error {
5353
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
5454
FOREIGN KEY(project_id) REFERENCES projects(id)
5555
);
56+
57+
CREATE TABLE IF NOT EXISTS user_preferences (
58+
key TEXT PRIMARY KEY,
59+
value TEXT NOT NULL,
60+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
61+
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
62+
);
5663
`
5764
_, err = DB.Exec(schema)
5865
if err != nil {

database/models.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,11 @@ type Asset struct {
5050
CreatedAt time.Time `db:"created_at" json:"createdAt"`
5151
UpdatedAt time.Time `db:"updated_at" json:"updatedAt"`
5252
}
53+
54+
// UserPreference represents a user preference key-value pair
55+
type UserPreference struct {
56+
Key string `db:"key" json:"key"`
57+
Value string `db:"value" json:"value"`
58+
CreatedAt time.Time `db:"created_at" json:"createdAt"`
59+
UpdatedAt time.Time `db:"updated_at" json:"updatedAt"`
60+
}

database/repository.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,3 +197,45 @@ func DeleteAsset(id int) error {
197197

198198
return nil
199199
}
200+
201+
// GetUserPreference retrieves a user preference by key
202+
func GetUserPreference(key string) (string, error) {
203+
var pref UserPreference
204+
err := DB.Get(&pref, "SELECT * FROM user_preferences WHERE key = ?", key)
205+
if err != nil {
206+
if errors.Is(err, sql.ErrNoRows) {
207+
return "", nil // Not found, return empty string
208+
}
209+
return "", err
210+
}
211+
return pref.Value, nil
212+
}
213+
214+
// SetUserPreference sets or updates a user preference
215+
func SetUserPreference(key, value string) error {
216+
// Try to update first
217+
result, err := DB.Exec(`
218+
UPDATE user_preferences
219+
SET value = ?, updated_at = CURRENT_TIMESTAMP
220+
WHERE key = ?
221+
`, value, key)
222+
if err != nil {
223+
return err
224+
}
225+
226+
// If no rows affected, insert
227+
rowsAffected, err := result.RowsAffected()
228+
if err != nil {
229+
return err
230+
}
231+
232+
if rowsAffected == 0 {
233+
_, err = DB.Exec(`
234+
INSERT INTO user_preferences (key, value, created_at, updated_at)
235+
VALUES (?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
236+
`, key, value)
237+
return err
238+
}
239+
240+
return nil
241+
}

frontend/lingui.config.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { defineConfig } from "@lingui/cli";
2+
3+
export default defineConfig({
4+
sourceLocale: "en",
5+
locales: ["en", "zh-CN"],
6+
catalogs: [
7+
{
8+
path: "<rootDir>/src/locales/{locale}/messages",
9+
include: ["src"],
10+
},
11+
],
12+
});

frontend/package.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,15 @@
77
"dev": "vite",
88
"build": "tsc -b && vite build",
99
"lint": "eslint .",
10-
"preview": "vite preview"
10+
"preview": "vite preview",
11+
"extract": "lingui extract",
12+
"compile": "lingui compile"
1113
},
1214
"dependencies": {
1315
"@base-ui/react": "^1.0.0",
1416
"@fontsource-variable/inter": "^5.2.8",
17+
"@lingui/core": "^5.7.0",
18+
"@lingui/react": "^5.7.0",
1519
"@tailwindcss/vite": "^4.1.17",
1620
"@xyflow/react": "^12.10.0",
1721
"class-variance-authority": "^0.7.1",
@@ -31,6 +35,9 @@
3135
},
3236
"devDependencies": {
3337
"@eslint/js": "^9.39.1",
38+
"@lingui/babel-plugin-lingui-macro": "^5.7.0",
39+
"@lingui/cli": "^5.7.0",
40+
"@lingui/vite-plugin": "^5.7.0",
3441
"@types/node": "^24.10.1",
3542
"@types/react": "^19.2.5",
3643
"@types/react-dom": "^19.2.3",

frontend/package.json.md5

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
f510197448dce85168f8ff06bb3b3003
1+
c8890003b031e7458f91b09c2b9f2c7b

0 commit comments

Comments
 (0)