Add per-player menu localization and refactor menus

Introduces per-player localization for menu categories and items using translation keys and IStringLocalizer, allowing modules and the main plugin to display menu names in the player's language. Refactors menu registration and builder logic to use translation keys, updates API and documentation, and adds database provider upsert query abstraction for player IPs. Also updates version to 1.7.8-beta-4 and corrects a translation string typo.
This commit is contained in:
Dawid Bepierszcz
2025-10-30 01:41:08 +01:00
parent b0d8696756
commit a03964c08a
20 changed files with 759 additions and 138 deletions

View File

@@ -366,66 +366,73 @@ public partial class CS2_SimpleAdmin_FunCommands : BasePlugin, IPluginConfig<Con
try
{
_sharedApi.RegisterMenuCategory("fun", Localizer?["fun_category_name"] ?? "Fun Commands", "@css/generic");
// 🆕 NEW: Per-player localization support for modules!
// - This module has its own lang/ folder with translations
// - We pass translation KEYS and the module's Localizer to the API
// - SimpleAdmin will translate menu names per-player based on their css_lang
// - Each player sees menus in their own language!
_sharedApi.RegisterMenuCategory("fun", "fun_category_name", "@css/generic", Localizer!);
// Register menus with command names for permission override support
// Server admins can override default permissions via CounterStrikeSharp admin system
// Example: If "css_god" is overdden to "@css/vip", only VIPs will see the God Mode menu
// Example: If "css_god" is overridden to "@css/vip", only VIPs will see the God Mode menu
//
// 🆕 NEW: All menus use translation keys and module's Localizer for per-player localization!
if (Config.GodCommands.Count > 0)
_sharedApi.RegisterMenu("fun", "god",
Localizer?["fun_menu_god"] ?? "God Mode",
CreateGodModeMenu, "@css/cheats", "css_god");
"fun_menu_god",
CreateGodModeMenu, "@css/cheats", "css_god", Localizer!);
if (Config.NoclipCommands.Count > 0)
_sharedApi.RegisterMenu("fun", "noclip",
Localizer?["fun_menu_noclip"] ?? "No Clip",
CreateNoClipMenu, "@css/cheats", "css_noclip");
"fun_menu_noclip",
CreateNoClipMenu, "@css/cheats", "css_noclip", Localizer!);
if (Config.RespawnCommands.Count > 0)
_sharedApi.RegisterMenu("fun", "respawn",
Localizer?["fun_menu_respawn"] ?? "Respawn",
CreateRespawnMenu, "@css/cheats", "css_respawn");
"fun_menu_respawn",
CreateRespawnMenu, "@css/cheats", "css_respawn", Localizer!);
if (Config.GiveCommands.Count > 0)
_sharedApi.RegisterMenu("fun", "give",
Localizer?["fun_menu_give"] ?? "Give Weapon",
CreateGiveWeaponMenu, "@css/cheats", "css_give");
"fun_menu_give",
CreateGiveWeaponMenu, "@css/cheats", "css_give", Localizer!);
if (Config.StripCommands.Count > 0)
_sharedApi.RegisterMenu("fun", "strip",
Localizer?["fun_menu_strip"] ?? "Strip Weapons",
CreateStripWeaponsMenu, "@css/slay", "css_strip");
"fun_menu_strip",
CreateStripWeaponsMenu, "@css/slay", "css_strip", Localizer!);
if (Config.FreezeCommands.Count > 0)
_sharedApi.RegisterMenu("fun", "freeze",
Localizer?["fun_menu_freeze"] ?? "Freeze",
CreateFreezeMenu, "@css/slay", "css_freeze");
"fun_menu_freeze",
CreateFreezeMenu, "@css/slay", "css_freeze", Localizer!);
if (Config.HpCommands.Count > 0)
_sharedApi.RegisterMenu("fun", "hp",
Localizer?["fun_menu_hp"] ?? "Set HP",
CreateSetHpMenu, "@css/slay", "css_hp");
"fun_menu_hp",
CreateSetHpMenu, "@css/slay", "css_hp", Localizer!);
if (Config.SpeedCommands.Count > 0)
_sharedApi.RegisterMenu("fun", "speed",
Localizer?["fun_menu_speed"] ?? "Set Speed",
CreateSetSpeedMenu, "@css/slay", "css_speed");
"fun_menu_speed",
CreateSetSpeedMenu, "@css/slay", "css_speed", Localizer!);
if (Config.GravityCommands.Count > 0)
_sharedApi.RegisterMenu("fun", "gravity",
Localizer?["fun_menu_gravity"] ?? "Set Gravity",
CreateSetGravityMenu, "@css/slay", "css_gravity");
"fun_menu_gravity",
CreateSetGravityMenu, "@css/slay", "css_gravity", Localizer!);
if (Config.MoneyCommands.Count > 0)
_sharedApi.RegisterMenu("fun", "money",
Localizer?["fun_menu_money"] ?? "Set Money",
CreateSetMoneyMenu, "@css/slay", "css_money");
"fun_menu_money",
CreateSetMoneyMenu, "@css/slay", "css_money", Localizer!);
if (Config.ResizeCommands.Count > 0)
_sharedApi.RegisterMenu("fun", "resize",
Localizer?["fun_menu_resize"] ?? "Resize Player",
CreateSetResizeMenu, "@css/slay", "css_resize");
"fun_menu_resize",
CreateSetResizeMenu, "@css/slay", "css_resize", Localizer!);
_menusRegistered = true;
Logger.LogInformation("Fun menus registered successfully!");

View File

@@ -1,6 +1,7 @@
using System.Globalization;
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Translations;
namespace CS2_SimpleAdmin_FunCommands;
@@ -139,8 +140,15 @@ public partial class CS2_SimpleAdmin_FunCommands
/// </summary>
private object CreateWeaponSelectionMenu(CCSPlayerController admin, CCSPlayerController target)
{
// Translate title per-player based on admin's css_lang
string translatedTitle;
using (new WithTemporaryCulture(admin.GetLanguage()))
{
translatedTitle = Localizer?["fun_menu_give_player", target.PlayerName] ?? $"Give Weapon: {target.PlayerName}";
}
var weaponMenu = _sharedApi!.CreateMenuWithBack(
Localizer?["fun_menu_give_player", target.PlayerName] ?? $"Give Weapon: {target.PlayerName}",
translatedTitle,
"fun",
admin);
@@ -212,8 +220,15 @@ public partial class CS2_SimpleAdmin_FunCommands
/// </summary>
private object CreateHpSelectionMenu(CCSPlayerController admin, CCSPlayerController target)
{
// Translate title per-player based on admin's css_lang
string translatedTitle;
using (new WithTemporaryCulture(admin.GetLanguage()))
{
translatedTitle = Localizer?["fun_menu_hp_player", target.PlayerName] ?? $"Set HP: {target.PlayerName}";
}
var hpSelectionMenu = _sharedApi!.CreateMenuWithBack(
Localizer?["fun_menu_hp_player", target.PlayerName] ?? $"Set HP: {target.PlayerName}",
translatedTitle,
"fun",
admin);
@@ -222,8 +237,15 @@ public partial class CS2_SimpleAdmin_FunCommands
foreach (var hp in hpValues)
{
// Translate option label per-player
string optionLabel;
using (new WithTemporaryCulture(admin.GetLanguage()))
{
optionLabel = Localizer?["fun_menu_hp_value", hp] ?? $"{hp} HP";
}
_sharedApi.AddMenuOption(hpSelectionMenu,
Localizer?["fun_menu_hp_value", hp] ?? $"{hp} HP",
optionLabel,
_ =>
{
if (target.IsValid)
@@ -261,8 +283,15 @@ public partial class CS2_SimpleAdmin_FunCommands
/// </summary>
private object CreateSpeedSelectionMenu(CCSPlayerController admin, CCSPlayerController target)
{
// Translate title per-player based on admin's css_lang
string translatedTitle;
using (new WithTemporaryCulture(admin.GetLanguage()))
{
translatedTitle = Localizer?["fun_menu_speed_player", target.PlayerName] ?? $"Set Speed: {target.PlayerName}";
}
var speedSelectionMenu = _sharedApi!.CreateMenuWithBack(
Localizer?["fun_menu_speed_player", target.PlayerName] ?? $"Set Speed: {target.PlayerName}",
translatedTitle,
"fun",
admin);
@@ -275,8 +304,15 @@ public partial class CS2_SimpleAdmin_FunCommands
foreach (var (speed, display) in speedValues)
{
// Translate option label per-player
string optionLabel;
using (new WithTemporaryCulture(admin.GetLanguage()))
{
optionLabel = Localizer?["fun_menu_speed_value", display] ?? $"Speed {display}";
}
_sharedApi.AddMenuOption(speedSelectionMenu,
Localizer?["fun_menu_speed_value", display] ?? $"Speed {display}",
optionLabel,
_ =>
{
if (target.IsValid)
@@ -316,8 +352,15 @@ public partial class CS2_SimpleAdmin_FunCommands
private object CreateGravitySelectionMenu(CCSPlayerController admin, CCSPlayerController target)
{
// Translate title per-player based on admin's css_lang
string translatedTitle;
using (new WithTemporaryCulture(admin.GetLanguage()))
{
translatedTitle = Localizer?["fun_menu_gravity_player", target.PlayerName] ?? $"Set Gravity: {target.PlayerName}";
}
var gravitySelectionMenu = _sharedApi!.CreateMenuWithBack(
Localizer?["fun_menu_gravity_player", target.PlayerName] ?? $"Set Gravity: {target.PlayerName}",
translatedTitle,
"fun",
admin);
var gravityValues = new[]
@@ -365,8 +408,15 @@ public partial class CS2_SimpleAdmin_FunCommands
private object CreateMoneySelectionMenu(CCSPlayerController admin, CCSPlayerController target)
{
// Translate title per-player based on admin's css_lang
string translatedTitle;
using (new WithTemporaryCulture(admin.GetLanguage()))
{
translatedTitle = Localizer?["fun_menu_money_player", target.PlayerName] ?? $"Set Money: {target.PlayerName}";
}
var moneySelectionMenu = _sharedApi!.CreateMenuWithBack(
Localizer?["fun_menu_money_player", target.PlayerName] ?? $"Set Money: {target.PlayerName}",
translatedTitle,
"fun",
admin);
var moneyValues = new[] { 0, 1000, 2500, 5000, 10000, 16000 };
@@ -407,8 +457,15 @@ public partial class CS2_SimpleAdmin_FunCommands
private object CreateResizeSelectionMenu(CCSPlayerController admin, CCSPlayerController target)
{
// Translate title per-player based on admin's css_lang
string translatedTitle;
using (new WithTemporaryCulture(admin.GetLanguage()))
{
translatedTitle = Localizer?["fun_menu_resize_player", target.PlayerName] ?? $"Resize: {target.PlayerName}";
}
var resizeSelectionMenu = _sharedApi!.CreateMenuWithBack(
Localizer?["fun_menu_resize_player", target.PlayerName] ?? $"Resize: {target.PlayerName}",
translatedTitle,
"fun",
admin);
var resizeValues = new[]