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:
parent
85066fccc8
commit
d0658feb26
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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,16 +110,12 @@ 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
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
@ -5,33 +5,32 @@ 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
|
||||
|
@ -39,37 +38,32 @@ Button {
|
|||
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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue