summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--applications/luci-app-adblock/luasrc/controller/adblock.lua10
-rw-r--r--applications/luci-app-adblock/luasrc/model/cbi/adblock/blacklist_tab.lua1
-rw-r--r--applications/luci-app-adblock/luasrc/model/cbi/adblock/configuration_tab.lua1
-rw-r--r--applications/luci-app-adblock/luasrc/model/cbi/adblock/overview_tab.lua4
-rw-r--r--applications/luci-app-adblock/luasrc/model/cbi/adblock/whitelist_tab.lua1
-rw-r--r--applications/luci-app-adblock/po/ja/adblock.po20
-rw-r--r--applications/luci-app-adblock/po/pt-br/adblock.po8
-rw-r--r--applications/luci-app-adblock/po/sv/adblock.po8
-rw-r--r--applications/luci-app-adblock/po/templates/adblock.pot8
-rw-r--r--applications/luci-app-adblock/po/zh-cn/adblock.po8
-rw-r--r--applications/luci-app-aria2/po/sv/aria2.po2
-rw-r--r--applications/luci-app-attendedsysupgrade/Makefile11
-rw-r--r--applications/luci-app-attendedsysupgrade/luasrc/controller/attendedsysupgrade.lua5
-rw-r--r--applications/luci-app-attendedsysupgrade/luasrc/view/attendedsysupgrade.htm266
-rw-r--r--applications/luci-app-bcp38/po/templates/bcp38.pot45
-rw-r--r--applications/luci-app-bcp38/po/zh-cn/bcp38.po52
-rw-r--r--applications/luci-app-clamav/po/sv/clamav.po2
-rw-r--r--applications/luci-app-commands/po/sv/commands.po4
-rw-r--r--applications/luci-app-ddns/po/sv/ddns.po17
-rw-r--r--applications/luci-app-diag-core/po/sv/diag_core.po4
-rw-r--r--applications/luci-app-firewall/luasrc/model/cbi/firewall/custom.lua2
-rw-r--r--applications/luci-app-firewall/po/ca/firewall.po2
-rw-r--r--applications/luci-app-firewall/po/cs/firewall.po2
-rw-r--r--applications/luci-app-firewall/po/de/firewall.po2
-rw-r--r--applications/luci-app-firewall/po/el/firewall.po2
-rw-r--r--applications/luci-app-firewall/po/en/firewall.po2
-rw-r--r--applications/luci-app-firewall/po/es/firewall.po2
-rw-r--r--applications/luci-app-firewall/po/fr/firewall.po2
-rw-r--r--applications/luci-app-firewall/po/he/firewall.po2
-rw-r--r--applications/luci-app-firewall/po/hu/firewall.po2
-rw-r--r--applications/luci-app-firewall/po/it/firewall.po2
-rw-r--r--applications/luci-app-firewall/po/ja/firewall.po2
-rw-r--r--applications/luci-app-firewall/po/ko/firewall.po2
-rw-r--r--applications/luci-app-firewall/po/ms/firewall.po2
-rw-r--r--applications/luci-app-firewall/po/no/firewall.po2
-rw-r--r--applications/luci-app-firewall/po/pl/firewall.po2
-rw-r--r--applications/luci-app-firewall/po/pt-br/firewall.po2
-rw-r--r--applications/luci-app-firewall/po/pt/firewall.po2
-rw-r--r--applications/luci-app-firewall/po/ro/firewall.po2
-rw-r--r--applications/luci-app-firewall/po/ru/firewall.po2
-rw-r--r--applications/luci-app-firewall/po/sk/firewall.po2
-rw-r--r--applications/luci-app-firewall/po/sv/firewall.po2
-rw-r--r--applications/luci-app-firewall/po/templates/firewall.pot2
-rw-r--r--applications/luci-app-firewall/po/tr/firewall.po2
-rw-r--r--applications/luci-app-firewall/po/uk/firewall.po2
-rw-r--r--applications/luci-app-firewall/po/vi/firewall.po2
-rw-r--r--applications/luci-app-firewall/po/zh-cn/firewall.po201
-rw-r--r--applications/luci-app-firewall/po/zh-tw/firewall.po4
-rw-r--r--applications/luci-app-mwan3/luasrc/controller/mwan3.lua2
-rw-r--r--applications/luci-app-mwan3/luasrc/model/cbi/mwan/globalsconfig.lua32
-rw-r--r--applications/luci-app-mwan3/luasrc/model/cbi/mwan/interfaceconfig.lua10
-rw-r--r--applications/luci-app-mwan3/po/ja/mwan3.po69
-rw-r--r--applications/luci-app-mwan3/po/templates/mwan3.pot29
-rw-r--r--applications/luci-app-mwan3/po/zh-cn/mwan3.po29
-rwxr-xr-xapplications/luci-app-mwan3/root/etc/uci-defaults/60_luci-mwan37
-rw-r--r--applications/luci-app-nlbwmon/Makefile8
-rw-r--r--applications/luci-app-nlbwmon/htdocs/luci-static/resources/nlbw.chart.min.js68
-rw-r--r--applications/luci-app-nlbwmon/luasrc/controller/nlbw.lua225
-rw-r--r--applications/luci-app-nlbwmon/luasrc/model/cbi/nlbw/config.lua215
-rw-r--r--applications/luci-app-nlbwmon/luasrc/view/nlbw/backup.htm34
-rw-r--r--applications/luci-app-nlbwmon/luasrc/view/nlbw/display.htm1052
-rw-r--r--applications/luci-app-nlbwmon/po/ja/nlbwmon.po387
-rw-r--r--applications/luci-app-nlbwmon/po/templates/nlbwmon.pot352
-rw-r--r--applications/luci-app-nlbwmon/po/zh-cn/nlbwmon.po366
-rw-r--r--applications/luci-app-nlbwmon/root/etc/uci-defaults/40_luci-nlbwmon11
-rw-r--r--applications/luci-app-shadowsocks-libev/luasrc/model/cbi/shadowsocks-libev/instance-details.lua6
-rw-r--r--applications/luci-app-shadowsocks-libev/luasrc/model/shadowsocks-libev.lua10
-rw-r--r--applications/luci-app-statistics/po/ca/statistics.po15
-rw-r--r--applications/luci-app-statistics/po/cs/statistics.po15
-rw-r--r--applications/luci-app-statistics/po/de/statistics.po15
-rw-r--r--applications/luci-app-statistics/po/el/statistics.po15
-rw-r--r--applications/luci-app-statistics/po/en/statistics.po15
-rw-r--r--applications/luci-app-statistics/po/es/statistics.po15
-rw-r--r--applications/luci-app-statistics/po/fr/statistics.po15
-rw-r--r--applications/luci-app-statistics/po/he/statistics.po15
-rw-r--r--applications/luci-app-statistics/po/hu/statistics.po15
-rw-r--r--applications/luci-app-statistics/po/it/statistics.po15
-rw-r--r--applications/luci-app-statistics/po/ja/statistics.po15
-rw-r--r--applications/luci-app-statistics/po/ms/statistics.po15
-rw-r--r--applications/luci-app-statistics/po/no/statistics.po15
-rw-r--r--applications/luci-app-statistics/po/pl/statistics.po15
-rw-r--r--applications/luci-app-statistics/po/pt-br/statistics.po15
-rw-r--r--applications/luci-app-statistics/po/pt/statistics.po15
-rw-r--r--applications/luci-app-statistics/po/ro/statistics.po15
-rw-r--r--applications/luci-app-statistics/po/ru/statistics.po15
-rw-r--r--applications/luci-app-statistics/po/sk/statistics.po15
-rw-r--r--applications/luci-app-statistics/po/sv/statistics.po15
-rw-r--r--applications/luci-app-statistics/po/templates/statistics.pot15
-rw-r--r--applications/luci-app-statistics/po/tr/statistics.po15
-rw-r--r--applications/luci-app-statistics/po/uk/statistics.po15
-rw-r--r--applications/luci-app-statistics/po/vi/statistics.po15
-rw-r--r--applications/luci-app-statistics/po/zh-cn/statistics.po15
-rw-r--r--applications/luci-app-statistics/po/zh-tw/statistics.po15
-rw-r--r--applications/luci-app-travelmate/po/ja/travelmate.po63
-rw-r--r--applications/luci-app-travelmate/po/pt-br/travelmate.po39
-rw-r--r--applications/luci-app-travelmate/po/templates/travelmate.pot39
-rw-r--r--applications/luci-app-watchcat/po/sv/watchcat.po4
-rw-r--r--applications/luci-app-wifischedule/po/sv/wifischedule.po2
-rw-r--r--applications/luci-app-wireguard/po/sv/wireguard.po2
-rw-r--r--modules/luci-base/htdocs/luci-static/resources/cbi.js11
-rw-r--r--modules/luci-base/htdocs/luci-static/resources/xhr.js2
-rw-r--r--modules/luci-base/luasrc/sys.lua4
-rw-r--r--modules/luci-base/po/ca/base.po3
-rw-r--r--modules/luci-base/po/cs/base.po3
-rw-r--r--modules/luci-base/po/de/base.po3
-rw-r--r--modules/luci-base/po/el/base.po3
-rw-r--r--modules/luci-base/po/en/base.po3
-rw-r--r--modules/luci-base/po/es/base.po3
-rw-r--r--modules/luci-base/po/fr/base.po3
-rw-r--r--modules/luci-base/po/he/base.po3
-rw-r--r--modules/luci-base/po/hu/base.po3
-rw-r--r--modules/luci-base/po/it/base.po3
-rw-r--r--modules/luci-base/po/ja/base.po29
-rw-r--r--modules/luci-base/po/ko/base.po3
-rw-r--r--modules/luci-base/po/ms/base.po3
-rw-r--r--modules/luci-base/po/no/base.po3
-rw-r--r--modules/luci-base/po/pl/base.po3
-rw-r--r--modules/luci-base/po/pt-br/base.po3
-rw-r--r--modules/luci-base/po/pt/base.po3
-rw-r--r--modules/luci-base/po/ro/base.po3
-rw-r--r--modules/luci-base/po/ru/base.po3
-rw-r--r--modules/luci-base/po/sk/base.po3
-rw-r--r--modules/luci-base/po/sv/base.po3
-rw-r--r--modules/luci-base/po/templates/base.pot3
-rw-r--r--modules/luci-base/po/tr/base.po3
-rw-r--r--modules/luci-base/po/uk/base.po3
-rw-r--r--modules/luci-base/po/vi/base.po3
-rw-r--r--modules/luci-base/po/zh-cn/base.po35
-rw-r--r--modules/luci-base/po/zh-tw/base.po3
-rw-r--r--modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/network.lua1
-rw-r--r--modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi.lua3
131 files changed, 4041 insertions, 304 deletions
diff --git a/applications/luci-app-adblock/luasrc/controller/adblock.lua b/applications/luci-app-adblock/luasrc/controller/adblock.lua
index 03b9fc20eb..efa99b5b89 100644
--- a/applications/luci-app-adblock/luasrc/controller/adblock.lua
+++ b/applications/luci-app-adblock/luasrc/controller/adblock.lua
@@ -5,7 +5,7 @@ module("luci.controller.adblock", package.seeall)
local fs = require("nixio.fs")
local util = require("luci.util")
-local template = require("luci.template")
+local templ = require("luci.template")
local i18n = require("luci.i18n")
function index()
@@ -19,17 +19,13 @@ function index()
entry({"admin", "services", "adblock", "advanced", "blacklist"}, cbi("adblock/blacklist_tab"), _("Edit Blacklist"), 110).leaf = true
entry({"admin", "services", "adblock", "advanced", "whitelist"}, cbi("adblock/whitelist_tab"), _("Edit Whitelist"), 120).leaf = true
entry({"admin", "services", "adblock", "advanced", "configuration"}, cbi("adblock/configuration_tab"), _("Edit Configuration"), 130).leaf = true
- entry({"admin", "services", "adblock", "advanced", "query"}, call("query"), _("Query domains"), 140).leaf = true
+ entry({"admin", "services", "adblock", "advanced", "query"}, template("adblock/query"), _("Query domains"), 140).leaf = true
entry({"admin", "services", "adblock", "advanced", "result"}, call("queryData"), nil, 150).leaf = true
end
function logread()
local logfile = util.trim(util.exec("logread -e 'adblock'"))
- template.render("adblock/logread", {title = i18n.translate("Adblock Logfile"), content = logfile})
-end
-
-function query()
- template.render("adblock/query", {title = i18n.translate("Adblock Domain Query")})
+ templ.render("adblock/logread", {title = i18n.translate("Adblock Logfile"), content = logfile})
end
function queryData(domain)
diff --git a/applications/luci-app-adblock/luasrc/model/cbi/adblock/blacklist_tab.lua b/applications/luci-app-adblock/luasrc/model/cbi/adblock/blacklist_tab.lua
index 59cd1e80fa..ef70100e4f 100644
--- a/applications/luci-app-adblock/luasrc/model/cbi/adblock/blacklist_tab.lua
+++ b/applications/luci-app-adblock/luasrc/model/cbi/adblock/blacklist_tab.lua
@@ -25,6 +25,7 @@ end
m = SimpleForm("input", nil)
m:append(Template("adblock/config_css"))
+m.submit = translate("Save")
m.reset = false
s = m:section(SimpleSection, nil,
diff --git a/applications/luci-app-adblock/luasrc/model/cbi/adblock/configuration_tab.lua b/applications/luci-app-adblock/luasrc/model/cbi/adblock/configuration_tab.lua
index 1607f1440a..1d89485e79 100644
--- a/applications/luci-app-adblock/luasrc/model/cbi/adblock/configuration_tab.lua
+++ b/applications/luci-app-adblock/luasrc/model/cbi/adblock/configuration_tab.lua
@@ -14,6 +14,7 @@ end
m = SimpleForm("input", nil)
m:append(Template("adblock/config_css"))
+m.submit = translate("Save")
m.reset = false
s = m:section(SimpleSection, nil,
diff --git a/applications/luci-app-adblock/luasrc/model/cbi/adblock/overview_tab.lua b/applications/luci-app-adblock/luasrc/model/cbi/adblock/overview_tab.lua
index 68f9c8897e..aa57014879 100644
--- a/applications/luci-app-adblock/luasrc/model/cbi/adblock/overview_tab.lua
+++ b/applications/luci-app-adblock/luasrc/model/cbi/adblock/overview_tab.lua
@@ -21,6 +21,8 @@ if parse ~= nil then
dnspath = "/var/lib/unbound"
elseif backend == "named" then
dnspath = "/var/lib/bind"
+ elseif backend == "kresd" then
+ dnspath = "/tmp/kresd"
end
end
end
@@ -180,7 +182,7 @@ e2 = e:option(Flag, "adb_forcesrt", translate("Force Overall Sort"),
e2.default = e2.disabled
e2.rmempty = false
-e3 = e:option(Flag, "adb_manmode", translate("Manual mode"),
+e3 = e:option(Flag, "adb_manmode", translate("Manual / Backup mode"),
translate("Do not automatically update blocklists during startup, use blocklist backups instead."))
e3.default = e3.disabled
e3.rmempty = false
diff --git a/applications/luci-app-adblock/luasrc/model/cbi/adblock/whitelist_tab.lua b/applications/luci-app-adblock/luasrc/model/cbi/adblock/whitelist_tab.lua
index 10a593859f..a3659eb469 100644
--- a/applications/luci-app-adblock/luasrc/model/cbi/adblock/whitelist_tab.lua
+++ b/applications/luci-app-adblock/luasrc/model/cbi/adblock/whitelist_tab.lua
@@ -24,6 +24,7 @@ end
m = SimpleForm("input", nil)
m:append(Template("adblock/config_css"))
+m.submit = translate("Save")
m.reset = false
s = m:section(SimpleSection, nil,
diff --git a/applications/luci-app-adblock/po/ja/adblock.po b/applications/luci-app-adblock/po/ja/adblock.po
index 07fd783ed2..b3e139e12d 100644
--- a/applications/luci-app-adblock/po/ja/adblock.po
+++ b/applications/luci-app-adblock/po/ja/adblock.po
@@ -8,15 +8,12 @@ msgstr ""
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Generator: Poedit 2.0.2\n"
+"X-Generator: Poedit 2.0.3\n"
"Language: ja\n"
msgid "Adblock"
msgstr "Adblock"
-msgid "Adblock Domain Query"
-msgstr "Adblock ドメイン検索"
-
msgid "Adblock Logfile"
msgstr "Adblock ログファイル"
@@ -137,8 +134,8 @@ msgstr "最終実行日時"
msgid "Loading"
msgstr "読込中"
-msgid "Manual mode"
-msgstr "マニュアル モード"
+msgid "Manual / Backup mode"
+msgstr "手動 / ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ— モード"
msgid "No"
msgstr "ã„ã„ãˆ"
@@ -189,6 +186,9 @@ msgstr "実行情報"
msgid "SSL req."
msgstr "SSL å¿…é ˆ"
+msgid "Save"
+msgstr "ä¿å­˜"
+
msgid ""
"Space separated list of interfaces that trigger adblock processing. To "
"disable event driven (re-)starts remove all entries."
@@ -201,15 +201,15 @@ msgid "Status"
msgstr "ステータス"
msgid "Suspend / Resume adblock"
-msgstr "Adblock ã®ä¸€æ™‚åœæ­¢/å†é–‹"
+msgstr "Adblock ã®ä¸€æ™‚åœæ­¢ / å†é–‹"
msgid "Suspend adblock"
msgstr "Adblock ã®ä¸€æ™‚åœæ­¢"
msgid "The file size is too large for online editing in LuCI (> 512 KB)."
msgstr ""
-"ファイル サイズãŒå¤§ãã™ãŽã‚‹ãŸã‚〠LuCI 上ã§ã‚ªãƒ³ãƒ©ã‚¤ãƒ³ç·¨é›†ã§ãã¾ã›ã‚“(> "
-"512 KB)。"
+"ファイル サイズãŒå¤§ãã™ãŽã‚‹ï¼ˆ512 KB超)ãŸã‚〠LuCI 上ã§ã‚ªãƒ³ãƒ©ã‚¤ãƒ³ç·¨é›†ã§ãã¾ã›"
+"ん。"
msgid ""
"This form allows you to modify the content of the adblock blacklist (%s)."
@@ -253,7 +253,7 @@ msgid "View Logfile"
msgstr "ログファイルを見る"
msgid "Waiting for command to complete..."
-msgstr "コマンドã®å®Œäº†ã‚’ãŠå¾…ã¡ãã ã•ã„..."
+msgstr "コマンド実行中ã§ã™..."
msgid "Yes"
msgstr "ã¯ã„"
diff --git a/applications/luci-app-adblock/po/pt-br/adblock.po b/applications/luci-app-adblock/po/pt-br/adblock.po
index 044352da63..586c318014 100644
--- a/applications/luci-app-adblock/po/pt-br/adblock.po
+++ b/applications/luci-app-adblock/po/pt-br/adblock.po
@@ -15,9 +15,6 @@ msgstr ""
msgid "Adblock"
msgstr "Adblock"
-msgid "Adblock Domain Query"
-msgstr ""
-
msgid "Adblock Logfile"
msgstr ""
@@ -127,7 +124,7 @@ msgstr ""
msgid "Loading"
msgstr ""
-msgid "Manual mode"
+msgid "Manual / Backup mode"
msgstr ""
msgid "No"
@@ -176,6 +173,9 @@ msgstr ""
msgid "SSL req."
msgstr ""
+msgid "Save"
+msgstr ""
+
msgid ""
"Space separated list of interfaces that trigger adblock processing. To "
"disable event driven (re-)starts remove all entries."
diff --git a/applications/luci-app-adblock/po/sv/adblock.po b/applications/luci-app-adblock/po/sv/adblock.po
index cf92dbddc0..a70a1a1d67 100644
--- a/applications/luci-app-adblock/po/sv/adblock.po
+++ b/applications/luci-app-adblock/po/sv/adblock.po
@@ -4,9 +4,6 @@ msgstr "Content-Type: text/plain; charset=UTF-8\n"
msgid "Adblock"
msgstr "Adblock"
-msgid "Adblock Domain Query"
-msgstr ""
-
msgid "Adblock Logfile"
msgstr "Adblock's loggfil"
@@ -117,7 +114,7 @@ msgstr ""
msgid "Loading"
msgstr "Laddar"
-msgid "Manual mode"
+msgid "Manual / Backup mode"
msgstr ""
msgid "No"
@@ -164,6 +161,9 @@ msgstr "Information om kör-tid"
msgid "SSL req."
msgstr ""
+msgid "Save"
+msgstr ""
+
msgid ""
"Space separated list of interfaces that trigger adblock processing. To "
"disable event driven (re-)starts remove all entries."
diff --git a/applications/luci-app-adblock/po/templates/adblock.pot b/applications/luci-app-adblock/po/templates/adblock.pot
index 5b5a96866a..3b61036e02 100644
--- a/applications/luci-app-adblock/po/templates/adblock.pot
+++ b/applications/luci-app-adblock/po/templates/adblock.pot
@@ -4,9 +4,6 @@ msgstr "Content-Type: text/plain; charset=UTF-8"
msgid "Adblock"
msgstr ""
-msgid "Adblock Domain Query"
-msgstr ""
-
msgid "Adblock Logfile"
msgstr ""
@@ -114,7 +111,7 @@ msgstr ""
msgid "Loading"
msgstr ""
-msgid "Manual mode"
+msgid "Manual / Backup mode"
msgstr ""
msgid "No"
@@ -161,6 +158,9 @@ msgstr ""
msgid "SSL req."
msgstr ""
+msgid "Save"
+msgstr ""
+
msgid ""
"Space separated list of interfaces that trigger adblock processing. To "
"disable event driven (re-)starts remove all entries."
diff --git a/applications/luci-app-adblock/po/zh-cn/adblock.po b/applications/luci-app-adblock/po/zh-cn/adblock.po
index 46dc99e66e..534e8f5cce 100644
--- a/applications/luci-app-adblock/po/zh-cn/adblock.po
+++ b/applications/luci-app-adblock/po/zh-cn/adblock.po
@@ -16,9 +16,6 @@ msgstr ""
msgid "Adblock"
msgstr "Adblock"
-msgid "Adblock Domain Query"
-msgstr ""
-
msgid "Adblock Logfile"
msgstr "Adblock 日志文件"
@@ -126,7 +123,7 @@ msgstr ""
msgid "Loading"
msgstr "加载中"
-msgid "Manual mode"
+msgid "Manual / Backup mode"
msgstr ""
msgid "No"
@@ -173,6 +170,9 @@ msgstr "è¿è¡Œä¿¡æ¯"
msgid "SSL req."
msgstr ""
+msgid "Save"
+msgstr ""
+
msgid ""
"Space separated list of interfaces that trigger adblock processing. To "
"disable event driven (re-)starts remove all entries."
diff --git a/applications/luci-app-aria2/po/sv/aria2.po b/applications/luci-app-aria2/po/sv/aria2.po
index a7f41f250d..3a129364cf 100644
--- a/applications/luci-app-aria2/po/sv/aria2.po
+++ b/applications/luci-app-aria2/po/sv/aria2.po
@@ -1,5 +1,5 @@
msgid ""
-msgstr "Content-Type: text/plain; charset=UTF-8"
+msgstr "Content-Type: text/plain; charset=UTF-8\n"
msgid "\"Falloc\" is not available in all cases."
msgstr ""
diff --git a/applications/luci-app-attendedsysupgrade/Makefile b/applications/luci-app-attendedsysupgrade/Makefile
new file mode 100644
index 0000000000..32992e19df
--- /dev/null
+++ b/applications/luci-app-attendedsysupgrade/Makefile
@@ -0,0 +1,11 @@
+# See /LICENSE for more information.
+# This is free software, licensed under the GNU General Public License v2.
+
+include $(TOPDIR)/rules.mk
+
+LUCI_TITLE:=LuCI support for attended sysupgrades
+LUCI_DEPENDS:=+luci-base +rpcd-mod-attendedsysupgrade
+
+include ../../luci.mk
+
+# call BuildPackage - OpenWrt buildroot signature
diff --git a/applications/luci-app-attendedsysupgrade/luasrc/controller/attendedsysupgrade.lua b/applications/luci-app-attendedsysupgrade/luasrc/controller/attendedsysupgrade.lua
new file mode 100644
index 0000000000..1bd050af66
--- /dev/null
+++ b/applications/luci-app-attendedsysupgrade/luasrc/controller/attendedsysupgrade.lua
@@ -0,0 +1,5 @@
+module("luci.controller.attendedsysupgrade", package.seeall)
+
+function index()
+ entry({"admin", "system", "attended_sysupgrade"}, template("attendedsysupgrade"), _("Attended Sysupgrade"), 1)
+end
diff --git a/applications/luci-app-attendedsysupgrade/luasrc/view/attendedsysupgrade.htm b/applications/luci-app-attendedsysupgrade/luasrc/view/attendedsysupgrade.htm
new file mode 100644
index 0000000000..4f8bf7cc9a
--- /dev/null
+++ b/applications/luci-app-attendedsysupgrade/luasrc/view/attendedsysupgrade.htm
@@ -0,0 +1,266 @@
+<%+header%>
+<h2 name="content"><%:Attended Sysupgrade%></h2>
+<div class="container">
+ <div style="display: none" id="update_info" class="alert-message info">
+ </div>
+ <div style="display: none" id="update_error" class="alert-message danger">
+ </div>
+</div>
+<input class="cbi-button" value="search for updates" onclick="update_request()" type="button" id="update_button">
+
+<script type="text/javascript">
+
+latest_release = "";
+data = {};
+ubus_counter = 1
+origin = document.location.href.replace(location.pathname, "")
+ubus_url = origin + "/ubus/"
+
+// requests to the update server
+function server_request(request_dict, path, callback) {
+ url = data.update_server + "/" + path
+ request_dict.distro = data.release.distribution;
+ request_dict.target = data.release.target.split("\/")[0];
+ request_dict.subtarget = data.release.target.split("\/")[1];
+ request_dict.packages = data.packagelist;
+ var xmlhttp = new XMLHttpRequest();
+ xmlhttp.open("POST", url, true);
+ xmlhttp.setRequestHeader("Content-type", "application/json");
+ xmlhttp.send(JSON.stringify(request_dict));
+ xmlhttp.onerror = function(e) {
+ update_error("update server down")
+ }
+ xmlhttp.addEventListener('load', function(event) {
+ callback(xmlhttp)
+ });
+}
+
+// requests ubus via rpcd
+function ubus_request(command, argument, params, callback) {
+ // perform login if ubus_rpc_session is empty
+ var request_data = '{ "jsonrpc": "2.0", "id": ' + ubus_counter + ', "method": "call", "params": [ "'+ data["ubus_rpc_session"] +'", "' + command + '", "' + argument + '", ' + params + ' ] }'
+ ubus_counter++
+ var xmlhttp = new XMLHttpRequest();
+ xmlhttp.open("POST", ubus_url, true);
+ xmlhttp.setRequestHeader("Content-type", "application/json");
+ xmlhttp.onerror = function(e) {
+ setTimeout(back_online, 5000)
+ }
+ xmlhttp.addEventListener('load', function(event) {
+ if(command === "uci") {
+ ubus_request_callback_uci(xmlhttp, callback)
+ } else {
+ ubus_request_callback(xmlhttp, callback)
+ }
+ });
+ xmlhttp.send(request_data);
+}
+
+// handle ubus_requests, set variables or perform functions
+function ubus_request_callback(response_object, callback) {
+ if(response_object.status === 200) {
+ console.log(callback)
+ if(typeof callback === "string") {
+ response_json = JSON.parse(response_object.responseText).result[1]
+ data[callback] = response_json[callback]
+ } else {
+ callback(response_object)
+ }
+ } else {
+ console.log(respons_object.responseText)
+ }
+}
+
+function ubus_request_callback_uci(response_object, callback) {
+ if(response_object.status === 200) {
+ console.log(callback)
+ response_json = JSON.parse(response_object.responseText).result[1].value
+ data[callback] = response_json
+ } else {
+ console.log(respons_object.responseText)
+ }
+}
+
+// initial setup, get system information
+function setup() {
+ data["ubus_rpc_session"] = "<%=luci.dispatcher.context.authsession%>"
+ ubus_request("packagelist", "list", '{ }', "packagelist")
+ ubus_request("system", "board", '{ }', "release")
+ ubus_request("system", "board", '{ }', "board_name")
+ ubus_request("uci", "get", '{"config": "attendedsysupgrade", "section": "@settings[0]", "option": "update_server"}', "update_server")
+}
+
+// shows notification if update is available
+function update_info(info_output) {
+ document.getElementById("update_info").style.display = "block";
+ document.getElementById("update_info").innerHTML = info_output;
+}
+
+function update_error(error_output) {
+ document.getElementById("update_error").style.display = "block";
+ document.getElementById("update_error").innerHTML = error_output;
+ document.getElementById("update_info").style.display = "None";
+}
+
+// asks server for news updates, actually only based on relesae not packages
+function update_request() {
+ console.log("update_request")
+ request_dict = {}
+ request_dict.version = data.release.version;
+ server_request(request_dict, "update-request", update_request_callback)
+}
+
+function update_request_callback(response_object) {
+ if (response_object.status === 500) {
+ // python crashed
+ update_error("internal server error, please try again later")
+ console.log("update server issue")
+ } else if (response_object.status === 502) {
+ // python part offline
+ update_error("internal server error, please try again later")
+ console.log("update server issue")
+ } else if (response_object.status === 503) {
+ // handle overload
+ update_error("server overloaded, retry in 5 minutes")
+ console.log("server overloaded")
+ setTimeout(update_request, 300000)
+ } else if (response_object.status === 201) {
+ update_info("imagebuilder not ready, please wait")
+ console.log("setting up imagebuilder")
+ setTimeout(update_request, 5000)
+ } else if (response_object.status === 204) {
+ // no updates
+ update_info("no updates available")
+ } else if (response_object.status === 400) {
+ // bad request
+ console.log(response_object.responseText)
+ response_object_content = JSON.parse(response_object.responseText)
+ update_error(response_object_content)
+ } else if (response_object.status === 200) {
+ // new release/updates
+ response_object_content = JSON.parse(response_object.responseText)
+ update_request_200(response_object_content)
+ }
+}
+
+function back_online() {
+ ubus_request("session", "login", '{ }', back_online_callback)
+}
+
+function back_online_callback(response_object) {
+ if (response_object.status != 200) {
+ setTimeout(back_online, 5000)
+ } else {
+ update_info("upgrade successfull!")
+ document.getElementById("update_button").value = "reload page";
+ document.getElementById("update_button").onclick = function() { location.reload(); }
+ }
+
+}
+
+function update_request_200(response_content) {
+ info_output = ""
+ if(response_content.version != undefined) {
+ info_output += "new update available. from " + data.release.version + " to " + response_content.version
+ latest_version = response_content.version;
+ }
+ if(response_content.packages != undefined) {
+ info_output += "package updates available"
+ }
+ update_info(info_output)
+ document.getElementById("update_button").value = "request image";
+ document.getElementById("update_button").onclick = image_request;
+}
+
+// request the image, need merge with update_request
+function image_request() {
+ console.log("image_request")
+ request_dict = {}
+ request_dict.version = latest_version;
+ request_dict.board = data.board_name
+ server_request(request_dict, "image-request", image_request_handler)
+}
+
+function image_request_handler(response) {
+ if (response.status === 400) {
+ response_content = JSON.parse(response.responseText)
+ update_error(response_content.error)
+ } else if (response.status === 500) {
+ image_request_500()
+ } else if (response.status === 503) {
+ update_error("please wait. server overloaded")
+ // handle overload
+ setTimeout(image_request, 30000)
+ } else if (response.status === 201) {
+ response_content = JSON.parse(response.responseText)
+ if(response_content.queue != undefined) {
+ // in queue
+ update_info("please wait. you are in queue position " + response_content.queue)
+ console.log("queued")
+ } else {
+ update_info("imagebuilder not ready, please wait")
+ console.log("setting up imagebuilder")
+ }
+ setTimeout(image_request, 5000)
+ } else if (response.status === 206) {
+ // building
+ console.log("building")
+ update_info("building image")
+ setTimeout(image_request, 5000)
+ } else if (response.status === 200) {
+ // ready to download
+ response_content = JSON.parse(response.responseText)
+ update_info("image created")
+ document.getElementById("update_button").value = "download and flash"
+ document.getElementById("update_button").onclick = function() {download_image(response_content.url); }
+ }
+}
+
+
+// uploads received blob data to the server using cgi-io
+function upload_image(blob) {
+ var upload_request = new XMLHttpRequest();
+ var form_data = new FormData();
+
+ form_data.append("sessionid", data.ubus_rpc_session)
+ form_data.append("filename", "/tmp/sysupgrade.bin")
+ form_data.append("filemode", 755) // insecure?
+ form_data.append("filedata", blob)
+
+ upload_request.addEventListener('load', function(event) {
+ // this checksum should be parsed
+ document.getElementById("update_info").innerHTML = "flashing... please wait" // show fancy indicator http://www.ajaxload.info/
+ ubus_request("attendedsysupgrade", "sysupgrade", '{ }', 'done');
+ });
+
+ upload_request.addEventListener('error', function(event) {
+ document.getElementById("update_info").innerHTML = "uploading failed, please retry"
+ });
+
+ upload_request.open('POST', origin + '/cgi-bin/cgi-upload');
+ upload_request.send(form_data);
+}
+
+// download image from server once the url was received by image_request
+function download_image(url) {
+ console.log("download_image")
+ document.getElementById("update_button").value = "flashing..."
+ document.getElementById("update_button").disabled = true;
+ var download_request = new XMLHttpRequest();
+ download_request.open("GET", url);
+ download_request.responseType = "arraybuffer";
+
+ download_request.onload = function () {
+ if (this.status === 200) {
+ var blob = new Blob([download_request.response], {type: "application/octet-stream"});
+ upload_image(blob)
+ }
+ };
+ document.getElementById("update_info").innerHTML = "downloading image"
+ download_request.send();
+}
+
+document.onload = setup()
+</script>
+
+<%+footer%>
diff --git a/applications/luci-app-bcp38/po/templates/bcp38.pot b/applications/luci-app-bcp38/po/templates/bcp38.pot
new file mode 100644
index 0000000000..1210784d23
--- /dev/null
+++ b/applications/luci-app-bcp38/po/templates/bcp38.pot
@@ -0,0 +1,45 @@
+msgid ""
+msgstr "Content-Type: text/plain; charset=UTF-8"
+
+msgid "Allowed IP ranges"
+msgstr ""
+
+msgid ""
+"Attempt to automatically detect if the upstream IP will be blocked by the "
+"configuration, and add an exception if it will. If this does not work "
+"correctly, you can add exceptions manually below."
+msgstr ""
+
+msgid "Auto-detect upstream IP"
+msgstr ""
+
+msgid "BCP38"
+msgstr ""
+
+msgid "BCP38 config"
+msgstr ""
+
+msgid "Blocked IP ranges"
+msgstr ""
+
+msgid "Enable"
+msgstr ""
+
+msgid "Interface name"
+msgstr ""
+
+msgid ""
+"Interface to apply the blocking to (should be the upstream WAN interface)."
+msgstr ""
+
+msgid ""
+"Takes precedence over blocked ranges. Use to whitelist your upstream network "
+"if you're behind a double NAT and the auto-detection doesn't work."
+msgstr ""
+
+msgid ""
+"This function blocks packets with private address destinations from going "
+"out onto the internet as per <a href=\"http://tools.ietf.org/html/"
+"bcp38\">BCP 38</a>. For IPv6, only source specific default routes are "
+"installed, so no BCP38 firewall routes are needed."
+msgstr ""
diff --git a/applications/luci-app-bcp38/po/zh-cn/bcp38.po b/applications/luci-app-bcp38/po/zh-cn/bcp38.po
new file mode 100644
index 0000000000..f9e0634b8b
--- /dev/null
+++ b/applications/luci-app-bcp38/po/zh-cn/bcp38.po
@@ -0,0 +1,52 @@
+msgid ""
+msgstr "Content-Type: text/plain; charset=UTF-8\n"
+
+msgid "Allowed IP ranges"
+msgstr "å…许的 IP 范围"
+
+msgid ""
+"Attempt to automatically detect if the upstream IP will be blocked by the "
+"configuration, and add an exception if it will. If this does not work "
+"correctly, you can add exceptions manually below."
+msgstr ""
+"自动检测上游 IP 是å¦ä¼šè¢«å½“å‰é…置所阻止,当检测到会被阻止时将会添加例外。如果"
+"自动检测无法正常工作,你å¯ä»¥åœ¨ä¸‹é¢æ‰‹åŠ¨æ·»åŠ ä¾‹å¤–。"
+
+msgid "Auto-detect upstream IP"
+msgstr "自动检测上游 IP"
+
+msgid "BCP38"
+msgstr "BCP38"
+
+msgid "BCP38 config"
+msgstr "BCP38 é…ç½®"
+
+msgid "Blocked IP ranges"
+msgstr "阻止的 IP 范围"
+
+msgid "Enable"
+msgstr "å¯ç”¨"
+
+msgid "Interface name"
+msgstr "接å£å称"
+
+msgid ""
+"Interface to apply the blocking to (should be the upstream WAN interface)."
+msgstr "应用“阻止规则â€çš„接å£ï¼ˆåº”当为上游 WAN 接å£ï¼‰ã€‚"
+
+msgid ""
+"Takes precedence over blocked ranges. Use to whitelist your upstream network "
+"if you're behind a double NAT and the auto-detection doesn't work."
+msgstr ""
+"这里的规则优先于阻止规则被使用。如果你在åŒé‡ NAT 之åŽå¹¶ä¸”自动检测功能ä¸èµ·ä½œ"
+"用,请在这里添加你上游网络的白åå•ã€‚"
+
+msgid ""
+"This function blocks packets with private address destinations from going "
+"out onto the internet as per <a href=\"http://tools.ietf.org/html/"
+"bcp38\">BCP 38</a>. For IPv6, only source specific default routes are "
+"installed, so no BCP38 firewall routes are needed."
+msgstr ""
+"此功能å¯ä»¥é˜»æ­¢å…·æœ‰ç§æœ‰ç›®æ ‡åœ°å€çš„æ•°æ®åŒ…通过 <a href=\"http://tools.ietf.org/"
+"html/bcp38\">BCP 38</a> å‘é€åˆ°äº’è”网上。对于 IPv6,仅安装æºç‰¹å®šçš„默认路由,因"
+"æ­¤ä¸éœ€è¦ BCP38 防ç«å¢™è·¯ç”±ã€‚"
diff --git a/applications/luci-app-clamav/po/sv/clamav.po b/applications/luci-app-clamav/po/sv/clamav.po
index 589d5f9aa3..37de249e54 100644
--- a/applications/luci-app-clamav/po/sv/clamav.po
+++ b/applications/luci-app-clamav/po/sv/clamav.po
@@ -1,5 +1,5 @@
msgid ""
-msgstr "Content-Type: text/plain; charset=UTF-8"
+msgstr "Content-Type: text/plain; charset=UTF-8\n"
msgid "10"
msgstr "10"
diff --git a/applications/luci-app-commands/po/sv/commands.po b/applications/luci-app-commands/po/sv/commands.po
index 8cb1923e29..a944fdb63d 100644
--- a/applications/luci-app-commands/po/sv/commands.po
+++ b/applications/luci-app-commands/po/sv/commands.po
@@ -104,8 +104,8 @@ msgid ""
"This page allows you to configure custom shell commands which can be easily "
"invoked from the web interface."
msgstr ""
-"Den här sidan tillåter dig att ställa in anpassade skalkommandon som lättast kan "
-"åberopas från webbgränssnittet."
+"Den här sidan tillåter dig att ställa in anpassade skalkommandon som lättast "
+"kan åberopas från webbgränssnittet."
msgid "Waiting for command to complete..."
msgstr "Väntar på att kommandot ska slutföras..."
diff --git a/applications/luci-app-ddns/po/sv/ddns.po b/applications/luci-app-ddns/po/sv/ddns.po
index 780a2f9c8f..9373fea3a4 100644
--- a/applications/luci-app-ddns/po/sv/ddns.po
+++ b/applications/luci-app-ddns/po/sv/ddns.po
@@ -1,5 +1,5 @@
msgid ""
-msgstr "Content-Type: text/plain; charset=UTF-8"
+msgstr "Content-Type: text/plain; charset=UTF-8\n"
msgid "&"
msgstr "&"
@@ -237,8 +237,8 @@ msgid ""
"GNU Wget will use the IP of given network, cURL will use the physical "
"interface."
msgstr ""
-"GNU Wget kommer att använda IP-adressen för det angivna nätverket, cURL kommer att använda det fysiska "
-"gränssnittet."
+"GNU Wget kommer att använda IP-adressen för det angivna nätverket, cURL "
+"kommer att använda det fysiska gränssnittet."
msgid "Global Settings"
msgstr "Globala inställningar"
@@ -277,7 +277,8 @@ msgid "IPv6-Address"
msgstr "IPv6-adress"
msgid "If both cURL and GNU Wget are installed, Wget is used by default."
-msgstr "Om både cURL och GNU Wget är installerade så används Wget som standard."
+msgstr ""
+"Om både cURL och GNU Wget är installerade så används Wget som standard."
msgid ""
"If this service section is disabled it could not be started.<br />Neither "
@@ -319,7 +320,9 @@ msgid ""
msgstr ""
msgid "It is NOT recommended for casual users to change settings on this page."
-msgstr "Det är INTE rekommenderat för vanliga användare att ändra inställningar på den här sidan."
+msgstr ""
+"Det är INTE rekommenderat för vanliga användare att ändra inställningar på "
+"den här sidan."
msgid "Last Update"
msgstr "Senaste uppdateringen"
@@ -604,7 +607,9 @@ msgid "cURL without Proxy Support"
msgstr "cURL utan Proxy-stöd"
msgid "can not detect local IP. Please select a different Source combination"
-msgstr "kan inte upptäcka lokal IP-adress. Vänligen välj en annorlunda Käll-kombination"
+msgstr ""
+"kan inte upptäcka lokal IP-adress. Vänligen välj en annorlunda Käll-"
+"kombination"
msgid "can not resolve host:"
msgstr "kan inte avgöra värd:"
diff --git a/applications/luci-app-diag-core/po/sv/diag_core.po b/applications/luci-app-diag-core/po/sv/diag_core.po
index b5679655d0..c31433287f 100644
--- a/applications/luci-app-diag-core/po/sv/diag_core.po
+++ b/applications/luci-app-diag-core/po/sv/diag_core.po
@@ -29,5 +29,5 @@ msgid ""
"With this menu you can configure network diagnostics, such as network device "
"scans and ping tests."
msgstr ""
-"Med den här menyn så kan du ställa in nätverksdiagnostik så som igenomsökningar och "
-"ping-tester för nätverksenheten."
+"Med den här menyn så kan du ställa in nätverksdiagnostik så som "
+"igenomsökningar och ping-tester för nätverksenheten."
diff --git a/applications/luci-app-firewall/luasrc/model/cbi/firewall/custom.lua b/applications/luci-app-firewall/luasrc/model/cbi/firewall/custom.lua
index 2b3cee3283..21a1b2796d 100644
--- a/applications/luci-app-firewall/luasrc/model/cbi/firewall/custom.lua
+++ b/applications/luci-app-firewall/luasrc/model/cbi/firewall/custom.lua
@@ -5,7 +5,7 @@ local fs = require "nixio.fs"
local f = SimpleForm("firewall",
translate("Firewall - Custom Rules"),
- translate("Custom rules allow you to execute arbritary iptables commands \
+ translate("Custom rules allow you to execute arbitrary iptables commands \
which are not otherwise covered by the firewall framework. \
The commands are executed after each firewall restart, right after \
the default ruleset has been loaded."))
diff --git a/applications/luci-app-firewall/po/ca/firewall.po b/applications/luci-app-firewall/po/ca/firewall.po
index 913fb759e4..3abdc892d8 100644
--- a/applications/luci-app-firewall/po/ca/firewall.po
+++ b/applications/luci-app-firewall/po/ca/firewall.po
@@ -70,7 +70,7 @@ msgid "Custom Rules"
msgstr "Regles personalitzades"
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
diff --git a/applications/luci-app-firewall/po/cs/firewall.po b/applications/luci-app-firewall/po/cs/firewall.po
index 1ab1360f57..c796873ded 100644
--- a/applications/luci-app-firewall/po/cs/firewall.po
+++ b/applications/luci-app-firewall/po/cs/firewall.po
@@ -66,7 +66,7 @@ msgid "Custom Rules"
msgstr "Vlastní pravidla"
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
diff --git a/applications/luci-app-firewall/po/de/firewall.po b/applications/luci-app-firewall/po/de/firewall.po
index 448f951fa0..00e259ca70 100644
--- a/applications/luci-app-firewall/po/de/firewall.po
+++ b/applications/luci-app-firewall/po/de/firewall.po
@@ -68,7 +68,7 @@ msgid "Custom Rules"
msgstr "Benutzerdefinierte Regeln"
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
diff --git a/applications/luci-app-firewall/po/el/firewall.po b/applications/luci-app-firewall/po/el/firewall.po
index 2229bf09f6..6ebc2286ab 100644
--- a/applications/luci-app-firewall/po/el/firewall.po
+++ b/applications/luci-app-firewall/po/el/firewall.po
@@ -68,7 +68,7 @@ msgid "Custom Rules"
msgstr "ΠÏοσαÏμοσμένοι Κανόνες"
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
diff --git a/applications/luci-app-firewall/po/en/firewall.po b/applications/luci-app-firewall/po/en/firewall.po
index 9dc277dbed..f7658a5b0c 100644
--- a/applications/luci-app-firewall/po/en/firewall.po
+++ b/applications/luci-app-firewall/po/en/firewall.po
@@ -66,7 +66,7 @@ msgid "Custom Rules"
msgstr ""
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
diff --git a/applications/luci-app-firewall/po/es/firewall.po b/applications/luci-app-firewall/po/es/firewall.po
index 670b4db6f6..8550d0567a 100644
--- a/applications/luci-app-firewall/po/es/firewall.po
+++ b/applications/luci-app-firewall/po/es/firewall.po
@@ -69,7 +69,7 @@ msgid "Custom Rules"
msgstr "Reglas propias"
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
diff --git a/applications/luci-app-firewall/po/fr/firewall.po b/applications/luci-app-firewall/po/fr/firewall.po
index cdff282964..7be4d8f4f4 100644
--- a/applications/luci-app-firewall/po/fr/firewall.po
+++ b/applications/luci-app-firewall/po/fr/firewall.po
@@ -68,7 +68,7 @@ msgid "Custom Rules"
msgstr "Régles spécifiques"
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
diff --git a/applications/luci-app-firewall/po/he/firewall.po b/applications/luci-app-firewall/po/he/firewall.po
index ce0ad04050..e269e58cb2 100644
--- a/applications/luci-app-firewall/po/he/firewall.po
+++ b/applications/luci-app-firewall/po/he/firewall.po
@@ -63,7 +63,7 @@ msgid "Custom Rules"
msgstr ""
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
diff --git a/applications/luci-app-firewall/po/hu/firewall.po b/applications/luci-app-firewall/po/hu/firewall.po
index c201e3da88..2c3ae02f61 100644
--- a/applications/luci-app-firewall/po/hu/firewall.po
+++ b/applications/luci-app-firewall/po/hu/firewall.po
@@ -66,7 +66,7 @@ msgid "Custom Rules"
msgstr "Egyéni szabályok"
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
diff --git a/applications/luci-app-firewall/po/it/firewall.po b/applications/luci-app-firewall/po/it/firewall.po
index 88535243be..33e835183a 100644
--- a/applications/luci-app-firewall/po/it/firewall.po
+++ b/applications/luci-app-firewall/po/it/firewall.po
@@ -68,7 +68,7 @@ msgid "Custom Rules"
msgstr "Regole Personalizzate"
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
diff --git a/applications/luci-app-firewall/po/ja/firewall.po b/applications/luci-app-firewall/po/ja/firewall.po
index 0e8d71c6b3..eb4b06f29a 100644
--- a/applications/luci-app-firewall/po/ja/firewall.po
+++ b/applications/luci-app-firewall/po/ja/firewall.po
@@ -69,7 +69,7 @@ msgid "Custom Rules"
msgstr "手動設定ルール"
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
diff --git a/applications/luci-app-firewall/po/ko/firewall.po b/applications/luci-app-firewall/po/ko/firewall.po
index f43fdc8826..e5e0e871ee 100644
--- a/applications/luci-app-firewall/po/ko/firewall.po
+++ b/applications/luci-app-firewall/po/ko/firewall.po
@@ -68,7 +68,7 @@ msgid "Custom Rules"
msgstr "Custom Rule"
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
diff --git a/applications/luci-app-firewall/po/ms/firewall.po b/applications/luci-app-firewall/po/ms/firewall.po
index b82e2c116f..edc92514fb 100644
--- a/applications/luci-app-firewall/po/ms/firewall.po
+++ b/applications/luci-app-firewall/po/ms/firewall.po
@@ -62,7 +62,7 @@ msgid "Custom Rules"
msgstr ""
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
diff --git a/applications/luci-app-firewall/po/no/firewall.po b/applications/luci-app-firewall/po/no/firewall.po
index 59167db541..e26e36564d 100644
--- a/applications/luci-app-firewall/po/no/firewall.po
+++ b/applications/luci-app-firewall/po/no/firewall.po
@@ -63,7 +63,7 @@ msgid "Custom Rules"
msgstr "Egendefinerte Regler"
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
diff --git a/applications/luci-app-firewall/po/pl/firewall.po b/applications/luci-app-firewall/po/pl/firewall.po
index 2eea8c31f8..77e6a956a2 100644
--- a/applications/luci-app-firewall/po/pl/firewall.po
+++ b/applications/luci-app-firewall/po/pl/firewall.po
@@ -70,7 +70,7 @@ msgid "Custom Rules"
msgstr "Własne reguły"
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
diff --git a/applications/luci-app-firewall/po/pt-br/firewall.po b/applications/luci-app-firewall/po/pt-br/firewall.po
index ab714b50b9..1ee89cfbfb 100644
--- a/applications/luci-app-firewall/po/pt-br/firewall.po
+++ b/applications/luci-app-firewall/po/pt-br/firewall.po
@@ -68,7 +68,7 @@ msgid "Custom Rules"
msgstr "Regras Personalizadas"
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
diff --git a/applications/luci-app-firewall/po/pt/firewall.po b/applications/luci-app-firewall/po/pt/firewall.po
index f552616714..d803dfab10 100644
--- a/applications/luci-app-firewall/po/pt/firewall.po
+++ b/applications/luci-app-firewall/po/pt/firewall.po
@@ -68,7 +68,7 @@ msgid "Custom Rules"
msgstr "Regras Personalizadas"
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
diff --git a/applications/luci-app-firewall/po/ro/firewall.po b/applications/luci-app-firewall/po/ro/firewall.po
index 69b911e17f..e0027de417 100644
--- a/applications/luci-app-firewall/po/ro/firewall.po
+++ b/applications/luci-app-firewall/po/ro/firewall.po
@@ -67,7 +67,7 @@ msgid "Custom Rules"
msgstr "Reguli suplimentare"
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
diff --git a/applications/luci-app-firewall/po/ru/firewall.po b/applications/luci-app-firewall/po/ru/firewall.po
index 98bc92dd6b..be16fece88 100644
--- a/applications/luci-app-firewall/po/ru/firewall.po
+++ b/applications/luci-app-firewall/po/ru/firewall.po
@@ -70,7 +70,7 @@ msgid "Custom Rules"
msgstr "ПользовательÑкие правила"
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
diff --git a/applications/luci-app-firewall/po/sk/firewall.po b/applications/luci-app-firewall/po/sk/firewall.po
index f45e74b14f..1dda5bf53a 100644
--- a/applications/luci-app-firewall/po/sk/firewall.po
+++ b/applications/luci-app-firewall/po/sk/firewall.po
@@ -63,7 +63,7 @@ msgid "Custom Rules"
msgstr ""
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
diff --git a/applications/luci-app-firewall/po/sv/firewall.po b/applications/luci-app-firewall/po/sv/firewall.po
index 777c81787d..8e310c0f94 100644
--- a/applications/luci-app-firewall/po/sv/firewall.po
+++ b/applications/luci-app-firewall/po/sv/firewall.po
@@ -64,7 +64,7 @@ msgid "Custom Rules"
msgstr "Anpassade regler"
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
diff --git a/applications/luci-app-firewall/po/templates/firewall.pot b/applications/luci-app-firewall/po/templates/firewall.pot
index d1e8eeca16..bec02d4486 100644
--- a/applications/luci-app-firewall/po/templates/firewall.pot
+++ b/applications/luci-app-firewall/po/templates/firewall.pot
@@ -56,7 +56,7 @@ msgid "Custom Rules"
msgstr ""
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
diff --git a/applications/luci-app-firewall/po/tr/firewall.po b/applications/luci-app-firewall/po/tr/firewall.po
index 1b5444f0f4..5bb897cc28 100644
--- a/applications/luci-app-firewall/po/tr/firewall.po
+++ b/applications/luci-app-firewall/po/tr/firewall.po
@@ -63,7 +63,7 @@ msgid "Custom Rules"
msgstr ""
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
diff --git a/applications/luci-app-firewall/po/uk/firewall.po b/applications/luci-app-firewall/po/uk/firewall.po
index 1c4117f3f0..8ca1428e71 100644
--- a/applications/luci-app-firewall/po/uk/firewall.po
+++ b/applications/luci-app-firewall/po/uk/firewall.po
@@ -67,7 +67,7 @@ msgid "Custom Rules"
msgstr "ÐаÑтроювані правила"
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
diff --git a/applications/luci-app-firewall/po/vi/firewall.po b/applications/luci-app-firewall/po/vi/firewall.po
index 6c00a6f298..9509613f23 100644
--- a/applications/luci-app-firewall/po/vi/firewall.po
+++ b/applications/luci-app-firewall/po/vi/firewall.po
@@ -68,7 +68,7 @@ msgid "Custom Rules"
msgstr ""
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
diff --git a/applications/luci-app-firewall/po/zh-cn/firewall.po b/applications/luci-app-firewall/po/zh-cn/firewall.po
index d36eeeaa6d..f2faab8809 100644
--- a/applications/luci-app-firewall/po/zh-cn/firewall.po
+++ b/applications/luci-app-firewall/po/zh-cn/firewall.po
@@ -1,17 +1,7 @@
msgid ""
msgstr ""
-"Project-Id-Version: PACKAGE VERSION\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-03-30 17:00+0200\n"
-"PO-Revision-Date: 2014-06-14 18:05+0200\n"
-"Last-Translator: jame-he <755085131@qq.com>\n"
-"Language-Team: QQ Group 75543259 <axishero@foxmail.com>\n"
-"Language: zh_CN\n"
-"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Pootle 2.0.6\n"
+"Last-Translator: Hing-wang Liao <kuoruan@gmail.com>\n"
msgid "%s in %s"
msgstr "%s ä½äºŽ %s"
@@ -23,22 +13,22 @@ msgid "%s, %s in %s"
msgstr "%s, %s ä½äºŽ %s"
msgid "(Unnamed Entry)"
-msgstr "(未命åæ¡ç›®)"
+msgstr "(未命åæ¡ç›®ï¼‰"
msgid "(Unnamed Rule)"
-msgstr "(未命å规则)"
+msgstr "(未命å规则)"
msgid "(Unnamed SNAT)"
-msgstr "(未命åSNAT)"
+msgstr "(未命å SNAT)"
msgid "<var>%d</var> pkts. per <var>%s</var>"
-msgstr "<var>%d</var> 包.æ¯ <var>%s</var>"
+msgstr "<var>%d</var> æ•°æ®åŒ…ã€‚æ¯ <var>%s</var>"
msgid "<var>%d</var> pkts. per <var>%s</var>, burst <var>%d</var> pkts."
-msgstr "<var>%d</var> 包. æ¯ <var>%s</var>, çªå‘ <var>%d</var> 包."
+msgstr "<var>%d</var> æ•°æ®åŒ…ã€‚æ¯ <var>%s</var>,çªå‘ <var>%d</var> æ•°æ®åŒ…。"
msgid "<var>%s</var> and limit to %s"
-msgstr "<var>%s</var> 并且é™åˆ¶åˆ° %s"
+msgstr "<var>%s</var> 并é™åˆ¶åˆ° %s"
msgid "Action"
msgstr "动作"
@@ -53,10 +43,10 @@ msgid "Advanced Settings"
msgstr "高级设置"
msgid "Allow forward from <em>source zones</em>:"
-msgstr "å…许从<em>æºåŒºåŸŸ</em>转å‘"
+msgstr "å…许从<em>æºåŒºåŸŸ</em>转å‘:"
msgid "Allow forward to <em>destination zones</em>:"
-msgstr "å…许转å‘到<em>目标区域</em>"
+msgstr "å…许转å‘到<em>目标区域</em>:"
msgid "Any"
msgstr "任何"
@@ -68,15 +58,15 @@ msgid "Custom Rules"
msgstr "自定义规则"
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
-"自定义规则å…许è¿è¡Œä¸€äº›é˜²ç«å¢™æ²¡æœ‰åŒ…å«çš„功能。这些命令将在æ¯æ¬¡é‡å¯é˜²ç«å¢™æ—¶ï¼Œåœ¨"
-"默认的规则è¿è¡ŒåŽç«‹å³æ‰§è¡Œã€‚"
+"自定义规则å…许你执行ä¸å±žäºŽé˜²ç«å¢™æ¡†æž¶çš„ä»»æ„ iptables 命令。æ¯æ¬¡é‡å¯é˜²ç«å¢™æ—¶ï¼Œ"
+"在默认的规则è¿è¡ŒåŽè¿™äº›å‘½ä»¤å°†ç«‹å³æ‰§è¡Œã€‚"
msgid "Destination IP address"
-msgstr "目标IP地å€"
+msgstr "目标 IP 地å€"
msgid "Destination address"
msgstr "目标地å€"
@@ -88,7 +78,7 @@ msgid "Destination zone"
msgstr "目标区域"
msgid "Do not rewrite"
-msgstr "ä¸å¡«å†™=(所有端å£ï¼‰"
+msgstr "ä¸é‡å†™"
msgid "Drop invalid packets"
msgstr "丢弃无效数æ®åŒ…"
@@ -97,16 +87,16 @@ msgid "Enable"
msgstr "å¯ç”¨"
msgid "Enable NAT Loopback"
-msgstr "å¯ç”¨NAT环回"
+msgstr "å¯ç”¨ NAT 环回"
msgid "Enable SYN-flood protection"
-msgstr "å¯ç”¨SYN-flood防御"
+msgstr "å¯ç”¨ SYN-flood 防御"
msgid "Enable logging on this zone"
-msgstr "在此区域å…许进入"
+msgstr "å¯ç”¨æ­¤åŒºåŸŸçš„日志记录"
msgid "External IP address"
-msgstr "外部IP地å€"
+msgstr "外部 IP 地å€"
msgid "External port"
msgstr "外部端å£"
@@ -130,7 +120,7 @@ msgid "Firewall - Traffic Rules"
msgstr "防ç«å¢™ - 通信规则"
msgid "Firewall - Zone Settings"
-msgstr "防ç«å¢™-区域设置"
+msgstr "防ç«å¢™ - 区域设置"
msgid "Force connection tracking"
msgstr "强制连接追踪"
@@ -142,16 +132,16 @@ msgid "Forward to"
msgstr "转å‘到"
msgid "Friday"
-msgstr ""
+msgstr "星期五"
msgid "From %s in %s"
msgstr "æ¥è‡ª %s ä½äºŽ %s"
msgid "From %s in %s with source %s"
-msgstr "æ¥è‡ª %s ä½äºŽ %s å¸¦æº %s"
+msgstr "æ¥è‡ª %s ä½äºŽ %s æºäºŽ %s"
msgid "From %s in %s with source %s and %s"
-msgstr "æ¥è‡ª %s ä½äºŽ %s å¸¦æº %s 并且 %s"
+msgstr "æ¥è‡ª %s ä½äºŽ %s æºç«¯å£ %s æº MAC %s"
msgid "General Settings"
msgstr "基本设置"
@@ -163,13 +153,13 @@ msgid "IPv4 and IPv6"
msgstr "IPv4 和 IPv6"
msgid "IPv4 only"
-msgstr "ä»…IPv4"
+msgstr "ä»… IPv4"
msgid "IPv6"
msgstr "IPv6"
msgid "IPv6 only"
-msgstr "ä»…IPv6"
+msgstr "ä»… IPv6"
msgid "Input"
msgstr "入站数æ®"
@@ -178,7 +168,7 @@ msgid "Inter-Zone Forwarding"
msgstr "端å£è§¦å‘"
msgid "Internal IP address"
-msgstr "内部IP地å€"
+msgstr "内部 IP 地å€"
msgid "Internal port"
msgstr "内部端å£"
@@ -190,41 +180,41 @@ msgid "Limit log messages"
msgstr "é™åˆ¶æ—¥å¿—ä¿¡æ¯"
msgid "MSS clamping"
-msgstr "MSS钳制"
+msgstr "MSS 钳制"
msgid "Masquerading"
-msgstr "IP动æ€ä¼ªè£…"
+msgstr "IP 动æ€ä¼ªè£…"
msgid "Match"
msgstr "匹é…规则"
msgid "Match ICMP type"
-msgstr "匹é…ICMP类型"
+msgstr "åŒ¹é… ICMP 类型"
msgid "Match forwarded traffic to the given destination port or port range."
-msgstr "需è¦åŒ¹é…转å‘æµé‡åˆ°çš„目标端å£æˆ–端å£èŒƒå›´"
+msgstr "匹é…指定目标端å£æˆ–目标端å£èŒƒå›´çš„转å‘æµé‡ã€‚"
msgid ""
"Match incoming traffic directed at the given destination port or port range "
"on this host"
-msgstr "需è¦åŒ¹é…入站æµé‡åˆ°çš„目标端å£æˆ–端å£èŒƒå›´"
+msgstr "匹é…指å‘此主机上指定目标端å£æˆ–目标端å£èŒƒå›´çš„入站æµé‡ã€‚"
msgid ""
"Match incoming traffic originating from the given source port or port range "
"on the client host."
-msgstr "需è¦åŒ¹é…入站æµé‡çš„æºç«¯å£æˆ–端å£èŒƒå›´"
+msgstr "匹é…æ¥è‡ªå®¢æˆ·ç«¯ä¸»æœºä¸ŠæŒ‡å®šæºç«¯å£æˆ–æºç«¯å£èŒƒå›´çš„入站æµé‡ã€‚"
msgid "Monday"
-msgstr ""
+msgstr "星期一"
msgid "Month Days"
-msgstr ""
+msgstr "日期"
msgid "Name"
msgstr "åå­—"
msgid "New SNAT rule"
-msgstr "新建SNAT规则"
+msgstr "新建 SNAT 规则"
msgid "New forward rule"
msgstr "新建转å‘规则"
@@ -236,21 +226,21 @@ msgid "New port forward"
msgstr "新建端å£è½¬å‘"
msgid "New source NAT"
-msgstr "新建Source NAT"
+msgstr "新建 Source NAT"
msgid "Only match incoming traffic directed at the given IP address."
-msgstr "需è¦åŒ¹é…入站æµé‡çš„æºIP"
+msgstr "仅匹é…指定目的 IP 地å€çš„入站æµé‡ã€‚"
msgid "Only match incoming traffic from these MACs."
-msgstr "需è¦åŒ¹é…入站æµé‡çš„æºMACs(å¯ä»¥ä¸ºå¤šä¸ªï¼‰"
+msgstr "仅匹é…æ¥è‡ªè¿™äº› MAC 的入站æµé‡ã€‚"
msgid "Only match incoming traffic from this IP or range."
-msgstr "需è¦åŒ¹é…入站æµé‡çš„æºIP或IP范围"
+msgstr "仅匹é…æ¥è‡ªæ­¤ IP 或 IP 范围的入站æµé‡ã€‚"
msgid ""
"Only match incoming traffic originating from the given source port or port "
"range on the client host"
-msgstr "需è¦åŒ¹é…入站æµé‡çš„æºç«¯å£æˆ–端å£èŒƒå›´"
+msgstr "仅匹é…æºè‡ªå®¢æˆ·ç«¯ä¸»æœºä¸Šç»™å®šæºç«¯å£æˆ–æºç«¯å£èŒƒå›´çš„入站æµé‡ã€‚"
msgid "Open ports on router"
msgstr "打开路由器端å£"
@@ -262,7 +252,7 @@ msgid "Output"
msgstr "出站数æ®"
msgid "Passes additional arguments to iptables. Use with care!"
-msgstr "传递到iptablesçš„é¢å¤–å‚数。å°å¿ƒä½¿ç”¨ï¼"
+msgstr "传递到 iptables çš„é¢å¤–å‚数。å°å¿ƒä½¿ç”¨ï¼"
msgid "Port Forwards"
msgstr "端å£è½¬å‘"
@@ -270,7 +260,8 @@ msgstr "端å£è½¬å‘"
msgid ""
"Port forwarding allows remote computers on the Internet to connect to a "
"specific computer or service within the private LAN."
-msgstr "端å£è½¬å‘å…许æ¥è‡ªInternet的计算机访问ç§æœ‰å±€åŸŸç½‘内的计算机或æœåŠ¡"
+msgstr ""
+"端å£è½¬å‘å…许 Internet 上的远程计算机连接到内部网络中的特定计算机或æœåŠ¡ã€‚"
msgid "Protocol"
msgstr "åè®®"
@@ -280,27 +271,27 @@ msgid ""
msgstr "é‡å®šå‘匹é…的入站æµé‡åˆ°å†…部主机的端å£"
msgid "Redirect matched incoming traffic to the specified internal host"
-msgstr "é‡å®šå‘匹é…的入站æµé‡åˆ°çš„内部主机"
+msgstr "é‡å®šå‘匹é…的入站æµé‡åˆ°æŒ‡å®šçš„内部主机"
msgid "Restart Firewall"
-msgstr ""
+msgstr "é‡å¯é˜²ç«å¢™"
msgid "Restrict Masquerading to given destination subnets"
-msgstr "è¦é™åˆ¶IP动æ€ä¼ªè£…的目标å­ç½‘"
+msgstr "è¦é™åˆ¶ IP 动æ€ä¼ªè£…的目标å­ç½‘"
msgid "Restrict Masquerading to given source subnets"
-msgstr "è¦é™åˆ¶IP动æ€ä¼ªè£…çš„æºå­ç½‘"
+msgstr "è¦é™åˆ¶ IP 动æ€ä¼ªè£…çš„æºå­ç½‘"
msgid "Restrict to address family"
msgstr "é™åˆ¶åœ°å€"
msgid "Rewrite matched traffic to the given address."
-msgstr "将匹é…æµé‡çš„æºåœ°å€æ”¹å†™æˆæŒ‡å®šåœ°å€"
+msgstr "将匹é…æµé‡çš„æºåœ°å€æ”¹å†™æˆæŒ‡å®šåœ°å€ã€‚"
msgid ""
"Rewrite matched traffic to the given source port. May be left empty to only "
"rewrite the IP address."
-msgstr "将匹é…æµé‡çš„æºç«¯å£æ”¹å†™æˆæŒ‡å®šç«¯å£ã€‚也å¯ä»¥ç•™ç©ºï¼Œåªæ”¹å†™IP地å€ã€‚"
+msgstr "将匹é…æµé‡çš„æºç«¯å£æ”¹å†™æˆæŒ‡å®šç«¯å£ã€‚留空åªæ”¹å†™ IP 地å€ã€‚"
msgid "Rewrite to source %s"
msgstr "æºåœ°å€æ”¹å†™æˆ %s"
@@ -309,49 +300,19 @@ msgid "Rewrite to source %s, %s"
msgstr "æºåœ°å€æ”¹å†™æˆ %s, %s"
msgid "SNAT IP address"
-msgstr "SNAT IP地å€"
+msgstr "SNAT IP 地å€"
msgid "SNAT port"
msgstr "SNAT 端å£"
msgid "Saturday"
-msgstr ""
+msgstr "星期六"
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-# Generated from applications/luci-fw/luasrc/model/cbi/luci_fw/rrule.lua #
-# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
-#
-# msgid "Traffic Redirection"
-# msgstr ""
-#
-# msgid ""
-# "Traffic redirection allows you to change the destination address of "
-# "forwarded packets."
-# msgstr ""
-#
-# msgid "Overview"
-# msgstr ""
-#
-# msgid "Name"
-# msgstr ""
-#
-# msgid "Source zone"
-# msgstr ""
-#
-# msgid "Source MAC-address"
-# msgstr ""
-#
-# msgid "Source port"
-# msgstr ""
-#
-# msgid "Protocol"
-# msgstr ""
-#
msgid "Source IP address"
-msgstr "æºIP地å€"
+msgstr "æº IP 地å€"
msgid "Source MAC address"
-msgstr "æºMAC地å€"
+msgstr "æº MAC 地å€"
msgid "Source NAT"
msgstr "Source NAT"
@@ -361,8 +322,8 @@ msgid ""
"control over the source IP used for outgoing traffic, for example to map "
"multiple WAN addresses to internal subnets."
msgstr ""
-"Source NAT是一ç§ç‰¹æ®Šå½¢å¼çš„å°åŒ…伪装,它å…许精细的控制传出æµé‡çš„æºIP,例如,将"
-"多个WAN地å€æ˜ å°„到内部å­ç½‘。"
+"Source NAT 是一ç§ç‰¹æ®Šå½¢å¼çš„å°åŒ…伪装,它å…许精细的控制传出æµé‡çš„æº IP,例如:"
+"将多个 WAN 地å€æ˜ å°„到内部å­ç½‘。"
msgid "Source address"
msgstr "æºåœ°å€"
@@ -374,24 +335,24 @@ msgid "Source zone"
msgstr "æºåŒºåŸŸ"
msgid "Start Date (yyyy-mm-dd)"
-msgstr ""
+msgstr "开始日期(yyyy-mm-dd)"
msgid "Start Time (hh:mm:ss)"
-msgstr ""
+msgstr "开始时间(hh:mm:ss)"
msgid "Stop Date (yyyy-mm-dd)"
-msgstr ""
+msgstr "åœæ­¢æ—¥æœŸï¼ˆyyyy-mm-dd)"
msgid "Stop Time (hh:mm:ss)"
-msgstr ""
+msgstr "åœæ­¢æ—¶é—´ï¼ˆhh:mm:ss)"
msgid "Sunday"
-msgstr ""
+msgstr "星期日"
msgid ""
"The firewall creates zones over your network interfaces to control network "
"traffic flow."
-msgstr "防ç«å¢™æŠŠç½‘络接å£åˆ†ä¸ºä¸åŒçš„区域进行管ç†"
+msgstr "防ç«å¢™é€šè¿‡åœ¨ç½‘络接å£ä¸Šåˆ›å»ºåŒºåŸŸæ¥æŽ§åˆ¶ç½‘络æµé‡ã€‚"
msgid ""
"The options below control the forwarding policies between this zone (%s) and "
@@ -401,10 +362,10 @@ msgid ""
"rule is <em>unidirectional</em>, e.g. a forward from lan to wan does "
"<em>not</em> imply a permission to forward from wan to lan as well."
msgstr ""
-"以下选项å¯ä»¥æŽ§åˆ¶åŒºåŸŸ(%s)和其它区域间的转å‘规则。 <em>目标区域</em>接收"
-"<strong>从%q</strong>转å‘çš„æµé‡ã€‚<em>æºåŒºåŸŸ</em>匹é…从<strong>目标为%q</"
-"strong>的区域的需转å‘æµé‡ã€‚以下规则<em>无法转å‘</em>,例如:转å‘lanæµé‡åˆ°wan,"
-"但是<em>ä¸å…许</em>从wan转å‘到lan。"
+"以下选项å¯ä»¥æŽ§åˆ¶åŒºåŸŸï¼ˆ%s)和其它区域间的转å‘规则。<em>目标区域</em>接收"
+"<strong>æºè‡ª %q</strong> 的转å‘æµé‡ã€‚<em>æºåŒºåŸŸ</em>匹é…从<strong>目标为 %q</"
+"strong> 的区域的需转å‘æµé‡ã€‚转å‘规则的作用是<em>å•å‘</em>的,例如:一æ¡å…许"
+"从 lan 到 wan 的转å‘规则并ä¸éšå«æœ‰å…许相åæ–¹å‘从 wan 到 lan çš„æµé‡è½¬å‘。"
msgid ""
"This page allows you to change advanced properties of the port forwarding "
@@ -416,7 +377,6 @@ msgid ""
"entry, such as matched source and destination hosts."
msgstr "本页é¢å¯ä»¥æ›´æ”¹é€šä¿¡è§„则的高级设置,比如:需匹é…çš„æºä¸»æœºå’Œç›®æ ‡ä¸»æœºã€‚"
-#, fuzzy
msgid ""
"This section defines common properties of %q. The <em>input</em> and "
"<em>output</em> options set the default policies for traffic entering and "
@@ -424,19 +384,18 @@ msgid ""
"forwarded traffic between different networks within the zone. <em>Covered "
"networks</em> specifies which available networks are members of this zone."
msgstr ""
-"本节定义 %q 的通用属性, <em>入站数æ®</em> å’Œ <em>出站数æ®</em>规则用于设置数"
-"æ®åŒ…“进â€å’Œâ€œå‡ºâ€è·¯ç”±å™¨ï¼ˆæŸä¸ªæŽ¥å£ï¼‰é»˜è®¤çš„转å‘原则,<em>转å‘</em>规则用于特定(一"
-"个或多个)区域的ä¸åŒå­ç½‘之间的数æ®åŒ…转å‘。<em>覆盖网络</em>选择从属于这个区域"
-"的网络。"
+"本节定义 %q 的通用属性, <em>入站数æ®</em>å’Œ<em>出站数æ®</em>选项用于设置此区"
+"域入站和出站æµé‡çš„默认策略,<em>转å‘</em>选项æ述该区域内ä¸åŒç½‘络之间的æµé‡è½¬"
+"å‘策略。<em>覆盖网络</em>指定从属于这个区域的网络。"
msgid "Thursday"
-msgstr ""
+msgstr "星期四"
msgid "Time in UTC"
-msgstr ""
+msgstr "UTC 时间"
msgid "To %s at %s on <var>this device</var>"
-msgstr "到 %s at %s ä½äºŽ<var>本设备</var>"
+msgstr "到 %s 在 %s ä½äºŽ<var>本设备</var>"
msgid "To %s in %s"
msgstr "到 %s ä½äºŽ %s"
@@ -448,7 +407,7 @@ msgid "To %s, %s in %s"
msgstr "到 %s, %s ä½äºŽ %s"
msgid "To source IP"
-msgstr "到æºIP"
+msgstr "åˆ°æº IP"
msgid "To source port"
msgstr "到æºç«¯å£"
@@ -461,23 +420,23 @@ msgid ""
"for example to reject traffic between certain hosts or to open WAN ports on "
"the router."
msgstr ""
-"通信规则定义了ä¸åŒåŒºåŸŸé—´çš„æµé‡ä¼ é€ï¼Œä¾‹å¦‚:拒ç»ä¸€äº›ä¸»æœºä¹‹é—´çš„通信ã€æ‰“开到WANçš„"
-"端å£ã€‚"
+"通信规则定义了ä¸åŒåŒºåŸŸé—´çš„æ•°æ®åŒ…传输策略,例如:拒ç»ä¸€äº›ä¸»æœºä¹‹é—´çš„通信,开放"
+"路由器 WAN 上的端å£ã€‚"
msgid "Tuesday"
-msgstr ""
+msgstr "星期二"
msgid "Via %s"
msgstr "通过 %s"
msgid "Via %s at %s"
-msgstr "通过 %s at %s"
+msgstr "通过 %s 在 %s"
msgid "Wednesday"
-msgstr ""
+msgstr "星期三"
msgid "Week Days"
-msgstr ""
+msgstr "星期"
msgid ""
"You may specify multiple by selecting \"-- custom --\" and then entering "
@@ -503,13 +462,13 @@ msgid "any host"
msgstr "所有主机"
msgid "any router IP"
-msgstr "所有路由地å€"
+msgstr "所有路由 IP"
msgid "any zone"
msgstr "所有区域"
msgid "don't track"
-msgstr "无动作"
+msgstr "ä¸è·Ÿè¸ª"
msgid "drop"
msgstr "丢弃"
@@ -518,4 +477,4 @@ msgid "reject"
msgstr "æ‹’ç»"
msgid "traffic"
-msgstr "交通"
+msgstr "通信"
diff --git a/applications/luci-app-firewall/po/zh-tw/firewall.po b/applications/luci-app-firewall/po/zh-tw/firewall.po
index b89cfab7fd..fff89cbcdf 100644
--- a/applications/luci-app-firewall/po/zh-tw/firewall.po
+++ b/applications/luci-app-firewall/po/zh-tw/firewall.po
@@ -66,11 +66,11 @@ msgid "Custom Rules"
msgstr "自訂的è¦å‰‡ç¾¤"
msgid ""
-"Custom rules allow you to execute arbritary iptables commands which are not "
+"Custom rules allow you to execute arbitrary iptables commands which are not "
"otherwise covered by the firewall framework. The commands are executed after "
"each firewall restart, right after the default ruleset has been loaded."
msgstr ""
-"自定義è¦å‰‡å…許你執行這是ä¸ä»¥å…¶ä»–æ–¹å¼æ¶‰åŠçš„防ç«ç‰†æ¡†æž¶arbritaryçš„iptables命令。"
+"自定義è¦å‰‡å…許你執行這是ä¸ä»¥å…¶ä»–æ–¹å¼æ¶‰åŠçš„防ç«ç‰†æ¡†æž¶arbitraryçš„iptables命令。"
"該命令是æ¯å€‹é˜²ç«ç‰†é‡å•Ÿå¾ŒåŸ·è¡Œï¼Œé»˜èªè¦å‰‡é›†å·²ç¶“加載之後。"
msgid "Destination IP address"
diff --git a/applications/luci-app-mwan3/luasrc/controller/mwan3.lua b/applications/luci-app-mwan3/luasrc/controller/mwan3.lua
index ca39c9bf30..c24beda281 100644
--- a/applications/luci-app-mwan3/luasrc/controller/mwan3.lua
+++ b/applications/luci-app-mwan3/luasrc/controller/mwan3.lua
@@ -29,6 +29,8 @@ function index()
entry({"admin", "network", "mwan", "configuration"},
alias("admin", "network", "mwan", "configuration", "interface"),
_("Configuration"), 20)
+ entry({"admin", "network", "mwan", "configuration", "globals"},
+ cbi("mwan/globalsconfig"),_("Globals"), 5).leaf = true
entry({"admin", "network", "mwan", "configuration", "interface"},
arcombine(cbi("mwan/interface"), cbi("mwan/interfaceconfig")),
_("Interfaces"), 10).leaf = true
diff --git a/applications/luci-app-mwan3/luasrc/model/cbi/mwan/globalsconfig.lua b/applications/luci-app-mwan3/luasrc/model/cbi/mwan/globalsconfig.lua
new file mode 100644
index 0000000000..54d20bdcb5
--- /dev/null
+++ b/applications/luci-app-mwan3/luasrc/model/cbi/mwan/globalsconfig.lua
@@ -0,0 +1,32 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2017 Florian Eckert <fe@dev.tdt.de>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+]]--
+
+local net = require "luci.model.network".init()
+
+m = Map("mwan3")
+
+s = m:section(NamedSection, "globals", "globals", translate("Globals mwan3 options"))
+n = s:option(ListValue, "local_source",
+ translate("Local source interface"),
+ translate("Use the IP address of this interface as source IP address for traffic initiated by the router itself"))
+n:value("none")
+n.default = "none"
+for _, net in ipairs(net:get_networks()) do
+ if net:name() ~= "loopback" then
+ n:value(net:name())
+ end
+end
+n.rmempty = false
+
+return m
diff --git a/applications/luci-app-mwan3/luasrc/model/cbi/mwan/interfaceconfig.lua b/applications/luci-app-mwan3/luasrc/model/cbi/mwan/interfaceconfig.lua
index 2b46376399..ab44ba6970 100644
--- a/applications/luci-app-mwan3/luasrc/model/cbi/mwan/interfaceconfig.lua
+++ b/applications/luci-app-mwan3/luasrc/model/cbi/mwan/interfaceconfig.lua
@@ -102,6 +102,12 @@ enabled = mwan_interface:option(ListValue, "enabled", translate("Enabled"))
enabled:value("1", translate("Yes"))
enabled:value("0", translate("No"))
+initial_state = mwan_interface:option(ListValue, "initial_state", translate("Initial state"),
+ translate("Expect interface state on up event"))
+ initial_state.default = "online"
+ initial_state:value("online", translate("Online"))
+ initial_state:value("offline", translate("Offline"))
+
family = mwan_interface:option(ListValue, "family", translate("Internet Protocol"))
family.default = "ipv4"
family:value("ipv4", translate("IPv4"))
@@ -183,6 +189,10 @@ failure = mwan_interface:option(Value, "failure_interval", translate("Failure in
failure:value("1800", translatef("%d minutes", 30))
failure:value("3600", translatef("%d hour", 1))
+keep_failure = mwan_interface:option(Flag, "keep_failure_interval", translate("Keep failure interval"),
+ translate("Keep ping failure interval during failure state"))
+ keep_failure.default = keep_failure.disabled
+
recovery = mwan_interface:option(Value, "recovery_interval", translate("Recovery interval"),
translate("Ping interval during failure recovering"))
recovery.default = "5"
diff --git a/applications/luci-app-mwan3/po/ja/mwan3.po b/applications/luci-app-mwan3/po/ja/mwan3.po
index 925912e3ce..89fa5ea02d 100644
--- a/applications/luci-app-mwan3/po/ja/mwan3.po
+++ b/applications/luci-app-mwan3/po/ja/mwan3.po
@@ -7,7 +7,7 @@ msgstr ""
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Generator: Poedit 2.0.2\n"
+"X-Generator: Poedit 2.0.3\n"
"Last-Translator: INAGAKI Hiroshi <musashino.open@gmail.com>\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"Language: ja\n"
@@ -47,7 +47,7 @@ msgid "Check routing table"
msgstr "ルーティング テーブルã®ãƒã‚§ãƒƒã‚¯"
msgid "Collecting data..."
-msgstr ""
+msgstr "データåŽé›†ä¸­ã§ã™..."
msgid "Configuration"
msgstr "設定"
@@ -77,7 +77,7 @@ msgid "Diagnostics"
msgstr "診断機能"
msgid "Disabled"
-msgstr ""
+msgstr "無効"
msgid ""
"Downed interface will be deemed up after this many successful ping tests"
@@ -89,11 +89,14 @@ msgid "Enabled"
msgstr "有効"
msgid "Error collecting troubleshooting information"
-msgstr ""
+msgstr "トラブルシューティング情報ã®åŽé›†ã‚¨ãƒ©ãƒ¼"
msgid "Errors"
msgstr "エラー"
+msgid "Expect interface state on up event"
+msgstr ""
+
msgid "Failure interval"
msgstr "障害検出 インターãƒãƒ«"
@@ -103,6 +106,12 @@ msgstr ""
msgid "Flush global firewall conntrack table on interface events"
msgstr ""
+msgid "Globals"
+msgstr ""
+
+msgid "Globals mwan3 options"
+msgstr ""
+
msgid "Hotplug Script"
msgstr "ホットプラグ スクリプト"
@@ -121,6 +130,9 @@ msgstr "IPv4"
msgid "IPv6"
msgstr "IPv6"
+msgid "Initial state"
+msgstr ""
+
msgid "Interface"
msgstr "インターフェース"
@@ -144,9 +156,15 @@ msgstr "インターフェース"
msgid "Internet Protocol"
msgstr "インターãƒãƒƒãƒˆ プロトコル"
-msgid "Last 50 MWAN systemlog entries. Newest entries sorted at the top :"
+msgid "Keep failure interval"
msgstr ""
+msgid "Keep ping failure interval during failure state"
+msgstr ""
+
+msgid "Last 50 MWAN systemlog entries. Newest entries sorted at the top :"
+msgstr "ç›´è¿‘ã® MWAN システムログ(50行)ã§ã™ã€‚一番上ãŒæœ€æ–°ã®è¡Œã§ã™:"
+
msgid "Last resort"
msgstr "最終手段"
@@ -156,6 +174,9 @@ msgstr "è² è·åˆ†æ•£"
msgid "Loading"
msgstr "読込中"
+msgid "Local source interface"
+msgstr ""
+
msgid "MWAN Config"
msgstr "MWAN 設定"
@@ -222,7 +243,7 @@ msgstr ""
"(例: \"1024:2048\")をã€ã‚¯ã‚ªãƒ¼ãƒ†ãƒ¼ã‚·ãƒ§ãƒ³ç„¡ã—ã§æŒ‡å®šã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚"
msgid "Member"
-msgstr ""
+msgstr "メンãƒãƒ¼"
msgid "Member used"
msgstr "使用ã•ã‚Œã‚‹ãƒ¡ãƒ³ãƒãƒ¼"
@@ -260,28 +281,31 @@ msgid "No"
msgstr "ã„ã„ãˆ"
msgid "No MWAN interfaces found"
-msgstr ""
+msgstr "MWAN インターフェースãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
msgid "No MWAN systemlog history found"
-msgstr ""
+msgstr "MWAN システムログã®å±¥æ­´ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
msgid "No detailed status information available"
-msgstr ""
+msgstr "詳細ステータス情報ã¯åˆ©ç”¨ã§ãã¾ã›ã‚“"
msgid "No diagnostic results returned"
-msgstr ""
+msgstr "診断çµæžœãŒã‚ã‚Šã¾ã›ã‚“"
msgid "No protocol specified"
-msgstr ""
+msgstr "プロトコルãŒè¨­å®šã•ã‚Œã¦ã„ã¾ã›ã‚“"
msgid "Offline"
+msgstr "オフライン"
+
+msgid "Online"
msgstr ""
msgid "Online (tracking active)"
-msgstr ""
+msgstr "オンライン(追跡実行中)"
msgid "Online (tracking off)"
-msgstr ""
+msgstr "オンライン(追跡オフ)"
msgid "Overview"
msgstr "概è¦"
@@ -332,7 +356,7 @@ msgstr ""
"ターフェースやメンãƒãƒ¼ã€ãƒ«ãƒ¼ãƒ«ã¨åŒã˜åå‰ã‚’使用ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。"
msgid "Policy"
-msgstr ""
+msgstr "ãƒãƒªã‚·ãƒ¼"
msgid "Policy assigned"
msgstr "アサイン済ã¿ãƒãƒªã‚·ãƒ¼"
@@ -353,7 +377,7 @@ msgid "Restore..."
msgstr "復元..."
msgid "Rule"
-msgstr ""
+msgstr "ルール"
msgid "Rules"
msgstr "ルール"
@@ -477,6 +501,11 @@ msgstr "トラブルシューティング"
msgid "Troubleshooting Data"
msgstr "トラブルシューティング データ"
+msgid ""
+"Use the IP address of this interface as source IP address for traffic "
+"initiated by the router itself"
+msgstr ""
+
msgid "View the contents of /etc/protocols for protocol descriptions"
msgstr "プロトコルã®èª¬æ˜Žã«ã¤ã„ã¦ã¯ã€ /etc/protocols ã®å†…容を確èªã—ã¦ãã ã•ã„。"
@@ -575,10 +604,10 @@ msgstr ""
"ã„ã¾ã›ã‚“ï¼ãƒ—ロトコルを指定ã—ç›´ã—ã¦ãã ã•ã„ï¼"
msgid "Waiting for MWAN to %s..."
-msgstr ""
+msgstr "MWAN ã® %s ã‚’å¾…ã£ã¦ã„ã¾ã™..."
msgid "Waiting for diagnostic results..."
-msgstr ""
+msgstr "診断çµæžœã‚’å¾…ã£ã¦ã„ã¾ã™..."
msgid "Weight"
msgstr "ウエイト"
@@ -614,13 +643,13 @@ msgid "never"
msgstr "never"
msgid "restart"
-msgstr ""
+msgstr "å†èµ·å‹•"
msgid "start"
-msgstr ""
+msgstr "èµ·å‹•"
msgid "stop"
-msgstr ""
+msgstr "åœæ­¢"
msgid "unreachable (reject)"
msgstr "unreachable (reject)"
diff --git a/applications/luci-app-mwan3/po/templates/mwan3.pot b/applications/luci-app-mwan3/po/templates/mwan3.pot
index 3d25e844ac..8694298728 100644
--- a/applications/luci-app-mwan3/po/templates/mwan3.pot
+++ b/applications/luci-app-mwan3/po/templates/mwan3.pot
@@ -79,6 +79,9 @@ msgstr ""
msgid "Errors"
msgstr ""
+msgid "Expect interface state on up event"
+msgstr ""
+
msgid "Failure interval"
msgstr ""
@@ -88,6 +91,12 @@ msgstr ""
msgid "Flush global firewall conntrack table on interface events"
msgstr ""
+msgid "Globals"
+msgstr ""
+
+msgid "Globals mwan3 options"
+msgstr ""
+
msgid "Hotplug Script"
msgstr ""
@@ -106,6 +115,9 @@ msgstr ""
msgid "IPv6"
msgstr ""
+msgid "Initial state"
+msgstr ""
+
msgid "Interface"
msgstr ""
@@ -127,6 +139,12 @@ msgstr ""
msgid "Internet Protocol"
msgstr ""
+msgid "Keep failure interval"
+msgstr ""
+
+msgid "Keep ping failure interval during failure state"
+msgstr ""
+
msgid "Last 50 MWAN systemlog entries. Newest entries sorted at the top :"
msgstr ""
@@ -139,6 +157,9 @@ msgstr ""
msgid "Loading"
msgstr ""
+msgid "Local source interface"
+msgstr ""
+
msgid "MWAN Config"
msgstr ""
@@ -245,6 +266,9 @@ msgstr ""
msgid "Offline"
msgstr ""
+msgid "Online"
+msgstr ""
+
msgid "Online (tracking active)"
msgstr ""
@@ -408,6 +432,11 @@ msgstr ""
msgid "Troubleshooting Data"
msgstr ""
+msgid ""
+"Use the IP address of this interface as source IP address for traffic "
+"initiated by the router itself"
+msgstr ""
+
msgid "View the contents of /etc/protocols for protocol descriptions"
msgstr ""
diff --git a/applications/luci-app-mwan3/po/zh-cn/mwan3.po b/applications/luci-app-mwan3/po/zh-cn/mwan3.po
index 1e0f34f088..3c505d8477 100644
--- a/applications/luci-app-mwan3/po/zh-cn/mwan3.po
+++ b/applications/luci-app-mwan3/po/zh-cn/mwan3.po
@@ -82,6 +82,9 @@ msgstr "收集故障排除信æ¯æ—¶å‡ºé”™"
msgid "Errors"
msgstr "错误"
+msgid "Expect interface state on up event"
+msgstr ""
+
msgid "Failure interval"
msgstr "故障检测间隔"
@@ -91,6 +94,12 @@ msgstr "刷新连接跟踪表"
msgid "Flush global firewall conntrack table on interface events"
msgstr "在接å£äº‹ä»¶è§¦å‘时刷新全局防ç«å¢™è¿žæŽ¥è·Ÿè¸ªè¡¨"
+msgid "Globals"
+msgstr ""
+
+msgid "Globals mwan3 options"
+msgstr ""
+
msgid "Hotplug Script"
msgstr "Hotplug 脚本"
@@ -109,6 +118,9 @@ msgstr "IPv4"
msgid "IPv6"
msgstr "IPv6"
+msgid "Initial state"
+msgstr ""
+
msgid "Interface"
msgstr "接å£"
@@ -130,6 +142,12 @@ msgstr "接å£"
msgid "Internet Protocol"
msgstr "互è”网åè®®"
+msgid "Keep failure interval"
+msgstr ""
+
+msgid "Keep ping failure interval during failure state"
+msgstr ""
+
msgid "Last 50 MWAN systemlog entries. Newest entries sorted at the top :"
msgstr "最近 50 æ¡ MWAN 系统日志,最新æ¡ç›®æŽ’在顶部:"
@@ -142,6 +160,9 @@ msgstr "è´Ÿè½½å‡è¡¡"
msgid "Loading"
msgstr "载入中"
+msgid "Local source interface"
+msgstr ""
+
msgid "MWAN Config"
msgstr "MWAN é…置文件"
@@ -260,6 +281,9 @@ msgstr "未指定åè®®"
msgid "Offline"
msgstr "离线"
+msgid "Online"
+msgstr ""
+
msgid "Online (tracking active)"
msgstr "在线(追踪å¯ç”¨ä¸­ï¼‰"
@@ -443,6 +467,11 @@ msgstr "故障排除"
msgid "Troubleshooting Data"
msgstr "故障排除数æ®"
+msgid ""
+"Use the IP address of this interface as source IP address for traffic "
+"initiated by the router itself"
+msgstr ""
+
msgid "View the contents of /etc/protocols for protocol descriptions"
msgstr "请查看 /etc/protocols 获å–å¯é€‰å议详情"
diff --git a/applications/luci-app-mwan3/root/etc/uci-defaults/60_luci-mwan3 b/applications/luci-app-mwan3/root/etc/uci-defaults/60_luci-mwan3
index ff9a229edd..509a694364 100755
--- a/applications/luci-app-mwan3/root/etc/uci-defaults/60_luci-mwan3
+++ b/applications/luci-app-mwan3/root/etc/uci-defaults/60_luci-mwan3
@@ -8,6 +8,13 @@ uci -q batch <<-EOF >/dev/null
commit ucitrack
EOF
+uci -q get mwan3.globals >/dev/null || {
+ uci -q add mwan3 globals >/dev/null
+ uci -q rename mwan3.@globals[-1]="globals" >/dev/null
+ uci -q set mwan3.globals.initial_source="none" >/dev/null
+ uci commit mwan3
+}
+
# remove LuCI cache
rm -rf /tmp/luci-indexcache /tmp/luci-modulecache
diff --git a/applications/luci-app-nlbwmon/Makefile b/applications/luci-app-nlbwmon/Makefile
new file mode 100644
index 0000000000..a00177f2ca
--- /dev/null
+++ b/applications/luci-app-nlbwmon/Makefile
@@ -0,0 +1,8 @@
+include $(TOPDIR)/rules.mk
+
+LUCI_TITLE:=Netlink based bandwidth accounting
+LUCI_DEPENDS:=+nlbwmon
+
+include ../../luci.mk
+
+# call BuildPackage - OpenWrt buildroot signature
diff --git a/applications/luci-app-nlbwmon/htdocs/luci-static/resources/nlbw.chart.min.js b/applications/luci-app-nlbwmon/htdocs/luci-static/resources/nlbw.chart.min.js
new file mode 100644
index 0000000000..34e3026825
--- /dev/null
+++ b/applications/luci-app-nlbwmon/htdocs/luci-static/resources/nlbw.chart.min.js
@@ -0,0 +1,68 @@
+(function(){var p=this,l=p.Chart,e=function(a){this.canvas=a.canvas;this.ctx=a;var b=function(a,b){return a["offset"+b]?a["offset"+b]:document.defaultView.getComputedStyle(a).getPropertyValue(b)};this.width=b(a.canvas,"Width")||a.canvas.width;this.height=b(a.canvas,"Height")||a.canvas.height;this.width=a.canvas.width;this.height=a.canvas.height;this.aspectRatio=this.width/this.height;d.retinaScale(this);return this};e.defaults={global:{animation:!0,animationSteps:60,animationEasing:"easeOutQuart",
+showScale:!0,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null,scaleStartValue:null,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleIntegersOnly:!0,scaleBeginAtZero:!1,scaleFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",responsive:!1,maintainAspectRatio:!0,showTooltips:!0,customTooltips:!1,tooltipEvents:["mousemove","touchstart","touchmove","mouseout"],tooltipFillColor:"rgba(0,0,0,0.8)",
+tooltipFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",tooltipFontSize:14,tooltipFontStyle:"normal",tooltipFontColor:"#fff",tooltipTitleFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",tooltipTitleFontSize:14,tooltipTitleFontStyle:"bold",tooltipTitleFontColor:"#fff",tooltipTitleTemplate:"<%= label%>",tooltipYPadding:6,tooltipXPadding:6,tooltipCaretSize:8,tooltipCornerRadius:6,tooltipXOffset:10,tooltipTemplate:"<%if (label){%><%=label%>: <%}%><%= value %>",multiTooltipTemplate:"<%= value %>",
+multiTooltipKeyBackground:"#fff",segmentColorDefault:"#A6CEE3 #1F78B4 #B2DF8A #33A02C #FB9A99 #E31A1C #FDBF6F #FF7F00 #CAB2D6 #6A3D9A #B4B482 #B15928".split(" "),segmentHighlightColorDefaults:"#CEF6FF #47A0DC #DAFFB2 #5BC854 #FFC2C1 #FF4244 #FFE797 #FFA728 #F2DAFE #9265C2 #DCDCAA #D98150".split(" "),onAnimationProgress:function(){},onAnimationComplete:function(){}}};e.types={};var d=e.helpers={},k=d.each=function(a,b,c){var f=Array.prototype.slice.call(arguments,3);if(a)if(a.length===+a.length){var d;
+for(d=0;d<a.length;d++)b.apply(c,[a[d],d].concat(f))}else for(d in a)b.apply(c,[a[d],d].concat(f))},h=d.clone=function(a){var b={};k(a,function(c,f){a.hasOwnProperty(f)&&(b[f]=c)});return b},r=d.extend=function(a){k(Array.prototype.slice.call(arguments,1),function(b){k(b,function(c,f){b.hasOwnProperty(f)&&(a[f]=c)})});return a},I=d.merge=function(a,b){var c=Array.prototype.slice.call(arguments,0);c.unshift({});return r.apply(null,c)},J=d.indexOf=function(a,b){if(Array.prototype.indexOf)return a.indexOf(b);
+for(var c=0;c<a.length;c++)if(a[c]===b)return c;return-1};d.where=function(a,b){var c=[];d.each(a,function(a){b(a)&&c.push(a)});return c};d.findNextWhere=function(a,b,c){c||(c=-1);for(c+=1;c<a.length;c++){var f=a[c];if(b(f))return f}};d.findPreviousWhere=function(a,b,c){c||(c=a.length);for(--c;0<=c;c--){var f=a[c];if(b(f))return f}};var D=d.inherits=function(a){var b=this,c=a&&a.hasOwnProperty("constructor")?a.constructor:function(){return b.apply(this,arguments)},f=function(){this.constructor=c};
+f.prototype=b.prototype;c.prototype=new f;c.extend=D;a&&r(c.prototype,a);c.__super__=b.prototype;return c},A=d.noop=function(){},K=d.uid=function(){var a=0;return function(){return"chart-"+a++}}(),L=d.warn=function(a){window.console&&"function"===typeof window.console.warn&&console.warn(a)},M=d.amd="function"===typeof define&&define.amd,u=d.isNumber=function(a){return!isNaN(parseFloat(a))&&isFinite(a)},y=d.max=function(a){return Math.max.apply(Math,a)},w=d.min=function(a){return Math.min.apply(Math,
+a)};d.cap=function(a,b,c){if(u(b)){if(a>b)return b}else if(u(c)&&a<c)return c;return a};var E=d.getDecimalPlaces=function(a){if(0!==a%1&&u(a)){a=a.toString();if(0>a.indexOf("e-"))return a.split(".")[1].length;if(0>a.indexOf("."))return parseInt(a.split("e-")[1]);a=a.split(".")[1].split("e-");return a[0].length+parseInt(a[1])}return 0},B=d.radians=function(a){return Math.PI/180*a};d.getAngleFromPoint=function(a,b){var c=b.x-a.x,f=b.y-a.y,d=Math.sqrt(c*c+f*f),m=2*Math.PI+Math.atan2(f,c);0>c&&0>f&&(m+=
+2*Math.PI);return{angle:m,distance:d}};var F=d.aliasPixel=function(a){return 0===a%2?0:.5};d.splineCurve=function(a,b,c,f){var d=Math.sqrt(Math.pow(b.x-a.x,2)+Math.pow(b.y-a.y,2)),m=Math.sqrt(Math.pow(c.x-b.x,2)+Math.pow(c.y-b.y,2)),g=f*d/(d+m);f=f*m/(d+m);return{inner:{x:b.x-g*(c.x-a.x),y:b.y-g*(c.y-a.y)},outer:{x:b.x+f*(c.x-a.x),y:b.y+f*(c.y-a.y)}}};var N=d.calculateOrderOfMagnitude=function(a){return Math.floor(Math.log(a)/Math.LN10)};d.calculateScaleRange=function(a,b,c,f,d){b=Math.floor(b/(1.5*
+c));c=2>=b;var m=[];k(a,function(a){null==a||m.push(a)});var g=w(m),e=y(m);e===g&&(e+=.5,.5<=g&&!f?g-=.5:e+=.5);a=N(Math.abs(e-g));f=f?0:Math.floor(g/(1*Math.pow(10,a)))*Math.pow(10,a);for(var e=Math.ceil(e/(1*Math.pow(10,a)))*Math.pow(10,a)-f,g=Math.pow(10,a),n=Math.round(e/g);(n>b||2*n<b)&&!c;)if(n>b)g*=2,n=Math.round(e/g),0!==n%1&&(c=!0);else if(d&&0<=a)if(0===g/2%1)g/=2,n=Math.round(e/g);else break;else g/=2,n=Math.round(e/g);c&&(n=2,g=e/n);return{steps:n,stepValue:g,min:f,max:f+n*g}};var t=d.template=
+function(a,b){if(a instanceof Function)return a(b);var c={},c=/\W/.test(a)?new Function("obj","var p=[],print=function(){p.push.apply(p,arguments);};with(obj){p.push('"+a.replace(/[\r\t\n]/g," ").split("<%").join("\t").replace(/((^|%>)[^\t]*)'/g,"$1\r").replace(/\t=(.*?)%>/g,"',$1,'").split("\t").join("');").split("%>").join("p.push('").split("\r").join("\\'")+"');}return p.join('');"):c[a]=c[a];return b?c(b):c};d.generateLabels=function(a,b,c,f){var d=Array(b);a&&k(d,function(b,e){d[e]=t(a,{value:c+
+f*(e+1)})});return d};var x=d.easingEffects={linear:function(a){return a},easeInQuad:function(a){return a*a},easeOutQuad:function(a){return-1*a*(a-2)},easeInOutQuad:function(a){return 1>(a/=.5)?.5*a*a:-.5*(--a*(a-2)-1)},easeInCubic:function(a){return a*a*a},easeOutCubic:function(a){return 1*((a=a/1-1)*a*a+1)},easeInOutCubic:function(a){return 1>(a/=.5)?.5*a*a*a:.5*((a-=2)*a*a+2)},easeInQuart:function(a){return a*a*a*a},easeOutQuart:function(a){return-1*((a=a/1-1)*a*a*a-1)},easeInOutQuart:function(a){return 1>
+(a/=.5)?.5*a*a*a*a:-.5*((a-=2)*a*a*a-2)},easeInQuint:function(a){return 1*(a/=1)*a*a*a*a},easeOutQuint:function(a){return 1*((a=a/1-1)*a*a*a*a+1)},easeInOutQuint:function(a){return 1>(a/=.5)?.5*a*a*a*a*a:.5*((a-=2)*a*a*a*a+2)},easeInSine:function(a){return-1*Math.cos(a/1*(Math.PI/2))+1},easeOutSine:function(a){return 1*Math.sin(a/1*(Math.PI/2))},easeInOutSine:function(a){return-.5*(Math.cos(Math.PI*a/1)-1)},easeInExpo:function(a){return 0===a?1:1*Math.pow(2,10*(a/1-1))},easeOutExpo:function(a){return 1===
+a?1:1*(-Math.pow(2,-10*a/1)+1)},easeInOutExpo:function(a){return 0===a?0:1===a?1:1>(a/=.5)?.5*Math.pow(2,10*(a-1)):.5*(-Math.pow(2,-10*--a)+2)},easeInCirc:function(a){return 1<=a?a:-1*(Math.sqrt(1-(a/=1)*a)-1)},easeOutCirc:function(a){return 1*Math.sqrt(1-(a=a/1-1)*a)},easeInOutCirc:function(a){return 1>(a/=.5)?-.5*(Math.sqrt(1-a*a)-1):.5*(Math.sqrt(1-(a-=2)*a)+1)},easeInElastic:function(a){var b=1.70158,c=0,f=1;if(0===a)return 0;if(1==(a/=1))return 1;c||(c=.3);f<Math.abs(1)?(f=1,b=c/4):b=c/(2*Math.PI)*
+Math.asin(1/f);return-(f*Math.pow(2,10*--a)*Math.sin(2*(1*a-b)*Math.PI/c))},easeOutElastic:function(a){var b=1.70158,c=0,f=1;if(0===a)return 0;if(1==(a/=1))return 1;c||(c=.3);f<Math.abs(1)?(f=1,b=c/4):b=c/(2*Math.PI)*Math.asin(1/f);return f*Math.pow(2,-10*a)*Math.sin(2*(1*a-b)*Math.PI/c)+1},easeInOutElastic:function(a){var b=1.70158,c=0,f=1;if(0===a)return 0;if(2==(a/=.5))return 1;c||(c=.3*1.5);f<Math.abs(1)?(f=1,b=c/4):b=c/(2*Math.PI)*Math.asin(1/f);return 1>a?-.5*f*Math.pow(2,10*--a)*Math.sin(2*
+(1*a-b)*Math.PI/c):f*Math.pow(2,-10*--a)*Math.sin(2*(1*a-b)*Math.PI/c)*.5+1},easeInBack:function(a){return 1*(a/=1)*a*(2.70158*a-1.70158)},easeOutBack:function(a){return 1*((a=a/1-1)*a*(2.70158*a+1.70158)+1)},easeInOutBack:function(a){var b=1.70158;return 1>(a/=.5)?.5*a*a*(((b*=1.525)+1)*a-b):.5*((a-=2)*a*(((b*=1.525)+1)*a+b)+2)},easeInBounce:function(a){return 1-x.easeOutBounce(1-a)},easeOutBounce:function(a){return(a/=1)<1/2.75?7.5625*a*a:a<2/2.75?1*(7.5625*(a-=1.5/2.75)*a+.75):a<2.5/2.75?1*(7.5625*
+(a-=2.25/2.75)*a+.9375):1*(7.5625*(a-=2.625/2.75)*a+.984375)},easeInOutBounce:function(a){return.5>a?.5*x.easeInBounce(2*a):.5*x.easeOutBounce(2*a-1)+.5}},G=d.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){return window.setTimeout(a,1E3/60)}}();d.cancelAnimFrame=function(){return window.cancelAnimationFrame||window.webkitCancelAnimationFrame||
+window.mozCancelAnimationFrame||window.oCancelAnimationFrame||window.msCancelAnimationFrame||function(a){return window.clearTimeout(a,1E3/60)}}();d.animationLoop=function(a,b,c,f,d,e){var g=0,k=x[c]||x.linear,n=function(){g++;var c=g/b,h=k(c);a.call(e,h,c,g);f.call(e,h,c);g<b?e.animationFrame=G(n):d.apply(e)};G(n)};d.getRelativePosition=function(a){var b;b=a.originalEvent||a;var c=(a.currentTarget||a.srcElement).getBoundingClientRect();b.touches?(a=b.touches[0].clientX-c.left,b=b.touches[0].clientY-
+c.top):(a=b.clientX-c.left,b=b.clientY-c.top);return{x:a,y:b}};var O=d.addEvent=function(a,b,c){a.addEventListener?a.addEventListener(b,c):a.attachEvent?a.attachEvent("on"+b,c):a["on"+b]=c},P=d.removeEvent=function(a,b,c){a.removeEventListener?a.removeEventListener(b,c,!1):a.detachEvent?a.detachEvent("on"+b,c):a["on"+b]=A};d.bindEvents=function(a,b,c){a.events||(a.events={});k(b,function(b){a.events[b]=function(){c.apply(a,arguments)};O(a.chart.canvas,b,a.events[b])})};var Q=d.unbindEvents=function(a,
+b){k(b,function(b,f){P(a.chart.canvas,f,b)})},R=d.getMaximumWidth=function(a){a=a.parentNode;var b=parseInt(z(a,"padding-left"))+parseInt(z(a,"padding-right"));return a?a.clientWidth-b:0},S=d.getMaximumHeight=function(a){a=a.parentNode;var b=parseInt(z(a,"padding-bottom"))+parseInt(z(a,"padding-top"));return a?a.clientHeight-b:0},z=d.getStyle=function(a,b){return a.currentStyle?a.currentStyle[b]:document.defaultView.getComputedStyle(a,null).getPropertyValue(b)};d.getMaximumSize=d.getMaximumWidth;
+var T=d.retinaScale=function(a){var b=a.ctx,c=a.canvas.width;a=a.canvas.height;window.devicePixelRatio&&(b.canvas.style.width=c+"px",b.canvas.style.height=a+"px",b.canvas.height=a*window.devicePixelRatio,b.canvas.width=c*window.devicePixelRatio,b.scale(window.devicePixelRatio,window.devicePixelRatio))},U=d.clear=function(a){a.ctx.clearRect(0,0,a.width,a.height)},v=d.fontString=function(a,b,c){return b+" "+a+"px "+c},C=d.longestText=function(a,b,c){a.font=b;var f=0;k(c,function(b){b=a.measureText(b).width;
+f=b>f?b:f});return f},H=d.drawRoundedRectangle=function(a,b,c,f,d,e){a.beginPath();a.moveTo(b+e,c);a.lineTo(b+f-e,c);a.quadraticCurveTo(b+f,c,b+f,c+e);a.lineTo(b+f,c+d-e);a.quadraticCurveTo(b+f,c+d,b+f-e,c+d);a.lineTo(b+e,c+d);a.quadraticCurveTo(b,c+d,b,c+d-e);a.lineTo(b,c+e);a.quadraticCurveTo(b,c,b+e,c);a.closePath()};e.instances={};e.Type=function(a,b,c){this.options=b;this.chart=c;this.id=K();e.instances[this.id]=this;b.responsive&&this.resize();this.initialize.call(this,a)};r(e.Type.prototype,
+{initialize:function(){return this},clear:function(){U(this.chart);return this},stop:function(){e.animationService.cancelAnimation(this);return this},resize:function(a){this.stop();var b=this.chart.canvas,c=R(this.chart.canvas),f=this.options.maintainAspectRatio?c/this.chart.aspectRatio:S(this.chart.canvas);b.width=this.chart.width=c;b.height=this.chart.height=f;T(this.chart);"function"===typeof a&&a.apply(this,Array.prototype.slice.call(arguments,1));return this},reflow:A,render:function(a){a&&this.reflow();
+this.options.animation&&!a?(a=new e.Animation,a.numSteps=this.options.animationSteps,a.easing=this.options.animationEasing,a.render=function(a,c){var f=c.currentStep/c.numSteps,e=(0,d.easingEffects[c.easing])(f);a.draw(e,f,c.currentStep)},a.onAnimationProgress=this.options.onAnimationProgress,a.onAnimationComplete=this.options.onAnimationComplete,e.animationService.addAnimation(this,a)):(this.draw(),this.options.onAnimationComplete.call(this));return this},generateLegend:function(){return t(this.options.legendTemplate,
+this)},destroy:function(){this.clear();Q(this,this.events);var a=this.chart.canvas;a.width=this.chart.width;a.height=this.chart.height;a.style.removeProperty?(a.style.removeProperty("width"),a.style.removeProperty("height")):(a.style.removeAttribute("width"),a.style.removeAttribute("height"));delete e.instances[this.id]},showTooltip:function(a,b){"undefined"===typeof this.activeElements&&(this.activeElements=[]);if(function(a){var b=!1;if(a.length!==this.activeElements.length)return b=!0;k(a,function(a,
+c){a!==this.activeElements[c]&&(b=!0)},this);return b}.call(this,a)||b){this.activeElements=a;this.draw();this.options.customTooltips&&this.options.customTooltips(!1);if(0<a.length)if(this.datasets&&1<this.datasets.length){for(var c,f,q=this.datasets.length-1;0<=q&&(c=this.datasets[q].points||this.datasets[q].bars||this.datasets[q].segments,f=J(c,a[0]),-1===f);q--);var m=[],g=[];c=function(a){var b=[],c,e=[],q=[],k,h,l;d.each(this.datasets,function(a){c=a.points||a.bars||a.segments;c[f]&&c[f].hasValue()&&
+b.push(c[f])});d.each(b,function(a){e.push(a.x);q.push(a.y);m.push(d.template(this.options.multiTooltipTemplate,a));g.push({fill:a._saved.fillColor||a.fillColor,stroke:a._saved.strokeColor||a.strokeColor})},this);l=w(q);k=y(q);h=w(e);a=y(e);return{x:h>this.chart.width/2?h:a,y:(l+k)/2}}.call(this,f);(new e.MultiTooltip({x:c.x,y:c.y,xPadding:this.options.tooltipXPadding,yPadding:this.options.tooltipYPadding,xOffset:this.options.tooltipXOffset,fillColor:this.options.tooltipFillColor,textColor:this.options.tooltipFontColor,
+fontFamily:this.options.tooltipFontFamily,fontStyle:this.options.tooltipFontStyle,fontSize:this.options.tooltipFontSize,titleTextColor:this.options.tooltipTitleFontColor,titleFontFamily:this.options.tooltipTitleFontFamily,titleFontStyle:this.options.tooltipTitleFontStyle,titleFontSize:this.options.tooltipTitleFontSize,cornerRadius:this.options.tooltipCornerRadius,labels:m,legendColors:g,legendColorBackground:this.options.multiTooltipKeyBackground,title:t(this.options.tooltipTitleTemplate,a[0]),chart:this.chart,
+ctx:this.chart.ctx,custom:this.options.customTooltips})).draw()}else k(a,function(a){var b=a.tooltipPosition();(new e.Tooltip({x:Math.round(b.x),y:Math.round(b.y),xPadding:this.options.tooltipXPadding,yPadding:this.options.tooltipYPadding,fillColor:this.options.tooltipFillColor,textColor:this.options.tooltipFontColor,fontFamily:this.options.tooltipFontFamily,fontStyle:this.options.tooltipFontStyle,fontSize:this.options.tooltipFontSize,caretHeight:this.options.tooltipCaretSize,cornerRadius:this.options.tooltipCornerRadius,
+text:t(this.options.tooltipTemplate,a),chart:this.chart,custom:this.options.customTooltips})).draw()},this);return this}},toBase64Image:function(){return this.chart.canvas.toDataURL.apply(this.chart.canvas,arguments)}});e.Type.extend=function(a){var b=this,c=function(){return b.apply(this,arguments)};c.prototype=h(b.prototype);r(c.prototype,a);c.extend=e.Type.extend;if(a.name||b.prototype.name){var f=a.name||b.prototype.name,d=e.defaults[b.prototype.name]?h(e.defaults[b.prototype.name]):{};e.defaults[f]=
+r(d,a.defaults);e.types[f]=c;e.prototype[f]=function(a,b){var d=I(e.defaults.global,e.defaults[f],b||{});return new c(a,d,this)}}else L("Name not provided for this chart, so it hasn't been registered");return b};e.Element=function(a){r(this,a);this.initialize.apply(this,arguments);this.save()};r(e.Element.prototype,{initialize:function(){},restore:function(a){a?k(a,function(a){this[a]=this._saved[a]},this):r(this,this._saved);return this},save:function(){this._saved=h(this);delete this._saved._saved;
+return this},update:function(a){k(a,function(a,c){this._saved[c]=this[c];this[c]=a},this);return this},transition:function(a,b){k(a,function(a,f){this[f]=(a-this._saved[f])*b+this._saved[f]},this);return this},tooltipPosition:function(){return{x:this.x,y:this.y}},hasValue:function(){return u(this.value)}});e.Element.extend=D;e.Point=e.Element.extend({display:!0,inRange:function(a,b){return Math.pow(a-this.x,2)+Math.pow(b-this.y,2)<Math.pow(this.hitDetectionRadius+this.radius,2)},draw:function(){if(this.display){var a=
+this.ctx;a.beginPath();a.arc(this.x,this.y,this.radius,0,2*Math.PI);a.closePath();a.strokeStyle=this.strokeColor;a.lineWidth=this.strokeWidth;a.fillStyle=this.fillColor;a.fill();a.stroke()}}});e.Arc=e.Element.extend({inRange:function(a,b){var c=d.getAngleFromPoint(this,{x:a,y:b}),f=c.angle%(2*Math.PI),e=(2*Math.PI+this.startAngle)%(2*Math.PI),m=(2*Math.PI+this.endAngle)%(2*Math.PI)||360,c=c.distance>=this.innerRadius&&c.distance<=this.outerRadius;return(m<e?f<=m||f>=e:f>=e&&f<=m)&&c},tooltipPosition:function(){var a=
+this.startAngle+(this.endAngle-this.startAngle)/2,b=(this.outerRadius-this.innerRadius)/2+this.innerRadius;return{x:this.x+Math.cos(a)*b,y:this.y+Math.sin(a)*b}},draw:function(a){a=this.ctx;a.beginPath();a.arc(this.x,this.y,0>this.outerRadius?0:this.outerRadius,this.startAngle,this.endAngle);a.arc(this.x,this.y,0>this.innerRadius?0:this.innerRadius,this.endAngle,this.startAngle,!0);a.closePath();a.strokeStyle=this.strokeColor;a.lineWidth=this.strokeWidth;a.fillStyle=this.fillColor;a.fill();a.lineJoin=
+"bevel";this.showStroke&&a.stroke()}});e.Rectangle=e.Element.extend({draw:function(){var a=this.ctx,b=this.width/2,c=this.x-b,b=this.x+b,f=this.base-(this.base-this.y),d=this.strokeWidth/2;this.showStroke&&(c+=d,b-=d,f+=d);a.beginPath();a.fillStyle=this.fillColor;a.strokeStyle=this.strokeColor;a.lineWidth=this.strokeWidth;a.moveTo(c,this.base);a.lineTo(c,f);a.lineTo(b,f);a.lineTo(b,this.base);a.fill();this.showStroke&&a.stroke()},height:function(){return this.base-this.y},inRange:function(a,b){return a>=
+this.x-this.width/2&&a<=this.x+this.width/2&&b>=this.y&&b<=this.base}});e.Animation=e.Element.extend({currentStep:null,numSteps:60,easing:"",render:null,onAnimationProgress:null,onAnimationComplete:null});e.Tooltip=e.Element.extend({draw:function(){var a=this.chart.ctx;a.font=v(this.fontSize,this.fontStyle,this.fontFamily);this.xAlign="center";this.yAlign="above";var b=this.caretPadding=2,c=a.measureText(this.text).width+2*this.xPadding,f=this.fontSize+2*this.yPadding,d=f+this.caretHeight+b;this.x+
+c/2>this.chart.width?this.xAlign="left":0>this.x-c/2&&(this.xAlign="right");0>this.y-d&&(this.yAlign="below");var e=this.x-c/2,d=this.y-d;a.fillStyle=this.fillColor;if(this.custom)this.custom(this);else{switch(this.yAlign){case "above":a.beginPath();a.moveTo(this.x,this.y-b);a.lineTo(this.x+this.caretHeight,this.y-(b+this.caretHeight));a.lineTo(this.x-this.caretHeight,this.y-(b+this.caretHeight));a.closePath();a.fill();break;case "below":d=this.y+b+this.caretHeight,a.beginPath(),a.moveTo(this.x,this.y+
+b),a.lineTo(this.x+this.caretHeight,this.y+b+this.caretHeight),a.lineTo(this.x-this.caretHeight,this.y+b+this.caretHeight),a.closePath(),a.fill()}switch(this.xAlign){case "left":e=this.x-c+(this.cornerRadius+this.caretHeight);break;case "right":e=this.x-(this.cornerRadius+this.caretHeight)}H(a,e,d,c,f,this.cornerRadius);a.fill();a.fillStyle=this.textColor;a.textAlign="center";a.textBaseline="middle";a.fillText(this.text,e+c/2,d+f/2)}}});e.MultiTooltip=e.Element.extend({initialize:function(){this.font=
+v(this.fontSize,this.fontStyle,this.fontFamily);this.titleFont=v(this.titleFontSize,this.titleFontStyle,this.titleFontFamily);this.titleHeight=this.title?1.5*this.titleFontSize:0;this.height=this.labels.length*this.fontSize+this.fontSize/2*(this.labels.length-1)+2*this.yPadding+this.titleHeight;this.ctx.font=this.titleFont;var a=this.ctx.measureText(this.title).width,b=C(this.ctx,this.font,this.labels)+this.fontSize+3;this.width=y([b,a])+2*this.xPadding;a=this.height/2;0>this.y-a?this.y=a:this.y+
+a>this.chart.height&&(this.y=this.chart.height-a);this.x=this.x>this.chart.width/2?this.x-(this.xOffset+this.width):this.x+this.xOffset},getLineHeight:function(a){var b=this.y-this.height/2+this.yPadding;return 0===a?b+this.titleHeight/3:b+(1.5*this.fontSize*(a-1)+this.fontSize/2)+this.titleHeight},draw:function(){if(this.custom)this.custom(this);else{H(this.ctx,this.x,this.y-this.height/2,this.width,this.height,this.cornerRadius);var a=this.ctx;a.fillStyle=this.fillColor;a.fill();a.closePath();a.textAlign=
+"left";a.textBaseline="middle";a.fillStyle=this.titleTextColor;a.font=this.titleFont;a.fillText(this.title,this.x+this.xPadding,this.getLineHeight(0));a.font=this.font;d.each(this.labels,function(b,c){a.fillStyle=this.textColor;a.fillText(b,this.x+this.xPadding+this.fontSize+3,this.getLineHeight(c+1));a.fillStyle=this.legendColorBackground;a.fillRect(this.x+this.xPadding,this.getLineHeight(c+1)-this.fontSize/2,this.fontSize,this.fontSize);a.fillStyle=this.legendColors[c].fill;a.fillRect(this.x+this.xPadding,
+this.getLineHeight(c+1)-this.fontSize/2,this.fontSize,this.fontSize)},this)}}});e.Scale=e.Element.extend({initialize:function(){this.fit()},buildYLabels:function(){this.yLabels=[];for(var a=E(this.stepValue),b=0;b<=this.steps;b++)this.yLabels.push(t(this.templateString,{value:(this.min+b*this.stepValue).toFixed(a)}));this.yLabelWidth=this.display&&this.showLabels?C(this.ctx,this.font,this.yLabels)+10:0},addXLabel:function(a){this.xLabels.push(a);this.valuesCount++;this.fit()},removeXLabel:function(){this.xLabels.shift();
+this.valuesCount--;this.fit()},fit:function(){this.startPoint=this.display?this.fontSize:0;this.endPoint=this.display?this.height-1.5*this.fontSize-5:this.height;this.startPoint+=this.padding;var a=this.endPoint-=this.padding,b=this.endPoint-this.startPoint,c;this.calculateYRange(b);this.buildYLabels();for(this.calculateXLabelRotation();b>this.endPoint-this.startPoint;)b=this.endPoint-this.startPoint,c=this.yLabelWidth,this.calculateYRange(b),this.buildYLabels(),c<this.yLabelWidth&&(this.endPoint=
+a,this.calculateXLabelRotation())},calculateXLabelRotation:function(){this.ctx.font=this.font;var a=this.ctx.measureText(this.xLabels[0]).width,b;this.xScalePaddingRight=this.ctx.measureText(this.xLabels[this.xLabels.length-1]).width/2+3;this.xScalePaddingLeft=a/2>this.yLabelWidth?a/2:this.yLabelWidth;this.xLabelRotation=0;if(this.display){var c=C(this.ctx,this.font,this.xLabels),f;this.xLabelWidth=c;for(var d=Math.floor(this.calculateX(1)-this.calculateX(0))-6;this.xLabelWidth>d&&0===this.xLabelRotation||
+this.xLabelWidth>d&&90>=this.xLabelRotation&&0<this.xLabelRotation;)f=Math.cos(B(this.xLabelRotation)),b=f*a,b+this.fontSize/2>this.yLabelWidth&&(this.xScalePaddingLeft=b+this.fontSize/2),this.xScalePaddingRight=this.fontSize/2,this.xLabelRotation++,this.xLabelWidth=f*c;0<this.xLabelRotation&&(this.endPoint-=Math.sin(B(this.xLabelRotation))*c+3)}else this.xLabelWidth=0,this.xScalePaddingLeft=this.xScalePaddingRight=this.padding},calculateYRange:A,drawingArea:function(){return this.startPoint-this.endPoint},
+calculateY:function(a){var b=this.drawingArea()/(this.min-this.max);return this.endPoint-b*(a-this.min)},calculateX:function(a){var b=(this.width-(this.xScalePaddingLeft+this.xScalePaddingRight))/Math.max(this.valuesCount-(this.offsetGridLines?0:1),1);a=b*a+this.xScalePaddingLeft;this.offsetGridLines&&(a+=b/2);return Math.round(a)},update:function(a){d.extend(this,a);this.fit()},draw:function(){var a=this.ctx,b=(this.endPoint-this.startPoint)/this.steps,c=Math.round(this.xScalePaddingLeft);this.display&&
+(a.fillStyle=this.textColor,a.font=this.font,k(this.yLabels,function(f,e){var k=this.endPoint-b*e,g=Math.round(k),h=this.showHorizontalLines;a.textAlign="right";a.textBaseline="middle";this.showLabels&&a.fillText(f,c-10,k);0!==e||h||(h=!0);h&&a.beginPath();0<e?(a.lineWidth=this.gridLineWidth,a.strokeStyle=this.gridLineColor):(a.lineWidth=this.lineWidth,a.strokeStyle=this.lineColor);g+=d.aliasPixel(a.lineWidth);h&&(a.moveTo(c,g),a.lineTo(this.width,g),a.stroke(),a.closePath());a.lineWidth=this.lineWidth;
+a.strokeStyle=this.lineColor;a.beginPath();a.moveTo(c-5,g);a.lineTo(c,g);a.stroke();a.closePath()},this),k(this.xLabels,function(b,c){var d=this.calculateX(c)+F(this.lineWidth),e=this.calculateX(c-(this.offsetGridLines?.5:0))+F(this.lineWidth),k=0<this.xLabelRotation,h=this.showVerticalLines;0!==c||h||(h=!0);h&&a.beginPath();0<c?(a.lineWidth=this.gridLineWidth,a.strokeStyle=this.gridLineColor):(a.lineWidth=this.lineWidth,a.strokeStyle=this.lineColor);h&&(a.moveTo(e,this.endPoint),a.lineTo(e,this.startPoint-
+3),a.stroke(),a.closePath());a.lineWidth=this.lineWidth;a.strokeStyle=this.lineColor;a.beginPath();a.moveTo(e,this.endPoint);a.lineTo(e,this.endPoint+5);a.stroke();a.closePath();a.save();a.translate(d,k?this.endPoint+12:this.endPoint+8);a.rotate(-1*B(this.xLabelRotation));a.font=this.font;a.textAlign=k?"right":"center";a.textBaseline=k?"middle":"top";a.fillText(b,0,0);a.restore()},this))}});e.RadialScale=e.Element.extend({initialize:function(){this.size=w([this.height,this.width]);this.drawingArea=
+this.display?this.size/2-(this.fontSize/2+this.backdropPaddingY):this.size/2},calculateCenterOffset:function(a){return this.drawingArea/(this.max-this.min)*(a-this.min)},update:function(){this.lineArc?this.drawingArea=this.display?this.size/2-(this.fontSize/2+this.backdropPaddingY):this.size/2:this.setScaleSize();this.buildYLabels()},buildYLabels:function(){this.yLabels=[];for(var a=E(this.stepValue),b=0;b<=this.steps;b++)this.yLabels.push(t(this.templateString,{value:(this.min+b*this.stepValue).toFixed(a)}))},
+getCircumference:function(){return 2*Math.PI/this.valuesCount},setScaleSize:function(){var a=w([this.height/2-this.pointLabelFontSize-5,this.width/2]),b,c,d,e=this.width,k,g=0,h;this.ctx.font=v(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily);for(c=0;c<this.valuesCount;c++)b=this.getPointPosition(c,a),d=this.ctx.measureText(t(this.templateString,{value:this.labels[c]})).width+5,0===c||c===this.valuesCount/2?(d/=2,b.x+d>e&&(e=b.x+d,k=c),b.x-d<g&&(g=b.x-d,h=c)):c<this.valuesCount/
+2?b.x+d>e&&(e=b.x+d,k=c):c>this.valuesCount/2&&b.x-d<g&&(g=b.x-d,h=c);b=g;e=Math.ceil(e-this.width);k=this.getIndexAngle(k);h=this.getIndexAngle(h);k=e/Math.sin(k+Math.PI/2);h=b/Math.sin(h+Math.PI/2);k=u(k)?k:0;h=u(h)?h:0;this.drawingArea=a-(h+k)/2;this.setCenterPoint(h,k)},setCenterPoint:function(a,b){this.xCenter=(a+this.drawingArea+(this.width-b-this.drawingArea))/2;this.yCenter=this.height/2},getIndexAngle:function(a){return 2*Math.PI/this.valuesCount*a-Math.PI/2},getPointPosition:function(a,
+b){var c=this.getIndexAngle(a);return{x:Math.cos(c)*b+this.xCenter,y:Math.sin(c)*b+this.yCenter}},draw:function(){if(this.display){var a=this.ctx;k(this.yLabels,function(b,c){if(0<c){var d=this.drawingArea/this.steps*c,e=this.yCenter-d;if(0<this.lineWidth){a.strokeStyle=this.lineColor;a.lineWidth=this.lineWidth;if(this.lineArc)a.beginPath(),a.arc(this.xCenter,this.yCenter,d,0,2*Math.PI);else{a.beginPath();for(var f=0;f<this.valuesCount;f++)d=this.getPointPosition(f,this.calculateCenterOffset(this.min+
+c*this.stepValue)),0===f?a.moveTo(d.x,d.y):a.lineTo(d.x,d.y)}a.closePath();a.stroke()}this.showLabels&&(a.font=v(this.fontSize,this.fontStyle,this.fontFamily),this.showLabelBackdrop&&(d=a.measureText(b).width,a.fillStyle=this.backdropColor,a.fillRect(this.xCenter-d/2-this.backdropPaddingX,e-this.fontSize/2-this.backdropPaddingY,d+2*this.backdropPaddingX,this.fontSize+2*this.backdropPaddingY)),a.textAlign="center",a.textBaseline="middle",a.fillStyle=this.fontColor,a.fillText(b,this.xCenter,e))}},this);
+if(!this.lineArc){a.lineWidth=this.angleLineWidth;a.strokeStyle=this.angleLineColor;for(var b=this.valuesCount-1;0<=b;b--){var c=null,d=null;0<this.angleLineWidth&&(c=this.calculateCenterOffset(this.max),d=this.getPointPosition(b,c),a.beginPath(),a.moveTo(this.xCenter,this.yCenter),a.lineTo(d.x,d.y),a.stroke(),a.closePath());if(this.backgroundColors&&this.backgroundColors.length==this.valuesCount){null==c&&(c=this.calculateCenterOffset(this.max));null==d&&(d=this.getPointPosition(b,c));var e=this.getPointPosition(0===
+b?this.valuesCount-1:b-1,c),h=this.getPointPosition(b===this.valuesCount-1?0:b+1,c),c=(e.x+d.x)/2,e=(e.y+d.y)/2,g=(d.x+h.x)/2,h=(d.y+h.y)/2;a.beginPath();a.moveTo(this.xCenter,this.yCenter);a.lineTo(c,e);a.lineTo(d.x,d.y);a.lineTo(g,h);a.fillStyle=this.backgroundColors[b];a.fill();a.closePath()}d=this.getPointPosition(b,this.calculateCenterOffset(this.max)+5);a.font=v(this.pointLabelFontSize,this.pointLabelFontStyle,this.pointLabelFontFamily);a.fillStyle=this.pointLabelFontColor;e=this.labels.length;
+c=this.labels.length/2;g=c/2;h=b<g||b>e-g;e=b===g||b===e-g;a.textAlign=0===b?"center":b===c?"center":b<c?"left":"right";a.textBaseline=e?"middle":h?"bottom":"top";a.fillText(this.labels[b],d.x,d.y)}}}}});e.animationService={frameDuration:17,animations:[],dropFrames:0,addAnimation:function(a,b){for(var c=0;c<this.animations.length;++c)if(this.animations[c].chartInstance===a){this.animations[c].animationObject=b;return}this.animations.push({chartInstance:a,animationObject:b});1==this.animations.length&&
+d.requestAnimFrame.call(window,this.digestWrapper)},cancelAnimation:function(a){var b=d.findNextWhere(this.animations,function(b){return b.chartInstance===a});b&&this.animations.splice(b,1)},digestWrapper:function(){e.animationService.startDigest.call(e.animationService)},startDigest:function(){var a=Date.now(),b=0;1<this.dropFrames&&(b=Math.floor(this.dropFrames),this.dropFrames-=b);for(var c=0;c<this.animations.length;c++)null===this.animations[c].animationObject.currentStep&&(this.animations[c].animationObject.currentStep=
+0),this.animations[c].animationObject.currentStep+=1+b,this.animations[c].animationObject.currentStep>this.animations[c].animationObject.numSteps&&(this.animations[c].animationObject.currentStep=this.animations[c].animationObject.numSteps),this.animations[c].animationObject.render(this.animations[c].chartInstance,this.animations[c].animationObject),this.animations[c].animationObject.currentStep==this.animations[c].animationObject.numSteps&&(this.animations[c].animationObject.onAnimationComplete.call(this.animations[c].chartInstance),
+this.animations.splice(c,1),c--);a=(Date.now()-a-this.frameDuration)/this.frameDuration;1<a&&(this.dropFrames+=a);0<this.animations.length&&d.requestAnimFrame.call(window,this.digestWrapper)}};d.addEvent(window,"resize",function(){var a;return function(){clearTimeout(a);a=setTimeout(function(){k(e.instances,function(a){a.options.responsive&&a.resize(a.render,!0)})},50)}}());M?define(function(){return e}):"object"===typeof module&&module.exports&&(module.exports=e);p.Chart=e;e.noConflict=function(){p.Chart=
+l;return e}}).call(this);
+(function(){var p=this.Chart,l=p.helpers,e={segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2,percentageInnerCutout:50,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0,animateScale:!1,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><% for (var i=0; i<segments.length; i++){%><li><span style="background-color:<%=segments[i].fillColor%>"><%if(segments[i].label){%><%=segments[i].label%><%}%></span></li><%}%></ul>'};p.Type.extend({name:"Doughnut",defaults:e,
+initialize:function(d){this.segments=[];this.outerRadius=(l.min([this.chart.width,this.chart.height])-this.options.segmentStrokeWidth/2)/2;this.SegmentArc=p.Arc.extend({ctx:this.chart.ctx,x:this.chart.width/2,y:this.chart.height/2});this.options.showTooltips&&l.bindEvents(this,this.options.tooltipEvents,function(d){d="mouseout"!==d.type?this.getSegmentsAtEvent(d):[];l.each(this.segments,function(d){d.restore(["fillColor"])});l.each(d,function(d){d.fillColor=d.highlightColor});this.showTooltip(d)});
+this.calculateTotal(d);l.each(d,function(e,h){e.color||(e.color="hsl("+360*h/d.length+", 100%, 50%)");this.addData(e,h,!0)},this);this.render()},getSegmentsAtEvent:function(d){var e=[],h=l.getRelativePosition(d);l.each(this.segments,function(d){d.inRange(h.x,h.y)&&e.push(d)},this);return e},addData:function(d,e,h){e=void 0!==e?e:this.segments.length;"undefined"===typeof d.color&&(d.color=p.defaults.global.segmentColorDefault[e%p.defaults.global.segmentColorDefault.length],d.highlight=p.defaults.global.segmentHighlightColorDefaults[e%
+p.defaults.global.segmentHighlightColorDefaults.length]);this.segments.splice(e,0,new this.SegmentArc({value:d.value,outerRadius:this.options.animateScale?0:this.outerRadius,innerRadius:this.options.animateScale?0:this.outerRadius/100*this.options.percentageInnerCutout,fillColor:d.color,highlightColor:d.highlight||d.color,showStroke:this.options.segmentShowStroke,strokeWidth:this.options.segmentStrokeWidth,strokeColor:this.options.segmentStrokeColor,startAngle:1.5*Math.PI,circumference:this.options.animateRotate?
+0:this.calculateCircumference(d.value),label:d.label}));h||(this.reflow(),this.update())},calculateCircumference:function(d){return 0<this.total?d/this.total*Math.PI*2:0},calculateTotal:function(d){this.total=0;l.each(d,function(d){this.total+=Math.abs(d.value)},this)},update:function(){this.calculateTotal(this.segments);l.each(this.activeElements,function(d){d.restore(["fillColor"])});l.each(this.segments,function(d){d.save()});this.render()},removeData:function(d){d=l.isNumber(d)?d:this.segments.length-
+1;this.segments.splice(d,1);this.reflow();this.update()},reflow:function(){l.extend(this.SegmentArc.prototype,{x:this.chart.width/2,y:this.chart.height/2});this.outerRadius=(l.min([this.chart.width,this.chart.height])-this.options.segmentStrokeWidth/2)/2;l.each(this.segments,function(d){d.update({outerRadius:this.outerRadius,innerRadius:this.outerRadius/100*this.options.percentageInnerCutout})},this)},draw:function(d){var e=d?d:1;this.clear();l.each(this.segments,function(d,l){d.transition({circumference:this.calculateCircumference(d.value),
+outerRadius:this.outerRadius,innerRadius:this.outerRadius/100*this.options.percentageInnerCutout},e);d.endAngle=d.startAngle+d.circumference;d.draw();0===l&&(d.startAngle=1.5*Math.PI);l<this.segments.length-1&&(this.segments[l+1].startAngle=d.endAngle)},this)}});p.types.Doughnut.extend({name:"Pie",defaults:l.merge(e,{percentageInnerCutout:0})})}).call(this);
diff --git a/applications/luci-app-nlbwmon/luasrc/controller/nlbw.lua b/applications/luci-app-nlbwmon/luasrc/controller/nlbw.lua
new file mode 100644
index 0000000000..bb56bc6e6e
--- /dev/null
+++ b/applications/luci-app-nlbwmon/luasrc/controller/nlbw.lua
@@ -0,0 +1,225 @@
+-- Copyright 2017 Jo-Philipp Wich <jo@mein.io>
+-- Licensed to the public under the Apache License 2.0.
+
+module("luci.controller.nlbw", package.seeall)
+
+function index()
+ entry({"admin", "nlbw"}, firstchild(), _("Bandwidth Monitor"), 80)
+ entry({"admin", "nlbw", "display"}, template("nlbw/display"), _("Display"), 1)
+ entry({"admin", "nlbw", "config"}, cbi("nlbw/config"), _("Configuration"), 2)
+ entry({"admin", "nlbw", "backup"}, template("nlbw/backup"), _("Backup"), 3)
+ entry({"admin", "nlbw", "data"}, call("action_data"), nil, 4)
+ entry({"admin", "nlbw", "list"}, call("action_list"), nil, 5)
+ entry({"admin", "nlbw", "ptr"}, call("action_ptr"), nil, 6).leaf = true
+ entry({"admin", "nlbw", "download"}, call("action_download"), nil, 7)
+ entry({"admin", "nlbw", "restore"}, post("action_restore"), nil, 8)
+ entry({"admin", "nlbw", "commit"}, call("action_commit"), nil, 9)
+end
+
+local function exec(cmd, args, writer)
+ local os = require "os"
+ local nixio = require "nixio"
+
+ local fdi, fdo = nixio.pipe()
+ local pid = nixio.fork()
+
+ if pid > 0 then
+ fdo:close()
+
+ while true do
+ local buffer = fdi:read(2048)
+ local wpid, stat, code = nixio.waitpid(pid, "nohang")
+
+ if writer and buffer and #buffer > 0 then
+ writer(buffer)
+ end
+
+ if wpid and stat == "exited" then
+ break
+ end
+ end
+ elseif pid == 0 then
+ nixio.dup(fdo, nixio.stdout)
+ fdi:close()
+ fdo:close()
+ nixio.exece(cmd, args, nil)
+ nixio.stdout:close()
+ os.exit(1)
+ end
+end
+
+function action_data()
+ local http = require "luci.http"
+
+ local types = {
+ csv = "text/csv",
+ json = "application/json"
+ }
+
+ local args = { }
+ local mtype = http.formvalue("type") or "json"
+ local delim = http.formvalue("delim") or ";"
+ local period = http.formvalue("period")
+ local group_by = http.formvalue("group_by")
+ local order_by = http.formvalue("order_by")
+
+ if types[mtype] then
+ args[#args+1] = "-c"
+ args[#args+1] = mtype
+ else
+ http.status(400, "Unsupported type")
+ return
+ end
+
+ if delim and #delim > 0 then
+ args[#args+1] = "-s%s" % delim
+ end
+
+ if period and #period > 0 then
+ args[#args+1] = "-t"
+ args[#args+1] = period
+ end
+
+ if group_by and #group_by > 0 then
+ args[#args+1] = "-g"
+ args[#args+1] = group_by
+ end
+
+ if order_by and #order_by > 0 then
+ args[#args+1] = "-o"
+ args[#args+1] = order_by
+ end
+
+ http.prepare_content(types[mtype])
+ exec("/usr/sbin/nlbw", args, http.write)
+end
+
+function action_list()
+ local http = require "luci.http"
+
+ local fd = io.popen("/usr/sbin/nlbw -c list")
+ local periods = { }
+
+ if fd then
+ while true do
+ local period = fd:read("*l")
+
+ if not period then
+ break
+ end
+
+ periods[#periods+1] = period
+ end
+
+ fd:close()
+ end
+
+ http.prepare_content("application/json")
+ http.write_json(periods)
+end
+
+function action_ptr(...)
+ local http = require "luci.http"
+ local util = require "luci.util"
+
+ http.prepare_content("application/json")
+ http.write_json(util.ubus("network.rrdns", "lookup", {
+ addrs = {...}, timeout = 3000
+ }))
+end
+
+function action_download()
+ local nixio = require "nixio"
+ local http = require "luci.http"
+ local sys = require "luci.sys"
+ local uci = require "luci.model.uci".cursor()
+
+ local dir = uci:get_first("nlbwmon", "nlbwmon", "database_directory")
+ or "/var/lib/nlbwmon"
+
+ if dir and nixio.fs.stat(dir, "type") == "dir" then
+ local n = "nlbwmon-backup-%s-%s.tar.gz"
+ %{ sys.hostname(), os.date("%Y-%m-%d") }
+
+ http.prepare_content("application/octet-stream")
+ http.header("Content-Disposition", "attachment; filename=\"%s\"" % n)
+ exec("/bin/tar", { "-C", dir, "-c", "-z", ".", "-f", "-" }, http.write)
+ else
+ http.status(500, "Unable to find database directory")
+ end
+end
+
+function action_restore()
+ local nixio = require "nixio"
+ local http = require "luci.http"
+ local i18n = require "luci.i18n"
+ local tpl = require "luci.template"
+ local uci = require "luci.model.uci".cursor()
+
+ local tmp = "/tmp/nlbw-restore.tar.gz"
+ local dir = uci:get_first("nlbwmon", "nlbwmon", "database_directory")
+ or "/var/lib/nlbwmon"
+
+ local fp
+ http.setfilehandler(
+ function(meta, chunk, eof)
+ if not fp and meta and meta.name == "archive" then
+ fp = io.open(tmp, "w")
+ end
+ if fp and chunk then
+ fp:write(chunk)
+ end
+ if fp and eof then
+ fp:close()
+ end
+ end)
+
+ local files = { }
+ local tar = io.popen("/bin/tar -tzf %s" % tmp, "r")
+ if tar then
+ while true do
+ local file = tar:read("*l")
+ if not file then
+ break
+ elseif file:match("^%d%d%d%d%d%d%d%d%.db%.gz$") or
+ file:match("^%./%d%d%d%d%d%d%d%d%.db%.gz$") then
+ files[#files+1] = file
+ end
+ end
+ tar:close()
+ end
+
+ if #files == 0 then
+ http.status(500, "Internal Server Error")
+ tpl.render("nlbw/backup", {
+ message = i18n.translate("Invalid or empty backup archive")
+ })
+ return
+ end
+
+
+ local output = { }
+
+ exec("/etc/init.d/nlbwmon", { "stop" })
+ exec("/bin/mkdir", { "-p", dir })
+
+ exec("/bin/tar", { "-C", dir, "-vxzf", tmp, unpack(files) },
+ function(chunk) output[#output+1] = chunk:match("%S+") end)
+
+ exec("/bin/rm", { "-f", tmp })
+ exec("/etc/init.d/nlbwmon", { "start" })
+
+ tpl.render("nlbw/backup", {
+ message = i18n.translatef(
+ "The following database files have been restored: %s",
+ table.concat(output, ", "))
+ })
+end
+
+function action_commit()
+ local http = require "luci.http"
+ local disp = require "luci.dispatcher"
+
+ http.redirect(disp.build_url("admin/nlbw/display"))
+ exec("/usr/sbin/nlbw", { "-c", "commit" })
+end
diff --git a/applications/luci-app-nlbwmon/luasrc/model/cbi/nlbw/config.lua b/applications/luci-app-nlbwmon/luasrc/model/cbi/nlbw/config.lua
new file mode 100644
index 0000000000..71e096c617
--- /dev/null
+++ b/applications/luci-app-nlbwmon/luasrc/model/cbi/nlbw/config.lua
@@ -0,0 +1,215 @@
+-- Copyright 2017 Jo-Philipp Wich <jo@mein.io>
+-- Licensed to the public under the Apache License 2.0.
+
+local utl = require "luci.util"
+local sys = require "luci.sys"
+local fs = require "nixio.fs"
+local ip = require "luci.ip"
+local nw = require "luci.model.network"
+
+local s, m, period, warning, date, days, interval, ifaces, subnets, limit, prealloc, compress, generations, commit, refresh, directory, protocols
+
+m = Map("nlbwmon", translate("Netlink Bandwidth Monitor - Configuration"),
+ translate("The Netlink Bandwidth Monitor (nlbwmon) is a lightweight, efficient traffic accounting program keeping track of bandwidth usage per host and protocol."))
+
+nw.init(luci.model.uci.cursor_state())
+
+s = m:section(TypedSection, "nlbwmon")
+s.anonymous = true
+s.addremove = false
+s:tab("general", translate("General Settings"))
+s:tab("advanced", translate("Advanced Settings"))
+s:tab("protocol", translate("Protocol Mapping"),
+ translate("Protocol mappings to distinguish traffic types per host, one mapping per line. The first value specifies the IP protocol, the second value the port number and the third column is the name of the mapped protocol."))
+
+period = s:taboption("general", ListValue, "_period", translate("Accounting period"),
+ translate("Choose \"Day of month\" to restart the accounting period monthly on a specific date, e.g. every 3rd. Choose \"Fixed interval\" to restart the accounting period exactly every N days, beginning at a given date."))
+
+period:value("relative", translate("Day of month"))
+period:value("absolute", translate("Fixed interval"))
+
+period.write = function(self, cfg, val)
+ if period:formvalue(cfg) == "relative" then
+ m:set(cfg, "database_interval", interval:formvalue(cfg))
+ else
+ m:set(cfg, "database_interval", "%s/%s" %{
+ date:formvalue(cfg),
+ days:formvalue(cfg)
+ })
+ end
+end
+
+period.cfgvalue = function(self, cfg)
+ local val = m:get(cfg, "database_interval") or ""
+ if val:match("^%d%d%d%d%-%d%d%-%d%d/%d+$") then
+ return "absolute"
+ end
+ return "relative"
+end
+
+
+warning = s:taboption("general", DummyValue, "_warning", translate("Warning"))
+warning.default = translatef("Changing the accounting interval type will invalidate existing databases!<br /><strong><a href=\"%s\">Download backup</a></strong>.", luci.dispatcher.build_url("admin/nlbw/backup"))
+warning.rawhtml = true
+
+if (m.uci:get_first("nlbwmon", "nlbwmon", "database_interval") or ""):match("^%d%d%d%d-%d%d-%d%d/%d+$") then
+ warning:depends("_period", "relative")
+else
+ warning:depends("_period", "absolute")
+end
+
+
+interval = s:taboption("general", Value, "_interval", translate("Due date"),
+ translate("Day of month to restart the accounting period. Use negative values to count towards the end of month, e.g. \"-5\" to specify the 27th of July or the 24th of Februrary."))
+
+interval.datatype = "or(range(1,31),range(-31,-1))"
+interval.placeholder = "1"
+interval:value("1", translate("1 - Restart every 1st of month"))
+interval:value("-1", translate("-1 - Restart every last day of month"))
+interval:value("-7", translate("-7 - Restart a week before end of month"))
+interval.rmempty = false
+interval:depends("_period", "relative")
+interval.write = period.write
+
+interval.cfgvalue = function(self, cfg)
+ local val = m:get(cfg, "database_interval")
+ return val and tonumber(val)
+end
+
+
+date = s:taboption("general", Value, "_date", translate("Start date"),
+ translate("Start date of the first accounting period, e.g. begin of ISP contract."))
+
+date.datatype = "dateyyyymmdd"
+date.placeholder = "2016-03-15"
+date.rmempty = false
+date:depends("_period", "absolute")
+date.write = period.write
+
+date.cfgvalue = function(self, cfg)
+ local val = m:get(cfg, "database_interval") or ""
+ return (val:match("^(%d%d%d%d%-%d%d%-%d%d)/%d+$"))
+end
+
+
+days = s:taboption("general", Value, "_days", translate("Interval"),
+ translate("Length of accounting interval in days."))
+
+days.datatype = "min(1)"
+days.placeholder = "30"
+days.rmempty = false
+days:depends("_period", "absolute")
+days.write = period.write
+
+days.cfgvalue = function(self, cfg)
+ local val = m:get(cfg, "database_interval") or ""
+ return (val:match("^%d%d%d%d%-%d%d%-%d%d/(%d+)$"))
+end
+
+
+ifaces = s:taboption("general", Value, "_ifaces", translate("Local interfaces"),
+ translate("Only conntrack streams from or to any of these networks are counted."))
+
+ifaces.template = "cbi/network_netlist"
+ifaces.widget = "checkbox"
+ifaces.nocreate = true
+
+ifaces.cfgvalue = function(self, cfg)
+ return m:get(cfg, "local_network")
+end
+
+ifaces.write = function(self, cfg)
+ local item
+ local items = {}
+ for item in utl.imatch(subnets:formvalue(cfg)) do
+ items[#items+1] = item
+ end
+ for item in utl.imatch(ifaces:formvalue(cfg)) do
+ items[#items+1] = item
+ end
+ m:set(cfg, "local_network", items)
+end
+
+
+subnets = s:taboption("general", DynamicList, "_subnets", translate("Local subnets"),
+ translate("Only conntrack streams from or to any of these subnets are counted."))
+
+subnets.datatype = "ipaddr"
+
+subnets.cfgvalue = function(self, cfg)
+ local subnet
+ local subnets = {}
+ for subnet in utl.imatch(m:get(cfg, "local_network")) do
+ subnet = ip.new(subnet)
+ subnets[#subnets+1] = subnet and subnet:string()
+ end
+ return subnets
+end
+
+subnets.write = ifaces.write
+
+
+limit = s:taboption("advanced", Value, "database_limit", translate("Maximum entries"),
+ translate("The maximum amount of entries that should be put into the database, setting the limit to 0 will allow databases to grow indefinitely."))
+
+limit.datatype = "uinteger"
+limit.placeholder = "10000"
+
+prealloc = s:taboption("advanced", Flag, "database_prealloc", translate("Preallocate database"),
+ translate("Whether to preallocate the maximum possible database size in memory. This is mainly useful for memory constrained systems which might not be able to satisfy memory allocation after longer uptime periods."))
+
+prealloc:depends({["database_limit"] = "0", ["!reverse"] = true })
+
+
+compress = s:taboption("advanced", Flag, "database_compress", translate("Compress database"),
+ translate("Whether to gzip compress archive databases. Compressing the database files makes accessing old data slightly slower but helps to reduce storage requirements."))
+
+compress.default = compress.enabled
+
+
+generations = s:taboption("advanced", Value, "database_generations", translate("Stored periods"),
+ translate("Maximum number of accounting periods to keep, use zero to keep databases forever."))
+
+generations.datatype = "uinteger"
+generations.placeholder = "10"
+
+
+commit = s:taboption("advanced", Value, "commit_interval", translate("Commit interval"),
+ translate("Interval at which the temporary in-memory database is committed to the persistent database directory."))
+
+commit.placeholder = "24h"
+commit:value("24h", translate("24h - least flash wear at the expense of data loss risk"))
+commit:value("12h", translate("12h - compromise between risk of data loss and flash wear"))
+commit:value("10m", translate("10m - frequent commits at the expense of flash wear"))
+commit:value("60s", translate("60s - commit minutely, useful for non-flash storage"))
+
+
+refresh = s:taboption("advanced", Value, "refresh_interval", translate("Refresh interval"),
+ translate("Interval at which traffic counters of still established connections are refreshed from netlink information."))
+
+refresh.placeholder = "30s"
+refresh:value("30s", translate("30s - refresh twice per minute for reasonably current stats"))
+refresh:value("5m", translate("5m - rarely refresh to avoid frequently clearing conntrack counters"))
+
+
+directory = s:taboption("advanced", Value, "database_directory", translate("Database directory"),
+ translate("Database storage directory. One file per accounting period will be placed into this directory."))
+
+directory.placeholder = "/var/lib/nlbwmon"
+
+
+protocols = s:taboption("protocol", TextValue, "_protocols")
+protocols.rows = 50
+
+protocols.cfgvalue = function(self, cfg)
+ return fs.readfile("/usr/share/nlbwmon/protocols")
+end
+
+protocols.write = function(self, cfg, value)
+ fs.writefile("/usr/share/nlbwmon/protocols", (value or ""):gsub("\r\n", "\n"))
+end
+
+protocols.remove = protocols.write
+
+
+return m
diff --git a/applications/luci-app-nlbwmon/luasrc/view/nlbw/backup.htm b/applications/luci-app-nlbwmon/luasrc/view/nlbw/backup.htm
new file mode 100644
index 0000000000..ea2e0f05cf
--- /dev/null
+++ b/applications/luci-app-nlbwmon/luasrc/view/nlbw/backup.htm
@@ -0,0 +1,34 @@
+<%#
+ Copyright 2017 Jo-Philipp Wich <jo@mein.io>
+ Licensed to the public under the Apache License 2.0.
+-%>
+
+<%+header%>
+
+<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
+
+<h2 name="content"><%:Netlink Bandwidth Monitor - Backup / Restore %></h2>
+
+<fieldset class="cbi-section">
+ <legend><%:Restore Database Backup%></legend>
+ <p>
+ <form method="POST" action="<%=url("admin/nlbw/restore")%>" enctype="multipart/form-data">
+ <input type="hidden" name="token" value="<%=token%>" />
+ <input type="file" name="archive" accept="application/gzip,.gz" />
+ <input type="submit" value="<%:Restore%>" class="cbi-button cbi-button-apply" />
+ </form>
+
+ <% if message then %>
+ <div class="alert-message"><%=message%></div>
+ <% end %>
+ </p>
+
+ <legend><%:Download Database Backup%></legend>
+ <p>
+ <form method="GET" action="<%=url("admin/nlbw/download")%>">
+ <input type="submit" value="<%:Generate Backup%>" class="cbi-button cbi-button-link" />
+ </form>
+ </p>
+</fieldset>
+
+<%+footer%>
diff --git a/applications/luci-app-nlbwmon/luasrc/view/nlbw/display.htm b/applications/luci-app-nlbwmon/luasrc/view/nlbw/display.htm
new file mode 100644
index 0000000000..932c8849a7
--- /dev/null
+++ b/applications/luci-app-nlbwmon/luasrc/view/nlbw/display.htm
@@ -0,0 +1,1052 @@
+<%#
+ Copyright 2017 Jo-Philipp Wich <jo@mein.io>
+ Licensed to the public under the Apache License 2.0.
+-%>
+
+<% css = [[
+
+ #chartjs-tooltip {
+ opacity: 0;
+ position: absolute;
+ background: rgba(0, 0, 0, .7);
+ color: white;
+ padding: 3px;
+ border-radius: 3px;
+ -webkit-transition: all .1s ease;
+ transition: all .1s ease;
+ pointer-events: none;
+ -webkit-transform: translate(-50%, 0);
+ transform: translate(-50%, 0);
+ z-index: 200;
+ }
+
+ #chartjs-tooltip.above {
+ -webkit-transform: translate(-50%, -100%);
+ transform: translate(-50%, -100%);
+ }
+
+ #chartjs-tooltip.above:before {
+ border: solid;
+ border-color: #111 transparent;
+ border-color: rgba(0, 0, 0, .8) transparent;
+ border-width: 8px 8px 0 8px;
+ bottom: 1em;
+ content: "";
+ display: block;
+ left: 50%;
+ top: 100%;
+ position: absolute;
+ z-index: 99;
+ -webkit-transform: translate(-50%, 0);
+ transform: translate(-50%, 0);
+ }
+
+ table {
+ border: 1px solid #999;
+ border-collapse: collapse;
+ margin: 0 0 2px !important;
+ }
+
+ th, td, table table td {
+ border: 1px solid #999;
+ text-align: right;
+ padding: 1px 3px !important;
+ white-space: nowrap;
+ }
+
+ tbody td {
+ border-bottom-color: #ccc;
+ }
+
+ tbody td[rowspan] {
+ border-bottom-color: #999;
+ }
+
+ tbody tr:last-child td {
+ border-bottom-color: #999;
+ }
+
+
+ .pie {
+ width: 200px;
+ display: inline-block;
+ margin: 20px;
+ }
+
+ .pie label {
+ font-weight: bold;
+ font-size: 14px;
+ display: block;
+ margin-bottom: 10px;
+ text-align: center;
+ }
+
+ .kpi {
+ display: inline-block;
+ margin: 80px 20px 20px;
+ vertical-align: top;
+ }
+
+ .kpi ul {
+ list-style: none;
+ }
+
+ .kpi li {
+ margin: 10px;
+ display: none;
+ }
+
+ .kpi big {
+ font-weight: bold;
+ }
+
+ #detail-bubble {
+ position: absolute;
+ opacity: 0;
+ visibility: hidden;
+ }
+
+ #detail-bubble.in {
+ opacity: 1;
+ visibility: visible;
+ transition: opacity 0.5s;
+ }
+
+ #detail-bubble > div {
+ border: 1px solid #ccc;
+ border-radius: 2px;
+ padding: 5px;
+ background: #fcfcfc;
+ }
+
+ #detail-bubble .head {
+ text-align: center;
+ white-space: nowrap;
+ position: relative;
+ }
+
+ #detail-bubble .head .dismiss {
+ top: 0;
+ right: 0;
+ width: 20px;
+ line-height: 20px;
+ text-align: center;
+ text-decoration: none;
+ font-weight: bold;
+ color: #000;
+ position: absolute;
+ font-size: 20px;
+ }
+
+ #detail-bubble .pie {
+ width: 100px;
+ margin: 5px;
+ }
+
+ #detail-bubble .kpi {
+ margin: 40px 5px 5px;
+ font-size: smaller;
+ text-align: left;
+ }
+
+ #detail-bubble .kpi ul {
+ margin: 0;
+ }
+
+ #bubble-arrow {
+ border: 1px solid #ccc;
+ border-width: 1px 0 0 1px;
+ background: #fcfcfc;
+ width: 15px;
+ height: 15px;
+ position: absolute;
+ left: 0;
+ top: -8px;
+ transform: rotate(45deg);
+ margin: 0 0 0 -8px;
+ }
+
+ tr.active > td {
+ border-bottom: 2px solid red;
+ }
+
+ tr.active > td.active {
+ border: 2px solid red;
+ border-bottom: none;
+ }
+
+ td.detail {
+ border: 2px solid red;
+ border-top: none;
+ opacity: 0;
+ transition: opacity 0.5s;
+ }
+
+ td.detail.in {
+ opacity: 1;
+ }
+
+ th.hostname,
+ td.hostname {
+ text-align: left;
+ }
+
+]] -%>
+
+<%+header%>
+
+<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
+<script type="text/javascript" src="<%=resource%>/nlbw.chart.min.js"></script>
+<script type="text/javascript">//<![CDATA[
+
+var chartRegistry = {},
+ trafficPeriods = [],
+ trafficData = { columns: [], data: [] },
+ hostNames = {},
+ hostInfo = <%=luci.util.serialize_json(luci.sys.net.host_hints())%>,
+ ouiData = [];
+
+
+function off(elem)
+{
+ var val = [0, 0];
+ do {
+ if (!isNaN(elem.offsetLeft) && !isNaN(elem.offsetTop)) {
+ val[0] += elem.offsetLeft;
+ val[1] += elem.offsetTop;
+ }
+ }
+ while ((elem = elem.offsetParent) != null);
+ return val;
+}
+
+Chart.defaults.global.customTooltips = function(tooltip) {
+ var tooltipEl = document.getElementById('chartjs-tooltip');
+
+ if (!tooltipEl) {
+ tooltipEl = document.createElement('div');
+ tooltipEl.setAttribute('id', 'chartjs-tooltip');
+ document.body.appendChild(tooltipEl);
+ }
+
+ if (!tooltip) {
+ if (tooltipEl.row)
+ tooltipEl.row.style.backgroundColor = '';
+
+ tooltipEl.style.opacity = 0;
+ return;
+ }
+
+ var pos = off(tooltip.chart.canvas);
+
+ tooltipEl.className = tooltip.yAlign;
+ tooltipEl.innerHTML = tooltip.text[0];
+
+ tooltipEl.style.opacity = 1;
+ tooltipEl.style.left = pos[0] + tooltip.x + 'px';
+ tooltipEl.style.top = pos[1] + tooltip.y - tooltip.caretHeight - tooltip.caretPadding + 'px';
+
+ var row = tooltip.text[1],
+ hue = tooltip.text[2];
+
+ if (row && !isNaN(hue)) {
+ row.style.backgroundColor = 'hsl(%u, 100%%, 80%%)'.format(hue);
+ tooltipEl.row = row;
+ }
+};
+
+Chart.defaults.global.tooltipFontSize = 10;
+Chart.defaults.global.tooltipTemplate = function(tip) {
+ tip.label[0] = tip.label[0].format(tip.value);
+ return tip.label;
+};
+
+function kpi(id, val1, val2, val3)
+{
+ var e = document.getElementById(id);
+
+ if (val1 && val2 && val3)
+ e.innerHTML = '<%:%s, %s and %s%>'.format(val1, val2, val3);
+ else if (val1 && val2)
+ e.innerHTML = '<%:%s and %s%>'.format(val1, val2);
+ else if (val1)
+ e.innerHTML = val1;
+
+ e.parentNode.style.display = val1 ? 'list-item' : '';
+}
+
+function pie(id, data)
+{
+ data.sort(function(a, b) { return b.value - a.value });
+
+ if (data.length === 0 || (data.length === 1 && data[0].value === 0))
+ data[0] = {
+ value: 1,
+ color: '#cccccc',
+ label: [ '<%:no traffic%>' ]
+ };
+
+ for (var i = 0; i < data.length; i++) {
+ if (!data[i].color) {
+ var hue = 120 / (data.length-1) * i;
+ data[i].color = 'hsl(%u, 80%%, 50%%)'.format(hue);
+ data[i].label.push(hue);
+ }
+ }
+
+ var ctx = document.getElementById(id).getContext('2d');
+
+ if (chartRegistry.hasOwnProperty(id))
+ chartRegistry[id].destroy();
+
+ chartRegistry[id] = new Chart(ctx).Doughnut(data, {
+ segmentStrokeWidth: 1,
+ percentageInnerCutout: 30
+ });
+
+ return chartRegistry[id];
+}
+
+function query(filter, group, order)
+{
+ var keys = [], columns = {}, records = {}, result = [];
+
+ if (typeof(group) !== 'function' && typeof(group) !== 'object')
+ group = ['mac'];
+
+ for (var i = 0; i < trafficData.columns.length; i++)
+ columns[trafficData.columns[i]] = i;
+
+ for (var i = 0; i < trafficData.data.length; i++) {
+ var record = trafficData.data[i];
+
+ if (typeof(filter) === 'function' && filter(columns, record) !== true)
+ continue;
+
+ var key;
+
+ if (typeof(group) === 'function') {
+ key = group(columns, record);
+ }
+ else {
+ key = [];
+
+ for (var j = 0; j < group.length; j++)
+ if (columns.hasOwnProperty(group[j]))
+ key.push(record[columns[group[j]]]);
+
+ key = key.join(',');
+ }
+
+ if (!records.hasOwnProperty(key)) {
+ var rec = {};
+
+ for (var col in columns)
+ rec[col] = record[columns[col]];
+
+ records[key] = rec;
+ result.push(rec);
+ }
+ else {
+ records[key].conns += record[columns.conns];
+ records[key].rx_bytes += record[columns.rx_bytes];
+ records[key].rx_pkts += record[columns.rx_pkts];
+ records[key].tx_bytes += record[columns.tx_bytes];
+ records[key].tx_pkts += record[columns.tx_pkts];
+ }
+ }
+
+ if (typeof(order) === 'function')
+ result.sort(order);
+
+ return result;
+}
+
+function oui(mac) {
+ var m, l = 0, r = ouiData.length / 3 - 1;
+ var mac1 = parseInt(mac.replace(/[^a-fA-F0-9]/g, ''), 16);
+
+ while (l <= r) {
+ m = l + Math.floor((r - l) / 2);
+
+ var mask = (0xffffffffffff -
+ (Math.pow(2, 48 - ouiData[m * 3 + 1]) - 1));
+
+ var mac1_hi = ((mac1 / 0x10000) & (mask / 0x10000)) >>> 0;
+ var mac1_lo = ((mac1 & 0xffff) & (mask & 0xffff)) >>> 0;
+
+ var mac2 = parseInt(ouiData[m * 3], 16);
+ var mac2_hi = (mac2 / 0x10000) >>> 0;
+ var mac2_lo = (mac2 & 0xffff) >>> 0;
+
+ if (mac1_hi === mac2_hi && mac1_lo === mac2_lo)
+ return ouiData[m * 3 + 2];
+
+ if (mac2_hi > mac1_hi ||
+ (mac2_hi === mac1_hi && mac2_lo > mac1_lo))
+ r = m - 1;
+ else
+ l = m + 1;
+ }
+
+ return null;
+}
+
+
+function fetchData(period)
+{
+ XHR.get('<%=url("admin/nlbw/data")%>', { period: period, group_by: 'family,mac,ip,layer7', order_by: '-rx_bytes,-tx_bytes' }, function(xhr, res) {
+ if (res !== null && typeof(res) === 'object' && typeof(res.columns) === 'object' && typeof(res.data) === 'object')
+ trafficData = res;
+
+ var addrs = query(null, ['ip'], null);
+ var ipAddrs = [];
+
+ for (var i = 0; i < addrs.length; i++)
+ if (ipAddrs.indexOf(addrs[i].ip) < 0)
+ ipAddrs.push(addrs[i].ip);
+
+ renderHostData();
+ renderLayer7Data();
+ renderIPv6Data();
+
+ XHR.get('<%=url("admin/nlbw/ptr")%>/' + ipAddrs.join('/'), null, function(xhr, res) {
+ if (res !== null && typeof(res) === 'object')
+ hostNames = res;
+ });
+ });
+}
+
+function switchTab(tab)
+{
+ bubbleDismiss();
+
+ return cbi_t_switch('nlbw', tab);
+}
+
+function renderPeriods()
+{
+ var sel = document.getElementById('nlbw.period');
+
+ for (var e, i = trafficPeriods.length - 1; e = trafficPeriods[i]; i--) {
+ var d1 = new Date(e);
+ var d2, pd;
+
+ if (i) {
+ d2 = new Date(trafficPeriods[i - 1]);
+ d2.setDate(d2.getDate() - 1);
+ pd = '%04d-%02d-%02d'.format(d1.getFullYear(), d1.getMonth() + 1, d1.getDate());
+ }
+ else {
+ d2 = new Date();
+ pd = '';
+ }
+
+ var opt = document.createElement('option');
+ opt.setAttribute('data-duration', (d2.getTime() - d1.getTime()) / 1000);
+ opt.value = pd;
+ opt.text = '%04d-%02d-%02d - %04d-%02d-%02d'.format(
+ d1.getFullYear(), d1.getMonth() + 1, d1.getDate(),
+ d2.getFullYear(), d2.getMonth() + 1, d2.getDate());
+
+ sel.appendChild(opt);
+ }
+
+ sel.selectedIndex = sel.childNodes.length - 1;
+ sel.style.display = '';
+
+ sel.onchange = function() {
+ bubbleDismiss();
+ fetchData(sel.options[sel.selectedIndex].value);
+ }
+}
+
+function renderHostDetail()
+{
+ var key = this.getAttribute('href').substr(1),
+ col = this.getAttribute('data-col'),
+ label = this.getAttribute('data-label'),
+ bubble = document.getElementById('detail-bubble'),
+ arrow = document.getElementById('bubble-arrow'),
+ table = document.getElementById('bubble-table');
+
+ bubbleDismiss();
+
+ var detailData = query(
+ function(c, r) {
+ return ((r[c.mac] === key || r[c.ip] === key) &&
+ (r[c.rx_bytes] > 0 || r[c.tx_bytes] > 0));
+ },
+ [col],
+ function(r1, r2) {
+ return ((r2.rx_bytes + r2.tx_bytes) - (r1.rx_bytes + r1.tx_bytes));
+ }
+ );
+
+ var rxData = [], txData = [];
+
+ table.innerHTML = '<tr>' +
+ '<th>%s</th>'.format(label || col) +
+ '<th><%:Conn.%></th>' +
+ '<th colspan="2"><%:Down. (Bytes / Pkts.)%></th>' +
+ '<th colspan="2"><%:Up. (Bytes / Pkts.)%></th>' +
+ '</tr>';
+
+ for (var i = 0; i < detailData.length; i++) {
+ var rec = detailData[i],
+ row = table.insertRow(-1);
+
+ row.insertCell(-1).innerHTML = rec[col] || '<%:other%>';
+ row.insertCell(-1).innerHTML = "%1000.2m".format(rec.conns);
+ row.insertCell(-1).innerHTML = "%1024.2mB".format(rec.rx_bytes);
+ row.insertCell(-1).innerHTML = "%1000.2mP".format(rec.rx_pkts);
+ row.insertCell(-1).innerHTML = "%1024.2mB".format(rec.tx_bytes);
+ row.insertCell(-1).innerHTML = "%1000.2mP".format(rec.tx_pkts);
+
+ rxData.push({
+ label: ['%s: %%1024.2mB'.format(rec[col] || '<%:other%>'), row],
+ value: rec.rx_bytes
+ });
+
+ txData.push({
+ label: ['%s: %%1024.2mB'.format(rec[col] || '<%:other%>'), row],
+ value: rec.tx_bytes
+ });
+ }
+
+ pie('bubble-pie1', rxData);
+ pie('bubble-pie2', txData);
+
+ var mac = key.toUpperCase();
+ var name = hostInfo.hasOwnProperty(mac) ? hostInfo[mac].name : null;
+
+ if (!name)
+ for (var i = 0; i < detailData.length; i++)
+ if ((name = hostNames[detailData[i].ip]) !== undefined)
+ break;
+
+ if (mac !== '00:00:00:00:00:00') {
+ kpi('bubble-hostname', name);
+ kpi('bubble-vendor', oui(mac));
+ }
+ else {
+ kpi('bubble-hostname');
+ kpi('bubble-vendor');
+ }
+
+ var tr = this.parentNode.parentNode,
+ xy = off(tr),
+ xy2 = off(this);
+
+ bubble.style.width = tr.offsetWidth + 'px';
+ bubble.style.left = xy[0] + 'px';
+ bubble.style.top = (xy[1] + tr.offsetHeight) + 'px';
+ arrow.style.left = Math.floor(xy2[0] + this.offsetWidth / 2 - xy[0]) + 'px';
+
+ bubble.className = 'in';
+
+ return false;
+}
+
+function formatHostname(dns)
+{
+ if (dns === undefined || dns === null || dns === '')
+ return '-';
+
+ dns = dns.split('.')[0];
+
+ if (dns.length > 12)
+ return '<span title="%q">%h…</span>'.format(dns, dns.substr(0, 12));
+
+ return '%h'.format(dns);
+}
+
+function renderHostData()
+{
+ var trafData = [], connData = [];
+ var rx_total = 0, tx_total = 0, conn_total = 0;
+ var table = document.getElementById('host-data');
+
+ var hostData = query(
+ function(c, r) {
+ return (r[c.rx_bytes] > 0 || r[c.tx_bytes] > 0);
+ },
+ ['mac'],
+ //function(c, r) {
+ // return (r[c.mac] !== '00:00:00:00:00:00') ? r[c.mac] : r[c.ip];
+ //},
+ function(r1, r2) {
+ return ((r2.rx_bytes + r2.tx_bytes) - (r1.rx_bytes + r1.tx_bytes));
+ }
+ );
+
+ while (table.rows.length > 1)
+ table.deleteRow(1);
+
+ for (var i = 0; i < hostData.length; i++) {
+ var row = table.insertRow(-1),
+ cell = row.insertCell(-1),
+ rec = hostData[i],
+ mac = rec.mac.toUpperCase(),
+ key = (mac !== '00:00:00:00:00:00') ? mac : rec.ip,
+ dns = hostInfo[mac] ? hostInfo[mac].name : null;
+
+ var link1 = document.createElement('a');
+ link1.onclick = renderHostDetail;
+ link1.href = '#' + rec.mac;
+ link1.setAttribute('data-col', 'ip');
+ link1.setAttribute('data-label', '<%:Source IP%>');
+ link1.innerHTML = (mac !== '00:00:00:00:00:00') ? mac : '<%:other%>';
+
+ var link2 = document.createElement('a');
+ link2.onclick = renderHostDetail;
+ link2.href = '#' + rec.mac;
+ link2.setAttribute('data-col', 'layer7');
+ link2.setAttribute('data-label', '<%:Protocol%>');
+ link2.innerHTML = "%1000.2m".format(rec.conns);
+
+ cell.innerHTML = formatHostname(dns);
+ cell.className = 'hostname';
+
+ row.insertCell(-1).appendChild(link1);
+ row.insertCell(-1).appendChild(link2);
+ row.insertCell(-1).innerHTML = "%1024.2mB".format(rec.rx_bytes);
+ row.insertCell(-1).innerHTML = "%1000.2mP".format(rec.rx_pkts);
+ row.insertCell(-1).innerHTML = "%1024.2mB".format(rec.tx_bytes);
+ row.insertCell(-1).innerHTML = "%1000.2mP".format(rec.tx_pkts);
+
+ trafData.push({
+ value: rec.rx_bytes + rec.tx_bytes,
+ label: ["%s: %%.2mB".format(key), row]
+ });
+
+ connData.push({
+ value: rec.conns,
+ label: ["%s: %%.2m".format(key), row]
+ });
+
+ rx_total += rec.rx_bytes;
+ tx_total += rec.tx_bytes;
+ conn_total += rec.conns;
+ }
+
+ if (table.rows.length === 1) {
+ var cell = table.insertRow(-1).insertCell(-1);
+
+ cell.setAttribute('colspan', 6);
+ cell.innerHTML = '<em><%:No data recorded yet.%> <a href="<%=url("admin/nlbw/commit")%>"><%:Force reload…%></a></em>';
+ }
+
+ pie('traf-pie', trafData);
+ pie('conn-pie', connData);
+
+ kpi('rx-total', '%1024.2mB'.format(rx_total));
+ kpi('tx-total', '%1024.2mB'.format(tx_total));
+ kpi('conn-total', '%1000m'.format(conn_total));
+ kpi('host-total', '%u'.format(hostData.length));
+}
+
+function renderLayer7Data()
+{
+ var rxData = [], txData = [];
+ var topConn = [[0],[0],[0]], topRx = [[0],[0],[0]], topTx = [[0],[0],[0]];
+ var table = document.getElementById('layer7-data');
+
+ var layer7Data = query(
+ null, ['layer7'],
+ function(r1, r2) {
+ return ((r2.rx_bytes + r2.tx_bytes) - (r1.rx_bytes + r1.tx_bytes));
+ }
+ );
+
+ while (table.rows.length > 1)
+ table.deleteRow(1);
+
+ for (var i = 0, c = 0; i < layer7Data.length; i++) {
+ var rec = layer7Data[i],
+ row = table.insertRow(-1);
+
+ rxData.push({
+ value: rec.rx_bytes,
+ label: ["%s: %%.2mB".format(rec.layer7 || '<%:other%>'), row]
+ });
+
+ txData.push({
+ value: rec.tx_bytes,
+ label: ["%s: %%.2mB".format(rec.layer7 || '<%:other%>'), row]
+ });
+
+ row.insertCell(-1).innerHTML = rec.layer7 || '<%:other%>';
+ row.insertCell(-1).innerHTML = "%1000m".format(rec.conns);
+ row.insertCell(-1).innerHTML = "%1024.2mB".format(rec.rx_bytes);
+ row.insertCell(-1).innerHTML = "%1000.2mP".format(rec.rx_pkts);
+ row.insertCell(-1).innerHTML = "%1024.2mB".format(rec.tx_bytes);
+ row.insertCell(-1).innerHTML = "%1000.2mP".format(rec.tx_pkts);
+
+ if (rec.layer7) {
+ topRx.push([rec.rx_bytes, rec.layer7]);
+ topTx.push([rec.tx_bytes, rec.layer7]);
+ topConn.push([rec.conns, rec.layer7]);
+ }
+ }
+
+ if (table.rows.length === 1) {
+ var cell = table.insertRow(-1).insertCell(-1);
+
+ cell.setAttribute('colspan', 6);
+ cell.innerHTML = '<em><%:No data recorded yet.%> <a href="<%=url("admin/nlbw/commit")%>"><%:Force reload…%></a></em>';
+ }
+
+ pie('layer7-rx-pie', rxData);
+ pie('layer7-tx-pie', txData);
+
+ topRx.sort(function(a, b) { return b[0] - a[0] });
+ topTx.sort(function(a, b) { return b[0] - a[0] });
+ topConn.sort(function(a, b) { return b[0] - a[0] });
+
+ kpi('layer7-total', layer7Data.length);
+ kpi('layer7-most-rx', topRx[0][1], topRx[1][1], topRx[2][1]);
+ kpi('layer7-most-tx', topTx[0][1], topTx[1][1], topTx[2][1]);
+ kpi('layer7-most-conn', topConn[0][1], topConn[1][1], topConn[2][1]);
+}
+
+function renderIPv6Data()
+{
+ var table = document.getElementById('ipv6-data'),
+ col = { },
+ rx4_total = 0,
+ tx4_total = 0,
+ rx6_total = 0,
+ tx6_total = 0,
+ v4_total = 0,
+ v6_total = 0,
+ ds_total = 0,
+ families = { },
+ records = { };
+
+ ipv6Data = query(
+ null, ['family', 'mac'],
+ function(r1, r2) {
+ return ((r2.rx_bytes + r2.tx_bytes) - (r1.rx_bytes + r1.tx_bytes));
+ }
+ );
+
+ for (var i = 0, c = 0; i < ipv6Data.length; i++) {
+ var rec = ipv6Data[i],
+ mac = rec.mac.toUpperCase(),
+ ip = rec.ip,
+ fam = families[mac] || 0,
+ recs = records[mac] || {};
+
+ if (rec.family == 4) {
+ rx4_total += rec.rx_bytes;
+ tx4_total += rec.tx_bytes;
+ fam |= 1;
+ }
+ else {
+ rx6_total += rec.rx_bytes;
+ tx6_total += rec.tx_bytes;
+ fam |= 2;
+ }
+
+ recs[rec.family] = rec;
+ records[mac] = recs;
+
+ families[mac] = fam;
+ }
+
+ for (var mac in families) {
+ switch (families[mac])
+ {
+ case 3:
+ ds_total++;
+ break;
+
+ case 2:
+ v6_total++;
+ break;
+
+ case 1:
+ v4_total++;
+ break;
+ }
+ }
+
+ while (table.rows.length > 1)
+ table.deleteRow(1);
+
+ for (var mac in records) {
+ if (mac === '00:00:00:00:00:00')
+ continue;
+
+ var row = table.insertRow(-1),
+ cell1 = row.insertCell(-1),
+ cell2 = row.insertCell(-1),
+ dns = hostInfo[mac] ? hostInfo[mac].name : null,
+ rec4 = records[mac][4],
+ rec6 = records[mac][6];
+
+ cell1.setAttribute('rowspan', 2);
+ cell1.innerHTML = formatHostname(dns);
+ cell1.className = 'hostname';
+
+ cell2.setAttribute('rowspan', 2);
+ cell2.innerHTML = mac;
+
+ row.insertCell(-1).innerHTML = 'IPv4';
+ row.insertCell(-1).innerHTML = rec4 ? "%1024.2mB".format(rec4.rx_bytes) : '-';
+ row.insertCell(-1).innerHTML = rec4 ? "%1000.2mP".format(rec4.rx_pkts) : '-';
+ row.insertCell(-1).innerHTML = rec4 ? "%1024.2mB".format(rec4.tx_bytes) : '-';
+ row.insertCell(-1).innerHTML = rec4 ? "%1000.2mP".format(rec4.tx_pkts) : '-';
+
+ row = table.insertRow(-1);
+
+ row.insertCell(-1).innerHTML = 'IPv6';
+ row.insertCell(-1).innerHTML = rec6 ? "%1024.2mB".format(rec6.rx_bytes) : '-';
+ row.insertCell(-1).innerHTML = rec6 ? "%1000.2mP".format(rec6.rx_pkts) : '-';
+ row.insertCell(-1).innerHTML = rec6 ? "%1024.2mB".format(rec6.tx_bytes) : '-';
+ row.insertCell(-1).innerHTML = rec6 ? "%1000.2mP".format(rec6.tx_pkts) : '-';
+ }
+
+ if (table.rows.length === 1) {
+ var cell = table.insertRow(-1).insertCell(-1);
+
+ cell.setAttribute('colspan', 7);
+ cell.innerHTML = '<em><%:No data recorded yet.%> <a href="<%=url("admin/nlbw/commit")%>"><%:Force reload…%></a></em>';
+ }
+
+ var shareData = [], hostsData = [];
+
+ if (rx4_total > 0 || tx4_total > 0)
+ shareData.push({
+ value: rx4_total + tx4_total,
+ label: ["IPv4: %.2mB"],
+ color: 'hsl(140, 100%, 50%)'
+ });
+
+ if (rx6_total > 0 || tx6_total > 0)
+ shareData.push({
+ value: rx6_total + tx6_total,
+ label: ["IPv6: %.2mB"],
+ color: 'hsl(180, 100%, 50%)'
+ });
+
+ if (v4_total > 0)
+ hostsData.push({
+ value: v4_total,
+ label: ["<%:%d IPv4-only hosts%>"],
+ color: 'hsl(140, 100%, 50%)'
+ });
+
+ if (v6_total > 0)
+ hostsData.push({
+ value: v6_total,
+ label: ["<%:%d IPv6-only hosts%>"],
+ color: 'hsl(180, 100%, 50%)'
+ });
+
+ if (ds_total > 0)
+ hostsData.push({
+ value: ds_total,
+ label: ["<%:%d dual-stack hosts%>"],
+ color: 'hsl(50, 100%, 50%)'
+ });
+
+ pie('ipv6-share-pie', shareData);
+ pie('ipv6-hosts-pie', hostsData);
+
+ kpi('ipv6-hosts', '%.2f%%'.format(100 / (ds_total + v4_total + v6_total) * (ds_total + v6_total)));
+ kpi('ipv6-share', '%.2f%%'.format(100 / (rx4_total + rx6_total + tx4_total + tx6_total) * (rx6_total + tx6_total)));
+ kpi('ipv6-rx', '%1024.2mB'.format(rx6_total));
+ kpi('ipv6-tx', '%1024.2mB'.format(tx6_total));
+}
+
+function bubbleDismiss()
+{
+ var bubble = document.getElementById('detail-bubble');
+
+ bubble.className = '';
+ document.body.appendChild(bubble);
+
+ return false;
+}
+
+
+//]]></script>
+
+<h2 name="content"><%:Netlink Bandwidth Monitor%></h2>
+
+<div id="detail-bubble">
+ <span id="bubble-arrow"></span>
+ <div>
+ <div class="head">
+ <a class="dismiss" href="#" onclick="this.blur(); return bubbleDismiss()">×</a>
+ <div class="pie">
+ <label>Download</label>
+ <canvas id="bubble-pie1" width="100" height="100"></canvas>
+ </div>
+ <div class="pie">
+ <label>Upload</label>
+ <canvas id="bubble-pie2" width="100" height="100"></canvas>
+ </div>
+ <div class="kpi">
+ <ul>
+ <li><%_Hostname: <big id="bubble-hostname">example.org</big>%></li>
+ <li><%_Vendor: <big id="bubble-vendor">Example Corp.</big>%></li>
+ </ul>
+ </div>
+ </div>
+ <table id="bubble-table"></table>
+ </div>
+</div>
+
+<hr />
+
+<p>
+ <%:Select accounting period:%>
+ <select id="nlbw.period" style="display:none"></select>
+</p>
+
+<hr />
+
+<ul class="cbi-tabmenu">
+ <li id="tab.nlbw.traffic" class="cbi-tab"><a href="#" onclick="return switchTab('traffic')"><%:Traffic Distribution%></a></li>
+ <li id="tab.nlbw.layer7" class="cbi-tab-disabled"><a href="#" onclick="return switchTab('layer7')"><%:Application Protocols%></a></li>
+ <li id="tab.nlbw.ipv6" class="cbi-tab-disabled"><a href="#" onclick="return switchTab('ipv6')"><%:IPv6%></a></li>
+ <li id="tab.nlbw.export" class="cbi-tab-disabled"><a href="#" onclick="return switchTab('export')"><%:Export%></a></li>
+</ul>
+
+<div class="cbi-section" id="container.nlbw.traffic">
+ <div>
+ <div class="pie">
+ <label><%:Traffic / Host%></label>
+ <canvas id="traf-pie" width="200" height="200"></canvas>
+ </div>
+
+ <div class="pie">
+ <label><%:Connections / Host%></label>
+ <canvas id="conn-pie" width="200" height="200"></canvas>
+ </div>
+
+ <div class="kpi">
+ <ul>
+ <li><%_<big id="host-total">0</big> hosts%></li>
+ <li><%_<big id="rx-total">0</big> download%></li>
+ <li><%_<big id="tx-total">0</big> upload%></li>
+ <li><%_<big id="conn-total">0</big> connections%></li>
+ </ul>
+ </div>
+ </div>
+ <table id="host-data">
+ <tr>
+ <th width="10%" class="hostname"><%:Host%></th>
+ <th width="5%"><%:MAC%></th>
+ <th width="5%"><%:Connections%></th>
+ <th width="30%" colspan="2"><%:Download (Bytes / Packets)%></th>
+ <th width="30%" colspan="2"><%:Upload (Bytes / Packets)%></th>
+ </tr>
+ </table>
+</div>
+
+<div class="cbi-section" id="container.nlbw.layer7" style="display:none">
+ <div>
+ <div class="pie">
+ <label><%:Download / Application%></label>
+ <canvas id="layer7-rx-pie" width="200" height="200"></canvas>
+ </div>
+
+ <div class="pie">
+ <label><%:Upload / Application%></label>
+ <canvas id="layer7-tx-pie" width="200" height="200"></canvas>
+ </div>
+
+ <div class="kpi">
+ <ul>
+ <li><%_<big id="layer7-total">0</big> different application protocols%></li>
+ <li><%_<big id="layer7-most-rx">0</big> cause the most download%></li>
+ <li><%_<big id="layer7-most-tx">0</big> cause the most upload%></li>
+ <li><%_<big id="layer7-most-conn">0</big> cause the most connections%></li>
+ </ul>
+ </div>
+ </div>
+ <table id="layer7-data">
+ <tr>
+ <th width="20%"><%:Application%></th>
+ <th width="10%"><%:Connections%></th>
+ <th width="30%" colspan="2"><%:Download (Bytes / Packets)%></th>
+ <th width="30%" colspan="2"><%:Upload (Bytes / Packets)%></th>
+ </tr>
+ </table>
+</div>
+
+<div class="cbi-section" id="container.nlbw.ipv6" style="display:none">
+ <div>
+ <div class="pie">
+ <label><%:IPv4 vs. IPv6%></label>
+ <canvas id="ipv6-share-pie" width="200" height="200"></canvas>
+ </div>
+
+ <div class="pie">
+ <label><%:Dualstack enabled hosts%></label>
+ <canvas id="ipv6-hosts-pie" width="200" height="200"></canvas>
+ </div>
+
+ <div class="kpi">
+ <ul>
+ <li><%_<big id="ipv6-hosts">0%</big> IPv6 support rate among hosts%></li>
+ <li><%_<big id="ipv6-share">0%</big> of the total traffic is IPv6%></li>
+ <li><%_<big id="ipv6-rx">0B</big> total IPv6 download%></li>
+ <li><%_<big id="ipv6-tx">0B</big> total IPv6 upload%></li>
+ </ul>
+ </div>
+ </div>
+ <table id="ipv6-data">
+ <tr>
+ <th width="10%" class="hostname"><%:Host%></th>
+ <th width="5%"><%:MAC%></th>
+ <th width="5%"><%:Family%></th>
+ <th width="40%" colspan="2"><%:Download (Bytes / Packets)%></th>
+ <th width="40%" colspan="2"><%:Upload (Bytes / Packets)%></th>
+ </tr>
+ </table>
+</div>
+
+<div class="cbi-section" id="container.nlbw.export" style="display:none">
+ <ul>
+ <li><a href="<%=url('admin/nlbw/data')%>?type=csv&#38;group_by=mac&#38;order_by=-rx,-tx"><%:CSV, grouped by MAC%></a></li>
+ <li><a href="<%=url('admin/nlbw/data')%>?type=csv&#38;group_by=ip&#38;order_by=-rx,-tx"><%:CSV, grouped by IP%></a></li>
+ <li><a href="<%=url('admin/nlbw/data')%>?type=csv&#38;group_by=layer7&#38;order_by=-rx,-tx"><%:CSV, grouped by protocol%></a></li>
+ <li><a href="<%=url('admin/nlbw/data')%>?type=json"><%:JSON dump%></a></li>
+ </ul>
+</div>
+
+<script type="text/javascript">//<![CDATA[
+ cbi_t_add('nlbw', 'traffic');
+ cbi_t_add('nlbw', 'layer7');
+ cbi_t_add('nlbw', 'ipv6');
+ cbi_t_add('nlbw', 'export');
+
+ XHR.get('<%=url("admin/nlbw/list")%>', null, function(xhr, res) {
+
+ if (res !== null && typeof(res) === 'object' && res.length > 0) {
+ trafficPeriods = res;
+ renderPeriods();
+ }
+
+ xhr.open('GET', 'https://raw.githubusercontent.com/jow-/oui-database/master/oui.json', true);
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState === 4) {
+ try { res = JSON.parse(xhr.responseText); }
+ catch(e) { res = null; }
+
+ if (res !== null && typeof(res) === 'object' && (res.length % 3) === 0)
+ ouiData = res;
+
+ fetchData('');
+ }
+ };
+ xhr.send(null);
+ });
+//]]></script>
+
+<%+footer%>
diff --git a/applications/luci-app-nlbwmon/po/ja/nlbwmon.po b/applications/luci-app-nlbwmon/po/ja/nlbwmon.po
new file mode 100644
index 0000000000..b5931e0dfe
--- /dev/null
+++ b/applications/luci-app-nlbwmon/po/ja/nlbwmon.po
@@ -0,0 +1,387 @@
+msgid ""
+msgstr ""
+"Content-Type: text/plain; charset=UTF-8\n"
+"Project-Id-Version: \n"
+"POT-Creation-Date: \n"
+"PO-Revision-Date: \n"
+"Last-Translator: INAGAKI Hiroshi <musashino.open@gmail.com>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: ja\n"
+"X-Generator: Poedit 2.0.3\n"
+
+msgid "%d IPv4-only hosts"
+msgstr "%d IPv4 é™å®šãƒ›ã‚¹ãƒˆ"
+
+msgid "%d IPv6-only hosts"
+msgstr "%d IPv6 é™å®šãƒ›ã‚¹ãƒˆ"
+
+msgid "%d dual-stack hosts"
+msgstr "%d デュアルスタック ホスト"
+
+msgid "%s and %s"
+msgstr "%s, %s"
+
+msgid "%s, %s and %s"
+msgstr "%s, %s, %s"
+
+msgid "-1 - Restart every last day of month"
+msgstr "-1 - 月ã®æœ€çµ‚æ—¥"
+
+msgid "-7 - Restart a week before end of month"
+msgstr "-7 - 月ã®æœ€çµ‚æ—¥ã®ä¸€é€±é–“å‰"
+
+msgid "1 - Restart every 1st of month"
+msgstr "1 - 毎月1日"
+
+msgid "10m - frequent commits at the expense of flash wear"
+msgstr "10m - フラッシュ媒体ã¸ã®è² è·ãŒé«˜ã„é »ç¹ãªã‚³ãƒŸãƒƒãƒˆï¼ˆ10分)"
+
+msgid "12h - compromise between risk of data loss and flash wear"
+msgstr "12h - データ消失リスクã¨ãƒ•ãƒ©ãƒƒã‚·ãƒ¥åª’体ã¸ã®è² è·ã®å¦¥å”点(12時間)"
+
+msgid "24h - least flash wear at the expense of data loss risk"
+msgstr "24h - データ消失リスクã¯é«˜ã„ãŒãƒ•ãƒ©ãƒƒã‚·ãƒ¥åª’体ã¸ã®è² è·ã¯æœ€å°ï¼ˆ24時間)"
+
+msgid "30s - refresh twice per minute for reasonably current stats"
+msgstr "30s - ç¾åœ¨ã®çŠ¶æ…‹ã®æŠŠæ¡ã«é©åˆ‡ãª1分間ã«2回ã®ãƒªãƒ•ãƒ¬ãƒƒã‚·ãƒ¥ï¼ˆ30秒)"
+
+msgid "5m - rarely refresh to avoid frequently clearing conntrack counters"
+msgstr ""
+
+msgid "60s - commit minutely, useful for non-flash storage"
+msgstr "60秒 - 1分毎ã®ã‚³ãƒŸãƒƒãƒˆã€éžãƒ•ãƒ©ãƒƒã‚·ãƒ¥ ストレージã«æœ‰ç”¨"
+
+msgid "<big id=\"conn-total\">0</big> connections"
+msgstr "<big id=\"conn-total\">0</big> 接続数"
+
+msgid "<big id=\"host-total\">0</big> hosts"
+msgstr "<big id=\"host-total\">0</big> ホスト数"
+
+msgid "<big id=\"ipv6-hosts\">0%</big> IPv6 support rate among hosts"
+msgstr "<big id=\"ipv6-hosts\">0%</big> 全ホスト中㮠IPv6 サãƒãƒ¼ãƒˆæ¯”率"
+
+msgid "<big id=\"ipv6-rx\">0B</big> total IPv6 download"
+msgstr "<big id=\"ipv6-rx\">0B</big> IPv6 ç·ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰"
+
+msgid "<big id=\"ipv6-share\">0%</big> of the total traffic is IPv6"
+msgstr "<big id=\"ipv6-share\">0%</big> 全トラフィック中㮠IPv6 ã®å‰²åˆ"
+
+msgid "<big id=\"ipv6-tx\">0B</big> total IPv6 upload"
+msgstr "<big id=\"ipv6-tx\">0B</big> IPv6 ç·ã‚¢ãƒƒãƒ—ロード"
+
+msgid "<big id=\"layer7-most-conn\">0</big> cause the most connections"
+msgstr "<big id=\"layer7-most-conn\">0</big> 接続数上ä½"
+
+msgid "<big id=\"layer7-most-rx\">0</big> cause the most download"
+msgstr "<big id=\"layer7-most-rx\">0</big> ダウンロード上ä½"
+
+msgid "<big id=\"layer7-most-tx\">0</big> cause the most upload"
+msgstr "<big id=\"layer7-most-tx\">0</big> アップロード上ä½"
+
+msgid "<big id=\"layer7-total\">0</big> different application protocols"
+msgstr "<big id=\"layer7-total\">0</big> アプリケーション プロトコル数"
+
+msgid "<big id=\"rx-total\">0</big> download"
+msgstr "<big id=\"rx-total\">0</big> ダウンロード"
+
+msgid "<big id=\"tx-total\">0</big> upload"
+msgstr "<big id=\"tx-total\">0</big> アップロード"
+
+msgid "Accounting period"
+msgstr "åŽé›†æœŸé–“"
+
+msgid "Advanced Settings"
+msgstr "拡張設定"
+
+msgid "Application"
+msgstr "アプリケーション"
+
+msgid "Application Protocols"
+msgstr "アプリケーション プロトコル"
+
+msgid "Backup"
+msgstr "ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—"
+
+msgid "Bandwidth Monitor"
+msgstr "帯域幅モニター"
+
+msgid "CSV, grouped by IP"
+msgstr "CSV(IP ã«ã‚ˆã‚‹ã‚°ãƒ«ãƒ¼ãƒ—化)"
+
+msgid "CSV, grouped by MAC"
+msgstr "CSV(MAC ã«ã‚ˆã‚‹ã‚°ãƒ«ãƒ¼ãƒ—化)"
+
+msgid "CSV, grouped by protocol"
+msgstr "CSV(プロトコルã«ã‚ˆã‚‹ã‚°ãƒ«ãƒ¼ãƒ—化)"
+
+msgid ""
+"Changing the accounting interval type will invalidate existing databases!"
+"<br /><strong><a href=\"%s\">Download backup</a></strong>."
+msgstr ""
+"既存ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã¨äº’æ›æ€§ã®ç„¡ã„åŽé›†æœŸé–“ã®å½¢å¼ãŒé¸æŠžã•ã‚Œã¾ã—ãŸã€‚<br /"
+"><strong><a href=\"%s\">ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ã®ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰</a></strong>"
+
+msgid ""
+"Choose \"Day of month\" to restart the accounting period monthly on a "
+"specific date, e.g. every 3rd. Choose \"Fixed interval\" to restart the "
+"accounting period exactly every N days, beginning at a given date."
+msgstr ""
+"月毎ã§è¨­å®šã—ãŸæ—¥ä»˜ã‹ã‚‰ã®ãƒ‡ãƒ¼ã‚¿ã®è¨ˆæ¸¬ã‚’è¡Œã†ã«ã¯ã€ \"月間\" ã‚’é¸æŠžã—ã¾ã™ï¼ˆä¾‹: "
+"毎月3日)。設定ã—ãŸæ—¥æ•°æ¯Žã«ãƒ‡ãƒ¼ã‚¿ã®åŽé›†ã‚’è¡Œã†ã«ã¯ã€\"特定ã®é–“éš”\" ã‚’é¸æŠžã—ã¾"
+"ã™ã€‚後者ã®å ´åˆã€æŒ‡å®šã•ã‚ŒãŸæ—¥ä»˜ã‹ã‚‰é–‹å§‹ã•ã‚Œã¾ã™ã€‚"
+
+msgid "Commit interval"
+msgstr "コミット間隔"
+
+msgid "Compress database"
+msgstr "データベースã®åœ§ç¸®"
+
+msgid "Configuration"
+msgstr "設定"
+
+msgid "Conn."
+msgstr "接続数"
+
+msgid "Connections"
+msgstr "接続数"
+
+msgid "Connections / Host"
+msgstr "ホスト毎ã®æŽ¥ç¶šæ•°"
+
+msgid "Database directory"
+msgstr "データベース ディレクトリ"
+
+msgid ""
+"Database storage directory. One file per accounting period will be placed "
+"into this directory."
+msgstr ""
+"データベースã®ä¿å­˜å…ˆãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã§ã™ã€‚計測期間ã‚ãŸã‚Š 1 ã¤ã®ãƒ•ã‚¡ã‚¤ãƒ«ãŒã“ã®ãƒ‡ã‚£"
+"レクトリã«é…ç½®ã•ã‚Œã¾ã™ã€‚"
+
+msgid "Day of month"
+msgstr "月間"
+
+msgid ""
+"Day of month to restart the accounting period. Use negative values to count "
+"towards the end of month, e.g. \"-5\" to specify the 27th of July or the "
+"24th of Februrary."
+msgstr ""
+"月ã®ä¸­ã§æ–°ãŸãªåŽé›†æœŸé–“を開始ã™ã‚‹æ—¥ã§ã™ã€‚月ã®æœ€çµ‚æ—¥ã‹ã‚‰ã®æ—¥æ•°ã‚’マイナス値ã§æŒ‡"
+"定ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ï¼ˆä¾‹: 7月27æ—¥ã¾ãŸã¯2月24日㯠\"-5\")。"
+
+msgid "Display"
+msgstr "表示"
+
+msgid "Down. (Bytes / Pkts.)"
+msgstr "ダウンロード(Bytes / Pkts.)"
+
+msgid "Download (Bytes / Packets)"
+msgstr "ダウンロード(Bytes / Packets)"
+
+msgid "Download / Application"
+msgstr "ダウンロード / アプリケーション"
+
+msgid "Download Database Backup"
+msgstr "データベース ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ã®ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰"
+
+msgid "Dualstack enabled hosts"
+msgstr "デュアルスタック ホスト"
+
+msgid "Due date"
+msgstr "期日"
+
+msgid "Export"
+msgstr "エクスãƒãƒ¼ãƒˆ"
+
+msgid "Family"
+msgstr "IP 種別"
+
+msgid "Fixed interval"
+msgstr "特定ã®é–“éš”"
+
+msgid "Force reload…"
+msgstr "強制リロード..."
+
+msgid "General Settings"
+msgstr "全般設定"
+
+msgid "Generate Backup"
+msgstr "ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ã®ä½œæˆ"
+
+msgid "Host"
+msgstr "ホスト"
+
+msgid "Hostname: <big id=\"bubble-hostname\">example.org</big>"
+msgstr "ホストå: <big id=\"bubble-hostname\">example.org</big>"
+
+msgid "IPv4 vs. IPv6"
+msgstr "IPv4 åŠã³ IPv6"
+
+msgid "IPv6"
+msgstr "IPv6"
+
+msgid "Interval"
+msgstr "é–“éš”"
+
+msgid ""
+"Interval at which the temporary in-memory database is committed to the "
+"persistent database directory."
+msgstr ""
+"メモリー上ã®ä¸€æ™‚çš„ãªãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‹ã‚‰ã€æ°¸ç¶šçš„ãªãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ ディレクトリã¸ã®ã‚³"
+"ミットを実行ã™ã‚‹é–“éš”ã§ã™ã€‚"
+
+msgid ""
+"Interval at which traffic counters of still established connections are "
+"refreshed from netlink information."
+msgstr ""
+
+msgid "Invalid or empty backup archive"
+msgstr "無効ã¾ãŸã¯ç©ºã®ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ— アーカイブã§ã™ã€‚"
+
+msgid "JSON dump"
+msgstr "JSON ダンプ"
+
+msgid "Length of accounting interval in days."
+msgstr "åŽé›†æœŸé–“ã®æ—¥æ•°ã§ã™ã€‚"
+
+msgid "Local interfaces"
+msgstr "ローカル インターフェース"
+
+msgid "Local subnets"
+msgstr "ローカル サブãƒãƒƒãƒˆ"
+
+msgid "MAC"
+msgstr "MAC"
+
+msgid "Maximum entries"
+msgstr "最大件数"
+
+msgid ""
+"Maximum number of accounting periods to keep, use zero to keep databases "
+"forever."
+msgstr ""
+"計測データをä¿æŒã™ã‚‹ã€åŽé›†æœŸé–“ã®æœ€å¤§å€‹æ•°ã§ã™ã€‚ '0' を設定ã—ãŸå ´åˆã€å…¨ãƒ‡ãƒ¼ã‚¿ã‚’"
+"ä¿æŒã—ã¾ã™ã€‚"
+
+msgid "Netlink Bandwidth Monitor"
+msgstr "Netlink Bandwidth Monitor"
+
+msgid "Netlink Bandwidth Monitor - Backup / Restore"
+msgstr "Netlink Bandwidth Monitor - ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ— / 復元"
+
+msgid "Netlink Bandwidth Monitor - Configuration"
+msgstr "Netlink Bandwidth Monitor - 設定"
+
+msgid "No data recorded yet."
+msgstr "ã¾ã ãƒ‡ãƒ¼ã‚¿ãŒã‚ã‚Šã¾ã›ã‚“。"
+
+msgid "Only conntrack streams from or to any of these networks are counted."
+msgstr ""
+"é¸æŠžã•ã‚ŒãŸãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã«ãŠã‘ã‚‹ conntrack ストリームã®ã¿ãŒè¨ˆæ¸¬ã•ã‚Œã¾ã™ã€‚"
+
+msgid "Only conntrack streams from or to any of these subnets are counted."
+msgstr "設定ã•ã‚ŒãŸã‚µãƒ–ãƒãƒƒãƒˆã«ãŠã‘ã‚‹ conntrack ストリームã®ã¿ãŒè¨ˆæ¸¬ã•ã‚Œã¾ã™ã€‚"
+
+msgid "Preallocate database"
+msgstr "データベースã®äº‹å‰å‰²å½“"
+
+msgid "Protocol"
+msgstr "プロトコル"
+
+msgid "Protocol Mapping"
+msgstr "プロトコル マッピング"
+
+msgid ""
+"Protocol mappings to distinguish traffic types per host, one mapping per "
+"line. The first value specifies the IP protocol, the second value the port "
+"number and the third column is the name of the mapped protocol."
+msgstr ""
+"ホスト毎ã®ãƒˆãƒ©ãƒ•ã‚£ãƒƒã‚¯å½¢å¼ã‚’区別ã™ã‚‹ãŸã‚ã®ãƒ—ロトコル マッピングã§ã€ä¸€è¡Œã‚ãŸã‚Š"
+"一ã¤ã®ãƒžãƒƒãƒ”ングを追加ã—ã¾ã™ã€‚å„エントリーã®ä¸€ã¤ç›®ã®å€¤ã¯ IP プロトコルをã€2ã¤"
+"ç›®ã®å€¤ã¯ãƒãƒ¼ãƒˆç•ªå·ã€3ã¤ç›®ã¯ãƒžãƒƒãƒ”ングã•ã‚ŒãŸãƒ—ロトコルã®åå‰ã‚’ãã‚Œãžã‚Œè¡¨ã—ã¾"
+"ã™ã€‚"
+
+msgid "Refresh interval"
+msgstr "リフレッシュ間隔"
+
+msgid "Restore"
+msgstr "復元"
+
+msgid "Restore Database Backup"
+msgstr "データベースã®å¾©å…ƒ"
+
+msgid "Select accounting period:"
+msgstr "åŽé›†æœŸé–“ã‚’é¸æŠž:"
+
+msgid "Source IP"
+msgstr "アクセス元 IP"
+
+msgid "Start date"
+msgstr "開始日"
+
+msgid "Start date of the first accounting period, e.g. begin of ISP contract."
+msgstr "åˆå›žã®ãƒ‡ãƒ¼ã‚¿åŽé›†ã®é–‹å§‹æ—¥ã§ã™ï¼ˆä¾‹: ISP 契約ã®é–‹å§‹æ—¥ï¼‰ã€‚"
+
+msgid "Stored periods"
+msgstr "ä¿å­˜æœŸé–“"
+
+msgid ""
+"The Netlink Bandwidth Monitor (nlbwmon) is a lightweight, efficient traffic "
+"accounting program keeping track of bandwidth usage per host and protocol."
+msgstr ""
+"Netlink Bandwidth Monitor (nlbwmon) ã¯ã€è»½é‡ã‹ã¤ã€ãƒ›ã‚¹ãƒˆã‚„プロトコル毎ã«å¸¯åŸŸ"
+"幅使用é‡ã®è¿½è·¡ã‚’è¡Œã†åŠ¹çŽ‡çš„ãªãƒˆãƒ©ãƒ•ã‚£ãƒƒã‚¯è¨ˆæ¸¬ãƒ—ログラムã§ã™ã€‚"
+
+msgid "The following database files have been restored: %s"
+msgstr "次ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ ファイルãŒå¾©å…ƒã•ã‚Œã¾ã—ãŸ: %s"
+
+msgid ""
+"The maximum amount of entries that should be put into the database, setting "
+"the limit to 0 will allow databases to grow indefinitely."
+msgstr ""
+"データベースã«ä¿ç®¡ã•ã‚Œã‚‹æœ€å¤§ä»¶æ•°ã§ã™ã€‚ '0' を設定ã—ãŸå ´åˆã€åˆ¶é™ç„¡ã—ã®ãƒ‡ãƒ¼ã‚¿"
+"ベースã®å¢—大を許å¯ã—ã¾ã™ã€‚"
+
+msgid "Traffic / Host"
+msgstr "トラフィック / ホスト"
+
+msgid "Traffic Distribution"
+msgstr "トラフィック内訳"
+
+msgid "Up. (Bytes / Pkts.)"
+msgstr "アップロード(Bytes / Pkts.)"
+
+msgid "Upload (Bytes / Packets)"
+msgstr "アップロード(Bytes / Packets)"
+
+msgid "Upload / Application"
+msgstr "アップロード / アプリケーション"
+
+msgid "Vendor: <big id=\"bubble-vendor\">Example Corp.</big>"
+msgstr "ベンダ: <big id=\"bubble-vendor\">Example Corp.</big>"
+
+msgid "Warning"
+msgstr "警告"
+
+msgid ""
+"Whether to gzip compress archive databases. Compressing the database files "
+"makes accessing old data slightly slower but helps to reduce storage "
+"requirements."
+msgstr ""
+"データベース㮠gzip 圧縮アーカイブ化ã§ã™ã€‚データベース ファイルを圧縮ã™ã‚‹ã¨å¤"
+"ã„データã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ãŒå¤šå°‘é…ããªã‚Šã¾ã™ãŒã€ã‚¹ãƒˆãƒ¬ãƒ¼ã‚¸ä½¿ç”¨é‡ã®ä½Žæ¸›ã«å½¹ç«‹ã¡ã¾"
+"ã™ã€‚"
+
+msgid ""
+"Whether to preallocate the maximum possible database size in memory. This is "
+"mainly useful for memory constrained systems which might not be able to "
+"satisfy memory allocation after longer uptime periods."
+msgstr ""
+
+msgid "no traffic"
+msgstr "トラフィック無ã—"
+
+msgid "other"
+msgstr "ãã®ä»–"
diff --git a/applications/luci-app-nlbwmon/po/templates/nlbwmon.pot b/applications/luci-app-nlbwmon/po/templates/nlbwmon.pot
new file mode 100644
index 0000000000..61d2230793
--- /dev/null
+++ b/applications/luci-app-nlbwmon/po/templates/nlbwmon.pot
@@ -0,0 +1,352 @@
+msgid ""
+msgstr "Content-Type: text/plain; charset=UTF-8"
+
+msgid "%d IPv4-only hosts"
+msgstr ""
+
+msgid "%d IPv6-only hosts"
+msgstr ""
+
+msgid "%d dual-stack hosts"
+msgstr ""
+
+msgid "%s and %s"
+msgstr ""
+
+msgid "%s, %s and %s"
+msgstr ""
+
+msgid "-1 - Restart every last day of month"
+msgstr ""
+
+msgid "-7 - Restart a week before end of month"
+msgstr ""
+
+msgid "1 - Restart every 1st of month"
+msgstr ""
+
+msgid "10m - frequent commits at the expense of flash wear"
+msgstr ""
+
+msgid "12h - compromise between risk of data loss and flash wear"
+msgstr ""
+
+msgid "24h - least flash wear at the expense of data loss risk"
+msgstr ""
+
+msgid "30s - refresh twice per minute for reasonably current stats"
+msgstr ""
+
+msgid "5m - rarely refresh to avoid frequently clearing conntrack counters"
+msgstr ""
+
+msgid "60s - commit minutely, useful for non-flash storage"
+msgstr ""
+
+msgid "<big id=\"conn-total\">0</big> connections"
+msgstr ""
+
+msgid "<big id=\"host-total\">0</big> hosts"
+msgstr ""
+
+msgid "<big id=\"ipv6-hosts\">0%</big> IPv6 support rate among hosts"
+msgstr ""
+
+msgid "<big id=\"ipv6-rx\">0B</big> total IPv6 download"
+msgstr ""
+
+msgid "<big id=\"ipv6-share\">0%</big> of the total traffic is IPv6"
+msgstr ""
+
+msgid "<big id=\"ipv6-tx\">0B</big> total IPv6 upload"
+msgstr ""
+
+msgid "<big id=\"layer7-most-conn\">0</big> cause the most connections"
+msgstr ""
+
+msgid "<big id=\"layer7-most-rx\">0</big> cause the most download"
+msgstr ""
+
+msgid "<big id=\"layer7-most-tx\">0</big> cause the most upload"
+msgstr ""
+
+msgid "<big id=\"layer7-total\">0</big> different application protocols"
+msgstr ""
+
+msgid "<big id=\"rx-total\">0</big> download"
+msgstr ""
+
+msgid "<big id=\"tx-total\">0</big> upload"
+msgstr ""
+
+msgid "Accounting period"
+msgstr ""
+
+msgid "Advanced Settings"
+msgstr ""
+
+msgid "Application"
+msgstr ""
+
+msgid "Application Protocols"
+msgstr ""
+
+msgid "Backup"
+msgstr ""
+
+msgid "Bandwidth Monitor"
+msgstr ""
+
+msgid "CSV, grouped by IP"
+msgstr ""
+
+msgid "CSV, grouped by MAC"
+msgstr ""
+
+msgid "CSV, grouped by protocol"
+msgstr ""
+
+msgid ""
+"Changing the accounting interval type will invalidate existing databases!"
+"<br /><strong><a href=\"%s\">Download backup</a></strong>."
+msgstr ""
+
+msgid ""
+"Choose \"Day of month\" to restart the accounting period monthly on a "
+"specific date, e.g. every 3rd. Choose \"Fixed interval\" to restart the "
+"accounting period exactly every N days, beginning at a given date."
+msgstr ""
+
+msgid "Commit interval"
+msgstr ""
+
+msgid "Compress database"
+msgstr ""
+
+msgid "Configuration"
+msgstr ""
+
+msgid "Conn."
+msgstr ""
+
+msgid "Connections"
+msgstr ""
+
+msgid "Connections / Host"
+msgstr ""
+
+msgid "Database directory"
+msgstr ""
+
+msgid ""
+"Database storage directory. One file per accounting period will be placed "
+"into this directory."
+msgstr ""
+
+msgid "Day of month"
+msgstr ""
+
+msgid ""
+"Day of month to restart the accounting period. Use negative values to count "
+"towards the end of month, e.g. \"-5\" to specify the 27th of July or the "
+"24th of Februrary."
+msgstr ""
+
+msgid "Display"
+msgstr ""
+
+msgid "Down. (Bytes / Pkts.)"
+msgstr ""
+
+msgid "Download (Bytes / Packets)"
+msgstr ""
+
+msgid "Download / Application"
+msgstr ""
+
+msgid "Download Database Backup"
+msgstr ""
+
+msgid "Dualstack enabled hosts"
+msgstr ""
+
+msgid "Due date"
+msgstr ""
+
+msgid "Export"
+msgstr ""
+
+msgid "Family"
+msgstr ""
+
+msgid "Fixed interval"
+msgstr ""
+
+msgid "Force reload…"
+msgstr ""
+
+msgid "General Settings"
+msgstr ""
+
+msgid "Generate Backup"
+msgstr ""
+
+msgid "Host"
+msgstr ""
+
+msgid "Hostname: <big id=\"bubble-hostname\">example.org</big>"
+msgstr ""
+
+msgid "IPv4 vs. IPv6"
+msgstr ""
+
+msgid "IPv6"
+msgstr ""
+
+msgid "Interval"
+msgstr ""
+
+msgid ""
+"Interval at which the temporary in-memory database is committed to the "
+"persistent database directory."
+msgstr ""
+
+msgid ""
+"Interval at which traffic counters of still established connections are "
+"refreshed from netlink information."
+msgstr ""
+
+msgid "Invalid or empty backup archive"
+msgstr ""
+
+msgid "JSON dump"
+msgstr ""
+
+msgid "Length of accounting interval in days."
+msgstr ""
+
+msgid "Local interfaces"
+msgstr ""
+
+msgid "Local subnets"
+msgstr ""
+
+msgid "MAC"
+msgstr ""
+
+msgid "Maximum entries"
+msgstr ""
+
+msgid ""
+"Maximum number of accounting periods to keep, use zero to keep databases "
+"forever."
+msgstr ""
+
+msgid "Netlink Bandwidth Monitor"
+msgstr ""
+
+msgid "Netlink Bandwidth Monitor - Backup / Restore"
+msgstr ""
+
+msgid "Netlink Bandwidth Monitor - Configuration"
+msgstr ""
+
+msgid "No data recorded yet."
+msgstr ""
+
+msgid "Only conntrack streams from or to any of these networks are counted."
+msgstr ""
+
+msgid "Only conntrack streams from or to any of these subnets are counted."
+msgstr ""
+
+msgid "Preallocate database"
+msgstr ""
+
+msgid "Protocol"
+msgstr ""
+
+msgid "Protocol Mapping"
+msgstr ""
+
+msgid ""
+"Protocol mappings to distinguish traffic types per host, one mapping per "
+"line. The first value specifies the IP protocol, the second value the port "
+"number and the third column is the name of the mapped protocol."
+msgstr ""
+
+msgid "Refresh interval"
+msgstr ""
+
+msgid "Restore"
+msgstr ""
+
+msgid "Restore Database Backup"
+msgstr ""
+
+msgid "Select accounting period:"
+msgstr ""
+
+msgid "Source IP"
+msgstr ""
+
+msgid "Start date"
+msgstr ""
+
+msgid "Start date of the first accounting period, e.g. begin of ISP contract."
+msgstr ""
+
+msgid "Stored periods"
+msgstr ""
+
+msgid ""
+"The Netlink Bandwidth Monitor (nlbwmon) is a lightweight, efficient traffic "
+"accounting program keeping track of bandwidth usage per host and protocol."
+msgstr ""
+
+msgid "The following database files have been restored: %s"
+msgstr ""
+
+msgid ""
+"The maximum amount of entries that should be put into the database, setting "
+"the limit to 0 will allow databases to grow indefinitely."
+msgstr ""
+
+msgid "Traffic / Host"
+msgstr ""
+
+msgid "Traffic Distribution"
+msgstr ""
+
+msgid "Up. (Bytes / Pkts.)"
+msgstr ""
+
+msgid "Upload (Bytes / Packets)"
+msgstr ""
+
+msgid "Upload / Application"
+msgstr ""
+
+msgid "Vendor: <big id=\"bubble-vendor\">Example Corp.</big>"
+msgstr ""
+
+msgid "Warning"
+msgstr ""
+
+msgid ""
+"Whether to gzip compress archive databases. Compressing the database files "
+"makes accessing old data slightly slower but helps to reduce storage "
+"requirements."
+msgstr ""
+
+msgid ""
+"Whether to preallocate the maximum possible database size in memory. This is "
+"mainly useful for memory constrained systems which might not be able to "
+"satisfy memory allocation after longer uptime periods."
+msgstr ""
+
+msgid "no traffic"
+msgstr ""
+
+msgid "other"
+msgstr ""
diff --git a/applications/luci-app-nlbwmon/po/zh-cn/nlbwmon.po b/applications/luci-app-nlbwmon/po/zh-cn/nlbwmon.po
new file mode 100644
index 0000000000..54fb3f6498
--- /dev/null
+++ b/applications/luci-app-nlbwmon/po/zh-cn/nlbwmon.po
@@ -0,0 +1,366 @@
+msgid ""
+msgstr "Content-Type: text/plain; charset=UTF-8\n"
+
+msgid "%d IPv4-only hosts"
+msgstr "%d ä¸ªä¸»æœºä»…æ”¯æŒ IPv4"
+
+msgid "%d IPv6-only hosts"
+msgstr "%d ä¸ªä¸»æœºä»…æ”¯æŒ IPv6"
+
+msgid "%d dual-stack hosts"
+msgstr "%d 个åŒå议栈主机"
+
+msgid "%s and %s"
+msgstr "%s 和 %s"
+
+msgid "%s, %s and %s"
+msgstr "%s, %s 和 %s"
+
+msgid "-1 - Restart every last day of month"
+msgstr "-1 - æ¯æœˆçš„最åŽä¸€å¤©é‡æ–°å¼€å§‹"
+
+msgid "-7 - Restart a week before end of month"
+msgstr "-7 - æ¯æœˆåº•å‰ä¸€å‘¨é‡æ–°å¼€å§‹"
+
+msgid "1 - Restart every 1st of month"
+msgstr "1 - æ¯æœˆçš„第一天é‡æ–°å¼€å§‹"
+
+msgid "10m - frequent commits at the expense of flash wear"
+msgstr "10m - 频ç¹æ交,闪存æŸè€—的开销也增大"
+
+msgid "12h - compromise between risk of data loss and flash wear"
+msgstr "12h - 平衡统计数æ®ä¸¢å¤±çš„风险以åŠé—ªå­˜ä½¿ç”¨å¯¿å‘½"
+
+msgid "24h - least flash wear at the expense of data loss risk"
+msgstr "24h - 以数æ®ä¸¢å¤±é£Žé™©çš„代价æ¢å–最å°çš„闪存æŸè€—"
+
+msgid "30s - refresh twice per minute for reasonably current stats"
+msgstr "30s - æ¯åˆ†é’Ÿåˆ·æ–°äºŒæ¬¡ä»¥èŽ·å¾—较准确的当å‰ç»Ÿè®¡å€¼"
+
+msgid "5m - rarely refresh to avoid frequently clearing conntrack counters"
+msgstr "5m - 较少刷新以é¿å…频ç¹æ¸…除连接跟踪计数器"
+
+msgid "60s - commit minutely, useful for non-flash storage"
+msgstr "60s - æ¯åˆ†é’Ÿæ交,适用于éžé—ªå­˜ç±»åž‹å­˜å‚¨"
+
+msgid "<big id=\"conn-total\">0</big> connections"
+msgstr "连接:<big id=\"conn-total\">0</big>"
+
+msgid "<big id=\"host-total\">0</big> hosts"
+msgstr "主机:<big id=\"host-total\">0</big>"
+
+msgid "<big id=\"ipv6-hosts\">0%</big> IPv6 support rate among hosts"
+msgstr "æ”¯æŒ IPv6 的主机比例:<big id=\"ipv6-hosts\">0%</big>"
+
+msgid "<big id=\"ipv6-rx\">0B</big> total IPv6 download"
+msgstr "IPv6 总下载é‡ï¼š<big id=\"ipv6-rx\">0B</big>"
+
+msgid "<big id=\"ipv6-share\">0%</big> of the total traffic is IPv6"
+msgstr "IPv6 æµé‡æ¯”例:<big id=\"ipv6-share\">0%</big>"
+
+msgid "<big id=\"ipv6-tx\">0B</big> total IPv6 upload"
+msgstr "IPv6 总上传é‡ï¼š<big id=\"ipv6-tx\">0B</big>"
+
+msgid "<big id=\"layer7-most-conn\">0</big> cause the most connections"
+msgstr "<big id=\"layer7-most-conn\">0</big> 是连接数最多的åè®®"
+
+msgid "<big id=\"layer7-most-rx\">0</big> cause the most download"
+msgstr "<big id=\"layer7-most-rx\">0</big> 是下载é‡æœ€å¤§çš„åè®®"
+
+msgid "<big id=\"layer7-most-tx\">0</big> cause the most upload"
+msgstr "<big id=\"layer7-most-tx\">0</big> 是上传é‡æœ€å¤§çš„åè®®"
+
+msgid "<big id=\"layer7-total\">0</big> different application protocols"
+msgstr "<big id=\"layer7-total\">0</big> ç§ä¸åŒçš„应用层åè®®"
+
+msgid "<big id=\"rx-total\">0</big> download"
+msgstr "下载:<big id=\"rx-total\">0</big>"
+
+msgid "<big id=\"tx-total\">0</big> upload"
+msgstr "上传:<big id=\"tx-total\">0</big>"
+
+msgid "Accounting period"
+msgstr "统计周期"
+
+msgid "Advanced Settings"
+msgstr "高级设置"
+
+msgid "Application"
+msgstr "应用层åè®®"
+
+msgid "Application Protocols"
+msgstr "应用层åè®®"
+
+msgid "Backup"
+msgstr "备份"
+
+msgid "Bandwidth Monitor"
+msgstr "带宽监控"
+
+msgid "CSV, grouped by IP"
+msgstr "CSV,按 IP 分组"
+
+msgid "CSV, grouped by MAC"
+msgstr "CSV,按 MAC 分组"
+
+msgid "CSV, grouped by protocol"
+msgstr "CSV,按å议分组"
+
+msgid ""
+"Changing the accounting interval type will invalidate existing databases!"
+"<br /><strong><a href=\"%s\">Download backup</a></strong>."
+msgstr ""
+"更改统计周期类型会使现有数æ®åº“无效ï¼<br /><strong><a href=\"%s\">下载备份</"
+"a></strong>."
+
+msgid ""
+"Choose \"Day of month\" to restart the accounting period monthly on a "
+"specific date, e.g. every 3rd. Choose \"Fixed interval\" to restart the "
+"accounting period exactly every N days, beginning at a given date."
+msgstr ""
+"选择“æ¯æœˆçš„æŸä¸€å¤©â€æ¥è®¾ç½®ç»Ÿè®¡å‘¨æœŸçš„é‡å¯æ—¶é—´ï¼Œä¾‹å¦‚:æ¯ä¸ªæœˆçš„第 3 天。选择“固定周"
+"期â€æ¥è®¾ç½®ä»Žç»™å®šæ—¥æœŸå¼€å§‹æ¯ N 天é‡å¯ç»Ÿè®¡å‘¨æœŸã€‚"
+
+msgid "Commit interval"
+msgstr "æ交间隔"
+
+msgid "Compress database"
+msgstr "压缩数æ®åº“"
+
+msgid "Configuration"
+msgstr "é…ç½®"
+
+msgid "Conn."
+msgstr "连接"
+
+msgid "Connections"
+msgstr "连接"
+
+msgid "Connections / Host"
+msgstr "连接 / 主机"
+
+msgid "Database directory"
+msgstr "æ•°æ®åº“目录"
+
+msgid ""
+"Database storage directory. One file per accounting period will be placed "
+"into this directory."
+msgstr "æ•°æ®åº“存储目录。æ¯ä¸ªâ€œç»Ÿè®¡å‘¨æœŸâ€çš„文件将被放到这个目录中。"
+
+msgid "Day of month"
+msgstr "æ¯æœˆçš„æŸä¸€å¤©"
+
+msgid ""
+"Day of month to restart the accounting period. Use negative values to count "
+"towards the end of month, e.g. \"-5\" to specify the 27th of July or the "
+"24th of Februrary."
+msgstr ""
+"æ¯ä¸ªæœˆé‡å¯ç»Ÿè®¡å‘¨æœŸçš„日期。使用负数表示从月底开始计算,例如:\"-5\" å¯ä»¥è¡¨"
+"示 7 月份的 27 å·æˆ–者 2 月份的 24 å·ã€‚"
+
+msgid "Display"
+msgstr "显示"
+
+msgid "Down. (Bytes / Pkts.)"
+msgstr "下载(字节 / æ•°æ®åŒ…)"
+
+msgid "Download (Bytes / Packets)"
+msgstr "下载(字节 / æ•°æ®åŒ…)"
+
+msgid "Download / Application"
+msgstr "下载 / 应用层åè®®"
+
+msgid "Download Database Backup"
+msgstr "下载数æ®åº“备份"
+
+msgid "Dualstack enabled hosts"
+msgstr "åŒå议栈主机"
+
+msgid "Due date"
+msgstr "é‡ç½®æ—¥æœŸ"
+
+msgid "Export"
+msgstr "导出"
+
+msgid "Family"
+msgstr "å议类型"
+
+msgid "Fixed interval"
+msgstr "固定周期"
+
+msgid "Force reload…"
+msgstr "强制é‡æ–°åŠ è½½..."
+
+msgid "General Settings"
+msgstr "基本设置"
+
+msgid "Generate Backup"
+msgstr "生æˆå¤‡ä»½"
+
+msgid "Host"
+msgstr "主机"
+
+msgid "Hostname: <big id=\"bubble-hostname\">example.org</big>"
+msgstr "主机å:<big id=\"bubble-hostname\">example.org</big>"
+
+msgid "IPv4 vs. IPv6"
+msgstr "IPv4 与 IPv6"
+
+msgid "IPv6"
+msgstr "IPv6"
+
+msgid "Interval"
+msgstr "周期"
+
+msgid ""
+"Interval at which the temporary in-memory database is committed to the "
+"persistent database directory."
+msgstr "将内存中的临时数æ®åº“æ交到æŒä¹…性数æ®åº“目录的间隔时间。"
+
+msgid ""
+"Interval at which traffic counters of still established connections are "
+"refreshed from netlink information."
+msgstr "从 netlink ä¿¡æ¯ä¸­åˆ·æ–°â€œå·²å»ºç«‹è¿žæŽ¥â€çš„æµé‡è®¡æ•°å™¨çš„间隔时间。"
+
+msgid "Invalid or empty backup archive"
+msgstr "备份存档无效或为空"
+
+msgid "JSON dump"
+msgstr "JSON 输出"
+
+msgid "Length of accounting interval in days."
+msgstr "统计周期(天)。"
+
+msgid "Local interfaces"
+msgstr "本地接å£"
+
+msgid "Local subnets"
+msgstr "本地å­ç½‘"
+
+msgid "MAC"
+msgstr "MAC"
+
+msgid "Maximum entries"
+msgstr "最大æ¡ç›®"
+
+msgid ""
+"Maximum number of accounting periods to keep, use zero to keep databases "
+"forever."
+msgstr "ä¿ç•™çš„统计周期数æ®åº“的最大数é‡ï¼Œè®¾ç½® 0 表示ä¸é™åˆ¶ã€‚"
+
+msgid "Netlink Bandwidth Monitor"
+msgstr "网络带宽监视器"
+
+msgid "Netlink Bandwidth Monitor - Backup / Restore"
+msgstr "网络带宽监视器 - 备份 / æ¢å¤"
+
+msgid "Netlink Bandwidth Monitor - Configuration"
+msgstr "网络带宽监视器 - é…ç½®"
+
+msgid "No data recorded yet."
+msgstr "æš‚æ— æ•°æ®è®°å½•ã€‚"
+
+msgid "Only conntrack streams from or to any of these networks are counted."
+msgstr "仅统计æ¥è‡ªæˆ–目标为这些网络接å£çš„连接æµé‡ã€‚"
+
+msgid "Only conntrack streams from or to any of these subnets are counted."
+msgstr "仅统计æ¥è‡ªæˆ–目标为这些å­ç½‘的连接æµé‡ã€‚"
+
+msgid "Preallocate database"
+msgstr "预分é…æ•°æ®åº“"
+
+msgid "Protocol"
+msgstr "åè®®"
+
+msgid "Protocol Mapping"
+msgstr "å议映射"
+
+msgid ""
+"Protocol mappings to distinguish traffic types per host, one mapping per "
+"line. The first value specifies the IP protocol, the second value the port "
+"number and the third column is the name of the mapped protocol."
+msgstr ""
+"å议映射用于区分æµé‡ç±»åž‹ï¼Œæ¯è¡Œä¸€æ¡ã€‚第一个值指定 IP å议类型,第二个值是"
+"端å£å·ï¼Œç¬¬ä¸‰ä¸ªå€¼æ˜¯æ˜ å°„çš„åè®®å称。"
+
+msgid "Refresh interval"
+msgstr "刷新间隔"
+
+msgid "Restore"
+msgstr "æ¢å¤"
+
+msgid "Restore Database Backup"
+msgstr "æ¢å¤æ•°æ®åº“备份"
+
+msgid "Select accounting period:"
+msgstr "选择统计周期:"
+
+msgid "Source IP"
+msgstr "æº IP"
+
+msgid "Start date"
+msgstr "起始日期"
+
+msgid "Start date of the first accounting period, e.g. begin of ISP contract."
+msgstr "第一个统计周期的起始日期,例如:ISP åˆçº¦çš„起始日期。"
+
+msgid "Stored periods"
+msgstr "储存周期"
+
+msgid ""
+"The Netlink Bandwidth Monitor (nlbwmon) is a lightweight, efficient traffic "
+"accounting program keeping track of bandwidth usage per host and protocol."
+msgstr ""
+"网络带宽监视器(nlbwmon)是一个轻é‡ã€é«˜æ•ˆçš„æµé‡ç»Ÿè®¡ç¨‹åºï¼Œå¯ä»¥ç»Ÿè®¡æ¯ä¸ªä¸»æœºå’Œ"
+"å议的带宽使用情况。"
+
+msgid "The following database files have been restored: %s"
+msgstr "以下数æ®åº“文件已æ¢å¤ï¼š%s"
+
+msgid ""
+"The maximum amount of entries that should be put into the database, setting "
+"the limit to 0 will allow databases to grow indefinitely."
+msgstr "æ•°æ®åº“中的最大æ¡ç›®æ•°é‡, 设置为 0 å°†å…许数æ®åº“æ— é™å¢žé•¿ã€‚"
+
+msgid "Traffic / Host"
+msgstr "æµé‡ / 主机"
+
+msgid "Traffic Distribution"
+msgstr "æµé‡åˆ†å¸ƒ"
+
+msgid "Up. (Bytes / Pkts.)"
+msgstr "上传(字节 / æ•°æ®åŒ…)"
+
+msgid "Upload (Bytes / Packets)"
+msgstr "上传(字节 / æ•°æ®åŒ…)"
+
+msgid "Upload / Application"
+msgstr "上传 / 应用层åè®®"
+
+msgid "Vendor: <big id=\"bubble-vendor\">Example Corp.</big>"
+msgstr "供应商: <big id=\"bubble-vendor\">Example Corp.</big>"
+
+msgid "Warning"
+msgstr "警告"
+
+msgid ""
+"Whether to gzip compress archive databases. Compressing the database files "
+"makes accessing old data slightly slower but helps to reduce storage "
+"requirements."
+msgstr ""
+"是å¦ä½¿ç”¨ gzip 压缩数æ®åº“存档。压缩数æ®åº“文件会使访问旧数æ®ç¨å¾®æ…¢ä¸€äº›, 但有助"
+"于å‡å°‘存储å ç”¨ç©ºé—´ã€‚"
+
+msgid ""
+"Whether to preallocate the maximum possible database size in memory. This is "
+"mainly useful for memory constrained systems which might not be able to "
+"satisfy memory allocation after longer uptime periods."
+msgstr ""
+"是å¦é¢„先分é…æ•°æ®åº“最大å¯èƒ½å ç”¨çš„内存大å°ã€‚这主è¦é€‚用于内存较å°ç³»ç»Ÿï¼Œè¿™äº›ç³»ç»Ÿ"
+"在长时间è¿è¡Œä¹‹åŽå¯èƒ½æ— æ³•æ»¡è¶³æ•°æ®åº“的内存需求。"
+
+msgid "no traffic"
+msgstr "æ— æµé‡æ•°æ®"
+
+msgid "other"
+msgstr "其他"
diff --git a/applications/luci-app-nlbwmon/root/etc/uci-defaults/40_luci-nlbwmon b/applications/luci-app-nlbwmon/root/etc/uci-defaults/40_luci-nlbwmon
new file mode 100644
index 0000000000..c9771779ee
--- /dev/null
+++ b/applications/luci-app-nlbwmon/root/etc/uci-defaults/40_luci-nlbwmon
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+uci -q batch <<-EOF >/dev/null
+ delete ucitrack.@nlbwmon[-1]
+ add ucitrack nlbwmon
+ set ucitrack.@nlbwmon[-1].init=nlbwmon
+ commit ucitrack
+EOF
+
+rm -f /tmp/luci-indexcache
+exit 0
diff --git a/applications/luci-app-shadowsocks-libev/luasrc/model/cbi/shadowsocks-libev/instance-details.lua b/applications/luci-app-shadowsocks-libev/luasrc/model/cbi/shadowsocks-libev/instance-details.lua
index d9a61d0bf7..22f3106d03 100644
--- a/applications/luci-app-shadowsocks-libev/luasrc/model/cbi/shadowsocks-libev/instance-details.lua
+++ b/applications/luci-app-shadowsocks-libev/luasrc/model/cbi/shadowsocks-libev/instance-details.lua
@@ -24,6 +24,7 @@ s:tab("general", translate("General Settings"))
s:tab("advanced", translate("Advanced Settings"))
s:taboption("general", Flag, "disabled", translate("Disable"))
ss.option_install_package(s, "general")
+ss.options_common(s, "advanced")
if stype == "ss_server" then
ss.options_server(s, "general")
@@ -42,8 +43,11 @@ else
translate("Tunnel address"),
translate("The address ss-tunnel will forward traffic to"))
o.datatype = "hostport"
+ elseif stype == "ss_redir" then
+ o = s:taboption("advanced", Flag, "disable_sni",
+ translate("Disable SNI"),
+ translate("Disable parsing HTTP/HTTPS payload to find then resolve hostname at remote server"))
end
end
-ss.options_common(s, "advanced")
return m
diff --git a/applications/luci-app-shadowsocks-libev/luasrc/model/shadowsocks-libev.lua b/applications/luci-app-shadowsocks-libev/luasrc/model/shadowsocks-libev.lua
index 2753f458b5..0a14f33554 100644
--- a/applications/luci-app-shadowsocks-libev/luasrc/model/shadowsocks-libev.lua
+++ b/applications/luci-app-shadowsocks-libev/luasrc/model/shadowsocks-libev.lua
@@ -108,6 +108,7 @@ function options_common(s, tab)
s:taboption(tab, Value, "user", translate("Run as"))
s:taboption(tab, Flag, "verbose", translate("Verbose"))
+ s:taboption(tab, Flag, "ipv6_first", translate("IPv6 First"), translate("Prefer IPv6 addresses when resolving names"))
s:taboption(tab, Flag, "fast_open", translate("Enable TCP Fast Open"))
s:taboption(tab, Flag, "reuse_port", translate("Enable SO_REUSEPORT"))
end
@@ -131,6 +132,8 @@ function cfgvalue_overview(sdata)
cfgvalue_overview_(sdata, lines, names_options_client)
if stype == "ss_tunnel" then
cfgvalue_overview_(sdata, lines, {"tunnel_address"})
+ elseif stype == "ss_redir" then
+ cfgvalue_overview_(sdata, lines, {"disable_sni"})
end
cfgvalue_overview_(sdata, lines, names_options_common)
else
@@ -153,6 +156,9 @@ function cfgvalue_overview_(sdata, lines, names)
for _, n in ipairs(names) do
local v = sdata[n]
if v ~= nil then
+ if n == "key" or n == "password" then
+ v = translate("<hidden>")
+ end
local fv = "<var>%s</var>" % ut.pcdata(v)
if sdata[".type"] ~= "ss_server" and n == "server" then
fv = '<a class="label" href="%s">%s</a>' % {
@@ -205,6 +211,7 @@ names_options_client = {
names_options_common = {
"verbose",
+ "ipv6_first",
"fast_open",
"reuse_port",
"mode",
@@ -247,7 +254,4 @@ methods = {
"salsa20",
"chacha20",
"chacha20-ietf",
- "aes-128-gcm",
- "aes-192-gcm",
- "aes-256-gcm",
}
diff --git a/applications/luci-app-statistics/po/ca/statistics.po b/applications/luci-app-statistics/po/ca/statistics.po
index 33d5051f44..738af5510f 100644
--- a/applications/luci-app-statistics/po/ca/statistics.po
+++ b/applications/luci-app-statistics/po/ca/statistics.po
@@ -15,6 +15,12 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Pootle 2.0.6\n"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr "Acció (objectiu)"
@@ -295,6 +301,9 @@ msgstr "Monitoritza els discs i les particions"
msgid "Monitor filesystem types"
msgstr "Monitoritza els tipus de sistema de fitxers"
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr "Monitoritza màquines"
@@ -381,6 +390,9 @@ msgstr "Configuració del connector ping"
msgid "Port"
msgstr "Port"
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr "Processos"
@@ -506,6 +518,9 @@ msgstr "TTL per paquets ping"
msgid "Table"
msgstr "Taula"
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr ""
diff --git a/applications/luci-app-statistics/po/cs/statistics.po b/applications/luci-app-statistics/po/cs/statistics.po
index 849831607c..fc3f513c5c 100644
--- a/applications/luci-app-statistics/po/cs/statistics.po
+++ b/applications/luci-app-statistics/po/cs/statistics.po
@@ -11,6 +11,12 @@ msgstr ""
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
"X-Generator: Pootle 2.0.6\n"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr "Akce (cíl)"
@@ -290,6 +296,9 @@ msgstr "Sledovat disky a oddíly"
msgid "Monitor filesystem types"
msgstr "Sledovat typy souborových systémů"
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr "Sledovat hostitele"
@@ -376,6 +385,9 @@ msgstr "Nastavení pluginu Ping"
msgid "Port"
msgstr "Port"
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr "Procesy"
@@ -500,6 +512,9 @@ msgstr "TTL pro pakety pingu"
msgid "Table"
msgstr ""
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr ""
diff --git a/applications/luci-app-statistics/po/de/statistics.po b/applications/luci-app-statistics/po/de/statistics.po
index 196433e503..45ba020ada 100644
--- a/applications/luci-app-statistics/po/de/statistics.po
+++ b/applications/luci-app-statistics/po/de/statistics.po
@@ -13,6 +13,12 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Pootle 2.0.6\n"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr "Aktion (Ziel)"
@@ -297,6 +303,9 @@ msgstr "Geräte und Partitionen überwachen"
msgid "Monitor filesystem types"
msgstr "Datesystemtypen überwachen"
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr "Hosts überwachen"
@@ -383,6 +392,9 @@ msgstr "Ping Plugin Konfiguration"
msgid "Port"
msgstr "Port"
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr "Prozesse"
@@ -506,6 +518,9 @@ msgstr "TTL für Ping Pakete"
msgid "Table"
msgstr "Tabelle"
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr ""
"Das NUT-Plugin liest Informationen über Unterbrechungsfreie Stromversorgungen"
diff --git a/applications/luci-app-statistics/po/el/statistics.po b/applications/luci-app-statistics/po/el/statistics.po
index da54cdac6c..4062868446 100644
--- a/applications/luci-app-statistics/po/el/statistics.po
+++ b/applications/luci-app-statistics/po/el/statistics.po
@@ -13,6 +13,12 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Pootle 2.0.4\n"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr ""
@@ -288,6 +294,9 @@ msgstr ""
msgid "Monitor filesystem types"
msgstr ""
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr ""
@@ -374,6 +383,9 @@ msgstr ""
msgid "Port"
msgstr ""
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr "ΔιεÏγασίες"
@@ -497,6 +509,9 @@ msgstr ""
msgid "Table"
msgstr "Πίνακας"
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr ""
diff --git a/applications/luci-app-statistics/po/en/statistics.po b/applications/luci-app-statistics/po/en/statistics.po
index d9ab59ce0a..f7ebfe0c2b 100644
--- a/applications/luci-app-statistics/po/en/statistics.po
+++ b/applications/luci-app-statistics/po/en/statistics.po
@@ -13,6 +13,12 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Translate Toolkit 1.1.1\n"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr "Action (target)"
@@ -293,6 +299,9 @@ msgstr "Monitor disks and partitions"
msgid "Monitor filesystem types"
msgstr "Monitor filesystem types"
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr "Monitor hosts"
@@ -379,6 +388,9 @@ msgstr "Ping Plugin Configuration"
msgid "Port"
msgstr ""
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr "Processes"
@@ -502,6 +514,9 @@ msgstr "TTL for ping packets"
msgid "Table"
msgstr "Table"
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr ""
diff --git a/applications/luci-app-statistics/po/es/statistics.po b/applications/luci-app-statistics/po/es/statistics.po
index 18c25819a6..3c811ffeff 100644
--- a/applications/luci-app-statistics/po/es/statistics.po
+++ b/applications/luci-app-statistics/po/es/statistics.po
@@ -13,6 +13,12 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Pootle 2.0.6\n"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr "Acción (objetivo)"
@@ -292,6 +298,9 @@ msgstr "Monitorizar discos y particiones"
msgid "Monitor filesystem types"
msgstr "Monitorizar tipos de sistema de archivos"
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr "Monitorizar máquinas"
@@ -378,6 +387,9 @@ msgstr "Configuración del plugin \"Ping\""
msgid "Port"
msgstr "Puerto"
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr "Procesos"
@@ -501,6 +513,9 @@ msgstr "TTL para paquetes de ping"
msgid "Table"
msgstr "Tabla"
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr ""
"El plugin NUT obtiene información sobre Sistemas de Alimentación "
diff --git a/applications/luci-app-statistics/po/fr/statistics.po b/applications/luci-app-statistics/po/fr/statistics.po
index b657bd38f0..bc156dd42a 100644
--- a/applications/luci-app-statistics/po/fr/statistics.po
+++ b/applications/luci-app-statistics/po/fr/statistics.po
@@ -13,6 +13,12 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Generator: Pootle 2.0.4\n"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr "Action (cible)"
@@ -294,6 +300,9 @@ msgstr "Disques et partitions à surveiller"
msgid "Monitor filesystem types"
msgstr "types de systèmes de fichier à surveiller"
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr "Hôtes à surveiller"
@@ -380,6 +389,9 @@ msgstr "Configuration du greffon Ping"
msgid "Port"
msgstr ""
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr "Processus"
@@ -503,6 +515,9 @@ msgstr "TTL des paquets ping"
msgid "Table"
msgstr "Table"
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr ""
diff --git a/applications/luci-app-statistics/po/he/statistics.po b/applications/luci-app-statistics/po/he/statistics.po
index 6f40a47a24..35f978ed20 100644
--- a/applications/luci-app-statistics/po/he/statistics.po
+++ b/applications/luci-app-statistics/po/he/statistics.po
@@ -13,6 +13,12 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Pootle 2.0.6\n"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr ""
@@ -283,6 +289,9 @@ msgstr ""
msgid "Monitor filesystem types"
msgstr ""
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr ""
@@ -369,6 +378,9 @@ msgstr ""
msgid "Port"
msgstr ""
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr ""
@@ -492,6 +504,9 @@ msgstr ""
msgid "Table"
msgstr ""
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr ""
diff --git a/applications/luci-app-statistics/po/hu/statistics.po b/applications/luci-app-statistics/po/hu/statistics.po
index 979c72f0f8..e5c4e601cb 100644
--- a/applications/luci-app-statistics/po/hu/statistics.po
+++ b/applications/luci-app-statistics/po/hu/statistics.po
@@ -11,6 +11,12 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Pootle 2.0.6\n"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr "Tevékenység (cél)"
@@ -295,6 +301,9 @@ msgstr "Lemezek és partíciók figyelése"
msgid "Monitor filesystem types"
msgstr "Fájlrendszer típusok figyelése"
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr "Gépek figyelése"
@@ -381,6 +390,9 @@ msgstr "Ping bővítmény beállítása"
msgid "Port"
msgstr "Port"
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr "Folyamatok"
@@ -508,6 +520,9 @@ msgstr "TTL a ping csomagokhoz"
msgid "Table"
msgstr "Táblázat"
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr "A NUT bővítmény a szünetmentes tápokról ad információkat."
diff --git a/applications/luci-app-statistics/po/it/statistics.po b/applications/luci-app-statistics/po/it/statistics.po
index b0ae3d6b76..2451503f23 100644
--- a/applications/luci-app-statistics/po/it/statistics.po
+++ b/applications/luci-app-statistics/po/it/statistics.po
@@ -13,6 +13,12 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Pootle 2.0.6\n"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr "Azione (destinazione)"
@@ -293,6 +299,9 @@ msgstr ""
msgid "Monitor filesystem types"
msgstr ""
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr ""
@@ -379,6 +388,9 @@ msgstr ""
msgid "Port"
msgstr ""
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr ""
@@ -502,6 +514,9 @@ msgstr ""
msgid "Table"
msgstr "Tabella"
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr ""
diff --git a/applications/luci-app-statistics/po/ja/statistics.po b/applications/luci-app-statistics/po/ja/statistics.po
index 690d9207d7..53941cf0f8 100644
--- a/applications/luci-app-statistics/po/ja/statistics.po
+++ b/applications/luci-app-statistics/po/ja/statistics.po
@@ -13,6 +13,12 @@ msgstr ""
"X-Generator: Poedit 1.8.11\n"
"Language-Team: \n"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr "アクション(対象)"
@@ -295,6 +301,9 @@ msgstr "ディスクã¨ãƒ‘ーティションをモニターã™ã‚‹"
msgid "Monitor filesystem types"
msgstr "ファイルシステム タイプをモニターã™ã‚‹"
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr "ホストをモニターã™ã‚‹"
@@ -384,6 +393,9 @@ msgstr "Ping プラグイン設定"
msgid "Port"
msgstr "ãƒãƒ¼ãƒˆ"
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr "プロセス"
@@ -507,6 +519,9 @@ msgstr "pingパケットã®TTL"
msgid "Table"
msgstr "テーブル"
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr "NUT プラグインã¯ã€ç„¡åœé›»é›»æºè£…ç½®ã«ã¤ã„ã¦ã®æƒ…報を読ã¿å–ã‚Šã¾ã™ã€‚"
diff --git a/applications/luci-app-statistics/po/ms/statistics.po b/applications/luci-app-statistics/po/ms/statistics.po
index 582314c545..c02556fc86 100644
--- a/applications/luci-app-statistics/po/ms/statistics.po
+++ b/applications/luci-app-statistics/po/ms/statistics.po
@@ -10,6 +10,12 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr ""
@@ -280,6 +286,9 @@ msgstr ""
msgid "Monitor filesystem types"
msgstr ""
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr ""
@@ -366,6 +375,9 @@ msgstr ""
msgid "Port"
msgstr ""
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr ""
@@ -489,6 +501,9 @@ msgstr ""
msgid "Table"
msgstr ""
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr ""
diff --git a/applications/luci-app-statistics/po/no/statistics.po b/applications/luci-app-statistics/po/no/statistics.po
index d37bc488f5..4de2ee6b55 100644
--- a/applications/luci-app-statistics/po/no/statistics.po
+++ b/applications/luci-app-statistics/po/no/statistics.po
@@ -4,6 +4,12 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr "Handling (mål)"
@@ -282,6 +288,9 @@ msgstr "Overvåk disker og partisjoner"
msgid "Monitor filesystem types"
msgstr "Overvåk filsystem typer"
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr "Overvåk verter"
@@ -368,6 +377,9 @@ msgstr "Ping plugin konfigurasjon"
msgid "Port"
msgstr ""
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr "Prosesser"
@@ -491,6 +503,9 @@ msgstr "TTL for ping pakker"
msgid "Table"
msgstr "Tabell"
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr ""
diff --git a/applications/luci-app-statistics/po/pl/statistics.po b/applications/luci-app-statistics/po/pl/statistics.po
index bf2ec93516..6e34ce0725 100644
--- a/applications/luci-app-statistics/po/pl/statistics.po
+++ b/applications/luci-app-statistics/po/pl/statistics.po
@@ -14,6 +14,12 @@ msgstr ""
"|| n%100>=20) ? 1 : 2);\n"
"X-Generator: Pootle 2.0.6\n"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr "Akcja (cel)"
@@ -296,6 +302,9 @@ msgstr "Monitoruj dyski i partycje"
msgid "Monitor filesystem types"
msgstr "Monitoruj system plików"
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr "Monitoruj hosty"
@@ -382,6 +391,9 @@ msgstr "Konfiguracja wtyczki Ping"
msgid "Port"
msgstr "Port"
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr "Procesy"
@@ -506,6 +518,9 @@ msgstr "TTL dla pakietów ping"
msgid "Table"
msgstr "Tabela"
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr "Wtyczka Nut Informuje o Nie przerywalnym Zasilaniu"
diff --git a/applications/luci-app-statistics/po/pt-br/statistics.po b/applications/luci-app-statistics/po/pt-br/statistics.po
index 74c4a2603f..c5d6899332 100644
--- a/applications/luci-app-statistics/po/pt-br/statistics.po
+++ b/applications/luci-app-statistics/po/pt-br/statistics.po
@@ -13,6 +13,12 @@ msgstr ""
"X-Generator: Poedit 1.8.11\n"
"Language-Team: \n"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr "Ação (destino)"
@@ -299,6 +305,9 @@ msgstr "Monitoras discos e partições"
msgid "Monitor filesystem types"
msgstr "Monitorar tipos de sistemas de arquivos"
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr "Monitorar os equipamentos"
@@ -388,6 +397,9 @@ msgstr "Configuração do plugin Ping"
msgid "Port"
msgstr "Porta"
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr "Processos"
@@ -511,6 +523,9 @@ msgstr "TTL para os pacotes do ping"
msgid "Table"
msgstr "Tabela"
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr "O plugin NUT lê informações sobre Fontes de alimentação ininterruptas."
diff --git a/applications/luci-app-statistics/po/pt/statistics.po b/applications/luci-app-statistics/po/pt/statistics.po
index 79c7bd03e6..245e6e9bf9 100644
--- a/applications/luci-app-statistics/po/pt/statistics.po
+++ b/applications/luci-app-statistics/po/pt/statistics.po
@@ -13,6 +13,12 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Pootle 2.0.6\n"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr "Ação (destino)"
@@ -295,6 +301,9 @@ msgstr "Monitoras discos e partições"
msgid "Monitor filesystem types"
msgstr "Monitorar tipos de sistemas de arquivos"
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr "Monitorar os hosts"
@@ -381,6 +390,9 @@ msgstr "Configuração do plugin Ping"
msgid "Port"
msgstr "Porta"
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr "Processos"
@@ -504,6 +516,9 @@ msgstr "TTL para os pacotes do ping"
msgid "Table"
msgstr "Tabela"
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr ""
diff --git a/applications/luci-app-statistics/po/ro/statistics.po b/applications/luci-app-statistics/po/ro/statistics.po
index c5dfcfe558..a326fec799 100644
--- a/applications/luci-app-statistics/po/ro/statistics.po
+++ b/applications/luci-app-statistics/po/ro/statistics.po
@@ -14,6 +14,12 @@ msgstr ""
"20)) ? 1 : 2);;\n"
"X-Generator: Pootle 2.0.4\n"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr ""
@@ -287,6 +293,9 @@ msgstr ""
msgid "Monitor filesystem types"
msgstr ""
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr ""
@@ -373,6 +382,9 @@ msgstr ""
msgid "Port"
msgstr ""
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr "Procese"
@@ -496,6 +508,9 @@ msgstr ""
msgid "Table"
msgstr ""
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr ""
diff --git a/applications/luci-app-statistics/po/ru/statistics.po b/applications/luci-app-statistics/po/ru/statistics.po
index 3a418dec75..9d0ff9fdf2 100644
--- a/applications/luci-app-statistics/po/ru/statistics.po
+++ b/applications/luci-app-statistics/po/ru/statistics.po
@@ -15,6 +15,12 @@ msgstr ""
"X-Generator: Pootle 2.0.6\n"
"X-Poedit-SourceCharset: UTF-8\n"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr "ДейÑтвие (цель)"
@@ -297,6 +303,9 @@ msgstr "Собирать ÑтатиÑтику Ñ Ð´Ð¸Ñков и разделоÐ
msgid "Monitor filesystem types"
msgstr "Собирать ÑтатиÑтику Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð²Ñ‹Ñ… ÑиÑтем"
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr "Собирать ÑтатиÑтику Ñ Ñ…Ð¾Ñтов"
@@ -383,6 +392,9 @@ msgstr "ÐšÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñ Ð¼Ð¾Ð´ÑƒÐ»Ñ Ping"
msgid "Port"
msgstr "Порт"
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr "ПроцеÑÑÑ‹"
@@ -508,6 +520,9 @@ msgstr "TTL Ð´Ð»Ñ ping-пакетов"
msgid "Table"
msgstr "Таблица"
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr ""
diff --git a/applications/luci-app-statistics/po/sk/statistics.po b/applications/luci-app-statistics/po/sk/statistics.po
index 6dba7d09b8..53858ca540 100644
--- a/applications/luci-app-statistics/po/sk/statistics.po
+++ b/applications/luci-app-statistics/po/sk/statistics.po
@@ -8,6 +8,12 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr ""
@@ -278,6 +284,9 @@ msgstr ""
msgid "Monitor filesystem types"
msgstr ""
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr ""
@@ -364,6 +373,9 @@ msgstr ""
msgid "Port"
msgstr ""
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr ""
@@ -487,6 +499,9 @@ msgstr ""
msgid "Table"
msgstr ""
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr ""
diff --git a/applications/luci-app-statistics/po/sv/statistics.po b/applications/luci-app-statistics/po/sv/statistics.po
index bef0f2d6c9..9d738f2f33 100644
--- a/applications/luci-app-statistics/po/sv/statistics.po
+++ b/applications/luci-app-statistics/po/sv/statistics.po
@@ -9,6 +9,12 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr ""
@@ -283,6 +289,9 @@ msgstr "Övervaka hårddiskar och partitioner"
msgid "Monitor filesystem types"
msgstr "Övervaka filsystemtyper"
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr "Övervaka värdar"
@@ -369,6 +378,9 @@ msgstr ""
msgid "Port"
msgstr "Port"
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr "Processer"
@@ -492,6 +504,9 @@ msgstr "TTL för ping-paket"
msgid "Table"
msgstr "Tabell"
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr ""
diff --git a/applications/luci-app-statistics/po/templates/statistics.pot b/applications/luci-app-statistics/po/templates/statistics.pot
index c57a85b76a..ec630b6962 100644
--- a/applications/luci-app-statistics/po/templates/statistics.pot
+++ b/applications/luci-app-statistics/po/templates/statistics.pot
@@ -1,6 +1,12 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr ""
@@ -271,6 +277,9 @@ msgstr ""
msgid "Monitor filesystem types"
msgstr ""
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr ""
@@ -357,6 +366,9 @@ msgstr ""
msgid "Port"
msgstr ""
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr ""
@@ -480,6 +492,9 @@ msgstr ""
msgid "Table"
msgstr ""
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr ""
diff --git a/applications/luci-app-statistics/po/tr/statistics.po b/applications/luci-app-statistics/po/tr/statistics.po
index 6d7056f3b7..860ff95e88 100644
--- a/applications/luci-app-statistics/po/tr/statistics.po
+++ b/applications/luci-app-statistics/po/tr/statistics.po
@@ -9,6 +9,12 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr ""
@@ -279,6 +285,9 @@ msgstr ""
msgid "Monitor filesystem types"
msgstr ""
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr ""
@@ -365,6 +374,9 @@ msgstr ""
msgid "Port"
msgstr ""
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr ""
@@ -488,6 +500,9 @@ msgstr ""
msgid "Table"
msgstr ""
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr ""
diff --git a/applications/luci-app-statistics/po/uk/statistics.po b/applications/luci-app-statistics/po/uk/statistics.po
index de17a3caf8..ac9ae50940 100644
--- a/applications/luci-app-statistics/po/uk/statistics.po
+++ b/applications/luci-app-statistics/po/uk/statistics.po
@@ -14,6 +14,12 @@ msgstr ""
"10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
"X-Generator: Pootle 2.0.6\n"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr ""
@@ -284,6 +290,9 @@ msgstr ""
msgid "Monitor filesystem types"
msgstr ""
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr ""
@@ -370,6 +379,9 @@ msgstr ""
msgid "Port"
msgstr ""
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr ""
@@ -493,6 +505,9 @@ msgstr ""
msgid "Table"
msgstr ""
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr ""
diff --git a/applications/luci-app-statistics/po/vi/statistics.po b/applications/luci-app-statistics/po/vi/statistics.po
index bdb7f1a3a1..f5798a2651 100644
--- a/applications/luci-app-statistics/po/vi/statistics.po
+++ b/applications/luci-app-statistics/po/vi/statistics.po
@@ -14,6 +14,12 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Pootle 1.1.0\n"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr "Action (target)"
@@ -294,6 +300,9 @@ msgstr "Kiểm soát đĩa và phân vùng"
msgid "Monitor filesystem types"
msgstr "Kiểm soát loại filesystem"
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr "Monitor hosts"
@@ -380,6 +389,9 @@ msgstr "Cấu hình Ping plugin"
msgid "Port"
msgstr ""
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr "Quá trình xử lý"
@@ -503,6 +515,9 @@ msgstr "TTl cho gói ping"
msgid "Table"
msgstr "Table"
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr ""
diff --git a/applications/luci-app-statistics/po/zh-cn/statistics.po b/applications/luci-app-statistics/po/zh-cn/statistics.po
index 46cf59feed..20f5a93cb4 100644
--- a/applications/luci-app-statistics/po/zh-cn/statistics.po
+++ b/applications/luci-app-statistics/po/zh-cn/statistics.po
@@ -13,6 +13,12 @@ msgstr ""
"X-Generator: Poedit 2.0.1\n"
"Language-Team: \n"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr "动作(目标)"
@@ -289,6 +295,9 @@ msgstr "监测ç£ç›˜å’Œåˆ†åŒº"
msgid "Monitor filesystem types"
msgstr "监测文件系统类型"
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr "监测主机"
@@ -377,6 +386,9 @@ msgstr "Pingæ’件é…ç½®"
msgid "Port"
msgstr "端å£"
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr "进程"
@@ -500,6 +512,9 @@ msgstr "ping包TTL"
msgid "Table"
msgstr "表"
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr "NUTæ’件读å–UPSä¿¡æ¯ã€‚"
diff --git a/applications/luci-app-statistics/po/zh-tw/statistics.po b/applications/luci-app-statistics/po/zh-tw/statistics.po
index cbd6d9d38e..36e42c1d09 100644
--- a/applications/luci-app-statistics/po/zh-tw/statistics.po
+++ b/applications/luci-app-statistics/po/zh-tw/statistics.po
@@ -7,6 +7,12 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Transfer-Encoding: 8bit\n"
+msgid "APC UPS"
+msgstr ""
+
+msgid "APCUPS Plugin Configuration"
+msgstr ""
+
msgid "Action (target)"
msgstr ""
@@ -277,6 +283,9 @@ msgstr ""
msgid "Monitor filesystem types"
msgstr ""
+msgid "Monitor host"
+msgstr ""
+
msgid "Monitor hosts"
msgstr ""
@@ -363,6 +372,9 @@ msgstr ""
msgid "Port"
msgstr ""
+msgid "Port for apcupsd communication"
+msgstr ""
+
msgid "Processes"
msgstr ""
@@ -486,6 +498,9 @@ msgstr ""
msgid "Table"
msgstr ""
+msgid "The APCUPS plugin collects statistics about the APC UPS."
+msgstr ""
+
msgid "The NUT plugin reads information about Uninterruptible Power Supplies."
msgstr ""
diff --git a/applications/luci-app-travelmate/po/ja/travelmate.po b/applications/luci-app-travelmate/po/ja/travelmate.po
index bd1d54739c..70561533d4 100644
--- a/applications/luci-app-travelmate/po/ja/travelmate.po
+++ b/applications/luci-app-travelmate/po/ja/travelmate.po
@@ -12,6 +12,9 @@ msgstr ""
"Plural-Forms: nplurals=1; plural=0;\n"
"Language: ja\n"
+msgid "Actions"
+msgstr "æ“作"
+
msgid "Add Interface"
msgstr "インターフェースã®è¿½åŠ "
@@ -58,9 +61,6 @@ msgstr "ã“ã®ã‚¢ãƒƒãƒ—リンクを削除"
msgid "Device"
msgstr "デãƒã‚¤ã‚¹"
-msgid "Disabled"
-msgstr "無効"
-
msgid "Edit"
msgstr "編集"
@@ -124,18 +124,31 @@ msgstr "インターフェース タイムアウト"
msgid "Interface Wizard"
msgstr "インターフェース ウィザード"
-msgid "Keep travelmate in an active state."
-msgstr "Travelmate をアクティブ状態ã§ç¶­æŒã—ã¾ã™ã€‚"
+msgid ""
+"Keep travelmate in an active state. Check every n seconds the connection "
+"status, i.e. the uplink availability."
+msgstr ""
+"Travelmate をアクティブ状態ã§ç¶­æŒã—ã¾ã™ã€‚\"実行間隔\" ã§è¨­å®šã•ã‚ŒãŸæ™‚間毎"
+"(秒)ã«ã€ã‚¢ãƒƒãƒ—リンクã®å¯ç”¨æ€§ã‚’確èªã™ã‚‹ãŸã‚ã«æŽ¥ç¶šçŠ¶æ…‹ã‚’ãƒã‚§ãƒƒã‚¯ã—ã¾ã™"
msgid "Last rundate"
msgstr "最終実行日時"
-msgid "Mode"
-msgstr "モード"
+msgid "Manual Rescan"
+msgstr "手動å†ã‚¹ã‚­ãƒ£ãƒ³"
-msgid "Name of the uplink interface that triggers travelmate processing."
+msgid "Move down"
+msgstr "下ã¸"
+
+msgid "Move up"
+msgstr "上ã¸"
+
+msgid ""
+"Name of the uplink interface that triggers travelmate processing in 'manual' "
+"mode."
msgstr ""
-"Travelmate ã®å‡¦ç†ã®ãƒˆãƒªã‚¬ãƒ¼ã¨ãªã‚‹ã€ã‚¢ãƒƒãƒ—リンク インターフェースã®åå‰ã§ã™ã€‚"
+"'manual' モード時㫠Travelmate ã®å‡¦ç†ã®ãƒˆãƒªã‚¬ãƒ¼ã¨ãªã‚‹ã€ã‚¢ãƒƒãƒ—リンク インター"
+"フェースã®åå‰ã§ã™ã€‚"
msgid "Online Status"
msgstr "オンライン ステータス"
@@ -148,7 +161,7 @@ msgid ""
msgstr "デフォルトã®è¨­å®šãŒé©åˆ‡ã§ãªã„å ´åˆã€ã•ã‚‰ã«è¨­å®šã™ã‚‹ãŸã‚ã®ã‚ªãƒ—ションã§ã™ã€‚"
msgid "Overall Timeout"
-msgstr "全体タイムアウト"
+msgstr "実行間隔"
msgid "Overview"
msgstr "概è¦"
@@ -157,12 +170,14 @@ msgid "Passphrase (%s)"
msgstr "æš—å·ãƒ•ãƒ¬ãƒ¼ã‚º (%s)"
msgid ""
-"Provides an overview of all configured uplink interfaces for travelmate. You "
-"can edit and delete existing interfaces or scan for new uplinks."
+"Provides an overview of all configured uplinks for the travelmate interface "
+"(%s). You can edit, delete or re-order existing uplinks or scan for a new "
+"one. The currently used uplink is emphasized in blue."
msgstr ""
-"Travelmate ã«ãŠã‘ã‚‹ã€å…¨ã¦ã®è¨­å®šæ¸ˆã¿ã‚¢ãƒƒãƒ—リンク インターフェースã®ä¸€è¦§ã§ã™ã€‚"
-"既存ã®ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ãƒ¼ã‚¹ã‚’編集ã¾ãŸã¯å‰Šé™¤ã—ãŸã‚Šã€æ–°è¦ã‚¢ãƒƒãƒ—リンクã®è¿½åŠ ã®ãŸã‚ã«"
-"スキャンを行ã†ã“ã¨ãŒã§ãã¾ã™ã€‚"
+"Travelmate 用インターフェース(%s)ã«è¨­å®šæ¸ˆã¿ã®å…¨ã‚¢ãƒƒãƒ—リンクã®ä¸€è¦§ã§ã™ã€‚既存"
+"ã®ã‚¢ãƒƒãƒ—リンクã®ç·¨é›†ã‚„削除ã€ä¸¦ã¹æ›¿ãˆã‚’è¡Œã£ãŸã‚Šã€ã‚¹ã‚­ãƒ£ãƒ³ã‚’è¡Œã£ã¦æ–°è¦ã‚¢ãƒƒãƒ—リ"
+"ンクを追加ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ç¾åœ¨ä½¿ç”¨ã•ã‚Œã¦ã„るアップリンクã¯ã€é’色ã§å¼·èª¿ã•"
+"ã‚Œã¾ã™ã€‚"
msgid "Radio selection"
msgstr "ç„¡ç·šã®é¸æŠž"
@@ -170,8 +185,11 @@ msgstr "ç„¡ç·šã®é¸æŠž"
msgid "Repeat scan"
msgstr "å†ã‚¹ã‚­ãƒ£ãƒ³"
+msgid "Rescan"
+msgstr "å†ã‚¹ã‚­ãƒ£ãƒ³"
+
msgid "Restrict travelmate to a dedicated radio, e.g. 'radio0'"
-msgstr "Travelmate ãŒç‰¹å®šã®ç„¡ç·šã«æŽ¥ç¶šã™ã‚‹ã‚ˆã†ã«ã—ã¾ã™ã€‚例: 'radio0'"
+msgstr "Travelmate ãŒæŒ‡å®šã•ã‚ŒãŸç„¡ç·šã«æŽ¥ç¶šã™ã‚‹ã‚ˆã†åˆ¶é™ã—ã¾ã™ã€‚例: 'radio0'"
msgid "Runtime information"
msgstr "実行情報"
@@ -179,6 +197,12 @@ msgstr "実行情報"
msgid "SSID"
msgstr "SSID"
+msgid "SSID (hidden)"
+msgstr "SSID(ステルス)"
+
+msgid "Save"
+msgstr "ä¿å­˜"
+
msgid "Scan"
msgstr "スキャン:"
@@ -233,7 +257,7 @@ msgstr ""
"ã‚Œã¾ã™ã€‚"
msgid "Timeout in seconds between retries in 'automatic' mode"
-msgstr "'automatic' モード時ã«æŽ¥ç¶šã‚’å†è©¦è¡Œã™ã‚‹é–“隔(秒)ã§ã™ã€‚"
+msgstr "'automatic' モード時ã«æŽ¥ç¶šã‚’確èªã¾ãŸã¯å†è©¦è¡Œã™ã‚‹é–“隔(秒)ã§ã™ã€‚"
msgid "Travelmate"
msgstr "Travelmate"
@@ -251,10 +275,7 @@ msgid "Unknown"
msgstr "ä¸æ˜Ž"
msgid "Uplink / Trigger interface"
-msgstr "アップリンク/トリガー インターフェース"
-
-msgid "Uplink Interface"
-msgstr "アップリンク インターフェース"
+msgstr "アップリンク / トリガー インターフェース"
msgid "Uplink SSID"
msgstr "アップリンク SSID"
diff --git a/applications/luci-app-travelmate/po/pt-br/travelmate.po b/applications/luci-app-travelmate/po/pt-br/travelmate.po
index 5e09759c4a..282dda8dad 100644
--- a/applications/luci-app-travelmate/po/pt-br/travelmate.po
+++ b/applications/luci-app-travelmate/po/pt-br/travelmate.po
@@ -12,6 +12,9 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"Language: pt_BR\n"
+msgid "Actions"
+msgstr ""
+
msgid "Add Interface"
msgstr ""
@@ -55,9 +58,6 @@ msgstr ""
msgid "Device"
msgstr ""
-msgid "Disabled"
-msgstr ""
-
msgid "Edit"
msgstr ""
@@ -117,16 +117,26 @@ msgstr ""
msgid "Interface Wizard"
msgstr ""
-msgid "Keep travelmate in an active state."
+msgid ""
+"Keep travelmate in an active state. Check every n seconds the connection "
+"status, i.e. the uplink availability."
msgstr ""
msgid "Last rundate"
msgstr ""
-msgid "Mode"
+msgid "Manual Rescan"
+msgstr ""
+
+msgid "Move down"
+msgstr ""
+
+msgid "Move up"
msgstr ""
-msgid "Name of the uplink interface that triggers travelmate processing."
+msgid ""
+"Name of the uplink interface that triggers travelmate processing in 'manual' "
+"mode."
msgstr ""
msgid "Online Status"
@@ -149,8 +159,9 @@ msgid "Passphrase (%s)"
msgstr ""
msgid ""
-"Provides an overview of all configured uplink interfaces for travelmate. You "
-"can edit and delete existing interfaces or scan for new uplinks."
+"Provides an overview of all configured uplinks for the travelmate interface "
+"(%s). You can edit, delete or re-order existing uplinks or scan for a new "
+"one. The currently used uplink is emphasized in blue."
msgstr ""
msgid "Radio selection"
@@ -159,6 +170,9 @@ msgstr ""
msgid "Repeat scan"
msgstr ""
+msgid "Rescan"
+msgstr ""
+
msgid "Restrict travelmate to a dedicated radio, e.g. 'radio0'"
msgstr ""
@@ -168,6 +182,12 @@ msgstr ""
msgid "SSID"
msgstr ""
+msgid "SSID (hidden)"
+msgstr ""
+
+msgid "Save"
+msgstr ""
+
msgid "Scan"
msgstr ""
@@ -232,9 +252,6 @@ msgstr ""
msgid "Uplink / Trigger interface"
msgstr ""
-msgid "Uplink Interface"
-msgstr ""
-
msgid "Uplink SSID"
msgstr ""
diff --git a/applications/luci-app-travelmate/po/templates/travelmate.pot b/applications/luci-app-travelmate/po/templates/travelmate.pot
index a0e5629696..2190055683 100644
--- a/applications/luci-app-travelmate/po/templates/travelmate.pot
+++ b/applications/luci-app-travelmate/po/templates/travelmate.pot
@@ -1,6 +1,9 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
+msgid "Actions"
+msgstr ""
+
msgid "Add Interface"
msgstr ""
@@ -44,9 +47,6 @@ msgstr ""
msgid "Device"
msgstr ""
-msgid "Disabled"
-msgstr ""
-
msgid "Edit"
msgstr ""
@@ -106,16 +106,26 @@ msgstr ""
msgid "Interface Wizard"
msgstr ""
-msgid "Keep travelmate in an active state."
+msgid ""
+"Keep travelmate in an active state. Check every n seconds the connection "
+"status, i.e. the uplink availability."
msgstr ""
msgid "Last rundate"
msgstr ""
-msgid "Mode"
+msgid "Manual Rescan"
+msgstr ""
+
+msgid "Move down"
+msgstr ""
+
+msgid "Move up"
msgstr ""
-msgid "Name of the uplink interface that triggers travelmate processing."
+msgid ""
+"Name of the uplink interface that triggers travelmate processing in 'manual' "
+"mode."
msgstr ""
msgid "Online Status"
@@ -138,8 +148,9 @@ msgid "Passphrase (%s)"
msgstr ""
msgid ""
-"Provides an overview of all configured uplink interfaces for travelmate. You "
-"can edit and delete existing interfaces or scan for new uplinks."
+"Provides an overview of all configured uplinks for the travelmate interface "
+"(%s). You can edit, delete or re-order existing uplinks or scan for a new "
+"one. The currently used uplink is emphasized in blue."
msgstr ""
msgid "Radio selection"
@@ -148,6 +159,9 @@ msgstr ""
msgid "Repeat scan"
msgstr ""
+msgid "Rescan"
+msgstr ""
+
msgid "Restrict travelmate to a dedicated radio, e.g. 'radio0'"
msgstr ""
@@ -157,6 +171,12 @@ msgstr ""
msgid "SSID"
msgstr ""
+msgid "SSID (hidden)"
+msgstr ""
+
+msgid "Save"
+msgstr ""
+
msgid "Scan"
msgstr ""
@@ -221,9 +241,6 @@ msgstr ""
msgid "Uplink / Trigger interface"
msgstr ""
-msgid "Uplink Interface"
-msgstr ""
-
msgid "Uplink SSID"
msgstr ""
diff --git a/applications/luci-app-watchcat/po/sv/watchcat.po b/applications/luci-app-watchcat/po/sv/watchcat.po
index 07aa726493..96c73e3111 100644
--- a/applications/luci-app-watchcat/po/sv/watchcat.po
+++ b/applications/luci-app-watchcat/po/sv/watchcat.po
@@ -19,8 +19,8 @@ msgid ""
"How often to check internet connection. Default unit is seconds, you can you "
"use the suffix 'm' for minutes, 'h' for hours or 'd' for days"
msgstr ""
-"Hur ofta internet-anslutningen ska kollas. Standardenheten är sekunder, du kan använda "
-"tillägget 'm' för minutrar, 't' för timmar eller 'd' för dagar"
+"Hur ofta internet-anslutningen ska kollas. Standardenheten är sekunder, du "
+"kan använda tillägget 'm' för minutrar, 't' för timmar eller 'd' för dagar"
msgid ""
"In periodic mode, it defines the reboot period. In internet mode, it defines "
diff --git a/applications/luci-app-wifischedule/po/sv/wifischedule.po b/applications/luci-app-wifischedule/po/sv/wifischedule.po
index ca4e5aac78..50953aa285 100644
--- a/applications/luci-app-wifischedule/po/sv/wifischedule.po
+++ b/applications/luci-app-wifischedule/po/sv/wifischedule.po
@@ -1,5 +1,5 @@
msgid ""
-msgstr "Content-Type: text/plain; charset=UTF-8"
+msgstr "Content-Type: text/plain; charset=UTF-8\n"
msgid "Activate wifi"
msgstr "Aktivera wifi"
diff --git a/applications/luci-app-wireguard/po/sv/wireguard.po b/applications/luci-app-wireguard/po/sv/wireguard.po
index b7e3ed5b58..1aa68e251e 100644
--- a/applications/luci-app-wireguard/po/sv/wireguard.po
+++ b/applications/luci-app-wireguard/po/sv/wireguard.po
@@ -1,5 +1,5 @@
msgid ""
-msgstr "Content-Type: text/plain; charset=UTF-8"
+msgstr "Content-Type: text/plain; charset=UTF-8\n"
msgid "Allowed IPs"
msgstr "Tillåtna IP-adresser"
diff --git a/modules/luci-base/htdocs/luci-static/resources/cbi.js b/modules/luci-base/htdocs/luci-static/resources/cbi.js
index 4be917d098..b819230cf3 100644
--- a/modules/luci-base/htdocs/luci-static/resources/cbi.js
+++ b/modules/luci-base/htdocs/luci-static/resources/cbi.js
@@ -481,8 +481,9 @@ function cbi_d_check(deps) {
istat = (istat && cbi_d_checkvalue(j, deps[i][j]))
}
}
- if (istat) {
- return !reverse;
+
+ if (istat ^ reverse) {
+ return true;
}
}
return def;
@@ -648,9 +649,6 @@ function cbi_combobox(id, values, def, man, focus) {
var dt = obj.getAttribute('cbi_datatype');
var op = obj.getAttribute('cbi_optional');
- if (dt)
- cbi_validate_field(sel, op == 'true', dt);
-
if (!values[obj.value]) {
if (obj.value == "") {
var optdef = document.createElement("option");
@@ -685,6 +683,9 @@ function cbi_combobox(id, values, def, man, focus) {
obj.style.display = "none";
+ if (dt)
+ cbi_validate_field(sel, op == 'true', dt);
+
cbi_bind(sel, "change", function() {
if (sel.selectedIndex == sel.options.length - 1) {
obj.style.display = "inline";
diff --git a/modules/luci-base/htdocs/luci-static/resources/xhr.js b/modules/luci-base/htdocs/luci-static/resources/xhr.js
index 701c12ac19..3385f8f230 100644
--- a/modules/luci-base/htdocs/luci-static/resources/xhr.js
+++ b/modules/luci-base/htdocs/luci-static/resources/xhr.js
@@ -91,8 +91,6 @@ XHR = function()
xhr.open('POST', url, true);
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
- xhr.setRequestHeader('Content-length', code.length);
- xhr.setRequestHeader('Connection', 'close');
xhr.send(code);
}
diff --git a/modules/luci-base/luasrc/sys.lua b/modules/luci-base/luasrc/sys.lua
index 99f3ee2919..115c54d54a 100644
--- a/modules/luci-base/luasrc/sys.lua
+++ b/modules/luci-base/luasrc/sys.lua
@@ -348,8 +348,10 @@ end
function net.devices()
local devs = {}
+ local seen = {}
for k, v in ipairs(nixio.getifaddrs()) do
- if v.family == "packet" then
+ if v.name and not seen[v.name] then
+ seen[v.name] = true
devs[#devs+1] = v.name
end
end
diff --git a/modules/luci-base/po/ca/base.po b/modules/luci-base/po/ca/base.po
index 9f4efdd1f1..0486ec2502 100644
--- a/modules/luci-base/po/ca/base.po
+++ b/modules/luci-base/po/ca/base.po
@@ -2342,6 +2342,9 @@ msgstr ""
msgid "Password successfully changed!"
msgstr "La contrasenya s'ha canviat amb èxit!"
+msgid "Password2"
+msgstr ""
+
msgid "Path to CA-Certificate"
msgstr "Ruta als Certificats CA"
diff --git a/modules/luci-base/po/cs/base.po b/modules/luci-base/po/cs/base.po
index 9efe3b7d8e..c217b0c394 100644
--- a/modules/luci-base/po/cs/base.po
+++ b/modules/luci-base/po/cs/base.po
@@ -2365,6 +2365,9 @@ msgstr ""
msgid "Password successfully changed!"
msgstr "Heslo bylo úspěšně změněno!"
+msgid "Password2"
+msgstr ""
+
msgid "Path to CA-Certificate"
msgstr "Cesta k certifikátu CA"
diff --git a/modules/luci-base/po/de/base.po b/modules/luci-base/po/de/base.po
index fa26a1d72e..183e495a22 100644
--- a/modules/luci-base/po/de/base.po
+++ b/modules/luci-base/po/de/base.po
@@ -2427,6 +2427,9 @@ msgstr "Password des inneren, privaten Schlüssels"
msgid "Password successfully changed!"
msgstr "Passwort erfolgreich geändert!"
+msgid "Password2"
+msgstr ""
+
msgid "Path to CA-Certificate"
msgstr "Pfad zum CA-Zertifikat"
diff --git a/modules/luci-base/po/el/base.po b/modules/luci-base/po/el/base.po
index e3969afff0..b385651f34 100644
--- a/modules/luci-base/po/el/base.po
+++ b/modules/luci-base/po/el/base.po
@@ -2372,6 +2372,9 @@ msgstr ""
msgid "Password successfully changed!"
msgstr "Ο κωδικός Ï€Ïόσβασης άλλαξε επιτυχώς!"
+msgid "Password2"
+msgstr ""
+
msgid "Path to CA-Certificate"
msgstr "ΔιαδÏομή για Πιστοποιητικό CA"
diff --git a/modules/luci-base/po/en/base.po b/modules/luci-base/po/en/base.po
index 6537370156..04207336e3 100644
--- a/modules/luci-base/po/en/base.po
+++ b/modules/luci-base/po/en/base.po
@@ -2339,6 +2339,9 @@ msgstr ""
msgid "Password successfully changed!"
msgstr ""
+msgid "Password2"
+msgstr ""
+
msgid "Path to CA-Certificate"
msgstr "Path to CA-Certificate"
diff --git a/modules/luci-base/po/es/base.po b/modules/luci-base/po/es/base.po
index a3476735b5..626e374b45 100644
--- a/modules/luci-base/po/es/base.po
+++ b/modules/luci-base/po/es/base.po
@@ -2379,6 +2379,9 @@ msgstr ""
msgid "Password successfully changed!"
msgstr "¡Contraseña cambiada!"
+msgid "Password2"
+msgstr ""
+
msgid "Path to CA-Certificate"
msgstr "Ruta al Certificado CA"
diff --git a/modules/luci-base/po/fr/base.po b/modules/luci-base/po/fr/base.po
index 1aab5cb9a4..b0b4b4334c 100644
--- a/modules/luci-base/po/fr/base.po
+++ b/modules/luci-base/po/fr/base.po
@@ -2392,6 +2392,9 @@ msgstr ""
msgid "Password successfully changed!"
msgstr "Mot de passe changé avec succès !"
+msgid "Password2"
+msgstr ""
+
msgid "Path to CA-Certificate"
msgstr "Chemin de la CA"
diff --git a/modules/luci-base/po/he/base.po b/modules/luci-base/po/he/base.po
index d8eae1f84f..2c2c5d27ec 100644
--- a/modules/luci-base/po/he/base.po
+++ b/modules/luci-base/po/he/base.po
@@ -2306,6 +2306,9 @@ msgstr ""
msgid "Password successfully changed!"
msgstr ""
+msgid "Password2"
+msgstr ""
+
msgid "Path to CA-Certificate"
msgstr ""
diff --git a/modules/luci-base/po/hu/base.po b/modules/luci-base/po/hu/base.po
index dfed45de59..8f5aee4c78 100644
--- a/modules/luci-base/po/hu/base.po
+++ b/modules/luci-base/po/hu/base.po
@@ -2382,6 +2382,9 @@ msgstr ""
msgid "Password successfully changed!"
msgstr "A jelszó megváltoztatása sikeres!"
+msgid "Password2"
+msgstr ""
+
msgid "Path to CA-Certificate"
msgstr "CA tanúsítvány elérési útja"
diff --git a/modules/luci-base/po/it/base.po b/modules/luci-base/po/it/base.po
index 04331ab75d..ea7578e612 100644
--- a/modules/luci-base/po/it/base.po
+++ b/modules/luci-base/po/it/base.po
@@ -2378,6 +2378,9 @@ msgstr ""
msgid "Password successfully changed!"
msgstr "Password cambiata con successo!"
+msgid "Password2"
+msgstr ""
+
msgid "Path to CA-Certificate"
msgstr "Percorso al certificato CA"
diff --git a/modules/luci-base/po/ja/base.po b/modules/luci-base/po/ja/base.po
index 714b064dcb..7d23abede2 100644
--- a/modules/luci-base/po/ja/base.po
+++ b/modules/luci-base/po/ja/base.po
@@ -3,14 +3,14 @@ msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-06-10 03:40+0200\n"
-"PO-Revision-Date: 2017-04-03 02:32+0900\n"
+"PO-Revision-Date: 2017-07-28 12:17+0900\n"
"Last-Translator: INAGAKI Hiroshi <musashino.open@gmail.com>\n"
"Language: ja\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Poedit 2.0\n"
+"X-Generator: Poedit 2.0.3\n"
"Language-Team: \n"
msgid "%s is untagged in multiple VLANs!"
@@ -44,7 +44,7 @@ msgid "-- match by label --"
msgstr "-- ラベルを指定 --"
msgid "-- match by uuid --"
-msgstr "-- UUIDを指定 --"
+msgstr "-- UUID を指定 --"
msgid "1 Minute Load:"
msgstr "éŽåŽ»1分ã®è² è·:"
@@ -157,6 +157,8 @@ msgid ""
"<br/>Note: you need to manually restart the cron service if the crontab file "
"was empty before editing."
msgstr ""
+"<br />注æ„: 編集å‰ã® crontab ファイルãŒç©ºã®å ´åˆã€æ‰‹å‹•ã§ cron サービスã®å†èµ·å‹•"
+"ã‚’è¡Œã†å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
msgid "A43C + J43 + A43"
msgstr ""
@@ -283,7 +285,7 @@ msgid "Allocate IP sequentially"
msgstr ""
msgid "Allow <abbr title=\"Secure Shell\">SSH</abbr> password authentication"
-msgstr "<abbr title=\"Secure Shell\">SSH</abbr> パスワードèªè¨¼ã‚’許å¯ã—ã¾ã™"
+msgstr "<abbr title=\"Secure Shell\">SSH</abbr> パスワードèªè¨¼ã‚’許å¯ã—ã¾ã™ã€‚"
msgid "Allow all except listed"
msgstr "リスト内ã®ç«¯æœ«ã‹ã‚‰ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’ç¦æ­¢"
@@ -299,10 +301,10 @@ msgstr ""
"リモートホストãŒSSH転é€ã•ã‚ŒãŸãƒ­ãƒ¼ã‚«ãƒ«ã®ãƒãƒ¼ãƒˆã«æŽ¥ç¶šã™ã‚‹ã“ã¨ã‚’許å¯ã—ã¾ã™"
msgid "Allow root logins with password"
-msgstr "パスワードを使用ã—ãŸroot権é™ã§ã®ãƒ­ã‚°ã‚¤ãƒ³ã‚’許å¯ã™ã‚‹"
+msgstr "パスワードã§ã® root ログインを許å¯"
msgid "Allow the <em>root</em> user to login with password"
-msgstr "パスワードを使用ã—ãŸ<em>root</em>権é™ã§ã®ãƒ­ã‚°ã‚¤ãƒ³ã‚’許å¯ã™ã‚‹"
+msgstr "パスワードを使用ã—㟠<em>root</em> 権é™ã§ã®ãƒ­ã‚°ã‚¤ãƒ³ã‚’許å¯ã—ã¾ã™ã€‚"
msgid ""
"Allow upstream responses in the 127.0.0.0/8 range, e.g. for RBL services"
@@ -515,8 +517,8 @@ msgid ""
"defined backup patterns."
msgstr ""
"以下ã¯ã€ãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—ã®éš›ã«å«ã¾ã‚Œã‚‹ãƒ•ã‚¡ã‚¤ãƒ«ã®ãƒªã‚¹ãƒˆã§ã™ã€‚ã“ã®ãƒªã‚¹ãƒˆã¯ã€opkgã«"
-"よã£ã¦èªè­˜ã•ã‚Œã¦ã„る設定ファイルã€é‡è¦ãªãƒ™ãƒ¼ã‚¹ãƒ•ã‚¡ã‚¤ãƒ«ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒè¨­å®šã—ãŸæ­£"
-"è¦è¡¨ç¾ã«ä¸€è‡´ã—ãŸãƒ•ã‚¡ã‚¤ãƒ«ã®ä¸€è¦§ã§ã™ã€‚"
+"よã£ã¦èªè­˜ã•ã‚Œã¦ã„る設定ファイルã€é‡è¦ãªãƒ™ãƒ¼ã‚¹ãƒ•ã‚¡ã‚¤ãƒ«ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒè¨­å®šã—ãŸãƒ‘"
+"ターンã«ä¸€è‡´ã—ãŸãƒ•ã‚¡ã‚¤ãƒ«ã®ä¸€è¦§ã§ã™ã€‚"
msgid "Bind interface"
msgstr ""
@@ -858,7 +860,7 @@ msgid "Device is rebooting..."
msgstr "デãƒã‚¤ã‚¹ã‚’å†èµ·å‹•ä¸­ã§ã™..."
msgid "Device unreachable"
-msgstr ""
+msgstr "デãƒã‚¤ã‚¹ã«åˆ°é”ã§ãã¾ã›ã‚“"
msgid "Diagnostics"
msgstr "診断機能"
@@ -1217,7 +1219,7 @@ msgid "Force TKIP and CCMP (AES)"
msgstr "TKIP åŠã³CCMP (AES) を使用"
msgid "Force link"
-msgstr ""
+msgstr "強制リンク"
msgid "Force use of NAT-T"
msgstr "NAT-Tã®å¼·åˆ¶ä½¿ç”¨"
@@ -1467,7 +1469,7 @@ msgid "IPv6 routed prefix"
msgstr ""
msgid "IPv6 suffix"
-msgstr ""
+msgstr "IPv6 サフィックス"
msgid "IPv6-Address"
msgstr "IPv6-アドレス"
@@ -2380,6 +2382,9 @@ msgstr ""
msgid "Password successfully changed!"
msgstr "パスワードを変更ã—ã¾ã—ãŸ"
+msgid "Password2"
+msgstr "パスワード2"
+
msgid "Path to CA-Certificate"
msgstr "CA証明書ã®ãƒ‘ス"
@@ -3672,7 +3677,7 @@ msgid "Waiting for command to complete..."
msgstr "コマンド実行中ã§ã™..."
msgid "Waiting for device..."
-msgstr "デãƒã‚¤ã‚¹ã®èµ·å‹•ã‚’ãŠå¾…ã¡ãã ã•ã„..."
+msgstr "デãƒã‚¤ã‚¹ã®èµ·å‹•ã‚’å¾…ã£ã¦ã„ã¾ã™..."
msgid "Warning"
msgstr "警告"
diff --git a/modules/luci-base/po/ko/base.po b/modules/luci-base/po/ko/base.po
index 587b4890af..770a49cc5e 100644
--- a/modules/luci-base/po/ko/base.po
+++ b/modules/luci-base/po/ko/base.po
@@ -2332,6 +2332,9 @@ msgstr ""
msgid "Password successfully changed!"
msgstr ""
+msgid "Password2"
+msgstr ""
+
msgid "Path to CA-Certificate"
msgstr ""
diff --git a/modules/luci-base/po/ms/base.po b/modules/luci-base/po/ms/base.po
index 97912183f6..c2f62721d1 100644
--- a/modules/luci-base/po/ms/base.po
+++ b/modules/luci-base/po/ms/base.po
@@ -2311,6 +2311,9 @@ msgstr ""
msgid "Password successfully changed!"
msgstr ""
+msgid "Password2"
+msgstr ""
+
msgid "Path to CA-Certificate"
msgstr "Path ke CA-Sijil"
diff --git a/modules/luci-base/po/no/base.po b/modules/luci-base/po/no/base.po
index 9e3df81f84..6a6e818681 100644
--- a/modules/luci-base/po/no/base.po
+++ b/modules/luci-base/po/no/base.po
@@ -2357,6 +2357,9 @@ msgstr ""
msgid "Password successfully changed!"
msgstr "Passordet er endret!"
+msgid "Password2"
+msgstr ""
+
msgid "Path to CA-Certificate"
msgstr "Sti til CA-sertifikat"
diff --git a/modules/luci-base/po/pl/base.po b/modules/luci-base/po/pl/base.po
index 98067c8654..e36461615d 100644
--- a/modules/luci-base/po/pl/base.po
+++ b/modules/luci-base/po/pl/base.po
@@ -2401,6 +2401,9 @@ msgstr ""
msgid "Password successfully changed!"
msgstr "Pomyślnie zmieniono hasło!"
+msgid "Password2"
+msgstr ""
+
msgid "Path to CA-Certificate"
msgstr "Ścieżka do certyfikatu CA"
diff --git a/modules/luci-base/po/pt-br/base.po b/modules/luci-base/po/pt-br/base.po
index f2ba57555f..87c32bff92 100644
--- a/modules/luci-base/po/pt-br/base.po
+++ b/modules/luci-base/po/pt-br/base.po
@@ -2497,6 +2497,9 @@ msgstr "Senha da Chave Privada interna"
msgid "Password successfully changed!"
msgstr "A senha foi alterada com sucesso!"
+msgid "Password2"
+msgstr ""
+
msgid "Path to CA-Certificate"
msgstr "Caminho para o Certificado da AC"
diff --git a/modules/luci-base/po/pt/base.po b/modules/luci-base/po/pt/base.po
index cb90df5435..bea93f5c38 100644
--- a/modules/luci-base/po/pt/base.po
+++ b/modules/luci-base/po/pt/base.po
@@ -2379,6 +2379,9 @@ msgstr ""
msgid "Password successfully changed!"
msgstr "Password alterada com sucesso!"
+msgid "Password2"
+msgstr ""
+
msgid "Path to CA-Certificate"
msgstr "Directorio do Certificado CA"
diff --git a/modules/luci-base/po/ro/base.po b/modules/luci-base/po/ro/base.po
index d51f4d05cb..2ee8537ac8 100644
--- a/modules/luci-base/po/ro/base.po
+++ b/modules/luci-base/po/ro/base.po
@@ -2303,6 +2303,9 @@ msgstr ""
msgid "Password successfully changed!"
msgstr "Parola schimbata cu succes !"
+msgid "Password2"
+msgstr ""
+
msgid "Path to CA-Certificate"
msgstr "Calea catre certificatul CA"
diff --git a/modules/luci-base/po/ru/base.po b/modules/luci-base/po/ru/base.po
index d30c643fce..6515772620 100644
--- a/modules/luci-base/po/ru/base.po
+++ b/modules/luci-base/po/ru/base.po
@@ -2387,6 +2387,9 @@ msgstr ""
msgid "Password successfully changed!"
msgstr "Пароль уÑпешно изменён!"
+msgid "Password2"
+msgstr ""
+
msgid "Path to CA-Certificate"
msgstr "Путь к центру Ñертификации"
diff --git a/modules/luci-base/po/sk/base.po b/modules/luci-base/po/sk/base.po
index f4037ea351..ab876ce326 100644
--- a/modules/luci-base/po/sk/base.po
+++ b/modules/luci-base/po/sk/base.po
@@ -2278,6 +2278,9 @@ msgstr ""
msgid "Password successfully changed!"
msgstr ""
+msgid "Password2"
+msgstr ""
+
msgid "Path to CA-Certificate"
msgstr ""
diff --git a/modules/luci-base/po/sv/base.po b/modules/luci-base/po/sv/base.po
index 6af6d610f2..803ac28196 100644
--- a/modules/luci-base/po/sv/base.po
+++ b/modules/luci-base/po/sv/base.po
@@ -2284,6 +2284,9 @@ msgstr ""
msgid "Password successfully changed!"
msgstr ""
+msgid "Password2"
+msgstr ""
+
msgid "Path to CA-Certificate"
msgstr ""
diff --git a/modules/luci-base/po/templates/base.pot b/modules/luci-base/po/templates/base.pot
index d3fc6a7324..1aa1816c20 100644
--- a/modules/luci-base/po/templates/base.pot
+++ b/modules/luci-base/po/templates/base.pot
@@ -2271,6 +2271,9 @@ msgstr ""
msgid "Password successfully changed!"
msgstr ""
+msgid "Password2"
+msgstr ""
+
msgid "Path to CA-Certificate"
msgstr ""
diff --git a/modules/luci-base/po/tr/base.po b/modules/luci-base/po/tr/base.po
index afabfa29d4..3c814cd30f 100644
--- a/modules/luci-base/po/tr/base.po
+++ b/modules/luci-base/po/tr/base.po
@@ -2291,6 +2291,9 @@ msgstr ""
msgid "Password successfully changed!"
msgstr ""
+msgid "Password2"
+msgstr ""
+
msgid "Path to CA-Certificate"
msgstr ""
diff --git a/modules/luci-base/po/uk/base.po b/modules/luci-base/po/uk/base.po
index 7ee06885ff..83e5501963 100644
--- a/modules/luci-base/po/uk/base.po
+++ b/modules/luci-base/po/uk/base.po
@@ -2398,6 +2398,9 @@ msgstr ""
msgid "Password successfully changed!"
msgstr "Пароль уÑпішно змінено!"
+msgid "Password2"
+msgstr ""
+
msgid "Path to CA-Certificate"
msgstr "ШлÑÑ… до центру Ñертифікції"
diff --git a/modules/luci-base/po/vi/base.po b/modules/luci-base/po/vi/base.po
index 239e1c251d..7bd7868cf4 100644
--- a/modules/luci-base/po/vi/base.po
+++ b/modules/luci-base/po/vi/base.po
@@ -2314,6 +2314,9 @@ msgstr ""
msgid "Password successfully changed!"
msgstr ""
+msgid "Password2"
+msgstr ""
+
msgid "Path to CA-Certificate"
msgstr "ÄÆ°á»ng dẫn tá»›i CA-Certificate"
diff --git a/modules/luci-base/po/zh-cn/base.po b/modules/luci-base/po/zh-cn/base.po
index 7f4918557e..0ea00ff28d 100644
--- a/modules/luci-base/po/zh-cn/base.po
+++ b/modules/luci-base/po/zh-cn/base.po
@@ -7,7 +7,7 @@ msgid "%s is untagged in multiple VLANs!"
msgstr "%s 在多个 VLAN 中å‡æœªå…³è”ï¼"
msgid "(%d minute window, %d second interval)"
-msgstr "(%d 分钟信æ¯ï¼Œæ¯ %d 秒刷新)"
+msgstr "(最近 %d 分钟信æ¯ï¼Œæ¯ %d 秒刷新)"
msgid "(%s available)"
msgstr "(%s å¯ç”¨ï¼‰"
@@ -85,8 +85,8 @@ msgid ""
"<abbr title=\"Domain Name System\">DNS</abbr> servers will be queried in the "
"order of the resolvfile"
msgstr ""
-"按照 resolvfile 里的顺åºæŸ¥è¯¢ <abbr title=\"Domain Name System\">DNS</abbr> æœ"
-"务器"
+"按照“解æžæ–‡ä»¶â€é‡Œçš„顺åºæŸ¥è¯¢ <abbr title=\"Domain Name System\">DNS</abbr> æœåŠ¡"
+"器"
msgid "<abbr title=\"Extended Service Set Identifier\">ESSID</abbr>"
msgstr "<abbr title=\"Extended Service Set Identifier\">ESSID</abbr>"
@@ -620,7 +620,7 @@ msgid "Client"
msgstr "客户端 Client"
msgid "Client ID to send when requesting DHCP"
-msgstr "请求 DHCP æ—¶å‘é€çš„客户 ID"
+msgstr "请求 DHCP æ—¶å‘é€çš„客户端 ID"
msgid ""
"Close inactive connection after the given amount of seconds, use 0 to "
@@ -710,8 +710,7 @@ msgstr "自定义软件æº"
msgid ""
"Customizes the behaviour of the device <abbr title=\"Light Emitting Diode"
"\">LED</abbr>s if possible."
-msgstr ""
-"自定义设备 <abbr title=\"Light Emitting Diode\">LED</abbr> 行为(如果å¯èƒ½ï¼‰ã€‚"
+msgstr "自定义此设备的 <abbr title=\"Light Emitting Diode\">LED</abbr> 行为。"
msgid "DHCP Leases"
msgstr "DHCP 分é…"
@@ -1015,10 +1014,10 @@ msgid "Enable the DF (Don't Fragment) flag of the encapsulating packets."
msgstr "å¯ç”¨åŽæŠ¥æ–‡çš„ DF(ç¦æ­¢åˆ†ç‰‡ï¼‰æ ‡å¿—。"
msgid "Enable this mount"
-msgstr "å¯ç”¨æŒ‚载点"
+msgstr "å¯ç”¨æ­¤æŒ‚载点"
msgid "Enable this swap"
-msgstr "å¯ç”¨äº¤æ¢åŒº"
+msgstr "å¯ç”¨æ­¤ swap 分区"
msgid "Enable/Disable"
msgstr "å¯ç”¨/ç¦ç”¨"
@@ -1477,8 +1476,8 @@ msgid ""
msgstr ""
"如果物ç†å†…å­˜ä¸è¶³ï¼Œé—²ç½®æ•°æ®å¯è‡ªåŠ¨ç§»åˆ° swap 区暂存,以增加å¯ç”¨çš„ <abbr title="
"\"Random Access Memory\">RAM</abbr>。请注æ„:swap 区的数æ®å¤„ç†ä¼šéžå¸¸æ…¢ï¼Œå› ä¸º "
-"swapè®¾å¤‡æ— æ³•åƒ <abbr title=\"Random Access Memory\">RAM</abbr> 这样的高速率访"
-"问。"
+"swap è®¾å¤‡æ— æ³•åƒ <abbr title=\"Random Access Memory\">RAM</abbr> 这样的高速率"
+"访问。"
msgid "Ignore <code>/etc/hosts</code>"
msgstr "忽略 <code>/etc/hosts</code>"
@@ -2794,10 +2793,10 @@ msgid "Scheduled Tasks"
msgstr "计划任务"
msgid "Section added"
-msgstr "添加的区域"
+msgstr "添加的节点"
msgid "Section removed"
-msgstr "移除的区域"
+msgstr "移除的节点"
msgid "See \"mount\" manpage for details"
msgstr "è¯¦å‚ \"mount\" è”机帮助"
@@ -3124,7 +3123,7 @@ msgid ""
"\">e.g.</abbr> <samp><abbr title=\"Third Extended Filesystem\">ext3</abbr></"
"samp>)"
msgstr ""
-"用于格å¼åŒ–存储器的文件系统,(例如:<samp><abbr title=\"Third Extended "
+"用于格å¼åŒ–存储器的文件系统(例如:<samp><abbr title=\"Third Extended "
"Filesystem\">ext3</abbr></samp>)"
msgid ""
@@ -3142,7 +3141,7 @@ msgid "The following changes have been reverted"
msgstr "以下更改已放弃"
msgid "The following rules are currently active on this system."
-msgstr "系统中的活跃连接。"
+msgstr "以下规则当å‰åœ¨ç³»ç»Ÿä¸­å¤„于活动状æ€ã€‚"
msgid "The given network name is not unique"
msgstr "给定的网络åé‡å¤"
@@ -3185,7 +3184,7 @@ msgstr "æ交的安全令牌无效或已过期ï¼"
msgid ""
"The system is erasing the configuration partition now and will reboot itself "
"when finished."
-msgstr "系统正在删除é…置分区,完æˆåŽä¼šè‡ªåŠ¨é‡å¯ã€‚"
+msgstr "系统正在擦除é…置分区,完æˆåŽä¼šè‡ªåŠ¨é‡å¯ã€‚"
msgid ""
"The system is flashing now.<br /> DO NOT POWER OFF THE DEVICE!<br /> Wait a "
@@ -3204,7 +3203,7 @@ msgstr "隧é“端点在 NAT 之åŽï¼Œé»˜è®¤ä¸ºç¦ç”¨ï¼Œä»…适用于 AYIYA"
msgid ""
"The uploaded image file does not contain a supported format. Make sure that "
"you choose the generic image format for your platform."
-msgstr "ä¸æ”¯æŒæ‰€ä¸Šä¼ çš„文件格å¼ã€‚请确认选择的文件无误。"
+msgstr "ä¸æ”¯æŒæ‰€ä¸Šä¼ çš„映åƒæ–‡ä»¶æ ¼å¼ï¼Œè¯·é€‰æ‹©é€‚åˆå½“å‰å¹³å°çš„通用映åƒæ–‡ä»¶ã€‚"
msgid "There are no active leases."
msgstr "没有已分é…的租约。"
@@ -3286,7 +3285,7 @@ msgstr "这通常是隧é“代ç†æ‰€ç®¡ç†çš„最近的 PoP 的地å€"
msgid ""
"This list gives an overview over currently running system processes and "
"their status."
-msgstr "系统中正在è¿è¡Œçš„进程和其状æ€ä¿¡æ¯ã€‚"
+msgstr "系统中正在è¿è¡Œçš„进程概况和它们的状æ€ä¿¡æ¯ã€‚"
msgid "This page allows the configuration of custom button actions"
msgstr "自定义按键动作。"
@@ -3318,7 +3317,7 @@ msgid "Total Available"
msgstr "å¯ç”¨æ•°"
msgid "Traceroute"
-msgstr "路由追踪"
+msgstr "Traceroute"
msgid "Traffic"
msgstr "æµé‡"
diff --git a/modules/luci-base/po/zh-tw/base.po b/modules/luci-base/po/zh-tw/base.po
index 7521324f1c..7b2792e61f 100644
--- a/modules/luci-base/po/zh-tw/base.po
+++ b/modules/luci-base/po/zh-tw/base.po
@@ -2319,6 +2319,9 @@ msgstr ""
msgid "Password successfully changed!"
msgstr "密碼已變更æˆåŠŸ!"
+msgid "Password2"
+msgstr ""
+
msgid "Path to CA-Certificate"
msgstr "CA-證書的路徑"
diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/network.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/network.lua
index 385e1141ec..22f7c5f700 100644
--- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/network.lua
+++ b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/network.lua
@@ -38,6 +38,7 @@ if fs.access("/etc/init.d/dsl_control") then
tone:value("bv", translate("B43 + B43C + V43"))
xfer_mode = dsl:option(ListValue, "xfer_mode", translate("Encapsulation mode"))
+ xfer_mode:value("", translate("auto"))
xfer_mode:value("atm", translate("ATM (Asynchronous Transfer Mode)"))
xfer_mode:value("ptm", translate("PTM/EFM (Packet Transfer Mode)"))
diff --git a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi.lua b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi.lua
index e1e21bcb58..51913729dc 100644
--- a/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi.lua
+++ b/modules/luci-mod-admin-full/luasrc/model/cbi/admin_network/wifi.lua
@@ -769,6 +769,9 @@ if hwtype == "mac80211" or hwtype == "prism2" then
ieee80211r:depends({mode="ap", encryption="psk"})
ieee80211r:depends({mode="ap", encryption="psk2"})
ieee80211r:depends({mode="ap", encryption="psk-mixed"})
+ ieee80211r:depends({mode="ap-wds", encryption="psk"})
+ ieee80211r:depends({mode="ap-wds", encryption="psk2"})
+ ieee80211r:depends({mode="ap-wds", encryption="psk-mixed"})
end
ieee80211r.rmempty = true