feat: disable language/translations selection

- make it conditionally available for testing via
Settings/Advanced/Enable translations
- display a tooltip and infobox explaining the current and future
situation
- upon app start, force the language to "en" if the translations are not
enabled; and suggest app restart when they get disabled

Fixes #14527
This commit is contained in:
Lukáš Tinkl 2024-04-29 14:02:19 +02:00 committed by Lukáš Tinkl
parent 85066fccc8
commit d0658feb26
9 changed files with 157 additions and 68 deletions

View File

@ -4,7 +4,7 @@ import ../../constants
# Local App Settings keys:
const LAS_KEY_LANGUAGE* = "global/language"
const DEFAULT_LOCALE = "en"
const DEFAULT_LAS_KEY_LANGUAGE* = "en"
const LAS_KEY_THEME* = "global/theme"
const DEFAULT_THEME = 2 #system theme, from qml
const LAS_KEY_GEOMETRY = "global/app_geometry"
@ -20,6 +20,8 @@ const LAS_KEY_FAKE_LOADING_SCREEN_ENABLED = "global/fake_loading_screen"
let DEFAULT_FAKE_LOADING_SCREEN_ENABLED = defined(production) and not TEST_MODE_ENABLED #enabled in production, disabled in development and e2e tests
const LAS_KEY_SHARDED_COMMUNITIES_ENABLED = "global/sharded_communities"
const DEFAULT_LAS_KEY_SHARDED_COMMUNITIES_ENABLED = false
const LAS_KEY_TRANSLATIONS_ENABLED = "global/translations_enabled"
const DEFAULT_LAS_KEY_TRANSLATIONS_ENABLED = false
QtObject:
type LocalAppSettings* = ref object of QObject
@ -42,7 +44,7 @@ QtObject:
proc languageChanged*(self: LocalAppSettings) {.signal.}
proc getLanguage*(self: LocalAppSettings): string {.slot.} =
self.settings.value(LAS_KEY_LANGUAGE, newQVariant(DEFAULT_LOCALE)).stringVal
self.settings.value(LAS_KEY_LANGUAGE, newQVariant(DEFAULT_LAS_KEY_LANGUAGE)).stringVal
proc setLanguage*(self: LocalAppSettings, value: string) {.slot.} =
self.settings.setValue(LAS_KEY_LANGUAGE, newQVariant(value))
self.languageChanged()
@ -127,22 +129,6 @@ QtObject:
write = setScrollDeceleration
notify = scrollDecelerationChanged
proc removeKey*(self: LocalAppSettings, key: string) =
if(self.settings.isNil):
return
self.settings.remove(key)
case key:
of LAS_KEY_LANGUAGE: self.languageChanged()
of LAS_KEY_THEME: self.themeChanged()
of LAS_KEY_GEOMETRY: self.geometryChanged()
of LAS_KEY_VISIBILITY: self.visibilityChanged()
of LAS_KEY_SCROLL_VELOCITY: self.scrollVelocityChanged()
of LAS_KEY_SCROLL_DECELERATION: self.scrollDecelerationChanged()
of LAS_KEY_CUSTOM_MOUSE_SCROLLING_ENABLED: self.isCustomMouseScrollingEnabledChanged()
proc getTestEnvironment*(self: LocalAppSettings): bool {.slot.} =
return TEST_MODE_ENABLED
@ -174,3 +160,35 @@ QtObject:
read = getWakuV2ShardedCommunitiesEnabled
write = setWakuV2ShardedCommunitiesEnabled
notify = wakuV2ShardedCommunitiesEnabledChanged
proc translationsEnabledChanged*(self: LocalAppSettings) {.signal.}
proc getTranslationsEnabled*(self: LocalAppSettings): bool {.slot.} =
self.settings.value(LAS_KEY_TRANSLATIONS_ENABLED, newQVariant(DEFAULT_LAS_KEY_TRANSLATIONS_ENABLED)).boolVal
proc setTranslationsEnabled*(self: LocalAppSettings, value: bool) {.slot.} =
if value == self.getTranslationsEnabled:
return
self.settings.setValue(LAS_KEY_TRANSLATIONS_ENABLED, newQVariant(value))
self.translationsEnabledChanged()
QtProperty[bool] translationsEnabled:
read = getTranslationsEnabled
write = setTranslationsEnabled
notify = translationsEnabledChanged
proc removeKey*(self: LocalAppSettings, key: string) =
if(self.settings.isNil):
return
self.settings.remove(key)
case key:
of LAS_KEY_LANGUAGE: self.languageChanged()
of LAS_KEY_THEME: self.themeChanged()
of LAS_KEY_GEOMETRY: self.geometryChanged()
of LAS_KEY_VISIBILITY: self.visibilityChanged()
of LAS_KEY_SCROLL_VELOCITY: self.scrollVelocityChanged()
of LAS_KEY_SCROLL_DECELERATION: self.scrollDecelerationChanged()
of LAS_KEY_CUSTOM_MOUSE_SCROLLING_ENABLED: self.isCustomMouseScrollingEnabledChanged()
of LAS_KEY_FAKE_LOADING_SCREEN_ENABLED: self.fakeLoadingScreenEnabledChanged()
of LAS_KEY_SHARDED_COMMUNITIES_ENABLED: self.wakuV2ShardedCommunitiesEnabledChanged()
of LAS_KEY_TRANSLATIONS_ENABLED: self.translationsEnabledChanged()

View File

@ -6,6 +6,7 @@ import app/core/main
import constants as main_constants
import app/global/global_singleton
import app/global/local_app_settings
import app/boot/app_controller
when defined(macosx) and defined(arm64):
@ -132,6 +133,11 @@ proc mainProc() =
let app = newQGuiApplication()
# force default language ("en") if not "Settings/Advanced/Enable translations"
if not singletonInstance.localAppSettings.getTranslationsEnabled():
if singletonInstance.localAppSettings.getLanguage() != DEFAULT_LAS_KEY_LANGUAGE:
singletonInstance.localAppSettings.setLanguage(DEFAULT_LAS_KEY_LANGUAGE)
# Required by the WalletConnectSDK view right after creating the QGuiApplication instance
initializeWebView()

View File

@ -8,10 +8,19 @@ import AppLayouts.Profile.stores 1.0
import Storybook 1.0
import utils 1.0
import mainui 1.0
SplitView {
id: root
Logs { id: logs }
Popups {
popupParent: root
rootStore: QtObject {}
communityTokensStore: QtObject {}
}
SplitView {
orientation: Qt.Vertical
SplitView.fillWidth: true
@ -19,8 +28,9 @@ SplitView {
LanguageView {
SplitView.fillWidth: true
SplitView.fillHeight: true
contentWidth: parent.width
contentWidth: parent.width - 150
languageSelectionEnabled: ctrlLanguageSelectionEnabled.checked
languageStore: LanguageStore {
property string currentLanguage: "en"
@ -41,6 +51,14 @@ SplitView {
state: 2
selected: true
}
ListElement {
locale: "cs_CZ"
name: "Czech"
shortName: "čeština"
flag: "🇨🇿"
state: 1
selected: false
}
}
function changeLanguage(language) {
@ -92,17 +110,13 @@ SplitView {
SplitView.preferredHeight: 200
logsView.logText: logs.logText
Switch {
id: ctrlLanguageSelectionEnabled
text: "Language selection enabled"
}
}
}
Control {
SplitView.minimumWidth: 300
SplitView.preferredWidth: 300
font.pixelSize: 13
// model editor will go here
}
}
// category: Components

View File

@ -118,9 +118,11 @@ Item {
*/
property int menuAlignment: StatusListPicker.MenuAlignment.Right
readonly property alias button: btn
/*!
\qmlproperty enum StatusListPicker::MenuAlignment
This property holds the allignment of the menu in terms of the button
This property holds the alignment of the menu in terms of the button
values can be Left, Right or Center
*/
enum MenuAlignment {
@ -216,7 +218,7 @@ Item {
contentColor: Theme.palette.primaryColor1
text: d.selectedItemsText
font.pixelSize: 13
type: StatusPickerButton.Type.Down
type: StatusPickerButton.PickerType.Down
onClicked: {
picker.visible = !picker.visible

View File

@ -5,71 +5,65 @@ import QtQuick.Layouts 1.15
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
import StatusQ.Controls 0.1
Button {
StatusButton {
id: root
property color bgColor: Theme.palette.baseColor2
property color contentColor: Theme.palette.baseColor1
property var type: StatusPickerButton.Type.Next
property int type: StatusPickerButton.PickerType.Next
/*!
\qmlproperty StatusAssetSettings StatusPickerButton::asset
This property holds the image settings information.
*/
property StatusAssetSettings asset: StatusAssetSettings {
asset {
width: 20
height: 20
imgIsIdenticon: false
}
enum Type {
enum PickerType {
Next,
Down
}
implicitWidth: 446
implicitHeight: 44
font.pixelSize: 15
horizontalPadding: 16
verticalPadding: 3
spacing: 4
icon.width: 16
icon.height: 16
background:Rectangle {
background: Rectangle {
radius: 8
color: root.bgColor
}
opacity: !root.interactive || !root.enabled ? 0.5 : 1
contentItem: RowLayout {
clip: true
spacing: root.spacing
StatusIcon {
icon: "tiny/chevron-down"
visible: root.type === StatusPickerButton.Type.Down
Layout.alignment: Qt.AlignVCenter
visible: root.type === StatusPickerButton.PickerType.Down
color: !Qt.colorEqual(root.contentColor, Theme.palette.baseColor1) ? root.contentColor : Theme.palette.directColor1
width: root.icon.width
height: root.icon.height
}
StatusRoundedImage {
visible: root.asset.name.toString() !== ""
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: root.asset.width
Layout.preferredHeight: root.asset.height
image.source: root.asset.name
}
StatusBaseText {
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
font.pixelSize: root.font.pixelSize
font: root.font
color: root.contentColor
text: root.text
clip: true
elide: Text.ElideRight
}
StatusIcon {
icon: "tiny/chevron-right"
visible: root.type === StatusPickerButton.Type.Next
Layout.alignment: Qt.AlignVCenter
visible: root.type === StatusPickerButton.PickerType.Next
color: !Qt.colorEqual(root.contentColor, Theme.palette.baseColor1) ? root.contentColor : Theme.palette.directColor1
width: root.icon.width
height: root.icon.height

View File

@ -10,9 +10,9 @@ import StatusQ.Core.Theme 0.1
\inqmlmodule StatusQ.Controls
\since StatusQ.Controls 0.1
\brief Displays a customizable WarningBox component.
Inherits \l{https://doc.qt.io/qt-5/qml-qtquick-controls2-control.html}{Item}.
Inherits \l{https://doc.qt.io/qt-5/qml-qtquick-controls2-control.html}{Control}.
The \c StatusWarningBox displays an customizable WarningBox for users to show an icon and text.
The \c StatusWarningBox displays a customizable WarningBox for users to show an icon and text.
For example:
\qml
@ -30,7 +30,6 @@ import StatusQ.Core.Theme 0.1
Control {
id: root
implicitWidth: 614
padding: 16
/*!
@ -70,6 +69,12 @@ Control {
*/
property int textSize: Theme.primaryTextFontSize
/*!
\qmlproperty Component StatusWarningBox::extraContentComponent
This property lets you add some extra component on the trailing side (like a button)
*/
property alias extraContentComponent: extraContent.sourceComponent
background: Rectangle {
radius: 8
opacity: 0.5
@ -93,12 +98,12 @@ Control {
StatusBaseText {
id: warningText
Layout.fillWidth: true
Layout.preferredHeight: contentHeight
wrapMode: Text.WordWrap
verticalAlignment: Text.AlignVCenter
font.pixelSize: root.textSize
color: root.textColor
}
Loader {
id: extraContent
}
}
}

View File

@ -278,6 +278,7 @@ StatusSectionLayout {
implicitWidth: parent.width
implicitHeight: parent.height
languageSelectionEnabled: localAppSettings.translationsEnabled
languageStore: root.store.languageStore
currencyStore: root.currencyStore
sectionTitle: root.store.getNameForSubsection(Constants.settingsSubsection.language)

View File

@ -339,6 +339,30 @@ SettingsContentBase {
width: parent.width
}
StatusSettingsLineButton {
anchors.leftMargin: 0
anchors.rightMargin: 0
text: qsTr("Enable translations")
isSwitch: true
switchChecked: localAppSettings.translationsEnabled
onClicked: {
localAppSettings.translationsEnabled = !localAppSettings.translationsEnabled
if (!checked)
Global.openPopup(disableLanguagesPopupComponent)
}
}
Component {
id: disableLanguagesPopupComponent
ConfirmationDialog {
destroyOnClose: true
headerSettings.title: qsTr("Language reset")
confirmationText: qsTr("Display language will be switched back to English. You must restart the application for changes to take effect.")
confirmButtonLabel: qsTr("Restart")
onConfirmButtonClicked: Utils.restartApplication()
}
}
// TODO: replace with StatusQ component
StatusSettingsLineButton {
anchors.leftMargin: 0
@ -479,7 +503,7 @@ SettingsContentBase {
onConfirmButtonClicked: {
root.advancedStore.toggleIsGoerliEnabled()
close()
Qt.quit()
Utils.restartApplication()
}
onCancelButtonClicked: {
close()

View File

@ -1,11 +1,12 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import utils 1.0
import shared.panels 1.0
import shared.popups 1.0
import StatusQ 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1 as StatusQUtils
@ -23,6 +24,7 @@ SettingsContentBase {
property LanguageStore languageStore
property var currencyStore
property bool languageSelectionEnabled
objectName: "languageView"
onVisibleChanged: { if(!visible) root.setViewIdleState()}
@ -93,6 +95,16 @@ SettingsContentBase {
Item { Layout.fillWidth: true }
StatusListPicker {
id: languagePicker
button.interactive: root.languageSelectionEnabled
StatusToolTip {
y: parent.height + Style.current.padding
margins: 0
visible: !root.languageSelectionEnabled && languagePicker.button.hovered
orientation: StatusToolTip.Orientation.Bottom
text: qsTr("Translations coming soon")
}
property string newKey
function descriptionForState(state) {
@ -105,13 +117,13 @@ SettingsContentBase {
inputList: SortFilterProxyModel {
sourceModel: root.languageStore.languageModel
// !Don't use proxy roles cause they harm performance a lot!
// "category" is the only role that can't be mocked by StatusListPicker::proxy
// due to StatusListPicker internal implementation limitation (ListView's section.property)
proxyRoles: [
ExpressionRole {
FastExpressionRole {
name: "category"
expression: languagePicker.descriptionForState(model.state)
expectedRoles: ["state"]
}
]
@ -129,7 +141,7 @@ SettingsContentBase {
proxy {
key: (model) => model.locale
name: (model) => model.name
shortName: (model) => model.native
shortName: (model) => model.native || model.shortName
symbol: (model) => ""
imageSource: (model) => StatusQUtils.Emoji.iconSource(model.flag)
selected: (model) => model.locale === root.languageStore.currentLanguage
@ -143,13 +155,28 @@ SettingsContentBase {
onItemPickerChanged: {
if(selected && root.languageStore.currentLanguage !== key) {
root.changeLanguage(key)
languageConfirmationDialog.active = true
languageConfirmationDialog.item.open()
Global.openPopup(languageConfirmationDialog)
}
}
}
}
StatusWarningBox {
Layout.fillWidth: true
Layout.bottomMargin: Style.current.padding
borderColor: Theme.palette.baseColor2
textColor: Theme.palette.directColor1
icon: "group-chat"
iconColor: Theme.palette.baseColor1
text: qsTr("We need your help to translate Status, so that together we can bring privacy and free speech to the people everywhere, including those who need it most.")
extraContentComponent: StatusFlatButton {
icon.name: "external-link"
text: qsTr("Learn more")
size: StatusBaseButton.Size.Small
onClicked: Global.openLinkWithConfirmation(Constants.externalStatusLinkWithHttps + '/translations', Constants.externalStatusLinkWithHttps)
}
}
Separator {
Layout.fillWidth: true
Layout.bottomMargin: Style.current.padding
@ -158,8 +185,7 @@ SettingsContentBase {
// Time format options:
Column {
Layout.fillWidth: true
Layout.topMargin: Style.current.padding
spacing: Style.current.padding
spacing: Constants.settingsSection.itemSpacing
StatusBaseText {
text: qsTr("Time Format")
}
@ -183,15 +209,14 @@ SettingsContentBase {
}
}
Loader {
Component {
id: languageConfirmationDialog
active: false
sourceComponent: ConfirmationDialog {
ConfirmationDialog {
destroyOnClose: true
headerSettings.title: qsTr("Change language")
confirmationText: qsTr("Display language has been changed. You must restart the application for changes to take effect.")
confirmButtonLabel: qsTr("Restart")
onConfirmButtonClicked: {
languageConfirmationDialog.active = false
Utils.restartApplication()
}
}