mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-13 20:08:05 +08:00
🌈 Sync 2026-11-13 03:33:44
This commit is contained in:
1 parent
4fe4df083c
commit
82323be37b
37 files changed
+938
-6332
No files matched your search
@@ -1,48 +1,21 @@
|
||||
#
|
||||
# Copyright (C) 2008-2014 The LuCI Team <luci@lists.subsignal.org>
|
||||
#
|
||||
# This is free software, licensed under the Apache License, Version 2.0 .
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-fancontrol
|
||||
PKG_VERSION:=1.0.0
|
||||
PKG_RELEASE:=5
|
||||
PKG_LICENSE:=Apache-2.0
|
||||
PKG_MAINTAINER:=Dante <dante@seckv.com>
|
||||
|
||||
LUCI_TITLE:=LuCI support for BPI-R4 PWM Fan Control
|
||||
LUCI_DEPENDS:=+luci-base +ucode +ucode-mod-fs +ucode-mod-uci +ucode-mod-ubus
|
||||
LUCI_TITLE:=LuCI support for the generic PWM fan controller
|
||||
LUCI_DEPENDS:=+luci-base +fancontrol
|
||||
LUCI_PKGARCH:=all
|
||||
|
||||
define Package/$(PKG_NAME)/conffiles
|
||||
/etc/config/fancontrol
|
||||
endef
|
||||
PKG_LICENSE:=Apache-2.0
|
||||
PKG_MAINTAINER:=JiaY-shi <shi05275@163.com>
|
||||
|
||||
define Package/$(PKG_NAME)/postinst
|
||||
#!/bin/sh
|
||||
[ -n "$${IPKG_INSTROOT}" ] || {
|
||||
chmod 755 /etc/init.d/fancontrol /usr/sbin/fancontrold 2>/dev/null
|
||||
/etc/init.d/rpcd restart
|
||||
/etc/init.d/fancontrol enable
|
||||
/etc/init.d/fancontrol restart
|
||||
}
|
||||
exit 0
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/prerm
|
||||
#!/bin/sh
|
||||
if [ -z "$${IPKG_INSTROOT}" ]; then
|
||||
/etc/init.d/fancontrol stop
|
||||
/etc/init.d/fancontrol disable
|
||||
fi
|
||||
exit 0
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/postrm
|
||||
#!/bin/sh
|
||||
if [ -z "$${IPKG_INSTROOT}" ]; then
|
||||
rm -f /var/log/fancontrol.log*
|
||||
rm -f /var/run/fancontrol.*
|
||||
fi
|
||||
exit 0
|
||||
endef
|
||||
PKG_NAME:=luci-app-fancontrol
|
||||
PKG_VERSION:=2.2.0
|
||||
PKG_RELEASE:=6
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
@@ -0,0 +1,171 @@
|
||||
.fancontrol-runtime {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.fancontrol-status {
|
||||
width: 100%;
|
||||
max-width: 1200px;
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(127, 127, 127, .28);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.fancontrol-status-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
min-height: 0;
|
||||
padding: .4rem .7rem;
|
||||
background: rgba(127, 127, 127, .08);
|
||||
border-bottom: 1px solid rgba(127, 127, 127, .22);
|
||||
}
|
||||
|
||||
.fancontrol-status-title {
|
||||
font-size: .88rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.fancontrol-metrics {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.fancontrol-metric {
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
padding: .55rem .7rem;
|
||||
border-right: 1px solid rgba(127, 127, 127, .2);
|
||||
}
|
||||
|
||||
.fancontrol-metric:last-child {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
.fancontrol-metric-label,
|
||||
.fancontrol-detail-label {
|
||||
display: block;
|
||||
color: var(--text-color-medium, inherit);
|
||||
font-size: .72rem;
|
||||
}
|
||||
|
||||
.fancontrol-metric-reading {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: .3rem;
|
||||
min-height: 0;
|
||||
margin-top: .12rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.fancontrol-metric-value {
|
||||
font-size: 1.18rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.fancontrol-metric-unit {
|
||||
overflow: hidden;
|
||||
color: var(--text-color-medium, inherit);
|
||||
font-size: .72rem;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.fancontrol-chart-wrap {
|
||||
height: 72px;
|
||||
margin-top: .4rem;
|
||||
}
|
||||
|
||||
.fancontrol-chart {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
color: var(--text-color-medium, #666);
|
||||
background: rgba(127, 127, 127, .025);
|
||||
border: 1px solid rgba(127, 127, 127, .24);
|
||||
}
|
||||
|
||||
.fancontrol-chart-temperature {
|
||||
--fancontrol-chart-line: #c74b45;
|
||||
--fancontrol-chart-fill: rgba(199, 75, 69, .2);
|
||||
}
|
||||
|
||||
.fancontrol-chart-pwm {
|
||||
--fancontrol-chart-line: #1976d2;
|
||||
--fancontrol-chart-fill: rgba(25, 118, 210, .2);
|
||||
}
|
||||
|
||||
.fancontrol-chart-rpm {
|
||||
--fancontrol-chart-line: #2f8a57;
|
||||
--fancontrol-chart-fill: rgba(47, 138, 87, .2);
|
||||
}
|
||||
|
||||
.fancontrol-details {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
gap: .3rem 1rem;
|
||||
padding: .42rem .7rem;
|
||||
background: rgba(127, 127, 127, .04);
|
||||
border-top: 1px solid rgba(127, 127, 127, .2);
|
||||
}
|
||||
|
||||
.fancontrol-detail {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(7rem, .34fr) minmax(0, 1fr);
|
||||
align-items: baseline;
|
||||
gap: .45rem;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.fancontrol-detail-value {
|
||||
min-width: 0;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.fancontrol-ok {
|
||||
color: var(--success-color-medium, #00884a);
|
||||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
.fancontrol-metrics {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.fancontrol-metric:nth-child(2) {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
.fancontrol-metric:last-child {
|
||||
grid-column: 1 / -1;
|
||||
border-top: 1px solid rgba(127, 127, 127, .2);
|
||||
}
|
||||
|
||||
.fancontrol-details {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media (max-width: 420px) {
|
||||
.fancontrol-metrics {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.fancontrol-metric,
|
||||
.fancontrol-metric:nth-child(2) {
|
||||
border-right: 0;
|
||||
border-top: 1px solid rgba(127, 127, 127, .2);
|
||||
}
|
||||
|
||||
.fancontrol-metric:first-child {
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
.fancontrol-metric:last-child {
|
||||
grid-column: auto;
|
||||
}
|
||||
|
||||
.fancontrol-detail {
|
||||
grid-template-columns: 1fr;
|
||||
gap: .15rem;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,463 @@
|
||||
'use strict';
|
||||
'require dom';
|
||||
'require form';
|
||||
'require fs';
|
||||
'require poll';
|
||||
'require rpc';
|
||||
'require uci';
|
||||
'require view';
|
||||
|
||||
const callServiceList = rpc.declare({
|
||||
object: 'service',
|
||||
method: 'list',
|
||||
params: [ 'name' ],
|
||||
expect: { '': {} }
|
||||
});
|
||||
|
||||
const HISTORY_WINDOW_MS = 2 * 60 * 1000;
|
||||
const TIME_GRID_INTERVAL_MS = 10 * 1000;
|
||||
const TIME_LABEL_INTERVAL_MS = 30 * 1000;
|
||||
const VALUE_GRID_DIVISIONS = 4;
|
||||
|
||||
function serviceRunning(result) {
|
||||
const instances = result?.fancontrol?.instances || {};
|
||||
|
||||
return Object.keys(instances).some(function(name) {
|
||||
return instances[name].running === true;
|
||||
});
|
||||
}
|
||||
|
||||
function parseStatus(text) {
|
||||
const status = {};
|
||||
|
||||
String(text || '').split(/\n/).forEach(function(line) {
|
||||
const separator = line.indexOf('=');
|
||||
|
||||
if (separator > 0)
|
||||
status[line.substring(0, separator)] = line.substring(separator + 1);
|
||||
});
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
function validStatusNumber(value) {
|
||||
const number = Number(value);
|
||||
|
||||
return Number.isFinite(number) && number >= 0 ? number : null;
|
||||
}
|
||||
|
||||
function appendHistory(history, running, status) {
|
||||
const now = Date.now();
|
||||
const temperature = validStatusNumber(status.temperature_mc);
|
||||
const pwm = validStatusNumber(status.pwm);
|
||||
const rpm = validStatusNumber(status.rpm);
|
||||
|
||||
history.push({
|
||||
time: now,
|
||||
temperature: running && temperature != null ? temperature / 1000 : null,
|
||||
pwm: running && pwm != null ? pwm * 100 / 255 : null,
|
||||
rpm: running ? rpm : null
|
||||
});
|
||||
|
||||
while (history.length && history[0].time < now - HISTORY_WINDOW_MS)
|
||||
history.shift();
|
||||
}
|
||||
|
||||
function chartScale(history, key, minimumMax, step) {
|
||||
let maximum = minimumMax;
|
||||
|
||||
history.forEach(function(sample) {
|
||||
if (sample[key] != null)
|
||||
maximum = Math.max(maximum, sample[key]);
|
||||
});
|
||||
|
||||
return Math.ceil(maximum / step) * step;
|
||||
}
|
||||
|
||||
function drawChart(canvas, history, key, options) {
|
||||
const style = window.getComputedStyle(canvas);
|
||||
const width = Math.max(canvas.clientWidth, 1);
|
||||
const height = Math.max(canvas.clientHeight, 1);
|
||||
const ratio = Math.min(window.devicePixelRatio || 1, 2);
|
||||
const context = canvas.getContext('2d');
|
||||
const padding = { left: 28, right: 5, top: 6, bottom: 14 };
|
||||
const plotWidth = Math.max(width - padding.left - padding.right, 1);
|
||||
const plotHeight = Math.max(height - padding.top - padding.bottom, 1);
|
||||
const plotBottom = padding.top + plotHeight;
|
||||
const now = history.length ? history[history.length - 1].time : Date.now();
|
||||
const start = now - HISTORY_WINDOW_MS;
|
||||
const maximum = chartScale(history, key, options.minimumMax, options.step);
|
||||
const lineColor = style.getPropertyValue('--fancontrol-chart-line').trim() || '#1976d2';
|
||||
const fillColor = style.getPropertyValue('--fancontrol-chart-fill').trim() || 'rgba(25, 118, 210, .2)';
|
||||
const labelColor = style.color || '#666';
|
||||
const gridColor = 'rgba(127, 127, 127, .2)';
|
||||
let segment = [];
|
||||
|
||||
canvas.width = Math.round(width * ratio);
|
||||
canvas.height = Math.round(height * ratio);
|
||||
context.setTransform(ratio, 0, 0, ratio, 0, 0);
|
||||
context.clearRect(0, 0, width, height);
|
||||
|
||||
context.strokeStyle = gridColor;
|
||||
context.lineWidth = 1;
|
||||
context.beginPath();
|
||||
for (let elapsed = 0; elapsed <= HISTORY_WINDOW_MS; elapsed += TIME_GRID_INTERVAL_MS) {
|
||||
const x = padding.left + plotWidth * elapsed / HISTORY_WINDOW_MS;
|
||||
|
||||
context.moveTo(x, padding.top);
|
||||
context.lineTo(x, plotBottom);
|
||||
}
|
||||
for (let division = 0; division <= VALUE_GRID_DIVISIONS; division++) {
|
||||
const y = padding.top + plotHeight * division / VALUE_GRID_DIVISIONS;
|
||||
|
||||
context.moveTo(padding.left, y);
|
||||
context.lineTo(padding.left + plotWidth, y);
|
||||
}
|
||||
context.stroke();
|
||||
|
||||
context.fillStyle = labelColor;
|
||||
context.font = '9px sans-serif';
|
||||
context.textAlign = 'right';
|
||||
context.textBaseline = 'top';
|
||||
context.fillText(options.format(maximum), padding.left - 4, padding.top - 1);
|
||||
context.textBaseline = 'bottom';
|
||||
context.fillText(options.format(0), padding.left - 4, plotBottom + 1);
|
||||
context.textBaseline = 'middle';
|
||||
context.fillText(options.format(maximum / 2), padding.left - 4,
|
||||
padding.top + plotHeight / 2);
|
||||
|
||||
context.textBaseline = 'bottom';
|
||||
for (let elapsed = 0; elapsed <= HISTORY_WINDOW_MS; elapsed += TIME_LABEL_INTERVAL_MS) {
|
||||
const x = padding.left + plotWidth * elapsed / HISTORY_WINDOW_MS;
|
||||
const remaining = (HISTORY_WINDOW_MS - elapsed) / 1000;
|
||||
|
||||
context.textAlign = elapsed === 0 ? 'left' :
|
||||
elapsed === HISTORY_WINDOW_MS ? 'right' : 'center';
|
||||
context.fillText(remaining ? '-%ds'.format(remaining) : '0', x, height);
|
||||
}
|
||||
|
||||
function point(sample) {
|
||||
return {
|
||||
x: padding.left + (sample.time - start) / HISTORY_WINDOW_MS * plotWidth,
|
||||
y: plotBottom - sample[key] / maximum * plotHeight
|
||||
};
|
||||
}
|
||||
|
||||
function drawSegment() {
|
||||
if (!segment.length)
|
||||
return;
|
||||
|
||||
if (segment.length > 1) {
|
||||
context.beginPath();
|
||||
context.moveTo(segment[0].x, plotBottom);
|
||||
segment.forEach(function(item) { context.lineTo(item.x, item.y); });
|
||||
context.lineTo(segment[segment.length - 1].x, plotBottom);
|
||||
context.closePath();
|
||||
context.fillStyle = fillColor;
|
||||
context.fill();
|
||||
|
||||
context.beginPath();
|
||||
segment.forEach(function(item, index) {
|
||||
if (index)
|
||||
context.lineTo(item.x, item.y);
|
||||
else
|
||||
context.moveTo(item.x, item.y);
|
||||
});
|
||||
context.strokeStyle = lineColor;
|
||||
context.lineWidth = 1.5;
|
||||
context.lineJoin = 'round';
|
||||
context.stroke();
|
||||
} else {
|
||||
context.beginPath();
|
||||
context.arc(segment[0].x, segment[0].y, 2, 0, Math.PI * 2);
|
||||
context.fillStyle = lineColor;
|
||||
context.fill();
|
||||
}
|
||||
|
||||
segment = [];
|
||||
}
|
||||
|
||||
history.forEach(function(sample) {
|
||||
if (sample[key] == null) {
|
||||
drawSegment();
|
||||
return;
|
||||
}
|
||||
|
||||
segment.push(point(sample));
|
||||
});
|
||||
drawSegment();
|
||||
}
|
||||
|
||||
function statusMetric(title, value, unit, chartClass) {
|
||||
const canvas = E('canvas', {
|
||||
'class': 'fancontrol-chart fancontrol-chart-%s'.format(chartClass),
|
||||
'role': 'img',
|
||||
'aria-label': title
|
||||
});
|
||||
const children = [
|
||||
E('span', { 'class': 'fancontrol-metric-label' }, title),
|
||||
E('div', { 'class': 'fancontrol-metric-reading' }, [
|
||||
E('span', { 'class': 'fancontrol-metric-value' }, value),
|
||||
unit ? E('span', { 'class': 'fancontrol-metric-unit' }, unit) : ''
|
||||
]),
|
||||
E('div', { 'class': 'fancontrol-chart-wrap' }, canvas)
|
||||
];
|
||||
|
||||
return {
|
||||
node: E('div', { 'class': 'fancontrol-metric' }, children),
|
||||
canvas: canvas
|
||||
};
|
||||
}
|
||||
|
||||
function statusDetail(title, value) {
|
||||
return E('div', { 'class': 'fancontrol-detail' }, [
|
||||
E('span', { 'class': 'fancontrol-detail-label' }, title),
|
||||
E('span', { 'class': 'fancontrol-detail-value' }, value)
|
||||
]);
|
||||
}
|
||||
|
||||
function renderStatus(node, running, status, history) {
|
||||
const temp = Number(status.temperature_mc);
|
||||
const pwm = Number(status.pwm);
|
||||
const rpm = Number(status.rpm);
|
||||
const tempValid = Number.isFinite(temp) && temp >= 0;
|
||||
const pwmValid = Number.isFinite(pwm) && pwm >= 0;
|
||||
const rpmValid = Number.isFinite(rpm) && rpm >= 0;
|
||||
const pwmPercent = pwmValid ? Math.round(pwm * 100 / 255) : null;
|
||||
const fault = status.error
|
||||
? E('span', { 'class': 'label warning' }, status.error)
|
||||
: E('span', { 'class': 'fancontrol-ok' }, _('None'));
|
||||
const temperatureMetric = statusMetric(_('Temperature'),
|
||||
tempValid ? '%.1f'.format(temp / 1000) : '-', tempValid ? '°C' : '', 'temperature');
|
||||
const pwmMetric = statusMetric(_('PWM output'), pwmValid ? String(pwm) : '-',
|
||||
pwmValid ? '/ 255 · %d%%'.format(pwmPercent) : '', 'pwm');
|
||||
const rpmMetric = statusMetric(_('Fan speed'), rpmValid ? String(rpm) : '-',
|
||||
rpmValid ? 'RPM' : '', 'rpm');
|
||||
|
||||
dom.content(node, E('div', { 'class': 'fancontrol-status' }, [
|
||||
E('div', { 'class': 'fancontrol-status-head' }, [
|
||||
E('span', { 'class': 'fancontrol-status-title' }, _('Runtime Status')),
|
||||
E('span', { 'class': running ? 'label success' : 'label warning' },
|
||||
running ? _('Running') : _('Stopped'))
|
||||
]),
|
||||
E('div', { 'class': 'fancontrol-metrics' }, [
|
||||
temperatureMetric.node,
|
||||
pwmMetric.node,
|
||||
rpmMetric.node
|
||||
]),
|
||||
E('div', { 'class': 'fancontrol-details' }, [
|
||||
statusDetail(_('Temperature input'), status.thermal_file || '-'),
|
||||
statusDetail(_('PWM device'), status.fan_file || '-'),
|
||||
statusDetail(_('Fault'), fault)
|
||||
])
|
||||
]));
|
||||
|
||||
drawChart(temperatureMetric.canvas, history, 'temperature', {
|
||||
minimumMax: 100,
|
||||
step: 10,
|
||||
format: function(value) { return '%d°'.format(value); }
|
||||
});
|
||||
drawChart(pwmMetric.canvas, history, 'pwm', {
|
||||
minimumMax: 100,
|
||||
step: 100,
|
||||
format: function(value) { return '%d%%'.format(value); }
|
||||
});
|
||||
drawChart(rpmMetric.canvas, history, 'rpm', {
|
||||
minimumMax: 1000,
|
||||
step: 500,
|
||||
format: function(value) { return String(value); }
|
||||
});
|
||||
}
|
||||
|
||||
function validateAutoPath(sectionId, value) {
|
||||
if (value === 'auto' || value?.startsWith('/'))
|
||||
return true;
|
||||
|
||||
return _('Enter "auto" or an absolute sysfs path.');
|
||||
}
|
||||
|
||||
return view.extend({
|
||||
load() {
|
||||
return uci.load('fancontrol');
|
||||
},
|
||||
|
||||
render() {
|
||||
let m, s, o;
|
||||
let startTemp, fullTemp, startSpeed, maxSpeed, kickSpeed, kickMs;
|
||||
|
||||
m = new form.Map('fancontrol', _('Fan Control'),
|
||||
_('Configure a continuous PWM curve based on device temperature. Automatic hardware detection is suitable for most devices.'));
|
||||
|
||||
s = m.section(form.TypedSection, 'fancontrol', _('Runtime Status'));
|
||||
s.anonymous = true;
|
||||
s.addremove = false;
|
||||
s.render = function() {
|
||||
const history = [];
|
||||
const node = E('div', { 'class': 'cbi-section fancontrol-runtime' }, [
|
||||
E('link', {
|
||||
'rel': 'stylesheet',
|
||||
'href': L.resource('view/fancontrol.css')
|
||||
}),
|
||||
E('div', { 'class': 'cbi-section-node' }, _('Collecting data...'))
|
||||
]);
|
||||
const statusNode = node.lastElementChild;
|
||||
|
||||
poll.add(function() {
|
||||
return Promise.all([
|
||||
L.resolveDefault(callServiceList('fancontrol'), {}),
|
||||
L.resolveDefault(fs.read_direct('/var/run/fancontrol.status'), '')
|
||||
]).then(function(result) {
|
||||
const running = serviceRunning(result[0]);
|
||||
const status = parseStatus(result[1]);
|
||||
|
||||
appendHistory(history, running, status);
|
||||
renderStatus(statusNode, running, status, history);
|
||||
});
|
||||
}, 5);
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
s = m.section(form.NamedSection, 'settings', 'fancontrol', _('Settings'));
|
||||
s.addremove = false;
|
||||
s.tab('curve', _('Temperature Curve'),
|
||||
_('Controls when the fan starts and how its speed rises with temperature.'));
|
||||
s.tab('hardware', _('Hardware'),
|
||||
_('Automatic detection works on most devices. Select explicit sysfs entries only when necessary.'));
|
||||
s.tab('safety', _('Safety'),
|
||||
_('Controls startup assistance and fail-safe behavior. Full-speed safety defaults are recommended.'));
|
||||
|
||||
o = s.taboption('curve', form.Flag, 'enabled', _('Enable'));
|
||||
o.default = o.disabled;
|
||||
o.rmempty = false;
|
||||
o.description = _('Run the controller and apply this temperature curve.');
|
||||
|
||||
startTemp = s.taboption('curve', form.Value, 'start_temp', _('Start temperature'));
|
||||
startTemp.default = '45';
|
||||
startTemp.datatype = 'range(-40,200)';
|
||||
startTemp.rmempty = false;
|
||||
startTemp.description = _('The fan remains off below this temperature and starts at the minimum running PWM when it is reached. Unit: °C.');
|
||||
|
||||
fullTemp = s.taboption('curve', form.Value, 'full_speed_temp', _('Full-speed temperature'));
|
||||
fullTemp.default = '85';
|
||||
fullTemp.datatype = 'range(-39,250)';
|
||||
fullTemp.rmempty = false;
|
||||
fullTemp.description = _('PWM rises linearly and reaches the configured maximum at this temperature. Unit: °C.');
|
||||
fullTemp.validate = function(sectionId, value) {
|
||||
if (Number(value) <= Number(startTemp.formvalue(sectionId)))
|
||||
return _('Full-speed temperature must be higher than start temperature.');
|
||||
return true;
|
||||
};
|
||||
|
||||
o = s.taboption('curve', form.Value, 'hysteresis', _('Stop hysteresis'));
|
||||
o.default = '3';
|
||||
o.datatype = 'range(0,50)';
|
||||
o.rmempty = false;
|
||||
o.description = _('After starting, the fan stops only after temperature falls this many degrees below the start temperature. This prevents rapid on/off cycling.');
|
||||
|
||||
startSpeed = s.taboption('curve', form.Value, 'start_speed', _('Minimum running PWM'));
|
||||
startSpeed.default = '64';
|
||||
startSpeed.datatype = 'range(1,255)';
|
||||
startSpeed.rmempty = false;
|
||||
startSpeed.description = _('Lowest PWM used while the fan is running. Increase it if the fan stalls or cannot maintain rotation. Range: 1–255.');
|
||||
|
||||
maxSpeed = s.taboption('curve', form.Value, 'max_speed', _('Maximum PWM'));
|
||||
maxSpeed.default = '255';
|
||||
maxSpeed.datatype = 'range(1,255)';
|
||||
maxSpeed.rmempty = false;
|
||||
maxSpeed.description = _('Highest PWM allowed by the curve. A value of 255 means 100% duty cycle.');
|
||||
maxSpeed.validate = function(sectionId, value) {
|
||||
if (Number(value) < Number(startSpeed.formvalue(sectionId)))
|
||||
return _('Maximum PWM must not be lower than minimum running PWM.');
|
||||
return true;
|
||||
};
|
||||
|
||||
o = s.taboption('curve', form.Value, 'interval', _('Polling interval'));
|
||||
o.default = '5';
|
||||
o.datatype = 'range(1,300)';
|
||||
o.rmempty = false;
|
||||
o.description = _('How often the temperature is read and the PWM output is updated. Unit: seconds.');
|
||||
|
||||
o = s.taboption('hardware', form.Value, 'thermal_file', _('Temperature input'));
|
||||
o.default = 'auto';
|
||||
o.rmempty = false;
|
||||
o.validate = validateAutoPath;
|
||||
o.description = _('Use "auto" to select a CPU or SoC thermal sensor, or enter an absolute thermal zone or hwmon tempN_input path.');
|
||||
|
||||
o = s.taboption('hardware', form.Value, 'thermal_zone', _('Thermal zone type'));
|
||||
o.default = 'auto';
|
||||
o.rmempty = false;
|
||||
o.description = _('Preferred thermal zone type when temperature input is automatic, for example cpu_top_thermal. Leave as "auto" unless several sensors are available.');
|
||||
|
||||
o = s.taboption('hardware', form.Value, 'fan_file', _('PWM output'));
|
||||
o.default = 'auto';
|
||||
o.rmempty = false;
|
||||
o.validate = validateAutoPath;
|
||||
o.description = _('Use "auto" to select a writable hwmon pwmN output, or enter its absolute path. cooling_device cur_state is not a PWM output.');
|
||||
|
||||
o = s.taboption('hardware', form.Value, 'fan_hwmon', _('Hwmon device name'));
|
||||
o.default = 'auto';
|
||||
o.rmempty = false;
|
||||
o.description = _('Preferred hwmon name when PWM output is automatic. The pwmfan driver is preferred by default.');
|
||||
|
||||
o = s.taboption('hardware', form.Value, 'enable_file', _('PWM mode control'));
|
||||
o.default = 'auto';
|
||||
o.rmempty = false;
|
||||
o.validate = validateAutoPath;
|
||||
o.description = _('Optional pwmN_enable path used to select manual PWM mode. With "auto", the matching control is used when available.');
|
||||
|
||||
o = s.taboption('hardware', form.Value, 'cooling_device', _('Kernel cooling device'));
|
||||
o.default = 'auto';
|
||||
o.value('auto');
|
||||
o.value('none');
|
||||
o.rmempty = false;
|
||||
o.validate = function(sectionId, value) {
|
||||
return value === 'none' ? true : validateAutoPath(sectionId, value);
|
||||
};
|
||||
o.description = _('Use auto for a single pwm-fan device, an explicit cooling_device path for multiple fans, or none when kernel fan control is already handled elsewhere.');
|
||||
|
||||
o = s.taboption('hardware', form.Value, 'temp_div', _('Temperature divisor'));
|
||||
o.default = '1000';
|
||||
o.value('1');
|
||||
o.value('1000');
|
||||
o.datatype = 'range(1,1000000)';
|
||||
o.rmempty = false;
|
||||
o.description = _('Divides the raw sensor value before control calculations. Standard Linux temperature inputs use 1000; sensors reporting whole degrees use 1.');
|
||||
|
||||
kickSpeed = s.taboption('safety', form.Value, 'kick_speed', _('Start kick PWM'));
|
||||
kickSpeed.default = '255';
|
||||
kickSpeed.datatype = 'range(0,255)';
|
||||
kickSpeed.rmempty = false;
|
||||
kickSpeed.description = _('Brief PWM applied when a stopped fan starts. It helps fans that cannot start reliably at low duty. Set to 0 together with a zero duration to disable.');
|
||||
|
||||
kickMs = s.taboption('safety', form.Value, 'kick_ms', _('Start kick duration'));
|
||||
kickMs.default = '500';
|
||||
kickMs.datatype = 'range(0,10000)';
|
||||
kickMs.rmempty = false;
|
||||
kickMs.description = _('How long the startup kick is applied. Unit: milliseconds.');
|
||||
kickMs.validate = function(sectionId, value) {
|
||||
if (Number(value) > 0 && Number(kickSpeed.formvalue(sectionId)) === 0)
|
||||
return _('Start kick PWM must be non-zero when a kick duration is configured.');
|
||||
return true;
|
||||
};
|
||||
|
||||
o = s.taboption('safety', form.Value, 'fail_safe_speed', _('Sensor failure PWM'));
|
||||
o.default = '255';
|
||||
o.datatype = 'range(0,255)';
|
||||
o.rmempty = false;
|
||||
o.description = _('PWM used when the temperature sensor cannot be read. Keeping 255 is the safest choice.');
|
||||
|
||||
o = s.taboption('safety', form.Value, 'exit_speed', _('Service exit PWM'));
|
||||
o.default = '255';
|
||||
o.datatype = 'range(0,255)';
|
||||
o.rmempty = false;
|
||||
o.description = _('PWM written when the service stops. Keeping the fan at full speed avoids losing cooling after an unexpected exit.');
|
||||
|
||||
o = s.taboption('safety', form.Flag, 'debug', _('Debug logging'));
|
||||
o.default = o.disabled;
|
||||
o.rmempty = false;
|
||||
o.description = _('Write temperature, PWM and RPM values to the system log at every polling interval.');
|
||||
|
||||
return m.render();
|
||||
}
|
||||
});
|
||||
@@ -1,88 +0,0 @@
|
||||
'use strict';
|
||||
'require view';
|
||||
'require rpc';
|
||||
'require poll';
|
||||
'require ui';
|
||||
|
||||
var callGetLogs = rpc.declare({
|
||||
object: 'luci.fancontrol',
|
||||
method: 'get_logs',
|
||||
params: [ 'lines' ]
|
||||
});
|
||||
|
||||
var callClearLogs = rpc.declare({
|
||||
object: 'luci.fancontrol',
|
||||
method: 'clear_logs'
|
||||
});
|
||||
|
||||
return view.extend({
|
||||
handleSaveApply: null,
|
||||
handleSave: null,
|
||||
handleReset: null,
|
||||
|
||||
render: function() {
|
||||
var area = E('textarea', {
|
||||
id: 'fancontrol_log_content',
|
||||
style: 'width:100%; height:460px; background:#f9f9f9; color:#222; padding:12px; border:1px solid #ccc; border-radius:4px; font-family:monospace; font-size:12px; line-height:1.5; overflow-y:auto; white-space:pre-wrap; word-break:break-all;',
|
||||
readonly: 'readonly'
|
||||
}, _('正在加载日志...'));
|
||||
|
||||
var btnRefresh = E('button', {
|
||||
'class': 'btn cbi-button cbi-button-action',
|
||||
'style': 'margin-right:10px;',
|
||||
click: ui.createHandlerFn(this, 'updateLogs')
|
||||
}, _('刷新日志'));
|
||||
|
||||
var btnClear = E('button', {
|
||||
'class': 'btn cbi-button cbi-button-reset',
|
||||
click: ui.createHandlerFn(this, 'handleClearLogs')
|
||||
}, _('清空日志'));
|
||||
|
||||
poll.add(L.bind(this.updateLogs, this), 5);
|
||||
|
||||
// 初始加载一次日志
|
||||
this.updateLogs();
|
||||
|
||||
return E('div', { 'class': 'cbi-map' }, [
|
||||
E('h2', {}, _('风扇控制') + ' - ' + _('运行日志')),
|
||||
E('div', { 'class': 'cbi-map-descr' }, _('实时展示温控守护进程的调速动作、温度变化与自检日志。')),
|
||||
E('fieldset', { 'class': 'cbi-section' }, [
|
||||
E('legend', {}, _('系统日志')),
|
||||
E('div', { 'class': 'cbi-section-node' }, [
|
||||
E('div', { 'style': 'margin-bottom:10px;' }, [ btnRefresh, btnClear ]),
|
||||
area
|
||||
])
|
||||
])
|
||||
]);
|
||||
},
|
||||
|
||||
updateLogs: function() {
|
||||
return callGetLogs(100).then(function(res) {
|
||||
var area = document.getElementById('fancontrol_log_content');
|
||||
if (area) {
|
||||
if (res && res.logs && res.logs.length > 0) {
|
||||
area.value = res.logs.join('\n');
|
||||
area.scrollTop = area.scrollHeight;
|
||||
} else {
|
||||
area.value = _('暂无日志记录。');
|
||||
}
|
||||
}
|
||||
}).catch(function(err) {
|
||||
var area = document.getElementById('fancontrol_log_content');
|
||||
if (area) area.value = _('读取日志失败: %s').format(err.message);
|
||||
});
|
||||
},
|
||||
|
||||
handleClearLogs: function() {
|
||||
return callClearLogs().then(L.bind(function(res) {
|
||||
if (res && res.success) {
|
||||
ui.addNotification(null, E('p', _('日志已成功清空。')), 'info');
|
||||
this.updateLogs();
|
||||
} else {
|
||||
ui.addNotification(null, E('p', _('清空日志失败。')), 'error');
|
||||
}
|
||||
}, this)).catch(function(err) {
|
||||
ui.addNotification(null, E('p', _('RPC 请求失败: %s').format(err.message)), 'error');
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -1,329 +0,0 @@
|
||||
'use strict';
|
||||
'require view';
|
||||
'require rpc';
|
||||
'require poll';
|
||||
'require ui';
|
||||
'require dom';
|
||||
|
||||
var callGetStatus = rpc.declare({
|
||||
object: 'luci.fancontrol',
|
||||
method: 'get_status'
|
||||
});
|
||||
|
||||
var callSetLevel = rpc.declare({
|
||||
object: 'luci.fancontrol',
|
||||
method: 'set_level',
|
||||
params: [ 'level' ]
|
||||
});
|
||||
|
||||
var callServiceAction = rpc.declare({
|
||||
object: 'luci.fancontrol',
|
||||
method: 'service',
|
||||
params: [ 'action' ]
|
||||
});
|
||||
|
||||
return view.extend({
|
||||
handleSaveApply: null,
|
||||
handleSave: null,
|
||||
handleReset: null,
|
||||
|
||||
load: function() {
|
||||
return callGetStatus();
|
||||
},
|
||||
|
||||
render: function(status) {
|
||||
var container = E('div', { 'class': 'cbi-map' }, [
|
||||
E('h2', {}, _('风扇控制') + ' - ' + _('状态概览')),
|
||||
E('div', { 'class': 'cbi-map-descr' }, _('实时监控香蕉派 BPI-R4 处理器温度与 PWM 风扇运行档位,提供硬件即时测试功能。'))
|
||||
]);
|
||||
|
||||
// 运行状态卡片
|
||||
var statusSection = E('fieldset', { 'class': 'cbi-section' }, [
|
||||
E('legend', {}, _('运行状态')),
|
||||
E('div', { 'class': 'cbi-section-node' }, [
|
||||
E('table', { 'class': 'table cbi-section-table' }, [
|
||||
E('tr', { 'class': 'tr' }, [
|
||||
E('td', { 'class': 'td left', 'width': '33%' }, _('服务状态')),
|
||||
E('td', { 'class': 'td left' }, [
|
||||
E('span', { id: 'fan-service-state', style: 'font-weight:bold; margin-right:15px;' }, '-'),
|
||||
E('button', {
|
||||
id: 'fan-restart-btn',
|
||||
'class': 'btn cbi-button cbi-button-reload',
|
||||
click: ui.createHandlerFn(this, 'handleServiceAction', 'restart')
|
||||
}, _('重启服务'))
|
||||
])
|
||||
]),
|
||||
E('tr', { 'class': 'tr' }, [
|
||||
E('td', { 'class': 'td left' }, _('运行模式')),
|
||||
E('td', { 'class': 'td left', 'id': 'fan-service-mode', 'style': 'font-weight:bold;' }, '-')
|
||||
]),
|
||||
E('tr', { 'class': 'tr' }, [
|
||||
E('td', { 'class': 'td left' }, _('处理器温度')),
|
||||
E('td', { 'class': 'td left', 'id': 'fan-cpu-temp', 'style': 'font-size:16px; font-weight:bold;' }, '-')
|
||||
]),
|
||||
E('tr', { 'class': 'tr' }, [
|
||||
E('td', { 'class': 'td left' }, _('当前风扇档位')),
|
||||
E('td', { 'class': 'td left', 'id': 'fan-cur-level', 'style': 'font-weight:bold;' }, '-')
|
||||
]),
|
||||
E('tr', { 'class': 'tr' }, [
|
||||
E('td', { 'class': 'td left' }, _('脉宽占空比')),
|
||||
E('td', { 'class': 'td left', 'id': 'fan-pwm-duty' }, '-')
|
||||
])
|
||||
])
|
||||
])
|
||||
]);
|
||||
container.appendChild(statusSection);
|
||||
|
||||
// 当前策略配置卡片
|
||||
var policySection = E('fieldset', { 'class': 'cbi-section' }, [
|
||||
E('legend', {}, _('当前策略配置')),
|
||||
E('div', { 'class': 'cbi-section-node' }, [
|
||||
E('table', { 'class': 'table cbi-section-table' }, [
|
||||
E('tr', { 'class': 'tr', id: 'policy-row-interval' }, [
|
||||
E('td', { 'class': 'td left', 'width': '33%' }, _('检测轮询周期')),
|
||||
E('td', { 'class': 'td left', 'id': 'policy-interval' }, '-')
|
||||
]),
|
||||
E('tr', { 'class': 'tr', id: 'policy-row-spin' }, [
|
||||
E('td', { 'class': 'td left' }, _('启动除尘自检')),
|
||||
E('td', { 'class': 'td left', 'id': 'policy-start-spin' }, '-')
|
||||
]),
|
||||
E('tr', { 'class': 'tr', id: 'policy-row-low' }, [
|
||||
E('td', { 'class': 'td left' }, _('低速触发阈值')),
|
||||
E('td', { 'class': 'td left', 'id': 'policy-temp-low' }, '-')
|
||||
]),
|
||||
E('tr', { 'class': 'tr', id: 'policy-row-med' }, [
|
||||
E('td', { 'class': 'td left' }, _('中速触发阈值')),
|
||||
E('td', { 'class': 'td left', 'id': 'policy-temp-med' }, '-')
|
||||
]),
|
||||
E('tr', { 'class': 'tr', id: 'policy-row-high' }, [
|
||||
E('td', { 'class': 'td left' }, _('全速触发阈值')),
|
||||
E('td', { 'class': 'td left', 'id': 'policy-temp-high' }, '-')
|
||||
]),
|
||||
E('tr', { 'class': 'tr', id: 'policy-row-hyst' }, [
|
||||
E('td', { 'class': 'td left' }, _('换挡回差温差')),
|
||||
E('td', { 'class': 'td left', 'id': 'policy-hysteresis' }, '-')
|
||||
]),
|
||||
E('tr', { 'class': 'tr', id: 'policy-row-manual' }, [
|
||||
E('td', { 'class': 'td left' }, _('预设运转档位')),
|
||||
E('td', { 'class': 'td left', 'id': 'policy-manual-level' }, '-')
|
||||
]),
|
||||
E('tr', { 'class': 'tr', id: 'policy-row-kernel' }, [
|
||||
E('td', { 'class': 'td left' }, _('控制驱动策略')),
|
||||
E('td', { 'class': 'td left', 'id': 'policy-kernel-desc' }, _('系统内核设备树原生驱动接管'))
|
||||
])
|
||||
])
|
||||
])
|
||||
]);
|
||||
container.appendChild(policySection);
|
||||
|
||||
// 快速测试面板
|
||||
var testSection = E('fieldset', { 'class': 'cbi-section' }, [
|
||||
E('legend', {}, _('硬件快速测试')),
|
||||
E('div', { 'class': 'cbi-section-node' }, [
|
||||
E('p', { 'style': 'margin-bottom:15px; color:#666;' },
|
||||
_('点击按钮可即时下发档位进行硬件测试,测试结果立即生效并在状态栏回显。若服务处于运行中,后续温控检测将按设定规则恢复。')),
|
||||
E('div', { 'style': 'display:flex; gap:10px; flex-wrap:wrap;' }, [
|
||||
E('button', {
|
||||
'class': 'btn cbi-button cbi-button-reset',
|
||||
click: ui.createHandlerFn(this, 'handleSetLevel', 0)
|
||||
}, _('停止风扇 (0 级)')),
|
||||
E('button', {
|
||||
'class': 'btn cbi-button cbi-button-action',
|
||||
click: ui.createHandlerFn(this, 'handleSetLevel', 1)
|
||||
}, _('低速测试 (1 级)')),
|
||||
E('button', {
|
||||
'class': 'btn cbi-button cbi-button-action',
|
||||
click: ui.createHandlerFn(this, 'handleSetLevel', 2)
|
||||
}, _('中速测试 (2 级)')),
|
||||
E('button', {
|
||||
'class': 'btn cbi-button cbi-button-apply',
|
||||
click: ui.createHandlerFn(this, 'handleSetLevel', 3)
|
||||
}, _('全速测试 (3 级)'))
|
||||
])
|
||||
])
|
||||
]);
|
||||
container.appendChild(testSection);
|
||||
|
||||
// 初始刷新
|
||||
this.updateStatusView(status);
|
||||
|
||||
// 启动定时轮询 (每 3 秒)
|
||||
poll.add(L.bind(function() {
|
||||
return callGetStatus().then(L.bind(function(res) {
|
||||
this.updateStatusView(res);
|
||||
}, this));
|
||||
}, this), 3);
|
||||
|
||||
return container;
|
||||
},
|
||||
|
||||
updateStatusView: function(status) {
|
||||
if (!status) return;
|
||||
|
||||
var stateEl = document.getElementById('fan-service-state');
|
||||
if (stateEl) {
|
||||
if (status.state === 'managed') {
|
||||
stateEl.textContent = _('运行中 [受控]') + (status.pid ? ' [PID: ' + status.pid + ']' : '');
|
||||
stateEl.style.color = '#2e7d32';
|
||||
} else if (status.state === 'unmanaged') {
|
||||
stateEl.textContent = _('运行中 [非受控]') + (status.pid ? ' [PID: ' + status.pid + ']' : '');
|
||||
stateEl.style.color = '#ef6c00';
|
||||
} else {
|
||||
stateEl.textContent = _('已停止');
|
||||
stateEl.style.color = '#c62828';
|
||||
}
|
||||
}
|
||||
|
||||
var modeEl = document.getElementById('fan-service-mode');
|
||||
if (modeEl) {
|
||||
if (status.mode === 'auto') {
|
||||
modeEl.textContent = _('阶梯温控模式');
|
||||
modeEl.style.color = '#1565c0';
|
||||
} else if (status.mode === 'manual') {
|
||||
modeEl.textContent = _('手动定速模式');
|
||||
modeEl.style.color = '#6a1b9a';
|
||||
} else if (status.mode === 'kernel') {
|
||||
modeEl.textContent = _('内核接管模式');
|
||||
modeEl.style.color = '#455a64';
|
||||
} else {
|
||||
modeEl.textContent = status.mode || '-';
|
||||
modeEl.style.color = '#333';
|
||||
}
|
||||
}
|
||||
|
||||
var tempEl = document.getElementById('fan-cpu-temp');
|
||||
if (tempEl) {
|
||||
var tempVal = parseFloat(status.temp) || 0;
|
||||
tempEl.textContent = tempVal.toFixed(1) + ' °C';
|
||||
if (tempVal >= 75) {
|
||||
tempEl.style.color = '#c62828';
|
||||
} else if (tempVal >= 60) {
|
||||
tempEl.style.color = '#ef6c00';
|
||||
} else {
|
||||
tempEl.style.color = '#2e7d32';
|
||||
}
|
||||
}
|
||||
|
||||
var levelEl = document.getElementById('fan-cur-level');
|
||||
if (levelEl) {
|
||||
var lvl = parseInt(status.level) || 0;
|
||||
var lvlName = '';
|
||||
switch (lvl) {
|
||||
case 0: lvlName = _('0 级 [停转]'); break;
|
||||
case 1: lvlName = _('1 级 [低速 31%]'); break;
|
||||
case 2: lvlName = _('2 级 [中速 50%]'); break;
|
||||
case 3: lvlName = _('3 级 [全速 100%]'); break;
|
||||
default: lvlName = lvl + ' ' + _('级'); break;
|
||||
}
|
||||
levelEl.textContent = lvlName;
|
||||
}
|
||||
|
||||
var pwmEl = document.getElementById('fan-pwm-duty');
|
||||
if (pwmEl) {
|
||||
var pwmVal = parseInt(status.pwm) || 0;
|
||||
var pct = Math.round((pwmVal / 255) * 100);
|
||||
pwmEl.textContent = pwmVal + ' / 255 (' + pct + '%)';
|
||||
}
|
||||
|
||||
// 策略配置数据更新与模式显隐
|
||||
var curMode = status.mode || 'auto';
|
||||
var isAuto = (curMode === 'auto');
|
||||
var isManual = (curMode === 'manual');
|
||||
var isKernel = (curMode === 'kernel');
|
||||
|
||||
var setRowDisplay = function(id, visible) {
|
||||
var el = document.getElementById(id);
|
||||
if (el) el.style.display = visible ? '' : 'none';
|
||||
};
|
||||
|
||||
setRowDisplay('policy-row-interval', isAuto);
|
||||
setRowDisplay('policy-row-spin', isAuto || isManual);
|
||||
setRowDisplay('policy-row-low', isAuto);
|
||||
setRowDisplay('policy-row-med', isAuto);
|
||||
setRowDisplay('policy-row-high', isAuto);
|
||||
setRowDisplay('policy-row-hyst', isAuto);
|
||||
setRowDisplay('policy-row-manual', isManual);
|
||||
setRowDisplay('policy-row-kernel', isKernel);
|
||||
|
||||
var intervalValEl = document.getElementById('policy-interval');
|
||||
if (intervalValEl && status.interval) {
|
||||
intervalValEl.textContent = status.interval + ' ' + _('秒');
|
||||
}
|
||||
|
||||
var spinValEl = document.getElementById('policy-start-spin');
|
||||
if (spinValEl) {
|
||||
spinValEl.textContent = (status.start_spin == 1) ? _('已开启 (开机全速 2 秒)') : _('未开启');
|
||||
}
|
||||
|
||||
if (isAuto) {
|
||||
var low = parseInt(status.temp_low) || 45;
|
||||
var med = parseInt(status.temp_med) || 60;
|
||||
var high = parseInt(status.temp_high) || 75;
|
||||
var hyst = parseInt(status.hysteresis) || 3;
|
||||
|
||||
var lowEl = document.getElementById('policy-temp-low');
|
||||
if (lowEl) lowEl.textContent = low + ' °C (' + _('低于 %d °C 停转').format(low - hyst) + ')';
|
||||
|
||||
var medEl = document.getElementById('policy-temp-med');
|
||||
if (medEl) medEl.textContent = med + ' °C (' + _('低于 %d °C 降回低速').format(med - hyst) + ')';
|
||||
|
||||
var highEl = document.getElementById('policy-temp-high');
|
||||
if (highEl) highEl.textContent = high + ' °C (' + _('低于 %d °C 降回中速').format(high - hyst) + ')';
|
||||
|
||||
var hystEl = document.getElementById('policy-hysteresis');
|
||||
if (hystEl) hystEl.textContent = hyst + ' °C (' + _('防临界点振荡') + ')';
|
||||
} else if (isManual) {
|
||||
var mLevelEl = document.getElementById('policy-manual-level');
|
||||
if (mLevelEl) {
|
||||
var ml = parseInt(status.manual_level) || 0;
|
||||
var mlName = '';
|
||||
switch (ml) {
|
||||
case 0: mlName = _('0 级 [停转 0%]'); break;
|
||||
case 1: mlName = _('1 级 [低速 31%]'); break;
|
||||
case 2: mlName = _('2 级 [中速 50%]'); break;
|
||||
case 3: mlName = _('3 级 [全速 100%]'); break;
|
||||
default: mlName = ml + ' ' + _('级'); break;
|
||||
}
|
||||
mLevelEl.textContent = mlName;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
handleSetLevel: function(lvl) {
|
||||
ui.showModal(null, [
|
||||
E('p', { 'class': 'spinning' }, _('正在下发测试档位: %d 级 ...').format(lvl))
|
||||
]);
|
||||
|
||||
return callSetLevel(lvl).then(L.bind(function(res) {
|
||||
ui.hideModal();
|
||||
if (res && res.success) {
|
||||
ui.addNotification(null, E('p', _('风扇测试档位下发成功: %d 级').format(lvl)), 'info');
|
||||
return callGetStatus().then(L.bind(this.updateStatusView, this));
|
||||
} else {
|
||||
ui.addNotification(null, E('p', _('风扇档位下发失败,请检查硬件节点。')), 'error');
|
||||
}
|
||||
}, this)).catch(function(err) {
|
||||
ui.hideModal();
|
||||
ui.addNotification(null, E('p', _('RPC 请求失败: %s').format(err.message)), 'error');
|
||||
});
|
||||
},
|
||||
|
||||
handleServiceAction: function(action) {
|
||||
ui.showModal(null, [
|
||||
E('p', { 'class': 'spinning' }, _('正在执行服务操作: %s ...').format(action))
|
||||
]);
|
||||
|
||||
return callServiceAction(action).then(L.bind(function(res) {
|
||||
ui.hideModal();
|
||||
if (res && res.success) {
|
||||
ui.addNotification(null, E('p', _('服务操作成功执行。')), 'info');
|
||||
return callGetStatus().then(L.bind(this.updateStatusView, this));
|
||||
} else {
|
||||
ui.addNotification(null, E('p', _('服务操作执行失败。')), 'error');
|
||||
}
|
||||
}, this)).catch(function(err) {
|
||||
ui.hideModal();
|
||||
ui.addNotification(null, E('p', _('RPC 请求失败: %s').format(err.message)), 'error');
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -1,76 +0,0 @@
|
||||
'use strict';
|
||||
'require view';
|
||||
'require form';
|
||||
|
||||
return view.extend({
|
||||
render: function() {
|
||||
var m, s, o;
|
||||
|
||||
m = new form.Map('fancontrol', _('风扇控制') + ' - ' + _('温控配置'),
|
||||
_('配置香蕉派 BPI-R4 的 PWM 智能风扇调速策略与温度响应区间。'));
|
||||
|
||||
s = m.section(form.NamedSection, 'global', 'fancontrol', _('参数设置'));
|
||||
s.anonymous = false;
|
||||
|
||||
o = s.option(form.Flag, 'enabled', _('启用服务'),
|
||||
_('开启风扇温控自动守护服务。'));
|
||||
o.rmempty = false;
|
||||
o.default = '1';
|
||||
|
||||
o = s.option(form.ListValue, 'mode', _('工作模式'),
|
||||
_('选择风扇的控制策略模式。'));
|
||||
o.value('auto', _('阶梯温控模式'));
|
||||
o.value('manual', _('手动定速模式'));
|
||||
o.value('kernel', _('内核接管模式'));
|
||||
o.default = 'auto';
|
||||
|
||||
o = s.option(form.Value, 'interval', _('检测周期 (秒)'),
|
||||
_('温度轮询检测的时间间隔,推荐 3 到 10 秒。'));
|
||||
o.datatype = 'range(1, 60)';
|
||||
o.default = '5';
|
||||
o.depends('mode', 'auto');
|
||||
|
||||
o = s.option(form.Flag, 'start_spin', _('启动自检清洁'),
|
||||
_('服务启动时全速转动 2 秒,清洁积灰并确保轴承起步运转。'));
|
||||
o.default = '1';
|
||||
o.depends('mode', 'auto');
|
||||
o.depends('mode', 'manual');
|
||||
|
||||
// 手动模式档位
|
||||
o = s.option(form.ListValue, 'manual_level', _('手动常开档位'),
|
||||
_('指定风扇持续运转的固定档位。'));
|
||||
o.value('0', _('0 级 [停转 0%]'));
|
||||
o.value('1', _('1 级 [低速 31%]'));
|
||||
o.value('2', _('2 级 [中速 50%]'));
|
||||
o.value('3', _('3 级 [全速 100%]'));
|
||||
o.default = '2';
|
||||
o.depends('mode', 'manual');
|
||||
|
||||
// 阶梯模式各档温度
|
||||
o = s.option(form.Value, 'temp_low', _('1 级低速触发温度 (°C)'),
|
||||
_('温度达到此数值时启动 1 级低速 (约 31% 占空比),低于该值停转。'));
|
||||
o.datatype = 'range(30, 90)';
|
||||
o.default = '45';
|
||||
o.depends('mode', 'auto');
|
||||
|
||||
o = s.option(form.Value, 'temp_med', _('2 级中速触发温度 (°C)'),
|
||||
_('温度达到此数值时提升至 2 级中速 (约 50% 占空比)。'));
|
||||
o.datatype = 'range(35, 100)';
|
||||
o.default = '60';
|
||||
o.depends('mode', 'auto');
|
||||
|
||||
o = s.option(form.Value, 'temp_high', _('3 级全速触发温度 (°C)'),
|
||||
_('温度达到此数值时提升至 3 级全速 (100% 占空比)。'));
|
||||
o.datatype = 'range(40, 110)';
|
||||
o.default = '75';
|
||||
o.depends('mode', 'auto');
|
||||
|
||||
o = s.option(form.Value, 'hysteresis', _('换挡回差温度 (°C)'),
|
||||
_('降温换挡的滞后温差。例如 60°C 升至中速,需降至 57°C 才会降回低速,防止临界点频繁启停。'));
|
||||
o.datatype = 'range(1, 10)';
|
||||
o.default = '3';
|
||||
o.depends('mode', 'auto');
|
||||
|
||||
return m.render();
|
||||
}
|
||||
});
|
||||
@@ -1,261 +0,0 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
||||
msgid "风扇控制"
|
||||
msgstr ""
|
||||
|
||||
msgid "状态概览"
|
||||
msgstr ""
|
||||
|
||||
msgid "温控配置"
|
||||
msgstr ""
|
||||
|
||||
msgid "运行日志"
|
||||
msgstr ""
|
||||
|
||||
msgid "实时监控香蕉派 BPI-R4 处理器温度与 PWM 风扇运行档位,提供硬件即时测试功能。"
|
||||
msgstr ""
|
||||
|
||||
msgid "运行状态"
|
||||
msgstr ""
|
||||
|
||||
msgid "服务状态"
|
||||
msgstr ""
|
||||
|
||||
msgid "运行中 [受控]"
|
||||
msgstr ""
|
||||
|
||||
msgid "运行中 [非受控]"
|
||||
msgstr ""
|
||||
|
||||
msgid "已停止"
|
||||
msgstr ""
|
||||
|
||||
msgid "重启服务"
|
||||
msgstr ""
|
||||
|
||||
msgid "运行模式"
|
||||
msgstr ""
|
||||
|
||||
msgid "阶梯温控模式"
|
||||
msgstr ""
|
||||
|
||||
msgid "手动定速模式"
|
||||
msgstr ""
|
||||
|
||||
msgid "内核接管模式"
|
||||
msgstr ""
|
||||
|
||||
msgid "处理器温度"
|
||||
msgstr ""
|
||||
|
||||
msgid "当前风扇档位"
|
||||
msgstr ""
|
||||
|
||||
msgid "脉宽占空比"
|
||||
msgstr ""
|
||||
|
||||
msgid "0 级 [停转]"
|
||||
msgstr ""
|
||||
|
||||
msgid "1 级 [低速 31%]"
|
||||
msgstr ""
|
||||
|
||||
msgid "2 级 [中速 50%]"
|
||||
msgstr ""
|
||||
|
||||
msgid "3 级 [全速 100%]"
|
||||
msgstr ""
|
||||
|
||||
msgid "级"
|
||||
msgstr ""
|
||||
|
||||
msgid "硬件快速测试"
|
||||
msgstr ""
|
||||
|
||||
msgid "点击按钮可即时下发档位进行硬件测试,测试结果立即生效并在状态栏回显。若服务处于运行中,后续温控检测将按设定规则恢复。"
|
||||
msgstr ""
|
||||
|
||||
msgid "停止风扇 (0 级)"
|
||||
msgstr ""
|
||||
|
||||
msgid "低速测试 (1 级)"
|
||||
msgstr ""
|
||||
|
||||
msgid "中速测试 (2 级)"
|
||||
msgstr ""
|
||||
|
||||
msgid "全速测试 (3 级)"
|
||||
msgstr ""
|
||||
|
||||
msgid "正在下发测试档位: %d 级 ..."
|
||||
msgstr ""
|
||||
|
||||
msgid "风扇测试档位下发成功: %d 级"
|
||||
msgstr ""
|
||||
|
||||
msgid "风扇档位下发失败,请检查硬件节点。"
|
||||
msgstr ""
|
||||
|
||||
msgid "正在执行服务操作: %s ..."
|
||||
msgstr ""
|
||||
|
||||
msgid "服务操作成功执行。"
|
||||
msgstr ""
|
||||
|
||||
msgid "服务操作执行失败。"
|
||||
msgstr ""
|
||||
|
||||
msgid "RPC 请求失败: %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "配置香蕉派 BPI-R4 的 PWM 智能风扇调速策略与温度响应区间。"
|
||||
msgstr ""
|
||||
|
||||
msgid "参数设置"
|
||||
msgstr ""
|
||||
|
||||
msgid "启用服务"
|
||||
msgstr ""
|
||||
|
||||
msgid "开启风扇温控自动守护服务。"
|
||||
msgstr ""
|
||||
|
||||
msgid "工作模式"
|
||||
msgstr ""
|
||||
|
||||
msgid "选择风扇的控制策略模式。"
|
||||
msgstr ""
|
||||
|
||||
msgid "检测周期 (秒)"
|
||||
msgstr ""
|
||||
|
||||
msgid "温度轮询检测的时间间隔,推荐 3 到 10 秒。"
|
||||
msgstr ""
|
||||
|
||||
msgid "启动自检清洁"
|
||||
msgstr ""
|
||||
|
||||
msgid "服务启动时全速转动 2 秒,清洁积灰并确保轴承起步运转。"
|
||||
msgstr ""
|
||||
|
||||
msgid "手动常开档位"
|
||||
msgstr ""
|
||||
|
||||
msgid "指定风扇持续运转的固定档位。"
|
||||
msgstr ""
|
||||
|
||||
msgid "0 级 [停转 0%]"
|
||||
msgstr ""
|
||||
|
||||
msgid "1 级 [低速 31%]"
|
||||
msgstr ""
|
||||
|
||||
msgid "2 级 [中速 50%]"
|
||||
msgstr ""
|
||||
|
||||
msgid "3 级 [全速 100%]"
|
||||
msgstr ""
|
||||
|
||||
msgid "1 级低速触发温度 (°C)"
|
||||
msgstr ""
|
||||
|
||||
msgid "温度达到此数值时启动 1 级低速 (约 31% 占空比),低于该值停转。"
|
||||
msgstr ""
|
||||
|
||||
msgid "2 级中速触发温度 (°C)"
|
||||
msgstr ""
|
||||
|
||||
msgid "温度达到此数值时提升至 2 级中速 (约 50% 占空比)。"
|
||||
msgstr ""
|
||||
|
||||
msgid "3 级全速触发温度 (°C)"
|
||||
msgstr ""
|
||||
|
||||
msgid "温度达到此数值时提升至 3 级全速 (100% 占空比)。"
|
||||
msgstr ""
|
||||
|
||||
msgid "换挡回差温度 (°C)"
|
||||
msgstr ""
|
||||
|
||||
msgid "降温换挡的滞后温差。例如 60°C 升至中速,需降至 57°C 才会降回低速,防止临界点频繁启停。"
|
||||
msgstr ""
|
||||
|
||||
msgid "正在加载日志..."
|
||||
msgstr ""
|
||||
|
||||
msgid "刷新日志"
|
||||
msgstr ""
|
||||
|
||||
msgid "清空日志"
|
||||
msgstr ""
|
||||
|
||||
msgid "实时展示温控守护进程的调速动作、温度变化与自检日志。"
|
||||
msgstr ""
|
||||
|
||||
msgid "系统日志"
|
||||
msgstr ""
|
||||
|
||||
msgid "暂无日志记录。"
|
||||
msgstr ""
|
||||
|
||||
msgid "读取日志失败: %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "日志已成功清空。"
|
||||
msgstr ""
|
||||
|
||||
msgid "清空日志失败。"
|
||||
msgstr ""
|
||||
|
||||
msgid "当前策略配置"
|
||||
msgstr ""
|
||||
|
||||
msgid "检测轮询周期"
|
||||
msgstr ""
|
||||
|
||||
msgid "启动除尘自检"
|
||||
msgstr ""
|
||||
|
||||
msgid "低速触发阈值"
|
||||
msgstr ""
|
||||
|
||||
msgid "中速触发阈值"
|
||||
msgstr ""
|
||||
|
||||
msgid "全速触发阈值"
|
||||
msgstr ""
|
||||
|
||||
msgid "换挡回差温差"
|
||||
msgstr ""
|
||||
|
||||
msgid "预设运转档位"
|
||||
msgstr ""
|
||||
|
||||
msgid "控制驱动策略"
|
||||
msgstr ""
|
||||
|
||||
msgid "系统内核设备树原生驱动接管"
|
||||
msgstr ""
|
||||
|
||||
msgid "秒"
|
||||
msgstr ""
|
||||
|
||||
msgid "已开启 (开机全速 2 秒)"
|
||||
msgstr ""
|
||||
|
||||
msgid "未开启"
|
||||
msgstr ""
|
||||
|
||||
msgid "低于 %d °C 停转"
|
||||
msgstr ""
|
||||
|
||||
msgid "低于 %d °C 降回低速"
|
||||
msgstr ""
|
||||
|
||||
msgid "低于 %d °C 降回中速"
|
||||
msgstr ""
|
||||
|
||||
msgid "防临界点振荡"
|
||||
msgstr ""
|
||||
|
||||
@@ -1,261 +1,293 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8\n"
|
||||
msgstr ""
|
||||
"Project-Id-Version: luci-app-fancontrol 2.2.0\n"
|
||||
"PO-Revision-Date: 2026-07-30 00:00+0800\n"
|
||||
"Last-Translator: JiaY-shi <shi05275@163.com>\n"
|
||||
"Language-Team: Chinese (Simplified Han script)\n"
|
||||
"Language: zh_Hans\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"
|
||||
|
||||
msgid "风扇控制"
|
||||
msgid "Kernel cooling device"
|
||||
msgstr "内核散热设备"
|
||||
|
||||
msgid "Use auto for a single pwm-fan device, an explicit cooling_device path for multiple fans, or none when kernel fan control is already handled elsewhere."
|
||||
msgstr "单个 pwm-fan 设备使用 auto;多个风扇需指定对应的 cooling_device 路径;已通过其他方式处理内核风扇控制时使用 none。"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:173
|
||||
msgid ""
|
||||
"After starting, the fan stops only after temperature falls this many degrees "
|
||||
"below the start temperature. This prevents rapid on/off cycling."
|
||||
msgstr "风扇启动后,温度需要降到比启动温度低这么多度时才会停转,避免风扇频繁启停。"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:143
|
||||
msgid ""
|
||||
"Automatic detection works on most devices. Select explicit sysfs entries "
|
||||
"only when necessary."
|
||||
msgstr "自动检测适用于大多数设备,仅在必要时手动指定 sysfs 项。"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:238
|
||||
msgid ""
|
||||
"Brief PWM applied when a stopped fan starts. It helps fans that cannot start "
|
||||
"reliably at low duty. Set to 0 together with a zero duration to disable."
|
||||
msgstr "风扇从停止状态启动时短暂使用的 PWM,可帮助低占空比下无法可靠启动的风扇。将此项和助推时长都设为 0 可禁用。"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:122
|
||||
msgid "Collecting data..."
|
||||
msgstr "正在采集数据..."
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:111
|
||||
msgid ""
|
||||
"Configure a continuous PWM curve based on device temperature. Automatic "
|
||||
"hardware detection is suitable for most devices."
|
||||
msgstr "根据设备温度配置连续 PWM 调速曲线。自动硬件检测适用于大多数设备。"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:145
|
||||
msgid ""
|
||||
"Controls startup assistance and fail-safe behavior. Full-speed safety "
|
||||
"defaults are recommended."
|
||||
msgstr "控制启动助推和故障保护行为,建议保留默认的全速安全设置。"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:141
|
||||
msgid "Controls when the fan starts and how its speed rises with temperature."
|
||||
msgstr "控制风扇何时启动,以及转速如何随温度升高。"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:263
|
||||
msgid "Debug logging"
|
||||
msgstr "调试日志"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:232
|
||||
msgid ""
|
||||
"Divides the raw sensor value before control calculations. Standard Linux "
|
||||
"temperature inputs use 1000; sensors reporting whole degrees use 1."
|
||||
msgstr "进行控制计算前用于换算传感器原始值。标准 Linux 温度输入使用 1000,直接报告摄氏度的传感器使用 1。"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:147
|
||||
msgid "Enable"
|
||||
msgstr "启用"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:98
|
||||
msgid "Enter \"auto\" or an absolute sysfs path."
|
||||
msgstr "请输入 \"auto\" 或 sysfs 绝对路径。"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:110
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/root/usr/share/luci/menu.d/luci-app-fancontrol.json:3
|
||||
msgid "Fan Control"
|
||||
msgstr "风扇控制"
|
||||
|
||||
msgid "状态概览"
|
||||
msgstr "状态概览"
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:84
|
||||
msgid "Fan speed"
|
||||
msgstr "风扇转速"
|
||||
|
||||
msgid "温控配置"
|
||||
msgstr "温控配置"
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:89
|
||||
msgid "Fault"
|
||||
msgstr "故障"
|
||||
|
||||
msgid "运行日志"
|
||||
msgstr "运行日志"
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:158
|
||||
msgid "Full-speed temperature"
|
||||
msgstr "全速温度"
|
||||
|
||||
msgid "实时监控香蕉派 BPI-R4 处理器温度与 PWM 风扇运行档位,提供硬件即时测试功能。"
|
||||
msgstr "实时监控香蕉派 BPI-R4 处理器温度与 PWM 风扇运行档位,提供硬件即时测试功能。"
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:165
|
||||
msgid "Full-speed temperature must be higher than start temperature."
|
||||
msgstr "全速温度必须高于启动温度。"
|
||||
|
||||
msgid "运行状态"
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/root/usr/share/rpcd/acl.d/luci-app-fancontrol.json:3
|
||||
msgid "Grant access to Fan Control"
|
||||
msgstr "授予风扇控制访问权限"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:142
|
||||
msgid "Hardware"
|
||||
msgstr "硬件"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:185
|
||||
msgid "Highest PWM allowed by the curve. A value of 255 means 100% duty cycle."
|
||||
msgstr "温控曲线允许的最高 PWM,255 表示 100% 占空比。"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:244
|
||||
msgid "How long the startup kick is applied. Unit: milliseconds."
|
||||
msgstr "启动助推持续的时间,单位为毫秒。"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:196
|
||||
msgid ""
|
||||
"How often the temperature is read and the PWM output is updated. Unit: "
|
||||
"seconds."
|
||||
msgstr "读取温度并更新 PWM 输出的时间间隔,单位为秒。"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:215
|
||||
msgid "Hwmon device name"
|
||||
msgstr "Hwmon 设备名称"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:179
|
||||
msgid ""
|
||||
"Lowest PWM used while the fan is running. Increase it if the fan stalls or "
|
||||
"cannot maintain rotation. Range: 1–255."
|
||||
msgstr "风扇运行时使用的最低 PWM。如果风扇停转或无法持续旋转,请提高此值。范围:1–255。"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:181
|
||||
msgid "Maximum PWM"
|
||||
msgstr "最大 PWM"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:188
|
||||
msgid "Maximum PWM must not be lower than minimum running PWM."
|
||||
msgstr "最大 PWM 不得低于最低运行 PWM。"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:175
|
||||
msgid "Minimum running PWM"
|
||||
msgstr "最低运行 PWM"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:71
|
||||
msgid "None"
|
||||
msgstr "无"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:224
|
||||
msgid ""
|
||||
"Optional pwmN_enable path used to select manual PWM mode. With \"auto\", the "
|
||||
"matching control is used when available."
|
||||
msgstr "用于选择手动 PWM 模式的可选 pwmN_enable 路径。设为 \"auto\" 时会自动使用匹配的控制项。"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:88
|
||||
msgid "PWM device"
|
||||
msgstr "PWM 设备"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:220
|
||||
msgid "PWM mode control"
|
||||
msgstr "PWM 模式控制"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:82
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:209
|
||||
msgid "PWM output"
|
||||
msgstr "PWM 输出"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:162
|
||||
msgid ""
|
||||
"PWM rises linearly and reaches the configured maximum at this temperature. "
|
||||
"Unit: °C."
|
||||
msgstr "PWM 随温度线性升高,并在此温度达到设定的最大值,单位为 °C。"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:255
|
||||
msgid ""
|
||||
"PWM used when the temperature sensor cannot be read. Keeping 255 is the "
|
||||
"safest choice."
|
||||
msgstr "温度传感器读取失败时使用的 PWM。保持 255 是最安全的选择。"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:261
|
||||
msgid ""
|
||||
"PWM written when the service stops. Keeping the fan at full speed avoids "
|
||||
"losing cooling after an unexpected exit."
|
||||
msgstr "服务停止时写入的 PWM。保持风扇全速可避免服务意外退出后失去散热。"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:192
|
||||
msgid "Polling interval"
|
||||
msgstr "轮询间隔"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:218
|
||||
msgid ""
|
||||
"Preferred hwmon name when PWM output is automatic. The pwmfan driver is "
|
||||
"preferred by default."
|
||||
msgstr "自动选择 PWM 输出时优先使用的 hwmon 名称,默认优先选择 pwmfan 驱动。"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:207
|
||||
msgid ""
|
||||
"Preferred thermal zone type when temperature input is automatic, for example "
|
||||
"cpu_top_thermal. Leave as \"auto\" unless several sensors are available."
|
||||
msgstr "自动选择温度输入时优先使用的 thermal zone 类型,例如 cpu_top_thermal。除非存在多个传感器,否则保持 \"auto\"。"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:150
|
||||
msgid "Run the controller and apply this temperature curve."
|
||||
msgstr "运行风扇控制器并应用此温控曲线。"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:77
|
||||
msgid "Running"
|
||||
msgstr "运行中"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:75
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:113
|
||||
msgid "Runtime Status"
|
||||
msgstr "运行状态"
|
||||
|
||||
msgid "服务状态"
|
||||
msgstr "服务状态"
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:144
|
||||
msgid "Safety"
|
||||
msgstr "安全"
|
||||
|
||||
msgid "运行中 [受控]"
|
||||
msgstr "运行中 [受控]"
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:251
|
||||
msgid "Sensor failure PWM"
|
||||
msgstr "传感器故障 PWM"
|
||||
|
||||
msgid "运行中 [非受控]"
|
||||
msgstr "运行中 [非受控]"
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:257
|
||||
msgid "Service exit PWM"
|
||||
msgstr "服务退出 PWM"
|
||||
|
||||
msgid "已停止"
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:138
|
||||
msgid "Settings"
|
||||
msgstr "设置"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:234
|
||||
msgid "Start kick PWM"
|
||||
msgstr "启动助推 PWM"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:247
|
||||
msgid "Start kick PWM must be non-zero when a kick duration is configured."
|
||||
msgstr "配置启动助推时长时,启动助推 PWM 不能为零。"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:240
|
||||
msgid "Start kick duration"
|
||||
msgstr "启动助推时长"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:152
|
||||
msgid "Start temperature"
|
||||
msgstr "启动温度"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:169
|
||||
msgid "Stop hysteresis"
|
||||
msgstr "停转回差"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:77
|
||||
msgid "Stopped"
|
||||
msgstr "已停止"
|
||||
|
||||
msgid "重启服务"
|
||||
msgstr "重启服务"
|
||||
|
||||
msgid "运行模式"
|
||||
msgstr "运行模式"
|
||||
|
||||
msgid "阶梯温控模式"
|
||||
msgstr "阶梯温控模式"
|
||||
|
||||
msgid "手动定速模式"
|
||||
msgstr "手动定速模式"
|
||||
|
||||
msgid "内核接管模式"
|
||||
msgstr "内核接管模式"
|
||||
|
||||
msgid "处理器温度"
|
||||
msgstr "处理器温度"
|
||||
|
||||
msgid "当前风扇档位"
|
||||
msgstr "当前风扇档位"
|
||||
|
||||
msgid "脉宽占空比"
|
||||
msgstr "脉宽占空比"
|
||||
|
||||
msgid "0 级 [停转]"
|
||||
msgstr "0 级 [停转]"
|
||||
|
||||
msgid "1 级 [低速 31%]"
|
||||
msgstr "1 级 [低速 31%]"
|
||||
|
||||
msgid "2 级 [中速 50%]"
|
||||
msgstr "2 级 [中速 50%]"
|
||||
|
||||
msgid "3 级 [全速 100%]"
|
||||
msgstr "3 级 [全速 100%]"
|
||||
|
||||
msgid "级"
|
||||
msgstr "级"
|
||||
|
||||
msgid "硬件快速测试"
|
||||
msgstr "硬件快速测试"
|
||||
|
||||
msgid "点击按钮可即时下发档位进行硬件测试,测试结果立即生效并在状态栏回显。若服务处于运行中,后续温控检测将按设定规则恢复。"
|
||||
msgstr "点击按钮可即时下发档位进行硬件测试,测试结果立即生效并在状态栏回显。若服务处于运行中,后续温控检测将按设定规则恢复。"
|
||||
|
||||
msgid "停止风扇 (0 级)"
|
||||
msgstr "停止风扇 (0 级)"
|
||||
|
||||
msgid "低速测试 (1 级)"
|
||||
msgstr "低速测试 (1 级)"
|
||||
|
||||
msgid "中速测试 (2 级)"
|
||||
msgstr "中速测试 (2 级)"
|
||||
|
||||
msgid "全速测试 (3 级)"
|
||||
msgstr "全速测试 (3 级)"
|
||||
|
||||
msgid "正在下发测试档位: %d 级 ..."
|
||||
msgstr "正在下发测试档位: %d 级 ..."
|
||||
|
||||
msgid "风扇测试档位下发成功: %d 级"
|
||||
msgstr "风扇测试档位下发成功: %d 级"
|
||||
|
||||
msgid "风扇档位下发失败,请检查硬件节点。"
|
||||
msgstr "风扇档位下发失败,请检查硬件节点。"
|
||||
|
||||
msgid "正在执行服务操作: %s ..."
|
||||
msgstr "正在执行服务操作: %s ..."
|
||||
|
||||
msgid "服务操作成功执行。"
|
||||
msgstr "服务操作成功执行。"
|
||||
|
||||
msgid "服务操作执行失败。"
|
||||
msgstr "服务操作执行失败。"
|
||||
|
||||
msgid "RPC 请求失败: %s"
|
||||
msgstr "RPC 请求失败: %s"
|
||||
|
||||
msgid "配置香蕉派 BPI-R4 的 PWM 智能风扇调速策略与温度响应区间。"
|
||||
msgstr "配置香蕉派 BPI-R4 的 PWM 智能风扇调速策略与温度响应区间。"
|
||||
|
||||
msgid "参数设置"
|
||||
msgstr "参数设置"
|
||||
|
||||
msgid "启用服务"
|
||||
msgstr "启用服务"
|
||||
|
||||
msgid "开启风扇温控自动守护服务。"
|
||||
msgstr "开启风扇温控自动守护服务。"
|
||||
|
||||
msgid "工作模式"
|
||||
msgstr "工作模式"
|
||||
|
||||
msgid "选择风扇的控制策略模式。"
|
||||
msgstr "选择风扇的控制策略模式。"
|
||||
|
||||
msgid "检测周期 (秒)"
|
||||
msgstr "检测周期 (秒)"
|
||||
|
||||
msgid "温度轮询检测的时间间隔,推荐 3 到 10 秒。"
|
||||
msgstr "温度轮询检测的时间间隔,推荐 3 到 10 秒。"
|
||||
|
||||
msgid "启动自检清洁"
|
||||
msgstr "启动自检清洁"
|
||||
|
||||
msgid "服务启动时全速转动 2 秒,清洁积灰并确保轴承起步运转。"
|
||||
msgstr "服务启动时全速转动 2 秒,清洁积灰并确保轴承起步运转。"
|
||||
|
||||
msgid "手动常开档位"
|
||||
msgstr "手动常开档位"
|
||||
|
||||
msgid "指定风扇持续运转的固定档位。"
|
||||
msgstr "指定风扇持续运转的固定档位。"
|
||||
|
||||
msgid "0 级 [停转 0%]"
|
||||
msgstr "0 级 [停转 0%]"
|
||||
|
||||
msgid "1 级 [低速 31%]"
|
||||
msgstr "1 级 [低速 31%]"
|
||||
|
||||
msgid "2 级 [中速 50%]"
|
||||
msgstr "2 级 [中速 50%]"
|
||||
|
||||
msgid "3 级 [全速 100%]"
|
||||
msgstr "3 级 [全速 100%]"
|
||||
|
||||
msgid "1 级低速触发温度 (°C)"
|
||||
msgstr "1 级低速触发温度 (°C)"
|
||||
|
||||
msgid "温度达到此数值时启动 1 级低速 (约 31% 占空比),低于该值停转。"
|
||||
msgstr "温度达到此数值时启动 1 级低速 (约 31% 占空比),低于该值停转。"
|
||||
|
||||
msgid "2 级中速触发温度 (°C)"
|
||||
msgstr "2 级中速触发温度 (°C)"
|
||||
|
||||
msgid "温度达到此数值时提升至 2 级中速 (约 50% 占空比)。"
|
||||
msgstr "温度达到此数值时提升至 2 级中速 (约 50% 占空比)。"
|
||||
|
||||
msgid "3 级全速触发温度 (°C)"
|
||||
msgstr "3 级全速触发温度 (°C)"
|
||||
|
||||
msgid "温度达到此数值时提升至 3 级全速 (100% 占空比)。"
|
||||
msgstr "温度达到此数值时提升至 3 级全速 (100% 占空比)。"
|
||||
|
||||
msgid "换挡回差温度 (°C)"
|
||||
msgstr "换挡回差温度 (°C)"
|
||||
|
||||
msgid "降温换挡的滞后温差。例如 60°C 升至中速,需降至 57°C 才会降回低速,防止临界点频繁启停。"
|
||||
msgstr "降温换挡的滞后温差。例如 60°C 升至中速,需降至 57°C 才会降回低速,防止临界点频繁启停。"
|
||||
|
||||
msgid "正在加载日志..."
|
||||
msgstr "正在加载日志..."
|
||||
|
||||
msgid "刷新日志"
|
||||
msgstr "刷新日志"
|
||||
|
||||
msgid "清空日志"
|
||||
msgstr "清空日志"
|
||||
|
||||
msgid "实时展示温控守护进程的调速动作、温度变化与自检日志。"
|
||||
msgstr "实时展示温控守护进程的调速动作、温度变化与自检日志。"
|
||||
|
||||
msgid "系统日志"
|
||||
msgstr "系统日志"
|
||||
|
||||
msgid "暂无日志记录。"
|
||||
msgstr "暂无日志记录。"
|
||||
|
||||
msgid "读取日志失败: %s"
|
||||
msgstr "读取日志失败: %s"
|
||||
|
||||
msgid "日志已成功清空。"
|
||||
msgstr "日志已成功清空。"
|
||||
|
||||
msgid "清空日志失败。"
|
||||
msgstr "清空日志失败。"
|
||||
|
||||
msgid "当前策略配置"
|
||||
msgstr "当前策略配置"
|
||||
|
||||
msgid "检测轮询周期"
|
||||
msgstr "检测轮询周期"
|
||||
|
||||
msgid "启动除尘自检"
|
||||
msgstr "启动除尘自检"
|
||||
|
||||
msgid "低速触发阈值"
|
||||
msgstr "低速触发阈值"
|
||||
|
||||
msgid "中速触发阈值"
|
||||
msgstr "中速触发阈值"
|
||||
|
||||
msgid "全速触发阈值"
|
||||
msgstr "全速触发阈值"
|
||||
|
||||
msgid "换挡回差温差"
|
||||
msgstr "换挡回差温差"
|
||||
|
||||
msgid "预设运转档位"
|
||||
msgstr "预设运转档位"
|
||||
|
||||
msgid "控制驱动策略"
|
||||
msgstr "控制驱动策略"
|
||||
|
||||
msgid "系统内核设备树原生驱动接管"
|
||||
msgstr "系统内核设备树原生驱动接管"
|
||||
|
||||
msgid "秒"
|
||||
msgstr "秒"
|
||||
|
||||
msgid "已开启 (开机全速 2 秒)"
|
||||
msgstr "已开启 (开机全速 2 秒)"
|
||||
|
||||
msgid "未开启"
|
||||
msgstr "未开启"
|
||||
|
||||
msgid "低于 %d °C 停转"
|
||||
msgstr "低于 %d °C 停转"
|
||||
|
||||
msgid "低于 %d °C 降回低速"
|
||||
msgstr "低于 %d °C 降回低速"
|
||||
|
||||
msgid "低于 %d °C 降回中速"
|
||||
msgstr "低于 %d °C 降回中速"
|
||||
|
||||
msgid "防临界点振荡"
|
||||
msgstr "防临界点振荡"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:80
|
||||
msgid "Temperature"
|
||||
msgstr "温度"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:140
|
||||
msgid "Temperature Curve"
|
||||
msgstr "温控曲线"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:226
|
||||
msgid "Temperature divisor"
|
||||
msgstr "温度除数"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:87
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:198
|
||||
msgid "Temperature input"
|
||||
msgstr "温度输入"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:156
|
||||
msgid ""
|
||||
"The fan remains off below this temperature and starts at the minimum running "
|
||||
"PWM when it is reached. Unit: °C."
|
||||
msgstr "低于此温度时风扇保持停止;达到此温度时,以最低运行 PWM 启动。单位为 °C。"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:204
|
||||
msgid "Thermal zone type"
|
||||
msgstr "温度区域类型"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:202
|
||||
msgid ""
|
||||
"Use \"auto\" to select a CPU or SoC thermal sensor, or enter an absolute "
|
||||
"thermal zone or hwmon tempN_input path."
|
||||
msgstr "使用 \"auto\" 自动选择 CPU 或 SoC 温度传感器,也可输入 thermal zone 或 hwmon tempN_input 的绝对路径。"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:213
|
||||
msgid ""
|
||||
"Use \"auto\" to select a writable hwmon pwmN output, or enter its absolute "
|
||||
"path. cooling_device cur_state is not a PWM output."
|
||||
msgstr "使用 \"auto\" 自动选择可写的 hwmon pwmN 输出,也可输入其绝对路径。cooling_device cur_state 不是 PWM 输出。"
|
||||
|
||||
#: /home/shi/document/c-service/fancontrol/luci-app-fancontrol/htdocs/luci-static/resources/view/fancontrol.js:266
|
||||
msgid ""
|
||||
"Write temperature, PWM and RPM values to the system log at every polling "
|
||||
"interval."
|
||||
msgstr "每次轮询时将温度、PWM 和 RPM 数值写入系统日志。"
|
||||
@@ -1,10 +0,0 @@
|
||||
config fancontrol 'global'
|
||||
option enabled '1'
|
||||
option mode 'auto'
|
||||
option interval '5'
|
||||
option start_spin '1'
|
||||
option temp_low '45'
|
||||
option temp_med '60'
|
||||
option temp_high '75'
|
||||
option hysteresis '3'
|
||||
option manual_level '2'
|
||||
@@ -1,44 +0,0 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# Copyright (C) 2026 Dante <dante@seckv.com>
|
||||
|
||||
USE_PROCD=1
|
||||
START=95
|
||||
STOP=10
|
||||
|
||||
PROG="/usr/sbin/fancontrold"
|
||||
CONFIG="fancontrol"
|
||||
|
||||
start_service() {
|
||||
local enabled
|
||||
enabled=$(uci -q get "${CONFIG}.global.enabled" || echo 0)
|
||||
[ "${enabled}" = "1" ] || return 0
|
||||
|
||||
chmod 755 "${PROG}" 2>/dev/null
|
||||
|
||||
# 启动前清理任何可能残留的孤儿进程
|
||||
killall -q fancontrold 2>/dev/null
|
||||
|
||||
procd_open_instance "main"
|
||||
procd_set_param command "${PROG}"
|
||||
procd_set_param respawn 3600 5 0
|
||||
procd_set_param stdout 1
|
||||
procd_set_param stderr 1
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
stop_service() {
|
||||
killall -q fancontrold 2>/dev/null
|
||||
if [ -f "/sys/class/thermal/thermal_zone0/policy" ]; then
|
||||
echo "step_wise" > "/sys/class/thermal/thermal_zone0/policy" 2>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
reload_service() {
|
||||
stop
|
||||
start
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "${CONFIG}"
|
||||
}
|
||||
@@ -1,249 +0,0 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# Copyright (C) 2026 Dante <dante@seckv.com>
|
||||
|
||||
LOG_FILE="/var/log/fancontrol.log"
|
||||
CONFIG="fancontrol"
|
||||
|
||||
log_msg() {
|
||||
local level="$1"
|
||||
local msg="$2"
|
||||
local timestamp
|
||||
timestamp="$(date '+%Y-%m-%d %H:%M:%S')"
|
||||
echo "${timestamp} [${level}] ${msg}" >> "${LOG_FILE}"
|
||||
|
||||
# 保持日志行数在 200 行以内
|
||||
if [ -f "${LOG_FILE}" ]; then
|
||||
local lines
|
||||
lines=$(wc -l < "${LOG_FILE}" 2>/dev/null || echo 0)
|
||||
if [ "${lines}" -gt 200 ]; then
|
||||
local tmp_log
|
||||
tmp_log="$(tail -n 100 "${LOG_FILE}")"
|
||||
echo "${tmp_log}" > "${LOG_FILE}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# 寻找硬件节点
|
||||
find_nodes() {
|
||||
THERMAL_ZONE=""
|
||||
COOLING_DEV=""
|
||||
HWMON_PWM=""
|
||||
|
||||
# 优先寻找 thermal_zone0
|
||||
if [ -f "/sys/class/thermal/thermal_zone0/temp" ]; then
|
||||
THERMAL_ZONE="/sys/class/thermal/thermal_zone0"
|
||||
else
|
||||
for z in /sys/class/thermal/thermal_zone*; do
|
||||
if [ -f "${z}/temp" ]; then
|
||||
THERMAL_ZONE="${z}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# 寻找 pwm-fan 冷却设备
|
||||
for c in /sys/class/thermal/cooling_device*; do
|
||||
if [ -f "${c}/type" ]; then
|
||||
local ctype
|
||||
ctype=$(cat "${c}/type" 2>/dev/null)
|
||||
if [ "${ctype}" = "pwm-fan" ] || [ "${ctype}" = "pwmfan" ]; then
|
||||
COOLING_DEV="${c}"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# 寻找 hwmon pwm 节点
|
||||
for h in /sys/class/hwmon/hwmon*; do
|
||||
if [ -f "${h}/name" ]; then
|
||||
local hname
|
||||
hname=$(cat "${h}/name" 2>/dev/null)
|
||||
if [ "${hname}" = "pwmfan" ] && [ -f "${h}/pwm1" ]; then
|
||||
HWMON_PWM="${h}/pwm1"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
get_temperature() {
|
||||
if [ -n "${THERMAL_ZONE}" ] && [ -f "${THERMAL_ZONE}/temp" ]; then
|
||||
cat "${THERMAL_ZONE}/temp" 2>/dev/null || echo "0"
|
||||
else
|
||||
echo "0"
|
||||
fi
|
||||
}
|
||||
|
||||
set_fan_level() {
|
||||
local lvl="$1"
|
||||
if [ -n "${COOLING_DEV}" ] && [ -w "${COOLING_DEV}/cur_state" ]; then
|
||||
echo "${lvl}" > "${COOLING_DEV}/cur_state" 2>/dev/null
|
||||
fi
|
||||
if [ -n "${HWMON_PWM}" ] && [ -w "${HWMON_PWM}" ]; then
|
||||
local pwm_val=0
|
||||
case "${lvl}" in
|
||||
0) pwm_val=0 ;;
|
||||
1) pwm_val=80 ;;
|
||||
2) pwm_val=128 ;;
|
||||
3) pwm_val=255 ;;
|
||||
*) pwm_val=0 ;;
|
||||
esac
|
||||
echo "${pwm_val}" > "${HWMON_PWM}" 2>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
get_level_name() {
|
||||
case "$1" in
|
||||
0) echo "0 级 (停转)" ;;
|
||||
1) echo "1 级 (低速 31%)" ;;
|
||||
2) echo "2 级 (中速 50%)" ;;
|
||||
3) echo "3 级 (全速 100%)" ;;
|
||||
*) echo "$1 级" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
calc_level() {
|
||||
local temp="$1"
|
||||
local cur="$2"
|
||||
local l1="$3"
|
||||
local l2="$4"
|
||||
local l3="$5"
|
||||
local h="$6"
|
||||
|
||||
if [ "${cur}" -le 0 ]; then
|
||||
if [ "${temp}" -ge "${l3}" ]; then
|
||||
echo 3
|
||||
elif [ "${temp}" -ge "${l2}" ]; then
|
||||
echo 2
|
||||
elif [ "${temp}" -ge "${l1}" ]; then
|
||||
echo 1
|
||||
else
|
||||
echo 0
|
||||
fi
|
||||
elif [ "${cur}" -eq 1 ]; then
|
||||
if [ "${temp}" -ge "${l3}" ]; then
|
||||
echo 3
|
||||
elif [ "${temp}" -ge "${l2}" ]; then
|
||||
echo 2
|
||||
elif [ "${temp}" -lt "$((l1 - h))" ]; then
|
||||
echo 0
|
||||
else
|
||||
echo 1
|
||||
fi
|
||||
elif [ "${cur}" -eq 2 ]; then
|
||||
if [ "${temp}" -ge "${l3}" ]; then
|
||||
echo 3
|
||||
elif [ "${temp}" -lt "$((l1 - h))" ]; then
|
||||
echo 0
|
||||
elif [ "${temp}" -lt "$((l2 - h))" ]; then
|
||||
echo 1
|
||||
else
|
||||
echo 2
|
||||
fi
|
||||
else
|
||||
if [ "${temp}" -lt "$((l1 - h))" ]; then
|
||||
echo 0
|
||||
elif [ "${temp}" -lt "$((l2 - h))" ]; then
|
||||
echo 1
|
||||
elif [ "${temp}" -lt "$((l3 - h))" ]; then
|
||||
echo 2
|
||||
else
|
||||
echo 3
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
if [ -n "${THERMAL_ZONE}" ] && [ -w "${THERMAL_ZONE}/policy" ]; then
|
||||
echo "step_wise" > "${THERMAL_ZONE}/policy" 2>/dev/null
|
||||
fi
|
||||
log_msg "信息" "风扇控制守护服务已停止,已恢复内核温控策略"
|
||||
exit 0
|
||||
}
|
||||
|
||||
trap cleanup INT TERM QUIT
|
||||
|
||||
find_nodes
|
||||
|
||||
if [ -z "${COOLING_DEV}" ] && [ -z "${HWMON_PWM}" ]; then
|
||||
log_msg "错误" "未找到可用的风扇硬件控制节点,服务退出"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
enabled=$(uci -q get ${CONFIG}.global.enabled || echo 1)
|
||||
if [ "${enabled}" != "1" ]; then
|
||||
log_msg "信息" "服务配置为未启用状态,退出"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mode=$(uci -q get ${CONFIG}.global.mode || echo "auto")
|
||||
interval=$(uci -q get ${CONFIG}.global.interval || echo 5)
|
||||
start_spin=$(uci -q get ${CONFIG}.global.start_spin || echo 1)
|
||||
temp_low=$(uci -q get ${CONFIG}.global.temp_low || echo 45)
|
||||
temp_med=$(uci -q get ${CONFIG}.global.temp_med || echo 60)
|
||||
temp_high=$(uci -q get ${CONFIG}.global.temp_high || echo 75)
|
||||
hysteresis=$(uci -q get ${CONFIG}.global.hysteresis || echo 3)
|
||||
manual_level=$(uci -q get ${CONFIG}.global.manual_level || echo 2)
|
||||
|
||||
[ "${interval}" -lt 1 ] 2>/dev/null && interval=1
|
||||
[ "${interval}" -gt 60 ] 2>/dev/null && interval=60
|
||||
|
||||
log_msg "信息" "风扇控制守护服务启动,运行模式: ${mode},检测周期: ${interval} 秒"
|
||||
|
||||
# 启动自检
|
||||
if [ "${start_spin}" = "1" ] && [ "${mode}" != "kernel" ]; then
|
||||
log_msg "信息" "执行启动自检,全速运转 2 秒以清洁防尘"
|
||||
set_fan_level 3
|
||||
sleep 2
|
||||
fi
|
||||
|
||||
# 非内核模式下切换为用户空间接管,防止内核 step_wise 依据 40°C 强制拉高转速
|
||||
if [ "${mode}" != "kernel" ] && [ -n "${THERMAL_ZONE}" ] && [ -w "${THERMAL_ZONE}/policy" ]; then
|
||||
echo "user_space" > "${THERMAL_ZONE}/policy" 2>/dev/null
|
||||
fi
|
||||
|
||||
current_level=-1
|
||||
|
||||
while true; do
|
||||
case "${mode}" in
|
||||
"kernel")
|
||||
# 内核托管模式
|
||||
if [ -n "${THERMAL_ZONE}" ] && [ -w "${THERMAL_ZONE}/policy" ]; then
|
||||
echo "step_wise" > "${THERMAL_ZONE}/policy" 2>/dev/null
|
||||
fi
|
||||
sleep "${interval}"
|
||||
;;
|
||||
|
||||
"manual")
|
||||
if [ "${current_level}" -ne "${manual_level}" ]; then
|
||||
set_fan_level "${manual_level}"
|
||||
current_level="${manual_level}"
|
||||
lvl_name=$(get_level_name "${manual_level}")
|
||||
log_msg "信息" "手动定速模式生效,当前档位设定为: ${lvl_name}"
|
||||
fi
|
||||
sleep "${interval}"
|
||||
;;
|
||||
|
||||
"auto"|*)
|
||||
raw_t=$(get_temperature)
|
||||
# 单位毫摄氏度转整数摄氏度
|
||||
t_c=$((raw_t / 1000))
|
||||
t_dec=$(((raw_t % 1000) / 100))
|
||||
target_lvl=$(calc_level "${t_c}" "${current_level}" "${temp_low}" "${temp_med}" "${temp_high}" "${hysteresis}")
|
||||
|
||||
if [ "${target_lvl}" -ne "${current_level}" ]; then
|
||||
set_fan_level "${target_lvl}"
|
||||
old_name=$(get_level_name "${current_level}")
|
||||
new_name=$(get_level_name "${target_lvl}")
|
||||
if [ "${current_level}" -eq -1 ]; then
|
||||
log_msg "信息" "初始化风扇档位: 当前温度 ${t_c}.${t_dec} °C,设定为 ${new_name}"
|
||||
else
|
||||
log_msg "信息" "温度变化 (${t_c}.${t_dec} °C): 档位由 ${old_name} 调整为 ${new_name}"
|
||||
fi
|
||||
current_level="${target_lvl}"
|
||||
fi
|
||||
sleep "${interval}"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
@@ -1,37 +1,13 @@
|
||||
{
|
||||
"admin/system/fancontrol": {
|
||||
"title": "风扇控制",
|
||||
"order": 65,
|
||||
"admin/services/fancontrol": {
|
||||
"title": "Fan Control",
|
||||
"order": 90,
|
||||
"action": {
|
||||
"type": "firstchild"
|
||||
"type": "view",
|
||||
"path": "fancontrol"
|
||||
},
|
||||
"depends": {
|
||||
"acl": [ "luci-app-fancontrol" ],
|
||||
"uci": { "fancontrol": true }
|
||||
}
|
||||
},
|
||||
"admin/system/fancontrol/overview": {
|
||||
"title": "状态概览",
|
||||
"order": 10,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "fancontrol/overview"
|
||||
}
|
||||
},
|
||||
"admin/system/fancontrol/settings": {
|
||||
"title": "温控配置",
|
||||
"order": 20,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "fancontrol/settings"
|
||||
}
|
||||
},
|
||||
"admin/system/fancontrol/log": {
|
||||
"title": "运行日志",
|
||||
"order": 30,
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "fancontrol/log"
|
||||
"acl": [ "luci-app-fancontrol" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,17 @@
|
||||
{
|
||||
"luci-app-fancontrol": {
|
||||
"description": "Grant access to BPI-R4 fan control procedures",
|
||||
"description": "Grant access to Fan Control",
|
||||
"read": {
|
||||
"uci": [ "fancontrol" ],
|
||||
"ubus": {
|
||||
"luci.fancontrol": [ "*" ]
|
||||
"service": [ "list" ]
|
||||
},
|
||||
"uci": [
|
||||
"fancontrol"
|
||||
]
|
||||
"file": {
|
||||
"/var/run/fancontrol.status": [ "read" ]
|
||||
}
|
||||
},
|
||||
"write": {
|
||||
"ubus": {
|
||||
"luci.fancontrol": [ "*" ]
|
||||
},
|
||||
"uci": [
|
||||
"fancontrol"
|
||||
]
|
||||
"uci": [ "fancontrol" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,223 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
import { access, readfile, writefile, stat, popen } from 'fs';
|
||||
import { cursor } from 'uci';
|
||||
import { connect } from 'ubus';
|
||||
|
||||
const UCI_CONFIG = 'fancontrol';
|
||||
const LOG_FILE = '/var/log/fancontrol.log';
|
||||
const THERMAL_ZONE_TEMP = '/sys/class/thermal/thermal_zone0/temp';
|
||||
const COOLING_DEV_CUR = '/sys/class/thermal/cooling_device0/cur_state';
|
||||
const HWMON_PWM = '/sys/class/hwmon/hwmon1/pwm1';
|
||||
|
||||
function get_procd_status() {
|
||||
let u = connect();
|
||||
if (!u) return { running: false, pid: null, state: 'stopped' };
|
||||
|
||||
let res = u.call('service', 'list', { name: 'fancontrol' });
|
||||
u.disconnect();
|
||||
|
||||
if (res && res['fancontrol'] && res['fancontrol'].instances) {
|
||||
let instances = res['fancontrol'].instances;
|
||||
for (let name in instances) {
|
||||
let inst = instances[name];
|
||||
if (inst && inst.running) {
|
||||
return { running: true, pid: inst.pid, state: 'managed' };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否有残留孤儿进程
|
||||
let p = popen('pidof /usr/sbin/fancontrold', 'r');
|
||||
if (p) {
|
||||
let pid_str = p.read('all');
|
||||
p.close();
|
||||
if (pid_str && length(trim(pid_str)) > 0) {
|
||||
let pids = split(trim(pid_str), /\s+/);
|
||||
if (length(pids) > 0 && pids[0] != '') {
|
||||
return { running: true, pid: int(pids[0]), state: 'unmanaged' };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { running: false, pid: null, state: 'stopped' };
|
||||
}
|
||||
|
||||
function get_hardware_info() {
|
||||
let temp_c = 0.0;
|
||||
if (access(THERMAL_ZONE_TEMP, 'r')) {
|
||||
let raw_t = readfile(THERMAL_ZONE_TEMP);
|
||||
if (raw_t) {
|
||||
let raw_val = int(trim(raw_t));
|
||||
temp_c = sprintf('%.1f', raw_val / 1000.0);
|
||||
}
|
||||
}
|
||||
|
||||
let cur_level = 0;
|
||||
if (access(COOLING_DEV_CUR, 'r')) {
|
||||
let raw_lvl = readfile(COOLING_DEV_CUR);
|
||||
if (raw_lvl) cur_level = int(trim(raw_lvl));
|
||||
}
|
||||
|
||||
let pwm_val = 0;
|
||||
if (access(HWMON_PWM, 'r')) {
|
||||
let raw_pwm = readfile(HWMON_PWM);
|
||||
if (raw_pwm) pwm_val = int(trim(raw_pwm));
|
||||
} else {
|
||||
// 依据档位估算
|
||||
if (cur_level == 1) pwm_val = 80;
|
||||
else if (cur_level == 2) pwm_val = 128;
|
||||
else if (cur_level == 3) pwm_val = 255;
|
||||
}
|
||||
|
||||
return {
|
||||
temp: temp_c,
|
||||
level: cur_level,
|
||||
pwm: pwm_val
|
||||
};
|
||||
}
|
||||
|
||||
const methods = {
|
||||
get_status: {
|
||||
call: function() {
|
||||
let proc = get_procd_status();
|
||||
let hw = get_hardware_info();
|
||||
let uci_c = cursor();
|
||||
let enabled = int(uci_c.get(UCI_CONFIG, 'global', 'enabled') || '0');
|
||||
let mode = uci_c.get(UCI_CONFIG, 'global', 'mode') || 'auto';
|
||||
let interval = int(uci_c.get(UCI_CONFIG, 'global', 'interval') || '5');
|
||||
|
||||
let start_spin = int(uci_c.get(UCI_CONFIG, 'global', 'start_spin') || '1');
|
||||
let temp_low = int(uci_c.get(UCI_CONFIG, 'global', 'temp_low') || '45');
|
||||
let temp_med = int(uci_c.get(UCI_CONFIG, 'global', 'temp_med') || '60');
|
||||
let temp_high = int(uci_c.get(UCI_CONFIG, 'global', 'temp_high') || '75');
|
||||
let hysteresis = int(uci_c.get(UCI_CONFIG, 'global', 'hysteresis') || '3');
|
||||
let manual_level = int(uci_c.get(UCI_CONFIG, 'global', 'manual_level') || '2');
|
||||
|
||||
return {
|
||||
running: proc.running,
|
||||
state: proc.state,
|
||||
pid: proc.pid,
|
||||
enabled: enabled,
|
||||
mode: mode,
|
||||
interval: interval,
|
||||
start_spin: start_spin,
|
||||
temp_low: temp_low,
|
||||
temp_med: temp_med,
|
||||
temp_high: temp_high,
|
||||
hysteresis: hysteresis,
|
||||
manual_level: manual_level,
|
||||
temp: hw.temp,
|
||||
level: hw.level,
|
||||
pwm: hw.pwm
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
set_level: {
|
||||
args: { level: 0 },
|
||||
call: function(req) {
|
||||
let lvl = int(req.args?.level ?? 0);
|
||||
if (lvl < 0) lvl = 0;
|
||||
if (lvl > 3) lvl = 3;
|
||||
|
||||
let applied = false;
|
||||
if (access(COOLING_DEV_CUR, 'w')) {
|
||||
try {
|
||||
writefile(COOLING_DEV_CUR, lvl + "\n");
|
||||
applied = true;
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
if (!applied && access(HWMON_PWM, 'w')) {
|
||||
let pwm_val = 0;
|
||||
if (lvl == 1) pwm_val = 80;
|
||||
else if (lvl == 2) pwm_val = 128;
|
||||
else if (lvl == 3) pwm_val = 255;
|
||||
try {
|
||||
writefile(HWMON_PWM, pwm_val + "\n");
|
||||
applied = true;
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// 记录测试日志
|
||||
try {
|
||||
let p = popen('date "+%Y-%m-%d %H:%M:%S"', 'r');
|
||||
let ts = p ? trim(p.read('all')) : '';
|
||||
if (p) p.close();
|
||||
let line = ts + ' [测试] 手动即时下发风扇档位: ' + lvl + ' 级\n';
|
||||
let old_content = readfile(LOG_FILE) || '';
|
||||
writefile(LOG_FILE, old_content + line);
|
||||
} catch (e) {}
|
||||
|
||||
return { success: applied, level: lvl };
|
||||
}
|
||||
},
|
||||
|
||||
get_logs: {
|
||||
args: { lines: 100 },
|
||||
call: function(req) {
|
||||
let lines_limit = int(req.args?.lines ?? 100);
|
||||
let logs = [];
|
||||
try {
|
||||
if (access(LOG_FILE, 'r')) {
|
||||
let log_stat = stat(LOG_FILE);
|
||||
let content = '';
|
||||
if (log_stat && log_stat.size > 65536) {
|
||||
let fd = popen('tail -c 65536 ' + LOG_FILE, 'r');
|
||||
if (fd) {
|
||||
content = fd.read('all');
|
||||
fd.close();
|
||||
}
|
||||
} else {
|
||||
content = readfile(LOG_FILE);
|
||||
}
|
||||
if (content) {
|
||||
let all_lines = split(content, "\n");
|
||||
let total = length(all_lines);
|
||||
let start = (total > lines_limit) ? (total - lines_limit) : 0;
|
||||
for (let i = start; i < total; i++) {
|
||||
if (all_lines[i] && length(trim(all_lines[i])) > 0) {
|
||||
push(logs, all_lines[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
return { logs: logs };
|
||||
}
|
||||
},
|
||||
|
||||
clear_logs: {
|
||||
call: function() {
|
||||
try {
|
||||
writefile(LOG_FILE, '');
|
||||
return { success: true };
|
||||
} catch (e) {
|
||||
return { success: false, error: e };
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
service: {
|
||||
args: { action: 'restart' },
|
||||
call: function(req) {
|
||||
let action = req.args?.action || 'restart';
|
||||
if (action != 'start' && action != 'stop' && action != 'restart') {
|
||||
return { success: false, error: 'Invalid action' };
|
||||
}
|
||||
|
||||
if (action == 'restart' || action == 'stop') {
|
||||
// 强杀孤儿残留进程
|
||||
let p = popen('killall -9 fancontrold', 'r');
|
||||
if (p) p.close();
|
||||
}
|
||||
|
||||
let rc = system('/etc/init.d/fancontrol ' + action + ' >/dev/null 2>&1');
|
||||
system('sleep 1');
|
||||
return { success: (rc === 0) };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return { 'luci.fancontrol': methods };
|
||||
@@ -1,25 +0,0 @@
|
||||
#
|
||||
# Copyright 2025 Rafał Wabik - IceG - From eko.one.pl forum
|
||||
#
|
||||
# MIT License
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-ports-status-mod
|
||||
PKG_MAINTAINER:=Rafał Wabik <4Rafal@gmail.com>
|
||||
LUCI_TITLE:=Small modification of Ports Status
|
||||
LUCI_DEPENDS:=+luci-mod-admin-full
|
||||
LUCI_PKGARCH:=all
|
||||
PKG_LICENSE:=MIT
|
||||
PKG_VERSION:=1.0.8
|
||||
PKG_RELEASE:=1
|
||||
|
||||
define Package/luci-app-ports-status-mod/conffiles
|
||||
/etc/user_defined_ports.json
|
||||
/etc/user_defined_ports.json.bak
|
||||
endef
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
-1566
File diff suppressed because it is too large.
Load diff
@@ -1,175 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Language-Team: Rafał Wabik (IceG)\n"
|
||||
"Language: cs\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2);\n"
|
||||
|
||||
msgid "Edit Port Label"
|
||||
msgstr "Upravit štítek portu"
|
||||
|
||||
msgid "Enter new label for this port:"
|
||||
msgstr "Zadejte nový štítek pro tento port:"
|
||||
|
||||
msgid "Device"
|
||||
msgstr "Zařízení"
|
||||
|
||||
msgid "Original label"
|
||||
msgstr "Původní štítek"
|
||||
|
||||
msgid "Restore Original"
|
||||
msgstr "Obnovit původní"
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr "Zrušit"
|
||||
|
||||
msgid "Save"
|
||||
msgstr "Uložit"
|
||||
|
||||
msgid "Port configuration saved successfully"
|
||||
msgstr "Konfigurace portu byla úspěšně uložena"
|
||||
|
||||
msgid "Port order saved"
|
||||
msgstr "Pořadí portů bylo uloženo"
|
||||
|
||||
msgid "Click to edit label"
|
||||
msgstr "Kliknutím upravíte štítek"
|
||||
|
||||
msgid "Hold to drag and reorder"
|
||||
msgstr "Podržením přetáhněte a změňte pořadí"
|
||||
|
||||
msgid "Label max 9 chars, description max 50 chars."
|
||||
msgstr "Štítek maximálně 9 znaků, popis maximálně 50 znaků."
|
||||
|
||||
msgid "Enter description (optional):"
|
||||
msgstr "Zadejte popis (volitelné):"
|
||||
|
||||
msgid "Optional description"
|
||||
msgstr "Volitelný popis"
|
||||
|
||||
msgid "User settings are saved to the /etc/user_defined_ports.json file."
|
||||
msgstr "Uživatelská nastavení jsou ukládána do souboru /etc/user_defined_ports.json."
|
||||
|
||||
msgid "Configuration file downloaded"
|
||||
msgstr "Konfigurační soubor byl stažen"
|
||||
|
||||
msgid "Configuration file not found"
|
||||
msgstr "Konfigurační soubor nebyl nalezen"
|
||||
|
||||
msgid "Download error: %s"
|
||||
msgstr "Chyba stahování: %s"
|
||||
|
||||
msgid "Invalid configuration format"
|
||||
msgstr "Neplatný formát konfigurace"
|
||||
|
||||
msgid "Restore configuration"
|
||||
msgstr "Obnovit konfiguraci"
|
||||
|
||||
msgid "This will overwrite current ports configuration. Continue?"
|
||||
msgstr "Tato operace přepíše aktuální konfiguraci portů. Pokračovat?"
|
||||
|
||||
msgid "Configuration restored successfully. Reloading..."
|
||||
msgstr "Konfigurace byla úspěšně obnovena. Načítání..."
|
||||
|
||||
msgid "File restore failed: %s"
|
||||
msgstr "Obnovení souboru selhalo: %s"
|
||||
|
||||
msgid "Save .json file"
|
||||
msgstr "Uložit soubor .json"
|
||||
|
||||
msgid "Upload .json file"
|
||||
msgstr "Nahrát soubor .json"
|
||||
|
||||
msgid "Cannot save empty configuration"
|
||||
msgstr "Nelze uložit prázdnou konfiguraci"
|
||||
|
||||
msgid "Cannot save port configuration. "
|
||||
msgstr "Nelze uložit konfiguraci portu. "
|
||||
|
||||
msgid "Directory /etc may be read-only or insufficient permissions. "
|
||||
msgstr "Adresář /etc může být pouze pro čtení nebo má nedostatečná oprávnění. "
|
||||
|
||||
msgid "Try running: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
msgstr "Zkuste spustit: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
|
||||
msgid "Save Error"
|
||||
msgstr "Chyba ukládání"
|
||||
|
||||
msgid "Original error: %s"
|
||||
msgstr "Původní chyba: %s"
|
||||
|
||||
msgid "Restore from backup"
|
||||
msgstr "Obnovit ze zálohy"
|
||||
|
||||
msgid "Restore configuration from backup file? This will overwrite current settings."
|
||||
msgstr "Obnovit konfiguraci ze záložního souboru? Tímto dojde k přepsání aktuálního nastavení."
|
||||
|
||||
msgid "Backup contains:"
|
||||
msgstr "Záloha obsahuje:"
|
||||
|
||||
msgid "Configuration restored from backup. Reloading..."
|
||||
msgstr "Konfigurace byla obnovena ze zálohy. Načítání..."
|
||||
|
||||
msgid "Restore failed: %s"
|
||||
msgstr "Obnovení selhalo: %s"
|
||||
|
||||
msgid "Backup file is corrupted: %s"
|
||||
msgstr "Záložní soubor je poškozen: %s"
|
||||
|
||||
msgid "Error reading backup: %s"
|
||||
msgstr "Chyba při čtení zálohy: %s"
|
||||
|
||||
msgid "Restore backup .bak"
|
||||
msgstr "Obnovit zálohu .bak"
|
||||
|
||||
msgid "Change port state"
|
||||
msgstr "Změnit stav portu"
|
||||
|
||||
msgid "Enable this port"
|
||||
msgstr "Povolit tento port"
|
||||
|
||||
msgid "Enable port"
|
||||
msgstr "Povolit port"
|
||||
|
||||
msgid "Disable this port"
|
||||
msgstr "Zakázat tento port"
|
||||
|
||||
msgid "Disable port"
|
||||
msgstr "Zakázat port"
|
||||
|
||||
msgid "Down"
|
||||
msgstr "neaktivní"
|
||||
|
||||
msgid "Disabled"
|
||||
msgstr "zakázáno"
|
||||
|
||||
msgid "Idle"
|
||||
msgstr "nečinný"
|
||||
|
||||
msgid "Active"
|
||||
msgstr "aktivní"
|
||||
|
||||
msgid "Unknown"
|
||||
msgstr "neznámý"
|
||||
|
||||
msgid "No config file to backup"
|
||||
msgstr "Žádný konfigurační soubor k zálohování"
|
||||
|
||||
msgid "Config file is corrupted, cannot create backup"
|
||||
msgstr "Konfigurační soubor je poškozen, nelze vytvořit zálohu"
|
||||
|
||||
msgid "Backup file created: %s"
|
||||
msgstr "Záložní soubor byl vytvořen: %s"
|
||||
|
||||
msgid "Backup write verification failed!"
|
||||
msgstr "Ověření zápisu zálohy selhalo!"
|
||||
|
||||
msgid "Backup creation failed: %s"
|
||||
msgstr "Vytvoření zálohy selhalo: %s"
|
||||
|
||||
msgid "Error reading config: %s"
|
||||
msgstr "Chyba při čtení konfigurace: %s"
|
||||
|
||||
msgid "Create backup .bak"
|
||||
msgstr "Vytvořit zálohu .bak"
|
||||
@@ -1,175 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Language-Team: Rafał Wabik (IceG)\n"
|
||||
"Language: da\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
|
||||
msgid "Edit Port Label"
|
||||
msgstr "Rediger portmærkat"
|
||||
|
||||
msgid "Enter new label for this port:"
|
||||
msgstr "Indtast ny mærkat for denne port:"
|
||||
|
||||
msgid "Device"
|
||||
msgstr "Enhed"
|
||||
|
||||
msgid "Original label"
|
||||
msgstr "Oprindelig mærkat"
|
||||
|
||||
msgid "Restore Original"
|
||||
msgstr "Gendan oprindelig"
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr "Annuller"
|
||||
|
||||
msgid "Save"
|
||||
msgstr "Gem"
|
||||
|
||||
msgid "Port configuration saved successfully"
|
||||
msgstr "Portkonfigurationen blev gemt"
|
||||
|
||||
msgid "Port order saved"
|
||||
msgstr "Portrækkefølge gemt"
|
||||
|
||||
msgid "Click to edit label"
|
||||
msgstr "Klik for at redigere mærkat"
|
||||
|
||||
msgid "Hold to drag and reorder"
|
||||
msgstr "Hold nede for at trække og omarrangere"
|
||||
|
||||
msgid "Label max 9 chars, description max 50 chars."
|
||||
msgstr "Mærkat maks. 9 tegn, beskrivelse maks. 50 tegn."
|
||||
|
||||
msgid "Enter description (optional):"
|
||||
msgstr "Indtast beskrivelse (valgfri):"
|
||||
|
||||
msgid "Optional description"
|
||||
msgstr "Valgfri beskrivelse"
|
||||
|
||||
msgid "User settings are saved to the /etc/user_defined_ports.json file."
|
||||
msgstr "Brugerindstillinger gemmes i filen /etc/user_defined_ports.json."
|
||||
|
||||
msgid "Configuration file downloaded"
|
||||
msgstr "Konfigurationsfil downloadet"
|
||||
|
||||
msgid "Configuration file not found"
|
||||
msgstr "Konfigurationsfil ikke fundet"
|
||||
|
||||
msgid "Download error: %s"
|
||||
msgstr "Downloadfejl: %s"
|
||||
|
||||
msgid "Invalid configuration format"
|
||||
msgstr "Ugyldigt konfigurationsformat"
|
||||
|
||||
msgid "Restore configuration"
|
||||
msgstr "Gendan konfiguration"
|
||||
|
||||
msgid "This will overwrite current ports configuration. Continue?"
|
||||
msgstr "Dette vil overskrive den nuværende portkonfiguration. Fortsæt?"
|
||||
|
||||
msgid "Configuration restored successfully. Reloading..."
|
||||
msgstr "Konfigurationen blev gendannet. Genindlæser..."
|
||||
|
||||
msgid "File restore failed: %s"
|
||||
msgstr "Gendannelse af fil mislykkedes: %s"
|
||||
|
||||
msgid "Save .json file"
|
||||
msgstr "Gem .json-fil"
|
||||
|
||||
msgid "Upload .json file"
|
||||
msgstr "Upload .json-fil"
|
||||
|
||||
msgid "Cannot save empty configuration"
|
||||
msgstr "Kan ikke gemme en tom konfiguration"
|
||||
|
||||
msgid "Cannot save port configuration. "
|
||||
msgstr "Kan ikke gemme portkonfiguration. "
|
||||
|
||||
msgid "Directory /etc may be read-only or insufficient permissions. "
|
||||
msgstr "Mappen /etc er muligvis skrivebeskyttet eller har utilstrækkelige tilladelser. "
|
||||
|
||||
msgid "Try running: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
msgstr "Prøv at køre: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
|
||||
msgid "Save Error"
|
||||
msgstr "Fejl ved lagring"
|
||||
|
||||
msgid "Original error: %s"
|
||||
msgstr "Oprindelig fejl: %s"
|
||||
|
||||
msgid "Restore from backup"
|
||||
msgstr "Gendan fra sikkerhedskopi"
|
||||
|
||||
msgid "Restore configuration from backup file? This will overwrite current settings."
|
||||
msgstr "Gendan konfiguration fra sikkerhedskopifil? Dette vil overskrive de nuværende indstillinger."
|
||||
|
||||
msgid "Backup contains:"
|
||||
msgstr "Sikkerhedskopi indeholder:"
|
||||
|
||||
msgid "Configuration restored from backup. Reloading..."
|
||||
msgstr "Konfiguration gendannet fra sikkerhedskopi. Genindlæser..."
|
||||
|
||||
msgid "Restore failed: %s"
|
||||
msgstr "Gendannelse mislykkedes: %s"
|
||||
|
||||
msgid "Backup file is corrupted: %s"
|
||||
msgstr "Sikkerhedskopifilen er beskadiget: %s"
|
||||
|
||||
msgid "Error reading backup: %s"
|
||||
msgstr "Fejl ved læsning af sikkerhedskopi: %s"
|
||||
|
||||
msgid "Restore backup .bak"
|
||||
msgstr "Gendan .bak-sikkerhedskopi"
|
||||
|
||||
msgid "Change port state"
|
||||
msgstr "Skift portstatus"
|
||||
|
||||
msgid "Enable this port"
|
||||
msgstr "Aktiver denne port"
|
||||
|
||||
msgid "Enable port"
|
||||
msgstr "Aktiver port"
|
||||
|
||||
msgid "Disable this port"
|
||||
msgstr "Deaktiver denne port"
|
||||
|
||||
msgid "Disable port"
|
||||
msgstr "Deaktiver port"
|
||||
|
||||
msgid "Down"
|
||||
msgstr "nede"
|
||||
|
||||
msgid "Disabled"
|
||||
msgstr "deaktiveret"
|
||||
|
||||
msgid "Idle"
|
||||
msgstr "inaktiv"
|
||||
|
||||
msgid "Active"
|
||||
msgstr "aktiv"
|
||||
|
||||
msgid "Unknown"
|
||||
msgstr "ukendt"
|
||||
|
||||
msgid "No config file to backup"
|
||||
msgstr "Ingen konfigurationsfil at sikkerhedskopiere"
|
||||
|
||||
msgid "Config file is corrupted, cannot create backup"
|
||||
msgstr "Konfigurationsfilen er beskadiget, kan ikke oprette sikkerhedskopi"
|
||||
|
||||
msgid "Backup file created: %s"
|
||||
msgstr "Sikkerhedskopifil oprettet: %s"
|
||||
|
||||
msgid "Backup write verification failed!"
|
||||
msgstr "Skriveverifikation af sikkerhedskopi mislykkedes!"
|
||||
|
||||
msgid "Backup creation failed: %s"
|
||||
msgstr "Oprettelse af sikkerhedskopi mislykkedes: %s"
|
||||
|
||||
msgid "Error reading config: %s"
|
||||
msgstr "Fejl ved læsning af konfiguration: %s"
|
||||
|
||||
msgid "Create backup .bak"
|
||||
msgstr "Opret .bak-sikkerhedskopi"
|
||||
@@ -1,175 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Language-Team: Rafał Wabik (IceG)\n"
|
||||
"Language: de\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
|
||||
msgid "Edit Port Label"
|
||||
msgstr "Port-Beschriftung bearbeiten"
|
||||
|
||||
msgid "Enter new label for this port:"
|
||||
msgstr "Neue Beschriftung für diesen Port eingeben:"
|
||||
|
||||
msgid "Device"
|
||||
msgstr "Gerät"
|
||||
|
||||
msgid "Original label"
|
||||
msgstr "Originalbeschriftung"
|
||||
|
||||
msgid "Restore Original"
|
||||
msgstr "Original wiederherstellen"
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr "Abbrechen"
|
||||
|
||||
msgid "Save"
|
||||
msgstr "Speichern"
|
||||
|
||||
msgid "Port configuration saved successfully"
|
||||
msgstr "Port-Konfiguration erfolgreich gespeichert"
|
||||
|
||||
msgid "Port order saved"
|
||||
msgstr "Port-Reihenfolge gespeichert"
|
||||
|
||||
msgid "Click to edit label"
|
||||
msgstr "Klicken Sie, um die Beschriftung zu bearbeiten"
|
||||
|
||||
msgid "Hold to drag and reorder"
|
||||
msgstr "Halten Sie gedrückt, um zu ziehen und neu anzuordnen"
|
||||
|
||||
msgid "Label max 9 chars, description max 50 chars."
|
||||
msgstr "Beschriftung max. 9 Zeichen, Beschreibung max. 50 Zeichen."
|
||||
|
||||
msgid "Enter description (optional):"
|
||||
msgstr "Beschreibung eingeben (optional):"
|
||||
|
||||
msgid "Optional description"
|
||||
msgstr "Optionale Beschreibung"
|
||||
|
||||
msgid "User settings are saved to the /etc/user_defined_ports.json file."
|
||||
msgstr "Benutzereinstellungen werden in der Datei /etc/user_defined_ports.json gespeichert."
|
||||
|
||||
msgid "Configuration file downloaded"
|
||||
msgstr "Konfigurationsdatei heruntergeladen"
|
||||
|
||||
msgid "Configuration file not found"
|
||||
msgstr "Konfigurationsdatei nicht gefunden"
|
||||
|
||||
msgid "Download error: %s"
|
||||
msgstr "Download-Fehler: %s"
|
||||
|
||||
msgid "Invalid configuration format"
|
||||
msgstr "Ungültiges Konfigurationsformat"
|
||||
|
||||
msgid "Restore configuration"
|
||||
msgstr "Konfiguration wiederherstellen"
|
||||
|
||||
msgid "This will overwrite current ports configuration. Continue?"
|
||||
msgstr "Dies überschreibt die aktuelle Port-Konfiguration. Fortfahren?"
|
||||
|
||||
msgid "Configuration restored successfully. Reloading..."
|
||||
msgstr "Konfiguration erfolgreich wiederhergestellt. Wird neu geladen..."
|
||||
|
||||
msgid "File restore failed: %s"
|
||||
msgstr "Dateiwiederherstellung fehlgeschlagen: %s"
|
||||
|
||||
msgid "Save .json file"
|
||||
msgstr ".json-Datei speichern"
|
||||
|
||||
msgid "Upload .json file"
|
||||
msgstr ".json-Datei hochladen"
|
||||
|
||||
msgid "Cannot save empty configuration"
|
||||
msgstr "Leere Konfiguration kann nicht gespeichert werden"
|
||||
|
||||
msgid "Cannot save port configuration. "
|
||||
msgstr "Port-Konfiguration kann nicht gespeichert werden. "
|
||||
|
||||
msgid "Directory /etc may be read-only or insufficient permissions. "
|
||||
msgstr "Verzeichnis /etc ist möglicherweise schreibgeschützt oder hat unzureichende Berechtigungen. "
|
||||
|
||||
msgid "Try running: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
msgstr "Versuchen Sie auszuführen: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
|
||||
msgid "Save Error"
|
||||
msgstr "Speicherfehler"
|
||||
|
||||
msgid "Original error: %s"
|
||||
msgstr "Ursprünglicher Fehler: %s"
|
||||
|
||||
msgid "Restore from backup"
|
||||
msgstr "Aus Sicherung wiederherstellen"
|
||||
|
||||
msgid "Restore configuration from backup file? This will overwrite current settings."
|
||||
msgstr "Konfiguration aus Sicherungsdatei wiederherstellen? Dies überschreibt die aktuellen Einstellungen."
|
||||
|
||||
msgid "Backup contains:"
|
||||
msgstr "Sicherung enthält:"
|
||||
|
||||
msgid "Configuration restored from backup. Reloading..."
|
||||
msgstr "Konfiguration aus Sicherung wiederhergestellt. Wird neu geladen..."
|
||||
|
||||
msgid "Restore failed: %s"
|
||||
msgstr "Wiederherstellung fehlgeschlagen: %s"
|
||||
|
||||
msgid "Backup file is corrupted: %s"
|
||||
msgstr "Sicherungsdatei ist beschädigt: %s"
|
||||
|
||||
msgid "Error reading backup: %s"
|
||||
msgstr "Fehler beim Lesen der Sicherung: %s"
|
||||
|
||||
msgid "Restore backup .bak"
|
||||
msgstr "Sicherung .bak wiederherstellen"
|
||||
|
||||
msgid "Change port state"
|
||||
msgstr "Portstatus ändern"
|
||||
|
||||
msgid "Enable this port"
|
||||
msgstr "Diesen Port aktivieren"
|
||||
|
||||
msgid "Enable port"
|
||||
msgstr "Port aktivieren"
|
||||
|
||||
msgid "Disable this port"
|
||||
msgstr "Diesen Port deaktivieren"
|
||||
|
||||
msgid "Disable port"
|
||||
msgstr "Port deaktivieren"
|
||||
|
||||
msgid "Down"
|
||||
msgstr "inaktiv"
|
||||
|
||||
msgid "Disabled"
|
||||
msgstr "deaktiviert"
|
||||
|
||||
msgid "Idle"
|
||||
msgstr "leerlauf"
|
||||
|
||||
msgid "Active"
|
||||
msgstr "aktiv"
|
||||
|
||||
msgid "Unknown"
|
||||
msgstr "unbekannt"
|
||||
|
||||
msgid "No config file to backup"
|
||||
msgstr "Keine Konfigurationsdatei zum Sichern vorhanden"
|
||||
|
||||
msgid "Config file is corrupted, cannot create backup"
|
||||
msgstr "Konfigurationsdatei ist beschädigt, Sicherung kann nicht erstellt werden"
|
||||
|
||||
msgid "Backup file created: %s"
|
||||
msgstr "Sicherungsdatei erstellt: %s"
|
||||
|
||||
msgid "Backup write verification failed!"
|
||||
msgstr "Überprüfung des Sicherungsschreibvorgangs fehlgeschlagen!"
|
||||
|
||||
msgid "Backup creation failed: %s"
|
||||
msgstr "Erstellung der Sicherung fehlgeschlagen: %s"
|
||||
|
||||
msgid "Error reading config: %s"
|
||||
msgstr "Fehler beim Lesen der Konfiguration: %s"
|
||||
|
||||
msgid "Create backup .bak"
|
||||
msgstr "Sicherung .bak erstellen"
|
||||
@@ -1,175 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Language-Team: Rafał Wabik (IceG)\n"
|
||||
"Language: es\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
|
||||
msgid "Edit Port Label"
|
||||
msgstr "Editar etiqueta del puerto"
|
||||
|
||||
msgid "Enter new label for this port:"
|
||||
msgstr "Introduzca la nueva etiqueta para este puerto:"
|
||||
|
||||
msgid "Device"
|
||||
msgstr "Dispositivo"
|
||||
|
||||
msgid "Original label"
|
||||
msgstr "Etiqueta original"
|
||||
|
||||
msgid "Restore Original"
|
||||
msgstr "Restaurar original"
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr "Cancelar"
|
||||
|
||||
msgid "Save"
|
||||
msgstr "Guardar"
|
||||
|
||||
msgid "Port configuration saved successfully"
|
||||
msgstr "Configuración del puerto guardada correctamente"
|
||||
|
||||
msgid "Port order saved"
|
||||
msgstr "Orden de los puertos guardado"
|
||||
|
||||
msgid "Click to edit label"
|
||||
msgstr "Haga clic para editar la etiqueta"
|
||||
|
||||
msgid "Hold to drag and reorder"
|
||||
msgstr "Mantenga pulsado para arrastrar y reordenar"
|
||||
|
||||
msgid "Label max 9 chars, description max 50 chars."
|
||||
msgstr "Etiqueta máx. 9 caracteres, descripción máx. 50 caracteres."
|
||||
|
||||
msgid "Enter description (optional):"
|
||||
msgstr "Introduzca una descripción (opcional):"
|
||||
|
||||
msgid "Optional description"
|
||||
msgstr "Descripción opcional"
|
||||
|
||||
msgid "User settings are saved to the /etc/user_defined_ports.json file."
|
||||
msgstr "Los ajustes de usuario se guardan en el archivo /etc/user_defined_ports.json."
|
||||
|
||||
msgid "Configuration file downloaded"
|
||||
msgstr "Archivo de configuración descargado"
|
||||
|
||||
msgid "Configuration file not found"
|
||||
msgstr "Archivo de configuración no encontrado"
|
||||
|
||||
msgid "Download error: %s"
|
||||
msgstr "Error de descarga: %s"
|
||||
|
||||
msgid "Invalid configuration format"
|
||||
msgstr "Formato de configuración no válido"
|
||||
|
||||
msgid "Restore configuration"
|
||||
msgstr "Restaurar configuración"
|
||||
|
||||
msgid "This will overwrite current ports configuration. Continue?"
|
||||
msgstr "Esta acción sobrescribirá la configuración actual de los puertos. ¿Continuar?"
|
||||
|
||||
msgid "Configuration restored successfully. Reloading..."
|
||||
msgstr "Configuración restaurada correctamente. Recargando..."
|
||||
|
||||
msgid "File restore failed: %s"
|
||||
msgstr "Fallo al restaurar el archivo: %s"
|
||||
|
||||
msgid "Save .json file"
|
||||
msgstr "Guardar archivo .json"
|
||||
|
||||
msgid "Upload .json file"
|
||||
msgstr "Subir archivo .json"
|
||||
|
||||
msgid "Cannot save empty configuration"
|
||||
msgstr "No se puede guardar una configuración vacía"
|
||||
|
||||
msgid "Cannot save port configuration. "
|
||||
msgstr "No se puede guardar la configuración del puerto. "
|
||||
|
||||
msgid "Directory /etc may be read-only or insufficient permissions. "
|
||||
msgstr "El directorio /etc puede ser de solo lectura o no tener permisos suficientes. "
|
||||
|
||||
msgid "Try running: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
msgstr "Intente ejecutar: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
|
||||
msgid "Save Error"
|
||||
msgstr "Error al guardar"
|
||||
|
||||
msgid "Original error: %s"
|
||||
msgstr "Error original: %s"
|
||||
|
||||
msgid "Restore from backup"
|
||||
msgstr "Restaurar desde copia de seguridad"
|
||||
|
||||
msgid "Restore configuration from backup file? This will overwrite current settings."
|
||||
msgstr "¿Restaurar configuración desde el archivo de copia de seguridad? Se sobrescribirán los ajustes actuales."
|
||||
|
||||
msgid "Backup contains:"
|
||||
msgstr "La copia de seguridad contiene:"
|
||||
|
||||
msgid "Configuration restored from backup. Reloading..."
|
||||
msgstr "Configuración restaurada desde la copia de seguridad. Recargando..."
|
||||
|
||||
msgid "Restore failed: %s"
|
||||
msgstr "Fallo al restaurar: %s"
|
||||
|
||||
msgid "Backup file is corrupted: %s"
|
||||
msgstr "El archivo de copia de seguridad está dañado: %s"
|
||||
|
||||
msgid "Error reading backup: %s"
|
||||
msgstr "Error al leer la copia de seguridad: %s"
|
||||
|
||||
msgid "Restore backup .bak"
|
||||
msgstr "Restaurar copia .bak"
|
||||
|
||||
msgid "Change port state"
|
||||
msgstr "Cambiar estado del puerto"
|
||||
|
||||
msgid "Enable this port"
|
||||
msgstr "Habilitar este puerto"
|
||||
|
||||
msgid "Enable port"
|
||||
msgstr "Habilitar puerto"
|
||||
|
||||
msgid "Disable this port"
|
||||
msgstr "Deshabilitar este puerto"
|
||||
|
||||
msgid "Disable port"
|
||||
msgstr "Deshabilitar puerto"
|
||||
|
||||
msgid "Down"
|
||||
msgstr "caído"
|
||||
|
||||
msgid "Disabled"
|
||||
msgstr "deshabilitado"
|
||||
|
||||
msgid "Idle"
|
||||
msgstr "inactivo"
|
||||
|
||||
msgid "Active"
|
||||
msgstr "activo"
|
||||
|
||||
msgid "Unknown"
|
||||
msgstr "desconocido"
|
||||
|
||||
msgid "No config file to backup"
|
||||
msgstr "No hay archivo de configuración para respaldar"
|
||||
|
||||
msgid "Config file is corrupted, cannot create backup"
|
||||
msgstr "El archivo de configuración está dañado, no se puede crear la copia de seguridad"
|
||||
|
||||
msgid "Backup file created: %s"
|
||||
msgstr "Archivo de copia de seguridad creado: %s"
|
||||
|
||||
msgid "Backup write verification failed!"
|
||||
msgstr "¡Falló la verificación de escritura de la copia de seguridad!"
|
||||
|
||||
msgid "Backup creation failed: %s"
|
||||
msgstr "Fallo al crear la copia de seguridad: %s"
|
||||
|
||||
msgid "Error reading config: %s"
|
||||
msgstr "Error al leer la configuración: %s"
|
||||
|
||||
msgid "Create backup .bak"
|
||||
msgstr "Crear copia .bak"
|
||||
@@ -1,175 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Language-Team: Rafał Wabik (IceG)\n"
|
||||
"Language: fr\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
||||
|
||||
msgid "Edit Port Label"
|
||||
msgstr "Modifier l'étiquette du port"
|
||||
|
||||
msgid "Enter new label for this port:"
|
||||
msgstr "Entrez une nouvelle étiquette pour ce port :"
|
||||
|
||||
msgid "Device"
|
||||
msgstr "Périphérique"
|
||||
|
||||
msgid "Original label"
|
||||
msgstr "Étiquette d'origine"
|
||||
|
||||
msgid "Restore Original"
|
||||
msgstr "Restaurer l'original"
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr "Annuler"
|
||||
|
||||
msgid "Save"
|
||||
msgstr "Enregistrer"
|
||||
|
||||
msgid "Port configuration saved successfully"
|
||||
msgstr "Configuration du port enregistrée avec succès"
|
||||
|
||||
msgid "Port order saved"
|
||||
msgstr "Ordre des ports enregistré"
|
||||
|
||||
msgid "Click to edit label"
|
||||
msgstr "Cliquez pour modifier l'étiquette"
|
||||
|
||||
msgid "Hold to drag and reorder"
|
||||
msgstr "Maintenez enfoncé pour faire glisser et réorganiser"
|
||||
|
||||
msgid "Label max 9 chars, description max 50 chars."
|
||||
msgstr "Étiquette max. 9 caractères, description max. 50 caractères."
|
||||
|
||||
msgid "Enter description (optional):"
|
||||
msgstr "Entrez la description (facultatif) :"
|
||||
|
||||
msgid "Optional description"
|
||||
msgstr "Description facultative"
|
||||
|
||||
msgid "User settings are saved to the /etc/user_defined_ports.json file."
|
||||
msgstr "Les paramètres utilisateur sont enregistrés dans le fichier /etc/user_defined_ports.json."
|
||||
|
||||
msgid "Configuration file downloaded"
|
||||
msgstr "Fichier de configuration téléchargé"
|
||||
|
||||
msgid "Configuration file not found"
|
||||
msgstr "Fichier de configuration introuvable"
|
||||
|
||||
msgid "Download error: %s"
|
||||
msgstr "Erreur de téléchargement : %s"
|
||||
|
||||
msgid "Invalid configuration format"
|
||||
msgstr "Format de configuration non valide"
|
||||
|
||||
msgid "Restore configuration"
|
||||
msgstr "Restaurer la configuration"
|
||||
|
||||
msgid "This will overwrite current ports configuration. Continue?"
|
||||
msgstr "Cela écrasera la configuration actuelle des ports. Continuer ?"
|
||||
|
||||
msgid "Configuration restored successfully. Reloading..."
|
||||
msgstr "Configuration restaurée avec succès. Rechargement..."
|
||||
|
||||
msgid "File restore failed: %s"
|
||||
msgstr "Échec de la restauration du fichier : %s"
|
||||
|
||||
msgid "Save .json file"
|
||||
msgstr "Enregistrer le fichier .json"
|
||||
|
||||
msgid "Upload .json file"
|
||||
msgstr "Téléverser le fichier .json"
|
||||
|
||||
msgid "Cannot save empty configuration"
|
||||
msgstr "Impossible d'enregistrer une configuration vide"
|
||||
|
||||
msgid "Cannot save port configuration. "
|
||||
msgstr "Impossible d'enregistrer la configuration des ports. "
|
||||
|
||||
msgid "Directory /etc may be read-only or insufficient permissions. "
|
||||
msgstr "Le répertoire /etc est peut-être en lecture seule ou les permissions sont insuffisantes. "
|
||||
|
||||
msgid "Try running: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
msgstr "Essayez d'exécuter : chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
|
||||
msgid "Save Error"
|
||||
msgstr "Erreur d'enregistrement"
|
||||
|
||||
msgid "Original error: %s"
|
||||
msgstr "Erreur d'origine : %s"
|
||||
|
||||
msgid "Restore from backup"
|
||||
msgstr "Restaurer à partir de la sauvegarde"
|
||||
|
||||
msgid "Restore configuration from backup file? This will overwrite current settings."
|
||||
msgstr "Restaurer la configuration à partir du fichier de sauvegarde ? Cela écrasera les paramètres actuels."
|
||||
|
||||
msgid "Backup contains:"
|
||||
msgstr "La sauvegarde contient :"
|
||||
|
||||
msgid "Configuration restored from backup. Reloading..."
|
||||
msgstr "Configuration restaurée à partir de la sauvegarde. Rechargement..."
|
||||
|
||||
msgid "Restore failed: %s"
|
||||
msgstr "Échec de la restauration : %s"
|
||||
|
||||
msgid "Backup file is corrupted: %s"
|
||||
msgstr "Le fichier de sauvegarde est corrompu : %s"
|
||||
|
||||
msgid "Error reading backup: %s"
|
||||
msgstr "Erreur de lecture de la sauvegarde : %s"
|
||||
|
||||
msgid "Restore backup .bak"
|
||||
msgstr "Restaurer la sauvegarde .bak"
|
||||
|
||||
msgid "Change port state"
|
||||
msgstr "Changer l'état du port"
|
||||
|
||||
msgid "Enable this port"
|
||||
msgstr "Activer ce port"
|
||||
|
||||
msgid "Enable port"
|
||||
msgstr "Activer le port"
|
||||
|
||||
msgid "Disable this port"
|
||||
msgstr "Désactiver ce port"
|
||||
|
||||
msgid "Disable port"
|
||||
msgstr "Désactiver le port"
|
||||
|
||||
msgid "Down"
|
||||
msgstr "inactif"
|
||||
|
||||
msgid "Disabled"
|
||||
msgstr "désactivé"
|
||||
|
||||
msgid "Idle"
|
||||
msgstr "inactif"
|
||||
|
||||
msgid "Active"
|
||||
msgstr "actif"
|
||||
|
||||
msgid "Unknown"
|
||||
msgstr "inconnu"
|
||||
|
||||
msgid "No config file to backup"
|
||||
msgstr "Aucun fichier de configuration à sauvegarder"
|
||||
|
||||
msgid "Config file is corrupted, cannot create backup"
|
||||
msgstr "Le fichier de configuration est corrompu, impossible de créer une sauvegarde"
|
||||
|
||||
msgid "Backup file created: %s"
|
||||
msgstr "Fichier de sauvegarde créé : %s"
|
||||
|
||||
msgid "Backup write verification failed!"
|
||||
msgstr "Échec de la vérification de l'écriture de la sauvegarde !"
|
||||
|
||||
msgid "Backup creation failed: %s"
|
||||
msgstr "Échec de la création de la sauvegarde : %s"
|
||||
|
||||
msgid "Error reading config: %s"
|
||||
msgstr "Erreur lors de la lecture de la configuration : %s"
|
||||
|
||||
msgid "Create backup .bak"
|
||||
msgstr "Créer une sauvegarde .bak"
|
||||
@@ -1,122 +0,0 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||
|
||||
msgid "Edit Port Label"
|
||||
msgstr "Edit Label Port"
|
||||
|
||||
msgid "Enter new label for this port:"
|
||||
msgstr "Masukkan label baru untuk port ini:"
|
||||
|
||||
msgid "Device"
|
||||
msgstr "Perangkat"
|
||||
|
||||
msgid "Original label"
|
||||
msgstr "Label asli"
|
||||
|
||||
msgid "Restore Original"
|
||||
msgstr "Pulihkan Asli"
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr "Batal"
|
||||
|
||||
msgid "Save"
|
||||
msgstr "Simpan"
|
||||
|
||||
msgid "Port configuration saved successfully"
|
||||
msgstr "Konfigurasi port berhasil disimpan"
|
||||
|
||||
msgid "Port order saved"
|
||||
msgstr "Urutan port tersimpan"
|
||||
|
||||
msgid "Click to edit label"
|
||||
msgstr "Klik untuk mengedit label"
|
||||
|
||||
msgid "Hold to drag and reorder"
|
||||
msgstr "Tahan untuk menyeret dan mengurutkan ulang"
|
||||
|
||||
msgid "Label max 9 chars, description max 50 chars."
|
||||
msgstr "Label maks. 9 karakter, deskripsi maks. 50 karakter."
|
||||
|
||||
msgid "Enter description (optional):"
|
||||
msgstr "Masukkan deskripsi (opsional):"
|
||||
|
||||
msgid "Optional description"
|
||||
msgstr "Deskripsi opsional"
|
||||
|
||||
msgid "User settings are saved to the /etc/user_defined_ports.json file."
|
||||
msgstr "Pengaturan pengguna disimpan ke file /etc/user_defined_ports.json."
|
||||
|
||||
msgid "Configuration file downloaded"
|
||||
msgstr "File konfigurasi berhasil diunduh"
|
||||
|
||||
msgid "Configuration file not found"
|
||||
msgstr "File konfigurasi tidak ditemukan"
|
||||
|
||||
msgid "Download error: %s"
|
||||
msgstr "Kesalahan unduh: %s"
|
||||
|
||||
msgid "Invalid configuration format"
|
||||
msgstr "Format konfigurasi tidak valid"
|
||||
|
||||
msgid "Restore configuration"
|
||||
msgstr "Pulihkan konfigurasi"
|
||||
|
||||
msgid "This will overwrite current ports configuration. Continue?"
|
||||
msgstr "Ini akan menimpa konfigurasi port saat ini. Lanjutkan?"
|
||||
|
||||
msgid "Configuration restored successfully. Reloading..."
|
||||
msgstr "Konfigurasi berhasil dipulihkan. Memuat ulang..."
|
||||
|
||||
msgid "File restore failed: %s"
|
||||
msgstr "Pemulihan file gagal: %s"
|
||||
|
||||
msgid "Save .json file"
|
||||
msgstr "Simpan file .json"
|
||||
|
||||
msgid "Upload .json file"
|
||||
msgstr "Unggah file .json"
|
||||
|
||||
msgid "Cannot save empty configuration"
|
||||
msgstr "Tidak dapat menyimpan konfigurasi kosong"
|
||||
|
||||
msgid "Cannot save port configuration. "
|
||||
msgstr "Tidak dapat menyimpan konfigurasi port. "
|
||||
|
||||
msgid "Directory /etc may be read-only or insufficient permissions. "
|
||||
msgstr "Direktori /etc mungkin hanya-baca atau izin tidak mencukupi. "
|
||||
|
||||
msgid "Try running: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
msgstr "Coba jalankan: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
|
||||
msgid "Save Error"
|
||||
msgstr "Kesalahan Penyimpanan"
|
||||
|
||||
msgid "Original error: %s"
|
||||
msgstr "Kesalahan asli: %s"
|
||||
|
||||
msgid "Restore from backup"
|
||||
msgstr "Pulihkan dari cadangan"
|
||||
|
||||
msgid "Restore configuration from backup file? This will overwrite current settings."
|
||||
msgstr "Pulihkan konfigurasi dari file cadangan? Ini akan menimpa pengaturan saat ini."
|
||||
|
||||
msgid "Backup contains:"
|
||||
msgstr "Cadangan berisi:"
|
||||
|
||||
msgid "Configuration restored from backup. Reloading..."
|
||||
msgstr "Konfigurasi dipulihkan dari cadangan. Memuat ulang..."
|
||||
|
||||
msgid "Restore failed: %s"
|
||||
msgstr "Pemulihan gagal: %s"
|
||||
|
||||
msgid "Backup file is corrupted: %s"
|
||||
msgstr "File cadangan rusak: %s"
|
||||
|
||||
msgid "Error reading backup: %s"
|
||||
msgstr "Kesalahan membaca cadangan: %s"
|
||||
|
||||
msgid "Restore backup .bak"
|
||||
msgstr "Pulihkan cadangan .bak"
|
||||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -1,176 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Language-Team: Rafał Wabik (IceG)\n"
|
||||
"Language: lt\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
|
||||
"(n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||
|
||||
msgid "Edit Port Label"
|
||||
msgstr "Modifica etichetta porta"
|
||||
|
||||
msgid "Enter new label for this port:"
|
||||
msgstr "Inserisci una nuova etichetta per questa porta:"
|
||||
|
||||
msgid "Device"
|
||||
msgstr "Dispositivo"
|
||||
|
||||
msgid "Original label"
|
||||
msgstr "Etichetta originale"
|
||||
|
||||
msgid "Restore Original"
|
||||
msgstr "Ripristina originale"
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr "Annulla"
|
||||
|
||||
msgid "Save"
|
||||
msgstr "Salva"
|
||||
|
||||
msgid "Port configuration saved successfully"
|
||||
msgstr "Configurazione della porta salvata con successo"
|
||||
|
||||
msgid "Port order saved"
|
||||
msgstr "Ordine delle porte salvato"
|
||||
|
||||
msgid "Click to edit label"
|
||||
msgstr "Fai clic per modificare l'etichetta"
|
||||
|
||||
msgid "Hold to drag and reorder"
|
||||
msgstr "Tieni premuto per trascinare e riordinare"
|
||||
|
||||
msgid "Label max 9 chars, description max 50 chars."
|
||||
msgstr "Etichetta max 9 caratteri, descrizione max 50 caratteri."
|
||||
|
||||
msgid "Enter description (optional):"
|
||||
msgstr "Inserisci descrizione (facoltativo):"
|
||||
|
||||
msgid "Optional description"
|
||||
msgstr "Descrizione facoltativa"
|
||||
|
||||
msgid "User settings are saved to the /etc/user_defined_ports.json file."
|
||||
msgstr "Le impostazioni utente vengono salvate nel file /etc/user_defined_ports.json."
|
||||
|
||||
msgid "Configuration file downloaded"
|
||||
msgstr "File di configurazione scaricato"
|
||||
|
||||
msgid "Configuration file not found"
|
||||
msgstr "File di configurazione non trovato"
|
||||
|
||||
msgid "Download error: %s"
|
||||
msgstr "Errore di download: %s"
|
||||
|
||||
msgid "Invalid configuration format"
|
||||
msgstr "Formato di configurazione non valido"
|
||||
|
||||
msgid "Restore configuration"
|
||||
msgstr "Ripristina configurazione"
|
||||
|
||||
msgid "This will overwrite current ports configuration. Continue?"
|
||||
msgstr "Questo sovrascriverà la configurazione attuale delle porte. Continuare?"
|
||||
|
||||
msgid "Configuration restored successfully. Reloading..."
|
||||
msgstr "Configurazione ripristinata con successo. Ricaricamento..."
|
||||
|
||||
msgid "File restore failed: %s"
|
||||
msgstr "Ripristino del file non riuscito: %s"
|
||||
|
||||
msgid "Save .json file"
|
||||
msgstr "Salva file .json"
|
||||
|
||||
msgid "Upload .json file"
|
||||
msgstr "Carica file .json"
|
||||
|
||||
msgid "Cannot save empty configuration"
|
||||
msgstr "Impossibile salvare una configurazione vuota"
|
||||
|
||||
msgid "Cannot save port configuration. "
|
||||
msgstr "Impossibile salvare la configurazione delle porte. "
|
||||
|
||||
msgid "Directory /etc may be read-only or insufficient permissions. "
|
||||
msgstr "La directory /etc potrebbe essere in sola lettura o avere permessi insufficienti. "
|
||||
|
||||
msgid "Try running: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
msgstr "Prova a eseguire: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
|
||||
msgid "Save Error"
|
||||
msgstr "Errore di salvataggio"
|
||||
|
||||
msgid "Original error: %s"
|
||||
msgstr "Errore originale: %s"
|
||||
|
||||
msgid "Restore from backup"
|
||||
msgstr "Ripristina dal backup"
|
||||
|
||||
msgid "Restore configuration from backup file? This will overwrite current settings."
|
||||
msgstr "Ripristinare la configurazione dal file di backup? Questo sovrascriverà le impostazioni correnti."
|
||||
|
||||
msgid "Backup contains:"
|
||||
msgstr "Il backup contiene:"
|
||||
|
||||
msgid "Configuration restored from backup. Reloading..."
|
||||
msgstr "Configurazione ripristinata dal backup. Ricaricamento..."
|
||||
|
||||
msgid "Restore failed: %s"
|
||||
msgstr "Ripristino non riuscito: %s"
|
||||
|
||||
msgid "Backup file is corrupted: %s"
|
||||
msgstr "Il file di backup è danneggiato: %s"
|
||||
|
||||
msgid "Error reading backup: %s"
|
||||
msgstr "Errore durante la lettura del backup: %s"
|
||||
|
||||
msgid "Restore backup .bak"
|
||||
msgstr "Ripristina backup .bak"
|
||||
|
||||
msgid "Change port state"
|
||||
msgstr "Cambia stato porta"
|
||||
|
||||
msgid "Enable this port"
|
||||
msgstr "Abilita questa porta"
|
||||
|
||||
msgid "Enable port"
|
||||
msgstr "Abilita porta"
|
||||
|
||||
msgid "Disable this port"
|
||||
msgstr "Disabilita questa porta"
|
||||
|
||||
msgid "Disable port"
|
||||
msgstr "Disabilita porta"
|
||||
|
||||
msgid "Down"
|
||||
msgstr "inattiva"
|
||||
|
||||
msgid "Disabled"
|
||||
msgstr "disabilitata"
|
||||
|
||||
msgid "Idle"
|
||||
msgstr "inattiva"
|
||||
|
||||
msgid "Active"
|
||||
msgstr "attiva"
|
||||
|
||||
msgid "Unknown"
|
||||
msgstr "sconosciuto"
|
||||
|
||||
msgid "No config file to backup"
|
||||
msgstr "Nessun file di configurazione da salvare"
|
||||
|
||||
msgid "Config file is corrupted, cannot create backup"
|
||||
msgstr "Il file di configurazione è corrotto, impossibile creare il backup"
|
||||
|
||||
msgid "Backup file created: %s"
|
||||
msgstr "File di backup creato: %s"
|
||||
|
||||
msgid "Backup write verification failed!"
|
||||
msgstr "Verifica della scrittura del backup non riuscita!"
|
||||
|
||||
msgid "Backup creation failed: %s"
|
||||
msgstr "Creazione del backup non riuscita: %s"
|
||||
|
||||
msgid "Error reading config: %s"
|
||||
msgstr "Errore durante la lettura della configurazione: %s"
|
||||
|
||||
msgid "Create backup .bak"
|
||||
msgstr "Crea backup .bak"
|
||||
@@ -1,174 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Language: ja\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
msgid "Edit Port Label"
|
||||
msgstr "ポートラベルを編集"
|
||||
|
||||
msgid "Enter new label for this port:"
|
||||
msgstr "このポートの新しいラベルを入力してください:"
|
||||
|
||||
msgid "Device"
|
||||
msgstr "デバイス"
|
||||
|
||||
msgid "Original label"
|
||||
msgstr "元のラベル"
|
||||
|
||||
msgid "Restore Original"
|
||||
msgstr "元に戻す"
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr "キャンセル"
|
||||
|
||||
msgid "Save"
|
||||
msgstr "保存"
|
||||
|
||||
msgid "Port configuration saved successfully"
|
||||
msgstr "ポート設定が正常に保存されました"
|
||||
|
||||
msgid "Port order saved"
|
||||
msgstr "ポート順序が保存されました"
|
||||
|
||||
msgid "Click to edit label"
|
||||
msgstr "クリックしてラベルを編集"
|
||||
|
||||
msgid "Hold to drag and reorder"
|
||||
msgstr "ドラッグして順序を変更するには長押し"
|
||||
|
||||
msgid "Label max 9 chars, description max 50 chars."
|
||||
msgstr "ラベルは最大9文字、説明は最大50文字です。"
|
||||
|
||||
msgid "Enter description (optional):"
|
||||
msgstr "説明を入力してください (オプション):"
|
||||
|
||||
msgid "Optional description"
|
||||
msgstr "オプションの説明"
|
||||
|
||||
msgid "User settings are saved to the /etc/user_defined_ports.json file."
|
||||
msgstr "ユーザー設定は /etc/user_defined_ports.json ファイルに保存されます。"
|
||||
|
||||
msgid "Configuration file downloaded"
|
||||
msgstr "設定ファイルがダウンロードされました"
|
||||
|
||||
msgid "Configuration file not found"
|
||||
msgstr "設定ファイルが見つかりません"
|
||||
|
||||
msgid "Download error: %s"
|
||||
msgstr "ダウンロードエラー: %s"
|
||||
|
||||
msgid "Invalid configuration format"
|
||||
msgstr "無効な設定形式"
|
||||
|
||||
msgid "Restore configuration"
|
||||
msgstr "設定を復元"
|
||||
|
||||
msgid "This will overwrite current ports configuration. Continue?"
|
||||
msgstr "これにより現在のポート設定が上書きされます。続行しますか?"
|
||||
|
||||
msgid "Configuration restored successfully. Reloading..."
|
||||
msgstr "設定が正常に復元されました。リロード中..."
|
||||
|
||||
msgid "File restore failed: %s"
|
||||
msgstr "ファイルの復元に失敗しました: %s"
|
||||
|
||||
msgid "Save .json file"
|
||||
msgstr ".json ファイルを保存"
|
||||
|
||||
msgid "Upload .json file"
|
||||
msgstr ".json ファイルをアップロード"
|
||||
|
||||
msgid "Cannot save empty configuration"
|
||||
msgstr "空の設定を保存できません"
|
||||
|
||||
msgid "Cannot save port configuration. "
|
||||
msgstr "ポート設定を保存できません。"
|
||||
|
||||
msgid "Directory /etc may be read-only or insufficient permissions. "
|
||||
msgstr "ディレクトリ /etc は読み取り専用または権限不足の可能性があります。"
|
||||
|
||||
msgid "Try running: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
msgstr "次のコマンドを実行してみてください: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
|
||||
msgid "Save Error"
|
||||
msgstr "保存エラー"
|
||||
|
||||
msgid "Original error: %s"
|
||||
msgstr "元のエラー: %s"
|
||||
|
||||
msgid "Restore from backup"
|
||||
msgstr "バックアップから復元"
|
||||
|
||||
msgid "Restore configuration from backup file? This will overwrite current settings."
|
||||
msgstr "バックアップファイルから設定を復元しますか? これにより現在の設定が上書きされます。"
|
||||
|
||||
msgid "Backup contains:"
|
||||
msgstr "バックアップに含まれるもの:"
|
||||
|
||||
msgid "Configuration restored from backup. Reloading..."
|
||||
msgstr "バックアップから設定が復元されました。リロード中..."
|
||||
|
||||
msgid "Restore failed: %s"
|
||||
msgstr "復元に失敗しました: %s"
|
||||
|
||||
msgid "Backup file is corrupted: %s"
|
||||
msgstr "バックアップファイルが破損しています: %s"
|
||||
|
||||
msgid "Error reading backup: %s"
|
||||
msgstr "バックアップの読み込みエラー: %s"
|
||||
|
||||
msgid "Restore backup .bak"
|
||||
msgstr "バックアップ .bak を復元"
|
||||
|
||||
msgid "Change port state"
|
||||
msgstr "ポート状態を変更"
|
||||
|
||||
msgid "Enable this port"
|
||||
msgstr "このポートを有効にする"
|
||||
|
||||
msgid "Enable port"
|
||||
msgstr "ポートを有効化"
|
||||
|
||||
msgid "Disable this port"
|
||||
msgstr "このポートを無効にする"
|
||||
|
||||
msgid "Disable port"
|
||||
msgstr "ポートを無効化"
|
||||
|
||||
msgid "Down"
|
||||
msgstr "ダウン"
|
||||
|
||||
msgid "Disabled"
|
||||
msgstr "無効"
|
||||
|
||||
msgid "Idle"
|
||||
msgstr "アイドル"
|
||||
|
||||
msgid "Active"
|
||||
msgstr "アクティブ"
|
||||
|
||||
msgid "Unknown"
|
||||
msgstr "不明"
|
||||
|
||||
msgid "No config file to backup"
|
||||
msgstr "バックアップする設定ファイルがありません"
|
||||
|
||||
msgid "Config file is corrupted, cannot create backup"
|
||||
msgstr "設定ファイルが破損しているため、バックアップを作成できません"
|
||||
|
||||
msgid "Backup file created: %s"
|
||||
msgstr "バックアップファイルが作成されました: %s"
|
||||
|
||||
msgid "Backup write verification failed!"
|
||||
msgstr "バックアップ書き込み検証に失敗しました!"
|
||||
|
||||
msgid "Backup creation failed: %s"
|
||||
msgstr "バックアップの作成に失敗しました: %s"
|
||||
|
||||
msgid "Error reading config: %s"
|
||||
msgstr "設定の読み込みエラー: %s"
|
||||
|
||||
msgid "Create backup .bak"
|
||||
msgstr "バックアップ .bak を作成"
|
||||
@@ -1,174 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Language: ko\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
msgid "Edit Port Label"
|
||||
msgstr "포트 레이블 편집"
|
||||
|
||||
msgid "Enter new label for this port:"
|
||||
msgstr "이 포트의 새 레이블을 입력하세요:"
|
||||
|
||||
msgid "Device"
|
||||
msgstr "장치"
|
||||
|
||||
msgid "Original label"
|
||||
msgstr "원본 레이블"
|
||||
|
||||
msgid "Restore Original"
|
||||
msgstr "원본 복원"
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr "취소"
|
||||
|
||||
msgid "Save"
|
||||
msgstr "저장"
|
||||
|
||||
msgid "Port configuration saved successfully"
|
||||
msgstr "포트 설정이 성공적으로 저장되었습니다"
|
||||
|
||||
msgid "Port order saved"
|
||||
msgstr "포트 순서가 저장되었습니다"
|
||||
|
||||
msgid "Click to edit label"
|
||||
msgstr "레이블을 편집하려면 클릭"
|
||||
|
||||
msgid "Hold to drag and reorder"
|
||||
msgstr "드래그하여 순서를 변경하려면 누르고 있기"
|
||||
|
||||
msgid "Label max 9 chars, description max 50 chars."
|
||||
msgstr "레이블 최대 9자, 설명 최대 50자."
|
||||
|
||||
msgid "Enter description (optional):"
|
||||
msgstr "설명을 입력하세요 (선택 사항):"
|
||||
|
||||
msgid "Optional description"
|
||||
msgstr "선택 사항 설명"
|
||||
|
||||
msgid "User settings are saved to the /etc/user_defined_ports.json file."
|
||||
msgstr "사용자 설정은 /etc/user_defined_ports.json 파일에 저장됩니다."
|
||||
|
||||
msgid "Configuration file downloaded"
|
||||
msgstr "설정 파일이 다운로드되었습니다"
|
||||
|
||||
msgid "Configuration file not found"
|
||||
msgstr "설정 파일을 찾을 수 없습니다"
|
||||
|
||||
msgid "Download error: %s"
|
||||
msgstr "다운로드 오류: %s"
|
||||
|
||||
msgid "Invalid configuration format"
|
||||
msgstr "잘못된 설정 형식"
|
||||
|
||||
msgid "Restore configuration"
|
||||
msgstr "설정 복원"
|
||||
|
||||
msgid "This will overwrite current ports configuration. Continue?"
|
||||
msgstr "이 작업은 현재 포트 설정을 덮어씁니다. 계속하시겠습니까?"
|
||||
|
||||
msgid "Configuration restored successfully. Reloading..."
|
||||
msgstr "설정이 성공적으로 복원되었습니다. 다시 로드 중..."
|
||||
|
||||
msgid "File restore failed: %s"
|
||||
msgstr "파일 복원 실패: %s"
|
||||
|
||||
msgid "Save .json file"
|
||||
msgstr ".json 파일 저장"
|
||||
|
||||
msgid "Upload .json file"
|
||||
msgstr ".json 파일 업로드"
|
||||
|
||||
msgid "Cannot save empty configuration"
|
||||
msgstr "빈 설정을 저장할 수 없습니다"
|
||||
|
||||
msgid "Cannot save port configuration. "
|
||||
msgstr "포트 설정을 저장할 수 없습니다. "
|
||||
|
||||
msgid "Directory /etc may be read-only or insufficient permissions. "
|
||||
msgstr "/etc 디렉토리가 읽기 전용이거나 권한이 부족할 수 있습니다. "
|
||||
|
||||
msgid "Try running: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
msgstr "다음 명령어를 실행해보세요: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
|
||||
msgid "Save Error"
|
||||
msgstr "저장 오류"
|
||||
|
||||
msgid "Original error: %s"
|
||||
msgstr "원본 오류: %s"
|
||||
|
||||
msgid "Restore from backup"
|
||||
msgstr "백업에서 복원"
|
||||
|
||||
msgid "Restore configuration from backup file? This will overwrite current settings."
|
||||
msgstr "백업 파일에서 설정을 복원하시겠습니까? 이 작업은 현재 설정을 덮어씁니다."
|
||||
|
||||
msgid "Backup contains:"
|
||||
msgstr "백업에 포함됨:"
|
||||
|
||||
msgid "Configuration restored from backup. Reloading..."
|
||||
msgstr "백업에서 설정이 복원되었습니다. 다시 로드 중..."
|
||||
|
||||
msgid "Restore failed: %s"
|
||||
msgstr "복원 실패: %s"
|
||||
|
||||
msgid "Backup file is corrupted: %s"
|
||||
msgstr "백업 파일이 손상됨: %s"
|
||||
|
||||
msgid "Error reading backup: %s"
|
||||
msgstr "백업 읽기 오류: %s"
|
||||
|
||||
msgid "Restore backup .bak"
|
||||
msgstr "백업 .bak 복원"
|
||||
|
||||
msgid "Change port state"
|
||||
msgstr "포트 상태 변경"
|
||||
|
||||
msgid "Enable this port"
|
||||
msgstr "이 포트 활성화"
|
||||
|
||||
msgid "Enable port"
|
||||
msgstr "포트 활성화"
|
||||
|
||||
msgid "Disable this port"
|
||||
msgstr "이 포트 비활성화"
|
||||
|
||||
msgid "Disable port"
|
||||
msgstr "포트 비활성화"
|
||||
|
||||
msgid "Down"
|
||||
msgstr "다운"
|
||||
|
||||
msgid "Disabled"
|
||||
msgstr "비활성화됨"
|
||||
|
||||
msgid "Idle"
|
||||
msgstr "유휴 상태"
|
||||
|
||||
msgid "Active"
|
||||
msgstr "활성"
|
||||
|
||||
msgid "Unknown"
|
||||
msgstr "알 수 없음"
|
||||
|
||||
msgid "No config file to backup"
|
||||
msgstr "백업할 설정 파일이 없습니다"
|
||||
|
||||
msgid "Config file is corrupted, cannot create backup"
|
||||
msgstr "설정 파일이 손상되어 백업을 만들 수 없습니다"
|
||||
|
||||
msgid "Backup file created: %s"
|
||||
msgstr "백업 파일이 생성되었습니다: %s"
|
||||
|
||||
msgid "Backup write verification failed!"
|
||||
msgstr "백업 쓰기 검증 실패!"
|
||||
|
||||
msgid "Backup creation failed: %s"
|
||||
msgstr "백업 생성 실패: %s"
|
||||
|
||||
msgid "Error reading config: %s"
|
||||
msgstr "설정 읽기 오류: %s"
|
||||
|
||||
msgid "Create backup .bak"
|
||||
msgstr "백업 .bak 생성"
|
||||
@@ -1,175 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Language-Team: Rafał Wabik (IceG)\n"
|
||||
"Language: nl\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
|
||||
msgid "Edit Port Label"
|
||||
msgstr "Poortlabel bewerken"
|
||||
|
||||
msgid "Enter new label for this port:"
|
||||
msgstr "Voer nieuw label in voor deze poort:"
|
||||
|
||||
msgid "Device"
|
||||
msgstr "Apparaat"
|
||||
|
||||
msgid "Original label"
|
||||
msgstr "Oorspronkelijk label"
|
||||
|
||||
msgid "Restore Original"
|
||||
msgstr "Oorspronkelijke herstellen"
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr "Annuleren"
|
||||
|
||||
msgid "Save"
|
||||
msgstr "Opslaan"
|
||||
|
||||
msgid "Port configuration saved successfully"
|
||||
msgstr "Poortconfiguratie succesvol opgeslagen"
|
||||
|
||||
msgid "Port order saved"
|
||||
msgstr "Poortvolgorde opgeslagen"
|
||||
|
||||
msgid "Click to edit label"
|
||||
msgstr "Klik om label te bewerken"
|
||||
|
||||
msgid "Hold to drag and reorder"
|
||||
msgstr "Vasthouden om te slepen en de volgorde te wijzigen"
|
||||
|
||||
msgid "Label max 9 chars, description max 50 chars."
|
||||
msgstr "Label max. 9 tekens, beschrijving max. 50 tekens."
|
||||
|
||||
msgid "Enter description (optional):"
|
||||
msgstr "Voer beschrijving in (optioneel):"
|
||||
|
||||
msgid "Optional description"
|
||||
msgstr "Optionele beschrijving"
|
||||
|
||||
msgid "User settings are saved to the /etc/user_defined_ports.json file."
|
||||
msgstr "Gebruikersinstellingen worden opgeslagen in het bestand /etc/user_defined_ports.json."
|
||||
|
||||
msgid "Configuration file downloaded"
|
||||
msgstr "Configuratiebestand gedownload"
|
||||
|
||||
msgid "Configuration file not found"
|
||||
msgstr "Configuratiebestand niet gevonden"
|
||||
|
||||
msgid "Download error: %s"
|
||||
msgstr "Downloadfout: %s"
|
||||
|
||||
msgid "Invalid configuration format"
|
||||
msgstr "Ongeldig configuratieformaat"
|
||||
|
||||
msgid "Restore configuration"
|
||||
msgstr "Configuratie herstellen"
|
||||
|
||||
msgid "This will overwrite current ports configuration. Continue?"
|
||||
msgstr "Dit zal de huidige poortconfiguratie overschrijven. Doorgaan?"
|
||||
|
||||
msgid "Configuration restored successfully. Reloading..."
|
||||
msgstr "Configuratie succesvol hersteld. Herladen..."
|
||||
|
||||
msgid "File restore failed: %s"
|
||||
msgstr "Bestandsherstel mislukt: %s"
|
||||
|
||||
msgid "Save .json file"
|
||||
msgstr "JSON-bestand opslaan"
|
||||
|
||||
msgid "Upload .json file"
|
||||
msgstr "JSON-bestand uploaden"
|
||||
|
||||
msgid "Cannot save empty configuration"
|
||||
msgstr "Kan geen lege configuratie opslaan"
|
||||
|
||||
msgid "Cannot save port configuration. "
|
||||
msgstr "Kan poortconfiguratie niet opslaan. "
|
||||
|
||||
msgid "Directory /etc may be read-only or insufficient permissions. "
|
||||
msgstr "De map /etc is mogelijk alleen-lezen of heeft onvoldoende rechten. "
|
||||
|
||||
msgid "Try running: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
msgstr "Probeer het volgende uit te voeren: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
|
||||
msgid "Save Error"
|
||||
msgstr "Opslagfout"
|
||||
|
||||
msgid "Original error: %s"
|
||||
msgstr "Oorspronkelijke fout: %s"
|
||||
|
||||
msgid "Restore from backup"
|
||||
msgstr "Herstellen van back-up"
|
||||
|
||||
msgid "Restore configuration from backup file? This will overwrite current settings."
|
||||
msgstr "Configuratie herstellen van back-upbestand? Dit zal de huidige instellingen overschrijven."
|
||||
|
||||
msgid "Backup contains:"
|
||||
msgstr "Back-up bevat:"
|
||||
|
||||
msgid "Configuration restored from backup. Reloading..."
|
||||
msgstr "Configuratie hersteld van back-up. Herladen..."
|
||||
|
||||
msgid "Restore failed: %s"
|
||||
msgstr "Herstel mislukt: %s"
|
||||
|
||||
msgid "Backup file is corrupted: %s"
|
||||
msgstr "Back-upbestand is beschadigd: %s"
|
||||
|
||||
msgid "Error reading backup: %s"
|
||||
msgstr "Fout bij lezen van back-up: %s"
|
||||
|
||||
msgid "Restore backup .bak"
|
||||
msgstr ".bak-back-up herstellen"
|
||||
|
||||
msgid "Change port state"
|
||||
msgstr "Poortstatus wijzigen"
|
||||
|
||||
msgid "Enable this port"
|
||||
msgstr "Deze poort inschakelen"
|
||||
|
||||
msgid "Enable port"
|
||||
msgstr "Poort inschakelen"
|
||||
|
||||
msgid "Disable this port"
|
||||
msgstr "Deze poort uitschakelen"
|
||||
|
||||
msgid "Disable port"
|
||||
msgstr "Poort uitschakelen"
|
||||
|
||||
msgid "Down"
|
||||
msgstr "down"
|
||||
|
||||
msgid "Disabled"
|
||||
msgstr "uitgeschakeld"
|
||||
|
||||
msgid "Idle"
|
||||
msgstr "onactief"
|
||||
|
||||
msgid "Active"
|
||||
msgstr "actief"
|
||||
|
||||
msgid "Unknown"
|
||||
msgstr "onbekend"
|
||||
|
||||
msgid "No config file to backup"
|
||||
msgstr "Geen configuratiebestand om back-up van te maken"
|
||||
|
||||
msgid "Config file is corrupted, cannot create backup"
|
||||
msgstr "Configuratiebestand is beschadigd, kan geen back-up maken"
|
||||
|
||||
msgid "Backup file created: %s"
|
||||
msgstr "Back-upbestand aangemaakt: %s"
|
||||
|
||||
msgid "Backup write verification failed!"
|
||||
msgstr "Schrijfverificatie van back-up mislukt!"
|
||||
|
||||
msgid "Backup creation failed: %s"
|
||||
msgstr "Aanmaken van back-up mislukt: %s"
|
||||
|
||||
msgid "Error reading config: %s"
|
||||
msgstr "Fout bij lezen van configuratie: %s"
|
||||
|
||||
msgid "Create backup .bak"
|
||||
msgstr ".bak-back-up maken"
|
||||
@@ -1,170 +0,0 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||
|
||||
msgid "Edit Port Label"
|
||||
msgstr "Edytuj etykietę portu"
|
||||
|
||||
msgid "Enter new label for this port:"
|
||||
msgstr "Wprowadź nową etykietę dla tego portu:"
|
||||
|
||||
msgid "Device"
|
||||
msgstr "Urządzenie"
|
||||
|
||||
msgid "Original label"
|
||||
msgstr "Oryginalna etykieta"
|
||||
|
||||
msgid "Restore Original"
|
||||
msgstr "Przywróć oryginalną"
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr "Anuluj"
|
||||
|
||||
msgid "Save"
|
||||
msgstr "Zapisz"
|
||||
|
||||
msgid "Port configuration saved successfully"
|
||||
msgstr "Konfiguracja portu została poprawnie zapisana"
|
||||
|
||||
msgid "Port order saved"
|
||||
msgstr "Zapisano kolejność portu"
|
||||
|
||||
msgid "Click to edit label"
|
||||
msgstr "Kliknij aby edytować etykietę"
|
||||
|
||||
msgid "Hold to drag and reorder"
|
||||
msgstr "Przytrzymaj aby przeciągnąć i zmienić kolejność"
|
||||
|
||||
msgid "Label max 9 chars, description max 50 chars."
|
||||
msgstr "Etykieta to maksymalnie 9 znaków, limit dla opisu wynosi 50 znaków."
|
||||
|
||||
msgid "Enter description (optional):"
|
||||
msgstr "Dodaj opis (opcjonalnie):"
|
||||
|
||||
msgid "Optional description"
|
||||
msgstr "Opcjonalny opis portu"
|
||||
|
||||
msgid "User settings are saved to the /etc/user_defined_ports.json file."
|
||||
msgstr "Ustawienia użytkownika zapisywane są w pliku /etc/user_defined_ports.json."
|
||||
|
||||
msgid "Configuration file downloaded"
|
||||
msgstr "Pobrano plik z ustawieniami"
|
||||
|
||||
msgid "Configuration file not found"
|
||||
msgstr "Nie znaleziono pliku z ustawieniami"
|
||||
|
||||
msgid "Download error: %s"
|
||||
msgstr "Błąd pobierania: %s"
|
||||
|
||||
msgid "Invalid configuration format"
|
||||
msgstr "Niewłaściwy format pliku"
|
||||
|
||||
msgid "Restore configuration"
|
||||
msgstr "Przywracanie ustawień"
|
||||
|
||||
msgid "This will overwrite current ports configuration. Continue?"
|
||||
msgstr "Operacja nadpisze bieżącą konfigurację portów. Kontynuować?"
|
||||
|
||||
msgid "Configuration restored successfully. Reloading..."
|
||||
msgstr "Konfiguracja została pomyślnie przywrócona. Odświeżanie..."
|
||||
|
||||
msgid "File restore failed: %s"
|
||||
msgstr "Przywracanie pliku nie powiodło się: %s"
|
||||
|
||||
msgid "Save .json file"
|
||||
msgstr "Zapisz plik .json"
|
||||
|
||||
msgid "Upload .json file"
|
||||
msgstr "Załaduj plik .json"
|
||||
|
||||
msgid "Cannot save empty configuration"
|
||||
msgstr "Nie można zapisać pustej konfiguracji"
|
||||
|
||||
msgid "Cannot save port configuration. "
|
||||
msgstr "Nie można zapisać konfiguracji portów. "
|
||||
|
||||
msgid "Directory /etc may be read-only or insufficient permissions. "
|
||||
msgstr "Katalog /etc może być tylko do odczytu lub mieć niewystarczające uprawnienia. "
|
||||
|
||||
msgid "Try running: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
msgstr "Spróbuj uruchomić: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
|
||||
msgid "Save Error"
|
||||
msgstr "Błąd zapisu"
|
||||
|
||||
msgid "Original error: %s"
|
||||
msgstr "Oryginalny błąd: %s"
|
||||
|
||||
msgid "Restore from backup"
|
||||
msgstr "Przywróć z kopii zapasowej"
|
||||
|
||||
msgid "Restore configuration from backup file? This will overwrite current settings."
|
||||
msgstr "Przywrócić konfigurację z pliku kopii zapasowej? Spowoduje to nadpisanie bieżących ustawień."
|
||||
|
||||
msgid "Backup contains:"
|
||||
msgstr "Kopia zapasowa zawiera:"
|
||||
|
||||
msgid "Configuration restored from backup. Reloading..."
|
||||
msgstr "Konfiguracja przywrócona z kopii zapasowej. Odświeżanie..."
|
||||
|
||||
msgid "Restore failed: %s"
|
||||
msgstr "Przywracanie nie powiodło się: %s"
|
||||
|
||||
msgid "Backup file is corrupted: %s"
|
||||
msgstr "Plik kopii zapasowej jest uszkodzony: %s"
|
||||
|
||||
msgid "Error reading backup: %s"
|
||||
msgstr "Błąd odczytu kopii zapasowej: %s"
|
||||
|
||||
msgid "Restore backup .bak"
|
||||
msgstr "Przywróć kopię .bak"
|
||||
|
||||
msgid "Change port state"
|
||||
msgstr "Zmień stan portu"
|
||||
|
||||
msgid "Enable this port"
|
||||
msgstr "Włącz ten port"
|
||||
|
||||
msgid "Enable port"
|
||||
msgstr "Włącz port"
|
||||
|
||||
msgid "Disable this port"
|
||||
msgstr "Wyłącz ten port"
|
||||
|
||||
msgid "Disable port"
|
||||
msgstr "Wyłącz port"
|
||||
|
||||
msgid "Down"
|
||||
msgstr "nieaktywny"
|
||||
|
||||
msgid "Disabled"
|
||||
msgstr "wyłączony"
|
||||
|
||||
msgid "Idle"
|
||||
msgstr "bezczynny"
|
||||
|
||||
msgid "Active"
|
||||
msgstr "aktywny"
|
||||
|
||||
msgid "Unknown"
|
||||
msgstr "nieznany"
|
||||
|
||||
msgid "No config file to backup"
|
||||
msgstr "Brak pliku konfiguracji do utworzenia kopii zapasowej"
|
||||
|
||||
msgid "Config file is corrupted, cannot create backup"
|
||||
msgstr "Plik konfiguracji jest uszkodzony, nie można utworzyć kopii zapasowej"
|
||||
|
||||
msgid "Backup file created: %s"
|
||||
msgstr "Plik kopii zapasowej został utworzony: %s"
|
||||
|
||||
msgid "Backup write verification failed!"
|
||||
msgstr "Weryfikacja zapisu kopii zapasowej nie powiodła się!"
|
||||
|
||||
msgid "Backup creation failed: %s"
|
||||
msgstr "Tworzenie kopii zapasowej nie powiodło się: %s"
|
||||
|
||||
msgid "Error reading config: %s"
|
||||
msgstr "Błąd odczytu konfiguracji: %s"
|
||||
|
||||
msgid "Create backup .bak"
|
||||
msgstr "Utwórz kopię .bak"
|
||||
@@ -1,174 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Language: pt_BR\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
||||
|
||||
msgid "Edit Port Label"
|
||||
msgstr "Editar rótulo da porta"
|
||||
|
||||
msgid "Enter new label for this port:"
|
||||
msgstr "Digite um novo rótulo para esta porta:"
|
||||
|
||||
msgid "Device"
|
||||
msgstr "Dispositivo"
|
||||
|
||||
msgid "Original label"
|
||||
msgstr "Rótulo original"
|
||||
|
||||
msgid "Restore Original"
|
||||
msgstr "Restaurar original"
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr "Cancelar"
|
||||
|
||||
msgid "Save"
|
||||
msgstr "Salvar"
|
||||
|
||||
msgid "Port configuration saved successfully"
|
||||
msgstr "Configuração da porta salva com sucesso"
|
||||
|
||||
msgid "Port order saved"
|
||||
msgstr "Ordem das portas salva"
|
||||
|
||||
msgid "Click to edit label"
|
||||
msgstr "Clique para editar rótulo"
|
||||
|
||||
msgid "Hold to drag and reorder"
|
||||
msgstr "Segure para arrastar e reordenar"
|
||||
|
||||
msgid "Label max 9 chars, description max 50 chars."
|
||||
msgstr "Rótulo máximo de 9 caracteres, descrição máximo de 50 caracteres."
|
||||
|
||||
msgid "Enter description (optional):"
|
||||
msgstr "Digite descrição (opcional):"
|
||||
|
||||
msgid "Optional description"
|
||||
msgstr "Descrição opcional"
|
||||
|
||||
msgid "User settings are saved to the /etc/user_defined_ports.json file."
|
||||
msgstr "As configurações do usuário são salvas no arquivo /etc/user_defined_ports.json."
|
||||
|
||||
msgid "Configuration file downloaded"
|
||||
msgstr "Arquivo de configuração baixado"
|
||||
|
||||
msgid "Configuration file not found"
|
||||
msgstr "Arquivo de configuração não encontrado"
|
||||
|
||||
msgid "Download error: %s"
|
||||
msgstr "Erro de download: %s"
|
||||
|
||||
msgid "Invalid configuration format"
|
||||
msgstr "Formato de configuração inválido"
|
||||
|
||||
msgid "Restore configuration"
|
||||
msgstr "Restaurar configuração"
|
||||
|
||||
msgid "This will overwrite current ports configuration. Continue?"
|
||||
msgstr "Isso sobrescreverá a configuração atual das portas. Continuar?"
|
||||
|
||||
msgid "Configuration restored successfully. Reloading..."
|
||||
msgstr "Configuração restaurada com sucesso. Recarregando..."
|
||||
|
||||
msgid "File restore failed: %s"
|
||||
msgstr "Falha na restauração do arquivo: %s"
|
||||
|
||||
msgid "Save .json file"
|
||||
msgstr "Salvar arquivo .json"
|
||||
|
||||
msgid "Upload .json file"
|
||||
msgstr "Carregar arquivo .json"
|
||||
|
||||
msgid "Cannot save empty configuration"
|
||||
msgstr "Não é possível salvar uma configuração vazia"
|
||||
|
||||
msgid "Cannot save port configuration. "
|
||||
msgstr "Não é possível salvar a configuração da porta. "
|
||||
|
||||
msgid "Directory /etc may be read-only or insufficient permissions. "
|
||||
msgstr "O diretório /etc pode estar somente leitura ou ter permissões insuficientes. "
|
||||
|
||||
msgid "Try running: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
msgstr "Tente executar: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
|
||||
msgid "Save Error"
|
||||
msgstr "Erro ao salvar"
|
||||
|
||||
msgid "Original error: %s"
|
||||
msgstr "Erro original: %s"
|
||||
|
||||
msgid "Restore from backup"
|
||||
msgstr "Restaurar do backup"
|
||||
|
||||
msgid "Restore configuration from backup file? This will overwrite current settings."
|
||||
msgstr "Restaurar configuração do arquivo de backup? Isso sobrescreverá as configurações atuais."
|
||||
|
||||
msgid "Backup contains:"
|
||||
msgstr "Backup contém:"
|
||||
|
||||
msgid "Configuration restored from backup. Reloading..."
|
||||
msgstr "Configuração restaurada do backup. Recarregando..."
|
||||
|
||||
msgid "Restore failed: %s"
|
||||
msgstr "Falha na restauração: %s"
|
||||
|
||||
msgid "Backup file is corrupted: %s"
|
||||
msgstr "Arquivo de backup corrompido: %s"
|
||||
|
||||
msgid "Error reading backup: %s"
|
||||
msgstr "Erro ao ler backup: %s"
|
||||
|
||||
msgid "Restore backup .bak"
|
||||
msgstr "Restaurar backup .bak"
|
||||
|
||||
msgid "Change port state"
|
||||
msgstr "Alterar estado da porta"
|
||||
|
||||
msgid "Enable this port"
|
||||
msgstr "Ativar esta porta"
|
||||
|
||||
msgid "Enable port"
|
||||
msgstr "Ativar porta"
|
||||
|
||||
msgid "Disable this port"
|
||||
msgstr "Desativar esta porta"
|
||||
|
||||
msgid "Disable port"
|
||||
msgstr "Desativar porta"
|
||||
|
||||
msgid "Down"
|
||||
msgstr "Inativo"
|
||||
|
||||
msgid "Disabled"
|
||||
msgstr "Desativado"
|
||||
|
||||
msgid "Idle"
|
||||
msgstr "Ocioso"
|
||||
|
||||
msgid "Active"
|
||||
msgstr "Ativo"
|
||||
|
||||
msgid "Unknown"
|
||||
msgstr "Desconhecido"
|
||||
|
||||
msgid "No config file to backup"
|
||||
msgstr "Nenhum arquivo de configuração para fazer backup"
|
||||
|
||||
msgid "Config file is corrupted, cannot create backup"
|
||||
msgstr "Arquivo de configuração corrompido, não é possível criar backup"
|
||||
|
||||
msgid "Backup file created: %s"
|
||||
msgstr "Arquivo de backup criado: %s"
|
||||
|
||||
msgid "Backup write verification failed!"
|
||||
msgstr "Falha na verificação de escrita do backup!"
|
||||
|
||||
msgid "Backup creation failed: %s"
|
||||
msgstr "Falha na criação do backup: %s"
|
||||
|
||||
msgid "Error reading config: %s"
|
||||
msgstr "Erro ao ler configuração: %s"
|
||||
|
||||
msgid "Create backup .bak"
|
||||
msgstr "Criar backup .bak"
|
||||
@@ -1,176 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Language-Team: Rafał Wabik (IceG)\n"
|
||||
"Language: ru\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
|
||||
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||
|
||||
msgid "Edit Port Label"
|
||||
msgstr "Редактировать метку порта"
|
||||
|
||||
msgid "Enter new label for this port:"
|
||||
msgstr "Введите новую метку для этого порта:"
|
||||
|
||||
msgid "Device"
|
||||
msgstr "Устройство"
|
||||
|
||||
msgid "Original label"
|
||||
msgstr "Исходная метка"
|
||||
|
||||
msgid "Restore Original"
|
||||
msgstr "Восстановить исходную"
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr "Отмена"
|
||||
|
||||
msgid "Save"
|
||||
msgstr "Сохранить"
|
||||
|
||||
msgid "Port configuration saved successfully"
|
||||
msgstr "Конфигурация порта успешно сохранена"
|
||||
|
||||
msgid "Port order saved"
|
||||
msgstr "Порядок портов сохранен"
|
||||
|
||||
msgid "Click to edit label"
|
||||
msgstr "Нажмите, чтобы изменить метку"
|
||||
|
||||
msgid "Hold to drag and reorder"
|
||||
msgstr "Удерживайте, чтобы перетащить и изменить порядок"
|
||||
|
||||
msgid "Label max 9 chars, description max 50 chars."
|
||||
msgstr "Метка макс. 9 символов, описание макс. 50 символов."
|
||||
|
||||
msgid "Enter description (optional):"
|
||||
msgstr "Введите описание (необязательно):"
|
||||
|
||||
msgid "Optional description"
|
||||
msgstr "Необязательное описание"
|
||||
|
||||
msgid "User settings are saved to the /etc/user_defined_ports.json file."
|
||||
msgstr "Пользовательские настройки сохраняются в файле /etc/user_defined_ports.json."
|
||||
|
||||
msgid "Configuration file downloaded"
|
||||
msgstr "Файл конфигурации загружен"
|
||||
|
||||
msgid "Configuration file not found"
|
||||
msgstr "Файл конфигурации не найден"
|
||||
|
||||
msgid "Download error: %s"
|
||||
msgstr "Ошибка загрузки: %s"
|
||||
|
||||
msgid "Invalid configuration format"
|
||||
msgstr "Неверный формат конфигурации"
|
||||
|
||||
msgid "Restore configuration"
|
||||
msgstr "Восстановление конфигурации"
|
||||
|
||||
msgid "This will overwrite current ports configuration. Continue?"
|
||||
msgstr "Это перезапишет текущую конфигурацию портов. Продолжить?"
|
||||
|
||||
msgid "Configuration restored successfully. Reloading..."
|
||||
msgstr "Конфигурация успешно восстановлена. Перезагрузка..."
|
||||
|
||||
msgid "File restore failed: %s"
|
||||
msgstr "Не удалось восстановить файл: %s"
|
||||
|
||||
msgid "Save .json file"
|
||||
msgstr "Сохранить файл .json"
|
||||
|
||||
msgid "Upload .json file"
|
||||
msgstr "Загрузить файл .json"
|
||||
|
||||
msgid "Cannot save empty configuration"
|
||||
msgstr "Невозможно сохранить пустую конфигурацию"
|
||||
|
||||
msgid "Cannot save port configuration. "
|
||||
msgstr "Невозможно сохранить конфигурацию портов. "
|
||||
|
||||
msgid "Directory /etc may be read-only or insufficient permissions. "
|
||||
msgstr "Каталог /etc может быть доступен только для чтения или иметь недостаточные права доступа. "
|
||||
|
||||
msgid "Try running: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
msgstr "Попробуйте выполнить: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
|
||||
msgid "Save Error"
|
||||
msgstr "Ошибка сохранения"
|
||||
|
||||
msgid "Original error: %s"
|
||||
msgstr "Исходная ошибка: %s"
|
||||
|
||||
msgid "Restore from backup"
|
||||
msgstr "Восстановить из резервной копии"
|
||||
|
||||
msgid "Restore configuration from backup file? This will overwrite current settings."
|
||||
msgstr "Восстановить конфигурацию из файла резервной копии? Это перезапишет текущие настройки."
|
||||
|
||||
msgid "Backup contains:"
|
||||
msgstr "Резервная копия содержит:"
|
||||
|
||||
msgid "Configuration restored from backup. Reloading..."
|
||||
msgstr "Конфигурация восстановлена из резервной копии. Перезагрузка..."
|
||||
|
||||
msgid "Restore failed: %s"
|
||||
msgstr "Восстановление не удалось: %s"
|
||||
|
||||
msgid "Backup file is corrupted: %s"
|
||||
msgstr "Файл резервной копии поврежден: %s"
|
||||
|
||||
msgid "Error reading backup: %s"
|
||||
msgstr "Ошибка чтения резервной копии: %s"
|
||||
|
||||
msgid "Restore backup .bak"
|
||||
msgstr "Восстановить резервную копию .bak"
|
||||
|
||||
msgid "Change port state"
|
||||
msgstr "Изменить состояние порта"
|
||||
|
||||
msgid "Enable this port"
|
||||
msgstr "Включить этот порт"
|
||||
|
||||
msgid "Enable port"
|
||||
msgstr "Включить порт"
|
||||
|
||||
msgid "Disable this port"
|
||||
msgstr "Отключить этот порт"
|
||||
|
||||
msgid "Disable port"
|
||||
msgstr "Отключить порт"
|
||||
|
||||
msgid "Down"
|
||||
msgstr "неактивен"
|
||||
|
||||
msgid "Disabled"
|
||||
msgstr "отключен"
|
||||
|
||||
msgid "Idle"
|
||||
msgstr "простаивает"
|
||||
|
||||
msgid "Active"
|
||||
msgstr "активен"
|
||||
|
||||
msgid "Unknown"
|
||||
msgstr "неизвестно"
|
||||
|
||||
msgid "No config file to backup"
|
||||
msgstr "Нет файла конфигурации для резервного копирования"
|
||||
|
||||
msgid "Config file is corrupted, cannot create backup"
|
||||
msgstr "Файл конфигурации повреждён, создание резервной копии невозможно"
|
||||
|
||||
msgid "Backup file created: %s"
|
||||
msgstr "Резервный файл создан: %s"
|
||||
|
||||
msgid "Backup write verification failed!"
|
||||
msgstr "Проверка записи резервной копии не удалась!"
|
||||
|
||||
msgid "Backup creation failed: %s"
|
||||
msgstr "Создание резервной копии не удалось: %s"
|
||||
|
||||
msgid "Error reading config: %s"
|
||||
msgstr "Ошибка чтения конфигурации: %s"
|
||||
|
||||
msgid "Create backup .bak"
|
||||
msgstr "Создать резервную копию .bak"
|
||||
@@ -1,175 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Language-Team: Rafał Wabik (IceG)\n"
|
||||
"Language: vi\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
msgid "Edit Port Label"
|
||||
msgstr "Chỉnh sửa nhãn cổng"
|
||||
|
||||
msgid "Enter new label for this port:"
|
||||
msgstr "Nhập nhãn mới cho cổng này:"
|
||||
|
||||
msgid "Device"
|
||||
msgstr "Thiết bị"
|
||||
|
||||
msgid "Original label"
|
||||
msgstr "Nhãn gốc"
|
||||
|
||||
msgid "Restore Original"
|
||||
msgstr "Khôi phục gốc"
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr "Hủy"
|
||||
|
||||
msgid "Save"
|
||||
msgstr "Lưu"
|
||||
|
||||
msgid "Port configuration saved successfully"
|
||||
msgstr "Đã lưu cấu hình cổng thành công"
|
||||
|
||||
msgid "Port order saved"
|
||||
msgstr "Đã lưu thứ tự cổng"
|
||||
|
||||
msgid "Click to edit label"
|
||||
msgstr "Nhấp để chỉnh sửa nhãn"
|
||||
|
||||
msgid "Hold to drag and reorder"
|
||||
msgstr "Giữ để kéo và sắp xếp lại"
|
||||
|
||||
msgid "Label max 9 chars, description max 50 chars."
|
||||
msgstr "Nhãn tối đa 9 ký tự, mô tả tối đa 50 ký tự."
|
||||
|
||||
msgid "Enter description (optional):"
|
||||
msgstr "Nhập mô tả (tùy chọn):"
|
||||
|
||||
msgid "Optional description"
|
||||
msgstr "Mô tả tùy chọn"
|
||||
|
||||
msgid "User settings are saved to the /etc/user_defined_ports.json file."
|
||||
msgstr "Cài đặt người dùng được lưu vào tệp /etc/user_defined_ports.json."
|
||||
|
||||
msgid "Configuration file downloaded"
|
||||
msgstr "Đã tải xuống tệp cấu hình"
|
||||
|
||||
msgid "Configuration file not found"
|
||||
msgstr "Không tìm thấy tệp cấu hình"
|
||||
|
||||
msgid "Download error: %s"
|
||||
msgstr "Lỗi tải xuống: %s"
|
||||
|
||||
msgid "Invalid configuration format"
|
||||
msgstr "Định dạng cấu hình không hợp lệ"
|
||||
|
||||
msgid "Restore configuration"
|
||||
msgstr "Khôi phục cấu hình"
|
||||
|
||||
msgid "This will overwrite current ports configuration. Continue?"
|
||||
msgstr "Thao tác này sẽ ghi đè cấu hình cổng hiện tại. Tiếp tục?"
|
||||
|
||||
msgid "Configuration restored successfully. Reloading..."
|
||||
msgstr "Đã khôi phục cấu hình thành công. Đang tải lại..."
|
||||
|
||||
msgid "File restore failed: %s"
|
||||
msgstr "Khôi phục tệp không thành công: %s"
|
||||
|
||||
msgid "Save .json file"
|
||||
msgstr "Lưu tệp .json"
|
||||
|
||||
msgid "Upload .json file"
|
||||
msgstr "Tải lên tệp .json"
|
||||
|
||||
msgid "Cannot save empty configuration"
|
||||
msgstr "Không thể lưu cấu hình trống"
|
||||
|
||||
msgid "Cannot save port configuration. "
|
||||
msgstr "Không thể lưu cấu hình cổng. "
|
||||
|
||||
msgid "Directory /etc may be read-only or insufficient permissions. "
|
||||
msgstr "Thư mục /etc có thể chỉ đọc hoặc không đủ quyền. "
|
||||
|
||||
msgid "Try running: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
msgstr "Thử chạy: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
|
||||
msgid "Save Error"
|
||||
msgstr "Lỗi lưu"
|
||||
|
||||
msgid "Original error: %s"
|
||||
msgstr "Lỗi gốc: %s"
|
||||
|
||||
msgid "Restore from backup"
|
||||
msgstr "Khôi phục từ bản sao lưu"
|
||||
|
||||
msgid "Restore configuration from backup file? This will overwrite current settings."
|
||||
msgstr "Khôi phục cấu hình từ tệp sao lưu? Thao tác này sẽ ghi đè cài đặt hiện tại."
|
||||
|
||||
msgid "Backup contains:"
|
||||
msgstr "Bản sao lưu chứa:"
|
||||
|
||||
msgid "Configuration restored from backup. Reloading..."
|
||||
msgstr "Đã khôi phục cấu hình từ bản sao lưu. Đang tải lại..."
|
||||
|
||||
msgid "Restore failed: %s"
|
||||
msgstr "Khôi phục không thành công: %s"
|
||||
|
||||
msgid "Backup file is corrupted: %s"
|
||||
msgstr "Tệp sao lưu bị hỏng: %s"
|
||||
|
||||
msgid "Error reading backup: %s"
|
||||
msgstr "Lỗi đọc bản sao lưu: %s"
|
||||
|
||||
msgid "Restore backup .bak"
|
||||
msgstr "Khôi phục bản sao lưu .bak"
|
||||
|
||||
msgid "Change port state"
|
||||
msgstr "Thay đổi trạng thái cổng"
|
||||
|
||||
msgid "Enable this port"
|
||||
msgstr "Bật cổng này"
|
||||
|
||||
msgid "Enable port"
|
||||
msgstr "Bật cổng"
|
||||
|
||||
msgid "Disable this port"
|
||||
msgstr "Tắt cổng này"
|
||||
|
||||
msgid "Disable port"
|
||||
msgstr "Tắt cổng"
|
||||
|
||||
msgid "Down"
|
||||
msgstr "không hoạt động"
|
||||
|
||||
msgid "Disabled"
|
||||
msgstr "đã tắt"
|
||||
|
||||
msgid "Idle"
|
||||
msgstr "rảnh rỗi"
|
||||
|
||||
msgid "Active"
|
||||
msgstr "hoạt động"
|
||||
|
||||
msgid "Unknown"
|
||||
msgstr "không rõ"
|
||||
|
||||
msgid "No config file to backup"
|
||||
msgstr "Không có tệp cấu hình để sao lưu"
|
||||
|
||||
msgid "Config file is corrupted, cannot create backup"
|
||||
msgstr "Tệp cấu hình bị hỏng, không thể tạo bản sao lưu"
|
||||
|
||||
msgid "Backup file created: %s"
|
||||
msgstr "Đã tạo tệp sao lưu: %s"
|
||||
|
||||
msgid "Backup write verification failed!"
|
||||
msgstr "Xác minh ghi bản sao lưu thất bại!"
|
||||
|
||||
msgid "Backup creation failed: %s"
|
||||
msgstr "Tạo bản sao lưu thất bại: %s"
|
||||
|
||||
msgid "Error reading config: %s"
|
||||
msgstr "Lỗi khi đọc cấu hình: %s"
|
||||
|
||||
msgid "Create backup .bak"
|
||||
msgstr "Tạo bản sao lưu .bak"
|
||||
@@ -1,122 +0,0 @@
|
||||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8"
|
||||
|
||||
msgid "Edit Port Label"
|
||||
msgstr "Chỉnh sửa nhãn cổng"
|
||||
|
||||
msgid "Enter new label for this port:"
|
||||
msgstr "Nhập nhãn mới cho cổng này:"
|
||||
|
||||
msgid "Device"
|
||||
msgstr "Thiết bị"
|
||||
|
||||
msgid "Original label"
|
||||
msgstr "Nhãn gốc"
|
||||
|
||||
msgid "Restore Original"
|
||||
msgstr "Khôi phục gốc"
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr "Hủy"
|
||||
|
||||
msgid "Save"
|
||||
msgstr "Lưu"
|
||||
|
||||
msgid "Port configuration saved successfully"
|
||||
msgstr "Cấu hình cổng đã được lưu thành công"
|
||||
|
||||
msgid "Port order saved"
|
||||
msgstr "Thứ tự cổng đã được lưu"
|
||||
|
||||
msgid "Click to edit label"
|
||||
msgstr "Nhấp để chỉnh sửa nhãn"
|
||||
|
||||
msgid "Hold to drag and reorder"
|
||||
msgstr "Giữ để kéo và sắp xếp lại"
|
||||
|
||||
msgid "Label max 9 chars, description max 50 chars."
|
||||
msgstr "Nhãn tối đa 9 ký tự, mô tả tối đa 50 ký tự."
|
||||
|
||||
msgid "Enter description (optional):"
|
||||
msgstr "Nhập mô tả (tùy chọn):"
|
||||
|
||||
msgid "Optional description"
|
||||
msgstr "Mô tả tùy chọn"
|
||||
|
||||
msgid "User settings are saved to the /etc/user_defined_ports.json file."
|
||||
msgstr "Cài đặt người dùng được lưu vào tệp /etc/user_defined_ports.json."
|
||||
|
||||
msgid "Configuration file downloaded"
|
||||
msgstr "Đã tải xuống tệp cấu hình"
|
||||
|
||||
msgid "Configuration file not found"
|
||||
msgstr "Không tìm thấy tệp cấu hình"
|
||||
|
||||
msgid "Download error: %s"
|
||||
msgstr "Lỗi tải xuống: %s"
|
||||
|
||||
msgid "Invalid configuration format"
|
||||
msgstr "Định dạng cấu hình không hợp lệ"
|
||||
|
||||
msgid "Restore configuration"
|
||||
msgstr "Khôi phục cấu hình"
|
||||
|
||||
msgid "This will overwrite current ports configuration. Continue?"
|
||||
msgstr "Thao tác này sẽ ghi đè cấu hình cổng hiện tại. Tiếp tục?"
|
||||
|
||||
msgid "Configuration restored successfully. Reloading..."
|
||||
msgstr "Cấu hình đã được khôi phục thành công. Đang tải lại..."
|
||||
|
||||
msgid "File restore failed: %s"
|
||||
msgstr "Khôi phục tệp không thành công: %s"
|
||||
|
||||
msgid "Save .json file"
|
||||
msgstr "Lưu tệp .json"
|
||||
|
||||
msgid "Upload .json file"
|
||||
msgstr "Tải lên tệp .json"
|
||||
|
||||
msgid "Cannot save empty configuration"
|
||||
msgstr "Không thể lưu cấu hình trống"
|
||||
|
||||
msgid "Cannot save port configuration. "
|
||||
msgstr "Không thể lưu cấu hình cổng. "
|
||||
|
||||
msgid "Directory /etc may be read-only or insufficient permissions. "
|
||||
msgstr "Thư mục /etc có thể chỉ đọc hoặc không đủ quyền. "
|
||||
|
||||
msgid "Try running: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
msgstr "Thử chạy: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
|
||||
msgid "Save Error"
|
||||
msgstr "Lỗi lưu"
|
||||
|
||||
msgid "Original error: %s"
|
||||
msgstr "Lỗi gốc: %s"
|
||||
|
||||
msgid "Restore from backup"
|
||||
msgstr "Khôi phục từ bản sao lưu"
|
||||
|
||||
msgid "Restore configuration from backup file? This will overwrite current settings."
|
||||
msgstr "Khôi phục cấu hình từ tệp sao lưu? Thao tác này sẽ ghi đè các cài đặt hiện tại."
|
||||
|
||||
msgid "Backup contains:"
|
||||
msgstr "Bản sao lưu chứa:"
|
||||
|
||||
msgid "Configuration restored from backup. Reloading..."
|
||||
msgstr "Cấu hình đã được khôi phục từ bản sao lưu. Đang tải lại..."
|
||||
|
||||
msgid "Restore failed: %s"
|
||||
msgstr "Khôi phục không thành công: %s"
|
||||
|
||||
msgid "Backup file is corrupted: %s"
|
||||
msgstr "Tệp sao lưu bị hỏng: %s"
|
||||
|
||||
msgid "Error reading backup: %s"
|
||||
msgstr "Lỗi đọc bản sao lưu: %s"
|
||||
|
||||
msgid "Restore backup .bak"
|
||||
msgstr "Khôi phục bản sao lưu .bak"
|
||||
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -1 +0,0 @@
|
||||
zh_Hans
|
||||
@@ -1,175 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Language-Team: Rafał Wabik (IceG)\n"
|
||||
"Language: zh_Hans\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
msgid "Edit Port Label"
|
||||
msgstr "编辑端口标签"
|
||||
|
||||
msgid "Enter new label for this port:"
|
||||
msgstr "输入此端口的新标签:"
|
||||
|
||||
msgid "Device"
|
||||
msgstr "设备"
|
||||
|
||||
msgid "Original label"
|
||||
msgstr "原始标签"
|
||||
|
||||
msgid "Restore Original"
|
||||
msgstr "恢复原始"
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr "取消"
|
||||
|
||||
msgid "Save"
|
||||
msgstr "保存"
|
||||
|
||||
msgid "Port configuration saved successfully"
|
||||
msgstr "端口配置已成功保存"
|
||||
|
||||
msgid "Port order saved"
|
||||
msgstr "端口顺序已保存"
|
||||
|
||||
msgid "Click to edit label"
|
||||
msgstr "点击编辑标签"
|
||||
|
||||
msgid "Hold to drag and reorder"
|
||||
msgstr "按住以拖动和重新排序"
|
||||
|
||||
msgid "Label max 9 chars, description max 50 chars."
|
||||
msgstr "标签最多 9 个字符,描述最多 50 个字符。"
|
||||
|
||||
msgid "Enter description (optional):"
|
||||
msgstr "输入描述(可选):"
|
||||
|
||||
msgid "Optional description"
|
||||
msgstr "可选描述"
|
||||
|
||||
msgid "User settings are saved to the /etc/user_defined_ports.json file."
|
||||
msgstr "用户设置保存在 /etc/user_defined_ports.json 文件中。"
|
||||
|
||||
msgid "Configuration file downloaded"
|
||||
msgstr "配置文件已下载"
|
||||
|
||||
msgid "Configuration file not found"
|
||||
msgstr "未找到配置文件"
|
||||
|
||||
msgid "Download error: %s"
|
||||
msgstr "下载错误:%s"
|
||||
|
||||
msgid "Invalid configuration format"
|
||||
msgstr "无效的配置格式"
|
||||
|
||||
msgid "Restore configuration"
|
||||
msgstr "恢复配置"
|
||||
|
||||
msgid "This will overwrite current ports configuration. Continue?"
|
||||
msgstr "这将覆盖当前端口配置。继续?"
|
||||
|
||||
msgid "Configuration restored successfully. Reloading..."
|
||||
msgstr "配置已成功恢复。正在重新加载..."
|
||||
|
||||
msgid "File restore failed: %s"
|
||||
msgstr "文件恢复失败:%s"
|
||||
|
||||
msgid "Save .json file"
|
||||
msgstr "保存 .json 文件"
|
||||
|
||||
msgid "Upload .json file"
|
||||
msgstr "上传 .json 文件"
|
||||
|
||||
msgid "Cannot save empty configuration"
|
||||
msgstr "无法保存空配置"
|
||||
|
||||
msgid "Cannot save port configuration. "
|
||||
msgstr "无法保存端口配置。"
|
||||
|
||||
msgid "Directory /etc may be read-only or insufficient permissions. "
|
||||
msgstr "目录 /etc 可能为只读或权限不足。"
|
||||
|
||||
msgid "Try running: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
msgstr "尝试运行:chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
|
||||
msgid "Save Error"
|
||||
msgstr "保存错误"
|
||||
|
||||
msgid "Original error: %s"
|
||||
msgstr "原始错误:%s"
|
||||
|
||||
msgid "Restore from backup"
|
||||
msgstr "从备份恢复"
|
||||
|
||||
msgid "Restore configuration from backup file? This will overwrite current settings."
|
||||
msgstr "从备份文件恢复配置?这将覆盖当前设置。"
|
||||
|
||||
msgid "Backup contains:"
|
||||
msgstr "备份包含:"
|
||||
|
||||
msgid "Configuration restored from backup. Reloading..."
|
||||
msgstr "已从备份恢复配置。正在重新加载..."
|
||||
|
||||
msgid "Restore failed: %s"
|
||||
msgstr "恢复失败:%s"
|
||||
|
||||
msgid "Backup file is corrupted: %s"
|
||||
msgstr "备份文件已损坏:%s"
|
||||
|
||||
msgid "Error reading backup: %s"
|
||||
msgstr "读取备份错误:%s"
|
||||
|
||||
msgid "Restore backup .bak"
|
||||
msgstr "恢复备份 .bak"
|
||||
|
||||
msgid "Change port state"
|
||||
msgstr "更改端口状态"
|
||||
|
||||
msgid "Enable this port"
|
||||
msgstr "启用此端口"
|
||||
|
||||
msgid "Enable port"
|
||||
msgstr "启用端口"
|
||||
|
||||
msgid "Disable this port"
|
||||
msgstr "禁用此端口"
|
||||
|
||||
msgid "Disable port"
|
||||
msgstr "禁用端口"
|
||||
|
||||
msgid "Down"
|
||||
msgstr "未连接"
|
||||
|
||||
msgid "Disabled"
|
||||
msgstr "已禁用"
|
||||
|
||||
msgid "Idle"
|
||||
msgstr "空闲"
|
||||
|
||||
msgid "Active"
|
||||
msgstr "活动"
|
||||
|
||||
msgid "Unknown"
|
||||
msgstr "未知"
|
||||
|
||||
msgid "No config file to backup"
|
||||
msgstr "没有可备份的配置文件"
|
||||
|
||||
msgid "Config file is corrupted, cannot create backup"
|
||||
msgstr "配置文件已损坏,无法创建备份"
|
||||
|
||||
msgid "Backup file created: %s"
|
||||
msgstr "备份文件已创建:%s"
|
||||
|
||||
msgid "Backup write verification failed!"
|
||||
msgstr "备份写入验证失败!"
|
||||
|
||||
msgid "Backup creation failed: %s"
|
||||
msgstr "备份创建失败:%s"
|
||||
|
||||
msgid "Error reading config: %s"
|
||||
msgstr "读取配置时出错:%s"
|
||||
|
||||
msgid "Create backup .bak"
|
||||
msgstr "创建备份 .bak"
|
||||
@@ -1,175 +0,0 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Language-Team: Rafał Wabik (IceG)\n"
|
||||
"Language: zh_Hant\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
msgid "Edit Port Label"
|
||||
msgstr "編輯連接埠標籤"
|
||||
|
||||
msgid "Enter new label for this port:"
|
||||
msgstr "輸入此連接埠的新標籤:"
|
||||
|
||||
msgid "Device"
|
||||
msgstr "裝置"
|
||||
|
||||
msgid "Original label"
|
||||
msgstr "原始標籤"
|
||||
|
||||
msgid "Restore Original"
|
||||
msgstr "恢復原始"
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr "取消"
|
||||
|
||||
msgid "Save"
|
||||
msgstr "儲存"
|
||||
|
||||
msgid "Port configuration saved successfully"
|
||||
msgstr "連接埠配置已成功儲存"
|
||||
|
||||
msgid "Port order saved"
|
||||
msgstr "連接埠順序已儲存"
|
||||
|
||||
msgid "Click to edit label"
|
||||
msgstr "點擊編輯標籤"
|
||||
|
||||
msgid "Hold to drag and reorder"
|
||||
msgstr "按住以拖曳和重新排序"
|
||||
|
||||
msgid "Label max 9 chars, description max 50 chars."
|
||||
msgstr "標籤最多 9 個字元,描述最多 50 個字元。"
|
||||
|
||||
msgid "Enter description (optional):"
|
||||
msgstr "輸入描述(選填):"
|
||||
|
||||
msgid "Optional description"
|
||||
msgstr "選填描述"
|
||||
|
||||
msgid "User settings are saved to the /etc/user_defined_ports.json file."
|
||||
msgstr "使用者設定儲存在 /etc/user_defined_ports.json 檔案中。"
|
||||
|
||||
msgid "Configuration file downloaded"
|
||||
msgstr "配置檔案已下載"
|
||||
|
||||
msgid "Configuration file not found"
|
||||
msgstr "未找到配置檔案"
|
||||
|
||||
msgid "Download error: %s"
|
||||
msgstr "下載錯誤:%s"
|
||||
|
||||
msgid "Invalid configuration format"
|
||||
msgstr "無效的配置格式"
|
||||
|
||||
msgid "Restore configuration"
|
||||
msgstr "恢復配置"
|
||||
|
||||
msgid "This will overwrite current ports configuration. Continue?"
|
||||
msgstr "這將覆蓋目前連接埠配置。繼續?"
|
||||
|
||||
msgid "Configuration restored successfully. Reloading..."
|
||||
msgstr "配置已成功恢復。正在重新載入..."
|
||||
|
||||
msgid "File restore failed: %s"
|
||||
msgstr "檔案恢復失敗:%s"
|
||||
|
||||
msgid "Save .json file"
|
||||
msgstr "儲存 .json 檔案"
|
||||
|
||||
msgid "Upload .json file"
|
||||
msgstr "上傳 .json 檔案"
|
||||
|
||||
msgid "Cannot save empty configuration"
|
||||
msgstr "無法儲存空白配置"
|
||||
|
||||
msgid "Cannot save port configuration. "
|
||||
msgstr "無法儲存連接埠配置。"
|
||||
|
||||
msgid "Directory /etc may be read-only or insufficient permissions. "
|
||||
msgstr "目錄 /etc 可能為唯讀或權限不足。"
|
||||
|
||||
msgid "Try running: chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
msgstr "嘗試執行:chmod 755 /etc && touch %s && chmod 644 %s"
|
||||
|
||||
msgid "Save Error"
|
||||
msgstr "儲存錯誤"
|
||||
|
||||
msgid "Original error: %s"
|
||||
msgstr "原始錯誤:%s"
|
||||
|
||||
msgid "Restore from backup"
|
||||
msgstr "從備份恢復"
|
||||
|
||||
msgid "Restore configuration from backup file? This will overwrite current settings."
|
||||
msgstr "從備份檔案恢復配置?這將覆蓋目前設定。"
|
||||
|
||||
msgid "Backup contains:"
|
||||
msgstr "備份包含:"
|
||||
|
||||
msgid "Configuration restored from backup. Reloading..."
|
||||
msgstr "已從備份恢復配置。正在重新載入..."
|
||||
|
||||
msgid "Restore failed: %s"
|
||||
msgstr "恢復失敗:%s"
|
||||
|
||||
msgid "Backup file is corrupted: %s"
|
||||
msgstr "備份檔案已損壞:%s"
|
||||
|
||||
msgid "Error reading backup: %s"
|
||||
msgstr "讀取備份錯誤:%s"
|
||||
|
||||
msgid "Restore backup .bak"
|
||||
msgstr "恢復備份 .bak"
|
||||
|
||||
msgid "Change port state"
|
||||
msgstr "變更連接埠狀態"
|
||||
|
||||
msgid "Enable this port"
|
||||
msgstr "啟用此連接埠"
|
||||
|
||||
msgid "Enable port"
|
||||
msgstr "啟用連接埠"
|
||||
|
||||
msgid "Disable this port"
|
||||
msgstr "停用此連接埠"
|
||||
|
||||
msgid "Disable port"
|
||||
msgstr "停用連接埠"
|
||||
|
||||
msgid "Down"
|
||||
msgstr "未連接"
|
||||
|
||||
msgid "Disabled"
|
||||
msgstr "已停用"
|
||||
|
||||
msgid "Idle"
|
||||
msgstr "閒置"
|
||||
|
||||
msgid "Active"
|
||||
msgstr "活動"
|
||||
|
||||
msgid "Unknown"
|
||||
msgstr "未知"
|
||||
|
||||
msgid "No config file to backup"
|
||||
msgstr "沒有可備份的設定檔"
|
||||
|
||||
msgid "Config file is corrupted, cannot create backup"
|
||||
msgstr "設定檔已損毀,無法建立備份"
|
||||
|
||||
msgid "Backup file created: %s"
|
||||
msgstr "備份檔案已建立:%s"
|
||||
|
||||
msgid "Backup write verification failed!"
|
||||
msgstr "備份寫入驗證失敗!"
|
||||
|
||||
msgid "Backup creation failed: %s"
|
||||
msgstr "備份建立失敗:%s"
|
||||
|
||||
msgid "Error reading config: %s"
|
||||
msgstr "讀取設定時發生錯誤:%s"
|
||||
|
||||
msgid "Create backup .bak"
|
||||
msgstr "建立備份 .bak"
|
||||
@@ -1,33 +0,0 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Copyright 2025-2026 Rafał Wabik (IceG) - From eko.one.pl forum
|
||||
#
|
||||
# MIT
|
||||
#
|
||||
|
||||
PORTS_ORIG="/www/luci-static/resources/view/status/include/29_ports.js"
|
||||
PORTS_BAK="/www/luci-static/resources/view/status/include/29_ports.bak"
|
||||
PORTS_CUSTOM="/www/luci-static/resources/view/status/include/29_ports_custom.js"
|
||||
USER_DEFINED_PORTS="/etc/user_defined_ports.json"
|
||||
|
||||
sleep 5
|
||||
|
||||
if [ -f "$PORTS_ORIG" ]; then
|
||||
mv "$PORTS_ORIG" "$PORTS_BAK"
|
||||
fi
|
||||
|
||||
if [ -f "$PORTS_CUSTOM" ]; then
|
||||
mv "$PORTS_CUSTOM" "$PORTS_ORIG"
|
||||
fi
|
||||
|
||||
if [ -f "$USER_DEFINED_PORTS" ]; then
|
||||
chmod 664 "$USER_DEFINED_PORTS" >/dev/null 2>&1 &
|
||||
fi
|
||||
|
||||
chmod +x /usr/libexec/rpcd/ports-status-mod >/dev/null 2>&1 &
|
||||
|
||||
rm -rf /tmp/luci-indexcache >/dev/null 2>&1 &
|
||||
rm -rf /tmp/luci-* >/dev/null 2>&1 &
|
||||
rm -rf /tmp/luci-modulecache/ >/dev/null 2>&1 &
|
||||
|
||||
exit 0
|
||||
@@ -1,203 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
. /usr/share/libubox/jshn.sh
|
||||
|
||||
##################################################################################################################
|
||||
#
|
||||
# Copyright 2026 Rafał Wabik - IceG - From eko.one.pl forum
|
||||
#
|
||||
# MIT License
|
||||
#
|
||||
##################################################################################################################
|
||||
|
||||
ACTIVITY_THRESHOLD=2000
|
||||
|
||||
check_activity() {
|
||||
local port="$1"
|
||||
local port_path="/sys/class/net/$port"
|
||||
|
||||
local rx_bytes_file="$port_path/statistics/rx_bytes"
|
||||
local tx_bytes_file="$port_path/statistics/tx_bytes"
|
||||
|
||||
if [ ! -f "$rx_bytes_file" ] || [ ! -f "$tx_bytes_file" ]; then
|
||||
echo "idle"
|
||||
return
|
||||
fi
|
||||
|
||||
local rx1 tx1 rx2 tx2
|
||||
rx1=$(cat "$rx_bytes_file" 2>/dev/null || echo "0")
|
||||
tx1=$(cat "$tx_bytes_file" 2>/dev/null || echo "0")
|
||||
|
||||
sleep 0.5
|
||||
|
||||
rx2=$(cat "$rx_bytes_file" 2>/dev/null || echo "0")
|
||||
tx2=$(cat "$tx_bytes_file" 2>/dev/null || echo "0")
|
||||
|
||||
local rx_diff=$((rx2 - rx1))
|
||||
local tx_diff=$((tx2 - tx1))
|
||||
local total_diff=$((rx_diff + tx_diff))
|
||||
|
||||
if [ "$total_diff" -gt "$ACTIVITY_THRESHOLD" ]; then
|
||||
echo "active"
|
||||
else
|
||||
echo "idle"
|
||||
fi
|
||||
}
|
||||
|
||||
get_port_status() {
|
||||
local port="$1"
|
||||
local port_path="/sys/class/net/$port"
|
||||
local operstate="unknown"
|
||||
|
||||
if [ ! -d "$port_path" ]; then
|
||||
echo "unknown"
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -f "$port_path/operstate" ]; then
|
||||
operstate=$(cat "$port_path/operstate" 2>/dev/null || echo "unknown")
|
||||
fi
|
||||
|
||||
local flags=""
|
||||
if [ -f "$port_path/flags" ]; then
|
||||
flags=$(cat "$port_path/flags" 2>/dev/null || echo "0x0")
|
||||
fi
|
||||
|
||||
local carrier=0
|
||||
if [ -f "$port_path/carrier" ]; then
|
||||
carrier=$(cat "$port_path/carrier" 2>/dev/null || echo "0")
|
||||
fi
|
||||
|
||||
if [ "$operstate" = "down" ]; then
|
||||
local flags_decimal=$(printf "%d" "$flags" 2>/dev/null || echo "0")
|
||||
local is_up=$((flags_decimal & 1))
|
||||
|
||||
if [ "$is_up" = "0" ]; then
|
||||
echo "disabled"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$carrier" != "1" ]; then
|
||||
echo "down"
|
||||
return
|
||||
fi
|
||||
|
||||
if [ "$operstate" = "unknown" ] && [ "$carrier" = "1" ]; then
|
||||
operstate="up"
|
||||
fi
|
||||
|
||||
if [ "$carrier" = "1" ]; then
|
||||
local activity=$(check_activity "$port")
|
||||
echo "$activity"
|
||||
return
|
||||
fi
|
||||
|
||||
echo "$operstate"
|
||||
}
|
||||
|
||||
get_all_ports_status() {
|
||||
local tmpdir
|
||||
tmpdir=$(mktemp -d)
|
||||
local pids=""
|
||||
|
||||
for port_path in /sys/class/net/*; do
|
||||
if [ -d "$port_path" ]; then
|
||||
port_name=$(basename "$port_path")
|
||||
case "$port_name" in
|
||||
lo|dummy*|tunl*|gre*|gretap*|sit*|ip6tnl*|ip6gre*|br-*)
|
||||
continue
|
||||
;;
|
||||
eth*|lan*|wan*|en*|sfp*)
|
||||
if [ -f "$port_path/address" ]; then
|
||||
(
|
||||
status=$(get_port_status "$port_name")
|
||||
echo "${port_name}=${status}" > "$tmpdir/$port_name"
|
||||
) &
|
||||
pids="$pids $!"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
done
|
||||
|
||||
for pid in $pids; do
|
||||
wait "$pid" 2>/dev/null
|
||||
done
|
||||
|
||||
json_init
|
||||
for result_file in "$tmpdir"/*; do
|
||||
[ -f "$result_file" ] || continue
|
||||
line=$(cat "$result_file")
|
||||
port_name="${line%%=*}"
|
||||
status="${line#*=}"
|
||||
json_add_string "$port_name" "$status"
|
||||
done
|
||||
rm -rf "$tmpdir"
|
||||
|
||||
json_dump
|
||||
}
|
||||
|
||||
set_port_status() {
|
||||
local port="$1"
|
||||
local status="$2"
|
||||
|
||||
if [ ! -d "/sys/class/net/$port" ]; then
|
||||
json_init
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "error" "Port not found"
|
||||
json_dump
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$status" = "up" ]; then
|
||||
ip link set "$port" up 2>/dev/null
|
||||
elif [ "$status" = "down" ]; then
|
||||
ip link set "$port" down 2>/dev/null
|
||||
else
|
||||
json_init
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "error" "Invalid status"
|
||||
json_dump
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
json_init
|
||||
json_add_boolean "success" 1
|
||||
json_dump
|
||||
return 0
|
||||
else
|
||||
json_init
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "error" "Failed to change port status"
|
||||
json_dump
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
list)
|
||||
json_init
|
||||
json_add_object "getPortsStatus"
|
||||
json_close_object
|
||||
json_add_object "setPortStatus"
|
||||
json_add_string "port" "port"
|
||||
json_add_string "status" "status"
|
||||
json_close_object
|
||||
json_dump
|
||||
;;
|
||||
call)
|
||||
case "$2" in
|
||||
getPortsStatus)
|
||||
get_all_ports_status
|
||||
;;
|
||||
setPortStatus)
|
||||
read input
|
||||
port=$(echo "$input" | jsonfilter -e '@.port')
|
||||
status=$(echo "$input" | jsonfilter -e '@.status')
|
||||
set_port_status "$port" "$status"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"luci-ports": {
|
||||
"description": "Access to custom Ports Status",
|
||||
"read": {
|
||||
"uci": [ "*" ],
|
||||
"ubus": {
|
||||
"luci": [ "getBuiltinEthernetPorts" ],
|
||||
"ports-status-mod": [ "getPortsStatus" ],
|
||||
"file": [ "read" ]
|
||||
},
|
||||
"file": {
|
||||
"/etc/user_defined_ports.json": [ "read" ],
|
||||
"/etc/user_defined_ports.json.bak": [ "read" ],
|
||||
"/www/luci-static/resources/view/status/include/29_ports.js": [ "read" ]
|
||||
}
|
||||
},
|
||||
"write": {
|
||||
"file": {
|
||||
"/etc/user_defined_ports.json": [ "write" ],
|
||||
"/etc/user_defined_ports.json.bak": [ "write" ]
|
||||
},
|
||||
"ubus": {
|
||||
"file": [ "write", "exec" ],
|
||||
"luci": [ "getBuiltinEthernetPorts" ],
|
||||
"ports-status-mod": [ "setPortStatus" ]
|
||||
},
|
||||
"exec": {
|
||||
"/usr/bin/stat": [ "*" ],
|
||||
"/bin/chmod": [ "*" ],
|
||||
"/bin/sh": [ "*" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user