summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/cmake.yml12
-rw-r--r--.github/workflows/linux-package.yml77
-rw-r--r--CMakeLists.txt2
-rw-r--r--README.md21
-rw-r--r--api/lang/de_DE.ts11
-rw-r--r--cmake/opentrack-hier.cmake10
-rw-r--r--cmake/opentrack-i18n.cmake5
-rw-r--r--compat/CMakeLists.txt4
-rw-r--r--compat/lang/de_DE.ts4
-rw-r--r--compat/process-list.hpp23
-rw-r--r--contrib-noinst/important-stuff/game-data.exebin0 -> 367104 bytes
-rw-r--r--csv/lang/de_DE.ts4
-rw-r--r--cv/lang/de_DE.ts4
-rw-r--r--filter-accela-hamilton/lang/de_DE.ts91
-rw-r--r--filter-accela/lang/de_DE.ts57
-rw-r--r--filter-ewma2/lang/de_DE.ts72
-rw-r--r--filter-hamilton/lang/de_DE.ts78
-rw-r--r--filter-nm/lang/de_DE.ts62
-rw-r--r--gui/lang/de_DE.ts428
-rw-r--r--logic/lang/de_DE.ts64
-rw-r--r--migration/lang/de_DE.ts4
-rw-r--r--opentrack/lang/de_DE.ts193
-rw-r--r--options/lang/de_DE.ts4
-rw-r--r--pose-widget/lang/de_DE.ts4
-rw-r--r--proto-flightgear/lang/de_DE.ts37
-rw-r--r--proto-libevdev/ftnoir_protocol_libevdev.cpp5
-rw-r--r--proto-libevdev/lang/de_DE.ts37
-rw-r--r--proto-udp/lang/de_DE.ts37
-rw-r--r--proto-wine/ftnoir_protocol_wine.cpp100
-rw-r--r--proto-wine/ftnoir_protocol_wine.h14
-rw-r--r--proto-wine/ftnoir_protocol_wine_dialog.cpp144
-rw-r--r--proto-wine/ftnoir_winecontrols.ui305
-rw-r--r--proto-wine/lang/de_DE.ts140
-rw-r--r--proto-wine/lang/nl_NL.ts44
-rw-r--r--proto-wine/lang/ru_RU.ts44
-rw-r--r--proto-wine/lang/stub.ts44
-rw-r--r--proto-wine/lang/zh_CN.ts44
-rw-r--r--proto-wine/proton.cpp33
-rw-r--r--proto-wine/proton.h7
-rw-r--r--qxt-mini/lang/de_DE.ts4
-rw-r--r--spline/lang/de_DE.ts4
-rw-r--r--tracker-easy/lang/de_DE.ts250
-rw-r--r--tracker-freepie-udp/lang/de_DE.ts86
-rw-r--r--tracker-fusion/lang/de_DE.ts56
-rw-r--r--tracker-linux-joystick/lang/de_DE.ts86
-rw-r--r--tracker-neuralnet/CMakeLists.txt2
-rw-r--r--tracker-neuralnet/ftnoir_tracker_neuralnet.cpp43
-rw-r--r--tracker-neuralnet/ftnoir_tracker_neuralnet.h12
-rw-r--r--tracker-neuralnet/lang/de_DE.ts172
-rw-r--r--tracker-neuralnet/models/head-pose-0.3-big-quantized.onnx (renamed from tracker-neuralnet/models/head-pose.onnx)bin13047683 -> 11385815 bytes
-rw-r--r--tracker-pt/lang/de_DE.ts378
-rw-r--r--tracker-pt/module/lang/de_DE.ts11
-rw-r--r--tracker-s2bot/lang/de_DE.ts90
-rw-r--r--tracker-test/lang/de_DE.ts22
-rw-r--r--tracker-udp/lang/de_DE.ts65
-rw-r--r--video-opencv/impl-camera.cpp2
-rw-r--r--video-opencv/lang/de_DE.ts4
-rw-r--r--video/lang/de_DE.ts4
58 files changed, 3281 insertions, 279 deletions
diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml
index 57f21bf4..fc53f6d7 100644
--- a/.github/workflows/cmake.yml
+++ b/.github/workflows/cmake.yml
@@ -43,7 +43,7 @@ jobs:
- name: Install Linux Dependencies
run: |
sudo apt-get update
- sudo apt-get install libprocps-dev libopencv-dev libopencv-dev wine64-tools
+ sudo apt-get install libproc2-dev libopencv-dev libopencv-dev wine64-tools
sudo apt-get install qttools5-dev qtbase5-dev libqt5serialport5-dev qtbase5-private-dev
if: matrix.os == 'ubuntu-latest'
@@ -59,8 +59,8 @@ jobs:
- name: Build
run: ${{matrix.cmake}} --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --target install
- - name: Upload build
- uses: actions/upload-artifact@v3
- with:
- name: buildoutput
- path: ${{github.workspace}}/build/
+# - name: Upload build
+# uses: actions/upload-artifact@v3
+# with:
+# name: buildoutput
+# path: ${{github.workspace}}/build/
diff --git a/.github/workflows/linux-package.yml b/.github/workflows/linux-package.yml
new file mode 100644
index 00000000..bc622b6f
--- /dev/null
+++ b/.github/workflows/linux-package.yml
@@ -0,0 +1,77 @@
+name: Linuax Package
+on:
+ push:
+ tags:
+ - 'opentrack-*'
+ workflow_dispatch:
+env:
+ build_type: Release
+ onnx_version: 1.21.0
+ onnx_prefix: onnxruntime-linux-x64
+ file_name: '' # to disable warning in case of a linter
+ Qt5_DIR: '' # to disable warning in case of a linter
+jobs:
+ Package:
+ runs-on: ubuntu-22.04
+ steps:
+ - name: Clone opentrack/opentrack
+ uses: actions/checkout@v4
+ - name: Clone opentrack/depends
+ uses: actions/checkout@v4
+ with:
+ repository: opentrack/opentrack-depends
+ submodules: true
+ path: opentrack-depends
+
+ - name: Install Dependencies
+ run: |
+ sudo apt-get update
+ sudo apt-get install libprocps-dev libopencv-dev wine64-tools
+ wget -q https://github.com/microsoft/onnxruntime/releases/download/v${{env.onnx_version}}/${{env.onnx_prefix}}-${{env.onnx_version}}.tgz
+ tar xzf ${{env.onnx_prefix}}-${{env.onnx_version}}.tgz
+ - name: Install Qt
+ uses: jurplel/install-qt-action@v4
+ with:
+ version: 5.15
+ archives: icu qtbase qttools qtserialport
+
+ - name: Configure and Build
+ run: |
+ cmake -S . -B build \
+ -DCMAKE_BUILD_TYPE=${{env.build_type}} \
+ -DONNXRuntime_DIR=${{env.onnx_prefix}}-${{env.onnx_version}} \
+ -DQt5_DIR=${{env.Qt5_DIR}}
+ cmake --build build --config ${{env.build_type}} --target install -- -j $(nproc)
+
+ - name: Pack
+ run: |
+ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(pwd)/${{env.onnx_prefix}}-${{env.onnx_version}}/lib
+
+ # required by linuxdeployqt
+ sudo apt-get install libfuse2
+ wget -q https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage
+ chmod +x linuxdeployqt-*.AppImage
+ cd build/install/
+ ln -s $(pwd)/libexec/opentrack $(pwd)/lib
+ ../../linuxdeployqt-*.AppImage bin/opentrack -bundle-non-qt-libs -unsupported-allow-new-glibc
+ rm lib
+
+ echo '#!/bin/sh' >> opentrack
+ echo 'CURRENT_PATH="$(dirname "$(readlink -f "$0")")"' >> opentrack
+ echo 'export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$CURRENT_PATH/libexec/opentrack' >> opentrack
+ echo '"$CURRENT_PATH/bin/opentrack" "$@"' >> opentrack
+ chmod +x opentrack
+
+ if [[ ${{github.ref_name}} =~ ^opentrack.*$ ]]; then
+ file_name=${{github.ref_name}}-linux.tar.gz
+ else
+ file_name=opentrack-dev-linux.tar.gz
+ fi
+ echo "file_name=$file_name" >> $GITHUB_ENV
+
+ tar czf ../../$file_name .
+ - name: Upload
+ uses: actions/upload-artifact@v4
+ with:
+ name: ${{env.file_name}}
+ path: ${{env.file_name}}
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 18dd48cd..c28ead74 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -66,7 +66,7 @@ include(opentrack-mrproper)
set_property(GLOBAL PROPERTY opentrack-all-modules "")
set_property(GLOBAL PROPERTY opentrack-all-source-dirs "")
-set(opentrack_all-translations "nl_NL;ru_RU;stub;zh_CN")
+set(opentrack_all-translations "de_DE;nl_NL;ru_RU;stub;zh_CN")
include(opentrack-hier)
include(opentrack-platform)
diff --git a/README.md b/README.md
index 35a52d88..f04200b4 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,10 @@
+[<img src="https://github.com/opentrack/opentrack/actions/workflows/cmake.yml/badge.svg">](https://github.com/opentrack/opentrack/actions/workflows/cmake.yml)
+
## Intro
-[<img src="https://github.com/opentrack/opentrack/actions/workflows/cmake.yml/badge.svg">](https://github.com/opentrack/opentrack/actions/workflows/cmake.yml)
+opentrack is a program for tracking user's head rotation and transmitting it to flight simulation software and military-themed video games. Project home is located at <<https://github.com/opentrack/opentrack>>.
-opentrack project home is located at <<http://github.com/opentrack/opentrack>>.
+Looking for **railway planning software**? <<https://opentrack.ch>> had the name `opentrack` first. Apologies for the long-standing naming conflict.
For the latest **downloads** visit <<https://github.com/opentrack/opentrack/releases>> Download an `.exe` installer or a `.7z` archive. Currently installers and portable versions for Windows are available for each release. It supports [USB stick truly "portable" installations](https://github.com/opentrack/opentrack/wiki/portable-mode-for-USB-sticks)
@@ -10,10 +12,6 @@ Please first refer to <<https://github.com/opentrack/opentrack/wiki>>
for [new user guide](https://github.com/opentrack/opentrack/wiki/Quick-Start-Guide-(WIP)), [frequent answers](https://github.com/opentrack/opentrack/wiki/common-issues), specific tracker/filter
documentation. See also the [gameplay video](https://www.youtube.com/watch?v=XI73ul_FnBI) with opentrack set up.
-## Looking for railway planning software?
-
-**Railway planning software** <<http://opentrack.ch>> had the name `opentrack` first. Apologies for the long-standing naming conflict.
-
## Usage
`opentrack` is an application dedicated to tracking user's head
@@ -28,17 +26,16 @@ Don't be afraid to submit an **issue/feature request** if you have any problems!
- PointTracker by Patrick Ruoff, FreeTrack-like light points
- Oculus Rift (Windows only)
-- Paper [marker](https://github.com/opentrack/opentrack/wiki/Aruco-tracker)
- via the Aruco<sup>[[1](https://github.com/opentrack/aruco)</sup> library
+- Paper [marker](https://github.com/opentrack/opentrack/wiki/Aruco-tracker) via the Aruco<sup>[[1](https://github.com/opentrack/aruco)]</sup> library
- Razer Hydra
- Relaying via UDP from a different computer
-- Relaying UDP via the FreePIE<sup>[[1](https://andersmalmgren.github.io/FreePIE/)</sup> Android [apps](https://github.com/opentrack/opentrack/tree/master/contrib/freepie-udp)
+- Relaying UDP via the FreePIE<sup>[[1](https://andersmalmgren.github.io/FreePIE/)]</sup> Android [apps](https://github.com/opentrack/opentrack/tree/master/contrib/freepie-udp)
- Joystick analog axes (Windows)
- Windows Phone [tracker](https://github.com/ZanderAdam/OpenTrack.WindowsPhone/wiki) over opentrack UDP protocol
- Arduino with custom Hatire firmware
- Intel RealSense 3D camera (Windows)
- BBC micro:bit, LEGO, sensortag support via Smalltalk<sup>[(1)](https://en.wikipedia.org/wiki/Smalltalk)[(2)](https://en.wikipedia.org/wiki/Alan_Kay)</sup>
- [S2Bot](http://www.picaxe.com/Teaching/Other-Software/Scratch-Helper-Apps/)
+ [S2Bot](https://www.picaxe.com/Teaching/Other-Software/Scratch-Helper-Apps/)
- Wiimote (Windows)
- NeuralNet face tracker
- Eyeware Beam<sup>[[1](https://beam.eyeware.tech/)]</sup>
@@ -60,7 +57,7 @@ Don't be afraid to submit an **issue/feature request** if you have any problems!
## Credits, in chronological order
- Stanisław Halik (maintainer)
-- Wim Vriend -- author of [FaceTrackNoIR](http://facetracknoir.sourceforge.net/) that served as the initial codebase for `opentrack`. While the code was almost entirely rewritten, we still hold on to many of `FaceTrackNoIR`'s ideas.
+- Wim Vriend -- author of [FaceTrackNoIR](https://facetracknoir.sourceforge.net/) that served as the initial codebase for `opentrack`. While the code was almost entirely rewritten, we still hold on to many of `FaceTrackNoIR`'s ideas.
- Chris Thompson (aka mm0zct, Rift and Razer Hydra author and maintainer)
- Patrick Ruoff (PT tracker author)
- Xavier Hallade (Intel RealSense tracker author and maintainer)
@@ -93,6 +90,8 @@ Don't be afraid to submit an **issue/feature request** if you have any problems!
See guides for writing new modules\[[1](https://github.com/opentrack/opentrack/blob/master/api/plugin-api.hpp)\]\[[2](https://github.com/opentrack/opentrack/blob/master/tracker-test/test.h)\], and for [working with core code](https://github.com/opentrack/opentrack/wiki/Hacking-opentrack).
+To edit the wiki, send pull requests to the [opentrack/wiki](https://github.com/opentrack/wiki) repository. The [user-facing wiki](https://github.com/opentrack/opentrack/wiki) will automatically update itself once the commit is merged.
+
## License and warranty
Almost all code is licensed under the [ISC license](https://en.wikipedia.org/wiki/ISC_license). There are very few proprietary dependencies. There is no copyleft code. See individual files for licensing and authorship information.
diff --git a/api/lang/de_DE.ts b/api/lang/de_DE.ts
new file mode 100644
index 00000000..688fe72b
--- /dev/null
+++ b/api/lang/de_DE.ts
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>module_status_mixin</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>Unbekannter Fehler</translation>
+ </message>
+</context>
+</TS>
diff --git a/cmake/opentrack-hier.cmake b/cmake/opentrack-hier.cmake
index 0d558d0d..bb1a435d 100644
--- a/cmake/opentrack-hier.cmake
+++ b/cmake/opentrack-hier.cmake
@@ -14,7 +14,7 @@ if(APPLE)
set(opentrack-runtime-libexec "/Plugins/") # MUST HAVE A TRAILING BACKSLASH, Used in APP
set(opentrack-runtime-doc "/") # MUST HAVE A TRAILING BACKSLASH
set(opentrack-bin "${CMAKE_INSTALL_PREFIX}")
- set(opentrack-doc "./doc")
+ set(opentrack-doc "doc")
set(opentrack-i18n "opentrack.app/Contents/Resources") # used during install
set(opentrack-runtime-i18n "../Resources/i18n") # used in application
set(opentrack-install-rpath "${CMAKE_INSTALL_PREFIX}/Library")
@@ -23,8 +23,8 @@ elseif(WIN32)
set(opentrack-runtime-libexec "/${opentrack-libexec}/") # MUST HAVE A TRAILING BACKSLASH
set(opentrack-runtime-doc "/doc/") # MUST HAVE A TRAILING BACKSLASH
set(opentrack-bin ".")
- set(opentrack-doc "./doc")
- set(opentrack-i18n "./i18n")
+ set(opentrack-doc "doc")
+ set(opentrack-i18n "i18n")
set(opentrack-runtime-i18n "./i18n")
set(opentrack-debug "./debug")
set(opentrack-install-rpath "")
@@ -33,9 +33,9 @@ else()
set(opentrack-runtime-libexec "/../${opentrack-libexec}/") # MUST HAVE A TRAILING BACKSLASH
set(opentrack-runtime-doc "/../share/doc/opentrack/") # MUST HAVE A TRAILING BACKSLASH
set(opentrack-bin "bin")
- set(opentrack-doc "./share/doc/opentrack")
+ set(opentrack-doc "share/doc/opentrack")
set(opentrack-install-rpath "${CMAKE_INSTALL_PREFIX}/${opentrack-libexec}")
- set(opentrack-i18n "./share/opentrack/i18n")
+ set(opentrack-i18n "share/opentrack/i18n")
set(opentrack-runtime-i18n "../share/opentrack/i18n")
endif()
diff --git a/cmake/opentrack-i18n.cmake b/cmake/opentrack-i18n.cmake
index 6c424017..1f0c67d9 100644
--- a/cmake/opentrack-i18n.cmake
+++ b/cmake/opentrack-i18n.cmake
@@ -58,7 +58,8 @@ endfunction()
function(otr_merge_translations)
otr_escape_string(i18n-pfx "${opentrack-i18n}")
- install(CODE "file(REMOVE_RECURSE \"\${CMAKE_INSTALL_PREFIX}/${i18n-pfx}\")")
+ #install(CODE "message(FATAL_ERROR \"foo \${CMAKE_INSTALL_PREFIX}\")")
+ #install(CODE "file(REMOVE_RECURSE \"\${CMAKE_INSTALL_PREFIX}/${i18n-pfx}\")")
foreach(i ${opentrack_all-translations})
get_property(ts-files GLOBAL PROPERTY "opentrack-ts-files-${i}")
@@ -90,7 +91,7 @@ function(otr_merge_translations)
add_dependencies(i18n-lrelease ${target-name})
install(FILES "${qm-output}"
- DESTINATION "${CMAKE_INSTALL_PREFIX}/${opentrack-i18n}"
+ DESTINATION "${opentrack-i18n}"
PERMISSIONS ${opentrack-perms-file})
endforeach()
endfunction()
diff --git a/compat/CMakeLists.txt b/compat/CMakeLists.txt
index fb498fb6..dc81436d 100644
--- a/compat/CMakeLists.txt
+++ b/compat/CMakeLists.txt
@@ -1,7 +1,3 @@
-if(CMAKE_COMPILER_IS_GNUCXX)
- add_compile_options(-fno-lto -fno-fast-math -fno-finite-math-only -O0)
-endif()
-
otr_module(compat NO-COMPAT BIN)
if(NOT WIN32 AND NOT APPLE)
diff --git a/compat/lang/de_DE.ts b/compat/lang/de_DE.ts
new file mode 100644
index 00000000..1552582e
--- /dev/null
+++ b/compat/lang/de_DE.ts
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+</TS>
diff --git a/compat/process-list.hpp b/compat/process-list.hpp
index 6d960610..39e12603 100644
--- a/compat/process-list.hpp
+++ b/compat/process-list.hpp
@@ -52,7 +52,7 @@ static QStringList get_all_executable_names()
template<typename = void>
static QStringList get_all_executable_names()
{
- QStringList ret;
+ QStringList ret; ret.reserve(2048);
std::vector<int> vec;
while (true)
@@ -138,19 +138,32 @@ static QStringList get_all_executable_names()
template<typename = void>
QStringList get_all_executable_names()
{
- QStringList ret;
+ QStringList ret; ret.reserve(2048);
enum pids_item items[] = { PIDS_ID_PID, PIDS_CMD, PIDS_CMDLINE_V };
enum rel_items { rel_pid, rel_cmd, rel_cmdline };
struct pids_info *info = NULL;
struct pids_stack *stack;
- QString tmp; tmp.reserve(64);
+ QString tmp; tmp.reserve(255);
procps_pids_new(&info, items, 3);
+ // procps-ng version 4.0.5 removed an unused argument in PIDS_VAL() macro.
+ // cf. https://gitlab.com/procps-ng/procps/-/commit/967fdcfb06e20aad0f3
+
+ // Although the emitted machine code is identical, backward API
+ // compatibility was silently broken in the patch with no upgrade path
+ // (e.g. deprecating PIDS_VAL() while introducing PIDS_VAL2()).
+
+ // Unfortunately, procps-ng doesn't include a #define for identifying its
+ // version. For these reasons the code below depends on undocumented ABI
+ // compatibility between procps-ng versions.. -sh 20241226
+
+#define OPENTRACK_PIDS_VAL(i, type, stack) stack->head[i].result.type
+
while ((stack = procps_pids_get(info, PIDS_FETCH_TASKS_ONLY)))
{
- char **p_cmdline = PIDS_VAL(rel_cmdline, strv, stack, info);
+ char **p_cmdline = OPENTRACK_PIDS_VAL(rel_cmdline, strv, stack);
// note, wine sets argv[0] so no parsing like in OSX case
if (p_cmdline && p_cmdline[0] && p_cmdline[0][0] &&
@@ -177,7 +190,7 @@ QStringList get_all_executable_names()
template<typename = void>
QStringList get_all_executable_names()
{
- QStringList ret;
+ QStringList ret; ret.reserve(2048);
proc_t** procs = readproctab(PROC_FILLCOM);
if (procs == nullptr)
{
diff --git a/contrib-noinst/important-stuff/game-data.exe b/contrib-noinst/important-stuff/game-data.exe
new file mode 100644
index 00000000..4e43a540
--- /dev/null
+++ b/contrib-noinst/important-stuff/game-data.exe
Binary files differ
diff --git a/csv/lang/de_DE.ts b/csv/lang/de_DE.ts
new file mode 100644
index 00000000..1552582e
--- /dev/null
+++ b/csv/lang/de_DE.ts
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+</TS>
diff --git a/cv/lang/de_DE.ts b/cv/lang/de_DE.ts
new file mode 100644
index 00000000..1552582e
--- /dev/null
+++ b/cv/lang/de_DE.ts
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+</TS>
diff --git a/filter-accela-hamilton/lang/de_DE.ts b/filter-accela-hamilton/lang/de_DE.ts
new file mode 100644
index 00000000..1a27c27b
--- /dev/null
+++ b/filter-accela-hamilton/lang/de_DE.ts
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>AccelaUICdialog_accela</name>
+ <message>
+ <source>Filter settings</source>
+ <translation>Filter-Einstellungen</translation>
+ </message>
+ <message>
+ <source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;Ubuntu&apos;; font-size:10pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p align=&quot;center&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Accela + Hamilton Filter&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;For both rotations and positions: No movement occurs within the dead zone.&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;For larger movements, rotation and translation occurs toward the new measurement. The strength is determined by the Smoothing setting and the builtin Accela gain curves.&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;When you lean forward, smoothing is added up to the set maximum at the distance of Max Z.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;Ubuntu&apos;; font-size:10pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p align=&quot;center&quot; style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Accela + Hamilton Filter&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Für Rotation und Position: Es erfolgt keine Bewegung innerhalb des Totbereichs.&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Bei größeren Bewegungen erfolgen Rotation und Übersetzung zugunsten der neuen Messung. Die Stärke wird durch die Glättungseinstellung und die vorgegebenen Accela-Verstärkungskurven bestimmt.&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Beim Vorbeugen wird eine Glättung bis zum eingestellten Maximum der Distanz Max Z hinzugefügt.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <source>Rotation Smoothing (Added when zoomed)</source>
+ <translation>Rotationsglättung (hinzugefügt beim Zoomen)</translation>
+ </message>
+ <message>
+ <source>Max Added</source>
+ <translation>Maximal hinzugefügt</translation>
+ </message>
+ <message>
+ <source>0° </source>
+ <translation>0° </translation>
+ </message>
+ <message>
+ <source>0mm</source>
+ <translation>0 mm</translation>
+ </message>
+ <message>
+ <source>Max Z</source>
+ <translation>Maximales Z</translation>
+ </message>
+ <message>
+ <source>Position filtering (X, Y, Z - translation)</source>
+ <translation>Positionsfilterung (X, Y, Z-Übersetzung)</translation>
+ </message>
+ <message>
+ <source>Smoothing</source>
+ <translation>Glättung</translation>
+ </message>
+ <message>
+ <source>Deadzone</source>
+ <translation>Totbereich</translation>
+ </message>
+ <message>
+ <source>Rotation filtering (Yaw, pitch, and roll)</source>
+ <translation>Rotationsfilterung (Gieren, Nicken und Rollen)</translation>
+ </message>
+ <message>
+ <source>0°</source>
+ <translation>0°</translation>
+ </message>
+</context>
+<context>
+ <name>accela_hamiltonDll</name>
+ <message>
+ <source>AccelaHamilton</source>
+ <translation>AccelaHamilton</translation>
+ </message>
+</context>
+<context>
+ <name>dialog_accela_hamilton</name>
+ <message>
+ <source>%1°</source>
+ <translation>%1°</translation>
+ </message>
+ <message>
+ <source>%1mm</source>
+ <translation>%1 mm</translation>
+ </message>
+</context>
+</TS>
diff --git a/filter-accela/lang/de_DE.ts b/filter-accela/lang/de_DE.ts
new file mode 100644
index 00000000..9ab4e8c5
--- /dev/null
+++ b/filter-accela/lang/de_DE.ts
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>AccelaUICdialog_accela</name>
+ <message>
+ <source>Filter settings</source>
+ <translation>Filter-Einstellungen</translation>
+ </message>
+ <message>
+ <source>Rotation filtering (Yaw, pitch, and roll)</source>
+ <translation>Rotationsfilterung (Gieren, Nicken und Rollen)</translation>
+ </message>
+ <message>
+ <source>Smoothing</source>
+ <translation>Glättung</translation>
+ </message>
+ <message>
+ <source>0°</source>
+ <translation>0°</translation>
+ </message>
+ <message>
+ <source>Deadzone</source>
+ <translation>Totbereich</translation>
+ </message>
+ <message>
+ <source>Position filtering (X, Y, Z - translation)</source>
+ <translation>Positionsfilterung (X, Y, Z-Übersetzung)</translation>
+ </message>
+ <message>
+ <source>0mm</source>
+ <translation>0 mm</translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;right&quot;&gt;&lt;br/&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Accela by &lt;/span&gt;&lt;a href=&quot;https://github.com/sthalik&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0057ae;&quot;&gt;Stanisław Halik&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;&lt;br/&gt;Thanks to &lt;/span&gt;&lt;a href=&quot;https://github.com/dbaarda&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0057ae;&quot;&gt;Donovan Baarda&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p align=&quot;right&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;2012-2017&lt;/span&gt;&lt;/p&gt;&lt;p align=&quot;right&quot;&gt;&lt;br/&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;Visit &lt;/span&gt;&lt;a href=&quot;https://github.com/opentrack/opentrack/wiki/Accela-in-opentrack-2.3&quot;&gt;&lt;span style=&quot; font-size:8pt; text-decoration: underline; color:#0000ff;&quot;&gt;our wiki&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt; for description of the settings.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;right&quot;&gt;&lt;br/&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Accela by &lt;/span&gt;&lt;a href=&quot;https://github.com/sthalik&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0057ae;&quot;&gt;Stanisław Halik&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;&lt;br/&gt;Thanks to &lt;/span&gt;&lt;a href=&quot;https://github.com/dbaarda&quot;&gt;&lt;span style=&quot; font-size:10pt; text-decoration: underline; color:#0057ae;&quot;&gt;Donovan Baarda&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;p align=&quot;right&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;2012-2017&lt;/span&gt;&lt;/p&gt;&lt;p align=&quot;right&quot;&gt;&lt;br/&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;In &lt;/span&gt;&lt;a href=&quot;https://github.com/opentrack/opentrack/wiki/Accela-in-opentrack-2.3&quot;&gt;&lt;span style=&quot; font-size:8pt; text-decoration: underline; color:#0000ff;&quot;&gt;unserem Wiki&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt; gibt es eine Beschreibung der Einstellungen.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>accelaDll</name>
+ <message>
+ <source>Accela</source>
+ <translation>Accela</translation>
+ </message>
+</context>
+<context>
+ <name>dialog_accela</name>
+ <message>
+ <source>%1°</source>
+ <translation>%1°</translation>
+ </message>
+ <message>
+ <source>%1mm</source>
+ <translation>%1 mm</translation>
+ </message>
+</context>
+</TS>
diff --git a/filter-ewma2/lang/de_DE.ts b/filter-ewma2/lang/de_DE.ts
new file mode 100644
index 00000000..be6712e6
--- /dev/null
+++ b/filter-ewma2/lang/de_DE.ts
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>UICdialog_ewma</name>
+ <message>
+ <source>EWMA filter settings</source>
+ <translation>EWMA-Filtereinstellungen</translation>
+ </message>
+ <message>
+ <source>Max</source>
+ <translation>Maximum</translation>
+ </message>
+ <message>
+ <source>Min</source>
+ <translation>Minimum</translation>
+ </message>
+ <message>
+ <source>Curve</source>
+ <translation>Kurve</translation>
+ </message>
+ <message>
+ <source>100%</source>
+ <translation>100%</translation>
+ </message>
+ <message>
+ <source>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;Sans Serif&apos;; font-size:10pt; font-weight:600;&quot;&gt;Give the filter a few seconds to warm up and stop shaking.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Min:&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Defines the way the filter responds to fast movements;&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Higher value: slower response;&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Max:&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Defines the way the filter responds to slow movements;&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Higher value: slower response;&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Pow:&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Defines the filters &apos;readiness&apos; to respond to speed changes;&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Higher value = &lt;/span&gt;&lt;span style=&quot; font-size:10pt; font-weight:600;&quot;&gt;faster&lt;/span&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; response;&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:&apos;MS Shell Dlg 2&apos;; font-size:8pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:&apos;Sans Serif&apos;; font-size:10pt; font-weight:600;&quot;&gt;Bitte einige Sekunden warten, bis der Filter warm gelaufen ist und nicht mehr zittert.&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Minimum:&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Definiert, wie der Filter auf schnelle Bewegungen reagiert;&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Höherer Wert: langsameres Ansprechen;&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Maximum:&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Definiert, wie der Filter auf langsame Bewegungen reagiert;&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Höherer Wert: langsameres Ansprechen;&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Stärke:&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Definiert die &apos;Bereitschaft&apos; des Filters, auf Geschwindigkeitsänderungen zu reagieren;&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt;Höherer Wert = &lt;/span&gt;&lt;span style=&quot; font-size:10pt; font-weight:600;&quot;&gt;schnelleres&lt;/span&gt;&lt;span style=&quot; font-size:10pt;&quot;&gt; Ansprechen;&lt;/span&gt;&lt;/p&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>ewmaDll</name>
+ <message>
+ <source>EWMA</source>
+ <translation>EWMA</translation>
+ </message>
+</context>
+</TS>
diff --git a/filter-hamilton/lang/de_DE.ts b/filter-hamilton/lang/de_DE.ts
new file mode 100644
index 00000000..6ea1f913
--- /dev/null
+++ b/filter-hamilton/lang/de_DE.ts
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>UICdialog_hamilton</name>
+ <message>
+ <source>Hamilton filter settings</source>
+ <translation>Hamilton-Filtereinstellungen</translation>
+ </message>
+ <message>
+ <source>Rotations: </source>
+ <translation>Rotationen: </translation>
+ </message>
+ <message>
+ <source>2,00</source>
+ <translation>2,00</translation>
+ </message>
+ <message>
+ <source>Smoothing power:</source>
+ <translation>Glättungsstärke:</translation>
+ </message>
+ <message>
+ <source>Dead Zone:</source>
+ <translation>Totbereich:</translation>
+ </message>
+ <message>
+ <source>0,01</source>
+ <translation>0,01</translation>
+ </message>
+ <message>
+ <source>Max distance:</source>
+ <translation>Maximale Distanz:</translation>
+ </message>
+ <message>
+ <source>10,00</source>
+ <translation>10,00</translation>
+ </message>
+ <message>
+ <source>For both rotations and positions: No movement occurs within the dead zone. Smoothing scales down to minimum at max distance + 2 x dead zone.</source>
+ <translation>Für alle Rotationen und Positionen: Es findet keine Bewegung innerhalb des Totbereichs statt. Die Glättung skaliert bis zum Minimum an der maximalen Distanz + 2x der Totbereich.</translation>
+ </message>
+ <message>
+ <source>Positions: </source>
+ <translation>Positionen: </translation>
+ </message>
+ <message>
+ <source>1,00</source>
+ <translation>1,00</translation>
+ </message>
+ <message>
+ <source>0,02</source>
+ <translation>0,02</translation>
+ </message>
+ <message>
+ <source>Zoom smoothing: </source>
+ <translation>Zoom-Glättung: </translation>
+ </message>
+ <message>
+ <source>Max Z:</source>
+ <translation>Maximales Z:</translation>
+ </message>
+ <message>
+ <source>15,00</source>
+ <translation>15,00</translation>
+ </message>
+ <message>
+ <source>When you lean forward, zoom smoothing increases the smoothing power for rotations. Maximum additonal smoothing power occurs when you lean forward by a distance of Max Z.</source>
+ <translation>Beim Vorbeugen erhöht die Zoom-Glättung die Glättungsstärke für Rotationen. Die maximal zusätzliche Glättungsstärke tritt auf beim Vorbeugen mit der Distanz Max Z.</translation>
+ </message>
+</context>
+<context>
+ <name>hamiltonDll</name>
+ <message>
+ <source>Hamilton</source>
+ <translation>Hamilton</translation>
+ </message>
+</context>
+</TS>
diff --git a/filter-nm/lang/de_DE.ts b/filter-nm/lang/de_DE.ts
new file mode 100644
index 00000000..9cfb1a22
--- /dev/null
+++ b/filter-nm/lang/de_DE.ts
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>UICdialog_nm</name>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Responsiveness</source>
+ <translation>Ansprechempfindlichkeit</translation>
+ </message>
+ <message>
+ <source>Rotation</source>
+ <translation>Rotation</translation>
+ </message>
+ <message>
+ <source>10.0</source>
+ <translation>10,0</translation>
+ </message>
+ <message>
+ <source>Position</source>
+ <translation>Position</translation>
+ </message>
+ <message>
+ <source>Natural movement filter by Tom Brazier: Cancels higher frequency noise and the natural tendency for our heads to drift even when we think we are sitting still.</source>
+ <translation>Natural Movement Filter von Tom Brazier: Hebt hohes Frequenzrauschen auf und unterdrückt die natürlich Tendenz unserer Köpfe, zu driften, selbst wenn wir denken, stillzusitzen.</translation>
+ </message>
+ <message>
+ <source>Drift speeds</source>
+ <translation>Drift-Geschwindigkeiten</translation>
+ </message>
+ <message>
+ <source>mm/s</source>
+ <translation>mm/s</translation>
+ </message>
+ <message>
+ <source>50</source>
+ <translation>50</translation>
+ </message>
+ <message>
+ <source>100</source>
+ <translation>100</translation>
+ </message>
+ <message>
+ <source>°/s</source>
+ <translation>°/s</translation>
+ </message>
+ <message>
+ <source>Instructions: Set all sliders to minimum. Then for each of rotation and position: First, increase responsiveness until the filter only just cancels jerkiness for faster head movements. Second, increase drift speed until the filter only just cancels drift movement when your head is still.</source>
+ <translation>Anleitung: Setze alle Regler auf Minimum. Dann führe folgendes für jede Rotation und Position durch: Erhöhe zunächst die Ansprechempfindlichkeit bis der Filter geradeeben das Ruckeln bei schnellen Kopfbewegungen aufhebt. Als nächstes erhöhe die Driftgeschwindigkeit, bis der Filter knapp das Driften des Kopfes aufhebt, während du ihn nicht bewegst.</translation>
+ </message>
+</context>
+<context>
+ <name>nmDll</name>
+ <message>
+ <source>NaturalMovement</source>
+ <translation>NaturalMovement</translation>
+ </message>
+</context>
+</TS>
diff --git a/gui/lang/de_DE.ts b/gui/lang/de_DE.ts
new file mode 100644
index 00000000..8d2dbcae
--- /dev/null
+++ b/gui/lang/de_DE.ts
@@ -0,0 +1,428 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>BrowseButton</name>
+ <message>
+ <source>Set executable name</source>
+ <translation>Namen der ausführbaren Datei setzen</translation>
+ </message>
+ <message>
+ <source>Executable (*.exe);;All Files (*)</source>
+ <translation>Ausführbare Dateien (*.exe);;Alle Dateien (*)</translation>
+ </message>
+</context>
+<context>
+ <name>Form</name>
+ <message>
+ <source>Press &quot;calibrate&quot; in given row to calibrate that axis. Follow instructions in the next window.
+Press &quot;clear calibration&quot; to remove any calibration data pertaining to that axis of position change or rotation.</source>
+ <translation>Klicke „Kalibrieren“ in den angegebenen Zeilen, um die jeweilige Achse zu kalibieren. Folge den Anweisungen im nächsten Fenster.
+Klicke „Kalibrierung löschen“, um jegliche Kalibrierungsdaten der zugehörigen Positions- oder Rotationsachse zu löschen.</translation>
+ </message>
+ <message>
+ <source>X</source>
+ <translation>X</translation>
+ </message>
+ <message>
+ <source>Y</source>
+ <translation>Y</translation>
+ </message>
+ <message>
+ <source>Z</source>
+ <translation>Z</translation>
+ </message>
+ <message>
+ <source>Yaw</source>
+ <translation>Gieren</translation>
+ </message>
+ <message>
+ <source>Pitch</source>
+ <translation>Nicken</translation>
+ </message>
+ <message>
+ <source>Roll</source>
+ <translation>Rollen</translation>
+ </message>
+ <message>
+ <source>Calibrate</source>
+ <translation>Kalibrieren</translation>
+ </message>
+ <message>
+ <source>Clear calibration</source>
+ <translation>Kalibrierung löschen</translation>
+ </message>
+ <message>
+ <source>1</source>
+ <translation>1</translation>
+ </message>
+</context>
+<context>
+ <name>keyboard_listener</name>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Press a key or close this window to remove the keybinding.</source>
+ <translation>Drücke eine Taste oder schließe das Fenster, um die Kurztaste zu löschen.</translation>
+ </message>
+</context>
+<context>
+ <name>mapping_dialog</name>
+ <message>
+ <source>Mapping properties</source>
+ <translation>Abbildungsparameter</translation>
+ </message>
+ <message>
+ <source>Yaw</source>
+ <translation>Gieren</translation>
+ </message>
+ <message>
+ <source>Max input</source>
+ <translation>Maximale Eingabe</translation>
+ </message>
+ <message>
+ <source>Asymmetric mapping below</source>
+ <translation>Assymmetrische Abbildung unterhalb</translation>
+ </message>
+ <message>
+ <source>Pitch</source>
+ <translation>Nicken</translation>
+ </message>
+ <message>
+ <source>Max output</source>
+ <translation>Maximale Ausgabe</translation>
+ </message>
+ <message>
+ <source>180°</source>
+ <translation>180°</translation>
+ </message>
+ <message>
+ <source>90°</source>
+ <translation>90°</translation>
+ </message>
+ <message>
+ <source>Roll</source>
+ <translation>Rollen</translation>
+ </message>
+ <message>
+ <source>X</source>
+ <translation>X</translation>
+ </message>
+ <message>
+ <source>Y</source>
+ <translation>Y</translation>
+ </message>
+ <message>
+ <source>Z</source>
+ <translation>Z</translation>
+ </message>
+ <message>
+ <source>%1°</source>
+ <translation>%1°</translation>
+ </message>
+ <message>
+ <source>%1 cm</source>
+ <translation>%1 cm</translation>
+ </message>
+</context>
+<context>
+ <name>options_dialog</name>
+ <message>
+ <source>Options</source>
+ <translation>Optionen</translation>
+ </message>
+ <message>
+ <source>Shortcuts</source>
+ <translation>Kurztasten</translation>
+ </message>
+ <message>
+ <source>Global shortcuts</source>
+ <translation>Globale Kurztasten</translation>
+ </message>
+ <message>
+ <source>Use current tracker pose as looking perfectly forward.</source>
+ <translation>Benutze aktuelle Tracker-Pose als perfekt nach vorn gerichtet.</translation>
+ </message>
+ <message>
+ <source>Center</source>
+ <translation>Zentrieren</translation>
+ </message>
+ <message>
+ <source>Bind</source>
+ <translation>Belegen</translation>
+ </message>
+ <message>
+ <source>Start tracking</source>
+ <translation>Tracking starten</translation>
+ </message>
+ <message>
+ <source>Stop tracking</source>
+ <translation>Tracking stoppen</translation>
+ </message>
+ <message>
+ <source>Keep looking forward until next zero keypress.</source>
+ <translation>Weiter vorwärts schauen bis zum nächsten Drücken der Nullen-Taste.</translation>
+ </message>
+ <message>
+ <source>Zero</source>
+ <translation>Nullen</translation>
+ </message>
+ <message>
+ <source>Freeze the position returned by the tracker while this mode is active.</source>
+ <translation>Position des Trackers einfrieren, solange dieser Modus aktiv ist.</translation>
+ </message>
+ <message>
+ <source>Toggle</source>
+ <translation>Umschalten</translation>
+ </message>
+ <message>
+ <source>Zero while held</source>
+ <translation>Nullen während gedrückt</translation>
+ </message>
+ <message>
+ <source>Restart tracking</source>
+ <translation>Tracking neu starten</translation>
+ </message>
+ <message>
+ <source>Toggle while held</source>
+ <translation>Umschalten während gedrückt</translation>
+ </message>
+ <message>
+ <source>Toggle tracking</source>
+ <translation>Tracking umschalten</translation>
+ </message>
+ <message>
+ <source>Disable user interface localization</source>
+ <translation>Übersetzungen der Benutzeroberfläche abschalten</translation>
+ </message>
+ <message>
+ <source>Centering method</source>
+ <translation>Zentriermethode</translation>
+ </message>
+ <message>
+ <source>Center at startup</source>
+ <translation>Zentrieren beim Start</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <translation>Abgeschaltet</translation>
+ </message>
+ <message>
+ <source>Point</source>
+ <translation>Punkt</translation>
+ </message>
+ <message>
+ <source>Wireless VR 360</source>
+ <translation>Wireless VR 360</translation>
+ </message>
+ <message>
+ <source>Roll compensated</source>
+ <translation>rollkompensiert</translation>
+ </message>
+ <message>
+ <source>Minimize to tray</source>
+ <translation>In den Systemabschnitt minimieren</translation>
+ </message>
+ <message>
+ <source>Enable tray</source>
+ <translation>Benachrichtigungssymbol aktivieren</translation>
+ </message>
+ <message>
+ <source>Minimize to tray on startup when enabled</source>
+ <translation>Wenn aktiviert, beim Start in den Systemabschnitt minimieren</translation>
+ </message>
+ <message>
+ <source>Output</source>
+ <translation>Ausgabe</translation>
+ </message>
+ <message>
+ <source>Axis assignment</source>
+ <translation>Achsen-Zuweisung</translation>
+ </message>
+ <message>
+ <source>Pitch</source>
+ <translation>Nicken</translation>
+ </message>
+ <message>
+ <source>X</source>
+ <translation>X</translation>
+ </message>
+ <message>
+ <source>Y</source>
+ <translation>Y</translation>
+ </message>
+ <message>
+ <source>Z</source>
+ <translation>Z</translation>
+ </message>
+ <message>
+ <source>Yaw</source>
+ <translation>Gieren</translation>
+ </message>
+ <message>
+ <source>Roll</source>
+ <translation>Rollen</translation>
+ </message>
+ <message>
+ <source>Relative translation only</source>
+ <translation>Nur relative Übersetzung</translation>
+ </message>
+ <message>
+ <source>Source</source>
+ <translation>Quelle</translation>
+ </message>
+ <message>
+ <source>Pre-invert</source>
+ <translation>Vor-Invertieren</translation>
+ </message>
+ <message>
+ <source>Destination</source>
+ <translation>Ziel</translation>
+ </message>
+ <message>
+ <source>Post-invert</source>
+ <translation>Nach-Invertieren</translation>
+ </message>
+ <message>
+ <source>Custom center pose</source>
+ <translation>Benutzerdefinierte Mittelpunkt-Pose</translation>
+ </message>
+ <message>
+ <source>Alter the centered position sent to games. Useful if the default position is too much downward or upward.</source>
+ <translation>Verändere die zentrierte Position, die an Spiele gesendet wird. Nützlich, falls die Standard-Position zu weit unten oder oben ist.</translation>
+ </message>
+ <message>
+ <source>°</source>
+ <translation>°</translation>
+ </message>
+ <message>
+ <source> cm</source>
+ <translation> cm</translation>
+ </message>
+ <message>
+ <source>CSV Data Logging</source>
+ <translation>CSV-Datenausgabe</translation>
+ </message>
+ <message>
+ <source>Enable - You will be asked for a filename whenever tracking starts</source>
+ <translation>Einschalten - Der Dateiname wird jedesmal abgefragt, wenn das Tracking startet</translation>
+ </message>
+ <message>
+ <source>Relative translation</source>
+ <translation>Relative Übersetzung</translation>
+ </message>
+ <message>
+ <source>With relative mode on, translation is applied after rotation. For example, rotating +180 degrees yaw and moving backwards results in moving forward as a result of that rotation.</source>
+ <translation>Wenn die relative Modus aktiv ist, wird die Übersetzung nach der Rotation angewendet. Zum Beispiel wird dadurch beim Gieren um 180° mit Rückwärtsbewegung in eine Vorwärtsbewegung umgewandelt.</translation>
+ </message>
+ <message>
+ <source>Mode</source>
+ <translation>Modus</translation>
+ </message>
+ <message>
+ <source>Enabled</source>
+ <translation>Eingeschaltet</translation>
+ </message>
+ <message>
+ <source>Enabled when not aiming</source>
+ <translation>Eingeschaltet, während nicht gezielt wird</translation>
+ </message>
+ <message>
+ <source>Disable for Y</source>
+ <translation>Für Y abschalten</translation>
+ </message>
+ <message>
+ <source>Disable for X</source>
+ <translation>Für X abschalten</translation>
+ </message>
+ <message>
+ <source>Disable effect by roll</source>
+ <translation>Effekt durch Rollen abschalten</translation>
+ </message>
+ <message>
+ <source>Disable for Z (for zoom on Z axis)</source>
+ <translation>Für Z abschalten (für Zoom auf der Z-Achse)</translation>
+ </message>
+ <message>
+ <source>Disable effect by pitch</source>
+ <translation>Effekt durch Nicken abschalten</translation>
+ </message>
+ <message>
+ <source>Disable effect by yaw</source>
+ <translation>Effekt durch Gieren abschalten</translation>
+ </message>
+ <message>
+ <source>Neck displacement</source>
+ <translation>Nacken-Versatz</translation>
+ </message>
+ <message>
+ <source>Eyes will be offset from the pivot of rotation, assumed to be the neck. It also works with relative translation disabled.</source>
+ <translation>Die Augen werden gegenüber des Drehpunktes versetzt sein, unter Annahme, sie seien der Nacken. Dies funktioniert auch dann, wenn die relative Übersetzung abgeschaltet ist.</translation>
+ </message>
+ <message>
+ <source>Enable</source>
+ <translation>Einschalten</translation>
+ </message>
+ <message>
+ <source>Forward from center of rotation</source>
+ <translation>Vom Drehpunkt nach vorn verschieben</translation>
+ </message>
+ <message>
+ <source>Game detection</source>
+ <translation>Spiel-Erkennung</translation>
+ </message>
+ <message>
+ <source>Start tracking automatically when a game starts with selected profile, and stop when the game exits.</source>
+ <translation>Tracking beim Spielstart automatisch mit dem ausgewählten Profil starten, und stoppen, wenn das Spiel beendet wird.</translation>
+ </message>
+ <message>
+ <source>Mouse %1</source>
+ <translation>Maus %1</translation>
+ </message>
+ <message>
+ <source>Joy button %1</source>
+ <translation>Joystick-Knopf %1</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>Nichts</translation>
+ </message>
+ <message>
+ <source>Tracker</source>
+ <translation>Tracker</translation>
+ </message>
+ <message>
+ <source>Filter</source>
+ <translation>Filter</translation>
+ </message>
+</context>
+<context>
+ <name>process_detector</name>
+ <message>
+ <source>Game detector</source>
+ <translation>Spiel-Erkennung</translation>
+ </message>
+ <message>
+ <source>Start profiles from game executable names in this list</source>
+ <translation>Profile anhand der ausführbaren Dateien dieser Liste starten</translation>
+ </message>
+ <message>
+ <source>Executable</source>
+ <translation>Ausführbare Datei</translation>
+ </message>
+ <message>
+ <source>Profile</source>
+ <translation>Profil</translation>
+ </message>
+ <message>
+ <source>+</source>
+ <translation>Hinzufügen</translation>
+ </message>
+ <message>
+ <source>-</source>
+ <translation>Entfernen</translation>
+ </message>
+</context>
+</TS>
diff --git a/logic/lang/de_DE.ts b/logic/lang/de_DE.ts
new file mode 100644
index 00000000..eca10616
--- /dev/null
+++ b/logic/lang/de_DE.ts
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>Work</name>
+ <message>
+ <source>Select filename</source>
+ <translation>Dateiname wählen</translation>
+ </message>
+ <message>
+ <source>CSV File (*.csv)</source>
+ <translation>CSV-Datei (*.csv)</translation>
+ </message>
+ <message>
+ <source>Logging error</source>
+ <translation>Protokollierungsfehler</translation>
+ </message>
+ <message>
+ <source>Unable to open file &apos;%1&apos;. Proceeding without logging.</source>
+ <translation>Datei &apos;%1&apos; kann nicht geöffnet werden. Es wird ohne Protokollierung fortgefahren.</translation>
+ </message>
+</context>
+<context>
+ <name>runtime_libraries</name>
+ <message>
+ <source>Library load failure</source>
+ <translation>Fehler beim Laden der Bibliothek</translation>
+ </message>
+ <message>
+ <source>Error occurred while loading protocol %1
+
+%2
+</source>
+ <translation>Ein Fehler trat auf beim Laden des Protokolls %1
+
+%2
+</translation>
+ </message>
+ <message>
+ <source>Error occurred while loading filter %1
+
+%2
+</source>
+ <translation>Fehler beim Laden des Filters %1
+
+%2
+</translation>
+ </message>
+ <message>
+ <source>Error occurred while loading tracker %1
+
+%2
+</source>
+ <translation>Fehler beim Laden des Trackers %1
+
+%2
+</translation>
+ </message>
+ <message>
+ <source>Startup failure</source>
+ <translation>Ausführungsfehler</translation>
+ </message>
+</context>
+</TS>
diff --git a/migration/lang/de_DE.ts b/migration/lang/de_DE.ts
new file mode 100644
index 00000000..1552582e
--- /dev/null
+++ b/migration/lang/de_DE.ts
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+</TS>
diff --git a/opentrack/lang/de_DE.ts b/opentrack/lang/de_DE.ts
new file mode 100644
index 00000000..6eaf28d4
--- /dev/null
+++ b/opentrack/lang/de_DE.ts
@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>UI_new_config</name>
+ <message>
+ <source>Config filename</source>
+ <translation>Konfigurationsdatei</translation>
+ </message>
+ <message>
+ <source>New file name:</source>
+ <translation>Neuer Dateiname:</translation>
+ </message>
+</context>
+<context>
+ <name>main_window</name>
+ <message>
+ <source>Raw tracker data</source>
+ <translation>Rohe Tracker-Daten</translation>
+ </message>
+ <message>
+ <source>Z</source>
+ <translation>Z</translation>
+ </message>
+ <message>
+ <source>Pitch</source>
+ <translation>Nicken</translation>
+ </message>
+ <message>
+ <source>Y</source>
+ <translation>Y</translation>
+ </message>
+ <message>
+ <source>X</source>
+ <translation>X</translation>
+ </message>
+ <message>
+ <source>Roll</source>
+ <translation>Rollen</translation>
+ </message>
+ <message>
+ <source>Yaw</source>
+ <translation>Gieren</translation>
+ </message>
+ <message>
+ <source>Game data</source>
+ <translation>Spieldaten</translation>
+ </message>
+ <message>
+ <source>Profile</source>
+ <translation>Profil</translation>
+ </message>
+ <message>
+ <source>Options</source>
+ <translation>Optionen</translation>
+ </message>
+ <message>
+ <source>Mapping</source>
+ <translation>Abbildung</translation>
+ </message>
+ <message>
+ <source>Tracking</source>
+ <translation>Tracking</translation>
+ </message>
+ <message>
+ <source>Start</source>
+ <translation>Starten</translation>
+ </message>
+ <message>
+ <source>Stop</source>
+ <translation>Stoppen</translation>
+ </message>
+ <message>
+ <source>Input</source>
+ <translation>Eingabe</translation>
+ </message>
+ <message>
+ <source>🔨</source>
+ <translation>🔨</translation>
+ </message>
+ <message>
+ <source>Output</source>
+ <translation>Ausgabe</translation>
+ </message>
+ <message>
+ <source>Filter</source>
+ <translation>Filter</translation>
+ </message>
+ <message>
+ <source>Create new empty config</source>
+ <translation>Neue leere Konfiguration erstellen</translation>
+ </message>
+ <message>
+ <source>Create new copied config</source>
+ <translation>Neue kopierte Konfiguration erstellen</translation>
+ </message>
+ <message>
+ <source>Open configuration directory</source>
+ <translation>Konfigurationsordner öffnen</translation>
+ </message>
+ <message>
+ <source>opentrack</source>
+ <translation>opentrack</translation>
+ </message>
+ <message>
+ <source> (debug)</source>
+ <translation> (Fehlersuche)</translation>
+ </message>
+ <message>
+ <source>Show the Octopus</source>
+ <translation>Den Oktopus anzeigen</translation>
+ </message>
+ <message>
+ <source>Hide the Octopus</source>
+ <translation>Den Oktopus verstecken</translation>
+ </message>
+ <message>
+ <source>Tracker settings</source>
+ <translation>Tracker-Einstellungen</translation>
+ </message>
+ <message>
+ <source>Filter settings</source>
+ <translation>Filter-Einstellungen</translation>
+ </message>
+ <message>
+ <source>Protocol settings</source>
+ <translation>Protokoll-Einstellungen</translation>
+ </message>
+ <message>
+ <source>Mappings</source>
+ <translation>Abbildungen</translation>
+ </message>
+ <message>
+ <source>Exit</source>
+ <translation>Beenden</translation>
+ </message>
+ <message>
+ <source>The Octopus is sad</source>
+ <translation>Der Oktopus ist traurig</translation>
+ </message>
+ <message>
+ <source>Check permissions for your .ini directory:
+
+&quot;%1&quot;%2
+
+Exiting now.</source>
+ <translation>Überprüfe die Berechtigungen des .ini-Ordners:
+
+&quot;%1&quot;%2
+
+Das Programm beendet sich nun.</translation>
+ </message>
+ <message>
+ <source> :: </source>
+ <translation> :: </translation>
+ </message>
+ <message>
+ <source>Running as root is bad</source>
+ <translation>Das Starten als root ist schlecht</translation>
+ </message>
+ <message>
+ <source>Do not run as root. Set correct device node permissions.</source>
+ <translation>Führe dieses Programm nicht als root aus. Setze die korrekten Gerätedatei-Berechtigungen.</translation>
+ </message>
+ <message>
+ <source>Running as root is bad, seriously</source>
+ <translation>Das Starten als root ist schlecht, ernsthaft</translation>
+ </message>
+ <message>
+ <source>Do not run as root. I&apos;ll keep whining at every startup.</source>
+ <translation>Führe dieses Programm nicht als root aus. Ich werde bei jedem Start rumheulen.</translation>
+ </message>
+ <message>
+ <source>Be annoyed, comprehensively.</source>
+ <translation>Sei verärgert, vollumfänglich.</translation>
+ </message>
+ <message>
+ <source>Don&apos;t run as root to remove these annoying messages.</source>
+ <translation>Führe das Programm nicht mehr als root aus, um diese ärgerliche Nachricht loszuwerden.</translation>
+ </message>
+</context>
+<context>
+ <name>new_file_dialog</name>
+ <message>
+ <source>File exists</source>
+ <translation>Die Datei existiert</translation>
+ </message>
+ <message>
+ <source>This file already exists. Pick another name.</source>
+ <translation>Diese Datei existiert bereits. Wähle einen anderen Namen.</translation>
+ </message>
+</context>
+</TS>
diff --git a/options/lang/de_DE.ts b/options/lang/de_DE.ts
new file mode 100644
index 00000000..1552582e
--- /dev/null
+++ b/options/lang/de_DE.ts
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+</TS>
diff --git a/pose-widget/lang/de_DE.ts b/pose-widget/lang/de_DE.ts
new file mode 100644
index 00000000..1552582e
--- /dev/null
+++ b/pose-widget/lang/de_DE.ts
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+</TS>
diff --git a/proto-flightgear/lang/de_DE.ts b/proto-flightgear/lang/de_DE.ts
new file mode 100644
index 00000000..436087bc
--- /dev/null
+++ b/proto-flightgear/lang/de_DE.ts
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>UICFGControls</name>
+ <message>
+ <source>FlightGear protocol settings</source>
+ <translation>FlightGear-Protokolleinstellungen</translation>
+ </message>
+ <message>
+ <source>IP address</source>
+ <translation>IP-Adresse</translation>
+ </message>
+ <message>
+ <source>Port</source>
+ <translation>Port</translation>
+ </message>
+</context>
+<context>
+ <name>flightgear</name>
+ <message>
+ <source>Can&apos;t bind to [%1.%2.%3.%4]:%5</source>
+ <translation>Konnte nicht an [%1.%2.%3.%4]:%5 binden</translation>
+ </message>
+ <message>
+ <source>FlightGear</source>
+ <translation>FlightGear</translation>
+ </message>
+</context>
+<context>
+ <name>flightgearDll</name>
+ <message>
+ <source>FlightGear</source>
+ <translation>FlightGear</translation>
+ </message>
+</context>
+</TS>
diff --git a/proto-libevdev/ftnoir_protocol_libevdev.cpp b/proto-libevdev/ftnoir_protocol_libevdev.cpp
index d357670d..fefcd9bb 100644
--- a/proto-libevdev/ftnoir_protocol_libevdev.cpp
+++ b/proto-libevdev/ftnoir_protocol_libevdev.cpp
@@ -55,6 +55,11 @@ evdev::evdev()
CHECK_LIBEVDEV(libevdev_enable_property(dev, INPUT_PROP_BUTTONPAD));
libevdev_set_name(dev, "opentrack headpose");
+
+ libevdev_set_id_bustype(dev, 3);
+ libevdev_set_id_vendor(dev, 4324);
+ libevdev_set_id_product(dev, 3798);
+ libevdev_set_id_version(dev, 123);
struct input_absinfo absinfo;
diff --git a/proto-libevdev/lang/de_DE.ts b/proto-libevdev/lang/de_DE.ts
new file mode 100644
index 00000000..f66a1b39
--- /dev/null
+++ b/proto-libevdev/lang/de_DE.ts
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>UICLibevdevControls</name>
+ <message>
+ <source>libevdev options</source>
+ <translation>libevdev-Optionen</translation>
+ </message>
+ <message>
+ <source>Make sure rw for /dev/input/uinput!</source>
+ <translation>Stelle sicher, dass /dev/input/uinput rw-Berechtigungen hat!</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Okay</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Abbruch</translation>
+ </message>
+</context>
+<context>
+ <name>evdev</name>
+ <message>
+ <source>Virtual joystick for Linux</source>
+ <translation>Virtueller Joystick für Linux</translation>
+ </message>
+</context>
+<context>
+ <name>evdevDll</name>
+ <message>
+ <source>libevdev joystick receiver</source>
+ <translation>libevdev-Joystick-Empfänger</translation>
+ </message>
+</context>
+</TS>
diff --git a/proto-udp/lang/de_DE.ts b/proto-udp/lang/de_DE.ts
new file mode 100644
index 00000000..442d8683
--- /dev/null
+++ b/proto-udp/lang/de_DE.ts
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>UICFTNControls</name>
+ <message>
+ <source>UDP protocol settings</source>
+ <translation>UDP-Protokolleinstellungen</translation>
+ </message>
+ <message>
+ <source>Remote IP address</source>
+ <translation>Entfernte IP-Adresse</translation>
+ </message>
+ <message>
+ <source>Port</source>
+ <translation>Port</translation>
+ </message>
+</context>
+<context>
+ <name>udp</name>
+ <message>
+ <source>Can&apos;t bind socket: %1</source>
+ <translation>Kann nicht an Socket binden: %1</translation>
+ </message>
+ <message>
+ <source>UDP over network</source>
+ <translation>UDP über Netzwerk</translation>
+ </message>
+</context>
+<context>
+ <name>udp_sender_dll</name>
+ <message>
+ <source>UDP over network</source>
+ <translation>UDP über Netzwerk</translation>
+ </message>
+</context>
+</TS>
diff --git a/proto-wine/ftnoir_protocol_wine.cpp b/proto-wine/ftnoir_protocol_wine.cpp
index b70b3f16..bae02b06 100644
--- a/proto-wine/ftnoir_protocol_wine.cpp
+++ b/proto-wine/ftnoir_protocol_wine.cpp
@@ -1,8 +1,8 @@
#include "ftnoir_protocol_wine.h"
+#include <qprocess.h>
#ifndef OTR_WINE_NO_WRAPPER
# include "csv/csv.h"
#endif
-#include "compat/library-path.hpp"
#include <cstring>
#include <cmath>
@@ -10,6 +10,8 @@
#include <QString>
#include <QDebug>
+#include "proton.h"
+
wine::wine() = default;
wine::~wine()
@@ -63,50 +65,91 @@ module_status wine::initialize()
#ifndef OTR_WINE_NO_WRAPPER
static const QString library_path(OPENTRACK_BASE_PATH + OPENTRACK_LIBRARY_PATH);
+ /////////////////////////
+ // determine wine path //
+ /////////////////////////
QString wine_path = "wine";
- if (s.wine_select_path().toString() != "WINE") {
- // if we are not supposed to use system wine then:
- if (s.wine_select_path().toString() != "CUSTOM") {
- // if we don't have a custom path then change the wine_path to the path corresponding to the selected version
- wine_path = s.wine_select_path().toString();
- }
- else if (!s.wine_custom_path->isEmpty()) {
- // if we do have a custom path and it is not empty then
- wine_path = s.wine_custom_path;
+
+ if (s.variant_wine) {
+ // NORMAL WINE
+
+ // resolve combo box
+ if (s.wine_select_path().toString() != "WINE") {
+ // if we are not supposed to use system wine then:
+ if (s.wine_select_path().toString() != "CUSTOM") {
+ // if we don't have a custom path then change the wine_path to the path corresponding to the selected version
+ wine_path = s.wine_select_path().toString();
+ }
+ else if (!s.wine_custom_path->isEmpty()) {
+ // if we do have a custom path and it is not empty then
+ wine_path = s.wine_custom_path;
+ }
}
+
+ // parse tilde if present
+ if (wine_path[0] == '~')
+ wine_path = qgetenv("HOME") + wine_path.mid(1);
}
- if (wine_path[0] == '~')
- wine_path = qgetenv("HOME") + wine_path.mid(1);
+ else if (s.variant_proton)
+ {
+ // PROTON
+ wine_path = s.proton_path().toString() + "/bin/wine";
+ }
qDebug() << "proto/wine: wine_path:" << wine_path;
- auto env = QProcessEnvironment::systemEnvironment();
+ /////////////////////////////////////
+ // determine environment variables //
+ /////////////////////////////////////
+ QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+
+ // if proton is used setup proton environment
if (s.variant_proton)
{
- if (s.proton_appid == 0)
- return error(tr("Must specify application id for Proton (Steam Play)"));
+ auto [proton_env, env_error_string, env_success] = make_steam_environ(s.proton_path().toString());
+ env = proton_env;
- std::tuple<QProcessEnvironment, QString, bool> make_steam_environ(const QString& proton_dist_path, int appid);
- QString proton_path(const QString& proton_dist_path);
+ if (!env_success)
+ return error(env_error_string);
+ }
- QString proton_dist_path = s.proton_path().toString();
+ // determine wineprefix
+ if (s.variant_proton && s.variant_proton_steamplay) {
+ // wine prefix is dependend on steam
- wine_path = proton_path(proton_dist_path);
- auto [proton_env, error_string, success] = make_steam_environ(proton_dist_path, s.proton_appid);
- env = proton_env;
+ if (s.proton_appid == 0)
+ return error(tr("Must specify application id for Proton (Steam Play)"));
+
+ auto [prefix, error_string, success] = make_wineprefix(s.proton_appid);
+ qDebug() << "proto/wine: wineprefix:" << prefix;
+ env.insert("WINEPREFIX", prefix);
if (!success)
return error(error_string);
}
- else
- {
- QString wineprefix = "~/.wine";
- if (!s.wineprefix->isEmpty())
+ else {
+ // wine prefix was supplied via path
+
+ QString wineprefix = "";
+
+ // check if prefix was supplied via wine
+ if (s.variant_wine && !s.wineprefix->isEmpty())
wineprefix = s.wineprefix;
+
+ // check if prefix was supplied via proton
+ if (s.variant_proton_external && !s.protonprefix->isEmpty())
+ wineprefix = s.protonprefix;
+
+ // check if the user specified a prefix anywhere
+ if (wineprefix.isEmpty())
+ return error(tr("Prefix has not been defined!").arg(wineprefix));
+
+ // handle tilde
if (wineprefix[0] == '~')
wineprefix = qgetenv("HOME") + wineprefix.mid(1);
+ // return error if relative path is given
if (wineprefix[0] != '/')
return error(tr("Wine prefix must be an absolute path (given '%1')").arg(wineprefix));
@@ -115,13 +158,20 @@ module_status wine::initialize()
env.insert("WINEPREFIX", wineprefix);
}
+ // ESYNC and FSYNC
if (s.esync)
env.insert("WINEESYNC", "1");
if (s.fsync)
env.insert("WINEFSYNC", "1");
+ // Headtracking Protocol
env.insert("OTR_WINE_PROTO", QString::number(s.protocol+1));
+
+ ////////////////////////////////
+ // launch the wrapper program //
+ ////////////////////////////////
+
wrapper.setProcessEnvironment(env);
wrapper.setWorkingDirectory(OPENTRACK_BASE_PATH);
wrapper.start(wine_path, { library_path + "opentrack-wrapper-wine.exe.so" });
diff --git a/proto-wine/ftnoir_protocol_wine.h b/proto-wine/ftnoir_protocol_wine.h
index f79f65dc..718699ac 100644
--- a/proto-wine/ftnoir_protocol_wine.h
+++ b/proto-wine/ftnoir_protocol_wine.h
@@ -19,8 +19,10 @@ using namespace options;
struct settings : opts
{
settings() : opts{"proto-wine"} {}
- value<bool> variant_proton{b, "variant-proton", false },
- variant_wine{b, "variant-wine", true },
+ value<bool> variant_wine{b, "variant-wine", true },
+ variant_proton{b, "variant-proton", false },
+ variant_proton_steamplay{b, "variant-proton-steamplay", true },
+ variant_proton_external{b, "variant-proton-external", false },
fsync{b, "fsync", true},
esync{b, "esync", true};
@@ -29,6 +31,7 @@ struct settings : opts
value<QVariant> wine_select_path{b, "wine-select-version", {"WINE"}};
value<QString> wine_custom_path{b, "wine-custom-version", ""};
value<QString> wineprefix{b, "wineprefix", "~/.wine/"};
+ value<QString> protonprefix{b, "protonprefix", ""};
value<int> protocol{b, "protocol", 2};
};
@@ -79,10 +82,13 @@ private:
settings s;
private slots:
- void onWinePathComboUpdated(QString selection);
+ void onWinePathComboUpdated();
+ void onRadioButtonsChanged();
void doBrowseWine();
- void doBrowsePrefix();
+ void doBrowseWinePrefix();
+
+ void doBrowseProtonPrefix();
void doOK();
void doCancel();
diff --git a/proto-wine/ftnoir_protocol_wine_dialog.cpp b/proto-wine/ftnoir_protocol_wine_dialog.cpp
index 23f82fda..2b7d08e0 100644
--- a/proto-wine/ftnoir_protocol_wine_dialog.cpp
+++ b/proto-wine/ftnoir_protocol_wine_dialog.cpp
@@ -3,10 +3,13 @@
#include <QFileDialog>
#include <QDir>
#include <QDirIterator>
+#include <qcombobox.h>
#include <qdebug.h>
#include <qdir.h>
+#include <qradiobutton.h>
#include "api/plugin-api.hpp"
+#include "options/tie.hpp"
/*
* 0: path to the directory with wine versions
@@ -18,17 +21,18 @@ static const char* wine_paths[][3] = {
{"/.var/app/net.lutris.Lutris/data/lutris/runners/wine/", "/bin/wine", "Flatpak Lutris"}
};
-static const char* proton_paths[] = {
- "/.steam/steam/steamapps/common",
- "/.steam/root/compatibilitytools.d",
- "/.local/share/Steam/steamapps/common",
+static const char* proton_paths[][2] = {
+ {"/.steam/steam/steamapps/common", "Proton*"},
+ {"/.steam/root/compatibilitytools.d", "*"},
+ {"/.local/share/Steam/steamapps/common", "Proton*"},
+ {"/.local/share/Steam/compatibilitytools.d", "*"},
};
FTControls::FTControls()
{
ui.setupUi(this);
- //populate wine select
+ // populate wine select
ui.wine_path_combo->addItem("System Wine", QVariant{"WINE"});
for (const char** path : wine_paths) {
QDir dir(QDir::homePath() + path[0]);
@@ -44,16 +48,19 @@ FTControls::FTControls()
}
ui.wine_path_combo->addItem("Custom path to Wine executable", QVariant{"CUSTOM"});
- //populate proton select
- for (const char* path : proton_paths) {
- QDir dir(QDir::homePath() + path);
- dir.setFilter(QDir::Dirs);
- dir.setNameFilters({ "Proton*" });
+ // populate proton select
+ for (const char** path : proton_paths) {
+ QDir dir(QDir::homePath() + path[0]);
+ dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
+ dir.setNameFilters({ path[1] });
QFileInfoList proton_dir_list = dir.entryInfoList();
for (int i = 0; i < proton_dir_list.size(); ++i) {
const QFileInfo &proton_dir = proton_dir_list.at(i);
- qDebug() << proton_dir.canonicalFilePath();
+
+ // check if this Proton Version is already present in any way
+ if (ui.proton_version->findText(proton_dir.fileName()) != -1)
+ continue;
QDirIterator proton_executable_it(proton_dir.canonicalFilePath(), QStringList() << "wine", QDir::Files, QDirIterator::Subdirectories);
@@ -62,38 +69,53 @@ FTControls::FTControls()
QDir proton_dist_dir(proton_executable_path);
proton_dist_dir.cd("../../");
- qDebug() << proton_dist_dir.canonicalPath();
-
ui.proton_version->addItem(proton_dir.fileName(), QVariant{proton_dist_dir.canonicalPath()});
}
}
}
-
- tie_setting(s.proton_path, ui.proton_version);
- tie_setting(s.variant_wine, ui.variant_wine);
- tie_setting(s.variant_proton, ui.variant_proton);
+ // settings - wine
+ tie_setting(s.variant_wine, ui.variant_wine); // radio button
+ tie_setting(s.wine_select_path, ui.wine_path_combo); // combo box (dropdown)
+ tie_setting(s.wine_custom_path, ui.wine_path); // line edit (enabled via dropdown)
+ tie_setting(s.wineprefix, ui.wineprefix); // line edit
+
+ // settings - proton
+ tie_setting(s.variant_proton, ui.variant_proton); // radio button
+ tie_setting(s.proton_path, ui.proton_version); // combo box (dropdown)
+ tie_setting(s.variant_proton_steamplay, ui.subvariant_steamplay); // radio button
+ tie_setting(s.proton_appid, ui.proton_appid); // number select
+ tie_setting(s.variant_proton_external, ui.subvariant_external); // radio button
+ tie_setting(s.protonprefix, ui.protonprefix); // line edit
+
+ // settings - advanced
tie_setting(s.esync, ui.esync);
tie_setting(s.fsync, ui.fsync);
- tie_setting(s.proton_appid, ui.proton_appid);
- tie_setting(s.wine_select_path, ui.wine_path_combo);
- tie_setting(s.wine_custom_path, ui.wine_path);
- tie_setting(s.wineprefix, ui.wineprefix);
tie_setting(s.protocol, ui.protocol_selection);
+ // setup signals and slots for UI
connect(ui.wine_path_combo, &QComboBox::currentTextChanged, this, &FTControls::onWinePathComboUpdated);
connect(ui.browse_wine_path_button, &QPushButton::clicked, this, &FTControls::doBrowseWine);
- connect(ui.browse_wine_prefix_button, &QPushButton::clicked, this, &FTControls::doBrowsePrefix);
+ connect(ui.browse_wine_prefix_button, &QPushButton::clicked, this, &FTControls::doBrowseWinePrefix);
+ connect(ui.browse_proton_prefix_button, &QPushButton::clicked, this, &FTControls::doBrowseProtonPrefix);
connect(ui.buttonBox, &QDialogButtonBox::accepted, this, &FTControls::doOK);
connect(ui.buttonBox, &QDialogButtonBox::rejected, this, &FTControls::doCancel);
+ // setup signals and slots for UI radio buttons
+ connect(ui.variant_wine, &QRadioButton::clicked, this, &FTControls::onRadioButtonsChanged);
+ connect(ui.variant_proton, &QRadioButton::clicked, this, &FTControls::onRadioButtonsChanged);
+ connect(ui.subvariant_steamplay, &QRadioButton::clicked, this, &FTControls::onRadioButtonsChanged);
+ connect(ui.subvariant_external, &QRadioButton::clicked, this, &FTControls::onRadioButtonsChanged);
+
// update state of the combo box and associated ui elements
- onWinePathComboUpdated(ui.wine_path_combo->currentText());
+ onWinePathComboUpdated();
+ // hide the correct items
+ onRadioButtonsChanged();
}
-void FTControls::onWinePathComboUpdated(QString selection) {
+void FTControls::onWinePathComboUpdated() {
// enable the custom text field if required
- if (selection == "Custom path to Wine executable") {
+ if (ui.wine_path_combo->currentData() == "CUSTOM") {
ui.wine_path->setEnabled(true);
ui.browse_wine_path_button->setEnabled(true);
}
@@ -103,6 +125,63 @@ void FTControls::onWinePathComboUpdated(QString selection) {
}
}
+void FTControls::onRadioButtonsChanged() {
+ if (ui.variant_wine->isChecked()) {
+ // wine settings selected
+
+ // enable wine settings
+ ui.wine_path_combo->setEnabled(true);
+ ui.wineprefix->setEnabled(true);
+ ui.browse_wine_prefix_button->setEnabled(true);
+ if (ui.wine_path_combo->currentData() == "CUSTOM") {
+ ui.wine_path->setEnabled(true);
+ ui.browse_wine_path_button->setEnabled(true);
+ }
+
+ // disable proton settings
+ ui.proton_version->setEnabled(false);
+ ui.proton_subgroup->setEnabled(false);
+ }
+ else if (ui.variant_proton->isChecked()) {
+ // proton settings selected
+
+ // disable wine settings
+ ui.wine_path_combo->setEnabled(false);
+ ui.wine_path->setEnabled(false);
+ ui.browse_wine_path_button->setEnabled(false);
+ ui.wineprefix->setEnabled(false);
+ ui.browse_wine_prefix_button->setEnabled(false);
+
+ // enable proton settings
+ ui.proton_version->setEnabled(true);
+ ui.proton_subgroup->setEnabled(true);
+
+ // run proton radio buttons logic
+ if (ui.subvariant_steamplay->isChecked()) {
+ // enable steamplay settings
+ ui.proton_appid->setEnabled(true);
+
+ // disable external settings
+ ui.protonprefix->setEnabled(false);
+ ui.browse_proton_prefix_button->setEnabled(false);
+ }
+ else if (ui.subvariant_external->isChecked()) {
+ // disable steamplay settings
+ ui.proton_appid->setEnabled(false);
+
+ // enable external settinsg
+ ui.protonprefix->setEnabled(true);
+ ui.browse_proton_prefix_button->setEnabled(true);
+ }
+ }
+ else {
+ // for some reason QTs auto exclusive feature is not always correctly working
+ // this is a somewhat hacky solution
+ ui.variant_wine->setChecked(ui.wine_path_combo->isEnabled());
+ ui.variant_proton->setChecked(ui.proton_version->isEnabled());
+ }
+}
+
void FTControls::doBrowseWine() {
QFileDialog d(this);
d.setFileMode(QFileDialog::FileMode::ExistingFile);
@@ -114,7 +193,7 @@ void FTControls::doBrowseWine() {
s.wine_custom_path = d.selectedFiles()[0];
}
}
-void FTControls::doBrowsePrefix() {
+void FTControls::doBrowseWinePrefix() {
QFileDialog d(this);
d.setFileMode(QFileDialog::FileMode::Directory);
d.setOption(QFileDialog::Option::ShowDirsOnly, true);
@@ -127,6 +206,19 @@ void FTControls::doBrowsePrefix() {
}
}
+void FTControls::doBrowseProtonPrefix() {
+ QFileDialog d(this);
+ d.setFileMode(QFileDialog::FileMode::Directory);
+ d.setOption(QFileDialog::Option::ShowDirsOnly, true);
+ d.setWindowTitle(tr("Select Proton Prefix"));
+ if (s.protonprefix->startsWith("/") || s.protonprefix->startsWith("~")) {
+ d.selectFile(s.protonprefix);
+ }
+ if (d.exec()) {
+ s.protonprefix = d.selectedFiles()[0];
+ }
+}
+
void FTControls::doOK()
{
s.b->save();
diff --git a/proto-wine/ftnoir_winecontrols.ui b/proto-wine/ftnoir_winecontrols.ui
index 365922ca..b601d6e5 100644
--- a/proto-wine/ftnoir_winecontrols.ui
+++ b/proto-wine/ftnoir_winecontrols.ui
@@ -9,8 +9,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>951</width>
- <height>424</height>
+ <width>934</width>
+ <height>466</height>
</rect>
</property>
<property name="windowTitle">
@@ -32,86 +32,8 @@
<property name="title">
<string>Wine variant</string>
</property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="10" column="0">
- <widget class="QRadioButton" name="variant_proton">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>Proton (Steam Play)</string>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QRadioButton" name="variant_wine">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>Wine (select path and prefix)</string>
- </property>
- </widget>
- </item>
- <item row="10" column="1">
- <widget class="QComboBox" name="proton_version">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>120</width>
- <height>0</height>
- </size>
- </property>
- <property name="layoutDirection">
- <enum>Qt::LeftToRight</enum>
- </property>
- </widget>
- </item>
- <item row="9" column="1">
- <layout class="QHBoxLayout" name="horizontalLayout_4">
- <item>
- <widget class="QLineEdit" name="wineprefix">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="minimumSize">
- <size>
- <width>450</width>
- <height>0</height>
- </size>
- </property>
- <property name="toolTip">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;prefix&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
- </property>
- <property name="placeholderText">
- <string>/path_to_the_prefix/</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QPushButton" name="browse_wine_prefix_button">
- <property name="text">
- <string>Browse Prefix</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item row="8" column="1">
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLineEdit" name="wine_path">
@@ -146,6 +68,12 @@
<property name="enabled">
<bool>false</bool>
</property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
<property name="text">
<string>Browse Wine Path</string>
</property>
@@ -153,8 +81,175 @@
</item>
</layout>
</item>
+ <item row="2" column="1">
+ <layout class="QVBoxLayout" name="verticalLayout_7">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="QLineEdit" name="wineprefix">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>450</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;prefix&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="placeholderText">
+ <string>/path_to_the_prefix/</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="browse_wine_prefix_button">
+ <property name="text">
+ <string>Browse Prefix</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item row="3" column="1">
+ <widget class="QComboBox" name="proton_version">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>120</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QRadioButton" name="variant_proton">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Proton (select version and mode)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QRadioButton" name="variant_wine">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Wine (select version and prefix)</string>
+ </property>
+ </widget>
+ </item>
<item row="0" column="1">
- <widget class="QComboBox" name="wine_path_combo"/>
+ <widget class="QComboBox" name="wine_path_combo">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" colspan="2">
+ <widget class="QGroupBox" name="proton_subgroup">
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="1">
+ <widget class="QSpinBox" name="proton_appid">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximum">
+ <number>2147483647</number>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QRadioButton" name="subvariant_steamplay">
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Steam Play is Steams System to run Windows titles on Linux via Proton.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>Steam Play (select Steam Application ID)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QRadioButton" name="subvariant_external">
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;UMU is a launcher that allows the use of Proton outside of Steam. Some game launchers like Lutris may use this to enable Proton support.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>UMU enabled Launchers (select prefix)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout_7">
+ <item>
+ <widget class="QLineEdit" name="protonprefix">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>450</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="browse_proton_prefix_button">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>105</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Browse Prefix</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
</item>
</layout>
</widget>
@@ -271,32 +366,6 @@
<property name="bottomMargin">
<number>0</number>
</property>
- <item>
- <widget class="QLabel" name="label">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="text">
- <string>Steam application id</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QSpinBox" name="proton_appid">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="maximum">
- <number>2147483647</number>
- </property>
- </widget>
- </item>
</layout>
</widget>
</item>
@@ -318,6 +387,24 @@
</item>
</layout>
</widget>
+ <tabstops>
+ <tabstop>variant_wine</tabstop>
+ <tabstop>wine_path_combo</tabstop>
+ <tabstop>wine_path</tabstop>
+ <tabstop>browse_wine_path_button</tabstop>
+ <tabstop>wineprefix</tabstop>
+ <tabstop>browse_wine_prefix_button</tabstop>
+ <tabstop>variant_proton</tabstop>
+ <tabstop>proton_version</tabstop>
+ <tabstop>subvariant_steamplay</tabstop>
+ <tabstop>proton_appid</tabstop>
+ <tabstop>subvariant_external</tabstop>
+ <tabstop>protonprefix</tabstop>
+ <tabstop>browse_proton_prefix_button</tabstop>
+ <tabstop>esync</tabstop>
+ <tabstop>fsync</tabstop>
+ <tabstop>protocol_selection</tabstop>
+ </tabstops>
<resources>
<include location="wine-protocol.qrc"/>
</resources>
diff --git a/proto-wine/lang/de_DE.ts b/proto-wine/lang/de_DE.ts
new file mode 100644
index 00000000..072c8626
--- /dev/null
+++ b/proto-wine/lang/de_DE.ts
@@ -0,0 +1,140 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>FTControls</name>
+ <message>
+ <source>Select path to Wine Binary</source>
+ <translation>Pfad des wine-Programms auswählen</translation>
+ </message>
+ <message>
+ <source>Select Wine Prefix</source>
+ <translation>wine-Prefix auswählen</translation>
+ </message>
+ <message>
+ <source>Select Proton Prefix</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>UICFTControls</name>
+ <message>
+ <source>Wine settings</source>
+ <translation>Wine-Einstellungen</translation>
+ </message>
+ <message>
+ <source>Wine variant</source>
+ <translation>Wine-Variante</translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;prefix&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Prefix&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <source>/path_to_the_prefix/</source>
+ <translation>/pfad_zum_prefix/</translation>
+ </message>
+ <message>
+ <source>Browse Prefix</source>
+ <translation>Prefix suchen</translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;wine/runner exectuable path&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Pfad zum ausführbaren wine/runner&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <source>Browse Wine Path</source>
+ <translation>Wine-Pfad suchen</translation>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation>Erweitert</translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;When supported.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Falls unterstützt.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <source>ESYNC</source>
+ <translation>ESYNC</translation>
+ </message>
+ <message>
+ <source>FSYNC</source>
+ <translation>FSYNC</translation>
+ </message>
+ <message>
+ <source>Protocol</source>
+ <translation>Protokoll</translation>
+ </message>
+ <message>
+ <source>Freetrack</source>
+ <translation>Freetrack</translation>
+ </message>
+ <message>
+ <source>NPClient</source>
+ <translation>NPClient</translation>
+ </message>
+ <message>
+ <source>Both</source>
+ <translation>Beides</translation>
+ </message>
+ <message>
+ <source>Proton (select version and mode)</source>
+ <translation>Proton (wähle Version und Modus)</translation>
+ </message>
+ <message>
+ <source>Steam Play (select Steam Application ID)</source>
+ <translation>Steam Play (wähle Steam Applikation ID)</translation>
+ </message>
+ <message>
+ <source>UMU enabled Launchers (select prefix)</source>
+ <translation>UMU unterstützte Launcher (wähle Prefix)</translation>
+ </message>
+ <message>
+ <source>Wine (select version and prefix)</source>
+ <translation>Wine (wähle Version und Prefix)</translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Steam Play is Steams System to run Windows titles on Linux via Proton.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Steam Play ist Steams System, um Windows Titel auf Linux, via Proton, auszuführen.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;UMU is a launcher that allows the use of Proton outside of Steam. Some game launchers like Lutris may use this to enable Proton support.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;UMU ist ein Launcher, der es erlaubt Proton außerhalb von Steam zu nutzen. Manche Spiel Launcher, wie Lutris, können dies für Proton Support nutzen.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>wine</name>
+ <message>
+ <source>Must specify application id for Proton (Steam Play)</source>
+ <translation>Die Application-ID für Proton (Steam Play) muss angegeben werden</translation>
+ </message>
+ <message>
+ <source>Wine prefix must be an absolute path (given &apos;%1&apos;)</source>
+ <translation>Wine-Prefix muss ein absoluter Pfad sein (&apos;%1&apos; angegeben)</translation>
+ </message>
+ <message>
+ <source>Failed to start Wine! Make sure the binary is set correctly.</source>
+ <translation>Starten von Wine fehlgeschlagen! Stelle sicher, dass der Programmpfad richtig gesetzt ist.</translation>
+ </message>
+ <message>
+ <source>Can&apos;t open shared memory mapping</source>
+ <translation>Shared-Memory-Mapping kann nicht geöffnet werden</translation>
+ </message>
+ <message>
+ <source>Prefix has not been defined!</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>wine_metadata</name>
+ <message>
+ <source>Wine -- Windows layer for Unix</source>
+ <translation>Wine -- Windows-Schicht für Unix</translation>
+ </message>
+ <message>
+ <source>X-Plane</source>
+ <translation>X-Plane</translation>
+ </message>
+</context>
+</TS>
diff --git a/proto-wine/lang/nl_NL.ts b/proto-wine/lang/nl_NL.ts
index 0298092b..bc3ef604 100644
--- a/proto-wine/lang/nl_NL.ts
+++ b/proto-wine/lang/nl_NL.ts
@@ -11,6 +11,10 @@
<source>Select Wine Prefix</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Select Proton Prefix</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UICFTControls</name>
@@ -39,14 +43,6 @@
<translation type="unfinished"></translation>
</message>
<message>
- <source>Steam application id</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>Proton (Steam Play)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
<source>Protocol</source>
<translation type="unfinished"></translation>
</message>
@@ -63,10 +59,6 @@
<translation type="unfinished"></translation>
</message>
<message>
- <source>Wine (select path and prefix)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;prefix&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
@@ -86,6 +78,30 @@
<source>Browse Wine Path</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Proton (select version and mode)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Steam Play (select Steam Application ID)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>UMU enabled Launchers (select prefix)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Wine (select version and prefix)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Steam Play is Steams System to run Windows titles on Linux via Proton.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;UMU is a launcher that allows the use of Proton outside of Steam. Some game launchers like Lutris may use this to enable Proton support.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>wine</name>
@@ -105,6 +121,10 @@
<source>Failed to start Wine! Make sure the binary is set correctly.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Prefix has not been defined!</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>wine_metadata</name>
diff --git a/proto-wine/lang/ru_RU.ts b/proto-wine/lang/ru_RU.ts
index c7e9c52e..a7702454 100644
--- a/proto-wine/lang/ru_RU.ts
+++ b/proto-wine/lang/ru_RU.ts
@@ -11,6 +11,10 @@
<source>Select Wine Prefix</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Select Proton Prefix</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UICFTControls</name>
@@ -39,14 +43,6 @@
<translation type="unfinished"></translation>
</message>
<message>
- <source>Steam application id</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>Proton (Steam Play)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
<source>Protocol</source>
<translation type="unfinished"></translation>
</message>
@@ -63,10 +59,6 @@
<translation type="unfinished"></translation>
</message>
<message>
- <source>Wine (select path and prefix)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;prefix&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
@@ -86,6 +78,30 @@
<source>Browse Wine Path</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Proton (select version and mode)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Steam Play (select Steam Application ID)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>UMU enabled Launchers (select prefix)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Wine (select version and prefix)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Steam Play is Steams System to run Windows titles on Linux via Proton.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;UMU is a launcher that allows the use of Proton outside of Steam. Some game launchers like Lutris may use this to enable Proton support.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>wine</name>
@@ -105,6 +121,10 @@
<source>Failed to start Wine! Make sure the binary is set correctly.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Prefix has not been defined!</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>wine_metadata</name>
diff --git a/proto-wine/lang/stub.ts b/proto-wine/lang/stub.ts
index 3366b44b..2c708749 100644
--- a/proto-wine/lang/stub.ts
+++ b/proto-wine/lang/stub.ts
@@ -11,6 +11,10 @@
<source>Select Wine Prefix</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Select Proton Prefix</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UICFTControls</name>
@@ -39,14 +43,6 @@
<translation type="unfinished"></translation>
</message>
<message>
- <source>Steam application id</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>Proton (Steam Play)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
<source>Protocol</source>
<translation type="unfinished"></translation>
</message>
@@ -63,10 +59,6 @@
<translation type="unfinished"></translation>
</message>
<message>
- <source>Wine (select path and prefix)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;prefix&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
@@ -86,6 +78,30 @@
<source>Browse Wine Path</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Proton (select version and mode)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Steam Play (select Steam Application ID)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>UMU enabled Launchers (select prefix)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Wine (select version and prefix)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Steam Play is Steams System to run Windows titles on Linux via Proton.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;UMU is a launcher that allows the use of Proton outside of Steam. Some game launchers like Lutris may use this to enable Proton support.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>wine</name>
@@ -105,6 +121,10 @@
<source>Failed to start Wine! Make sure the binary is set correctly.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Prefix has not been defined!</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>wine_metadata</name>
diff --git a/proto-wine/lang/zh_CN.ts b/proto-wine/lang/zh_CN.ts
index 0d285c7c..6884f266 100644
--- a/proto-wine/lang/zh_CN.ts
+++ b/proto-wine/lang/zh_CN.ts
@@ -11,6 +11,10 @@
<source>Select Wine Prefix</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Select Proton Prefix</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>UICFTControls</name>
@@ -39,14 +43,6 @@
<translation type="unfinished"></translation>
</message>
<message>
- <source>Steam application id</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <source>Proton (Steam Play)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
<source>Protocol</source>
<translation type="unfinished"></translation>
</message>
@@ -63,10 +59,6 @@
<translation type="unfinished"></translation>
</message>
<message>
- <source>Wine (select path and prefix)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;prefix&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation type="unfinished"></translation>
</message>
@@ -86,6 +78,30 @@
<source>Browse Wine Path</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Proton (select version and mode)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Steam Play (select Steam Application ID)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>UMU enabled Launchers (select prefix)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Wine (select version and prefix)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Steam Play is Steams System to run Windows titles on Linux via Proton.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;UMU is a launcher that allows the use of Proton outside of Steam. Some game launchers like Lutris may use this to enable Proton support.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>wine</name>
@@ -105,6 +121,10 @@
<source>Failed to start Wine! Make sure the binary is set correctly.</source>
<translation type="unfinished"></translation>
</message>
+ <message>
+ <source>Prefix has not been defined!</source>
+ <translation type="unfinished"></translation>
+ </message>
</context>
<context>
<name>wine_metadata</name>
diff --git a/proto-wine/proton.cpp b/proto-wine/proton.cpp
index 868a4004..998da748 100644
--- a/proto-wine/proton.cpp
+++ b/proto-wine/proton.cpp
@@ -10,28 +10,30 @@
#include <QDebug>
#include <QDir>
#include <QFileInfo>
-#include <QProcessEnvironment>
#include <QtGlobal>
+#include "proton.h"
static const char* steam_paths[] = {
"/.steam/steam/steamapps/compatdata",
"/.local/share/Steam/steamapps/compatdata",
+ "/.steam/debian-installation/steamapps/compatdata",
};
static const char* runtime_paths[] = {
"/.local/share/Steam/ubuntu12_32/steam-runtime",
"/.steam/ubuntu12_32/steam-runtime",
+ "/.steam/debian-installation/ubuntu12_32/steam-runtime",
};
-std::tuple<QProcessEnvironment, QString, bool> make_steam_environ(const QString& proton_dist_path, int appid)
+std::tuple<QProcessEnvironment, QString, bool> make_steam_environ(const QString& proton_dist_path)
{
using ret = std::tuple<QProcessEnvironment, QString, bool>;
auto env = QProcessEnvironment::systemEnvironment();
QString error = "";
QString home = qgetenv("HOME");
- QString runtime_path, app_wineprefix;
+ QString runtime_path;
auto expand = [&](QString x) {
x.replace("HOME", home);
@@ -49,14 +51,6 @@ std::tuple<QProcessEnvironment, QString, bool> make_steam_environ(const QString&
if (runtime_path.isEmpty())
error = QString("Couldn't find a Steam runtime.");
- for (const char* path : steam_paths) {
- QDir dir(QDir::homePath() + path + expand("/%1/pfx").arg(appid));
- if (dir.exists())
- app_wineprefix = dir.absolutePath();
- }
- if (app_wineprefix.isEmpty())
- error = QString("Couldn't find a Wineprefix for AppId %1").arg(appid);
-
QString path = expand(
":PROTON_DIST_PATH/bin"
);
@@ -79,14 +73,25 @@ std::tuple<QProcessEnvironment, QString, bool> make_steam_environ(const QString&
);
library_path += ':'; library_path += qgetenv("LD_LIBRARY_PATH");
env.insert("LD_LIBRARY_PATH", library_path);
- env.insert("WINEPREFIX", app_wineprefix);
return ret(env, error, error.isEmpty());
}
-QString proton_path(const QString& proton_dist_path)
+std::tuple<QString, QString, bool> make_wineprefix(int appid)
{
- return proton_dist_path + "/bin/wine";
+ using ret = std::tuple<QString, QString, bool>;
+ QString error = "";
+ QString app_wineprefix;
+ for (const char* path : steam_paths) {
+ QDir dir(QDir::homePath() + path + QString("/%1/pfx").arg(appid));
+ if (dir.exists())
+ app_wineprefix = dir.absolutePath();
+ }
+ if (app_wineprefix.isEmpty())
+ error = QString("Couldn't find a Wineprefix for AppId %1").arg(appid);
+
+ return ret(app_wineprefix, error, error.isEmpty());
}
+
#endif
diff --git a/proto-wine/proton.h b/proto-wine/proton.h
new file mode 100644
index 00000000..51539305
--- /dev/null
+++ b/proto-wine/proton.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#include <qchar.h>
+#include <qprocess.h>
+
+std::tuple<QProcessEnvironment, QString, bool> make_steam_environ(const QString& proton_dist_path);
+std::tuple<QString, QString, bool> make_wineprefix(int appid); \ No newline at end of file
diff --git a/qxt-mini/lang/de_DE.ts b/qxt-mini/lang/de_DE.ts
new file mode 100644
index 00000000..1552582e
--- /dev/null
+++ b/qxt-mini/lang/de_DE.ts
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+</TS>
diff --git a/spline/lang/de_DE.ts b/spline/lang/de_DE.ts
new file mode 100644
index 00000000..1552582e
--- /dev/null
+++ b/spline/lang/de_DE.ts
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+</TS>
diff --git a/tracker-easy/lang/de_DE.ts b/tracker-easy/lang/de_DE.ts
new file mode 100644
index 00000000..81e52cb0
--- /dev/null
+++ b/tracker-easy/lang/de_DE.ts
@@ -0,0 +1,250 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>EasyTracker::Metadata</name>
+ <message>
+ <source>Easy Tracker 1.1</source>
+ <translation>Easy Tracker 1.1</translation>
+ </message>
+</context>
+<context>
+ <name>UICPTClientControls</name>
+ <message>
+ <source>Easy Tracker Settings</source>
+ <translation>Easy-Tracker-Einstellungen</translation>
+ </message>
+ <message>
+ <source>Tracker</source>
+ <translation>Tracker</translation>
+ </message>
+ <message>
+ <source>Camera</source>
+ <translation>Kamera</translation>
+ </message>
+ <message>
+ <source>Desired capture framerate</source>
+ <translation>Angestrebte Aufnahmebildrate</translation>
+ </message>
+ <message>
+ <source> Hz</source>
+ <translation> Hz</translation>
+ </message>
+ <message>
+ <source>Camera settings (when available)</source>
+ <translation>Kamera-Einstellungen (falls verfügbar)</translation>
+ </message>
+ <message>
+ <source>Width</source>
+ <translation>Breite</translation>
+ </message>
+ <message>
+ <source>Height</source>
+ <translation>Höhe</translation>
+ </message>
+ <message>
+ <source>FPS</source>
+ <translation>FPS</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>Öffnen</translation>
+ </message>
+ <message>
+ <source>°</source>
+ <translation>°</translation>
+ </message>
+ <message>
+ <source>Device</source>
+ <translation>Gerät</translation>
+ </message>
+ <message>
+ <source>Desired capture height</source>
+ <translation>Angestrebte Aufnahmehöhe</translation>
+ </message>
+ <message>
+ <source> px</source>
+ <translation> px</translation>
+ </message>
+ <message>
+ <source>Desired capture width</source>
+ <translation>Angestrebte Aufnahmebreite</translation>
+ </message>
+ <message>
+ <source>Diagonal field of view</source>
+ <translation>Diagonales Sichtfeld</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>Einstellungen</translation>
+ </message>
+ <message>
+ <source>Debug (full size preview)</source>
+ <translation>Fehlersuche (Vorschau in voller Größe)</translation>
+ </message>
+ <message>
+ <source>Min size</source>
+ <translation>Minimale Größe</translation>
+ </message>
+ <message>
+ <source>Minimum point diameter</source>
+ <translation>Minimaler Punktdurchmesser</translation>
+ </message>
+ <message>
+ <source>Auto center</source>
+ <translation>Automatisch zentrieren</translation>
+ </message>
+ <message>
+ <source>Max size</source>
+ <translation>Maximale Größe</translation>
+ </message>
+ <message>
+ <source>Size in pixels of half the edge defining deadzone squares around tracked points</source>
+ <translation>Größe in Pixeln der halben Kante, die die Totbereichquadrate um die verfolgten Punkte definiert</translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use P3P or AP3P for three and four points setup. Use EPNP or ITERATIVE for five points setup. Inconsistent configuration will result in undefined behavior.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Benutze P3P oder AP3P für ein Drei- oder Vierpunkt-Setup. Benutze EPNP oder ITERATIVE für ein Fünfpunkt-Setup. Eine inkonsistente Konfiguration führt zu einem undefinierten Verhalten.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <source>Perspective-N-Point solver</source>
+ <translation>Perspektivischer N-Punkt-Löser</translation>
+ </message>
+ <message>
+ <source>Make sure you pick a solver supporting the number of marker you are using. For three points detection use either P3P or AP3P.</source>
+ <translation>Stelle sicher, einen Löser zu verwenden, der die Anzahl deiner verwendeten Markierungen unterstützt. Für die Erkennung von drei Punkten nutze entweder P3P oder AP3P.</translation>
+ </message>
+ <message>
+ <source>ITERATIVE</source>
+ <translation>ITERATIVE</translation>
+ </message>
+ <message>
+ <source>EPNP</source>
+ <translation>EPNP</translation>
+ </message>
+ <message>
+ <source>P3P</source>
+ <translation>P3P</translation>
+ </message>
+ <message>
+ <source>DLS</source>
+ <translation>DLS</translation>
+ </message>
+ <message>
+ <source>UPNP</source>
+ <translation>UPNP</translation>
+ </message>
+ <message>
+ <source>AP3P</source>
+ <translation>AP3P</translation>
+ </message>
+ <message>
+ <source>Deadzone</source>
+ <translation>Totbereich</translation>
+ </message>
+ <message>
+ <source>Maximum point diameter</source>
+ <translation>Maximaler Punktdurchmesser</translation>
+ </message>
+ <message>
+ <source>Auto center timeout</source>
+ <translation>Timeout für automatische Zentrierung</translation>
+ </message>
+ <message>
+ <source>If no valid pose can be determined after that much time the center pose will be used.</source>
+ <translation>Falls innerhalb dieses Zeitraums keine Pose erkannt wird, wird die zentrierte Pose verwendet.</translation>
+ </message>
+ <message>
+ <source> ms</source>
+ <translation> ms</translation>
+ </message>
+ <message>
+ <source>Model</source>
+ <translation>Modell</translation>
+ </message>
+ <message>
+ <source>Model type:</source>
+ <translation>Modelltyp:</translation>
+ </message>
+ <message>
+ <source>Hat three vertices</source>
+ <translation>Hut drei Eckpunkte</translation>
+ </message>
+ <message>
+ <source>Hat four vertices</source>
+ <translation>Hut vier Eckpunkte</translation>
+ </message>
+ <message>
+ <source>Hat five vertices</source>
+ <translation>Hut fünf Eckpunkte</translation>
+ </message>
+ <message>
+ <source>Clip three vertices</source>
+ <translation>Sticker drei Eckpunkte</translation>
+ </message>
+ <message>
+ <source>Vertices: </source>
+ <translation>Eckpunkte: </translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;X&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;X&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Y&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Y&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Z&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:12pt;&quot;&gt;Z&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <source>Top:</source>
+ <translation>Oben:</translation>
+ </message>
+ <message>
+ <source> mm</source>
+ <translation> mm</translation>
+ </message>
+ <message>
+ <source>Right:</source>
+ <translation>Rechts:</translation>
+ </message>
+ <message>
+ <source>Left:</source>
+ <translation>Links:</translation>
+ </message>
+ <message>
+ <source>Center:</source>
+ <translation>Mitte:</translation>
+ </message>
+ <message>
+ <source>Top right:</source>
+ <translation>Oben rechts:</translation>
+ </message>
+ <message>
+ <source>Top left:</source>
+ <translation>Oben links:</translation>
+ </message>
+ <message>
+ <source>Clip top:</source>
+ <translation>Sticker-Oberkante:</translation>
+ </message>
+ <message>
+ <source>Clip middle:</source>
+ <translation>Sticker-Mitte:</translation>
+ </message>
+ <message>
+ <source>Clip bottom:</source>
+ <translation>Sticker-Unterkante:</translation>
+ </message>
+ <message>
+ <source>About</source>
+ <translation>Über</translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Easy Tracker&lt;br/&gt;Version 1.1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;by Stéphane Lenclud&lt;/span&gt;&lt;/p&gt;&lt;p&gt;See &lt;a href=&quot;https://github.com/opentrack/opentrack/wiki/Easy-Tracker&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline; color:#9999aa;&quot;&gt;documentation on GitHub&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Easy Tracker&lt;br/&gt;Version 1.1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;von Stéphane Lenclud&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Siehe &lt;a href=&quot;https://github.com/opentrack/opentrack/wiki/Easy-Tracker&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline; color:#9999aa;&quot;&gt;Dokumentation auf GitHub&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+</context>
+</TS>
diff --git a/tracker-freepie-udp/lang/de_DE.ts b/tracker-freepie-udp/lang/de_DE.ts
new file mode 100644
index 00000000..27f3bc39
--- /dev/null
+++ b/tracker-freepie-udp/lang/de_DE.ts
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>UI_freepie_udp_dialog</name>
+ <message>
+ <source>Tracker settings</source>
+ <translation>Tracker-Einstellungen</translation>
+ </message>
+ <message>
+ <source>UDP port</source>
+ <translation>UDP-Port</translation>
+ </message>
+ <message>
+ <source>Axis order</source>
+ <translation>Achsen-Reihenfolge</translation>
+ </message>
+ <message>
+ <source>output yaw</source>
+ <translation>Gieren-Ausgabe</translation>
+ </message>
+ <message>
+ <source>input yaw</source>
+ <translation>Gieren-Eingabe</translation>
+ </message>
+ <message>
+ <source>input pitch</source>
+ <translation>Nicken-Eingabe</translation>
+ </message>
+ <message>
+ <source>input roll</source>
+ <translation>Rollen-Eingabe</translation>
+ </message>
+ <message>
+ <source>output pitch</source>
+ <translation>Nicken-Ausgabe</translation>
+ </message>
+ <message>
+ <source>output roll</source>
+ <translation>Rollen-Ausgabe</translation>
+ </message>
+ <message>
+ <source>Add to axis</source>
+ <translation>Zur Achse hinzufügen</translation>
+ </message>
+ <message>
+ <source>yaw</source>
+ <translation>Gieren</translation>
+ </message>
+ <message>
+ <source>0</source>
+ <translation>0</translation>
+ </message>
+ <message>
+ <source>+90</source>
+ <translation>+90</translation>
+ </message>
+ <message>
+ <source>-90</source>
+ <translation>-90</translation>
+ </message>
+ <message>
+ <source>+180</source>
+ <translation>+180</translation>
+ </message>
+ <message>
+ <source>-180</source>
+ <translation>-180</translation>
+ </message>
+ <message>
+ <source>pitch</source>
+ <translation>Nicken</translation>
+ </message>
+ <message>
+ <source>roll</source>
+ <translation>Rollen</translation>
+ </message>
+</context>
+<context>
+ <name>meta_freepie</name>
+ <message>
+ <source>FreePIE UDP receiver</source>
+ <translation>FreePIE-UDP-Empfänger</translation>
+ </message>
+</context>
+</TS>
diff --git a/tracker-fusion/lang/de_DE.ts b/tracker-fusion/lang/de_DE.ts
new file mode 100644
index 00000000..3019b655
--- /dev/null
+++ b/tracker-fusion/lang/de_DE.ts
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>fusion_dialog</name>
+ <message>
+ <source>Fusion tracker only works when distinct trackers are selected for rotation and position.</source>
+ <translation>Der Fusion-Tracker funktioniert nur, wenn für Rotation und Position unterschiedliche Tracker ausgewählt wurden.</translation>
+ </message>
+</context>
+<context>
+ <name>fusion_metadata</name>
+ <message>
+ <source>Fusion</source>
+ <translation>Fusion</translation>
+ </message>
+</context>
+<context>
+ <name>fusion_tracker</name>
+ <message>
+ <source>Fusion tracker</source>
+ <translation>Fusion-Tracker</translation>
+ </message>
+ <message>
+ <source>Trackers not selected.</source>
+ <translation>Keine Tracker ausgewählt.</translation>
+ </message>
+ <message>
+ <source>Select different trackers for rotation and position.</source>
+ <translation>Wähle unterschiedliche Tracker für Rotation und Position.</translation>
+ </message>
+</context>
+<context>
+ <name>fusion_ui</name>
+ <message>
+ <source>Fusion</source>
+ <translation>Fusion</translation>
+ </message>
+ <message>
+ <source>Set distinct trackers for rotation and position input.</source>
+ <translation>Wähle unterschiedliche Tracker für Rotations- und Positionseingabe.</translation>
+ </message>
+ <message>
+ <source>Configure the trackers on the main window. It&apos;s required that they&apos;re both distinct, and both are set to something.</source>
+ <translation>Konfiguriere die Tracker im Hauptfenster. Es ist unbedingt erforderlich, dass zwei unterschiedliche Tracker ausgewählt werden, und beides zumindest irgendeinen Tracker auswählt.</translation>
+ </message>
+ <message>
+ <source>Rotation</source>
+ <translation>Rotation</translation>
+ </message>
+ <message>
+ <source>Position</source>
+ <translation>Position</translation>
+ </message>
+</context>
+</TS>
diff --git a/tracker-linux-joystick/lang/de_DE.ts b/tracker-linux-joystick/lang/de_DE.ts
new file mode 100644
index 00000000..9f03ffe9
--- /dev/null
+++ b/tracker-linux-joystick/lang/de_DE.ts
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>UILinuxJoystickControls</name>
+ <message>
+ <source>Tracker settings</source>
+ <translation>Tracker-Einstellungen</translation>
+ </message>
+ <message>
+ <source>Device</source>
+ <translation>Gerät</translation>
+ </message>
+ <message>
+ <source>Mapping</source>
+ <translation>Abbildung</translation>
+ </message>
+ <message>
+ <source>Disabled</source>
+ <translation>Ausgeschaltet</translation>
+ </message>
+ <message>
+ <source>Joystick axis #1</source>
+ <translation>Joystick-Achse #1</translation>
+ </message>
+ <message>
+ <source>Joystick axis #2</source>
+ <translation>Joystick-Achse #2</translation>
+ </message>
+ <message>
+ <source>Joystick axis #3</source>
+ <translation>Joystick-Achse #3</translation>
+ </message>
+ <message>
+ <source>Joystick axis #4</source>
+ <translation>Joystick-Achse #4</translation>
+ </message>
+ <message>
+ <source>Joystick axis #5</source>
+ <translation>Joystick-Achse #5</translation>
+ </message>
+ <message>
+ <source>Joystick axis #6</source>
+ <translation>Joystick-Achse #6</translation>
+ </message>
+ <message>
+ <source>Joystick axis #7</source>
+ <translation>Joystick-Achse #7</translation>
+ </message>
+ <message>
+ <source>Joystick axis #8</source>
+ <translation>Joystick-Achse #8</translation>
+ </message>
+ <message>
+ <source>X</source>
+ <translation>X</translation>
+ </message>
+ <message>
+ <source>Y</source>
+ <translation>Y</translation>
+ </message>
+ <message>
+ <source>Z</source>
+ <translation>Z</translation>
+ </message>
+ <message>
+ <source>Yaw</source>
+ <translation>Gieren</translation>
+ </message>
+ <message>
+ <source>Pitch</source>
+ <translation>Nicken</translation>
+ </message>
+ <message>
+ <source>Roll</source>
+ <translation>Rollen</translation>
+ </message>
+</context>
+<context>
+ <name>joystickDll</name>
+ <message>
+ <source>Linux Joystick input</source>
+ <translation>Linux-Joystick-Eingabe</translation>
+ </message>
+</context>
+</TS>
diff --git a/tracker-neuralnet/CMakeLists.txt b/tracker-neuralnet/CMakeLists.txt
index e7bb3b1c..3729c789 100644
--- a/tracker-neuralnet/CMakeLists.txt
+++ b/tracker-neuralnet/CMakeLists.txt
@@ -33,9 +33,9 @@ if(OpenCV_FOUND AND ONNXRuntime_FOUND AND OpenMP_FOUND)
install(
FILES "models/head-localizer.onnx"
- "models/head-pose.onnx"
"models/head-pose-0.2-big.onnx"
"models/head-pose-0.2-small.onnx"
+ "models/head-pose-0.3-big-quantized.onnx"
DESTINATION "${opentrack-libexec}/models"
PERMISSIONS ${opentrack-perms-file}
)
diff --git a/tracker-neuralnet/ftnoir_tracker_neuralnet.cpp b/tracker-neuralnet/ftnoir_tracker_neuralnet.cpp
index a919bb81..c55ddf0c 100644
--- a/tracker-neuralnet/ftnoir_tracker_neuralnet.cpp
+++ b/tracker-neuralnet/ftnoir_tracker_neuralnet.cpp
@@ -66,13 +66,26 @@ QDir get_default_model_directory()
int enum_to_fps(int value)
{
+ int fps = 0;
+
switch (value)
{
- case fps_30: return 30;
- case fps_60: return 60;
- default: [[fallthrough]];
- case fps_default: return 0;
+ default: eval_once(qDebug() << "neuralnet tracker: invalid fps enum value");
+ [[fallthrough]];
+ case fps_default: fps = 0; break;
+ case fps_30: fps = 30; break;
+ case fps_60: fps = 60; break;
+ case fps_75: fps = 75; break;
+ case fps_125: fps = 125; break;
+ case fps_200: fps = 200; break;
+ case fps_50: fps = 50; break;
+ case fps_100: fps = 100; break;
+ case fps_120: fps = 120; break;
+ case fps_300: fps = 300; break;
+ case fps_250: fps = 250; break;
}
+
+ return fps;
}
@@ -414,7 +427,7 @@ QuatPose NeuralNetTracker::transform_to_world_pose(const cv::Quatf &face_rotatio
QuatPose NeuralNetTracker::compute_filtered_pose(const PoseEstimator::Face &face)
{
- if (fps_ > 0.01 && last_pose_ && poseestimator_->has_uncertainty())
+ if (fps_ > 0.001 && last_pose_ && poseestimator_->has_uncertainty())
{
auto image2world = [this](const cv::Quatf &face_rotation, const cv::Point2f& face_xy, const float face_size) {
return this->transform_to_world_pose(face_rotation, face_xy, face_size); };
@@ -667,14 +680,20 @@ void NeuralNetTracker::data(double *data)
const auto& my = tmp.R.col(1);
const auto& mz = tmp.R.col(2);
+ // For reference: https://en.wikipedia.org/wiki/Euler_angles. Section "Rotation matrix". The relevant matrix is
+ // under "Tait-Bryan angles", row with "Y_alpha Z_beta X_gamma = ...".
+ // Because for the NN tracker x is forward, and y is up. We can see that the x axis is independent of roll. Thus it
+ // is relatively easy to figure out the yaw and pitch angles (alpha and beta).
const float yaw = std::atan2(mx(2), mx(0));
const float pitch = -std::atan2(-mx(1), std::sqrt(mx(2)*mx(2)+mx(0)*mx(0)));
- const float roll = std::atan2(-my(2), mz(2));
+ // For the roll angle we recognize that the matrix entries in the second row contain cos(pitch)*cos(roll), and
+ // cos(pitch)*sin(roll). Using atan2 eliminates the common pitch factor and we obtain the roll angle.
+ const float roll = std::atan2(-mz(1), my(1));
{
constexpr double rad2deg = 180/M_PI;
data[Yaw] = rad2deg * yaw;
data[Pitch] = rad2deg * pitch;
- data[Roll] = rad2deg * roll;
+ data[Roll] = -rad2deg * roll;
// convert to cm
data[TX] = -tmp.t[2] * 0.1;
@@ -707,14 +726,6 @@ QString NeuralNetTracker::get_posenet_filename() const
}
-
-
-
-
-
-
-
-
void NeuralNetDialog::make_fps_combobox()
{
for (int k = 0; k < fps_MAX; k++)
@@ -855,7 +866,7 @@ void NeuralNetDialog::status_poll()
else
{
auto [ res, fps, inference_time ] = tracker_->stats();
- status = tr("%1x%2 @ %3 FPS / Inference: %4 ms").arg(res.width).arg(res.height).arg(int(fps)).arg(int(inference_time));
+ status = tr("%1x%2 @ %3 FPS / Inference: %4 ms").arg(res.width).arg(res.height).arg(int(fps)).arg(inference_time, 0, 'f', 1);
}
ui_.resolution_display->setText(status);
}
diff --git a/tracker-neuralnet/ftnoir_tracker_neuralnet.h b/tracker-neuralnet/ftnoir_tracker_neuralnet.h
index bafaa6e5..fe755f51 100644
--- a/tracker-neuralnet/ftnoir_tracker_neuralnet.h
+++ b/tracker-neuralnet/ftnoir_tracker_neuralnet.h
@@ -48,7 +48,15 @@ enum fps_choices
fps_default = 0,
fps_30 = 1,
fps_60 = 2,
- fps_MAX = 3
+ fps_75 = 3,
+ fps_125 = 4,
+ fps_200 = 5,
+ fps_50 = 6,
+ fps_100 = 7,
+ fps_120 = 8,
+ fps_300 = 9,
+ fps_250 = 10,
+ fps_MAX = 11,
};
struct resolution_tuple
@@ -84,7 +92,7 @@ struct Settings : opts {
value<int> resolution { b, "force-resolution", 0 };
value<double> deadzone_size { b, "deadzone-size", 1. };
value<double> deadzone_hardness { b, "deadzone-hardness", 1.5 };
- value<QString> posenet_file { b, "posenet-file", "head-pose.onnx" };
+ value<QString> posenet_file { b, "posenet-file", "head-pose-0.3-big-quantized.onnx" };
Settings();
};
diff --git a/tracker-neuralnet/lang/de_DE.ts b/tracker-neuralnet/lang/de_DE.ts
new file mode 100644
index 00000000..6261eec0
--- /dev/null
+++ b/tracker-neuralnet/lang/de_DE.ts
@@ -0,0 +1,172 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>Form</name>
+ <message>
+ <source>Tracker settings</source>
+ <translation>Tracker-Einstellungen</translation>
+ </message>
+ <message>
+ <source>Head Center Offset</source>
+ <translation>Versatz zur Kopfmitte</translation>
+ </message>
+ <message>
+ <source>Right</source>
+ <translation>Rechts</translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation>Vorwärts</translation>
+ </message>
+ <message>
+ <source>Up</source>
+ <translation>Hoch</translation>
+ </message>
+ <message>
+ <source> mm</source>
+ <translation> mm</translation>
+ </message>
+ <message>
+ <source>Use only yaw and pitch while calibrating.
+Don&apos;t roll or change position.</source>
+ <translation>Während der Kalibrierung nur gieren und nicken.
+Bitte nicht rollen oder die Position ändern.</translation>
+ </message>
+ <message>
+ <source>Start calibration</source>
+ <translation>Kalibrierung starten</translation>
+ </message>
+ <message>
+ <source>Camera Configuration</source>
+ <translation>Kamera-Konfiguration</translation>
+ </message>
+ <message>
+ <source>Diagonal FOV</source>
+ <translation>Diagonales Sichtfeld</translation>
+ </message>
+ <message>
+ <source>Camera name</source>
+ <translation>Kamera-Name</translation>
+ </message>
+ <message>
+ <source>Field of view. Needed to transform the pose to world coordinates.</source>
+ <translation>Sichtfeld. Benötigt, um die Pose in Welt-Koordinaten zu übersetzen.</translation>
+ </message>
+ <message>
+ <source>The requested resolution for cases where the camera delivers maximum frame rate only for a particular resolution. The image may still be downscaled to the internal resolution.</source>
+ <translation>Die angeforderte Auflösung für Fälle, in denen die Kamera die maximale Bildrate nur bei bestimmten Auflösungen ausgibt. Das Bild wird möglicherweise weiterhin herunterskaliert auf die interne Auflösung.</translation>
+ </message>
+ <message>
+ <source>Resolution</source>
+ <translation>Auflösung</translation>
+ </message>
+ <message>
+ <source>Requested video frame rate. Actual setting may not be supported by the camera.</source>
+ <translation>Angeforderte Bildrate. Die tatsächliche Einstellungen wird von der Kamera möglicherweise nicht unterstützt.</translation>
+ </message>
+ <message>
+ <source>Frames per second</source>
+ <translation>Bilder pro Sekunde</translation>
+ </message>
+ <message>
+ <source>MJPEG</source>
+ <translation>MJPEG</translation>
+ </message>
+ <message>
+ <source>Camera settings</source>
+ <translation>Kamera-Einstellungen</translation>
+ </message>
+ <message>
+ <source>Tuning / Debug</source>
+ <translation>Tuning / Fehlersuche</translation>
+ </message>
+ <message>
+ <source>Thread Count</source>
+ <translation>Anzahl der Threads</translation>
+ </message>
+ <message>
+ <source>Number of threads. Can be used to balance the CPU load between the game and the tracker.</source>
+ <translation>Anzahl der Threads. Kann verwendet werden, um die CPU-Last zwischen Spiel und Tracker zu balancieren.</translation>
+ </message>
+ <message>
+ <source>Show the image patch that the pose estimation model sees.</source>
+ <translation>Zeigt den Bildausschnitt, den das Modell zur Posenabschätzung sieht.</translation>
+ </message>
+ <message>
+ <source>Show Network Input</source>
+ <translation>Zeige Netzwerk-Eingabe</translation>
+ </message>
+ <message>
+ <source>ROI Smoothing Alpha</source>
+ <translation>ROI-Glättungsalpha</translation>
+ </message>
+ <message>
+ <source>Amount of smoothing of the face region coordinates. Can help stabilize the pose.</source>
+ <translation>Umfang der Glättung der Gesichtkoordinaten. Kann helfen, die Pose zu stabilisieren.</translation>
+ </message>
+ <message>
+ <source>ROI Zoom</source>
+ <translation>ROI-Zoom</translation>
+ </message>
+ <message>
+ <source>Zoom factor for the face region. Applied before the patch is fed into the pose estimation model. There is a sweet spot near 1.</source>
+ <translation>Zoom-Faktor der Gesichtsregion. Wird angewendet, bevor der Bildausschnitt zum Posen-Abschätzungsmodell gesendet wird. Der Sweet-Spot liegt nahe bei 1.</translation>
+ </message>
+ <message>
+ <source>Select the pose network. Changes take affect on the next tracker start</source>
+ <translation>Wählt das Pose-Netzwerk. Die Änderungen treten beim nächsten Start des Trackers inkraft</translation>
+ </message>
+ <message>
+ <source>Select Pose Net ONNX</source>
+ <translation>Wähle Pose-Netzwerk ONNX</translation>
+ </message>
+ <message>
+ <source>&lt;the pose net file&gt;</source>
+ <translation>&lt;die pose netzwerk datei&gt;</translation>
+ </message>
+</context>
+<context>
+ <name>neuralnet_tracker_ns::NeuralNetDialog</name>
+ <message>
+ <source>Default</source>
+ <translation>Standard</translation>
+ </message>
+ <message>
+ <source>Tracker Offline</source>
+ <translation>Tracker offline</translation>
+ </message>
+ <message>
+ <source>%1x%2 @ %3 FPS / Inference: %4 ms</source>
+ <translation>%1x%2 @ %3 FPS / Inferenz: %4 ms</translation>
+ </message>
+ <message>
+ <source>%1 yaw samples. Yaw more to %2 samples for stable calibration.</source>
+ <translation>%1 Gieren-Proben. Weiterhin gieren bis %2 Proben für eine stabile Kalibrierung.</translation>
+ </message>
+ <message>
+ <source>%1 pitch samples. Pitch more to %2 samples for stable calibration.</source>
+ <translation>%1 Nicken-Proben. Weiterhin nicken bis %2 Proben für eine stabile Kalibrierung.</translation>
+ </message>
+ <message>
+ <source>%1 samples. Over %2, good!</source>
+ <translation>%1 Proben. Mehr als %2, gut!</translation>
+ </message>
+ <message>
+ <source>Stop calibration</source>
+ <translation>Kalibrierung stoppen</translation>
+ </message>
+ <message>
+ <source>Start calibration</source>
+ <translation>Kalibrierung starten</translation>
+ </message>
+ <message>
+ <source>Select Pose Net ONNX</source>
+ <translation>Wähle Pose-Netzwerk ONNX</translation>
+ </message>
+ <message>
+ <source>ONNX Files (*.onnx)</source>
+ <translation>ONNX-Dateien (*.onnx)</translation>
+ </message>
+</context>
+</TS>
diff --git a/tracker-neuralnet/models/head-pose.onnx b/tracker-neuralnet/models/head-pose-0.3-big-quantized.onnx
index dcb55dcc..7f875c63 100644
--- a/tracker-neuralnet/models/head-pose.onnx
+++ b/tracker-neuralnet/models/head-pose-0.3-big-quantized.onnx
Binary files differ
diff --git a/tracker-pt/lang/de_DE.ts b/tracker-pt/lang/de_DE.ts
new file mode 100644
index 00000000..30ab42c2
--- /dev/null
+++ b/tracker-pt/lang/de_DE.ts
@@ -0,0 +1,378 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>UICPTClientControls</name>
+ <message>
+ <source>PointTracker Settings</source>
+ <translation>PointTracker-Einstellungen</translation>
+ </message>
+ <message>
+ <source>Camera</source>
+ <translation>Kamera</translation>
+ </message>
+ <message>
+ <source>Camera settings</source>
+ <translation>Kamera-Einstellungen</translation>
+ </message>
+ <message>
+ <source>This should be 56° or 76° for the PS3 Eye, dependent upon the physical lens setting. It&apos;s only neccessary to get position correspond to real-world values.</source>
+ <translation>Für die PS3 Eye sollte dies 56° oder 76° sein, abhängig von der Einstellung der physikalischen Linse. Dies wird nur benutzt, um die Position aus den Welt-Koordinaten zur ermitteln.</translation>
+ </message>
+ <message>
+ <source>Diagonal field of view</source>
+ <translation>Diagonales Sichtfeld</translation>
+ </message>
+ <message>
+ <source>Dynamic pose (for caps only, never clips)</source>
+ <translation>Dynamische Pose (nur für Hüte, niemals Sticker)</translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;For LEDs, &apos;Natural&apos; is the fastest grayscale mode thanks to optimized SIMD code. Color key allows to track regular pieces of colored paper.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;‚Natürlich‘ ist, dank des optimierten SIMD-Codes, die schnellste Methode für LEDs. Mit dem Farbschlüssel kann man normale farbige Papierstücke tracken.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <source>Color channels used</source>
+ <translation>Benutzte Farbkanäle</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>Öffnen</translation>
+ </message>
+ <message>
+ <source>Enable MJPEG compression for high-speed cameras other than the PS3 Eye. Windows only.</source>
+ <translation>Aktiviert MJPEG-Kompression für Hochgeschwindigkeitskameras, PS3 Eye ausgenommen. Nur für Windows.</translation>
+ </message>
+ <message>
+ <source>MJPEG compression</source>
+ <translation>MJPEG-Kompression</translation>
+ </message>
+ <message>
+ <source>FPS</source>
+ <translation>FPS</translation>
+ </message>
+ <message>
+ <source>Width</source>
+ <translation>Breite</translation>
+ </message>
+ <message>
+ <source>Chroma key includes overexposed pixels</source>
+ <translation>Chroma-Key enthält überbelichtete Pixel</translation>
+ </message>
+ <message>
+ <source>Camera settings (when available)</source>
+ <translation>Kamera-Einstellungen (falls verfügbar)</translation>
+ </message>
+ <message>
+ <source> ms</source>
+ <translation> ms</translation>
+ </message>
+ <message>
+ <source>Desired capture width</source>
+ <translation>Angestrebte Aufnahmebreite</translation>
+ </message>
+ <message>
+ <source> px</source>
+ <translation> px</translation>
+ </message>
+ <message>
+ <source>Dynamic pose timeout</source>
+ <translation>Dynamisches Pose-Timeout</translation>
+ </message>
+ <message>
+ <source>Device</source>
+ <translation>Gerät</translation>
+ </message>
+ <message>
+ <source>Height</source>
+ <translation>Höhe</translation>
+ </message>
+ <message>
+ <source>Desired capture framerate</source>
+ <translation>Angestrebte Aufnahme-Bildrate</translation>
+ </message>
+ <message>
+ <source> Hz</source>
+ <translation> Hz</translation>
+ </message>
+ <message>
+ <source>Grayscale BT.709</source>
+ <translation>Graustufen BT.709</translation>
+ </message>
+ <message>
+ <source>Grayscale (from hardware)</source>
+ <translation>Graustufen (gemäß Hardware)</translation>
+ </message>
+ <message>
+ <source>Red only</source>
+ <translation>nur Rot</translation>
+ </message>
+ <message>
+ <source>Green only</source>
+ <translation>nur Grün</translation>
+ </message>
+ <message>
+ <source>Blue only</source>
+ <translation>nur Blau</translation>
+ </message>
+ <message>
+ <source>Red chroma key</source>
+ <translation>Roter Chroma-Key</translation>
+ </message>
+ <message>
+ <source>Green chroma key</source>
+ <translation>Grüner Chroma-Key</translation>
+ </message>
+ <message>
+ <source>Blue chroma key</source>
+ <translation>Blauer Chroma-Key</translation>
+ </message>
+ <message>
+ <source>Cyan chroma key</source>
+ <translation>Cyan-Chroma-Key</translation>
+ </message>
+ <message>
+ <source>Yellow chroma key</source>
+ <translation>Gelber Chroma-Key</translation>
+ </message>
+ <message>
+ <source>Magenta chroma key</source>
+ <translation>Magenta-Chroma-Key</translation>
+ </message>
+ <message>
+ <source>°</source>
+ <translation>°</translation>
+ </message>
+ <message>
+ <source>Desired capture height</source>
+ <translation>Angestrebte Aufnahmehöhe</translation>
+ </message>
+ <message>
+ <source>Chroma key strength</source>
+ <translation>Chroma-Key-Stärke</translation>
+ </message>
+ <message>
+ <source>Point extraction</source>
+ <translation>Punktextraktion</translation>
+ </message>
+ <message>
+ <source>Threshold</source>
+ <translation>Schwelle</translation>
+ </message>
+ <message>
+ <source>Set minimum size to avoid small stray lights from being treated as points.</source>
+ <translation>Setzt die Mindestgröße, um zu verhindern, dass kleine Streulichter als Punkte erkannt werden.</translation>
+ </message>
+ <message>
+ <source>Min size</source>
+ <translation>Mindestgröße</translation>
+ </message>
+ <message>
+ <source>Max size</source>
+ <translation>Maximale Größe</translation>
+ </message>
+ <message>
+ <source>Intensity threshold for point extraction</source>
+ <translation>Intensitätsschwelle für die Punktextraktion</translation>
+ </message>
+ <message>
+ <source>Enable, slider sets point size</source>
+ <translation>Aktivieren, Regler setzt die Punktgröße</translation>
+ </message>
+ <message>
+ <source>Track dependent on point size and not absolute brightness. This may allow more stable tracking.</source>
+ <translation>Tracking abhängig von der Punktgröße anstelle der absoluten Helligkeit durchführen. Dies kann stabileres Tracking ermöglichen.</translation>
+ </message>
+ <message>
+ <source>Automatic threshold</source>
+ <translation>Automatische Schwelle</translation>
+ </message>
+ <message>
+ <source>Maximum point diameter</source>
+ <translation>Maximaler Punktdurchmesser</translation>
+ </message>
+ <message>
+ <source>Value</source>
+ <translation>Wert</translation>
+ </message>
+ <message>
+ <source>Minimum point diameter</source>
+ <translation>Minimaler Punktdurchmesser</translation>
+ </message>
+ <message>
+ <source>Model</source>
+ <translation>Modell</translation>
+ </message>
+ <message>
+ <source>Clip</source>
+ <translation>Sticker</translation>
+ </message>
+ <message>
+ <source>Model Dimensions</source>
+ <translation>Modellabmessungen</translation>
+ </message>
+ <message>
+ <source> mm</source>
+ <translation> mm</translation>
+ </message>
+ <message>
+ <source>Side</source>
+ <translation>Seitlich</translation>
+ </message>
+ <message>
+ <source>Front</source>
+ <translation>Vorne</translation>
+ </message>
+ <message>
+ <source>Cap</source>
+ <translation>Hut</translation>
+ </message>
+ <message>
+ <source>Custom</source>
+ <translation>Benutzerdefiniert</translation>
+ </message>
+ <message>
+ <source>z:</source>
+ <translation>z:</translation>
+ </message>
+ <message>
+ <source>x:</source>
+ <translation>x:</translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Location of the two remaining model points&lt;br/&gt;with respect to the reference point in default pose&lt;/p&gt;&lt;p&gt;Use any units you want, not necessarily centimeters.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Ort der verbleibenden zwei Modellpunkte&lt;br/&gt;unter Berücksichtigung der Referenzpunkte der Standard-Pose&lt;/p&gt;&lt;p&gt;Dies können beliebige Einheiten sein, nicht zwingend Zentimeter.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <source>y:</source>
+ <translation>y:</translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;P&lt;/span&gt;&lt;span style=&quot; font-size:16pt; vertical-align:sub;&quot;&gt;3&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;P&lt;/span&gt;&lt;span style=&quot; font-size:16pt; vertical-align:sub;&quot;&gt;3&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;P&lt;/span&gt;&lt;span style=&quot; font-size:16pt; vertical-align:sub;&quot;&gt;2&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:16pt;&quot;&gt;P&lt;/span&gt;&lt;span style=&quot; font-size:16pt; vertical-align:sub;&quot;&gt;2&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <source>Model position</source>
+ <translation>Modell-Position</translation>
+ </message>
+ <message>
+ <source>Use only yaw and pitch while calibrating.
+Don&apos;t roll or change position.</source>
+ <translation>Bitte nur gieren oder nicken während der Kalibrierung.
+Bitte nicht rollen oder die Position ändern.</translation>
+ </message>
+ <message>
+ <source>Start calibration</source>
+ <translation>Kalibrierung starten</translation>
+ </message>
+ <message>
+ <source>Filter</source>
+ <translation>Filter</translation>
+ </message>
+ <message>
+ <source>Point filter</source>
+ <translation>Punktfilter</translation>
+ </message>
+ <message>
+ <source>Limit</source>
+ <translation>Grenze</translation>
+ </message>
+ <message>
+ <source>Deadzone</source>
+ <translation>Totbereich</translation>
+ </message>
+ <message>
+ <source>Filter point centers prior to pose estimation.</source>
+ <translation>Punktmitten vor der Posen-Abschätzung filtern.</translation>
+ </message>
+ <message>
+ <source>Enable</source>
+ <translation>Einschalten</translation>
+ </message>
+ <message>
+ <source>About</source>
+ <translation>Über</translation>
+ </message>
+ <message>
+ <source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;FTNoIR PointTracker Plugin&lt;br/&gt;Version 1.1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;by Patrick Ruoff&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://ftnoirpt.sourceforge.net/&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline; color:#0000ff;&quot;&gt;Manual (external)&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
+ <translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;FTNoIR PointTracker Plugin&lt;br/&gt;Version 1.1&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;von Patrick Ruoff&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;http://ftnoirpt.sourceforge.net/&quot;&gt;&lt;span style=&quot; font-weight:600; text-decoration: underline; color:#0000ff;&quot;&gt;Anleitung (extern)&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
+ </message>
+ <message>
+ <source>Status</source>
+ <translation>Status</translation>
+ </message>
+ <message>
+ <source>Extracted Points:</source>
+ <translation>Extrahierte Punkte:</translation>
+ </message>
+ <message>
+ <source>Camera Info:</source>
+ <translation>Kamera-Info:</translation>
+ </message>
+</context>
+<context>
+ <name>pt_impl::TrackerDialog_PT</name>
+ <message>
+ <source>Brightness %1/255</source>
+ <translation>Helligkeit %1/255</translation>
+ </message>
+ <message>
+ <source>LED radius %1 pixels</source>
+ <translation>LED-Radius %1 Pixel</translation>
+ </message>
+ <message>
+ <source>%1 yaw samples. Yaw more to %2 samples for stable calibration.</source>
+ <translation>%1 Gieren-Proben. Weiterhin gieren bis %2 Proben für eine stabile Kalibrierung.</translation>
+ </message>
+ <message>
+ <source>%1 pitch samples. Pitch more to %2 samples for stable calibration.</source>
+ <translation>%1 Nicken-Proben. Weiterhin nicken bis %2 Proben für eine stabile Kalibrierung.</translation>
+ </message>
+ <message>
+ <source>%1 samples. Over %2, good!</source>
+ <translation>%1 Proben. Mehr als %2, gut!</translation>
+ </message>
+ <message>
+ <source>Stop calibration</source>
+ <translation>Kalibrierung stoppen</translation>
+ </message>
+ <message>
+ <source>Start calibration</source>
+ <translation>Kalibrierung starten</translation>
+ </message>
+ <message>
+ <source>%1x%2 @ %3 FPS</source>
+ <translation>%1x%2 @ %3 FPS</translation>
+ </message>
+ <message>
+ <source>%1 OK!</source>
+ <translation>%1 OKAY!</translation>
+ </message>
+ <message>
+ <source>%1 BAD!</source>
+ <translation>%1 SCHLECHT!</translation>
+ </message>
+ <message>
+ <source>Tracker offline</source>
+ <translation>Tracker offline</translation>
+ </message>
+</context>
+<context>
+ <name>pt_impl::Tracker_PT</name>
+ <message>
+ <source>Failed to open camera &apos;%1&apos;</source>
+ <translation>Öffnen der Kamera ‚%1‘ fehlgeschlagen</translation>
+ </message>
+</context>
+<context>
+ <name>pt_module::metadata_pt</name>
+ <message>
+ <source>PointTracker 1.1</source>
+ <translation>PointTracker 1.1</translation>
+ </message>
+</context>
+</TS>
diff --git a/tracker-pt/module/lang/de_DE.ts b/tracker-pt/module/lang/de_DE.ts
new file mode 100644
index 00000000..6c548aba
--- /dev/null
+++ b/tracker-pt/module/lang/de_DE.ts
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>pt_module::metadata_pt</name>
+ <message>
+ <source>PointTracker 1.1</source>
+ <translation>PointTracker 1.1</translation>
+ </message>
+</context>
+</TS>
diff --git a/tracker-s2bot/lang/de_DE.ts b/tracker-s2bot/lang/de_DE.ts
new file mode 100644
index 00000000..4071d117
--- /dev/null
+++ b/tracker-s2bot/lang/de_DE.ts
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>UI_s2bot_dialog</name>
+ <message>
+ <source>Tracker settings</source>
+ <translation>Tracker-Einstellungen</translation>
+ </message>
+ <message>
+ <source>Update frequency (Hz)</source>
+ <translation>Aktualisierungsfrequenz (Hz)</translation>
+ </message>
+ <message>
+ <source>Axis order</source>
+ <translation>Achsen-Reihenfolge</translation>
+ </message>
+ <message>
+ <source>output yaw</source>
+ <translation>Gieren-Ausgabe</translation>
+ </message>
+ <message>
+ <source>input yaw</source>
+ <translation>Gieren-Eingabe</translation>
+ </message>
+ <message>
+ <source>input pitch</source>
+ <translation>Nicken-Eingabe</translation>
+ </message>
+ <message>
+ <source>input roll</source>
+ <translation>Rollen-Eingabe</translation>
+ </message>
+ <message>
+ <source>input bearing</source>
+ <translation>Peilung-Eingabe</translation>
+ </message>
+ <message>
+ <source>output pitch</source>
+ <translation>Nicken-Ausgabe</translation>
+ </message>
+ <message>
+ <source>output roll</source>
+ <translation>Rollen-Ausgabe</translation>
+ </message>
+ <message>
+ <source>Add to axis</source>
+ <translation>Zur Achse hinzufügen</translation>
+ </message>
+ <message>
+ <source>yaw</source>
+ <translation>Gieren</translation>
+ </message>
+ <message>
+ <source>0</source>
+ <translation>0</translation>
+ </message>
+ <message>
+ <source>+90</source>
+ <translation>+90</translation>
+ </message>
+ <message>
+ <source>-90</source>
+ <translation>-90</translation>
+ </message>
+ <message>
+ <source>+180</source>
+ <translation>+180</translation>
+ </message>
+ <message>
+ <source>-180</source>
+ <translation>-180</translation>
+ </message>
+ <message>
+ <source>pitch</source>
+ <translation>Nicken</translation>
+ </message>
+ <message>
+ <source>roll</source>
+ <translation>Rollen</translation>
+ </message>
+</context>
+<context>
+ <name>meta_s2bot</name>
+ <message>
+ <source>S2Bot receiver</source>
+ <translation>S2Bot-Empfänger</translation>
+ </message>
+</context>
+</TS>
diff --git a/tracker-test/lang/de_DE.ts b/tracker-test/lang/de_DE.ts
new file mode 100644
index 00000000..e11372b6
--- /dev/null
+++ b/tracker-test/lang/de_DE.ts
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>test_metadata</name>
+ <message>
+ <source>Test tracker</source>
+ <translation>Test-Tracker</translation>
+ </message>
+</context>
+<context>
+ <name>test_ui</name>
+ <message>
+ <source>Sine wave</source>
+ <translation>Sinus-Welle</translation>
+ </message>
+ <message>
+ <source>Pressing &quot;Abort&quot; will immediately crash the application.</source>
+ <translation>Beim Klick auf „Abbrechen“ wird die Anwendung sofort abstürzen.</translation>
+ </message>
+</context>
+</TS>
diff --git a/tracker-udp/lang/de_DE.ts b/tracker-udp/lang/de_DE.ts
new file mode 100644
index 00000000..a609cd25
--- /dev/null
+++ b/tracker-udp/lang/de_DE.ts
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+<context>
+ <name>UICFTNClientControls</name>
+ <message>
+ <source>UDP tracker settings</source>
+ <translation>UDP-Tracker-Einstellungen</translation>
+ </message>
+ <message>
+ <source>Port</source>
+ <translation>Port</translation>
+ </message>
+ <message>
+ <source>Add to axis</source>
+ <translation>Zur Achse hinzufügen</translation>
+ </message>
+ <message>
+ <source>yaw</source>
+ <translation>Gieren</translation>
+ </message>
+ <message>
+ <source>0</source>
+ <translation>0</translation>
+ </message>
+ <message>
+ <source>+90</source>
+ <translation>+90</translation>
+ </message>
+ <message>
+ <source>-90</source>
+ <translation>-90</translation>
+ </message>
+ <message>
+ <source>+180</source>
+ <translation>+180</translation>
+ </message>
+ <message>
+ <source>-180</source>
+ <translation>-180</translation>
+ </message>
+ <message>
+ <source>pitch</source>
+ <translation>Nicken</translation>
+ </message>
+ <message>
+ <source>roll</source>
+ <translation>Rollen</translation>
+ </message>
+</context>
+<context>
+ <name>udp</name>
+ <message>
+ <source>Can&apos;t bind socket -- %1</source>
+ <translation>Kann nicht an Socket binden -- %1</translation>
+ </message>
+</context>
+<context>
+ <name>udp_receiver_dll</name>
+ <message>
+ <source>UDP over network</source>
+ <translation>UDP über Netzwerk</translation>
+ </message>
+</context>
+</TS>
diff --git a/video-opencv/impl-camera.cpp b/video-opencv/impl-camera.cpp
index 662eceb2..96081399 100644
--- a/video-opencv/impl-camera.cpp
+++ b/video-opencv/impl-camera.cpp
@@ -1,6 +1,7 @@
#include "impl.hpp"
#include "compat/sleep.hpp"
#include "video-property-page.hpp"
+#include <opencv2/core/utils/logger.hpp>
namespace opencv_camera_impl {
@@ -33,6 +34,7 @@ bool cam::is_open()
bool cam::start(info& args)
{
stop();
+ cv::utils::logging::setLogLevel(cv::utils::logging::LogLevel::LOG_LEVEL_WARNING);
cap.emplace(idx, video_capture_backend);
if (args.width > 0 && args.height > 0)
diff --git a/video-opencv/lang/de_DE.ts b/video-opencv/lang/de_DE.ts
new file mode 100644
index 00000000..1552582e
--- /dev/null
+++ b/video-opencv/lang/de_DE.ts
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+</TS>
diff --git a/video/lang/de_DE.ts b/video/lang/de_DE.ts
new file mode 100644
index 00000000..1552582e
--- /dev/null
+++ b/video/lang/de_DE.ts
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="de_DE">
+</TS>