Skip to content

Commit

Permalink
add language component
Browse files Browse the repository at this point in the history
  • Loading branch information
tanyaka committed Jul 18, 2024
1 parent 96e21cb commit d6199ec
Show file tree
Hide file tree
Showing 5 changed files with 340 additions and 0 deletions.
122 changes: 122 additions & 0 deletions src/components/LanguageSection/Language.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<!--
- @copyright 2021, Christopher Ng <chrng8@gmail.com>
-
- @author Christopher Ng <[email protected]>
-
- @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">
<NcSelect :aria-label-listbox="t('simplesettings', 'Languages')"
class="language__select"
:clearable="false"
:input-id="inputId"
label="name"
label-outside
:options="allLanguages"
:value="language"
@option:selected="onLanguageChange" />
</div>
</template>

<script>
import { ACCOUNT_SETTING_PROPERTY_ENUM } from '../../constants/AccountPropertyConstants.js'
import { savePrimaryAccountProperty } from '../../service/PersonalInfo/PersonalInfoService.js'
import { handleError } from '../../utils/handlers.js'

import NcSelect from '@nextcloud/vue/dist/Components/NcSelect.js'

export default {
name: 'Language',

components: {
NcSelect,
},

props: {
inputId: {
type: String,
default: null,
},
availableLanguages: {
type: Array,
required: true,
},
language: {
type: Object,
required: true,
},
},

data() {
return {
initialLanguage: this.language,
}
},

computed: {
/**
* All available languages, sorted like: current, common, other
*/
allLanguages() {
return [this.language, ...this.availableLanguages.filter(l => l.code !== this.language.code)]
},
},

methods: {
async onLanguageChange(language) {
this.$emit('update:language', language)

await this.updateLanguage(language)
},

async updateLanguage(language) {
try {
const responseData = await savePrimaryAccountProperty(ACCOUNT_SETTING_PROPERTY_ENUM.LANGUAGE, language.code)
this.handleResponse({
language,
status: responseData.ocs?.meta?.status,
})
window.location.reload()
} catch (e) {
this.handleResponse({
errorMessage: t('settings', 'Unable to update language'),
error: e,
})

}
},

handleResponse({ language, status, errorMessage, error }) {
if (status === 'ok') {
// Ensure that local state reflects server state
this.initialLanguage = language
} else {
handleError(error, errorMessage)
}
},
},
}
</script>

<style lang="scss" scoped>
.language {
display: grid;
max-width: 500px;
}
</style>
75 changes: 75 additions & 0 deletions src/components/LanguageSection/LanguageSection.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<!--
- @copyright 2021, Christopher Ng <chrng8@gmail.com>
-
- @author Christopher Ng <[email protected]>
-
- @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>
<section class="section">
<h2>{{ t('simplesettings', 'Language') }}</h2>
<Language v-if="isEditable"
:input-id="inputId"
:available-languages="availableLanguages"
:language.sync="language" />

<span v-else>
{{ t('simplesettings', 'No language set') }}
</span>
</section>
</template>

<script>
import { loadState } from '@nextcloud/initial-state'
import Language from './Language.vue'
import { ACCOUNT_SETTING_PROPERTY_ENUM, ACCOUNT_SETTING_PROPERTY_READABLE_ENUM } from '../../constants/AccountPropertyConstants.js'

const { languageMap: { activeLanguage, allLanguages } } = loadState('simplesettings', 'personalInfoParameters', {})

export default {
name: 'LanguageSection',

components: {
Language,
},

setup() {
// Non reactive instance properties
return {
availableLanguages: allLanguages,
propertyReadable: ACCOUNT_SETTING_PROPERTY_READABLE_ENUM.LANGUAGE,
}
},

data() {
return {
language: activeLanguage,
}
},

computed: {
inputId() {
return `account-setting-${ACCOUNT_SETTING_PROPERTY_ENUM.LANGUAGE}`
},

isEditable() {
return Boolean(this.language)
},
},
}
</script>
41 changes: 41 additions & 0 deletions src/constants/AccountPropertyConstants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* @copyright 2021, Christopher Ng <[email protected]>
*
* @author Christopher Ng <[email protected]>
*
* @license AGPL-3.0-or-later
*
* 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/>.
*
*/

/*
* SYNC to be kept in sync with `lib/public/Accounts/IAccountManager.php`
*/

import { translate as t } from '@nextcloud/l10n'

/**
* Enum of account setting properties
*
* Account setting properties unlike account properties do not support scopes*
*/
export const ACCOUNT_SETTING_PROPERTY_ENUM = Object.freeze({
LANGUAGE: 'language',
})

/** Enum of account setting properties to human readable setting properties */
export const ACCOUNT_SETTING_PROPERTY_READABLE_ENUM = Object.freeze({
LANGUAGE: t('simplesettings', 'Language'),
})
54 changes: 54 additions & 0 deletions src/service/PersonalInfo/PersonalInfoService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* @copyright 2021, Christopher Ng <[email protected]>
*
* @author Christopher Ng <[email protected]>
*
* @license AGPL-3.0-or-later
*
* 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/>.
*
*/

import axios from '@nextcloud/axios'
import { getCurrentUser } from '@nextcloud/auth'
import { generateOcsUrl } from '@nextcloud/router'
import { confirmPassword } from '@nextcloud/password-confirmation'
import '@nextcloud/password-confirmation/dist/style.css'

/**
* Save the primary account property value for the user
*
* @param {string} accountProperty the account property
* @param {string|boolean} value the primary value
* @return {object}
*/
export const savePrimaryAccountProperty = async (accountProperty, value) => {
// TODO allow boolean values on backend route handler
// Convert boolean to string for compatibility
if (typeof value === 'boolean') {
value = value ? '1' : '0'
}

const userId = getCurrentUser().uid
const url = generateOcsUrl('cloud/users/{userId}', { userId })

await confirmPassword()

const res = await axios.put(url, {
key: accountProperty,
value,
})

return res.data
}
48 changes: 48 additions & 0 deletions src/utils/handlers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* @copyright 2023 Christopher Ng <[email protected]>
*
* @author Christopher Ng <[email protected]>
*
* @license AGPL-3.0-or-later
*
* 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/>.
*
*/

import { showError } from '@nextcloud/dialogs'
import { translate as t } from '@nextcloud/l10n'

import logger from '../logger.ts'

/**
* @param {import('axios').AxiosError} error the error
* @param {string?} message the message to display
*/
export const handleError = (error, message) => {
let fullMessage = ''

if (message) {
fullMessage += message
}

if (error.response?.status === 429) {
if (fullMessage) {
fullMessage += '\n'
}
fullMessage += t('settings', 'There were too many requests from your network. Retry later or contact your administrator if this is an error.')
}

showError(fullMessage)
logger.error(fullMessage || t('Error'), error)
}

0 comments on commit d6199ec

Please sign in to comment.