diff --git a/game/engines/default/engine/FontPackage.lua b/game/engines/default/engine/FontPackage.lua
index 52f842d797999c5a21858463cd407ae715465df2..89e6ec1b8b13f9f9d00b1d8282e1044e436b5ca8 100644
--- a/game/engines/default/engine/FontPackage.lua
+++ b/game/engines/default/engine/FontPackage.lua
@@ -71,8 +71,8 @@ end
 -- @string orname
 -- @return font object
 -- @return size
-function _M:resolveFont(name, orname)
-	local font = packages[cur_id]
+function _M:resolveFont(name, orname, package_id)
+	local font = packages[package_id or cur_id]
 	local size = cur_size
 	if not font[name] then name = orname end
 	if not font[name] then name = "default" end
@@ -86,16 +86,16 @@ end
 -- @string orname
 -- @return font
 -- @return size
-function _M:getFont(name, orname)
-	local font, size = self:resolveFont(name, orname)
+function _M:getFont(name, orname, package_id)
+	local font, size = self:resolveFont(name, orname, package_id)
 	return font.font, math.ceil(font[size] * config.settings.font_scale / 100)
 end
 
 --- Get by name. 
 -- @string name
 -- @param[type=?boolean] force make a font bold no matter what
-function _M:get(name, force)
-	local font, size = self:resolveFont(name)
+function _M:get(name, force, package_id)
+	local font, size = self:resolveFont(name, nil, package_id)
 	local f = core.display.newFont(font.font, math.ceil(font[size] * config.settings.font_scale / 100), font.bold or force)
 	if font.bold then f:setStyle("bold") end
 	return f
diff --git a/game/engines/default/engine/dialogs/GameMenu.lua b/game/engines/default/engine/dialogs/GameMenu.lua
index 996b00b31f2b1c8beedb1bd9a2586df7cd0d80aa..f6d69eeedea2425aa760624a465982c92c86ae62 100644
--- a/game/engines/default/engine/dialogs/GameMenu.lua
+++ b/game/engines/default/engine/dialogs/GameMenu.lua
@@ -50,6 +50,12 @@ end
 function _M:generateList(actions)
 	local default_actions = {
 		resume = { _t"Resume", function() game:unregisterDialog(self) end },
+		language = { _t"Language", function()
+			game:unregisterDialog(self)
+			package.loaded["engine.dialogs.LanguageSelect"] = nil
+			local menu = require("engine.dialogs.LanguageSelect").new()
+			game:registerDialog(menu)
+		end },
 		keybinds = { _t"Key Bindings", function()
 			game:unregisterDialog(self)
 			local menu = require("engine.dialogs.KeyBinder").new(game.normal_key, nil, game.gestures)
diff --git a/game/engines/default/engine/dialogs/LanguageSelect.lua b/game/engines/default/engine/dialogs/LanguageSelect.lua
new file mode 100644
index 0000000000000000000000000000000000000000..56730b91f7511d0157d6bbc1d3cd008670279713
--- /dev/null
+++ b/game/engines/default/engine/dialogs/LanguageSelect.lua
@@ -0,0 +1,68 @@
+-- TE4 - T-Engine 4
+-- Copyright (C) 2009 - 2019 Nicolas Casalini
+--
+-- 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/>.
+--
+-- Nicolas Casalini "DarkGod"
+-- darkgod@te4.org
+
+require "engine.class"
+local Dialog = require "engine.ui.Dialog"
+local FontPackage = require "engine.FontPackage"
+local VariableList = require "engine.ui.VariableList"
+local Textzone = require "engine.ui.Textzone"
+local Separator = require "engine.ui.Separator"
+
+--- Language selection
+-- @classmod engine.dialogs.LanguageSelect
+module(..., package.seeall, class.inherit(Dialog))
+
+function _M:init()
+	Dialog.init(self, _t"Language Selection", 400, 500)
+
+	self:generateList()
+
+	self.c_list = VariableList.new{width=self.iw, max_height=self.ih, list=self.list, fct=function(item) self:select(item) end}
+
+	self:loadUI{
+		{left=0, top=0, ui=self.c_list},
+	}
+	self:setFocus(self.c_list)
+	self:setupUI(false, true)
+
+	self.key:addBinds{
+		EXIT = function() game:unregisterDialog(self) end,
+	}
+end
+
+function _M:select(item)
+	if not item then return end
+
+	game:saveSettings("locale", ("locale = %q\n"):format(item.locale))
+	config.settings.locale = item.locale
+
+	game:saveGame()
+	util.showMainMenu(false, nil, nil, game.__mod_info.short_name, game.save_name, false)	
+end
+
+function _M:generateList()
+	local list = {
+		{name = "English (English)", locale="en_US"},
+		{name = "简体中文 (Simplified Chinese)", locale="zh_hans", font=FontPackage:get("default", nil, "chinese")},
+	}
+
+	self:triggerHook{"I18N:listLanguages", list=list}
+	
+	self.list = list
+end
diff --git a/game/engines/default/engine/ui/VariableList.lua b/game/engines/default/engine/ui/VariableList.lua
index cb92c5cb5e956dd661ff19efd68e8466f1c9c020..69ac2c4c775b4cc5b29025741472cf388538ee0e 100644
--- a/game/engines/default/engine/ui/VariableList.lua
+++ b/game/engines/default/engine/ui/VariableList.lua
@@ -50,7 +50,7 @@ function _M:generate()
 	self.max = #self.list
 
 	local fw, fh = self.w, self.font_h
-	self.fw, self.fh = fw, fh
+	self.fw = fw, fh
 
 	self.frame = self:makeFrame(nil, fw, fh)
 	self.frame_sel = self:makeFrame("ui/selector-sel", fw, fh)
@@ -65,12 +65,18 @@ function _M:generate()
 			local color = item.color or {255,255,255}
 			local width = fw - self.frame_sel.b4.w - self.frame_sel.b6.w
 
-			local text = self.font:draw(item[self.display_prop], width, color[1], color[2], color[3])
+			local font, fh = self.font, fh
+			if item.font then
+				font = item.font
+				fh = font:lineSkip()
+			end
+
+			local text = font:draw(item[self.display_prop], width, color[1], color[2], color[3])
 			ifh = fh * #text + self.frame_sel.b8.w / 3 * 2
 
 			local texs = {}
 			for z, tex in ipairs(text) do
-				texs[z] = {t=tex._tex, tw=tex._tex_w, th = tex._tex_h, w=tex.w, h=tex.h, y = (z - 1) * self.font_h + self.frame_sel.b8.w / 3}
+				texs[z] = {t=tex._tex, tw=tex._tex_w, th = tex._tex_h, w=tex.w, h=tex.h, y = (z - 1) * fh + self.frame_sel.b8.w / 3}
 			end
 			item.start_h = sh
 			item.fh = ifh
diff --git a/game/engines/default/modules/boot/dialogs/MainMenu.lua b/game/engines/default/modules/boot/dialogs/MainMenu.lua
index 94ecb19beef9478cfa3867bba7eb8ae3b3ac4329..2823b376e9020b3507f194de74648cc4f3d6b01c 100644
--- a/game/engines/default/modules/boot/dialogs/MainMenu.lua
+++ b/game/engines/default/modules/boot/dialogs/MainMenu.lua
@@ -64,6 +64,7 @@ function _M:init()
 				end
 				game:registerDialog(d)
 			end},
+			"language",
 			"video",
 			"sound",
 			"steam",
diff --git a/game/modules/tome/class/Game.lua b/game/modules/tome/class/Game.lua
index 42b231e35e5f80f6949b031ff0e20f3466cb8c03..306f4b2fb05b38964ec3d0bfc854da15718d6afe 100644
--- a/game/modules/tome/class/Game.lua
+++ b/game/modules/tome/class/Game.lua
@@ -2361,6 +2361,7 @@ do return end
 				{ _t"Inventory", function() self:unregisterDialog(menu) self.key:triggerVirtual("SHOW_INVENTORY") end },
 				{ _t"Character Sheet", function() self:unregisterDialog(menu) self.key:triggerVirtual("SHOW_CHARACTER_SHEET") end },
 				"keybinds",
+				"language",
 				{_t"Game Options", function() self:unregisterDialog(menu) self:registerDialog(require("mod.dialogs.GameOptions").new()) end},
 				"video",
 				"sound",