# Module Translation Guide
> **π New to translations?** This guide shows you how to add multi-language support to your module!
## Why Use Module Translations?
When you use SimpleAdmin API's translation system, **each player automatically sees messages in their preferred language**!
**Example:**
- π¬π§ **Player with English:** "Admin gave PlayerName a weapon!"
- π΅π± **Player with Polish:** "Admin daΕ PlayerName broΕ!"
- π·πΊ **Player with Russian:** "Admin Π΄Π°Π» PlayerName ΠΎΡΡΠΆΠΈΠ΅!"
**All from ONE line of code!**
## Quick Start
### Step 1: Create Your Translation Files
Create a `lang` folder in your module with translation files for each language:
```
YourModule/
βββ lang/
βββ en.json
βββ pl.json
βββ ru.json
```
**Example: `lang/en.json`**
```json
{
"yourmod_admin_action": "{lightred}{0}{default} performed action on {lightred}{1}{default}!"
}
```
**Example: `lang/pl.json`**
```json
{
"yourmod_admin_action": "{lightred}{0}{default} wykonaΕ akcjΔ na {lightred}{1}{default}!"
}
```
### Step 2: Use in Your Code
**β RECOMMENDED METHOD:** `ShowAdminActivityLocalized`
```csharp
// Show activity with per-player language support
var args = new object[] { "CALLER", targetPlayer.PlayerName };
if (admin == null || !_api.IsAdminSilent(admin))
{
if (Localizer != null)
{
// Each player sees this in their language!
_api.ShowAdminActivityLocalized(
Localizer, // Your module's localizer
"yourmod_admin_action", // Translation key
admin.PlayerName, // Caller name
false, // dontPublish
args); // Message arguments
}
}
```
That's it! SimpleAdmin handles the rest.
## Complete Example
```csharp
using CounterStrikeSharp.API.Core;
using CS2_SimpleAdminApi;
public partial class MyModule : BasePlugin
{
private ICS2_SimpleAdminApi? _api;
private void GiveWeaponToPlayer(CCSPlayerController admin, CCSPlayerController target, string weaponName)
{
// Give the weapon
target.GiveNamedItem(weaponName);
var callerName = admin.PlayerName;
// Show activity using module's localizer - each player sees it in their language!
if (admin == null || !_api!.IsAdminSilent(admin))
{
var args = new object[] { "CALLER", target.PlayerName, weaponName };
if (Localizer != null)
{
_api!.ShowAdminActivityLocalized(Localizer, "yourmod_admin_give_message", callerName, false, args);
}
}
// Log the command
_api!.LogCommand(admin, $"css_give {target.PlayerName} {weaponName}");
}
}
```
## π Important: The "CALLER" Placeholder
**Always use `"CALLER"` as the first argument** in your translation messages!
The API automatically replaces `"CALLER"` based on the server's `ShowActivityType` configuration:
| ShowActivityType | What Players See |
|-----------------|-----------------|
| `1` | Non-admins see "Admin", admins see real name |
| `2+` | Everyone sees real admin name |
**Example:**
```json
{
"yourmod_message": "{0} did something to {1}"
β This will be replaced with "Admin" or admin's name
}
```
```csharp
var args = new object[] { "CALLER", targetPlayer.PlayerName };
// β API replaces this automatically
```
## π‘ Pro Tips
### Tip 1: Use a Helper Method
Create a reusable helper to reduce code duplication:
```csharp
///
/// Helper method to show activity and log command
/// Copy this to your module!
///
private void LogAndShowActivity(
CCSPlayerController? caller,
CCSPlayerController target,
string translationKey,
string baseCommand,
params string[] extraArgs)
{
var callerName = caller?.PlayerName ?? "Console";
// Build args: "CALLER" + target name + any extra args
var args = new List