diff --git a/datapack_development/data/html/mods/Lang/Error.htm b/datapack_development/data/html/mods/Lang/Error.htm
new file mode 100644
index 0000000000000000000000000000000000000000..c5bfc1b813fe5e35dcb800807cb88b0583639ade
--- /dev/null
+++ b/datapack_development/data/html/mods/Lang/Error.htm
@@ -0,0 +1,6 @@
+<html><title>Language selection</title>
+<body>
+<br>
+<center><font color="LEVEL">Unable to select new language, using default.</font></center>
+</body>
+</html>
\ No newline at end of file
diff --git a/datapack_development/data/html/mods/Lang/LanguageSelect.htm b/datapack_development/data/html/mods/Lang/LanguageSelect.htm
new file mode 100644
index 0000000000000000000000000000000000000000..4fed38ca2c91ee4da5f901d35b7d742f42712fc7
--- /dev/null
+++ b/datapack_development/data/html/mods/Lang/LanguageSelect.htm
@@ -0,0 +1,8 @@
+<html><title>Language selection</title>
+<body>
+<br>
+<center><font color="LEVEL">Please choose your language:</font><br>
+%list%
+</center>
+</body>
+</html>
\ No newline at end of file
diff --git a/datapack_development/data/html/mods/Lang/Ok.htm b/datapack_development/data/html/mods/Lang/Ok.htm
new file mode 100644
index 0000000000000000000000000000000000000000..c4c40e4c275bf987b388ce6ca7d59a2adb5155b3
--- /dev/null
+++ b/datapack_development/data/html/mods/Lang/Ok.htm
@@ -0,0 +1,6 @@
+<html><title>Language selection</title>
+<body>
+<br>
+<center><font color="LEVEL">Language successfully selected.</font></center>
+</body>
+</html>
\ No newline at end of file
diff --git a/datapack_development/data/lang/ru/data/html/mods/Lang/Error.htm b/datapack_development/data/lang/ru/data/html/mods/Lang/Error.htm
new file mode 100644
index 0000000000000000000000000000000000000000..652aa115c81454bcd79c0dc16a1dee72ac7c3f62
--- /dev/null
+++ b/datapack_development/data/lang/ru/data/html/mods/Lang/Error.htm
@@ -0,0 +1,6 @@
+<html><title>Выбор языка</title>
+<body>
+<br>
+<center><font color="LEVEL">Ошибка, используется язык по умолчанию.</font></center>
+</body>
+</html>
\ No newline at end of file
diff --git a/datapack_development/data/lang/ru/data/html/mods/Lang/LanguageSelect.htm b/datapack_development/data/lang/ru/data/html/mods/Lang/LanguageSelect.htm
new file mode 100644
index 0000000000000000000000000000000000000000..8a9646aaf00856f8227834c1322f76b82aa1a498
--- /dev/null
+++ b/datapack_development/data/lang/ru/data/html/mods/Lang/LanguageSelect.htm
@@ -0,0 +1,8 @@
+<html><title>Выбор языка</title>
+<body>
+<br>
+<center><font color="LEVEL">Пожалуйста выберите язык:</font><br>
+%list%
+</center>
+</body>
+</html>
\ No newline at end of file
diff --git a/datapack_development/data/lang/ru/data/html/mods/Lang/Ok.htm b/datapack_development/data/lang/ru/data/html/mods/Lang/Ok.htm
new file mode 100644
index 0000000000000000000000000000000000000000..549aadf5467d4c205929a73e719af72f2f89beff
--- /dev/null
+++ b/datapack_development/data/lang/ru/data/html/mods/Lang/Ok.htm
@@ -0,0 +1,6 @@
+<html><title>Выбор языка</title>
+<body>
+<br>
+<center><font color="LEVEL">Язык успешно выбран.</font></center>
+</body>
+</html>
\ No newline at end of file
diff --git a/datapack_development/data/scripts/ai/individual/IceFairySirra.java b/datapack_development/data/scripts/ai/individual/IceFairySirra.java
index 9ce180e97e655858bda9e86bd942f4761edf690a..eca6ec9d67985cf816679c205242ba5ba9b9ad6a 100644
--- a/datapack_development/data/scripts/ai/individual/IceFairySirra.java
+++ b/datapack_development/data/scripts/ai/individual/IceFairySirra.java
@@ -302,7 +302,7 @@ public class IceFairySirra extends L2AttackableAIScript
 	public void sendHtml(L2Npc npc, L2PcInstance player, String filename)
 	{
 		NpcHtmlMessage html = new NpcHtmlMessage(npc.getObjectId());
-		html.setFile(filename);
+		html.setFile(player.getHtmlPrefix(), filename);
 		html.replace("%objectId%", String.valueOf(npc.getObjectId()));
 		player.sendPacket(html);
 		player.sendPacket( ActionFailed.STATIC_PACKET );
diff --git a/datapack_development/data/scripts/handlers/MasterHandler.java b/datapack_development/data/scripts/handlers/MasterHandler.java
index 122e776a5e397493e2dc002c57b853c1b757669d..da0fb8b6bc5fa3fc321e139dc0041125b996de7d 100644
--- a/datapack_development/data/scripts/handlers/MasterHandler.java
+++ b/datapack_development/data/scripts/handlers/MasterHandler.java
@@ -235,6 +235,8 @@ public class MasterHandler
 			VoicedCommandHandler.getInstance().registerVoicedCommandHandler(new TvTVoicedInfo());
 		if (Config.L2JMOD_CHAT_ADMIN)
 			VoicedCommandHandler.getInstance().registerVoicedCommandHandler(new ChatAdmin());
+		if (Config.L2JMOD_MULTILANG_ENABLE && Config.L2JMOD_MULTILANG_VOICED_ALLOW)
+			VoicedCommandHandler.getInstance().registerVoicedCommandHandler(new Lang());
 		_log.config("Loaded " + VoicedCommandHandler.getInstance().size() + " VoicedHandlers");
 	}
 	
diff --git a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminAnnouncements.java b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminAnnouncements.java
index a5a9ad691cf930527c4a3a57f0ab3d0f53fdaf8f..2f49208aabf398526007895e1750c6675ed13565 100644
--- a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminAnnouncements.java
+++ b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminAnnouncements.java
@@ -195,7 +195,7 @@ public class AdminAnnouncements implements IAdminCommandHandler
 	
 	private void listAutoAnnouncements(L2PcInstance activeChar)
 	{
-		String content = HtmCache.getInstance().getHtmForce("data/html/admin/autoannounce.htm");
+		String content = HtmCache.getInstance().getHtmForce(activeChar.getHtmlPrefix(), "data/html/admin/autoannounce.htm");
 		NpcHtmlMessage adminReply = new NpcHtmlMessage(5);
 		adminReply.setHtml(content);
 		
diff --git a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminCursedWeapons.java b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminCursedWeapons.java
index 8596f56423a24212f6f02148de8077c128212883..4306ebbb22e2a1825a42f614740c0fdbedd582c8 100644
--- a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminCursedWeapons.java
+++ b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminCursedWeapons.java
@@ -95,7 +95,7 @@ public class AdminCursedWeapons implements IAdminCommandHandler
                             final StringBuilder replyMSG =
                                     new StringBuilder(cws.size() * 300);
                             NpcHtmlMessage adminReply = new NpcHtmlMessage(5);
-                            adminReply.setFile("data/html/admin/cwinfo.htm");
+                            adminReply.setFile(activeChar.getHtmlPrefix(), "data/html/admin/cwinfo.htm");
                             for (CursedWeapon cw : cwm.getCursedWeapons()) {
                                 itemId = cw.getItemId();
 
diff --git a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminEditChar.java b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminEditChar.java
index b131de66388b215a06d0e2fa6e8c0211bd7566a1..09383e96b5ae1d633ffd389013e2541262f7a279 100644
--- a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminEditChar.java
+++ b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminEditChar.java
@@ -719,7 +719,7 @@ public class AdminEditChar implements IAdminCommandHandler
 			charactersEnd = charactersStart + maxCharactersPerPage;
 		
 		NpcHtmlMessage adminReply = new NpcHtmlMessage(5);
-		adminReply.setFile("data/html/admin/charlist.htm");
+		adminReply.setFile(activeChar.getHtmlPrefix(), "data/html/admin/charlist.htm");
 
                 final StringBuilder replyMSG = new StringBuilder(1000);
 
@@ -787,7 +787,7 @@ public class AdminEditChar implements IAdminCommandHandler
 		{
 		}
 		NpcHtmlMessage adminReply = new NpcHtmlMessage(5);
-		adminReply.setFile("data/html/admin/" + filename);
+		adminReply.setFile(activeChar.getHtmlPrefix(), "data/html/admin/" + filename);
 		adminReply.replace("%name%", player.getName());
 		adminReply.replace("%level%", String.valueOf(player.getLevel()));
 		adminReply.replace("%clan%", String.valueOf(ClanTable.getInstance().getClan(player.getClanId())));
@@ -952,7 +952,7 @@ public class AdminEditChar implements IAdminCommandHandler
 			players = allPlayers.toArray(new L2PcInstance[allPlayers.size()]);
 		}
 		NpcHtmlMessage adminReply = new NpcHtmlMessage(5);
-		adminReply.setFile("data/html/admin/charfind.htm");
+		adminReply.setFile(activeChar.getHtmlPrefix(), "data/html/admin/charfind.htm");
 
                 final StringBuilder replyMSG = new StringBuilder(1000);
 
@@ -1024,7 +1024,7 @@ public class AdminEditChar implements IAdminCommandHandler
 		String name, ip = "0.0.0.0";
                 final StringBuilder replyMSG = new StringBuilder(1000);
 		NpcHtmlMessage adminReply = new NpcHtmlMessage(5);
-		adminReply.setFile("data/html/admin/ipfind.htm");
+		adminReply.setFile(activeChar.getHtmlPrefix(), "data/html/admin/ipfind.htm");
 		for (L2PcInstance player: players)
 		{
 			client = player.getClient();
@@ -1104,7 +1104,7 @@ public class AdminEditChar implements IAdminCommandHandler
                         final StringBuilder replyMSG =
                                 new StringBuilder(chars.size() * 20);
 			NpcHtmlMessage adminReply = new NpcHtmlMessage(5);
-			adminReply.setFile("data/html/admin/accountinfo.htm");
+			adminReply.setFile(activeChar.getHtmlPrefix(), "data/html/admin/accountinfo.htm");
 			for (String charname : chars.values()) {
                             StringUtil.append(replyMSG,
                                     charname,
@@ -1175,7 +1175,7 @@ public class AdminEditChar implements IAdminCommandHandler
 		}
 		
 		NpcHtmlMessage adminReply = new NpcHtmlMessage(5);
-		adminReply.setFile("data/html/admin/dualbox.htm");
+		adminReply.setFile(activeChar.getHtmlPrefix(), "data/html/admin/dualbox.htm");
 		adminReply.replace("%multibox%", String.valueOf(multibox));
 		adminReply.replace("%results%", results.toString());
 		activeChar.sendPacket(adminReply);
@@ -1184,7 +1184,7 @@ public class AdminEditChar implements IAdminCommandHandler
 	private void gatherSummonInfo(L2Summon target, L2PcInstance activeChar)
 	{
 		NpcHtmlMessage html = new NpcHtmlMessage(0);
-		html.setFile("data/html/admin/petinfo.htm");
+		html.setFile(activeChar.getHtmlPrefix(), "data/html/admin/petinfo.htm");
 		String name = target.getName();
 		html.replace("%name%", name == null ? "N/A" : name);
 		html.replace("%level%", Integer.toString(target.getLevel()));
@@ -1220,7 +1220,7 @@ public class AdminEditChar implements IAdminCommandHandler
 	{
 		boolean color = true;
 		NpcHtmlMessage html = new NpcHtmlMessage(0);
-		html.setFile("data/html/admin/partyinfo.htm");
+		html.setFile(activeChar.getHtmlPrefix(), "data/html/admin/partyinfo.htm");
 		StringBuilder text = new StringBuilder(400);
 		for (L2PcInstance member : target.getParty().getPartyMembers())
 		{
diff --git a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminEditNpc.java b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminEditNpc.java
index 34014fb38f0942c9b67cd95cb253d563126e0a23..72412390dee3d055027fdf487ab19243d638af92 100644
--- a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminEditNpc.java
+++ b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminEditNpc.java
@@ -777,7 +777,7 @@ public class AdminEditNpc implements IAdminCommandHandler
 	private void showNpcProperty(L2PcInstance activeChar, L2NpcTemplate npc)
 	{
 		NpcHtmlMessage adminReply = new NpcHtmlMessage(5);
-		String content = HtmCache.getInstance().getHtm("data/html/admin/editnpc.htm");
+		String content = HtmCache.getInstance().getHtm(activeChar.getHtmlPrefix(), "data/html/admin/editnpc.htm");
 		
 		if (content != null)
 		{
diff --git a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminExpSp.java b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminExpSp.java
index f07d1a7a6dd08235f8dba6fc3283fca83eda6bef..4038ce1600e4821774602dad675d74d0fd513df9 100644
--- a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminExpSp.java
+++ b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminExpSp.java
@@ -93,7 +93,7 @@ public class AdminExpSp implements IAdminCommandHandler
 			return;
 		}
 		NpcHtmlMessage adminReply = new NpcHtmlMessage(5);
-		adminReply.setFile("data/html/admin/expsp.htm");
+		adminReply.setFile(activeChar.getHtmlPrefix(), "data/html/admin/expsp.htm");
 		adminReply.replace("%name%", player.getName());
 		adminReply.replace("%level%", String.valueOf(player.getLevel()));
 		adminReply.replace("%xp%", String.valueOf(player.getExp()));
diff --git a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminFortSiege.java b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminFortSiege.java
index e956b1c6a6a047a8f88d36cdf061eb8224c8ee6e..1245e2d5a6160f3261d3e7488609bbb4a7be91d1 100644
--- a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminFortSiege.java
+++ b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminFortSiege.java
@@ -131,7 +131,7 @@ public class AdminFortSiege implements IAdminCommandHandler
 	{
 		int i = 0;
 		NpcHtmlMessage adminReply = new NpcHtmlMessage(5);
-		adminReply.setFile("data/html/admin/forts.htm");
+		adminReply.setFile(activeChar.getHtmlPrefix(), "data/html/admin/forts.htm");
                 
                 final List<Fort> forts = FortManager.getInstance().getForts();
                 final StringBuilder cList = new StringBuilder(forts.size() * 100);
@@ -162,7 +162,7 @@ public class AdminFortSiege implements IAdminCommandHandler
 	private void showFortSiegePage(L2PcInstance activeChar, Fort fort)
 	{
 		NpcHtmlMessage adminReply = new NpcHtmlMessage(5);
-		adminReply.setFile("data/html/admin/fort.htm");
+		adminReply.setFile(activeChar.getHtmlPrefix(), "data/html/admin/fort.htm");
 		adminReply.replace("%fortName%", fort.getName());
 		adminReply.replace("%fortId%", String.valueOf(fort.getFortId()));
 		activeChar.sendPacket(adminReply);
diff --git a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminHelpPage.java b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminHelpPage.java
index 6201823cf39089c31eebf3f87b62b8b6bf37ba62..bb4f94526458426ca20ff94148f21ba3bc3a1012 100644
--- a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminHelpPage.java
+++ b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminHelpPage.java
@@ -61,7 +61,7 @@ public class AdminHelpPage implements IAdminCommandHandler
 	//PUBLIC & STATIC so other classes from package can include it directly
 	public static void showHelpPage(L2PcInstance targetChar, String filename)
 	{
-		String content = HtmCache.getInstance().getHtmForce("data/html/admin/" + filename);
+		String content = HtmCache.getInstance().getHtmForce(targetChar.getHtmlPrefix(), "data/html/admin/" + filename);
 		NpcHtmlMessage adminReply = new NpcHtmlMessage(5);
 		adminReply.setHtml(content);
 		targetChar.sendPacket(adminReply);
diff --git a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminLogin.java b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminLogin.java
index 3109031e61acf1f7f16f49876d46536e47b1f116..1f33497b6f3b9f68c1049c4ee1169f0b54958ec2 100644
--- a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminLogin.java
+++ b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminLogin.java
@@ -125,7 +125,7 @@ public class AdminLogin implements IAdminCommandHandler
 	private void showMainPage(L2PcInstance activeChar)
 	{
 		NpcHtmlMessage html = new NpcHtmlMessage(1);
-		html.setFile("data/html/admin/login.htm");
+		html.setFile(activeChar.getHtmlPrefix(), "data/html/admin/login.htm");
 		html.replace("%server_name%", LoginServerThread.getInstance().getServerName());
 		html.replace("%status%", LoginServerThread.getInstance().getStatusString());
 		html.replace("%clock%", String.valueOf(Config.SERVER_LIST_CLOCK));
diff --git a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminPForge.java b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminPForge.java
index 89df6647993bccca33112b43ef2c28be56465217..2c8ac906c404a4a88d861117f6759358441bde98 100644
--- a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminPForge.java
+++ b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminPForge.java
@@ -168,7 +168,7 @@ public class AdminPForge implements IAdminCommandHandler
 	private void showPage2(L2PcInstance activeChar, String format)
 	{
 		NpcHtmlMessage adminReply = new NpcHtmlMessage(5);
-		adminReply.setFile("data/html/admin/pforge2.htm");
+		adminReply.setFile(activeChar.getHtmlPrefix(), "data/html/admin/pforge2.htm");
 		adminReply.replace("%format%", format);
 
                 final StringBuilder replyMSG =
@@ -192,7 +192,7 @@ public class AdminPForge implements IAdminCommandHandler
 	private void showPage3(L2PcInstance activeChar, String format, String command)
 	{
 		NpcHtmlMessage adminReply = new NpcHtmlMessage(5);
-		adminReply.setFile("data/html/admin/pforge3.htm");
+		adminReply.setFile(activeChar.getHtmlPrefix(), "data/html/admin/pforge3.htm");
 		adminReply.replace("%format%", format);
 		adminReply.replace("%command%", command);
 		activeChar.sendPacket(adminReply);
diff --git a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminShutdown.java b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminShutdown.java
index 7bb64dd698412312b55ed6d0bfd2302d744947d1..d272bbeafb47e6eb96c21a6533a5adc9d8e6d31e 100644
--- a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminShutdown.java
+++ b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminShutdown.java
@@ -92,7 +92,7 @@ public class AdminShutdown implements IAdminCommandHandler
 		Calendar cal = Calendar.getInstance();
 		cal.set(Calendar.HOUR_OF_DAY, h);
 		cal.set(Calendar.MINUTE, m);
-		adminReply.setFile("data/html/admin/shutdown.htm");
+		adminReply.setFile(activeChar.getHtmlPrefix(), "data/html/admin/shutdown.htm");
 		adminReply.replace("%count%", String.valueOf(L2World.getInstance().getAllPlayersCount()));
 		adminReply.replace("%used%", String.valueOf(Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()));
 		adminReply.replace("%xp%", String.valueOf(Config.RATE_XP));
diff --git a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminSiege.java b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminSiege.java
index 0081311c3722048cc74a57e848c9e5e6503b6a08..9d8a7ffefc0aefc3d5aeb42a0365cb1aa9ee233b 100644
--- a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminSiege.java
+++ b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminSiege.java
@@ -243,7 +243,7 @@ public class AdminSiege implements IAdminCommandHandler
 	{
 		int i = 0;
 		NpcHtmlMessage adminReply = new NpcHtmlMessage(5);
-		adminReply.setFile("data/html/admin/castles.htm");
+		adminReply.setFile(activeChar.getHtmlPrefix(), "data/html/admin/castles.htm");
                 final StringBuilder cList = new StringBuilder(500);
 		for (Castle castle : CastleManager.getInstance().getCastles()) {
 			if (castle != null) {
@@ -304,7 +304,7 @@ public class AdminSiege implements IAdminCommandHandler
 	private void showSiegePage(L2PcInstance activeChar, String castleName)
 	{
 		NpcHtmlMessage adminReply = new NpcHtmlMessage(5);
-		adminReply.setFile("data/html/admin/castle.htm");
+		adminReply.setFile(activeChar.getHtmlPrefix(), "data/html/admin/castle.htm");
 		adminReply.replace("%castleName%", castleName);
 		activeChar.sendPacket(adminReply);
 	}
@@ -312,7 +312,7 @@ public class AdminSiege implements IAdminCommandHandler
 	private void showSiegeTimePage(L2PcInstance activeChar, Castle castle)
 	{
 		NpcHtmlMessage adminReply = new NpcHtmlMessage(5);
-		adminReply.setFile("data/html/admin/castlesiegetime.htm");
+		adminReply.setFile(activeChar.getHtmlPrefix(), "data/html/admin/castlesiegetime.htm");
 		adminReply.replace("%castleName%", castle.getName());
 		adminReply.replace("%time%", castle.getSiegeDate().getTime().toString());
 		Calendar newDay = Calendar.getInstance();
@@ -346,7 +346,7 @@ public class AdminSiege implements IAdminCommandHandler
 	private void showClanHallPage(L2PcInstance activeChar, ClanHall clanhall)
 	{
 		NpcHtmlMessage adminReply = new NpcHtmlMessage(5);
-		adminReply.setFile("data/html/admin/clanhall.htm");
+		adminReply.setFile(activeChar.getHtmlPrefix(), "data/html/admin/clanhall.htm");
 		adminReply.replace("%clanhallName%", clanhall.getName());
 		adminReply.replace("%clanhallId%", String.valueOf(clanhall.getId()));
 		L2Clan owner = ClanTable.getInstance().getClan(clanhall.getOwnerId());
diff --git a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminSkill.java b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminSkill.java
index 6d148da7d3f368ee7cefa2de0123822a9939281b..2288477684cfb09c1086e6573811a96899a5b79b 100644
--- a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminSkill.java
+++ b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminSkill.java
@@ -323,7 +323,7 @@ public class AdminSkill implements IAdminCommandHandler
 			return;
 		}
 		NpcHtmlMessage adminReply = new NpcHtmlMessage(5);
-		adminReply.setFile("data/html/admin/charskills.htm");
+		adminReply.setFile(activeChar.getHtmlPrefix(), "data/html/admin/charskills.htm");
 		adminReply.replace("%name%", player.getName());
 		adminReply.replace("%level%", String.valueOf(player.getLevel()));
 		adminReply.replace("%class%", player.getTemplate().className);
diff --git a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminZone.java b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminZone.java
index 9debeac8cd35ed7b153ca19f9ad56ac1f293d5dd..d1fd4a0800d984a589b4d7c7937434f876ab37b6 100644
--- a/datapack_development/data/scripts/handlers/admincommandhandlers/AdminZone.java
+++ b/datapack_development/data/scripts/handlers/admincommandhandlers/AdminZone.java
@@ -61,7 +61,7 @@ public class AdminZone implements IAdminCommandHandler
 		
 		if (actualCommand.equalsIgnoreCase("admin_zone_check"))
 		{
-			final String htmContent = HtmCache.getInstance().getHtm("data/html/admin/zone.htm");
+			final String htmContent = HtmCache.getInstance().getHtm(activeChar.getHtmlPrefix(), "data/html/admin/zone.htm");
 			NpcHtmlMessage adminReply = new NpcHtmlMessage(5);
 			adminReply.setHtml(htmContent);			
 			adminReply.replace("%PEACE%", (activeChar.isInsideZone(L2Character.ZONE_PEACE) ? "<font color=\"LEVEL\">YES</font>" : "NO"));
diff --git a/datapack_development/data/scripts/handlers/itemhandlers/Book.java b/datapack_development/data/scripts/handlers/itemhandlers/Book.java
index 67e130950bd251c3bdbde6a63eff27f5177516c8..56e424b4d5d23529f41ff4807c088315159be1db 100644
--- a/datapack_development/data/scripts/handlers/itemhandlers/Book.java
+++ b/datapack_development/data/scripts/handlers/itemhandlers/Book.java
@@ -36,7 +36,7 @@ public class Book implements IItemHandler
 		final int itemId = item.getItemId();
 		
 		String filename = "data/html/help/" + itemId + ".htm";
-		String content = HtmCache.getInstance().getHtm(filename);
+		String content = HtmCache.getInstance().getHtm(activeChar.getHtmlPrefix(), filename);
 		
 		if (content == null)
 		{
diff --git a/datapack_development/data/scripts/handlers/voicedcommandhandlers/Lang.java b/datapack_development/data/scripts/handlers/voicedcommandhandlers/Lang.java
new file mode 100644
index 0000000000000000000000000000000000000000..42f37b3504a83be894e18d245c3dcad1ca3f2e0d
--- /dev/null
+++ b/datapack_development/data/scripts/handlers/voicedcommandhandlers/Lang.java
@@ -0,0 +1,88 @@
+/*
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ * 
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ * 
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package handlers.voicedcommandhandlers;
+
+import java.util.StringTokenizer;
+
+import com.l2jserver.Config;
+import com.l2jserver.gameserver.handler.IVoicedCommandHandler;
+import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jserver.gameserver.network.serverpackets.NpcHtmlMessage;
+import com.l2jserver.gameserver.util.StringUtil;
+
+public class Lang implements IVoicedCommandHandler
+{
+	private static final String[] VOICED_COMMANDS =
+	{
+		"lang"
+	};
+
+	/**
+	 * 
+	 * @see com.l2jserver.gameserver.handler.IVoicedCommandHandler#useVoicedCommand(java.lang.String, com.l2jserver.gameserver.model.actor.instance.L2PcInstance, java.lang.String)
+	 */
+	public boolean useVoicedCommand(String command, L2PcInstance activeChar, String params)
+	{
+		if (!Config.L2JMOD_MULTILANG_ENABLE
+				|| !Config.L2JMOD_MULTILANG_VOICED_ALLOW)
+			return false;
+
+		NpcHtmlMessage msg = new NpcHtmlMessage(1);
+
+		if (params == null)
+		{
+			final StringBuilder html = StringUtil.startAppend(100);
+			for (String lang : Config.L2JMOD_MULTILANG_ALLOWED)
+			{
+				StringUtil.append(html,
+						"<button value=\"",
+						lang.toUpperCase(),
+						"\" action=\"bypass -h voice .lang ",
+						lang,
+						"\" width=60 height=21 back=\"L2UI_ct1.button_df\" fore=\"L2UI_ct1.button_df\"><br>"
+						);
+			}
+
+			msg.setFile(activeChar.getHtmlPrefix(), "data/html/mods/Lang/LanguageSelect.htm");
+			msg.replace("%list%", html.toString());
+			activeChar.sendPacket(msg);
+			return true;
+		}
+
+		StringTokenizer st = new StringTokenizer(params);
+		if (st.hasMoreTokens())
+		{
+			final String lang = st.nextToken().trim();
+			if (activeChar.setLang(lang))
+			{
+				msg.setFile(activeChar.getHtmlPrefix(), "data/html/mods/Lang/Ok.htm");
+				return true;
+			}
+			else
+				msg.setFile(activeChar.getHtmlPrefix(), "data/html/mods/Lang/Error.htm");
+		}
+
+		return false;
+	}
+
+	/**
+	 * 
+	 * @see com.l2jserver.gameserver.handler.IVoicedCommandHandler#getVoicedCommandList()
+	 */
+	public String[] getVoicedCommandList()
+	{
+		return VOICED_COMMANDS;
+	}
+}
\ No newline at end of file
diff --git a/datapack_development/data/scripts/handlers/voicedcommandhandlers/TvTVoicedInfo.java b/datapack_development/data/scripts/handlers/voicedcommandhandlers/TvTVoicedInfo.java
index e454b2ca55eb312115765cb3d820ed3305406b54..239334a6a56fb6da4b448327c13bb88461e348d2 100644
--- a/datapack_development/data/scripts/handlers/voicedcommandhandlers/TvTVoicedInfo.java
+++ b/datapack_development/data/scripts/handlers/voicedcommandhandlers/TvTVoicedInfo.java
@@ -37,7 +37,7 @@ public class TvTVoicedInfo implements IVoicedCommandHandler
 	 * Recompiling the script will get the new html would be enough too [DrHouse]
 	 */
 	private static final boolean USE_STATIC_HTML = true;
-	private static final String HTML = HtmCache.getInstance().getHtm("data/html/mods/TvTEvent/Status.htm");
+	private static final String HTML = HtmCache.getInstance().getHtm(null, "data/html/mods/TvTEvent/Status.htm");
 
 	public boolean useVoicedCommand(String command, L2PcInstance activeChar, String target)
 	{
@@ -46,7 +46,7 @@ public class TvTVoicedInfo implements IVoicedCommandHandler
 			if (TvTEvent.isStarting() || TvTEvent.isStarted())
 			{
 				String htmContent = (USE_STATIC_HTML && !HTML.isEmpty()) ? HTML : 
-					HtmCache.getInstance().getHtm("data/html/mods/TvTEvent/Status.htm");
+					HtmCache.getInstance().getHtm(activeChar.getHtmlPrefix(), "data/html/mods/TvTEvent/Status.htm");
 				
 				try
 				{
diff --git a/datapack_development/data/scripts/quests/384_WarehouseKeepersPastime/__init__.py b/datapack_development/data/scripts/quests/384_WarehouseKeepersPastime/__init__.py
index c490ed501466f0f89d4909ce9dea48c575f2c422..cd5a4c21e463844b6b33677e98fdea5d44609b01 100644
--- a/datapack_development/data/scripts/quests/384_WarehouseKeepersPastime/__init__.py
+++ b/datapack_development/data/scripts/quests/384_WarehouseKeepersPastime/__init__.py
@@ -4,7 +4,6 @@ from com.l2jserver.gameserver.model.quest import State
 from com.l2jserver.gameserver.model.quest import QuestState
 from com.l2jserver.gameserver.model.quest.jython import QuestJython as JQuest
 from com.l2jserver.util import Rnd
-from com.l2jserver.gameserver.cache import HtmCache
 
 qn = "384_WarehouseKeepersPastime"
 
@@ -171,24 +170,24 @@ class Quest (JQuest) :
    elif event.startswith("select_1-") : #first pick
        selection = int(event[9])
        self.gameStatus[player.getName()][1].append(selection)
-       htmltext = HtmCache.getInstance().getHtm("data/scripts/quests/" + qn + "/" + npcId + "-14.htm")
+       htmltext = self.getHtm(player.getHtmlPrefix(), npcId + "-14.htm")
        htmltext = self.fillBoard(player,htmltext)
    elif event.startswith("select_2-") : #pick #2-5
        selection = int(event[9])
        guess = self.gameStatus[player.getName()][1]
        num_guesses = len(guess)
        if selection in guess : #already chose that number!
-           htmltext = HtmCache.getInstance().getHtm("data/scripts/quests/" + qn + "/" + npcId + "-" + str(14+2*num_guesses) + ".htm")
+           htmltext = self.getHtm(player.getHtmlPrefix(), npcId + "-" + str(14+2*num_guesses) + ".htm")
        else :
            self.gameStatus[player.getName()][1].append(selection)
            num_guesses += 1
-           htmltext = HtmCache.getInstance().getHtm("data/scripts/quests/" + qn + "/" + npcId + "-" + str(11+2*num_guesses) + ".htm")
+           htmltext = self.getHtm(player.getHtmlPrefix(), npcId + "-" + str(11+2*num_guesses) + ".htm")
        htmltext = self.fillBoard(player,htmltext)
    elif event.startswith("select_3-") : #pick #6
        selection = int(event[9])
        guess = self.gameStatus[player.getName()][1]
        if selection in guess : #already chose that number!
-           htmltext = HtmCache.getInstance().getHtm("data/scripts/quests/" + qn + "/" + npcId + "-26.htm")
+           htmltext = self.getHtm(player.getHtmlPrefix(), npcId + "-26.htm")
            htmltext = self.fillBoard(player,htmltext)
        else :
            self.gameStatus[player.getName()][1].append(selection)
@@ -197,14 +196,14 @@ class Quest (JQuest) :
            if wins == 3 :
                item = self.getReward(eval("Rewards_"+str(bet)+"_Win"))
                st.giveItems(item,1)
-               htmltext = HtmCache.getInstance().getHtm("data/scripts/quests/" + qn + "/" + npcId + "-23.htm")
+               htmltext = self.getHtm(player.getHtmlPrefix(), npcId + "-23.htm")
            elif wins == 0 :
                item = self.getReward(eval("Rewards_"+str(bet)+"_Lose"))
                if item == 2437 : st.giveItems(2463,1)
                st.giveItems(item,1)
-               htmltext = HtmCache.getInstance().getHtm("data/scripts/quests/" + qn + "/" + npcId + "-25.htm")
+               htmltext = self.getHtm(player.getHtmlPrefix(), npcId + "-25.htm")
            else :
-               htmltext = HtmCache.getInstance().getHtm("data/scripts/quests/" + qn + "/" + npcId + "-24.htm")
+               htmltext = self.getHtm(player.getHtmlPrefix(), npcId + "-24.htm")
            guess = self.gameStatus[player.getName()][1]
            for i in range(9) :
               num = self.gameStatus[player.getName()][0][i]
diff --git a/datapack_development/data/scripts/quests/662_AGameOfCards/__init__.py b/datapack_development/data/scripts/quests/662_AGameOfCards/__init__.py
index 2734d4387cf904abcc038037e62a520ea765ab7b..66075e3eaafc3642f70d9ed844d4d7ca6bf1cd36 100644
--- a/datapack_development/data/scripts/quests/662_AGameOfCards/__init__.py
+++ b/datapack_development/data/scripts/quests/662_AGameOfCards/__init__.py
@@ -5,7 +5,6 @@ from com.l2jserver import Config
 from com.l2jserver.gameserver.model.quest import State
 from com.l2jserver.gameserver.model.quest import QuestState
 from com.l2jserver.gameserver.model.quest.jython import QuestJython as JQuest
-from com.l2jserver.gameserver.cache import HtmCache
 
 qn = "662_AGameOfCards"
 
@@ -113,7 +112,7 @@ class Quest (JQuest) :
            if card3 == 0: link3 = "<a action=\"bypass -h Quest 662_AGameOfCards Klump_openCard3.htm\">Put the third card face up.</a><br>"
            if card4 == 0: link4 = "<a action=\"bypass -h Quest 662_AGameOfCards Klump_openCard4.htm\">Put the fourth card face up.</a><br>"
            if card5 == 0: link5 = "<a action=\"bypass -h Quest 662_AGameOfCards Klump_openCard5.htm\">Put the fifth card face up.</a><br>"
-         htmltext = HtmCache.getInstance().getHtm("data/scripts/quests/" + qn + "/Klump_PlayField.htm")
+         htmltext = self.getHtm(st.getPlayer().getHtmlPrefix(), "Klump_PlayField.htm")
          htmltext = htmltext.replace("CARD1",CARD_VALUES[card1]).replace("CARD2",CARD_VALUES[card2]).replace("CARD3",CARD_VALUES[card3]).replace("CARD4",CARD_VALUES[card4]).replace("CARD5",CARD_VALUES[card5])
          htmltext = htmltext.replace("LINK1",link1).replace("LINK2",link2).replace("LINK3",link3).replace("LINK4",link4).replace("LINK5",link5).replace("PRIZE",prizestr)
          if prize :
diff --git a/datapack_development/sql/characters.sql b/datapack_development/sql/characters.sql
index 3b873e14c3a498f9056479466ea3c743bcb05acc..322089ac3c7428723c61ebf27efed7b018cea20e 100644
--- a/datapack_development/sql/characters.sql
+++ b/datapack_development/sql/characters.sql
@@ -60,6 +60,7 @@ CREATE TABLE IF NOT EXISTS `characters` (
   `bookmarkslot` SMALLINT UNSIGNED NOT NULL DEFAULT 0,
   `vitality_points` SMALLINT UNSIGNED NOT NULL DEFAULT 0,
   `createTime` DECIMAL(20,0) NOT NULL default 0,
+  `language` VARCHAR(2) DEFAULT NULL,
   PRIMARY KEY (`charId`),
   KEY `clanid` (`clanid`)
 );
\ No newline at end of file
diff --git a/datapack_development/sql/updates/20100308update.sql b/datapack_development/sql/updates/20100308update.sql
new file mode 100644
index 0000000000000000000000000000000000000000..1580af03c2c9c62b9b5da7b2698af7d94adb5677
--- /dev/null
+++ b/datapack_development/sql/updates/20100308update.sql
@@ -0,0 +1 @@
+ALTER TABLE `characters` ADD `language` VARCHAR(2) DEFAULT NULL AFTER `createTime`;
\ No newline at end of file