commit: a9716701be26c696ee1b908a1787b34880175ffa
parent a3c971526a04aee8a8f42ce3e39d0195a442335d
Author: HJ <30-hj@users.noreply.git.pleroma.social>
Date: Wed, 25 Jan 2023 23:47:29 +0000
Merge branch 'from/develop/tusooa/multi-iface-lang' into 'develop'
Multiple interface languages support
See merge request pleroma/pleroma-fe!1568
Diffstat:
7 files changed, 108 insertions(+), 25 deletions(-)
diff --git a/src/components/interface_language_switcher/interface_language_switcher.vue b/src/components/interface_language_switcher/interface_language_switcher.vue
@@ -1,21 +1,44 @@
<template>
- <div>
- <label for="interface-language-switcher">
+ <div class="interface-language-switcher">
+ <label>
{{ promptText }}
</label>
- {{ ' ' }}
- <Select
- id="interface-language-switcher"
- v-model="controlledLanguage"
- >
- <option
- v-for="lang in languages"
- :key="lang.code"
- :value="lang.code"
+ <ul class="setting-list">
+ <li
+ v-for="index of controlledLanguage.keys()"
+ :key="index"
>
- {{ lang.name }}
- </option>
- </Select>
+ <label>
+ {{ index === 0 ? $t('settings.primary_language') : $tc('settings.fallback_language', index, { index }) }}
+ <Select
+ class="language-select"
+ :model-value="controlledLanguage[index]"
+ @update:modelValue="val => setLanguageAt(index, val)"
+ >
+ <option
+ v-for="lang in languages"
+ :key="lang.code"
+ :value="lang.code"
+ >
+ {{ lang.name }}
+ </option>
+ </Select>
+ </label>
+ <button
+ v-if="controlledLanguage.length > 1 && index !== 0"
+ 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>
+ </ul>
</div>
</template>
@@ -34,7 +57,7 @@ export default {
required: true
},
language: {
- type: String,
+ type: [Array, String],
required: true
},
setLanguage: {
@@ -48,7 +71,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 +83,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>
diff --git a/src/components/settings_modal/tabs/profile_tab.js b/src/components/settings_modal/tabs/profile_tab.js
@@ -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
diff --git a/src/i18n/en.json b/src/i18n/en.json
@@ -335,6 +335,10 @@
"select_all": "Select all"
},
"settings": {
+ "add_language": "Add fallback language",
+ "remove_language": "Remove",
+ "primary_language": "Primary language:",
+ "fallback_language": "Fallback language {index}:",
"app_name": "App name",
"expert_mode": "Show advanced",
"save": "Save changes",
diff --git a/src/i18n/messages.js b/src/i18n/messages.js
@@ -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)
+ }
+ const [first, ...rest] = languages
+
+ if (first === i18n.locale && isEqual(rest, i18n.fallbackLocale)) {
+ return
}
- i18n.locale = language
+
+ for (const lang of languages) {
+ if (hasLanguageFile(lang)) {
+ const messages = await loadLanguageFile(lang)
+ i18n.setLocaleMessage(lang, messages.default)
+ }
+ }
+
+ i18n.fallbackLocale = rest
+ i18n.locale = first
}
}
diff --git a/src/modules/config.js b/src/modules/config.js
@@ -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)
diff --git a/src/modules/instance.js b/src/modules/instance.js
@@ -286,8 +286,13 @@ const instance = {
langList
.map(async lang => {
if (!state.unicodeEmojiAnnotations[lang]) {
- const annotations = await loadAnnotations(lang)
- commit('setUnicodeEmojiAnnotations', { lang, annotations })
+ try {
+ const annotations = await loadAnnotations(lang)
+ commit('setUnicodeEmojiAnnotations', { lang, annotations })
+ } catch (e) {
+ console.warn(`Error loading unicode emoji annotations for ${lang}: `, e)
+ // ignore
+ }
}
}))
},
diff --git a/src/services/locale/locale.service.js b/src/services/locale/locale.service.js
@@ -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
}