Русский и английский языки интерфейса
Язык выбирается в шапке панели, а до первого выбора берётся из настроек браузера. Переведены интерфейс, подписи и описания всех параметров конфигов, ошибки API и служебные сообщения менеджера в консоли. Подписи параметров вынесены из app.js в hints-<язык>.json: их больше четырёхсот на язык, и грузить чужой язык незачем. Сообщения менеджера переводятся на выходе из API по словарю, где ключом служит русская фраза из кода, — вывод самого игрового сервера через него проходит без изменений. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+11
-9
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/mrleo1nid/pzmanager/internal/auth"
|
||||
"github.com/mrleo1nid/pzmanager/internal/backup"
|
||||
"github.com/mrleo1nid/pzmanager/internal/config"
|
||||
"github.com/mrleo1nid/pzmanager/internal/i18n"
|
||||
"github.com/mrleo1nid/pzmanager/internal/job"
|
||||
"github.com/mrleo1nid/pzmanager/internal/pzconfig"
|
||||
"github.com/mrleo1nid/pzmanager/internal/pzserver"
|
||||
@@ -175,7 +176,7 @@ func (s *Server) withCommonHeaders(next http.Handler) http.Handler {
|
||||
|
||||
if r.Method != http.MethodGet && r.Method != http.MethodHead &&
|
||||
strings.HasPrefix(r.URL.Path, "/api/") && r.Header.Get(csrfHeader) == "" {
|
||||
writeError(w, http.StatusForbidden, "запрос без заголовка "+csrfHeader)
|
||||
writeError(w, r, http.StatusForbidden, "запрос без заголовка "+csrfHeader)
|
||||
return
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
@@ -186,7 +187,7 @@ func (s *Server) withCommonHeaders(next http.Handler) http.Handler {
|
||||
func (s *Server) requireAuth(next http.HandlerFunc) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if _, ok := s.users.SessionFromRequest(r); !ok {
|
||||
writeError(w, http.StatusUnauthorized, "требуется вход")
|
||||
writeError(w, r, http.StatusUnauthorized, "требуется вход")
|
||||
return
|
||||
}
|
||||
next(w, r)
|
||||
@@ -228,20 +229,21 @@ func writeJSON(w http.ResponseWriter, status int, v any) {
|
||||
}
|
||||
|
||||
// writeError отправляет ошибку в том же формате, что и остальные ответы.
|
||||
func writeError(w http.ResponseWriter, status int, message string) {
|
||||
writeJSON(w, status, map[string]string{"error": message})
|
||||
// Текст переводится на язык панели: в коде сообщения написаны по-русски.
|
||||
func writeError(w http.ResponseWriter, r *http.Request, status int, message string) {
|
||||
writeJSON(w, status, map[string]string{"error": i18n.T(i18n.FromRequest(r), message)})
|
||||
}
|
||||
|
||||
// writeOpError переводит ошибку операции в подходящий HTTP-код.
|
||||
func writeOpError(w http.ResponseWriter, err error) {
|
||||
func writeOpError(w http.ResponseWriter, r *http.Request, err error) {
|
||||
switch {
|
||||
case errors.Is(err, pzserver.ErrAlreadyRunning), errors.Is(err, pzserver.ErrNotRunning),
|
||||
errors.Is(err, job.ErrBusy):
|
||||
writeError(w, http.StatusConflict, err.Error())
|
||||
writeError(w, r, http.StatusConflict, err.Error())
|
||||
case errors.Is(err, pzserver.ErrNotInstalled):
|
||||
writeError(w, http.StatusPreconditionFailed, err.Error())
|
||||
writeError(w, r, http.StatusPreconditionFailed, err.Error())
|
||||
default:
|
||||
writeError(w, http.StatusInternalServerError, err.Error())
|
||||
writeError(w, r, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,7 +253,7 @@ func decodeJSON(w http.ResponseWriter, r *http.Request, dst any) bool {
|
||||
dec := json.NewDecoder(r.Body)
|
||||
dec.DisallowUnknownFields()
|
||||
if err := dec.Decode(dst); err != nil {
|
||||
writeError(w, http.StatusBadRequest, "некорректный JSON: "+err.Error())
|
||||
writeError(w, r, http.StatusBadRequest, "некорректный JSON: "+err.Error())
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
||||
Reference in New Issue
Block a user