forked from AkkomaGang/akkoma-fe
Merge branch 'from/develop/tusooa/lang-opts' into 'develop'
Add language options See merge request pleroma/pleroma-fe!1494
This commit is contained in:
commit
a88abc7ee3
13 changed files with 127 additions and 37 deletions
|
@ -31,6 +31,7 @@
|
||||||
"cropperjs": "1.5.12",
|
"cropperjs": "1.5.12",
|
||||||
"diff": "3.5.0",
|
"diff": "3.5.0",
|
||||||
"escape-html": "1.0.3",
|
"escape-html": "1.0.3",
|
||||||
|
"js-cookie": "^3.0.1",
|
||||||
"localforage": "1.10.0",
|
"localforage": "1.10.0",
|
||||||
"parse-link-header": "1.0.1",
|
"parse-link-header": "1.0.1",
|
||||||
"phoenix": "1.6.2",
|
"phoenix": "1.6.2",
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<label for="interface-language-switcher">
|
<label for="interface-language-switcher">
|
||||||
{{ $t('settings.interfaceLanguage') }}
|
{{ promptText }}
|
||||||
</label>
|
</label>
|
||||||
{{ ' ' }}
|
{{ ' ' }}
|
||||||
<Select
|
<Select
|
||||||
id="interface-language-switcher"
|
id="interface-language-switcher"
|
||||||
v-model="language"
|
v-model="controlledLanguage"
|
||||||
>
|
>
|
||||||
<option
|
<option
|
||||||
v-for="lang in languages"
|
v-for="lang in languages"
|
||||||
|
@ -20,39 +20,43 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import languagesObject from '../../i18n/messages'
|
|
||||||
import localeService from '../../services/locale/locale.service.js'
|
import localeService from '../../services/locale/locale.service.js'
|
||||||
import ISO6391 from 'iso-639-1'
|
|
||||||
import _ from 'lodash'
|
|
||||||
import Select from '../select/select.vue'
|
import Select from '../select/select.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Select
|
Select
|
||||||
},
|
},
|
||||||
|
props: {
|
||||||
|
promptText: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
language: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
setLanguage: {
|
||||||
|
type: Function,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
languages () {
|
languages () {
|
||||||
return _.map(languagesObject.languages, (code) => ({ code: code, name: this.getLanguageName(code) })).sort((a, b) => a.name.localeCompare(b.name))
|
return localeService.languages
|
||||||
},
|
},
|
||||||
|
|
||||||
language: {
|
controlledLanguage: {
|
||||||
get: function () { return this.$store.getters.mergedConfig.interfaceLanguage },
|
get: function () { return this.language },
|
||||||
set: function (val) {
|
set: function (val) {
|
||||||
this.$store.dispatch('setOption', { name: 'interfaceLanguage', value: val })
|
this.setLanguage(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
getLanguageName (code) {
|
getLanguageName (code) {
|
||||||
const specialLanguageNames = {
|
return localeService.getLanguageName(code)
|
||||||
'ja_easy': 'やさしいにほんご',
|
|
||||||
'zh': '简体中文',
|
|
||||||
'zh_Hant': '繁體中文'
|
|
||||||
}
|
|
||||||
const languageName = specialLanguageNames[code] || ISO6391.getNativeName(code)
|
|
||||||
const browserLocale = localeService.internalToBrowserLocale(code)
|
|
||||||
return languageName.charAt(0).toLocaleUpperCase(browserLocale) + languageName.slice(1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import useVuelidate from '@vuelidate/core'
|
import useVuelidate from '@vuelidate/core'
|
||||||
import { required, requiredIf, sameAs } from '@vuelidate/validators'
|
import { required, requiredIf, sameAs } from '@vuelidate/validators'
|
||||||
import { mapActions, mapState } from 'vuex'
|
import { mapActions, mapState } from 'vuex'
|
||||||
|
import InterfaceLanguageSwitcher from '../interface_language_switcher/interface_language_switcher.vue'
|
||||||
|
import localeService from '../../services/locale/locale.service.js'
|
||||||
|
|
||||||
const registration = {
|
const registration = {
|
||||||
setup () { return { v$: useVuelidate() } },
|
setup () { return { v$: useVuelidate() } },
|
||||||
|
@ -11,10 +13,14 @@ const registration = {
|
||||||
username: '',
|
username: '',
|
||||||
password: '',
|
password: '',
|
||||||
confirm: '',
|
confirm: '',
|
||||||
reason: ''
|
reason: '',
|
||||||
|
language: ''
|
||||||
},
|
},
|
||||||
captcha: {}
|
captcha: {}
|
||||||
}),
|
}),
|
||||||
|
components: {
|
||||||
|
InterfaceLanguageSwitcher
|
||||||
|
},
|
||||||
validations () {
|
validations () {
|
||||||
return {
|
return {
|
||||||
user: {
|
user: {
|
||||||
|
@ -26,7 +32,8 @@ const registration = {
|
||||||
required,
|
required,
|
||||||
sameAs: sameAs(this.user.password)
|
sameAs: sameAs(this.user.password)
|
||||||
},
|
},
|
||||||
reason: { required: requiredIf(() => this.accountApprovalRequired) }
|
reason: { required: requiredIf(() => this.accountApprovalRequired) },
|
||||||
|
language: {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -64,6 +71,9 @@ const registration = {
|
||||||
this.user.captcha_solution = this.captcha.solution
|
this.user.captcha_solution = this.captcha.solution
|
||||||
this.user.captcha_token = this.captcha.token
|
this.user.captcha_token = this.captcha.token
|
||||||
this.user.captcha_answer_data = this.captcha.answer_data
|
this.user.captcha_answer_data = this.captcha.answer_data
|
||||||
|
if (this.user.language) {
|
||||||
|
this.user.language = localeService.internalToBackendLocale(this.user.language)
|
||||||
|
}
|
||||||
|
|
||||||
this.v$.$touch()
|
this.v$.$touch()
|
||||||
|
|
||||||
|
|
|
@ -162,6 +162,18 @@
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="form-group"
|
||||||
|
:class="{ 'form-group--error': $v.user.language.$error }"
|
||||||
|
>
|
||||||
|
<interface-language-switcher
|
||||||
|
for="email-language"
|
||||||
|
:prompt-text="$t('registration.email_language')"
|
||||||
|
:language="$v.user.language.$model"
|
||||||
|
:set-language="val => $v.user.language.$model = val"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-if="accountApprovalRequired"
|
v-if="accountApprovalRequired"
|
||||||
class="form-group"
|
class="form-group"
|
||||||
|
|
|
@ -72,6 +72,12 @@ const GeneralTab = {
|
||||||
!this.$store.state.users.currentUser.background_image
|
!this.$store.state.users.currentUser.background_image
|
||||||
},
|
},
|
||||||
instanceShoutboxPresent () { return this.$store.state.instance.shoutAvailable },
|
instanceShoutboxPresent () { return this.$store.state.instance.shoutAvailable },
|
||||||
|
language: {
|
||||||
|
get: function () { return this.$store.getters.mergedConfig.interfaceLanguage },
|
||||||
|
set: function (val) {
|
||||||
|
this.$store.dispatch('setOption', { name: 'interfaceLanguage', value: val })
|
||||||
|
}
|
||||||
|
},
|
||||||
...SharedComputedObject()
|
...SharedComputedObject()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
@ -4,7 +4,11 @@
|
||||||
<h2>{{ $t('settings.interface') }}</h2>
|
<h2>{{ $t('settings.interface') }}</h2>
|
||||||
<ul class="setting-list">
|
<ul class="setting-list">
|
||||||
<li>
|
<li>
|
||||||
<interface-language-switcher />
|
<interface-language-switcher
|
||||||
|
:prompt-text="$t('settings.interfaceLanguage')"
|
||||||
|
:language="language"
|
||||||
|
:set-language="val => language = val"
|
||||||
|
/>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="instanceSpecificPanelPresent">
|
<li v-if="instanceSpecificPanelPresent">
|
||||||
<BooleanSetting path="hideISP">
|
<BooleanSetting path="hideISP">
|
||||||
|
|
|
@ -8,8 +8,10 @@ import EmojiInput from 'src/components/emoji_input/emoji_input.vue'
|
||||||
import suggestor from 'src/components/emoji_input/suggestor.js'
|
import suggestor from 'src/components/emoji_input/suggestor.js'
|
||||||
import Autosuggest from 'src/components/autosuggest/autosuggest.vue'
|
import Autosuggest from 'src/components/autosuggest/autosuggest.vue'
|
||||||
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
||||||
|
import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue'
|
||||||
import BooleanSetting from '../helpers/boolean_setting.vue'
|
import BooleanSetting from '../helpers/boolean_setting.vue'
|
||||||
import SharedComputedObject from '../helpers/shared_computed_object.js'
|
import SharedComputedObject from '../helpers/shared_computed_object.js'
|
||||||
|
import localeService from 'src/services/locale/locale.service.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import {
|
import {
|
||||||
|
@ -40,7 +42,8 @@ const ProfileTab = {
|
||||||
banner: null,
|
banner: null,
|
||||||
bannerPreview: null,
|
bannerPreview: null,
|
||||||
background: null,
|
background: null,
|
||||||
backgroundPreview: null
|
backgroundPreview: null,
|
||||||
|
emailLanguage: this.$store.state.users.currentUser.language || ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
@ -50,7 +53,8 @@ const ProfileTab = {
|
||||||
Autosuggest,
|
Autosuggest,
|
||||||
ProgressButton,
|
ProgressButton,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
BooleanSetting
|
BooleanSetting,
|
||||||
|
InterfaceLanguageSwitcher
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
user () {
|
user () {
|
||||||
|
@ -111,19 +115,25 @@ const ProfileTab = {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateProfile () {
|
updateProfile () {
|
||||||
|
const params = {
|
||||||
|
note: this.newBio,
|
||||||
|
locked: this.newLocked,
|
||||||
|
// Backend notation.
|
||||||
|
/* eslint-disable camelcase */
|
||||||
|
display_name: this.newName,
|
||||||
|
fields_attributes: this.newFields.filter(el => el != null),
|
||||||
|
bot: this.bot,
|
||||||
|
show_role: this.showRole
|
||||||
|
/* eslint-enable camelcase */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.emailLanguage) {
|
||||||
|
params.language = localeService.internalToBackendLocale(this.emailLanguage)
|
||||||
|
}
|
||||||
|
|
||||||
this.$store.state.api.backendInteractor
|
this.$store.state.api.backendInteractor
|
||||||
.updateProfile({
|
.updateProfile({ params })
|
||||||
params: {
|
.then((user) => {
|
||||||
note: this.newBio,
|
|
||||||
locked: this.newLocked,
|
|
||||||
// Backend notation.
|
|
||||||
/* eslint-disable camelcase */
|
|
||||||
display_name: this.newName,
|
|
||||||
fields_attributes: this.newFields.filter(el => el != null),
|
|
||||||
bot: this.bot,
|
|
||||||
show_role: this.showRole
|
|
||||||
/* eslint-enable camelcase */
|
|
||||||
} }).then((user) => {
|
|
||||||
this.newFields.splice(user.fields.length)
|
this.newFields.splice(user.fields.length)
|
||||||
merge(this.newFields, user.fields)
|
merge(this.newFields, user.fields)
|
||||||
this.$store.commit('addNewUsers', [user])
|
this.$store.commit('addNewUsers', [user])
|
||||||
|
|
|
@ -89,6 +89,13 @@
|
||||||
{{ $t('settings.bot') }}
|
{{ $t('settings.bot') }}
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
<interface-language-switcher
|
||||||
|
:prompt-text="$t('settings.email_language')"
|
||||||
|
:language="emailLanguage"
|
||||||
|
:set-language="val => emailLanguage = val"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
<button
|
<button
|
||||||
:disabled="newName && newName.length === 0"
|
:disabled="newName && newName.length === 0"
|
||||||
class="btn button-default"
|
class="btn button-default"
|
||||||
|
|
|
@ -255,7 +255,8 @@
|
||||||
"password_required": "cannot be left blank",
|
"password_required": "cannot be left blank",
|
||||||
"password_confirmation_required": "cannot be left blank",
|
"password_confirmation_required": "cannot be left blank",
|
||||||
"password_confirmation_match": "should be the same as password"
|
"password_confirmation_match": "should be the same as password"
|
||||||
}
|
},
|
||||||
|
"email_language": "In which language do you want to receive emails from the server?"
|
||||||
},
|
},
|
||||||
"remote_user_resolver": {
|
"remote_user_resolver": {
|
||||||
"remote_user_resolver": "Remote user resolver",
|
"remote_user_resolver": "Remote user resolver",
|
||||||
|
@ -304,6 +305,7 @@
|
||||||
"avatarRadius": "Avatars",
|
"avatarRadius": "Avatars",
|
||||||
"background": "Background",
|
"background": "Background",
|
||||||
"bio": "Bio",
|
"bio": "Bio",
|
||||||
|
"email_language": "Language for receiving emails from the server",
|
||||||
"block_export": "Block export",
|
"block_export": "Block export",
|
||||||
"block_export_button": "Export your blocks to a csv file",
|
"block_export_button": "Export your blocks to a csv file",
|
||||||
"block_import": "Block import",
|
"block_import": "Block import",
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
|
import Cookies from 'js-cookie'
|
||||||
import { setPreset, applyTheme } from '../services/style_setter/style_setter.js'
|
import { setPreset, applyTheme } from '../services/style_setter/style_setter.js'
|
||||||
import messages from '../i18n/messages'
|
import messages from '../i18n/messages'
|
||||||
|
import localeService from '../services/locale/locale.service.js'
|
||||||
|
|
||||||
|
const BACKEND_LANGUAGE_COOKIE_NAME = 'userLanguage'
|
||||||
|
|
||||||
const browserLocale = (window.navigator.language || 'en').split('-')[0]
|
const browserLocale = (window.navigator.language || 'en').split('-')[0]
|
||||||
|
|
||||||
|
@ -163,6 +167,7 @@ const config = {
|
||||||
break
|
break
|
||||||
case 'interfaceLanguage':
|
case 'interfaceLanguage':
|
||||||
messages.setLanguage(this.getters.i18n, value)
|
messages.setLanguage(this.getters.i18n, value)
|
||||||
|
Cookies.set(BACKEND_LANGUAGE_COOKIE_NAME, localeService.internalToBackendLocale(value))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -197,6 +197,7 @@ const updateProfile = ({ credentials, params }) => {
|
||||||
// homepage
|
// homepage
|
||||||
// location
|
// location
|
||||||
// token
|
// token
|
||||||
|
// language
|
||||||
const register = ({ params, credentials }) => {
|
const register = ({ params, credentials }) => {
|
||||||
const { nickname, ...rest } = params
|
const { nickname, ...rest } = params
|
||||||
return fetch(MASTODON_REGISTRATION_URL, {
|
return fetch(MASTODON_REGISTRATION_URL, {
|
||||||
|
|
|
@ -1,12 +1,35 @@
|
||||||
|
import languagesObject from '../../i18n/messages'
|
||||||
|
import ISO6391 from 'iso-639-1'
|
||||||
|
import _ from 'lodash'
|
||||||
|
|
||||||
const specialLanguageCodes = {
|
const specialLanguageCodes = {
|
||||||
'ja_easy': 'ja',
|
'ja_easy': 'ja',
|
||||||
'zh_Hant': 'zh-HANT'
|
'zh_Hant': 'zh-HANT',
|
||||||
|
'zh': 'zh-Hans'
|
||||||
}
|
}
|
||||||
|
|
||||||
const internalToBrowserLocale = code => specialLanguageCodes[code] || code
|
const internalToBrowserLocale = code => specialLanguageCodes[code] || code
|
||||||
|
|
||||||
|
const internalToBackendLocale = code => internalToBrowserLocale(code).replace('_', '-')
|
||||||
|
|
||||||
|
const getLanguageName = (code) => {
|
||||||
|
const specialLanguageNames = {
|
||||||
|
'ja_easy': 'やさしいにほんご',
|
||||||
|
'zh': '简体中文',
|
||||||
|
'zh_Hant': '繁體中文'
|
||||||
|
}
|
||||||
|
const languageName = specialLanguageNames[code] || ISO6391.getNativeName(code)
|
||||||
|
const browserLocale = internalToBrowserLocale(code)
|
||||||
|
return languageName.charAt(0).toLocaleUpperCase(browserLocale) + languageName.slice(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const languages = _.map(languagesObject.languages, (code) => ({ code: code, name: getLanguageName(code) })).sort((a, b) => a.name.localeCompare(b.name))
|
||||||
|
|
||||||
const localeService = {
|
const localeService = {
|
||||||
internalToBrowserLocale
|
internalToBrowserLocale,
|
||||||
|
internalToBackendLocale,
|
||||||
|
languages,
|
||||||
|
getLanguageName
|
||||||
}
|
}
|
||||||
|
|
||||||
export default localeService
|
export default localeService
|
||||||
|
|
|
@ -5722,6 +5722,11 @@ js-base64@^2.1.9:
|
||||||
version "2.5.0"
|
version "2.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.0.tgz#42255ba183ab67ce59a0dee640afdc00ab5ae93e"
|
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.0.tgz#42255ba183ab67ce59a0dee640afdc00ab5ae93e"
|
||||||
|
|
||||||
|
js-cookie@^3.0.1:
|
||||||
|
version "3.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-3.0.1.tgz#9e39b4c6c2f56563708d7d31f6f5f21873a92414"
|
||||||
|
integrity sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw==
|
||||||
|
|
||||||
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^3.0.2:
|
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^3.0.2:
|
||||||
version "3.0.2"
|
version "3.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
|
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
|
||||||
|
|
Loading…
Reference in a new issue