Dockerfile, docker-compose, Gitea CI, Makefile, i18n (en/fa)
Some checks failed
CI / build (push) Failing after 27s

This commit is contained in:
2026-06-23 20:23:04 +03:30
parent 7176f9b81d
commit 0bb5db46d0
8 changed files with 200 additions and 0 deletions

16
pkg/i18n/en.json Normal file
View File

@@ -0,0 +1,16 @@
{
"unknown_command": "Unknown command",
"clock_in": "Clock In",
"clock_out": "Clock Out",
"error": "Error",
"no_permission": "You do not have permission",
"remote_switched_on": "Remote mode enabled",
"remote_switched_off": "Remote mode disabled",
"already_clocked_in": "You are already clocked in",
"already_clocked_out": "You are already clocked out",
"break_started": "Break started",
"remote_enabled": "Remote mode enabled",
"remote_disabled": "Remote mode disabled",
"dayoff_set": "Today marked as day off",
"dayoff_removed": "Day off removed"
}

16
pkg/i18n/fa.json Normal file
View File

@@ -0,0 +1,16 @@
{
"unknown_command": "دستور نامشخص",
"clock_in": "ورودی کاری",
"clock_out": "خروج کاری",
"error": "خطا",
"no_permission": "دسترسی ندارید",
"remote_switched_on": "وضعیت راه دور فعال شد",
"remote_switched_off": "وضعیت راه دور غیرفعال شد",
"already_clocked_in": "شما قبلاً ورود زده‌اید",
"already_clocked_out": "شما قبلاً خروج زده‌اید",
"break_started": "استراحت شروع شد",
"remote_enabled": "وضعیت راه دور فعال شد",
"remote_disabled": "وضعیت راه دور غیرفعال شد",
"dayoff_set": "امروز به عنوان تعطیل ثبت شد",
"dayoff_removed": "تعطیلی برداشته شد"
}

67
pkg/i18n/translator.go Normal file
View File

@@ -0,0 +1,67 @@
package i18n
import (
"encoding/json"
"fmt"
"io/ioutil"
"path/filepath"
"sync"
)
// Translator handles translation loading and retrieval.
type Translator struct {
mu sync.RWMutex
messages map[string]map[string]string // lang -> key -> message
}
// NewTranslator loads JSON locale files en.json and fa.json from the i18n directory.
// defaultLang sets the default fallback language (e.g., "en").
func NewTranslator(defaultLang string) (*Translator, error) {
if defaultLang == "" {
defaultLang = "en"
}
t := &Translator{
messages: make(map[string]map[string]string),
}
// Load known locale files: en.json and fa.json located in the same package directory.
for _, lang := range []string{"en", "fa"} {
filePath := filepath.Join("i18n", lang+".json")
data, err := ioutil.ReadFile(filePath)
if err != nil {
return nil, err
}
var m map[string]string
if err := json.Unmarshal(data, &m); err != nil {
return nil, err
}
t.messages[lang] = m
}
// Ensure default language exists.
if _, ok := t.messages[defaultLang]; !ok {
return nil, fmt.Errorf("default language %s not found", defaultLang)
}
return t, nil
}
// Get returns the translated string for a given key and language.
// Falls back to English if the key/language is missing.
func (t *Translator) Get(key, lang string) string {
if lang == "" {
lang = "en"
}
t.mu.RLock()
defer t.mu.RUnlock()
if msgs, ok := t.messages[lang]; ok {
if v, ok := msgs[key]; ok {
return v
}
}
// fallback to English messages
if msgs, ok := t.messages["en"]; ok {
if v, ok := msgs[key]; ok {
return v
}
}
// If not found, return the key itself.
return key
}