- Added multi-language support and a german translation

- Cleaned the code up
This commit is contained in:
Dorian Zedler 2018-08-14 17:07:42 +02:00
parent a18db2cc3a
commit fe6c62e9fc
15 changed files with 439 additions and 87 deletions

View File

@ -15,8 +15,7 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<manifest package="com.itsblue.speedclimbing_stopwatch" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="0.04" android:versionCode="4" android:installLocation="auto">
<manifest package="com.itsblue.speedclimbing_stopwatchtest" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="0.04" android:versionCode="4" android:installLocation="auto">
<application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="speedclimbing stw" android:icon="@drawable/icon">
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation" android:name="com.itsblue.speedclimbing_stopwatch.MainActivity" android:label="speedclimbing stw" android:screenOrientation="unspecified" android:launchMode="singleTop">
<intent-filter>

View File

@ -26,7 +26,7 @@ public:
double starttime;
bool connected;
int connection_progress;
QString buzz_url;
private:
QNetworkAccessManager *networkManager;

41
qml/BuzzerConn.qml Normal file
View File

@ -0,0 +1,41 @@
import QtQuick 2.0
Item {
id: buzzerConn
height: 0
width: 0
opacity: 0
visible: false
signal pushed()
Timer {
//timer that refreshes the connection state to the buzzer
id: connectionRefreshTimer
running: root.state !== "RUNNING" && root.state !== "STARTING"
repeat: false
interval: 1000
onTriggered: {
_cppBuzzerConn.refresh()
connectionRefreshTimer.start()
}
}
Timer {
id: running_refresh_timer
running: root.state === "RUNNING"
repeat: false
interval: 1
onTriggered: {
if(_cppBuzzerConn.buzzer_triggered()){
buzzerConn.pushed()
}
if(root.state === "RUNNING"){
running_refresh_timer.start()
}
}
}
}

View File

@ -167,21 +167,21 @@ Popup {
id: settings
Column {
property string title: "Options"
property string title: qsTr("Options")
id: settings_col
/*----Connect to buzzer----*/
ItemDelegate {
id: connect_del
width: parent.width
text: _cppBuzzerConn.get("connected")===1 ? "connected to buzzer":"connect to buzzer"
text: _cppBuzzerConn.get("connected")===1 ? qsTr("connected to buzzer"):qsTr("connect to buzzer")
font.pixelSize: options_stack.text_pixelSize
Timer {
running: connect_del.scale === 1
repeat: true
interval: 10
onTriggered: {
connect_del.text = _cppBuzzerConn.get("connected")===1 ? "connected to buzzer":"connect to buzzer"
connect_del.text = _cppBuzzerConn.get("connected")===1 ? qsTr("connected to buzzer"):qsTr("connect to buzzer")
}
}
@ -192,19 +192,19 @@ Popup {
prog.arcEnd = 0
prog.colorCircle = "grey"
prog.opacity = 1
prog.text = "connecting..."
prog.text = qsTr("connecting...")
prog_refresh.running = true
if(_cppBuzzerConn.connect()){
prog_refresh.running = false
prog.colorCircle = "green"
prog.text = "success!"
prog.text = qsTr("success")
prog.arcEnd = 360
}
else {
prog_refresh.running = false
prog.colorCircle = "red"
prog.text = "error!"
prog.text = qsTr("error")
prog.arcEnd = 360
}
@ -229,7 +229,7 @@ Popup {
/*----Automated Start----*/
ItemDelegate {
id: autostart_del
text: "start sequence"
text: qsTr("start sequence")
font.pixelSize: options_stack.text_pixelSize
width: parent.width
@ -288,7 +288,7 @@ Popup {
ItemDelegate {
id: ready_delay_del
text: "delay (ms)"
text: qsTr("delay (ms)")
enabled: ready_del.checked
width: parent.width
font.pixelSize: options_stack.text_pixelSize
@ -296,7 +296,7 @@ Popup {
TextField {
focus: true
placeholderText: "time"
placeholderText: qsTr("time")
width: parent.width * 0.3
height: parent.height
anchors.right: parent.right
@ -329,7 +329,7 @@ Popup {
ItemDelegate {
id: at_marks_delay_del
text: "delay (ms)"
text: qsTr("delay (ms)")
enabled: at_marks_del.checked
width: parent.width
height: parent.delegateHeight
@ -338,7 +338,7 @@ Popup {
TextField {
focus: true
placeholderText: "time"
placeholderText: qsTr("time")
width: parent.width * 0.3
height: parent.height
anchors.right: parent.right

View File

@ -44,7 +44,11 @@ Window {
property double buzzer_offset
property double last_button_pressed
property var last_run : {
'stopp_type': "", 'time': 0
};
//set default state to IDLE
state: "IDLE"
Timer {
@ -58,38 +62,10 @@ Window {
}
}
Timer {
//timer that refreshes the connection state to the buzzer
id: connectionRefreshTimer
running: root.state !== "RUNNING" && root.state !== "STARTING"
repeat: false
interval: 1000
onTriggered: {
_cppBuzzerConn.refresh()
connectionRefreshTimer.start()
}
}
Timer {
id: running_refresh_timer
running: root.state === "RUNNING"
repeat: false
interval: 1
onTriggered: {
if(_cppBuzzerConn.buzzer_triggered()){
//the buzzer was pushed
root.buzzer_offset = _cppBuzzerConn.get("offset")
root.last_button_pressed = _cppBuzzerConn.get("lastpressed")
root.stoppedTime = (root.last_button_pressed + root.buzzer_offset) - root.startTime
root.state = "STOPPED"
//time.text = ( root.stoppedTime / 1000 ).toFixed(3) + " sec"
console.log("STOPPED: "+root.stoppedTime)
}
if(root.state === "RUNNING"){
running_refresh_timer.start()
}
BuzzerConn {
onPushed: {
// the buzzer was pushed
root.stop("buzzer")
}
}
@ -192,11 +168,18 @@ Window {
//height: root.landscape() ? undefined:parent.height * 0.15
Label {
id: time
text: "Click start to start"
text: qsTr("Click start to start")
anchors.centerIn: parent
//font.pixelSize: root.landscape() ? parent.width * 0.1:parent.height * 0.3
elide: "ElideRight"
Behavior on text {
enabled: root.state !== "RUNNING"
FadeAnimation {
target: time
}
}
}
}
@ -238,12 +221,12 @@ Window {
}
/*----------------------
Start button
Start / Stop / Reset button
----------------------*/
Button {
id : startButt
text: "start"
text: qsTr("start")
property int size: root.landscape() ? parent.width * 0.5:parent.height * 0.5
anchors {
bottom: parent.bottom
@ -280,34 +263,24 @@ Window {
}
}
Behavior on text {
//animate a text change
enabled: true
FadeAnimation {
target: startButt_text
}
}
onClicked: {
switch(root.state) {
case "":
root.state = "IDLE"
case "IDLE":
root.state = "STARTING"
if(_cppAppSettings.loadSetting("at_marks_en") === "true"){
next_actionTimer.action = "at_marks"
next_actionTimer.interval = _cppAppSettings.loadSetting("at_marks_delay")>0 ? _cppAppSettings.loadSetting("at_marks_delay"):1
next_actionTimer.start()
return
}
if(_cppAppSettings.loadSetting("ready_en") === "true"){
next_actionTimer.action = "ready"
next_actionTimer.interval = _cppAppSettings.loadSetting("ready_delay")>0 ? _cppAppSettings.loadSetting("ready_delay"):1
next_actionTimer.start()
return
}
startSound.play()
root.start()
break
case "RUNNING":
root.stoppedTime = new Date().getTime() - root.startTime
time.text = ( root.stoppedTime / 1000 ).toFixed(3) + " sec"
root.state = "STOPPED"
root.stop("manual")
break
case "STOPPED":
root.state = "IDLE"
root.reset()
break
}
}
@ -343,7 +316,7 @@ Window {
RoundButton {
id: cancelButt
text: "cancel"
text: qsTr("cancel")
anchors {
right: startButt.right
bottom: startButt.bottom
@ -366,13 +339,7 @@ Window {
}
onClicked: {
root.stoppedTime = 0
time.text = "false start"
root.state = "STOPPED"
next_actionTimer.stop()
at_marksSound.stop()
readySound.stop()
startSound.stop()
root.stop("false")
}
Behavior on scale {
@ -537,7 +504,7 @@ Window {
State {
name: "IDLE"
//state for the start page
PropertyChanges { target: time; text: "Click start to start"; font.pixelSize: root.landscape() ? parent.width * 0.1:parent.height * 0.3; scale: 1 }
PropertyChanges { target: time; text: qsTr("Click start to start"); font.pixelSize: root.landscape() ? parent.width * 0.1:parent.height * 0.3; scale: 1 }
PropertyChanges {
target: time_container;
anchors.bottomMargin: root.landscape() ? undefined:parent.height * 0.1;
@ -546,7 +513,7 @@ Window {
PropertyChanges {
target: startButt;
enabled: true; text: "start";
enabled: true; text: qsTr("start");
size: root.landscape() ? parent.width * 0.5:parent.height * 0.5
anchors.bottomMargin: parent.height * 0.5 - startButt.height * 0.5
anchors.rightMargin: parent.width * 0.5 - startButt.width * 0.5
@ -556,7 +523,7 @@ Window {
State {
name: "STARTING"
//state for the start sequence
PropertyChanges { target: startButt; enabled: false; text: "starting...";
PropertyChanges { target: startButt; enabled: false; text: qsTr("starting...");
anchors.rightMargin: root.landscape() ? parent.width * 0.05:parent.width * 0.5 - startButt.width * 0.5 //put the button more to the right to hide the menu (only in landscape mode)
anchors.bottomMargin: root.landscape() ? parent.height * 0.5 - startButt.height * 0.5:parent.height * 0.1 //put the button lower to hide the menu (only in portrait mode)
}
@ -580,13 +547,14 @@ Window {
name: "STOPPED"
//state when the meassuring is over
PropertyChanges {
target: time; text: root.stoppedTime > 0 ? ( root.stoppedTime / 1000 ).toFixed(3) + " sec":"false start";
target: time;
text: root.stoppedTime > 0 ? ( root.stoppedTime / 1000 ).toFixed(3) + " sec":qsTr("false start");
font.pixelSize: root.landscape() ? parent.width * 0.15:parent.height * 0.1;
scale: 1
}
PropertyChanges {
target: startButt;
enabled: true; text: "reset";
enabled: true; text: qsTr("reset");
size: root.landscape() ? parent.height * 0.35:parent.height * 0.2;
anchors.bottomMargin: root.landscape() ? parent.height * 0.5 - startButt.height * 0.5:parent.height * 0.2 - startButt.height * 0.5
anchors.rightMargin: root.landscape() ? parent.height * 0.2 - startButt.height * 0.5:parent.width * 0.5 - startButt.width * 0.5
@ -613,7 +581,6 @@ Window {
Transition {
to: "IDLE"
NumberAnimation { properties: "size,rightMargin,height,width,bottomMargin,font.pixelSize"; easing.type: Easing.InOutQuad; duration: 700 }
FadeAnimation { target: time; fadeDuration_out: 1000; fadeDuration_in: 0}
},
Transition {
@ -628,5 +595,58 @@ Window {
function landscape(){
return(root.height < root.width)
}
/*----Functions to control the stopwatch----*/
function start(){
root.state = "STARTING"
if(_cppAppSettings.loadSetting("at_marks_en") === "true"){
next_actionTimer.action = "at_marks"
next_actionTimer.interval = _cppAppSettings.loadSetting("at_marks_delay")>0 ? _cppAppSettings.loadSetting("at_marks_delay"):1
next_actionTimer.start()
return
}
if(_cppAppSettings.loadSetting("ready_en") === "true"){
next_actionTimer.action = "ready"
next_actionTimer.interval = _cppAppSettings.loadSetting("ready_delay")>0 ? _cppAppSettings.loadSetting("ready_delay"):1
next_actionTimer.start()
return
}
startSound.play()
}
function stop(type){
switch(type){
case "buzzer":
//the buzzer was pushed
root.buzzer_offset = _cppBuzzerConn.get("offset")
root.last_button_pressed = _cppBuzzerConn.get("lastpressed")
root.stoppedTime = (root.last_button_pressed + root.buzzer_offset) - root.startTime
root.state = "STOPPED"
//time.text = ( root.stoppedTime / 1000 ).toFixed(3) + " sec"
console.log("STOPPED: "+root.stoppedTime)
break
case "manual":
//te stop button was pressed
root.stoppedTime = new Date().getTime() - root.startTime
time.text = ( root.stoppedTime / 1000 ).toFixed(3) + " sec"
root.state = "STOPPED"
break
case "false":
//the cancel button was pressed
root.stoppedTime = 0
time.text = "false start"
root.state = "STOPPED"
next_actionTimer.stop()
at_marksSound.stop()
readySound.stop()
startSound.stop()
break
}
}
function reset(){
root.state = "IDLE"
}
}
}

View File

@ -6,5 +6,6 @@
<file>ProgressCircle.qml</file>
<file>SettingsDialog.qml</file>
<file>SimpleIndicator.qml</file>
<file>BuzzerConn.qml</file>
</qresource>
</RCC>

View File

@ -15,5 +15,8 @@
<file>sounds/at_marks_2.wav</file>
<file>graphics/icons/buzzer_black.png</file>
<file>graphics/icons/ok_black.png</file>
<file>translations/german.ts</file>
<file>translations/de_DE.qm</file>
<file>translations/de_DE.ts</file>
</qresource>
</RCC>

View File

@ -25,6 +25,9 @@ BuzzerConn::BuzzerConn(QObject *parent) : QObject(parent)
this->date = new QDateTime;
this->latest_button_pressed = 0;
this->connected = false;
this->buzz_url = "https://api.itsblue.de/test/buzzerem.php";
// "http://192.168.4.1"
}
bool BuzzerConn::connect()
@ -81,7 +84,7 @@ bool BuzzerConn::calcoffset(QList<double> times)
QList<double> BuzzerConn::gettimes(int timeout)
{
QList<double> times;
ReturnData_t ret = senddata(this->networkManager, QUrl("http://192.168.4.1"), timeout);
ReturnData_t ret = senddata(this->networkManager, QUrl(this->buzz_url), timeout);
times.append(double(ret.status_code));
if(ret.status_code == 200){
@ -171,7 +174,7 @@ bool BuzzerConn::refresh()
return(false);
}
QList<double> times;
ReturnData_t ret = senddata(this->reloadNetworkManager, QUrl("http://192.168.4.1"), 1000);
ReturnData_t ret = senddata(this->reloadNetworkManager, QUrl(this->buzz_url), 1000);
times.append(double(ret.status_code));
if(ret.status_code == 200){

View File

@ -52,6 +52,7 @@
#include "headers/sqlprofilemodel.h"
#include "headers/buzzerconn.h"
#include "headers/appsettings.h"
#include <QTranslator>
static void connectToDatabase()
{
@ -100,6 +101,13 @@ int main(int argc, char *argv[])
qmlRegisterType<SqlProfileModel>("com.itsblue.speedclimbingstopwatch", 1, 0, "SqlProfileModel");
qmlRegisterType<SqlStorageModel>("com.itsblue.speedclimbingstopwatch", 1, 0, "SqlStorageModel");
//setup translation engine
//to the language of the system
//if the system language is not found the language is set to english
QTranslator translator;
translator.load(":/translations/"+QLocale::system().name()+".qm");
app.installTranslator(&translator);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())

View File

@ -36,6 +36,8 @@ RESOURCES += \
shared.qrc \
qml/qml.qrc
TRANSLATIONS = translations/de_DE.ts
# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =
@ -53,7 +55,8 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin
DISTFILES += \
android-sources/AndroidManifest.xml \
CHANGELOG \
android-sources/src/MainActivity.java
android-sources/src/MainActivity.java \
translations/german_de.ts
android {
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android-sources

BIN
translations/de_DE.qm Normal file

Binary file not shown.

108
translations/de_DE.ts Normal file
View File

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="de_DE" sourcelanguage="en">
<context>
<name>SettingsDialog</name>
<message>
<location filename="../qml/SettingsDialog.qml" line="170"/>
<source>Options</source>
<translation>Optionen</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="177"/>
<location filename="../qml/SettingsDialog.qml" line="184"/>
<source>connected to buzzer</source>
<translation>Mit Buzzer verbunden</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="177"/>
<location filename="../qml/SettingsDialog.qml" line="184"/>
<source>connect to buzzer</source>
<translation>Mit Buzzer verbinden</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="195"/>
<source>connecting...</source>
<translation>verbinde...</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="201"/>
<source>success!</source>
<translation>Erfolg</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="207"/>
<source>error!</source>
<translation>Fehler</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="232"/>
<source>start sequence</source>
<translation>Start Ablauf</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="275"/>
<source>say &apos;ready&apos;</source>
<translation>sage &apos;ready&apos;</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="291"/>
<location filename="../qml/SettingsDialog.qml" line="332"/>
<source>delay (ms)</source>
<translation>Verzögerung (ms)</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="299"/>
<location filename="../qml/SettingsDialog.qml" line="341"/>
<source>time</source>
<translation>Zeit</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="316"/>
<source>say
&apos;at your marks&apos;</source>
<translation>sage
&apos;at your marks&apos;</translation>
</message>
</context>
<context>
<name>main</name>
<message>
<location filename="../qml/main.qml" line="30"/>
<source>Speedclimbing stw</source>
<translation></translation>
</message>
<message>
<location filename="../qml/main.qml" line="195"/>
<location filename="../qml/main.qml" line="540"/>
<source>Click start to start</source>
<translation>Tippe start zum Starten</translation>
</message>
<message>
<location filename="../qml/main.qml" line="246"/>
<location filename="../qml/main.qml" line="549"/>
<source>start</source>
<translation>start</translation>
</message>
<message>
<location filename="../qml/main.qml" line="346"/>
<source>cancel</source>
<translation>Abbruch</translation>
</message>
<message>
<location filename="../qml/main.qml" line="559"/>
<source>starting...</source>
<translation>starte...</translation>
</message>
<message>
<location filename="../qml/main.qml" line="583"/>
<source>false start</source>
<translation>Fehlstart</translation>
</message>
<message>
<location filename="../qml/main.qml" line="589"/>
<source>reset</source>
<translation>reset</translation>
</message>
</context>
</TS>

58
translations/german.ts Normal file
View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
<context>
<name>SettingsDialog</name>
<message>
<location filename="../qml/SettingsDialog.qml" line="275"/>
<source>say &apos;ready&apos;</source>
<translation>fertig</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="316"/>
<source>say
&apos;at your marks&apos;</source>
<translation type="unfinished">auf die Plätze</translation>
</message>
</context>
<context>
<name>main</name>
<message>
<location filename="../qml/main.qml" line="30"/>
<source>Speedclimbing stw</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/main.qml" line="195"/>
<location filename="../qml/main.qml" line="540"/>
<source>Click start to start</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/main.qml" line="246"/>
<location filename="../qml/main.qml" line="549"/>
<source>start</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/main.qml" line="346"/>
<source>cancel</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/main.qml" line="559"/>
<source>starting...</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/main.qml" line="583"/>
<source>false start</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../qml/main.qml" line="589"/>
<source>reset</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

BIN
translations/german_de.qm Normal file

Binary file not shown.

108
translations/german_de.ts Normal file
View File

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="de_DE">
<context>
<name>SettingsDialog</name>
<message>
<location filename="../qml/SettingsDialog.qml" line="170"/>
<source>Options</source>
<translation>Einstellungen</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="177"/>
<location filename="../qml/SettingsDialog.qml" line="184"/>
<source>connected to buzzer</source>
<translation>Mit Buzzer verbunden</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="177"/>
<location filename="../qml/SettingsDialog.qml" line="184"/>
<source>connect to buzzer</source>
<translation>Mit Buzzer verbinden</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="195"/>
<source>connecting...</source>
<translation>verbinde...</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="201"/>
<source>success!</source>
<translation>erfolgreich!</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="207"/>
<source>error!</source>
<translation>fehler!</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="232"/>
<source>start sequence</source>
<translation>Start Abfolge</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="275"/>
<source>say &apos;ready&apos;</source>
<translation>sage &apos;ready&apos;</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="291"/>
<location filename="../qml/SettingsDialog.qml" line="332"/>
<source>delay (ms)</source>
<translation>Verzögerung (ms)</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="299"/>
<location filename="../qml/SettingsDialog.qml" line="341"/>
<source>time</source>
<translation>Zeit</translation>
</message>
<message>
<location filename="../qml/SettingsDialog.qml" line="316"/>
<source>say
&apos;at your marks&apos;</source>
<translation>sage
&apos;at your marks&apos;</translation>
</message>
</context>
<context>
<name>main</name>
<message>
<location filename="../qml/main.qml" line="30"/>
<source>Speedclimbing stw</source>
<translation></translation>
</message>
<message>
<location filename="../qml/main.qml" line="195"/>
<location filename="../qml/main.qml" line="540"/>
<source>Click start to start</source>
<translation>Tippe start zum Starten</translation>
</message>
<message>
<location filename="../qml/main.qml" line="246"/>
<location filename="../qml/main.qml" line="549"/>
<source>start</source>
<translation>start</translation>
</message>
<message>
<location filename="../qml/main.qml" line="346"/>
<source>cancel</source>
<translation>abbruch</translation>
</message>
<message>
<location filename="../qml/main.qml" line="559"/>
<source>starting...</source>
<translation>starte...</translation>
</message>
<message>
<location filename="../qml/main.qml" line="583"/>
<source>false start</source>
<translation>Fehlstart</translation>
</message>
<message>
<location filename="../qml/main.qml" line="589"/>
<source>reset</source>
<translation>reset</translation>
</message>
</context>
</TS>