Add support for multiple interface languages

This commit is contained in:
Tusooa Zhu 2022-07-25 15:38:05 -04:00 committed by tusooa
parent 25e628efe2
commit b7e9373965
No known key found for this signature in database
GPG Key ID: 7B467EDE43A08224
5 changed files with 92 additions and 23 deletions

View File

@ -1,12 +1,17 @@
<template>
<div>
<label for="interface-language-switcher">
<div class="interface-language-switcher">
<label>
{{ promptText }}
</label>
{{ ' ' }}
<ol>
<li
v-for="index of controlledLanguage.keys()"
:key="index"
>
<Select
id="interface-language-switcher"
v-model="controlledLanguage"
class="language-select"
:model-value="controlledLanguage[index]"
@update:modelValue="val => setLanguageAt(index, val)"
>
<option
v-for="lang in languages"
@ -16,6 +21,19 @@
{{ lang.name }}
</option>
</Select>
<button
v-if="controlledLanguage.length > 1"
class="button-default btn"
@click="() => removeLanguageAt(index)"
>{{ $t('settings.remove_language') }}</button>
</li>
<li>
<button
class="button-default btn"
@click="addLanguage"
>{{ $t('settings.add_language') }}</button>
</li>
</ol>
</div>
</template>
@ -34,7 +52,7 @@ export default {
required: true
},
language: {
type: String,
type: [Array, String],
required: true
},
setLanguage: {
@ -48,7 +66,9 @@ export default {
},
controlledLanguage: {
get: function () { return this.language },
get: function () {
return Array.isArray(this.language) ? this.language : [this.language]
},
set: function (val) {
this.setLanguage(val)
}
@ -58,7 +78,30 @@ export default {
methods: {
getLanguageName (code) {
return localeService.getLanguageName(code)
},
addLanguage () {
this.controlledLanguage = [...this.controlledLanguage, '']
},
setLanguageAt (index, val) {
const lang = [...this.controlledLanguage]
lang[index] = val
this.controlledLanguage = lang
},
removeLanguageAt (index) {
const lang = [...this.controlledLanguage]
lang.splice(index, 1)
this.controlledLanguage = lang
}
}
}
</script>
<style lang="scss">
@import '../../_variables.scss';
.interface-language-switcher {
.language-select {
margin-right: 1em;
}
}
</style>

View File

@ -43,7 +43,7 @@ const ProfileTab = {
bannerPreview: null,
background: null,
backgroundPreview: null,
emailLanguage: this.$store.state.users.currentUser.language || ''
emailLanguage: this.$store.state.users.currentUser.language || ['']
}
},
components: {
@ -130,7 +130,7 @@ const ProfileTab = {
}
if (this.emailLanguage) {
params.language = localeService.internalToBackendLocale(this.emailLanguage)
params.language = localeService.internalToBackendLocaleMulti(this.emailLanguage)
}
this.$store.state.api.backendInteractor

View File

@ -7,8 +7,11 @@
// sed -i -e "s/'//gm" -e 's/"/\\"/gm' -re 's/^( +)(.+?): ((.+?))?(,?)(\{?)$/\1"\2": "\4"/gm' -e 's/\"\{\"/{/g' -e 's/,"$/",/g' file.json
// There's only problem that apostrophe character ' gets replaced by \\ so you have to fix it manually, sorry.
import { isEqual } from 'lodash'
import { languages, langCodeToJsonName } from './languages.js'
const ULTIMATE_FALLBACK_LOCALE = 'en'
const hasLanguageFile = (code) => languages.includes(code)
const loadLanguageFile = (code) => {
@ -25,11 +28,26 @@ const messages = {
en: require('./en.json').default
},
setLanguage: async (i18n, language) => {
if (hasLanguageFile(language)) {
const messages = await loadLanguageFile(language)
i18n.setLocaleMessage(language, messages.default)
const languages = (Array.isArray(language) ? language : [language]).filter(k => k)
if (!languages.includes(ULTIMATE_FALLBACK_LOCALE)) {
languages.push(ULTIMATE_FALLBACK_LOCALE)
}
i18n.locale = language
const [first, ...rest] = languages
if (first === i18n.locale && isEqual(rest, i18n.fallbackLocale)) {
return
}
for (const lang of languages) {
if (hasLanguageFile(lang)) {
const messages = await loadLanguageFile(lang)
i18n.setLocaleMessage(lang, messages.default)
}
}
i18n.fallbackLocale = rest
i18n.locale = first
}
}

View File

@ -184,7 +184,10 @@ const config = {
case 'interfaceLanguage':
messages.setLanguage(this.getters.i18n, value)
dispatch('loadUnicodeEmojiData', value)
Cookies.set(BACKEND_LANGUAGE_COOKIE_NAME, localeService.internalToBackendLocale(value))
Cookies.set(
BACKEND_LANGUAGE_COOKIE_NAME,
localeService.internalToBackendLocaleMulti(value)
)
break
case 'thirdColumnMode':
dispatch('setLayoutWidth', undefined)

View File

@ -11,6 +11,10 @@ const specialLanguageCodes = {
const internalToBrowserLocale = code => specialLanguageCodes[code] || code
const internalToBackendLocale = code => internalToBrowserLocale(code).replace('_', '-')
const internalToBackendLocaleMulti = codes => {
const langs = Array.isArray(codes) ? codes : [codes]
return langs.map(internalToBackendLocale).join(',')
}
const getLanguageName = (code) => {
const specialLanguageNames = {
@ -28,6 +32,7 @@ const languages = _.map(languagesObject.languages, (code) => ({ code, name: getL
const localeService = {
internalToBrowserLocale,
internalToBackendLocale,
internalToBackendLocaleMulti,
languages,
getLanguageName
}