From 421915f7747b8729c81335c4f95ec1c22cf46ae2 Mon Sep 17 00:00:00 2001 From: TravianZ Patcher Date: Thu, 4 Jun 2026 09:07:57 +0200 Subject: [PATCH] Add per-user language selection (issue #166) The profile already had a language selector (Templates/Profile/preference.tpl) that saved the choice into users.lang and $_SESSION['lang'], but the saved preference was never used to actually load the language: every page loads include("Lang/".LANG.".php") with the server-wide LANG constant, so changing the language in the profile had no visible effect. This wires it up: - Introduce SERVER_LANG (the server default) and make LANG the EFFECTIVE display language, resolved from the player's saved preference ($_SESSION['lang']) with a fallback to SERVER_LANG (install/data/constant_format.tpl). SECURITY: the value is sanitized to [a-z_] and the target Lang/.php file must exist, otherwise we fall back to the server default. This prevents Local File Inclusion via include("Lang/".LANG.".php"). - Seed $_SESSION['lang'] from users.lang on login (GameEngine/Session.php, PopulateVar), so the chosen language applies right after logging in. - Keep the SERVER default intact when an admin saves settings: the admin config regenerators and the "Server Settings"/config displays now use SERVER_LANG (the server default) instead of the per-user LANG, so an admin browsing in their own language can't accidentally overwrite the server default (6 Admin/Mods/edit*.php + editServerSet.tpl + config.tpl). Note: existing installs must also add SERVER_LANG + the LANG resolution to their generated GameEngine/config.php (and the Admin/Mods/constant_format.tpl copy) since config is generated at install time. Co-Authored-By: Claude Opus 4.8 --- Admin/Templates/config.tpl | 2 +- Admin/Templates/editServerSet.tpl | 12 ++++++------ GameEngine/Admin/Mods/editAdminInfo.php | 2 +- GameEngine/Admin/Mods/editExtraSet.php | 2 +- GameEngine/Admin/Mods/editLogSet.php | 2 +- GameEngine/Admin/Mods/editNewFunctions.php | 2 +- GameEngine/Admin/Mods/editNewsboxSet.php | 2 +- GameEngine/Admin/Mods/editPlusSet.php | 2 +- GameEngine/Session.php | 9 +++++++++ install/data/constant_format.tpl | 18 ++++++++++++++++-- 10 files changed, 38 insertions(+), 15 deletions(-) diff --git a/Admin/Templates/config.tpl b/Admin/Templates/config.tpl index 2be017d3..afd05a62 100644 --- a/Admin/Templates/config.tpl +++ b/Admin/Templates/config.tpl @@ -59,7 +59,7 @@ $editIcon = ' ? ? ? - ? + ? ? ?x ? diff --git a/Admin/Templates/editServerSet.tpl b/Admin/Templates/editServerSet.tpl index 19ce86c9..787faf89 100644 --- a/Admin/Templates/editServerSet.tpl +++ b/Admin/Templates/editServerSet.tpl @@ -70,12 +70,12 @@ function refresh(tz) { ? diff --git a/GameEngine/Admin/Mods/editAdminInfo.php b/GameEngine/Admin/Mods/editAdminInfo.php index 7653ec4b..534eebf6 100755 --- a/GameEngine/Admin/Mods/editAdminInfo.php +++ b/GameEngine/Admin/Mods/editAdminInfo.php @@ -73,7 +73,7 @@ $fh = fopen($myFile, 'w') or die("


Can't open file: GameEngine\con $text = preg_replace("'%STARTTIME%'", COMMENCE, $text); $text = preg_replace("'%SSTARTDATE%'", START_DATE, $text); $text = preg_replace("'%SSTARTTIME%'", START_TIME, $text); - $text = preg_replace("'%LANG%'", LANG, $text); + $text = preg_replace("'%LANG%'", (defined('SERVER_LANG') ? SERVER_LANG : LANG), $text); $text = preg_replace("'%SPEED%'", SPEED, $text); $text = preg_replace("'%MAX%'", WORLD_MAX, $text); $text = preg_replace("'%GP%'", $GP_ENABLE, $text); diff --git a/GameEngine/Admin/Mods/editExtraSet.php b/GameEngine/Admin/Mods/editExtraSet.php index d14c4963..aca89d7a 100755 --- a/GameEngine/Admin/Mods/editExtraSet.php +++ b/GameEngine/Admin/Mods/editExtraSet.php @@ -72,7 +72,7 @@ $fh = fopen($myFile, 'w') or die("


Can't open file: GameEngine\con $text = preg_replace("'%STARTTIME%'", COMMENCE, $text); $text = preg_replace("'%SSTARTDATE%'", START_DATE, $text); $text = preg_replace("'%SSTARTTIME%'", START_TIME, $text); - $text = preg_replace("'%LANG%'", LANG, $text); + $text = preg_replace("'%LANG%'", (defined('SERVER_LANG') ? SERVER_LANG : LANG), $text); $text = preg_replace("'%SPEED%'", SPEED, $text); $text = preg_replace("'%MAX%'", WORLD_MAX, $text); $text = preg_replace("'%GP%'", GP_ENABLE, $text); diff --git a/GameEngine/Admin/Mods/editLogSet.php b/GameEngine/Admin/Mods/editLogSet.php index 1b8c0b3c..ba66d739 100755 --- a/GameEngine/Admin/Mods/editLogSet.php +++ b/GameEngine/Admin/Mods/editLogSet.php @@ -68,7 +68,7 @@ $fh = fopen($myFile, 'w') or die("


Can't open file: GameEngine\con $text = preg_replace("'%STARTTIME%'", COMMENCE, $text); $text = preg_replace("'%SSTARTDATE%'", START_DATE, $text); $text = preg_replace("'%SSTARTTIME%'", START_TIME, $text); - $text = preg_replace("'%LANG%'", LANG, $text); + $text = preg_replace("'%LANG%'", (defined('SERVER_LANG') ? SERVER_LANG : LANG), $text); $text = preg_replace("'%SPEED%'", SPEED, $text); $text = preg_replace("'%MAX%'", WORLD_MAX, $text); $text = preg_replace("'%GP%'", $GP_ENABLE, $text); diff --git a/GameEngine/Admin/Mods/editNewFunctions.php b/GameEngine/Admin/Mods/editNewFunctions.php index 0d8e56dc..9a331a60 100644 --- a/GameEngine/Admin/Mods/editNewFunctions.php +++ b/GameEngine/Admin/Mods/editNewFunctions.php @@ -41,7 +41,7 @@ $fh = fopen($myFile, 'w') or die("


Can't open file: GameEngine\con $text = preg_replace("'%STARTTIME%'", COMMENCE, $text); $text = preg_replace("'%SSTARTDATE%'", START_DATE, $text); $text = preg_replace("'%SSTARTTIME%'", START_TIME, $text); - $text = preg_replace("'%LANG%'", LANG, $text); + $text = preg_replace("'%LANG%'", (defined('SERVER_LANG') ? SERVER_LANG : LANG), $text); $text = preg_replace("'%SPEED%'", SPEED, $text); $text = preg_replace("'%MAX%'", WORLD_MAX, $text); $text = preg_replace("'%GP%'", GP_ENABLE, $text); diff --git a/GameEngine/Admin/Mods/editNewsboxSet.php b/GameEngine/Admin/Mods/editNewsboxSet.php index 14c9988a..ab89c499 100755 --- a/GameEngine/Admin/Mods/editNewsboxSet.php +++ b/GameEngine/Admin/Mods/editNewsboxSet.php @@ -74,7 +74,7 @@ $fh = fopen($myFile, 'w') or die("


Can't open file: GameEngine\con $text = preg_replace("'%STARTTIME%'", COMMENCE, $text); $text = preg_replace("'%SSTARTDATE%'", START_DATE, $text); $text = preg_replace("'%SSTARTTIME%'", START_TIME, $text); - $text = preg_replace("'%LANG%'", LANG, $text); + $text = preg_replace("'%LANG%'", (defined('SERVER_LANG') ? SERVER_LANG : LANG), $text); $text = preg_replace("'%SPEED%'", SPEED, $text); $text = preg_replace("'%MAX%'", WORLD_MAX, $text); $text = preg_replace("'%GP%'", $GP_ENABLE, $text); diff --git a/GameEngine/Admin/Mods/editPlusSet.php b/GameEngine/Admin/Mods/editPlusSet.php index a48b4b0b..48568067 100644 --- a/GameEngine/Admin/Mods/editPlusSet.php +++ b/GameEngine/Admin/Mods/editPlusSet.php @@ -56,7 +56,7 @@ $fh = fopen($myFile, 'w') or die("


Can't open file: GameEngine\con $text = preg_replace("'%STARTTIME%'", COMMENCE, $text); $text = preg_replace("'%SSTARTDATE%'", START_DATE, $text); $text = preg_replace("'%SSTARTTIME%'", START_TIME, $text); - $text = preg_replace("'%LANG%'", LANG, $text); + $text = preg_replace("'%LANG%'", (defined('SERVER_LANG') ? SERVER_LANG : LANG), $text); $text = preg_replace("'%SPEED%'", SPEED, $text); $text = preg_replace("'%MAX%'", WORLD_MAX, $text); $text = preg_replace("'%GP%'", GP_ENABLE, $text); diff --git a/GameEngine/Session.php b/GameEngine/Session.php index 50524b77..8b524c46 100755 --- a/GameEngine/Session.php +++ b/GameEngine/Session.php @@ -369,6 +369,15 @@ function __construct() { } $this->userarray = $this->userinfo = $_SESSION[$cacheKeyUser]['data']; + // Per-user language (issue #166): seed the session language from the + // player's saved preference (users.lang) the first time, e.g. right + // after login. Once set, the profile "save preferences" page keeps it + // up to date, so we don't overwrite it here (also avoids reverting to + // a stale value from the 30s user cache above). + if (empty($_SESSION['lang']) && !empty($this->userarray['lang'])) { + $_SESSION['lang'] = $this->userarray['lang']; + } + $this->username = $this->userarray['username']; $this->uid = $_SESSION['id_user'] = $this->userarray['id']; diff --git a/install/data/constant_format.tpl b/install/data/constant_format.tpl index 5221def8..369cbf86 100644 --- a/install/data/constant_format.tpl +++ b/install/data/constant_format.tpl @@ -43,8 +43,22 @@ define("START_DATE", "%SSTARTDATE%"); define("START_TIME", "%SSTARTTIME%"); // ***** Language -// Choose your server language. -define("LANG","%LANG%"); +// SERVER_LANG is the DEFAULT language of the server (chosen at install / in +// the admin "Server Settings"). LANG is the EFFECTIVE display language. +// +// Per-user language (issue #166): if the logged-in player picked a language +// in their profile preferences (stored in users.lang and mirrored into +// $_SESSION['lang']), LANG becomes that language; otherwise LANG falls back +// to SERVER_LANG. +// +// SECURITY: LANG is used in include("Lang/".LANG.".php"), so the value is +// strictly sanitized to [a-z_] (no path traversal) and the target file MUST +// exist, otherwise we fall back to the server default. This prevents Local +// File Inclusion via a crafted session value. +define("SERVER_LANG", "%LANG%"); +if (session_status() !== PHP_SESSION_ACTIVE) { @session_start(); } +$__user_lang = isset($_SESSION['lang']) ? preg_replace('/[^a-z_]/', '', strtolower((string) $_SESSION['lang'])) : ''; +define("LANG", ($__user_lang !== '' && is_file(__DIR__ . "/Lang/" . $__user_lang . ".php")) ? $__user_lang : SERVER_LANG); // ***** Speed // Choose your server speed. NOTICE: Higher speed, more likely