From 03e64ff8680cd214f61fd56a2b6049c82b1b2d36 Mon Sep 17 00:00:00 2001
From: pabera <1260686+pabera@users.noreply.github.com>
Date: Thu, 4 Jan 2024 16:35:04 +0100
Subject: [PATCH] New card actions: play, pause, prev, next, toggle, repeat,
shuffle (#2179)
* Adding additional player controls to assign to cards
* streamline some RPC command namings across jukebox and webapp
* Fix typos
* Fix Repeat toggles
* Fix toggle_shuffle
* Fix typo in command
* Fix another typo
* Fix wrong parameter for shuffle
* Update German translation for single-repeat
* Simplify Shuffle option
* Simplify Repeat option
* Streamline Player functions with new set_ methods in jukebox
* Abstract OptionsSelector
* Refactor some code
* Fix indentation
* Rename set_ methods
* Undo some doc changes
---
documentation/developers/docker.md | 15 ++++-
documentation/developers/status.md | 7 +-
src/jukebox/components/playermpd/__init__.py | 55 +++++++++++++--
src/jukebox/components/rpc_command_alias.py | 18 +++++
src/webapp/public/locales/de/translation.json | 44 +++++++++---
src/webapp/public/locales/en/translation.json | 45 ++++++++++---
src/webapp/src/commands/index.js | 13 +++-
.../Cards/controls/actions/audio/index.js | 34 +++++++++-
.../actions/audio/slider-change-volume.js | 4 +-
.../controls/actions/synchronisation/index.js | 11 ++-
.../rfidcards/change-on-rfid-scan-options.js | 67 -------------------
.../Cards/controls/options-selector.js | 61 +++++++++++++++++
src/webapp/src/components/Player/controls.js | 34 +++++-----
src/webapp/src/components/Player/cover.js | 6 +-
src/webapp/src/components/Player/index.js | 2 +-
src/webapp/src/components/Player/seekbar.js | 2 +-
src/webapp/src/config.js | 9 ++-
src/webapp/src/i18n.js | 1 +
18 files changed, 297 insertions(+), 131 deletions(-)
delete mode 100644 src/webapp/src/components/Cards/controls/actions/synchronisation/rfidcards/change-on-rfid-scan-options.js
create mode 100644 src/webapp/src/components/Cards/controls/options-selector.js
diff --git a/documentation/developers/docker.md b/documentation/developers/docker.md
index d7242750e..80651ce84 100644
--- a/documentation/developers/docker.md
+++ b/documentation/developers/docker.md
@@ -47,7 +47,20 @@ They can be run individually or in combination. To do that, we use
### Mac
1. [Install Docker & Compose (Mac)](https://docs.docker.com/docker-for-mac/install/)
-2. [Install pulseaudio](https://gist.github.com/seongyongkim/b7d630a03e74c7ab1c6b53473b592712) (Other references: [[1]](https://devops.datenkollektiv.de/running-a-docker-soundbox-on-mac.html), [[2]](https://stackoverflow.com/a/50939994/1062438))
+2. Install pulseaudio
+ 1. Use Homebrew to install
+ ```
+ $ brew install pulseaudio
+ ```
+ 2. Enable pulseaudio network capabilities. In an editor, open `/opt/homebrew/Cellar/pulseaudio/16.1/etc/pulse/default.pa` (you might need to adapt this path to your own system settings). Uncomment the following line.
+ ```
+ load-module module-native-protocol-tcp
+ ```
+ 3. Restart the pulseaudio service
+ ```
+ $ brew services restart pulseaudio
+ ```
+ 4. If you have trouble with your audio, try these resources to troubleshoot: [[1]](https://gist.github.com/seongyongkim/b7d630a03e74c7ab1c6b53473b592712), [[2]](https://devops.datenkollektiv.de/running-a-docker-soundbox-on-mac.html), [[3]](https://stackoverflow.com/a/50939994/1062438)
> [!NOTE]
> In order for Pulseaudio to work properly with Docker on your Mac, you need to start Pulseaudio in a specific way. Otherwise MPD will throw an exception. See [Pulseaudio issues on Mac](#pulseaudio-issue-on-mac) for more info.
diff --git a/documentation/developers/status.md b/documentation/developers/status.md
index 2fb92897f..48c2b6c3b 100644
--- a/documentation/developers/status.md
+++ b/documentation/developers/status.md
@@ -107,10 +107,9 @@ Topics marked _in progress_ are already in the process of implementation by comm
- [ ] Folder configuration (_in progress_)
- [ ] [Reference](https://github.com/MiczFlor/RPi-Jukebox-RFID/wiki/MANUAL#manage-playout-behaviour)
- [ ] Resume: Save and restore position (how interact with shuffle?)
- - [ ] Single: Enable mpc single
- - [ ] Shuffle: Enable mpc random (not shuffle)
- - Rename to random, as this is mpc random
- - [ ] Loop: Loop playlist
+ - [ ] Repeat Playlist
+ - [ ] Repeat Song
+ - [ ] Shuffle
### MPD Player
diff --git a/src/jukebox/components/playermpd/__init__.py b/src/jukebox/components/playermpd/__init__.py
index e854ee5ee..c77c21051 100644
--- a/src/jukebox/components/playermpd/__init__.py
+++ b/src/jukebox/components/playermpd/__init__.py
@@ -335,11 +335,6 @@ def seek(self, new_time):
with self.mpd_lock:
self.mpd_client.seekcur(new_time)
- @plugs.tag
- def shuffle(self, random):
- # As long as we don't work with waiting lists (aka playlist), this implementation is ok!
- self.mpd_retry_with_mutex(self.mpd_client.random, 1 if random else 0)
-
@plugs.tag
def rewind(self):
"""
@@ -363,7 +358,6 @@ def replay(self):
@plugs.tag
def toggle(self):
"""Toggle pause state, i.e. do a pause / resume depending on current state"""
- logger.debug("Toggle")
with self.mpd_lock:
self.mpd_client.pause()
@@ -378,8 +372,27 @@ def replay_if_stopped(self):
if self.mpd_status['state'] == 'stop':
self.play_folder(self.music_player_status['player_status']['last_played_folder'])
+ # Shuffle
+ def _shuffle(self, random):
+ # As long as we don't work with waiting lists (aka playlist), this implementation is ok!
+ self.mpd_retry_with_mutex(self.mpd_client.random, 1 if random else 0)
+
@plugs.tag
- def repeatmode(self, mode):
+ def shuffle(self, option='toggle'):
+ if option == 'toggle':
+ if self.mpd_status['random'] == '0':
+ self._shuffle(1)
+ else:
+ self._shuffle(0)
+ elif option == 'enable':
+ self._shuffle(1)
+ elif option == 'disable':
+ self._shuffle(0)
+ else:
+ logger.error(f"'{option}' does not exist for 'shuffle'")
+
+ # Repeat
+ def _repeatmode(self, mode):
if mode == 'repeat':
repeat = 1
single = 0
@@ -394,6 +407,34 @@ def repeatmode(self, mode):
self.mpd_client.repeat(repeat)
self.mpd_client.single(single)
+ @plugs.tag
+ def repeat(self, option='toggle'):
+ if option == 'toggle':
+ if self.mpd_status['repeat'] == '0':
+ self._repeatmode('repeat')
+ elif self.mpd_status['repeat'] == '1' and self.mpd_status['single'] == '0':
+ self._repeatmode('single')
+ else:
+ self._repeatmode(None)
+ elif option == 'toggle_repeat':
+ if self.mpd_status['repeat'] == '0':
+ self._repeatmode('repeat')
+ else:
+ self._repeatmode(None)
+ elif option == 'toggle_repeat_single':
+ if self.mpd_status['single'] == '0':
+ self._repeatmode('single')
+ else:
+ self._repeatmode(None)
+ elif option == 'enable_repeat':
+ self._repeatmode('repeat')
+ elif option == 'enable_repeat_single':
+ self._repeatmode('single')
+ elif option == 'disable':
+ self._repeatmode(None)
+ else:
+ logger.error(f"'{option}' does not exist for 'repeat'")
+
@plugs.tag
def get_current_song(self, param):
return self.mpd_status
diff --git a/src/jukebox/components/rpc_command_alias.py b/src/jukebox/components/rpc_command_alias.py
index bb484891a..e56727ff4 100644
--- a/src/jukebox/components/rpc_command_alias.py
+++ b/src/jukebox/components/rpc_command_alias.py
@@ -36,6 +36,12 @@
'package': 'player',
'plugin': 'ctrl',
'method': 'play_folder'},
+ 'play': {
+ 'package': 'player',
+ 'plugin': 'ctrl',
+ 'method': 'play',
+ 'note': 'Play the currently selected song',
+ 'ignore_card_removal_action': True},
'pause': {
'package': 'player',
'plugin': 'ctrl',
@@ -57,6 +63,18 @@
'plugin': 'ctrl',
'method': 'toggle',
'ignore_card_removal_action': True},
+ 'shuffle': {
+ 'package': 'player',
+ 'plugin': 'ctrl',
+ 'method': 'shuffle',
+ 'note': 'Shuffle',
+ 'ignore_card_removal_action': True},
+ 'repeat': {
+ 'package': 'player',
+ 'plugin': 'ctrl',
+ 'method': 'repeat',
+ 'note': 'Repeat',
+ 'ignore_card_removal_action': True},
# VOLUME
'set_volume': {
diff --git a/src/webapp/public/locales/de/translation.json b/src/webapp/public/locales/de/translation.json
index 85d39b879..f3bd89782 100644
--- a/src/webapp/public/locales/de/translation.json
+++ b/src/webapp/public/locales/de/translation.json
@@ -23,7 +23,14 @@
"timer_fade_volume": "Fade volume",
"toggle_output": "Audio-Ausgang umschalten",
"sync_rfidcards_all": "Alle Audiodateien und Karteneinträge synchronisieren",
- "sync_rfidcards_change_on_rfid_scan": "Aktivierung ändern für 'on RFID scan' "
+ "sync_rfidcards_change_on_rfid_scan": "Aktivierung ändern für 'on RFID scan'",
+ "next_song": "Nächster Song",
+ "pause": "Pause",
+ "play": "Abspielen",
+ "prev_song": "Vorheriger Song",
+ "shuffle": "Zufallswiedergabe",
+ "repeat": "Wiedergabe wiederholen",
+ "toggle": "Abspielen/Pause umschalten"
}
},
"controls-selector": {
@@ -56,8 +63,25 @@
"no-music-selected": "Es ist keine Musik ausgewählt.",
"loading-song-error": "Während des Ladens des Songs ist ein Fehler aufgetreten."
},
- "volume": {
- "title": "Lautstärke Stufen"
+ "audio": {
+ "repeat": {
+ "description": "Wähle den zu setzenden Status.",
+ "label-toggle": "Umschalten - Schaltet durch 1) Wiedergabeliste Wiederholen, 2) Song Wiederholen, 3) Wiederholen Deaktiveren",
+ "label-toggle-repeat": "Wiedergabeliste Wiederholen umschalten",
+ "label-toggle-repeat-single": "Song Wiederholen umschalten",
+ "label-enable-repeat": "Wiedergabeliste Wiederholen aktivieren",
+ "label-enable-repeat-single": "Song Wiederholen aktivieren",
+ "label-disable": "Wiederholen deaktivieren"
+ },
+ "shuffle": {
+ "description": "Wähle den zu setzenden Status.",
+ "label-toggle": "Umschalten",
+ "label-enable": "Aktivieren",
+ "label-disable": "Deaktivieren"
+ },
+ "volume": {
+ "title": "Lautstärke Stufen"
+ }
},
"timers": {
"description": "Wähle die Anzahl der Minuten nachdem die Aktion ausgeführt werden soll."
@@ -138,17 +162,17 @@
"player": {
"controls": {
"shuffle": {
- "activate": "Shuffle aktivieren",
- "deactivate": "Shuffle deaktivieren"
+ "enable": "Zufallswiedergabe aktivieren",
+ "disable": "Zufallswiedergabe deaktivieren"
},
- "skip": "Zurück",
+ "prev_song": "Zurück",
"play": "Abspielen",
"pause": "Pause",
- "next": "Weiter",
+ "next_song": "Weiter",
"repeat": {
- "activate": "Wiederholen aktivieren",
- "activate-single": "1 Wiederholen aktivieren",
- "deactivate": "Wiederholen deaktivieren"
+ "enable": "Wiedergabeliste Wiederholen aktivieren",
+ "enable-single": "Song Wiederholen aktivieren",
+ "disable": "Wiederholen deaktivieren"
}
},
"cover": {
diff --git a/src/webapp/public/locales/en/translation.json b/src/webapp/public/locales/en/translation.json
index d03941eb6..348d3771d 100644
--- a/src/webapp/public/locales/en/translation.json
+++ b/src/webapp/public/locales/en/translation.json
@@ -23,7 +23,14 @@
"timer_fade_volume": "Fade volume",
"toggle_output": "Toggle audio output",
"sync_rfidcards_all": "Sync all audiofiles and card entries",
- "sync_rfidcards_change_on_rfid_scan": "Change activation of 'on RFID scan'"
+ "sync_rfidcards_change_on_rfid_scan": "Change activation of 'on RFID scan'",
+ "next_song": "Next song",
+ "pause": "Pause",
+ "play": "Play",
+ "prev_song": "Previous song",
+ "shuffle": "Shuffle",
+ "repeat": "Repeat",
+ "toggle": "Toggle Play/Pause"
}
},
"controls-selector": {
@@ -56,8 +63,25 @@
"no-music-selected": "No music selected",
"loading-song-error": "An error occurred while loading song."
},
- "volume": {
- "title": "Volume steps"
+ "audio": {
+ "repeat": {
+ "description": "Choose the state to set.",
+ "label-toggle": "Toggle - Loops through 1) Repeat playlist, 2) Repeat song, 3) Disable repeat",
+ "label-toggle-repeat": "Toggle Repeat Playlist",
+ "label-toggle-repeat-single": "Toggle Repeat Song",
+ "label-enable-repeat": "Enable Repeat Playlist",
+ "label-enable-repeat-single": "Enable Repeat Song",
+ "label-disable": "Disable"
+ },
+ "shuffle": {
+ "description": "Choose the state to set.",
+ "label-toggle": "Toggle",
+ "label-enable": "Enable",
+ "label-disable": "Disable"
+ },
+ "volume": {
+ "title": "Volume steps"
+ }
},
"timers": {
"description": "Choose the amount of minutes you want the action to be performed."
@@ -138,17 +162,17 @@
"player": {
"controls": {
"shuffle": {
- "activate": "Activate shuffle",
- "deactivate": "Deactivate shuffle"
+ "enable": "Enable shuffle",
+ "disable": "Disable shuffle"
},
- "skip": "Skip previous track",
+ "prev_song": "Skip to previous track",
"play": "Play",
"pause": "Pause",
- "next": "Skip next track",
+ "next_song": "Skip to next track",
"repeat": {
- "activate": "Activate repeat",
- "activate-single": "Activate single repeat",
- "deactivate": "Deactivate repeat"
+ "enable": "Enable Playlist repeat",
+ "enable-single": "Enable Song repeat",
+ "disable": "Disable repeat"
}
},
"cover": {
@@ -207,6 +231,7 @@
},
"secondswipe": {
"title": "Second Swipe",
+ "description": "Second action after the same card swiped again",
"restart": "Restart playlist",
"toggle": "Toggle pause / play",
"skip": "Skip to next track",
diff --git a/src/webapp/src/commands/index.js b/src/webapp/src/commands/index.js
index 2352e46b7..8c844d8da 100644
--- a/src/webapp/src/commands/index.js
+++ b/src/webapp/src/commands/index.js
@@ -82,25 +82,32 @@ const commands = {
plugin: 'ctrl',
method: 'pause',
},
- previous: {
+ prev_song: {
_package: 'player',
plugin: 'ctrl',
method: 'prev',
},
- next: {
+ next_song: {
_package: 'player',
plugin: 'ctrl',
method: 'next',
},
+ toggle: {
+ _package: 'player',
+ plugin: 'ctrl',
+ method: 'toggle',
+ },
shuffle: {
_package: 'player',
plugin: 'ctrl',
method: 'shuffle',
+ argKeys: ['option'],
},
repeat: {
_package: 'player',
plugin: 'ctrl',
- method: 'repeatmode',
+ method: 'repeat',
+ argKeys: ['option'],
},
seek: {
_package: 'player',
diff --git a/src/webapp/src/components/Cards/controls/actions/audio/index.js b/src/webapp/src/components/Cards/controls/actions/audio/index.js
index 1d3ddc465..aba96cdc2 100644
--- a/src/webapp/src/components/Cards/controls/actions/audio/index.js
+++ b/src/webapp/src/components/Cards/controls/actions/audio/index.js
@@ -2,10 +2,11 @@ import React from 'react';
import CommandSelector from '../../command-selector';
import SliderChangeVolume from './slider-change-volume';
+import OptionsSelector from '../../options-selector';
import { getActionAndCommand } from '../../../utils';
-const SelectVolume = ({
+const SelectAudioVolume = ({
actionData,
handleActionDataChange,
}) => {
@@ -23,8 +24,37 @@ const SelectVolume = ({
handleActionDataChange={handleActionDataChange}
/>
}
+ {command === 'shuffle' &&
+
+ }
+ {command === 'repeat' &&
+
+ }
>
);
};
-export default SelectVolume;
\ No newline at end of file
+export default SelectAudioVolume;
\ No newline at end of file
diff --git a/src/webapp/src/components/Cards/controls/actions/audio/slider-change-volume.js b/src/webapp/src/components/Cards/controls/actions/audio/slider-change-volume.js
index 2e70b489a..64f5edada 100644
--- a/src/webapp/src/components/Cards/controls/actions/audio/slider-change-volume.js
+++ b/src/webapp/src/components/Cards/controls/actions/audio/slider-change-volume.js
@@ -37,12 +37,12 @@ const SliderChangeVolume = ({
- {t('cards.controls.actions.volume.title')}
+ {t('cards.controls.actions.audio.volume.title')}
{command === 'sync_rfidcards_change_on_rfid_scan' &&
-
}
>
diff --git a/src/webapp/src/components/Cards/controls/actions/synchronisation/rfidcards/change-on-rfid-scan-options.js b/src/webapp/src/components/Cards/controls/actions/synchronisation/rfidcards/change-on-rfid-scan-options.js
deleted file mode 100644
index 6d2b2fde6..000000000
--- a/src/webapp/src/components/Cards/controls/actions/synchronisation/rfidcards/change-on-rfid-scan-options.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-
-import {
- Grid,
- FormControl,
- FormControlLabel,
- Radio,
- RadioGroup,
- Typography,
-} from '@mui/material';
-
-import {
- getActionAndCommand,
- getArgsValues,
-} from '../../../../utils';
-
-
-const ChangeOnRfidScan = ({
- actionData,
- handleActionDataChange,
-}) => {
- const { t } = useTranslation();
-
- const { action, command } = getActionAndCommand(actionData);
- const [option] = getArgsValues(actionData);
-
- const onChange = (event, option) => {
- handleActionDataChange(action, command, { option })
- };
-
- return (
-
-
-
- {t('cards.controls.actions.synchronisation.rfidcards.description')}
-
-
-
- }
- label={t('cards.controls.actions.synchronisation.rfidcards.label-toggle')}
- value="toggle"
- />
- }
- label={t('cards.controls.actions.synchronisation.rfidcards.label-enable')}
- value="enable"
- />
- }
- label={t('cards.controls.actions.synchronisation.rfidcards.label-disable')}
- value="disable"
- />
-
-
-
-
- );
-};
-
-export default ChangeOnRfidScan;
diff --git a/src/webapp/src/components/Cards/controls/options-selector.js b/src/webapp/src/components/Cards/controls/options-selector.js
new file mode 100644
index 000000000..7a2fd1b22
--- /dev/null
+++ b/src/webapp/src/components/Cards/controls/options-selector.js
@@ -0,0 +1,61 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+
+import {
+ Grid,
+ FormControl,
+ FormControlLabel,
+ Radio,
+ RadioGroup,
+ Typography,
+} from '@mui/material';
+
+import {
+ getActionAndCommand,
+ getArgsValues,
+} from '../utils.js';
+
+const OptionsSelector = ({
+ actionType,
+ actionData,
+ handleActionDataChange,
+ optionLabel,
+ options,
+}) => {
+ const { t } = useTranslation();
+ const { action, command } = getActionAndCommand(actionData);
+ const [option] = getArgsValues(actionData);
+
+ const onChange = (event, option) => {
+ handleActionDataChange(action, command, { option })
+ };
+
+ return (
+
+
+
+ {t(optionLabel)}
+
+
+
+ {options.map(({ labelKey, value }) => (
+ }
+ label={t(labelKey)}
+ value={value}
+ />
+ ))}
+
+
+
+
+ );
+};
+
+export default OptionsSelector;
diff --git a/src/webapp/src/components/Player/controls.js b/src/webapp/src/components/Player/controls.js
index dc433cef8..48a587a32 100644
--- a/src/webapp/src/components/Player/controls.js
+++ b/src/webapp/src/components/Player/controls.js
@@ -32,15 +32,11 @@ const Controls = () => {
} = state;
const toggleShuffle = () => {
- request('shuffle', { random: !isShuffle });
+ request('shuffle', { option: 'toggle' });
}
const toggleRepeat = () => {
- let mode = null;
- if (!isRepeat && !isSingle) mode = 'repeat';
- if (isRepeat && !isSingle) mode = 'single';
-
- request('repeat', { mode });
+ request('repeat', { option: 'toggle' });
}
useEffect(() => {
@@ -58,14 +54,14 @@ const Controls = () => {
const labelShuffle = () => (
isShuffle
- ? t('player.controls.shuffle.deactivate')
- : t('player.controls.shuffle.activate')
+ ? t('player.controls.shuffle.disable')
+ : t('player.controls.shuffle.enable')
);
const labelRepeat = () => {
- if (!isRepeat) return t('player.controls.repeat.activate');
- if (isRepeat && !isSingle) return t('player.controls.repeat.activate-single');
- if (isRepeat && isSingle) return t('player.controls.repeat.deactivate');
+ if (!isRepeat) return t('player.controls.repeat.enable');
+ if (isRepeat && !isSingle) return t('player.controls.repeat.enable-single');
+ if (isRepeat && isSingle) return t('player.controls.repeat.disable');
};
return (
@@ -89,14 +85,14 @@ const Controls = () => {
- {/* Skip previous track */}
+ {/* Skip to previous song */}
request('previous')}
+ onClick={e => request('prev_song')}
size="large"
sx={iconStyles}
- title={t('player.controls.skip')}
+ title={t('player.controls.prev_song')}
>
@@ -127,14 +123,14 @@ const Controls = () => {
}
- {/* Skip next track */}
+ {/* Skip to next song */}
request('next')}
+ onClick={e => request('next_song')}
size="large"
sx={iconStyles}
- title={t('player.controls.next')}
+ title={t('player.controls.next_song')}
>
diff --git a/src/webapp/src/components/Player/cover.js b/src/webapp/src/components/Player/cover.js
index d20133acb..a744b7b5f 100644
--- a/src/webapp/src/components/Player/cover.js
+++ b/src/webapp/src/components/Player/cover.js
@@ -33,7 +33,11 @@ const Cover = ({ coverImage }) => {
}
{!coverImage &&
{
if (result) {
setCoverImage(`/cover-cache/${result}`);
setBackgroundImage([
- 'linear-gradient(to bottom, rgba(18, 18, 18, 0.7), rgba(18, 18, 18, 1))',
+ 'linear-gradient(to bottom, rgba(18, 18, 18, 0.5), rgba(18, 18, 18, 1))',
`url(/cover-cache/${result})`
].join(','));
};
diff --git a/src/webapp/src/components/Player/seekbar.js b/src/webapp/src/components/Player/seekbar.js
index aab3682ee..b138bf827 100644
--- a/src/webapp/src/components/Player/seekbar.js
+++ b/src/webapp/src/components/Player/seekbar.js
@@ -69,7 +69,7 @@ const SeekBar = () => {
direction="row"
justifyContent="space-between"
sx={ {
- marginTop: '-20px',
+ marginTop: '-10px',
}}
>
diff --git a/src/webapp/src/config.js b/src/webapp/src/config.js
index 35b5a980e..482db205e 100644
--- a/src/webapp/src/config.js
+++ b/src/webapp/src/config.js
@@ -42,7 +42,14 @@ const JUKEBOX_ACTIONS_MAP = {
audio: {
commands: {
change_volume: {},
- toggle_output: {}
+ toggle_output: {},
+ play: {},
+ pause: {},
+ toggle: {},
+ next_song: {},
+ prev_song: {},
+ shuffle: {},
+ repeat: {},
},
},
diff --git a/src/webapp/src/i18n.js b/src/webapp/src/i18n.js
index b2a752fdd..d374abae3 100644
--- a/src/webapp/src/i18n.js
+++ b/src/webapp/src/i18n.js
@@ -18,6 +18,7 @@ i18n
// for all options read: https://www.i18next.com/overview/configuration-options
.init({
debug: true,
+ // lng: 'en',
fallbackLng: 'en',
interpolation: {
escapeValue: false, // not needed for react as it escapes by default