Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/server.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/settings/src/components/PersonalInfo/LanguageSection/Language.vue151
-rw-r--r--apps/settings/src/components/PersonalInfo/LanguageSection/LanguageSection.vue102
-rw-r--r--apps/settings/src/components/PersonalInfo/shared/HeaderBar.vue40
-rw-r--r--apps/settings/src/main-personal-info.js4
-rw-r--r--apps/settings/templates/settings/personal/personal.info.php28
5 files changed, 286 insertions, 39 deletions
diff --git a/apps/settings/src/components/PersonalInfo/LanguageSection/Language.vue b/apps/settings/src/components/PersonalInfo/LanguageSection/Language.vue
new file mode 100644
index 00000000000..df847e87442
--- /dev/null
+++ b/apps/settings/src/components/PersonalInfo/LanguageSection/Language.vue
@@ -0,0 +1,151 @@
+<!--
+ - @copyright 2021, Christopher Ng <chrng8@gmail.com>
+ -
+ - @author Christopher Ng <chrng8@gmail.com>
+ -
+ - @license GNU AGPL version 3 or any later version
+ -
+ - This program is free software: you can redistribute it and/or modify
+ - it under the terms of the GNU Affero General Public License as
+ - published by the Free Software Foundation, either version 3 of the
+ - License, or (at your option) any later version.
+ -
+ - This program is distributed in the hope that it will be useful,
+ - but WITHOUT ANY WARRANTY; without even the implied warranty of
+ - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ - GNU Affero General Public License for more details.
+ -
+ - You should have received a copy of the GNU Affero General Public License
+ - along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<template>
+ <div class="language">
+ <select
+ id="language"
+ ref="language"
+ name="language"
+ :placeholder="t('settings', 'Language')"
+ required
+ @input="onLanguageChange">
+ <option v-for="commonLanguage in commonLanguages"
+ :key="commonLanguage.code"
+ :selected="language.code === commonLanguage.code"
+ :value="commonLanguage.code">
+ {{ commonLanguage.name }}
+ </option>
+ <optgroup label="––––––––––" />
+ <option v-for="otherLanguage in otherLanguages"
+ :key="otherLanguage.code"
+ :selected="language.code === otherLanguage.code"
+ :value="otherLanguage.code">
+ {{ otherLanguage.name }}
+ </option>
+ </select>
+
+ <a
+ href="https://www.transifex.com/nextcloud/nextcloud/"
+ target="_blank"
+ rel="noreferrer noopener">
+ <em>{{ t('settings', 'Help translate') }}</em>
+ </a>
+ </div>
+</template>
+
+<script>
+import { showError } from '@nextcloud/dialogs'
+
+import { saveLanguage } from '../../../service/PersonalInfo/LanguageService'
+
+export default {
+ name: 'Language',
+
+ props: {
+ commonLanguages: {
+ type: Array,
+ required: true,
+ },
+ otherLanguages: {
+ type: Array,
+ required: true,
+ },
+ language: {
+ type: Object,
+ required: true,
+ },
+ },
+
+ data() {
+ return {
+ initialLanguage: this.language,
+ }
+ },
+
+ computed: {
+ allLanguages() {
+ return Object.freeze(
+ [...this.commonLanguages, ...this.otherLanguages]
+ .reduce((acc, { code, name }) => ({ ...acc, [code]: name }), {})
+ )
+ },
+ },
+
+ methods: {
+ async onLanguageChange(e) {
+ const language = this.constructLanguage(e.target.value)
+ this.$emit('update:language', language)
+
+ if (this.$refs.language?.checkValidity()) {
+ await this.updateLanguage(language)
+ }
+ },
+
+ async updateLanguage(language) {
+ try {
+ const responseData = await saveLanguage(language.code)
+ this.handleResponse({
+ language,
+ status: responseData.ocs?.meta?.status,
+ })
+ this.reloadPage()
+ } catch (e) {
+ this.handleResponse({
+ errorMessage: 'Unable to update language',
+ error: e,
+ })
+ }
+ },
+
+ constructLanguage(languageCode) {
+ return {
+ code: languageCode,
+ name: this.allLanguages[languageCode],
+ }
+ },
+
+ handleResponse({ language, status, errorMessage, error }) {
+ if (status === 'ok') {
+ // Ensure that local state reflects server state
+ this.initialLanguage = language
+ } else {
+ showError(t('settings', errorMessage))
+ this.logger.error(errorMessage, error)
+ }
+ },
+
+ reloadPage() {
+ location.reload()
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+.language {
+ display: grid;
+
+ a {
+ width: max-content;
+ }
+}
+</style>
diff --git a/apps/settings/src/components/PersonalInfo/LanguageSection/LanguageSection.vue b/apps/settings/src/components/PersonalInfo/LanguageSection/LanguageSection.vue
new file mode 100644
index 00000000000..1489b96a465
--- /dev/null
+++ b/apps/settings/src/components/PersonalInfo/LanguageSection/LanguageSection.vue
@@ -0,0 +1,102 @@
+<!--
+ - @copyright 2021, Christopher Ng <chrng8@gmail.com>
+ -
+ - @author Christopher Ng <chrng8@gmail.com>
+ -
+ - @license GNU AGPL version 3 or any later version
+ -
+ - This program is free software: you can redistribute it and/or modify
+ - it under the terms of the GNU Affero General Public License as
+ - published by the Free Software Foundation, either version 3 of the
+ - License, or (at your option) any later version.
+ -
+ - This program is distributed in the hope that it will be useful,
+ - but WITHOUT ANY WARRANTY; without even the implied warranty of
+ - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ - GNU Affero General Public License for more details.
+ -
+ - You should have received a copy of the GNU Affero General Public License
+ - along with this program. If not, see <http://www.gnu.org/licenses/>.
+-->
+
+<template>
+ <form
+ ref="form"
+ class="section"
+ @submit.stop.prevent="() => {}">
+ <HeaderBar
+ :account-property="accountProperty"
+ label-for="language"
+ :is-valid-form="isValidForm" />
+
+ <template v-if="isEditable">
+ <Language
+ :common-languages="commonLanguages"
+ :other-languages="otherLanguages"
+ :language.sync="language"
+ @update:language="onUpdateLanguage" />
+ </template>
+
+ <span v-else>
+ {{ t('settings', 'No language set') }}
+ </span>
+ </form>
+</template>
+
+<script>
+import { loadState } from '@nextcloud/initial-state'
+
+import Language from './Language'
+import HeaderBar from '../shared/HeaderBar'
+
+import { SETTING_PROPERTY_READABLE_ENUM } from '../../../constants/AccountPropertyConstants'
+
+const { languages: { activeLanguage, commonLanguages, otherLanguages } } = loadState('settings', 'personalInfoParameters', {})
+
+export default {
+ name: 'LanguageSection',
+
+ components: {
+ Language,
+ HeaderBar,
+ },
+
+ data() {
+ return {
+ accountProperty: SETTING_PROPERTY_READABLE_ENUM.LANGUAGE,
+ isValidForm: true,
+ commonLanguages,
+ otherLanguages,
+ language: activeLanguage,
+ }
+ },
+
+ computed: {
+ isEditable() {
+ return Boolean(this.language)
+ },
+ },
+
+ mounted() {
+ this.$nextTick(() => this.updateFormValidity())
+ },
+
+ methods: {
+ onUpdateLanguage() {
+ this.$nextTick(() => this.updateFormValidity())
+ },
+
+ updateFormValidity() {
+ this.isValidForm = this.$refs.form?.checkValidity()
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+form::v-deep button {
+ &:disabled {
+ cursor: default;
+ }
+}
+</style>
diff --git a/apps/settings/src/components/PersonalInfo/shared/HeaderBar.vue b/apps/settings/src/components/PersonalInfo/shared/HeaderBar.vue
index e4ff0846a07..3cb293c8a34 100644
--- a/apps/settings/src/components/PersonalInfo/shared/HeaderBar.vue
+++ b/apps/settings/src/components/PersonalInfo/shared/HeaderBar.vue
@@ -20,18 +20,21 @@
-->
<template>
- <h3>
+ <h3
+ :class="{ 'setting-property': isSettingProperty }">
<label :for="labelFor">
<!-- Already translated as required by prop validator -->
{{ accountProperty }}
</label>
- <FederationControl
- class="federation-control"
- :account-property="accountProperty"
- :handle-scope-change="handleScopeChange"
- :scope.sync="localScope"
- @update:scope="onScopeChange" />
+ <template v-if="scope && handleScopeChange">
+ <FederationControl
+ class="federation-control"
+ :account-property="accountProperty"
+ :handle-scope-change="handleScopeChange"
+ :scope.sync="localScope"
+ @update:scope="onScopeChange" />
+ </template>
<template v-if="isEditable && isMultiValueSupported">
<AddButton
@@ -46,7 +49,7 @@
import AddButton from './AddButton'
import FederationControl from './FederationControl'
-import { ACCOUNT_PROPERTY_READABLE_ENUM } from '../../../constants/AccountPropertyConstants'
+import { ACCOUNT_PROPERTY_READABLE_ENUM, SETTING_PROPERTY_READABLE_ENUM } from '../../../constants/AccountPropertyConstants'
export default {
name: 'HeaderBar',
@@ -60,11 +63,11 @@ export default {
accountProperty: {
type: String,
required: true,
- validator: (value) => Object.values(ACCOUNT_PROPERTY_READABLE_ENUM).includes(value),
+ validator: (value) => Object.values(ACCOUNT_PROPERTY_READABLE_ENUM).includes(value) || Object.values(SETTING_PROPERTY_READABLE_ENUM).includes(value),
},
handleScopeChange: {
type: Function,
- required: true,
+ default: null,
},
isEditable: {
type: Boolean,
@@ -84,7 +87,7 @@ export default {
},
scope: {
type: String,
- required: true,
+ default: null,
},
},
@@ -94,6 +97,12 @@ export default {
}
},
+ computed: {
+ isSettingProperty() {
+ return Object.values(SETTING_PROPERTY_READABLE_ENUM).includes(this.accountProperty)
+ },
+ },
+
methods: {
onAddAdditional() {
this.$emit('add-additional')
@@ -119,6 +128,15 @@ export default {
}
}
+ h3.setting-property {
+ width: 100%;
+ min-height: 38px;
+ display: inline-flex;
+ position: relative;
+ flex-wrap: nowrap;
+ justify-content: flex-start;
+ }
+
.federation-control {
margin: -12px 0 0 8px;
}
diff --git a/apps/settings/src/main-personal-info.js b/apps/settings/src/main-personal-info.js
index 72ed4c15230..78de03cf7cf 100644
--- a/apps/settings/src/main-personal-info.js
+++ b/apps/settings/src/main-personal-info.js
@@ -29,8 +29,8 @@ import logger from './logger'
import DisplayNameSection from './components/PersonalInfo/DisplayNameSection/DisplayNameSection'
import EmailSection from './components/PersonalInfo/EmailSection/EmailSection'
+import LanguageSection from './components/PersonalInfo/LanguageSection/LanguageSection'
-// eslint-disable-next-line camelcase
__webpack_nonce__ = btoa(getRequestToken())
Vue.mixin({
@@ -44,6 +44,8 @@ Vue.mixin({
const DisplayNameView = Vue.extend(DisplayNameSection)
const EmailView = Vue.extend(EmailSection)
+const LanguageView = Vue.extend(LanguageSection)
new DisplayNameView().$mount('#vue-displaynamesection')
new EmailView().$mount('#vue-emailsection')
+new LanguageView().$mount('#vue-languagesection')
diff --git a/apps/settings/templates/settings/personal/personal.info.php b/apps/settings/templates/settings/personal/personal.info.php
index 8b1e22f964d..7484870a936 100644
--- a/apps/settings/templates/settings/personal/personal.info.php
+++ b/apps/settings/templates/settings/personal/personal.info.php
@@ -245,33 +245,7 @@ script('settings', [
<div class="profile-settings-container">
<div class="personal-settings-setting-box personal-settings-language-box">
- <?php if (isset($_['activelanguage'])) { ?>
- <form id="language" class="section">
- <h3>
- <label for="languageinput"><?php p($l->t('Language'));?></label>
- </h3>
- <select id="languageinput" name="lang" data-placeholder="<?php p($l->t('Language'));?>">
- <option value="<?php p($_['activelanguage']['code']);?>">
- <?php p($_['activelanguage']['name']);?>
- </option>
- <?php foreach ($_['commonlanguages'] as $language):?>
- <option value="<?php p($language['code']);?>">
- <?php p($language['name']);?>
- </option>
- <?php endforeach;?>
- <optgroup label="––––––––––"></optgroup>
- <?php foreach ($_['languages'] as $language):?>
- <option value="<?php p($language['code']);?>">
- <?php p($language['name']);?>
- </option>
- <?php endforeach;?>
- </select>
- <a href="https://www.transifex.com/nextcloud/nextcloud/"
- target="_blank" rel="noreferrer noopener">
- <em><?php p($l->t('Help translate'));?></em>
- </a>
- </form>
- <?php } ?>
+ <div id="vue-languagesection" class="section"></div>
</div>
<div class="personal-settings-setting-box personal-settings-locale-box">
<?php if (isset($_['activelocale'])) { ?>