1
0
mirror of https://gitlab.nic.cz/turris/reforis/foris-js.git synced 2025-08-06 20:33:46 +02:00

Compare commits

..

2 Commits

Author SHA1 Message Date
Štěpán Henek
6dd87cdf57 Merge branch 'feature/ws-included' into 'master'
Draft: Using socket.io for websocket handling and make reforis configurable

See merge request turris/reforis/foris-js!201
2023-09-27 22:27:48 +02:00
Stepan Henek
f6dece80b2 Using socket.io for websocket handling and make reforis configurable
Socket.io wrapper is used to handle websockets now,
this means that websocket logic had to be redone.

Also it is necessary to set `REFORIS_PREFIX` env variable
during the build process. To set the path of backend url.
It was previously fixed to `/reforis`.
2023-04-27 10:05:22 +02:00
16 changed files with 13381 additions and 13922 deletions

View File

@@ -1,4 +1,4 @@
image: registry.nic.cz/turris/reforis/reforis/reforis-image
image: node:16-alpine
stages:
- test
@@ -6,7 +6,7 @@ stages:
- publish
before_script:
- apt-get update && apt-get install -y make
- apk add make
- npm install
test:

26947
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "foris",
"version": "5.6.1",
"version": "5.6.0",
"description": "Foris JS library is a set of components and utils for reForis application and plugins.",
"author": "CZ.NIC, z.s.p.o.",
"repository": {
@@ -18,45 +18,46 @@
"immutability-helper": "3.0.1",
"moment": "^2.24.0",
"qrcode.react": "^1.0.1",
"react-datetime": "^3.1.1",
"react-uid": "^2.2.0"
"react-datetime": "^3.2.0",
"react-uid": "^2.2.0",
"socket.io-client": "^4.6.1"
},
"peerDependencies": {
"bootstrap": "^4.6.2",
"bootstrap": "4.4.1",
"prop-types": "15.8.1",
"react": "16.9.0",
"react-dom": "16.9.0",
"react-router-dom": "^5.1.2"
},
"devDependencies": {
"@babel/cli": "^7.12.10",
"@babel/core": "^7.9.0",
"@babel/plugin-transform-runtime": "^7.9.0",
"@babel/preset-env": "^7.9.0",
"@babel/cli": "^7.20.7",
"@babel/core": "^7.20.12",
"@babel/plugin-transform-runtime": "^7.19.6",
"@babel/preset-env": "^7.20.2",
"@babel/preset-react": "^7.9.4",
"@fortawesome/fontawesome-free": "^5.13.0",
"@testing-library/react": "^8.0.9",
"babel-loader": "^8.1.0",
"babel-loader": "^8.3.0",
"babel-polyfill": "^6.26.0",
"bootstrap": "^4.6.2",
"bootstrap": "^4.5.0",
"css-loader": "^5.2.4",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.11.0",
"eslint-config-reforis": "^1.0.0",
"eslint-plugin-prettier": "^3.1.4",
"file-loader": "^6.0.0",
"jest": "^25.2.0",
"jest": "^29.5.0",
"jest-mock-axios": "^3.2.0",
"moment-timezone": "^0.5.34",
"moment-timezone": "^0.5.40",
"prettier": "2.0.5",
"prop-types": "15.8.1",
"react": "16.9.0",
"react-dom": "16.9.0",
"react-router-dom": "^5.1.2",
"react-styleguidist": "^11.2.0",
"react-router-dom": "^5.3.4",
"react-styleguidist": "^13.1.1",
"snapshot-diff": "^0.7.0",
"style-loader": "^1.2.1",
"webpack": "^5.68.0"
"webpack": "^5.75.0"
},
"scripts": {
"lint": "eslint src",

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2023 CZ.NIC z.s.p.o. (https://www.nic.cz/)
* Copyright (C) 2019 CZ.NIC z.s.p.o. (http://www.nic.cz/)
*
* This is free software, licensed under the GNU General Public License v3.
* See /LICENSE for more information.
@@ -31,25 +31,24 @@ export function Button({
children,
...props
}) {
let buttonClass = className ? `btn ${className}` : "btn btn-primary";
let buttonClass = className ? `btn ${className}` : "btn btn-primary ";
if (forisFormSize) {
buttonClass = `${buttonClass} col-sm-12 col-md-3 col-lg-2`;
}
const span = loading ? (
<span
className="spinner-border spinner-border-sm"
role="status"
aria-hidden="true"
/>
) : null;
return (
<button
type="button"
className={`${buttonClass} d-inline-flex justify-content-center align-items-center`}
{...props}
>
{loading && (
<span
className="spinner-border spinner-border-sm mr-1"
role="status"
aria-hidden="true"
/>
)}
<span>{children}</span>
<button type="button" className={buttonClass} {...props}>
{span}
{span ? " " : null}
{children}
</button>
);
}

View File

@@ -31,7 +31,3 @@
.spinner-fs-wrapper .spinner-text {
margin: 1rem;
}
.spinner-border-sm {
min-width: 16px;
}

View File

@@ -2,38 +2,33 @@
exports[`<Button /> Render button correctly 1`] = `
<button
class="btn btn-primary d-inline-flex justify-content-center align-items-center"
class="btn btn-primary "
type="button"
>
<span>
Test Button
</span>
Test Button
</button>
`;
exports[`<Button /> Render button with custom classes 1`] = `
<button
class="btn one two three d-inline-flex justify-content-center align-items-center"
class="btn one two three"
type="button"
>
<span>
Test Button
</span>
Test Button
</button>
`;
exports[`<Button /> Render button with spinner 1`] = `
<button
class="btn btn-primary d-inline-flex justify-content-center align-items-center"
class="btn btn-primary "
type="button"
>
<span
aria-hidden="true"
class="spinner-border spinner-border-sm mr-1"
class="spinner-border spinner-border-sm"
role="status"
/>
<span>
Test Button
</span>
Test Button
</button>
`;

View File

@@ -25,7 +25,7 @@ export function ResetWiFiSettings({ ws, endpoint }) {
useEffect(() => {
const module = "wifi";
ws.subscribe(module).bind(module, "reset", () => {
ws.bind(module, "reset", () => {
// eslint-disable-next-line no-restricted-globals
setTimeout(() => location.reload(), 1000);
});

View File

@@ -301,12 +301,10 @@ exports[`<WiFiSettings/> Snapshot both modules disabled. 1`] = `
class="text-right"
>
<button
class="btn btn-primary col-sm-12 col-md-3 col-lg-2 d-inline-flex justify-content-center align-items-center"
class="btn btn-primary col-sm-12 col-md-3 col-lg-2"
type="submit"
>
<span>
Save
</span>
Save
</button>
</div>
</form>
@@ -324,12 +322,10 @@ exports[`<WiFiSettings/> Snapshot both modules disabled. 1`] = `
class="text-right"
>
<button
class="btn btn-primary col-sm-12 col-md-3 col-lg-2 d-inline-flex justify-content-center align-items-center"
class="btn btn-primary col-sm-12 col-md-3 col-lg-2"
type="button"
>
<span>
Reset Wi-Fi Settings
</span>
Reset Wi-Fi Settings
</button>
</div>
</div>
@@ -439,13 +435,13 @@ exports[`<WiFiSettings/> Snapshot guest network. 1`] = `
class=\\"text-right\\"
>
<button
class=\\"btn btn-primary col-sm-12 col-md-3 col-lg-2 d-inline-flex justify-content-center align-items-center\\"
class=\\"btn btn-primary col-sm-12 col-md-3 col-lg-2\\"
+ disabled=\\"\\"
type=\\"submit\\"
>
<span>
Save
</span>"
Save
</button>
</div>"
`;
exports[`<WiFiSettings/> Snapshot one module enabled. 1`] = `

View File

@@ -46,20 +46,16 @@ exports[`<RebootButton/> Render modal. 1`] = `
class="modal-footer"
>
<button
class="btn btn-primary d-inline-flex justify-content-center align-items-center"
class="btn btn-primary "
type="button"
>
<span>
Cancel
</span>
Cancel
</button>
<button
class="btn btn-danger d-inline-flex justify-content-center align-items-center"
class="btn btn-danger"
type="button"
>
<span>
Confirm reboot
</span>
Confirm reboot
</button>
</div>
</div>
@@ -67,12 +63,10 @@ exports[`<RebootButton/> Render modal. 1`] = `
</div>
</div>
<button
class="btn btn-danger d-inline-flex justify-content-center align-items-center"
class="btn btn-danger"
type="button"
>
<span>
Reboot
</span>
Reboot
</button>
</div>
`;
@@ -83,12 +77,10 @@ exports[`<RebootButton/> Render. 1`] = `
id="modal-container"
/>
<button
class="btn btn-danger d-inline-flex justify-content-center align-items-center"
class="btn btn-danger"
type="button"
>
<span>
Reboot
</span>
Reboot
</button>
</div>
`;

View File

@@ -3,18 +3,17 @@
exports[`<SubmitButton/> Render load 1`] = `
<div>
<button
class="btn btn-primary col-sm-12 col-md-3 col-lg-2 d-inline-flex justify-content-center align-items-center"
class="btn btn-primary col-sm-12 col-md-3 col-lg-2"
disabled=""
type="submit"
>
<span
aria-hidden="true"
class="spinner-border spinner-border-sm mr-1"
class="spinner-border spinner-border-sm"
role="status"
/>
<span>
Load settings
</span>
Load settings
</button>
</div>
`;
@@ -22,12 +21,10 @@ exports[`<SubmitButton/> Render load 1`] = `
exports[`<SubmitButton/> Render ready 1`] = `
<div>
<button
class="btn btn-primary col-sm-12 col-md-3 col-lg-2 d-inline-flex justify-content-center align-items-center"
class="btn btn-primary col-sm-12 col-md-3 col-lg-2"
type="submit"
>
<span>
Save
</span>
Save
</button>
</div>
`;
@@ -35,18 +32,17 @@ exports[`<SubmitButton/> Render ready 1`] = `
exports[`<SubmitButton/> Render saving 1`] = `
<div>
<button
class="btn btn-primary col-sm-12 col-md-3 col-lg-2 d-inline-flex justify-content-center align-items-center"
class="btn btn-primary col-sm-12 col-md-3 col-lg-2"
disabled=""
type="submit"
>
<span
aria-hidden="true"
class="spinner-border spinner-border-sm mr-1"
class="spinner-border spinner-border-sm"
role="status"
/>
<span>
Updating
</span>
Updating
</button>
</div>
`;

View File

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2019-2021 CZ.NIC z.s.p.o. (http://www.nic.cz/)
* Copyright (C) 2019-2022 CZ.NIC z.s.p.o. (http://www.nic.cz/)
*
* This is free software, licensed under the GNU General Public License v3.
* See /LICENSE for more information.
*/
export const REFORIS_URL_PREFIX = "/reforis";
export const REFORIS_URL_PREFIX = process.env.REFORIS_PREFIX || "";
export const REFORIS_API_URL_PREFIX = `${REFORIS_URL_PREFIX}/api`;
export const ForisURLs = {

View File

@@ -7,49 +7,33 @@
/* eslint no-console: "off" */
const PROTOCOL = window.location.protocol === "http:" ? "ws" : "wss";
import { REFORIS_URL_PREFIX } from "../utils/forisUrls";
const URL = process.env.LIGHTTPD
? `${PROTOCOL}://${window.location.host}/${
process.env.WSPATH || "foris-ws"
}`
: `${PROTOCOL}://${window.location.hostname}:9081`;
const WAITING_FOR_CONNECTION_TIMEOUT = 500;
const { io } = require("socket.io-client");
export class WebSockets {
constructor() {
this.ws = new WebSocket(URL);
this.ws.onerror = (e) => {
console.error("WS: Error:", e);
};
this.ws.onmessage = (e) => {
console.debug(`WS: Received Message: ${e.data}`);
const data = JSON.parse(e.data);
this.dispatch(data);
};
this.ws.onopen = () => {
console.debug("WS: Connection open.");
};
this.ws.onclose = () => {
console.debug("WS: Connection closed.");
};
this.socket = io("/notifications", {
path: `${REFORIS_URL_PREFIX}/reforis-ws`,
});
this.connection = null;
this.socket.on("disconnect", (reason) => {
this.connection = null;
console.debug(`SocketIO disconnected (${reason})`);
});
this.socket.on("notification", (message) => {
console.debug("WS: Received Message:", message);
this.dispatch(message);
});
this.socket.on("connect", (connection) => {
this.connection = connection;
console.debug(`SocketIO connected.`);
});
// callbacks[module][action]
this.callbacks = {};
}
waitForConnection(callback) {
if (this.ws.readyState === 1) {
callback();
} else {
const that = this;
setTimeout(() => {
that.waitForConnection(callback);
}, WAITING_FOR_CONNECTION_TIMEOUT);
}
}
bind(module, action, callback) {
this.callbacks[module] = this.callbacks[module] || {};
this.callbacks[module][action] = this.callbacks[module][action] || [];
@@ -57,13 +41,6 @@ export class WebSockets {
return this;
}
subscribe(module) {
this.waitForConnection(() => {
this.send("subscribe", module);
});
return this;
}
unbind(module, action, callback) {
const callbacks = this.callbacks[module][action];
@@ -77,28 +54,12 @@ export class WebSockets {
}
if (Object.keys(this.callbacks[module]).length === 0) {
this.unsubscribe(module);
delete this.callbacks[module];
}
return this;
}
unsubscribe(module) {
this.waitForConnection(() => {
this.send("unsubscribe", module);
delete this.callbacks[module];
});
return this;
}
send(action, params) {
const payload = JSON.stringify({ action, params });
this.waitForConnection(() => {
this.ws.send(payload);
});
return this;
}
dispatch(json) {
if (!json.module) return;
@@ -107,18 +68,15 @@ export class WebSockets {
chain = this.callbacks[json.module][json.action];
} catch (error) {
if (error instanceof TypeError) {
console.warn(
`Callback for this message wasn't found:${error.data}`
console.debug(
`Callbacks for this module wasn't found: ${json.module}`
);
} else throw error;
}
if (typeof chain === "undefined") return;
console.debug("Handling WS message", json);
chain.forEach((callback) => callback(json));
}
close() {
this.ws.close();
}
}

View File

@@ -32,7 +32,7 @@ export function useWSForisModule(
setData(message.data);
}
ws.subscribe(module).bind(module, action, callback);
ws.bind(module, action, callback);
return () => {
ws.unbind(module, action, callback);

View File

@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2022-12-02 15:54+0100\n"
"PO-Revision-Date: 2023-11-23 16:03+0000\n"
"Last-Translator: Lukas Jelinek <lukas.jelinek@nic.cz>\n"
"PO-Revision-Date: 2023-04-16 13:52+0000\n"
"Last-Translator: František Bartoš <frantisek.bartos@email.cz>\n"
"Language-Team: Czech <https://hosted.weblate.org/projects/turris/foris-js/cs/"
">\n"
"Language: cs\n"
@@ -17,7 +17,7 @@ msgstr ""
"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"
"X-Generator: Weblate 5.2.1-rc\n"
"X-Generator: Weblate 4.17-dev\n"
"Generated-By: Babel 2.11.0\n"
#: src/api/utils.js:61
@@ -79,7 +79,7 @@ msgstr "Nastavení Wi-Fi jsou uvedena do výchozího stavu."
#: src/common/WiFiSettings/ResetWiFiSettings.js:55
#: src/common/WiFiSettings/ResetWiFiSettings.js:69
msgid "Reset Wi-Fi Settings"
msgstr "Reset nastavení Wi-Fi"
msgstr "Resetovat nastavení Wi-Fi"
#: src/common/WiFiSettings/ResetWiFiSettings.js:57
msgid ""
@@ -105,6 +105,7 @@ msgid "Hide SSID"
msgstr "Skrýt SSID"
#: src/common/WiFiSettings/WiFiForm.js:186
#, fuzzy
msgid "802.11n/ac/ax mode"
msgstr "Režim 802.11n/ac/ax"
@@ -118,23 +119,22 @@ msgstr "Šifrování"
#: src/common/WiFiSettings/WiFiForm.js:226
msgid "Disable Management Frame Protection"
msgstr "Vypnout Management Frame Protection"
msgstr ""
#: src/common/WiFiSettings/WiFiForm.js:227
msgid ""
"In case you have trouble connecting to WiFi Access Point, try disabling "
"Management Frame Protection."
msgstr ""
"Máte-li problémy při připojování k přístupovému bodu Wi-Fi, zkuste vypnout "
"Management Frame Protection."
#: src/common/WiFiSettings/WiFiForm.js:262
msgid "auto"
msgstr "automaticky"
#: src/common/WiFiSettings/WiFiForm.js:303
#, fuzzy
msgid "Custom"
msgstr "Uživatelsky určené"
msgstr "automaticky"
#: src/common/WiFiSettings/WiFiGuestForm.js:42
msgid "Enable Guest Wi-Fi"
@@ -170,6 +170,7 @@ msgstr "Je třeba, aby heslo obsahovalo alespoň 8 znaků"
#: src/common/WiFiSettings/WiFiSettings.js:90
#: src/common/WiFiSettings/WiFiSettings.js:109
#, fuzzy
msgid "Password must not contain more than 63 symbols"
msgstr "Heslo nesmí obsahovat více než 63 znaků"
@@ -202,20 +203,24 @@ msgid "802.11ac - 160 MHz wide channel"
msgstr "802.11ac kanál šíře 160 MHz"
#: src/common/WiFiSettings/constants.js:16
#, fuzzy
msgid "802.11ax - 20 MHz wide channel"
msgstr "802.11ax kanál šíře 20 MHz"
msgstr "802.11ac kanál šíře 20 MHz"
#: src/common/WiFiSettings/constants.js:17
#, fuzzy
msgid "802.11ax - 40 MHz wide channel"
msgstr "802.11ax kanál šíře 40 MHz"
msgstr "802.11ac kanál šíře 40 MHz"
#: src/common/WiFiSettings/constants.js:18
#, fuzzy
msgid "802.11ax - 80 MHz wide channel"
msgstr "802.11ax kanál šíře 80 MHz"
msgstr "802.11ac kanál šíře 80 MHz"
#: src/common/WiFiSettings/constants.js:19
#, fuzzy
msgid "802.11ax - 160 MHz wide channel"
msgstr "802.11ax kanál šíře 160 MHz"
msgstr "802.11ac kanál šíře 160 MHz"
#: src/common/WiFiSettings/constants.js:26
msgid "WPA3 only"
@@ -223,7 +228,7 @@ msgstr "pouze WPA3"
#: src/common/WiFiSettings/constants.js:27
msgid "WPA3 with WPA2 as fallback (default)"
msgstr "WPA3, nouzově WPA2 (výchozí)"
msgstr ""
#: src/common/WiFiSettings/constants.js:28
msgid "WPA2 only"
@@ -238,8 +243,13 @@ msgstr ""
"problémy."
#: src/common/WiFiSettings/constants.js:34
#, fuzzy
msgid "WPA2/3 pre-shared key, that is required to connect to the network."
msgstr "Předsdílený klíč WPA2/3, který je vyžadován pro připojení se k síti."
msgstr ""
"\n"
" WPA2 předsdílený klíč, který je vyžadován pro připojení se k "
"síti.\n"
" "
#: src/common/WiFiSettings/constants.js:37
msgid "If set, network is not visible when scanning for available networks."
@@ -248,29 +258,38 @@ msgstr ""
"vyhledávat dostupné sítě."
#: src/common/WiFiSettings/constants.js:40
#, fuzzy
msgid ""
"The 2.4 GHz band is more widely supported by clients, but tends to have "
"more interference. The 5 GHz band is a newer standard and may not be "
"supported by all your devices. It usually has less interference, but the "
"signal does not carry so well indoors."
msgstr ""
"Pásmo 2,4 GHz je v klientských zařízeních podporováno nejčastěji, bývá ale "
"více zarušené. Pásmo 5 GHz je novější standard a nemusí být podporováno "
"všemi vámi používanými zařízeními. Obvykle bývá méně zarušené, signál se ale "
"hůře šíří uvnitř budov."
"\n"
" Pásmo 2,4 GHz je v klientských zařízeních podporováno nejčastěji,"
" ale bývá více zarušené. Pásmo 5 GHz je\n"
" novější standard a nemusí být podporováno všemi vámi používanými "
"zařízeními. Obvykle bývá méně zarušené,\n"
" ale signál se hůře šíři uvnitř budov."
#: src/common/WiFiSettings/constants.js:43
#, fuzzy
msgid ""
"Change this to adjust 802.11n/ac/ax mode of operation. 802.11n with 40 "
"MHz wide channels can yield higher throughput but can cause more "
"interference in the network. If you don't know what to choose, use the "
"default option with 20 MHz wide channel."
msgstr ""
"Změna tohoto parametru upraví režim fungování 802.11n/ac. 802.11n s kanály o "
"šíři 40 MHz může pomoci k vyšší propustnosti, je ale náchylnější na rušení. "
"Pokud nevíte co zvolit, použijte výchozí volbu s kanálem šíře 20 MHz."
"\n"
" Změna tohoto upraví režim fungování 802.11n/ac. 802.11n s kanály "
"o šíři 40 MHz kanály může pomoci k vyšší\n"
" propustnosti, ale je náchylnější na rušení. Pokud nevíte co "
"zvolit, použijte výchozí volbu s kanálem šíře\n"
" 20 MHz.\n"
" "
#: src/common/WiFiSettings/constants.js:46
#, fuzzy
msgid ""
"Enables Wi-Fi for guests, which is separated from LAN network. Devices "
"connected to this network are allowed to access the internet, but aren't "
@@ -278,10 +297,14 @@ msgid ""
"router. Parameters of the guest network can be set in the Guest network "
"tab."
msgstr ""
"Zapíná Wi-Fi pro hosty, která je oddělená od místní sítě (LAN). Zařízením "
"připojeným k této síti je umožněn přístup do Internetu, ale už ne na ostatní "
"zařízení a k rozhraní pro nastavování směrovače. Parametry sítě pro hosty je "
"možné nastavit na panelu „Síť pro hosty“."
"\n"
" Zapíná Wi-Fi pro hosty, která je oddělená od místní sítě (LAN). "
"Zařízením připojeným k této síti je umožněn\n"
" přístup do Internetu, ale už ne na ostatní zařízení a k rozhraní "
"pro nastavování směrovače.\n"
" Parametry sítě pro hosty je možné nastavit na panelu „Síť pro "
"hosty“.\n"
" "
#: src/common/WiFiSettings/constants.js:49
msgid ""
@@ -290,10 +313,6 @@ msgid ""
"without WPA3 support require older WPA2. If you experience issues with "
"connecting older devices, try to enable WPA2."
msgstr ""
"Standard WPA3 je nová nejbezpečnější metoda, již se doporučuje používat se "
"všemi zařízeními, která ji podporují. Starší zařízení bez podpory WPA3 "
"potřebují starší WPA2. Zaznamenáte-li problémy s připojováním starších "
"zařízení, zkuste zapnout WPA2."
#: src/form/components/ForisForm.js:121
msgid "Settings saved successfully"
@@ -338,6 +357,7 @@ msgid "This is not a valid domain name."
msgstr "Toto není platné doménové jméno."
#: src/utils/validations.js:17
#, fuzzy
msgid "This is not a valid hostname."
msgstr "Toto není platné doménové jméno."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2022-12-02 15:54+0100\n"
"PO-Revision-Date: 2024-01-04 21:08+0000\n"
"PO-Revision-Date: 2023-08-13 10:47+0000\n"
"Last-Translator: Erik Pfannenstein <debianignatz@gmx.de>\n"
"Language-Team: German <https://hosted.weblate.org/projects/turris/foris-js/"
"de/>\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.4-dev\n"
"X-Generator: Weblate 5.0-dev\n"
"Generated-By: Babel 2.11.0\n"
#: src/api/utils.js:61
@@ -89,9 +89,6 @@ msgid ""
"Fi settings. Note that this will remove the current Wi-Fi configuration "
"and restore the default values."
msgstr ""
"Falls die Anzahl der WLAN-Karten nicht korrekt ist, könnte es helfen, die "
"WLAN-Einstellungen zurückzusetzen. Beachten Sie, dass dabei die aktuelle "
"WLAN-Konfiguration mit den Werkseinstellungen überschrieben wird."
#: src/common/WiFiSettings/WiFiForm.js:95
msgid "Wi-Fi ${deviceID + 1}"

View File

@@ -8,16 +8,15 @@ msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2022-12-02 15:54+0100\n"
"PO-Revision-Date: 2024-01-04 21:08+0000\n"
"Last-Translator: powerburner-nl <peter.mulder.1981@gmail.com>\n"
"Language-Team: Dutch <https://hosted.weblate.org/projects/turris/foris-js/nl/"
">\n"
"PO-Revision-Date: 2020-11-29 19:29+0000\n"
"Last-Translator: Johan van de Wetering <mail@jvdwetering.nl>\n"
"Language: nl\n"
"Language-Team: Dutch <https://hosted.weblate.org/projects/turris/foris-"
"js/nl/>\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.4-dev\n"
"Generated-By: Babel 2.11.0\n"
#: src/api/utils.js:61
@@ -55,19 +54,19 @@ msgstr "Opnieuw opstarten"
#: src/common/RebootButton.js:66
msgid "Warning!"
msgstr "Waarschuwing!"
msgstr ""
#: src/common/RebootButton.js:68
msgid "Are you sure you want to restart the router?"
msgstr "Weet u zeker dat u de router opnieuw wilt opstarten?"
msgstr ""
#: src/common/RebootButton.js:71
msgid "Cancel"
msgstr "Annuleren"
msgstr ""
#: src/common/RebootButton.js:73
msgid "Confirm reboot"
msgstr "Opnieuw opstarten bevestigen"
msgstr ""
#: src/common/WiFiSettings/ResetWiFiSettings.js:38
msgid "An error occurred during resetting Wi-Fi settings."
@@ -419,3 +418,4 @@ msgstr "Bevat geen lijst met e-mails gescheiden door komma's."
#~ " default option with 20 MHz wide "
#~ "channel."
#~ msgstr ""