mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-11-12 21:44:22 +08:00
fix(i18n): use English runtime text and localize system UI
This commit is contained in:
@@ -467,7 +467,7 @@ func (r *Runner) tryRestartOpenresty(ctx context.Context) {
|
||||
|
||||
func (r *Runner) tryRegister(ctx context.Context, nodeID *string) error {
|
||||
if strings.TrimSpace(r.Config.DiscoveryToken) == "" {
|
||||
return errors.New("agent_token 为空且未配置 discovery_token")
|
||||
return errors.New("agent_token is empty and discovery_token is not configured")
|
||||
}
|
||||
slog.Info("agent discovery registration started")
|
||||
response, err := r.HeartbeatService.Register(ctx, r.HeartbeatCycle.NodePayload(ctx, *nodeID))
|
||||
@@ -475,7 +475,7 @@ func (r *Runner) tryRegister(ctx context.Context, nodeID *string) error {
|
||||
return err
|
||||
}
|
||||
if response == nil || strings.TrimSpace(response.AccessToken) == "" || strings.TrimSpace(response.NodeID) == "" {
|
||||
return errors.New("discovery register response 缺少 node_id 或 agent_token")
|
||||
return errors.New("discovery registration response is missing node_id or agent_token")
|
||||
}
|
||||
snapshot, err := r.StateStore.Load()
|
||||
if err != nil {
|
||||
|
||||
@@ -352,25 +352,25 @@ func joinManagedPath(base string, relative string) string {
|
||||
|
||||
func validate(cfg *Config) error {
|
||||
if cfg.ServerURL == "" {
|
||||
return errors.New("server_url 不能为空")
|
||||
return errors.New("server_url must not be empty")
|
||||
}
|
||||
if strings.TrimSpace(cfg.AccessToken) == "" && strings.TrimSpace(cfg.DiscoveryToken) == "" {
|
||||
return errors.New("agent_token 和 discovery_token 不能同时为空")
|
||||
return errors.New("agent_token and discovery_token must not both be empty")
|
||||
}
|
||||
if cfg.NodeName == "" {
|
||||
return errors.New("node_name 不能为空")
|
||||
return errors.New("node_name must not be empty")
|
||||
}
|
||||
if cfg.NodeIP == "" {
|
||||
return errors.New("node_ip 不能为空")
|
||||
return errors.New("node_ip must not be empty")
|
||||
}
|
||||
if cfg.OpenrestyObservabilityPort <= 0 || cfg.OpenrestyObservabilityPort > 65535 {
|
||||
return errors.New("openresty_observability_port 必须在 1-65535 之间")
|
||||
return errors.New("openresty_observability_port must be between 1 and 65535")
|
||||
}
|
||||
if cfg.ObservabilityReplayMinutes <= 0 {
|
||||
return errors.New("observability_replay_minutes 必须大于 0")
|
||||
return errors.New("observability_replay_minutes must be greater than 0")
|
||||
}
|
||||
if cfg.MMDBUpdateInterval <= 0 {
|
||||
return errors.New("mmdb_update_interval 必须大于 0")
|
||||
return errors.New("mmdb_update_interval must be greater than 0")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -397,10 +397,10 @@ func (cfg *Config) toConfigFile() configFile {
|
||||
// Save persists the current configuration back to its original file path.
|
||||
func (cfg *Config) Save() error {
|
||||
if cfg == nil {
|
||||
return errors.New("config 不能为空")
|
||||
return errors.New("config must not be empty")
|
||||
}
|
||||
if cfg.configPath == "" {
|
||||
return errors.New("config path 未初始化")
|
||||
return errors.New("configuration path is not initialized")
|
||||
}
|
||||
data, err := json.MarshalIndent(cfg.toConfigFile(), "", " ") //nolint:gosec // agent token must be persisted in local config file
|
||||
if err != nil {
|
||||
|
||||
@@ -325,7 +325,7 @@ func (m *Manager) ensureOpenRestyWorkerReadAccess() error {
|
||||
|
||||
func (m *Manager) activateConfig(ctx context.Context) error {
|
||||
if m.Executor == nil {
|
||||
return errors.New("executor 未配置")
|
||||
return errors.New("Executor is not configured")
|
||||
}
|
||||
if err := m.Executor.Test(ctx); err != nil {
|
||||
return err
|
||||
@@ -407,7 +407,7 @@ func (m *Manager) EnsureRuntime(ctx context.Context, recreate bool) error {
|
||||
m.runtimeMu.Lock()
|
||||
defer m.runtimeMu.Unlock()
|
||||
if m.Executor == nil {
|
||||
return errors.New("executor 未配置")
|
||||
return errors.New("Executor is not configured")
|
||||
}
|
||||
slog.Info("openresty ensure runtime requested", "recreate", recreate)
|
||||
return m.Executor.EnsureRuntime(ctx, recreate)
|
||||
@@ -422,7 +422,7 @@ func (m *Manager) EnsureSafeFallbackRuntime(ctx context.Context, reason string)
|
||||
|
||||
func (m *Manager) ensureSafeFallbackRuntime(ctx context.Context, reason string) error {
|
||||
if m.Executor == nil {
|
||||
return errors.New("executor 未配置")
|
||||
return errors.New("Executor is not configured")
|
||||
}
|
||||
trimmedReason := strings.TrimSpace(reason)
|
||||
if trimmedReason == "" {
|
||||
@@ -444,7 +444,7 @@ func (m *Manager) CheckHealth(ctx context.Context) error {
|
||||
m.runtimeMu.Lock()
|
||||
defer m.runtimeMu.Unlock()
|
||||
if m.Executor == nil {
|
||||
return errors.New("executor 未配置")
|
||||
return errors.New("Executor is not configured")
|
||||
}
|
||||
if m.MainConfigPath != "" {
|
||||
if _, err := os.Stat(m.MainConfigPath); os.IsNotExist(err) {
|
||||
@@ -462,7 +462,7 @@ func (m *Manager) Restart(ctx context.Context) error {
|
||||
m.runtimeMu.Lock()
|
||||
defer m.runtimeMu.Unlock()
|
||||
if m.Executor == nil {
|
||||
return errors.New("executor 未配置")
|
||||
return errors.New("Executor is not configured")
|
||||
}
|
||||
slog.Info("openresty restart requested")
|
||||
return m.Executor.Restart(ctx)
|
||||
@@ -473,10 +473,10 @@ func (m *Manager) CurrentChecksum() (string, error) {
|
||||
m.runtimeMu.Lock()
|
||||
defer m.runtimeMu.Unlock()
|
||||
if m.RouteConfigPath == "" {
|
||||
return "", errors.New("route config path 不能为空")
|
||||
return "", errors.New("route configuration path must not be empty")
|
||||
}
|
||||
if m.MainConfigPath == "" {
|
||||
return "", errors.New("main config path 不能为空")
|
||||
return "", errors.New("main configuration path must not be empty")
|
||||
}
|
||||
mainData, err := os.ReadFile(m.MainConfigPath)
|
||||
if err != nil {
|
||||
@@ -828,10 +828,10 @@ type managedFile struct {
|
||||
|
||||
func (m *Manager) backup() (*backupState, error) {
|
||||
if m.MainConfigPath == "" {
|
||||
return nil, errors.New("main config path 不能为空")
|
||||
return nil, errors.New("main configuration path must not be empty")
|
||||
}
|
||||
if m.RouteConfigPath == "" {
|
||||
return nil, errors.New("route config path 不能为空")
|
||||
return nil, errors.New("route configuration path must not be empty")
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(m.MainConfigPath), nginxDirPerm); err != nil {
|
||||
return nil, err
|
||||
@@ -1143,10 +1143,10 @@ func (m *Manager) restoreRuntimeConfig(file *protocol.SupportFile, name string)
|
||||
|
||||
func (m *Manager) writeSafeDefaultFallbackFiles() error {
|
||||
if strings.TrimSpace(m.MainConfigPath) == "" {
|
||||
return errors.New("main config path 不能为空")
|
||||
return errors.New("main configuration path must not be empty")
|
||||
}
|
||||
if strings.TrimSpace(m.RouteConfigPath) == "" {
|
||||
return errors.New("route config path 不能为空")
|
||||
return errors.New("route configuration path must not be empty")
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(m.MainConfigPath), nginxDirPerm); err != nil {
|
||||
return err
|
||||
@@ -1203,7 +1203,7 @@ func removeLegacyPowConfig(path string) error {
|
||||
|
||||
func (m *Manager) certFileTargetPath(relativePath string) (string, error) {
|
||||
if strings.TrimSpace(m.CertDir) == "" {
|
||||
return "", errors.New("cert dir 不能为空")
|
||||
return "", errors.New("certificate directory must not be empty")
|
||||
}
|
||||
candidate := strings.TrimSpace(relativePath)
|
||||
if strings.Contains(candidate, `\`) {
|
||||
@@ -1211,7 +1211,7 @@ func (m *Manager) certFileTargetPath(relativePath string) (string, error) {
|
||||
}
|
||||
normalizedPath := filepath.Clean(filepath.FromSlash(candidate))
|
||||
if normalizedPath == "." || normalizedPath == "" {
|
||||
return "", errors.New("cert file path 不能为空")
|
||||
return "", errors.New("certificate file path must not be empty")
|
||||
}
|
||||
if filepath.IsAbs(normalizedPath) || filepath.VolumeName(normalizedPath) != "" {
|
||||
return "", fmt.Errorf("cert file path %q must be relative", relativePath)
|
||||
@@ -1240,7 +1240,7 @@ func certFileMode(relativePath string) fs.FileMode {
|
||||
|
||||
func luaFileTargetPath(baseDir string, relativePath string) (string, error) {
|
||||
if strings.TrimSpace(baseDir) == "" {
|
||||
return "", errors.New("lua dir 不能为空")
|
||||
return "", errors.New("lua directory must not be empty")
|
||||
}
|
||||
candidate := strings.TrimSpace(relativePath)
|
||||
if strings.Contains(candidate, `\`) {
|
||||
@@ -1248,7 +1248,7 @@ func luaFileTargetPath(baseDir string, relativePath string) (string, error) {
|
||||
}
|
||||
normalizedPath := filepath.Clean(filepath.FromSlash(candidate))
|
||||
if normalizedPath == "." || normalizedPath == "" {
|
||||
return "", errors.New("lua file path 不能为空")
|
||||
return "", errors.New("lua file path must not be empty")
|
||||
}
|
||||
if filepath.IsAbs(normalizedPath) || filepath.VolumeName(normalizedPath) != "" {
|
||||
return "", fmt.Errorf("lua file path %q must be relative", relativePath)
|
||||
|
||||
@@ -14,6 +14,12 @@ import (
|
||||
//go:embed pow_static
|
||||
var powStaticFS embed.FS
|
||||
|
||||
//go:embed pow_static/locales/challenge.en.json
|
||||
var powChallengeEnglish string
|
||||
|
||||
//go:embed pow_static/locales/challenge.zh-CN.json
|
||||
var powChallengeChinese string
|
||||
|
||||
const openRestyPowRuntimeLua = `local _M = {}
|
||||
|
||||
local source = debug.getinfo(1, "S").source or ""
|
||||
@@ -290,7 +296,7 @@ end
|
||||
return require("pow.runtime").check()
|
||||
`
|
||||
|
||||
const openRestyPowChallengeLua = `local cjson = require "cjson.safe"
|
||||
var openRestyPowChallengeLua = `local cjson = require "cjson.safe"
|
||||
|
||||
local pow_challenges = ngx.shared.openflare_pow_challenges
|
||||
local pow_config_dict = ngx.shared.openflare_pow_config
|
||||
@@ -353,21 +359,17 @@ if string.find(accept_lang, "zh") then
|
||||
lang = "zh-CN"
|
||||
end
|
||||
|
||||
local t_title = "Making sure you're not a bot!"
|
||||
local t_status = "Loading..."
|
||||
local t_protected = "This site is protected by a Proof-of-Work challenge. Your browser will solve a small puzzle before the upstream response is shown."
|
||||
local t_why = "Why am I seeing this?"
|
||||
local t_why_desc = "OpenFlare is asking your browser to complete a lightweight computation to distinguish normal browser traffic from automated abuse. This should finish automatically."
|
||||
local t_noscript = "JavaScript is required to pass this verification. Please enable JavaScript and reload."
|
||||
|
||||
if lang == "zh-CN" then
|
||||
t_title = "正在确认你是不是机器人!"
|
||||
t_status = "加载中..."
|
||||
t_protected = "本网站受工作量证明(Proof-of-Work)挑战保护。在显示源站响应之前,您的浏览器将解决一个微型谜题。"
|
||||
t_why = "为什么我会看到这个?"
|
||||
t_why_desc = "OpenFlare 正在要求您的浏览器完成一项轻量级计算,以区分正常的浏览器流量和自动化的恶意请求。这应该会自动完成。"
|
||||
t_noscript = "很遗憾,您必须启用 JavaScript 才能通过这项验证。请开启 JavaScript 并刷新页面。"
|
||||
end
|
||||
local translations = {
|
||||
en = cjson.decode([==[` + powChallengeEnglish + `]==]),
|
||||
["zh-CN"] = cjson.decode([==[` + powChallengeChinese + `]==])
|
||||
}
|
||||
local text = translations[lang] or translations.en
|
||||
local t_title = text.title
|
||||
local t_status = text.status
|
||||
local t_protected = text.protected
|
||||
local t_why = text.why
|
||||
local t_why_desc = text.why_description
|
||||
local t_noscript = text.noscript
|
||||
|
||||
ngx.header.content_type = "text/html; charset=utf-8"
|
||||
ngx.say([[<!DOCTYPE html>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"title": "Making sure you're not a bot!",
|
||||
"status": "Loading...",
|
||||
"protected": "This site is protected by a Proof-of-Work challenge. Your browser will solve a small puzzle before the upstream response is shown.",
|
||||
"why": "Why am I seeing this?",
|
||||
"why_description": "OpenFlare is asking your browser to complete a lightweight computation to distinguish normal browser traffic from automated abuse. This should finish automatically.",
|
||||
"noscript": "JavaScript is required to pass this verification. Please enable JavaScript and reload."
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"title": "正在确认你是不是机器人!",
|
||||
"status": "加载中...",
|
||||
"protected": "本网站受工作量证明(Proof-of-Work)挑战保护。在显示源站响应之前,您的浏览器将解决一个微型谜题。",
|
||||
"why": "为什么我会看到这个?",
|
||||
"why_description": "OpenFlare 正在要求您的浏览器完成一项轻量级计算,以区分正常的浏览器流量和自动化的恶意请求。这应该会自动完成。",
|
||||
"noscript": "很遗憾,您必须启用 JavaScript 才能通过这项验证。请开启 JavaScript 并刷新页面。"
|
||||
}
|
||||
Reference in New Issue
Block a user