Русский и английский языки интерфейса
Язык выбирается в шапке панели, а до первого выбора берётся из настроек браузера. Переведены интерфейс, подписи и описания всех параметров конфигов, ошибки API и служебные сообщения менеджера в консоли. Подписи параметров вынесены из app.js в hints-<язык>.json: их больше четырёхсот на язык, и грузить чужой язык незачем. Сообщения менеджера переводятся на выходе из API по словарю, где ключом служит русская фраза из кода, — вывод самого игрового сервера через него проходит без изменений. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,19 +8,26 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/mrleo1nid/pzmanager/internal/i18n"
|
||||
"github.com/mrleo1nid/pzmanager/internal/pzserver"
|
||||
)
|
||||
|
||||
func (s *Server) handleStatus(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusOK, map[string]any{
|
||||
"server": s.sup.Status(),
|
||||
"task": s.jobs.Status(),
|
||||
})
|
||||
lang := i18n.FromRequest(r)
|
||||
status := s.sup.Status()
|
||||
status.LastExit = i18n.T(lang, status.LastExit)
|
||||
|
||||
// Имя задачи придумано менеджером и висит в панели, пока задача идёт.
|
||||
task := s.jobs.Status()
|
||||
task.Name = i18n.T(lang, task.Name)
|
||||
task.Error = i18n.T(lang, task.Error)
|
||||
|
||||
writeJSON(w, http.StatusOK, map[string]any{"server": status, "task": task})
|
||||
}
|
||||
|
||||
func (s *Server) handleStart(w http.ResponseWriter, r *http.Request) {
|
||||
if err := s.sup.Start(); err != nil {
|
||||
writeOpError(w, err)
|
||||
writeOpError(w, r, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, map[string]any{"state": s.sup.State()})
|
||||
@@ -31,7 +38,7 @@ func (s *Server) handleStart(w http.ResponseWriter, r *http.Request) {
|
||||
// видит прогресс по состоянию и логам.
|
||||
func (s *Server) handleStop(w http.ResponseWriter, r *http.Request) {
|
||||
if s.sup.State() == pzserver.StateStopped {
|
||||
writeOpError(w, pzserver.ErrNotRunning)
|
||||
writeOpError(w, r, pzserver.ErrNotRunning)
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
@@ -44,7 +51,7 @@ func (s *Server) handleStop(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func (s *Server) handleRestart(w http.ResponseWriter, r *http.Request) {
|
||||
if !s.sup.Installed() {
|
||||
writeOpError(w, pzserver.ErrNotInstalled)
|
||||
writeOpError(w, r, pzserver.ErrNotInstalled)
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
@@ -63,7 +70,7 @@ func (s *Server) handleConsole(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
if err := s.sup.Send(body.Command); err != nil {
|
||||
writeOpError(w, err)
|
||||
writeOpError(w, r, err)
|
||||
return
|
||||
}
|
||||
writeJSON(w, http.StatusOK, map[string]any{"sent": body.Command})
|
||||
@@ -72,7 +79,23 @@ func (s *Server) handleConsole(w http.ResponseWriter, r *http.Request) {
|
||||
// handleLogs отдаёт историю консоли начиная с указанного номера строки.
|
||||
func (s *Server) handleLogs(w http.ResponseWriter, r *http.Request) {
|
||||
since, _ := strconv.ParseInt(r.URL.Query().Get("since"), 10, 64)
|
||||
writeJSON(w, http.StatusOK, map[string]any{"lines": s.sup.Lines(since)})
|
||||
writeJSON(w, http.StatusOK, map[string]any{"lines": translateLines(r, s.sup.Lines(since))})
|
||||
}
|
||||
|
||||
// translateLines переводит строки консоли на язык читающего. Буфер один на
|
||||
// всех, поэтому перевод делается на выходе, у каждого подключения свой. Вывод
|
||||
// самого игрового сервера через словарь проходит без изменений: он английский.
|
||||
func translateLines(r *http.Request, lines []pzserver.LogLine) []pzserver.LogLine {
|
||||
lang := i18n.FromRequest(r)
|
||||
if lang == i18n.Default {
|
||||
return lines
|
||||
}
|
||||
out := make([]pzserver.LogLine, len(lines))
|
||||
for i, line := range lines {
|
||||
line.Text = i18n.T(lang, line.Text)
|
||||
out[i] = line
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// handleLogStream — живая консоль через Server-Sent Events. SSE выбран вместо
|
||||
@@ -80,7 +103,7 @@ func (s *Server) handleLogs(w http.ResponseWriter, r *http.Request) {
|
||||
func (s *Server) handleLogStream(w http.ResponseWriter, r *http.Request) {
|
||||
flusher, ok := w.(http.Flusher)
|
||||
if !ok {
|
||||
writeError(w, http.StatusInternalServerError, "потоковая отдача не поддерживается")
|
||||
writeError(w, r, http.StatusInternalServerError, "потоковая отдача не поддерживается")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -94,9 +117,11 @@ func (s *Server) handleLogStream(w http.ResponseWriter, r *http.Request) {
|
||||
lines, unsubscribe := s.sup.Subscribe()
|
||||
defer unsubscribe()
|
||||
|
||||
lang := i18n.FromRequest(r)
|
||||
|
||||
// Сначала отдаём хвост истории, чтобы вкладка не открывалась пустой.
|
||||
since, _ := strconv.ParseInt(r.URL.Query().Get("since"), 10, 64)
|
||||
for _, line := range s.sup.Lines(since) {
|
||||
for _, line := range translateLines(r, s.sup.Lines(since)) {
|
||||
if !writeSSE(w, line) {
|
||||
return
|
||||
}
|
||||
@@ -115,6 +140,7 @@ func (s *Server) handleLogStream(w http.ResponseWriter, r *http.Request) {
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
line.Text = i18n.T(lang, line.Text)
|
||||
if !writeSSE(w, line) {
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user