diff options
Diffstat (limited to 'applications')
140 files changed, 4261 insertions, 414 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..8d7a6163de --- /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 +uhttpd-mod-ubus +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..1edafa7c79 --- /dev/null +++ b/applications/luci-app-attendedsysupgrade/luasrc/view/attendedsysupgrade.htm @@ -0,0 +1,284 @@ +<%+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"> +<div style="display: none" id="packages" class="alert-message success"></div> +<div class="cbi-value" id="keep_container" style="display: none"> + <label class="cbi-value-title" for="keep">keep settings:</label> + <div class="cbi-value-field"> + <input type="checkbox" name="keep" id="keep" checked="checked" /> + </div> +</div> + +<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]; + 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) { + request_data = {}; + request_data.jsonrpc = "2.0"; + request_data.id = ubus_counter; + request_data.method = "call"; + request_data.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(JSON.stringify(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("system", "board", {}, "model"); + ubus_request("uci", "get", { "config": "attendedsysupgrade", "section": "updateserver", "option": "url" }, "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; + request_dict.packages = data.packagelist; + 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 += "<h3>new update available</h3>" + info_output += data.release.version + " to " + response_content.version + latest_version = response_content.version; + } + if(response_content.updates != undefined) { + info_output += "<h3>package updates available</h3>" + for (update in response_content.updates) { + info_output += "<b>" + update + "</b>: " + response_content.updates[update][1] + " to " + response_content.updates[update][0] + "</br>" + } + data.packages = response_content.packages + } + 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 + request_dict.packages = data.packages; + request_dict.model = data.model + 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 = "sysupgrade" + document.getElementById("update_button").onclick = function() {download_image(response_content.url); } + document.getElementById("keep_container").style.display = "block"; + } +} + + +// 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", { "keep_settings": document.getElementById("keep").checked }, '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/advanced_hotplugscript.lua b/applications/luci-app-mwan3/luasrc/model/cbi/mwan/advanced_hotplugscript.lua index 0e7b8b11d0..1b97080216 100644 --- a/applications/luci-app-mwan3/luasrc/model/cbi/mwan/advanced_hotplugscript.lua +++ b/applications/luci-app-mwan3/luasrc/model/cbi/mwan/advanced_hotplugscript.lua @@ -1,55 +1,40 @@ -- ------ hotplug script configuration ------ -- fs = require "nixio.fs" -sys = require "luci.sys" ut = require "luci.util" -script = "/etc/hotplug.d/iface/16-mwancustom" -scriptBackup = "/etc/hotplug.d/iface/16-mwancustombak" - -if luci.http.formvalue("cbid.luci.1._restorebak") then -- restore button has been clicked - luci.http.redirect(luci.dispatcher.build_url("admin/network/mwan/advanced/hotplugscript") .. "?restore=yes") -elseif luci.http.formvalue("restore") == "yes" then -- restore script from backup - os.execute("cp -f " .. scriptBackup .. " " .. script) -end - +script = "/etc/mwan3.user" m5 = SimpleForm("luci", nil) m5:append(Template("mwan/advanced_hotplugscript")) -- highlight current tab f = m5:section(SimpleSection, nil, - translate("This section allows you to modify the contents of /etc/hotplug.d/iface/16-mwancustom<br />" .. - "This is useful for running system commands and/or scripts based on interface ifup or ifdown hotplug events<br /><br />" .. + translate("This section allows you to modify the content of \"/etc/mwan3.user\".<br />" .. + "The file is also preserved during sysupgrade.<br />" .. + "<br />" .. "Notes:<br />" .. - "The first line of the script must be "#!/bin/sh" without quotes<br />" .. - "Lines beginning with # are comments and are not executed<br /><br />" .. - "Available variables:<br />" .. - "$ACTION is the hotplug event (ifup, ifdown)<br />" .. - "$INTERFACE is the interface name (wan1, wan2, etc.)<br />" .. - "$DEVICE is the device name attached to the interface (eth0.1, eth1, etc.)")) - - -restore = f:option(Button, "_restorebak", translate("Restore default hotplug script")) - restore.inputtitle = translate("Restore...") - restore.inputstyle = "apply" + "This file is interpreted as a shell script.<br />" .. + "The first line of the script must be "#!/bin/sh" without quotes.<br />" .. + "Lines beginning with # are comments and are not executed.<br />" .. + "Put your custom mwan3 action here, they will<br />" .. + "be executed with each netifd hotplug interface event<br />" .. + "on interfaces for which mwan3 is enabled.<br />" .. + "<br />" .. + "There are three main environment variables that are passed to this script.<br />" .. + "<br />" .. + "$ACTION Either \"ifup\" or \"ifdown\"<br />" .. + "$INTERFACE Name of the interface which went up or down (e.g. \"wan\" or \"wwan\")<br />" .. + "$DEVICE Physical device name which interface went up or down (e.g. \"eth0\" or \"wwan0\")<br />" .. + "<br />")) t = f:option(TextValue, "lines") t.rmempty = true t.rows = 20 - function t.cfgvalue() - local hps = fs.readfile(script) - if not hps or hps == "" then -- if script does not exist or is blank restore from backup - sys.call("cp -f " .. scriptBackup .. " " .. script) - return fs.readfile(script) - else - return hps - end + return fs.readfile(script) end - function t.write(self, section, data) -- format and write new data to script return fs.writefile(script, ut.trim(data:gsub("\r\n", "\n")) .. "\n") end - return m5 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..919ed46cd4 --- /dev/null +++ b/applications/luci-app-mwan3/luasrc/model/cbi/mwan/globalsconfig.lua @@ -0,0 +1,40 @@ +--[[ +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 + +mask = s:option( + Value, + "mmx_mask", + translate("Firewall mask"), + translate("Enter value in hex, starting with <code>0x</code>")) +mask.datatype = "hex(4)" +mask.default = "0xff00" + +return m diff --git a/applications/luci-app-mwan3/luasrc/model/cbi/mwan/interface.lua b/applications/luci-app-mwan3/luasrc/model/cbi/mwan/interface.lua index aeabc63616..c8c122ad48 100644 --- a/applications/luci-app-mwan3/luasrc/model/cbi/mwan/interface.lua +++ b/applications/luci-app-mwan3/luasrc/model/cbi/mwan/interface.lua @@ -147,6 +147,16 @@ track_ip = mwan_interface:option(DummyValue, "track_ip", translate("Tracking IP" end end +track_method = mwan_interface:option(DummyValue, "track_method", translate("Tracking method")) + track_method.rawhtml = true + function track_method.cfgvalue(self, s) + if tracked then + return self.map:get(s, "track_method") or "—" + else + return "—" + end + end + reliability = mwan_interface:option(DummyValue, "reliability", translate("Tracking reliability")) reliability.rawhtml = true function reliability.cfgvalue(self, s) 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..0318091d6c 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")) @@ -111,6 +117,12 @@ track_ip = mwan_interface:option(DynamicList, "track_ip", translate("Tracking ho translate("This hostname or IP address will be pinged to determine if the link is up or down. Leave blank to assume interface is always online")) track_ip.datatype = "host" +track_method = mwan_interface:option(ListValue, "track_method", translate("Tracking method")) + track_method.default = "ping" + track_method:value("ping") + track_method:value("arping") + track_method:value("httping") + reliability = mwan_interface:option(Value, "reliability", translate("Tracking reliability"), translate("Acceptable values: 1-100. This many Tracking IP addresses must respond for the link to be deemed up")) reliability.datatype = "range(1, 100)" @@ -183,6 +195,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..9e17c3d040 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 "" @@ -391,6 +415,9 @@ msgstr "" msgid "Tracking hostname or IP address" msgstr "" +msgid "Tracking method" +msgstr "" + msgid "Tracking reliability" msgstr "" @@ -408,6 +435,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&group_by=mac&order_by=-rx,-tx"><%:CSV, grouped by MAC%></a></li> + <li><a href="<%=url('admin/nlbw/data')%>?type=csv&group_by=ip&order_by=-rx,-tx"><%:CSV, grouped by IP%></a></li> + <li><a href="<%=url('admin/nlbw/data')%>?type=csv&group_by=layer7&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-samba/luasrc/model/cbi/samba.lua b/applications/luci-app-samba/luasrc/model/cbi/samba.lua index 68a5b3a9bc..2e533c3f57 100644 --- a/applications/luci-app-samba/luasrc/model/cbi/samba.lua +++ b/applications/luci-app-samba/luasrc/model/cbi/samba.lua @@ -36,7 +36,8 @@ function tmpl.write(self, section, value) end -s = m:section(TypedSection, "sambashare", translate("Shared Directories")) +s = m:section(TypedSection, "sambashare", translate("Shared Directories") + , translate("Please add directories to share. Each directory refers to a folder on a mounted device.")) s.anonymous = true s.addremove = true s.template = "cbi/tblsection" diff --git a/applications/luci-app-samba/po/ca/samba.po b/applications/luci-app-samba/po/ca/samba.po index fadcbdfdb9..eb6be15cd0 100644 --- a/applications/luci-app-samba/po/ca/samba.po +++ b/applications/luci-app-samba/po/ca/samba.po @@ -65,6 +65,11 @@ msgstr "Comparticions de xarxa" msgid "Path" msgstr "Ruta" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" + msgid "Read-only" msgstr "Només lectura" diff --git a/applications/luci-app-samba/po/cs/samba.po b/applications/luci-app-samba/po/cs/samba.po index 4a00124fb9..d66d87674d 100644 --- a/applications/luci-app-samba/po/cs/samba.po +++ b/applications/luci-app-samba/po/cs/samba.po @@ -63,6 +63,11 @@ msgstr "Síťová sdílení" msgid "Path" msgstr "Cesta" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" + msgid "Read-only" msgstr "Pouze pro čtení" diff --git a/applications/luci-app-samba/po/de/samba.po b/applications/luci-app-samba/po/de/samba.po index 1bcac0c9bc..4e8da53b5a 100644 --- a/applications/luci-app-samba/po/de/samba.po +++ b/applications/luci-app-samba/po/de/samba.po @@ -65,6 +65,11 @@ msgstr "Netzwerkfreigaben" msgid "Path" msgstr "Pfad" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" + msgid "Read-only" msgstr "Nur Lesen" diff --git a/applications/luci-app-samba/po/el/samba.po b/applications/luci-app-samba/po/el/samba.po index 9a15ad1e03..878416a638 100644 --- a/applications/luci-app-samba/po/el/samba.po +++ b/applications/luci-app-samba/po/el/samba.po @@ -61,6 +61,11 @@ msgstr "" msgid "Path" msgstr "" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" + msgid "Read-only" msgstr "" diff --git a/applications/luci-app-samba/po/en/samba.po b/applications/luci-app-samba/po/en/samba.po index 94cfdb5168..642580e9de 100644 --- a/applications/luci-app-samba/po/en/samba.po +++ b/applications/luci-app-samba/po/en/samba.po @@ -61,6 +61,11 @@ msgstr "Network Shares" msgid "Path" msgstr "Path" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" + msgid "Read-only" msgstr "Read-only" diff --git a/applications/luci-app-samba/po/es/samba.po b/applications/luci-app-samba/po/es/samba.po index c14ebd2c32..57c4b862d6 100644 --- a/applications/luci-app-samba/po/es/samba.po +++ b/applications/luci-app-samba/po/es/samba.po @@ -63,6 +63,11 @@ msgstr "Comparticiones de red" msgid "Path" msgstr "Dirección" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" + msgid "Read-only" msgstr "Solo lectura" diff --git a/applications/luci-app-samba/po/fr/samba.po b/applications/luci-app-samba/po/fr/samba.po index ff040b50d7..63960fca17 100644 --- a/applications/luci-app-samba/po/fr/samba.po +++ b/applications/luci-app-samba/po/fr/samba.po @@ -63,6 +63,11 @@ msgstr "Partages réseau" msgid "Path" msgstr "Chemin" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" + msgid "Read-only" msgstr "Lecture seule" diff --git a/applications/luci-app-samba/po/he/samba.po b/applications/luci-app-samba/po/he/samba.po index 620f56cf84..010d2b2480 100644 --- a/applications/luci-app-samba/po/he/samba.po +++ b/applications/luci-app-samba/po/he/samba.po @@ -56,6 +56,11 @@ msgstr "" msgid "Path" msgstr "" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" + msgid "Read-only" msgstr "" diff --git a/applications/luci-app-samba/po/hu/samba.po b/applications/luci-app-samba/po/hu/samba.po index 38a9a08439..0263edb6c1 100644 --- a/applications/luci-app-samba/po/hu/samba.po +++ b/applications/luci-app-samba/po/hu/samba.po @@ -63,6 +63,11 @@ msgstr "Hálózati megosztások" msgid "Path" msgstr "Elérési út" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" + msgid "Read-only" msgstr "Csak olvasható" diff --git a/applications/luci-app-samba/po/it/samba.po b/applications/luci-app-samba/po/it/samba.po index a2bb9b6735..8e5b062a08 100644 --- a/applications/luci-app-samba/po/it/samba.po +++ b/applications/luci-app-samba/po/it/samba.po @@ -64,6 +64,11 @@ msgstr "Condivisioni di rete" msgid "Path" msgstr "Percorso" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" + msgid "Read-only" msgstr "Solo lettura" diff --git a/applications/luci-app-samba/po/ja/samba.po b/applications/luci-app-samba/po/ja/samba.po index 9f338defbb..eca10efcc0 100644 --- a/applications/luci-app-samba/po/ja/samba.po +++ b/applications/luci-app-samba/po/ja/samba.po @@ -1,17 +1,17 @@ msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" +"Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-05-19 19:36+0200\n" -"PO-Revision-Date: 2011-11-03 18:09+0200\n" -"Last-Translator: Kentaro <kentaro.matsuyama@gmail.com>\n" -"Language-Team: LANGUAGE <LL@li.org>\n" +"PO-Revision-Date: 2017-08-16 00:41+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: Pootle 2.0.4\n" +"X-Generator: Poedit 2.0.3\n" +"Language-Team: \n" msgid "Allow guests" msgstr "ゲストアクセスを許可" @@ -61,6 +61,13 @@ msgstr "ネットワーク共有" msgid "Path" msgstr "パス" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" +"共有するディレクトリを追加してください。マウントされたデバイス等のディレクト" +"リを設定し、公開することができます。" + msgid "Read-only" msgstr "読み込みのみ" diff --git a/applications/luci-app-samba/po/ms/samba.po b/applications/luci-app-samba/po/ms/samba.po index de4ed7c365..d5f1ce15e7 100644 --- a/applications/luci-app-samba/po/ms/samba.po +++ b/applications/luci-app-samba/po/ms/samba.po @@ -55,6 +55,11 @@ msgstr "" msgid "Path" msgstr "" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" + msgid "Read-only" msgstr "" diff --git a/applications/luci-app-samba/po/no/samba.po b/applications/luci-app-samba/po/no/samba.po index 7059d7748d..349f6b9def 100644 --- a/applications/luci-app-samba/po/no/samba.po +++ b/applications/luci-app-samba/po/no/samba.po @@ -52,6 +52,11 @@ msgstr "Nettverks Mapper" msgid "Path" msgstr "Fysisk bane" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" + msgid "Read-only" msgstr "Skrivebeskyttet" diff --git a/applications/luci-app-samba/po/pl/samba.po b/applications/luci-app-samba/po/pl/samba.po index bf54e78c3d..d997268cda 100644 --- a/applications/luci-app-samba/po/pl/samba.po +++ b/applications/luci-app-samba/po/pl/samba.po @@ -62,6 +62,11 @@ msgstr "Udziały sieciowe" msgid "Path" msgstr "Ścieżka" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" + msgid "Read-only" msgstr "Tylko do odczytu" diff --git a/applications/luci-app-samba/po/pt-br/samba.po b/applications/luci-app-samba/po/pt-br/samba.po index 43ea3b9b97..a2e6e220c0 100644 --- a/applications/luci-app-samba/po/pt-br/samba.po +++ b/applications/luci-app-samba/po/pt-br/samba.po @@ -63,6 +63,11 @@ msgstr "Compartilhamentos de Rede" msgid "Path" msgstr "Caminho" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" + msgid "Read-only" msgstr "Somente leitura" diff --git a/applications/luci-app-samba/po/pt/samba.po b/applications/luci-app-samba/po/pt/samba.po index 6d4f003868..f58b58818e 100644 --- a/applications/luci-app-samba/po/pt/samba.po +++ b/applications/luci-app-samba/po/pt/samba.po @@ -63,6 +63,11 @@ msgstr "Partilhas da Rede" msgid "Path" msgstr "Caminho" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" + msgid "Read-only" msgstr "Apenas Leitura" diff --git a/applications/luci-app-samba/po/ro/samba.po b/applications/luci-app-samba/po/ro/samba.po index 78c55e4eb4..7cfcda7d11 100644 --- a/applications/luci-app-samba/po/ro/samba.po +++ b/applications/luci-app-samba/po/ro/samba.po @@ -62,6 +62,11 @@ msgstr "Partajari pe retea" msgid "Path" msgstr "Cale" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" + msgid "Read-only" msgstr "Doar citire" diff --git a/applications/luci-app-samba/po/ru/samba.po b/applications/luci-app-samba/po/ru/samba.po index 4823dc46d7..534770f5f1 100644 --- a/applications/luci-app-samba/po/ru/samba.po +++ b/applications/luci-app-samba/po/ru/samba.po @@ -64,6 +64,11 @@ msgstr "Сетевые ресурсы" msgid "Path" msgstr "Путь" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" + msgid "Read-only" msgstr "Только для чтения" diff --git a/applications/luci-app-samba/po/sk/samba.po b/applications/luci-app-samba/po/sk/samba.po index 2c511c8152..21f102d325 100644 --- a/applications/luci-app-samba/po/sk/samba.po +++ b/applications/luci-app-samba/po/sk/samba.po @@ -56,6 +56,11 @@ msgstr "" msgid "Path" msgstr "" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" + msgid "Read-only" msgstr "" diff --git a/applications/luci-app-samba/po/sv/samba.po b/applications/luci-app-samba/po/sv/samba.po index 549a69c5c0..f58f8b87d7 100644 --- a/applications/luci-app-samba/po/sv/samba.po +++ b/applications/luci-app-samba/po/sv/samba.po @@ -58,6 +58,11 @@ msgstr "Nätverksdelningar" msgid "Path" msgstr "Genväg" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" + msgid "Read-only" msgstr "Endast läsbar" diff --git a/applications/luci-app-samba/po/templates/samba.pot b/applications/luci-app-samba/po/templates/samba.pot index 9e4ab7ff17..674ed331ca 100644 --- a/applications/luci-app-samba/po/templates/samba.pot +++ b/applications/luci-app-samba/po/templates/samba.pot @@ -49,6 +49,11 @@ msgstr "" msgid "Path" msgstr "" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" + msgid "Read-only" msgstr "" diff --git a/applications/luci-app-samba/po/tr/samba.po b/applications/luci-app-samba/po/tr/samba.po index 486768f2ee..98d47beecf 100644 --- a/applications/luci-app-samba/po/tr/samba.po +++ b/applications/luci-app-samba/po/tr/samba.po @@ -56,6 +56,11 @@ msgstr "" msgid "Path" msgstr "" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" + msgid "Read-only" msgstr "" diff --git a/applications/luci-app-samba/po/uk/samba.po b/applications/luci-app-samba/po/uk/samba.po index 077315e214..a4469f961e 100644 --- a/applications/luci-app-samba/po/uk/samba.po +++ b/applications/luci-app-samba/po/uk/samba.po @@ -63,6 +63,11 @@ msgstr "Загальні мережеві ресурси" msgid "Path" msgstr "Шлях" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" + msgid "Read-only" msgstr "Тільки читання" diff --git a/applications/luci-app-samba/po/vi/samba.po b/applications/luci-app-samba/po/vi/samba.po index c5f6e02dfa..7c088cebe3 100644 --- a/applications/luci-app-samba/po/vi/samba.po +++ b/applications/luci-app-samba/po/vi/samba.po @@ -69,6 +69,11 @@ msgstr "Mạng chia sẻ" msgid "Path" msgstr "" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" + #, fuzzy msgid "Read-only" msgstr "Chỉ đọc " diff --git a/applications/luci-app-samba/po/zh-cn/samba.po b/applications/luci-app-samba/po/zh-cn/samba.po index 2294b611aa..b6fd8f31da 100644 --- a/applications/luci-app-samba/po/zh-cn/samba.po +++ b/applications/luci-app-samba/po/zh-cn/samba.po @@ -61,6 +61,11 @@ msgstr "网络共享" msgid "Path" msgstr "目录" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" + msgid "Read-only" msgstr "只读" diff --git a/applications/luci-app-samba/po/zh-tw/samba.po b/applications/luci-app-samba/po/zh-tw/samba.po index bfa2d7d6dd..ed0dabb807 100644 --- a/applications/luci-app-samba/po/zh-tw/samba.po +++ b/applications/luci-app-samba/po/zh-tw/samba.po @@ -59,6 +59,11 @@ msgstr "網路分享" msgid "Path" msgstr "路徑" +msgid "" +"Please add directories to share. Each directory refers to a folder on a " +"mounted device." +msgstr "" + msgid "Read-only" msgstr "唯讀" 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/cbi/shadowsocks-libev/rules.lua b/applications/luci-app-shadowsocks-libev/luasrc/model/cbi/shadowsocks-libev/rules.lua index fe5f9c31b8..5df59cb0ad 100644 --- a/applications/luci-app-shadowsocks-libev/luasrc/model/cbi/shadowsocks-libev/rules.lua +++ b/applications/luci-app-shadowsocks-libev/luasrc/model/cbi/shadowsocks-libev/rules.lua @@ -16,8 +16,13 @@ m = Map("shadowsocks-libev", If the prior check results in action <em>checkdst</em>, packets will continue \ to have their destination addresses checked.")) +local sdata = m:get('ss_rules') +if not sdata then + m:set('ss_rules', nil, 'ss_rules') + m:set('ss_rules', 'ss_rules', 'disabled', true) +end -s = m:section(NamedSection, "ss_rules", "ss-rules") +s = m:section(NamedSection, "ss_rules", "ss_rules") s:tab("general", translate("General Settings")) s:tab("srcip", translate("Source Settings")) s:tab("dstip", translate("Destination Settings")) 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..6608ee8d35 100644 --- a/applications/luci-app-shadowsocks-libev/luasrc/model/shadowsocks-libev.lua +++ b/applications/luci-app-shadowsocks-libev/luasrc/model/shadowsocks-libev.lua @@ -22,7 +22,7 @@ end function values_redir(o, xmode) o.map.uci.foreach("shadowsocks-libev", "ss_redir", function(sdata) local sname = sdata[".name"] - local mode = sdata["mode"] + local mode = sdata["mode"] or "tcp_only" if mode and mode:find(xmode) then local desc = "%s - %s" % {sname, mode} o:value(sname, desc) @@ -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/luasrc/model/cbi/travelmate/cfg_firewall_tab.lua b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/cfg_firewall_tab.lua index 009ed805db..e5a048fa88 100644 --- a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/cfg_firewall_tab.lua +++ b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/cfg_firewall_tab.lua @@ -12,6 +12,7 @@ end m = SimpleForm("input", nil) m:append(Template("travelmate/config_css")) +m.submit = translate("Save") m.reset = false s = m:section(SimpleSection, nil, diff --git a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/cfg_network_tab.lua b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/cfg_network_tab.lua index 4d43637d9c..0096d6a8c2 100644 --- a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/cfg_network_tab.lua +++ b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/cfg_network_tab.lua @@ -12,6 +12,7 @@ end m = SimpleForm("input", nil) m:append(Template("travelmate/config_css")) +m.submit = translate("Save") m.reset = false s = m:section(SimpleSection, nil, diff --git a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/cfg_wireless_tab.lua b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/cfg_wireless_tab.lua index a025c1379f..7ef9920a08 100644 --- a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/cfg_wireless_tab.lua +++ b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/cfg_wireless_tab.lua @@ -12,6 +12,7 @@ end m = SimpleForm("input", nil) m:append(Template("travelmate/config_css")) +m.submit = translate("Save") m.reset = false s = m:section(SimpleSection, nil, diff --git a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/configuration_tab.lua b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/configuration_tab.lua index 4233da6ac7..8a20ab9cce 100644 --- a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/configuration_tab.lua +++ b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/configuration_tab.lua @@ -14,6 +14,7 @@ end m = SimpleForm("input", nil) m:append(Template("travelmate/config_css")) +m.submit = translate("Save") m.reset = false s = m:section(SimpleSection, nil, diff --git a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/overview_tab.lua b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/overview_tab.lua index 64ab880c4d..add52317b4 100644 --- a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/overview_tab.lua +++ b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/overview_tab.lua @@ -4,8 +4,8 @@ local fs = require("nixio.fs") local uci = require("luci.model.uci").cursor() local json = require("luci.jsonc") -local nw = require("luci.model.network").init() -local fw = require("luci.model.firewall").init() +local nw = require("luci.model.network").init() +local fw = require("luci.model.firewall").init() local trmiface = uci.get("travelmate", "global", "trm_iface") or "trm_wwan" local trminput = uci.get("travelmate", "global", "trm_rtfile") or "/tmp/trm_runtime.json" local uplink = uci.get("network", trmiface) or "" @@ -18,7 +18,7 @@ m = Map("travelmate", translate("Travelmate"), .. "see online documentation</a>", "https://github.com/openwrt/packages/blob/master/net/travelmate/files/README.md")) function m.on_after_commit(self) - luci.sys.call("/etc/init.d/travelmate restart >/dev/null 2>&1") + luci.sys.call("env -i /etc/init.d/travelmate restart >/dev/null 2>&1") luci.http.redirect(luci.dispatcher.build_url("admin", "services", "travelmate")) end @@ -27,43 +27,38 @@ s = m:section(NamedSection, "global", "travelmate") -- Interface Wizard if uplink == "" then - dv = s:option(DummyValue, "nil", translate("Interface Wizard")) + dv = s:option(DummyValue, "", translate("Interface Wizard")) dv.template = "cbi/nullsection" - o = s:option(Value, "trm_iface", translate("Uplink interface")) + o = s:option(Value, "", translate("Uplink interface")) o.datatype = "and(uciname,rangelength(3,15))" - o.default = "trm_wwan" + o.default = trmiface o.rmempty = false - function o.validate(self, value) - iface = value - return iface - end - - function o.write(self, section, value) - uci:set("travelmate", section, "trm_iface", iface) - uci:save("travelmate") - uci:commit("travelmate") - end - - btn = s:option(Button, "", translate("Create Uplink Interface"), + btn = s:option(Button, "trm_iface", translate("Create Uplink Interface"), translate("Create a new wireless wan uplink interface, configure it to use dhcp and ") .. translate("add it to the wan zone of the firewall. This step has only to be done once.")) btn.inputtitle = translate("Add Interface") btn.inputstyle = "apply" btn.disabled = false - function btn.write() - local net = nw:add_network(iface, { proto = "dhcp" }) - if net then - nw:save("network") - nw:commit("network") - local zone = fw:get_zone_by_network("wan") - if zone then - zone:add_network(iface) - fw:save("firewall") - fw:commit("firewall") - luci.sys.call("env -i /bin/ubus call network reload >/dev/null 2>&1") + function btn.write(self, section, value) + local iface = o:formvalue(section) + if iface then + uci:set("travelmate", section, "trm_iface", iface) + uci:save("travelmate") + uci:commit("travelmate") + local net = nw:add_network(iface, { proto = "dhcp" }) + if net then + nw:save("network") + nw:commit("network") + local zone = fw:get_zone_by_network("wan") + if zone then + zone:add_network(iface) + fw:save("firewall") + fw:commit("firewall") + end end + luci.sys.call("env -i /bin/ubus call network reload >/dev/null 2>&1") end luci.http.redirect(luci.dispatcher.build_url("admin", "services", "travelmate")) end @@ -77,14 +72,24 @@ o1.default = o1.disabled o1.rmempty = false o2 = s:option(Flag, "trm_automatic", translate("Enable 'automatic' mode"), - translate("Keep travelmate in an active state.")) + translate("Keep travelmate in an active state. Check every n seconds the connection status, i.e. the uplink availability.")) o2.default = o2.enabled o2.rmempty = false +btn = s:option(Button, "", translate("Manual Rescan")) +btn:depends("trm_automatic", "") +btn.inputtitle = translate("Rescan") +btn.inputstyle = "find" +btn.disabled = false +function btn.write() + luci.sys.call("env -i /etc/init.d/travelmate start >/dev/null 2>&1") + luci.http.redirect(luci.dispatcher.build_url("admin", "services", "travelmate")) +end + o3 = s:option(Value, "trm_iface", translate("Uplink / Trigger interface"), - translate("Name of the uplink interface that triggers travelmate processing.")) + translate("Name of the uplink interface that triggers travelmate processing in 'manual' mode.")) o3.datatype = "and(uciname,rangelength(3,15))" -o3.default = "trm_wwan" +o3.default = trmiface o3.rmempty = false o4 = s:option(Value, "trm_triggerdelay", translate("Trigger delay"), @@ -159,6 +164,7 @@ translate("Options for further tweaking in case the defaults are not suitable fo e1 = e:option(Value, "trm_radio", translate("Radio selection"), translate("Restrict travelmate to a dedicated radio, e.g. 'radio0'")) +e1.datatype = "and(uciname,rangelength(6,6))" e1.rmempty = true e2 = e:option(Value, "trm_maxretry", translate("Connection Limit"), @@ -176,7 +182,7 @@ e3.rmempty = false e4 = e:option(Value, "trm_timeout", translate("Overall Timeout"), translate("Timeout in seconds between retries in 'automatic' mode")) e4.default = 60 -e4.datatype = "range(5,300)" +e4.datatype = "range(60,300)" e4.rmempty = false return m diff --git a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_add.lua b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_add.lua index 979307e001..dcfa17c8b5 100644 --- a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_add.lua +++ b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_add.lua @@ -7,6 +7,7 @@ local http = require("luci.http") local trmiface = uci.get("travelmate", "global", "trm_iface") or "trm_wwan" m = SimpleForm("add", translate("Add Wireless Uplink Configuration")) +m.submit = translate("Save") m.cancel = translate("Back to overview") m.reset = false @@ -18,7 +19,7 @@ m.hidden = { device = http.formvalue("device"), ssid = http.formvalue("ssid"), wep = http.formvalue("wep"), - wpa_suites = http.formvalue("wpa_suites"), + wpa_suites = http.formvalue("wpa_suites"), wpa_version = http.formvalue("wpa_version") } @@ -45,11 +46,11 @@ end function wssid.write(self, section, value) newsection = uci:section("wireless", "wifi-iface", nil, { - mode = "sta", - network = trmiface, - device = m.hidden.device, - ssid = wssid:formvalue(section), - disabled = "1" + mode = "sta", + network = trmiface, + device = m.hidden.device, + ssid = wssid:formvalue(section), + disabled = "1" }) if (tonumber(m.hidden.wep) or 0) == 1 then uci:set("wireless", newsection, "encryption", "wep-open") diff --git a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_delete.lua b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_delete.lua index 97ec1ca3ca..0c3cc1865b 100644 --- a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_delete.lua +++ b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_delete.lua @@ -10,5 +10,4 @@ if cfg ~= nil then uci:save("wireless") uci:commit("wireless") end - http.redirect(luci.dispatcher.build_url("admin/services/travelmate/stations")) diff --git a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_edit.lua b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_edit.lua index 0bae98460f..c60ff22c4d 100644 --- a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_edit.lua +++ b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_edit.lua @@ -6,6 +6,7 @@ local uci = require("luci.model.uci").cursor() local http = require("luci.http") m = SimpleForm("edit", translate("Edit Wireless Uplink Configuration")) +m.submit = translate("Save") m.cancel = translate("Back to overview") m.reset = false @@ -21,11 +22,15 @@ local s = uci:get_all("wireless", m.hidden.cfg) if s ~= nil then wssid = m:field(Value, "ssid", translate("SSID")) wssid.default = s.ssid - + wssid.datatype = "rangelength(1,32)" if s.encryption and s.key then wkey = m:field(Value, "key", translatef("Passphrase (%s)", s.encryption)) + elseif s.encryption and s.password then + wkey = m:field(Value, "password", translatef("Passphrase (%s)", s.encryption)) + end + if s.encryption and (s.key or s.password) then wkey.password = true - wkey.default = s.key + wkey.default = s.key or s.password if s.encryption == "wep" then wkey.datatype = "wepkey" else @@ -33,17 +38,19 @@ if s ~= nil then end end else - http.redirect(luci.dispatcher.build_url("admin/services/travelmate/stations")) + m.on_cancel() end function wssid.write(self, section, value) uci:set("wireless", m.hidden.cfg, "ssid", wssid:formvalue(section)) if s.encryption and s.key then uci:set("wireless", m.hidden.cfg, "key", wkey:formvalue(section)) + elseif s.encryption and s.password then + uci:set("wireless", m.hidden.cfg, "password", wkey:formvalue(section)) end uci:save("wireless") uci:commit("wireless") - http.redirect(luci.dispatcher.build_url("admin/services/travelmate/stations")) + m.on_cancel() end return m diff --git a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_order.lua b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_order.lua index 5734841030..6eb4c72063 100644 --- a/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_order.lua +++ b/applications/luci-app-travelmate/luasrc/model/cbi/travelmate/wifi_order.lua @@ -1,22 +1,36 @@ -- Copyright 2017 Dirk Brenken (dev@brenken.org) -- This is free software, licensed under the Apache License, Version 2.0 -local uci = require("luci.model.uci").cursor() local http = require("luci.http") local cfg = http.formvalue("cfg") -local pos = http.formvalue("pos") local dir = http.formvalue("dir") +local uci = require("luci.model.uci").cursor() +local trmiface = uci:get("travelmate", "global", "trm_iface") or "trm_wwan" if cfg ~= nil then - if dir == "up" then - pos = pos - 1 - uci:reorder("wireless", cfg, pos) - elseif dir == "down" then - pos = pos + 1 - uci:reorder("wireless", cfg, pos) + local section = "" + local idx = "" + local idx_change = "" + local changed = "" + uci:foreach("wireless", "wifi-iface", function(s) + local iface = s.network or "" + if iface == trmiface then + section = s['.name'] + if cfg == section then + idx = s['.index'] + else + idx_change = s['.index'] + end + if (dir == "up" and idx ~= "" and idx_change ~= "" and idx_change < idx) or + (dir == "down" and idx ~= "" and idx_change ~= "" and idx_change > idx) then + changed = uci:reorder("wireless", cfg, idx_change) + idx = "" + end + end + end) + if changed ~= "" then + uci:save("wireless") + uci:commit("wireless") end - uci:save("wireless") - uci:commit("wireless") end - http.redirect(luci.dispatcher.build_url("admin/services/travelmate/stations")) diff --git a/applications/luci-app-travelmate/luasrc/view/travelmate/stations.htm b/applications/luci-app-travelmate/luasrc/view/travelmate/stations.htm index bdb265f195..cbb6c189b8 100644 --- a/applications/luci-app-travelmate/luasrc/view/travelmate/stations.htm +++ b/applications/luci-app-travelmate/luasrc/view/travelmate/stations.htm @@ -3,10 +3,9 @@ Copyright 2017 Dirk Brenken (dev@brenken.org) This is free software, licensed under the Apache License, Version 2.0 -%> - <%- local write = io.write - local uci = require "luci.model.uci".cursor() + local uci = require("luci.model.uci").cursor() local trmiface = uci:get("travelmate", "global", "trm_iface") or "trm_wwan" -%> @@ -14,52 +13,46 @@ This is free software, licensed under the Apache License, Version 2.0 <div class="cbi-map"> <h2 name="content"><%:Wireless Stations%></h2> -<div class="cbi-map-descr"><%:Provides an overview of all configured uplink interfaces for travelmate. You can edit and delete existing interfaces or scan for new uplinks.%></div> +<div class="cbi-map-descr"> + <%=translatef("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.", trmiface)%> +</div> <fieldset class="cbi-section"> <table class="cbi-section-table" style="empty-cells:hide"> <tr class="cbi-section-table-titles"> <th class="cbi-section-table-cell" style="text-align:left"><%:Device%></th> - <th class="cbi-section-table-cell" style="text-align:left"><%:Mode%></th> - <th class="cbi-section-table-cell" style="text-align:left"><%:Uplink Interface%></th> <th class="cbi-section-table-cell" style="text-align:left"><%:SSID%></th> <th class="cbi-section-table-cell" style="text-align:left"><%:Encryption%></th> - <th class="cbi-section-table-cell" style="text-align:left" colspan="3"><%:Disabled%></th> + <th class="cbi-section-table-cell" style="text-align:center" colspan="2"><%:Actions%></th> </tr> <% - local pos = 1 - uci:foreach("wireless", "wifi-iface", function(s) - pos = pos + 1 - local section = s['.name'] - local device = s.device or "" - local mode = s.mode or "" + uci:foreach("wireless", "wifi-iface", function(s) local iface = s.network or "" - local ssid = s.ssid or "" - local encryption = s.encryption or "" - local disabled = s.disabled or "" - local style = "color:#000000" - if disabled == "0" then - style = "color:#0069d6" - end if iface == trmiface then + local section = s['.name'] or "" + local device = s.device or "" + local ssid = s.ssid or "" + local encryption = s.encryption or "" + local disabled = s.disabled or "" + local style = "color:#000000" + if disabled == "0" then + style = "color:#0069d6;font-weight:bold" + end %> - <tr class="cbi-section-table-row cbi-rowstyle-7" style="<%=style%>"> + <tr class="cbi-section-table-row cbi-rowstyle-1" style="<%=style%>"> <td style="text-align:left"><%=device%></td> - <td style="text-align:left"><%=mode%></td> - <td style="text-align:left"><%=iface%></td> <td style="text-align:left"><%=ssid%></td> <td style="text-align:left"><%=encryption%></td> - <td style="text-align:left"><%=disabled%></td> - <td class="cbi-value-field" style="width:100px;text-align:right"> - <input class="cbi-button cbi-button-up" type="button" value="" onclick="location.href='<%=url('admin/services/travelmate/wifiorder')%>?cfg=<%=section%>&pos=<%=pos%>&dir=up'" alt="<%:Move up%>" title="<%:Move up%>" /> - <input class="cbi-button cbi-button-down" type="button" value="" onclick="location.href='<%=url('admin/services/travelmate/wifiorder')%>?cfg=<%=section%>&pos=<%=pos%>&dir=down'" alt="<%:Move down%>" title="<%:Move down%>" /> + <td class="cbi-value-field" style="width:70px;text-align:right"> + <input class="cbi-button cbi-button-up" type="button" value="" onclick="location.href='<%=url('admin/services/travelmate/wifiorder')%>?cfg=<%=section%>;dir=up'" alt="<%:Move up%>" title="<%:Move up%>"/> + <input class="cbi-button cbi-button-down" type="button" value="" onclick="location.href='<%=url('admin/services/travelmate/wifiorder')%>?cfg=<%=section%>;dir=down'" alt="<%:Move down%>" title="<%:Move down%>"/> </td> - <td class="cbi-value-field" style="width:180px;text-align:right"> - <input type="button" class="cbi-button cbi-button-edit" style="width:85px" onclick="location.href='<%=url('admin/services/travelmate/wifiedit')%>?cfg=<%=section%>'" title="<%:Edit this Uplink%>" value="<%:Edit%>" /> - <input type="button" class="cbi-button cbi-button-remove" style="width:85px" onclick="location.href='<%=url('admin/services/travelmate/wifidelete')%>?cfg=<%=section%>'" title="<%:Delete this Uplink%>" value="<%:Delete%>"/> + <td class="cbi-value-field" style="width:150px;text-align:right"> + <input type="button" class="cbi-button cbi-button-edit" onclick="location.href='<%=url('admin/services/travelmate/wifiedit')%>?cfg=<%=section%>'" title="<%:Edit this Uplink%>" value="<%:Edit%>"/> + <input type="button" class="cbi-button cbi-button-remove" onclick="location.href='<%=url('admin/services/travelmate/wifidelete')%>?cfg=<%=section%>'" title="<%:Delete this Uplink%>" value="<%:Delete%>"/> </td> </tr> -<% +<% end end) %> @@ -71,13 +64,14 @@ This is free software, licensed under the Apache License, Version 2.0 local device = s[".name"] %> <form class="inline" action="<%=url('admin/services/travelmate/wifiscan')%>" method="post"> - <input type="hidden" name="device" value="<%=device%>" /> - <input type="hidden" name="token" value="<%=token%>" /> - <input type="submit" class="cbi-button cbi-button-find" style="width:110px" title="<%:Find and join network on %><%=device%>" value="<%:Scan %><%=device%>" /> + <input type="hidden" name="device" value="<%=device%>"/> + <input type="hidden" name="token" value="<%=token%>"/> + <input type="submit" class="cbi-button cbi-button-find" title="<%:Find and join network on %><%=device%>" value="<%:Scan %><%=device%>"/> </form> <% end) %> </div> +</div> <%+footer%> diff --git a/applications/luci-app-travelmate/luasrc/view/travelmate/wifi_scan.htm b/applications/luci-app-travelmate/luasrc/view/travelmate/wifi_scan.htm index 2ce45c63cb..af90c18d23 100644 --- a/applications/luci-app-travelmate/luasrc/view/travelmate/wifi_scan.htm +++ b/applications/luci-app-travelmate/luasrc/view/travelmate/wifi_scan.htm @@ -4,8 +4,8 @@ This is free software, licensed under the Apache License, Version 2.0 -%> <%- - local sys = require "luci.sys" - local utl = require "luci.util" + local sys = require("luci.sys") + local utl = require("luci.util") local dev = luci.http.formvalue("device") local iw = luci.sys.wifi.getiwinfo(dev) @@ -28,7 +28,7 @@ This is free software, licensed under the Apache License, Version 2.0 function percent_wifi_signal(info) local qc = info.quality or 0 local qm = info.quality_max or 0 - if info.bssid and qc > 0 and qm > 0 then + if info.ssid and qc > 0 and qm > 0 then return math.floor((100 / qm) * qc) else return 0 @@ -47,8 +47,8 @@ This is free software, licensed under the Apache License, Version 2.0 <th class="cbi-section-table-cell" style="text-align:left"><%:Encryption%></th> <th class="cbi-section-table-cell" style="text-align:left" colspan="2"><%:Signal strength%></th> </tr> - <% for i, net in ipairs(iw.scanlist or { }) do%> - <tr class="cbi-section-table-row cbi-rowstyle-4"> + <% for i, net in ipairs(iw.scanlist or { }) do %> + <tr class="cbi-section-table-row cbi-rowstyle-1"> <td class="cbi-value-field" style="text-align:left"> <strong><%=net.ssid and utl.pcdata(net.ssid) or "<em>%s</em>" % translate("hidden")%></strong> </td> @@ -58,17 +58,17 @@ This is free software, licensed under the Apache License, Version 2.0 <td class="cbi-value-field" style="text-align:left"> <%=percent_wifi_signal(net)%> % </td> - <td class="cbi-value-field" style="width:120px; text-align:right"> + <td class="cbi-value-field" style="width:100px;text-align:right"> <form class="inline" action="<%=url('admin/services/travelmate/wifiadd')%>" method="post"> - <input type="hidden" name="token" value="<%=token%>" /> - <input type="hidden" name="device" value="<%=utl.pcdata(dev)%>" /> - <input type="hidden" name="ssid" value="<%=utl.pcdata(net.ssid)%>" /> - <input type="hidden" name="wep" value="<%=net.encryption.wep and 1 or 0%>" /> + <input type="hidden" name="token" value="<%=token%>"/> + <input type="hidden" name="device" value="<%=utl.pcdata(dev)%>"/> + <input type="hidden" name="ssid" value="<%=utl.pcdata(net.ssid)%>"/> + <input type="hidden" name="wep" value="<%=net.encryption.wep and 1 or 0%>"/> <% if net.encryption.wpa then %> - <input type="hidden" name="wpa_version" value="<%=net.encryption.wpa%>" /> - <% for _, v in ipairs(net.encryption.auth_suites) do %><input type="hidden" name="wpa_suites" value="<%=v%>" /> + <input type="hidden" name="wpa_version" value="<%=net.encryption.wpa%>"/> + <% for _, v in ipairs(net.encryption.auth_suites) do %><input type="hidden" name="wpa_suites" value="<%=v%>"/> <% end; end %> - <input class="cbi-button cbi-button-apply" style="width:110px" type="submit" value="<%:Add Uplink%>" /> + <input class="cbi-button cbi-button-apply" type="submit" value="<%:Add Uplink%>"/> </form> </td> </tr> @@ -76,14 +76,15 @@ This is free software, licensed under the Apache License, Version 2.0 </table> </fieldset> <div class="cbi-page-actions right"> - <form class="inline" action="<%=url('admin/services/travelmate/stations')%>" method="post"> - <input class="cbi-button cbi-button-reset" type="submit" value="<%:Back to overview%>" /> - </form> <form class="inline" action="<%=url('admin/services/travelmate/wifiscan')%>" method="post"> - <input type="hidden" name="token" value="<%=token%>" /> - <input type="hidden" name="device" value="<%=utl.pcdata(dev)%>" /> - <input class="cbi-button cbi-input-find" type="submit" value="<%:Repeat scan%>" /> + <input type="hidden" name="token" value="<%=token%>"/> + <input type="hidden" name="device" value="<%=utl.pcdata(dev)%>"/> + <input class="cbi-button cbi-input-find" type="submit" value="<%:Repeat scan%>"/> </form> + <form class="inline" action="<%=url('admin/services/travelmate/stations')%>" method="post"> + <input class="cbi-button cbi-button-reset" type="submit" value="<%:Back to overview%>"/> + </form> +</div> </div> <%+footer%> 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" |