mirror of
https://github.com/gotson/komga.git
synced 2025-01-07 03:07:16 +08:00
parent
75019c9a1e
commit
efe6476a90
2
komga-webui/.env
Normal file
2
komga-webui/.env
Normal file
@ -0,0 +1,2 @@
|
||||
VUE_APP_I18N_LOCALE=en
|
||||
VUE_APP_I18N_FALLBACK_LOCALE=en
|
20936
komga-webui/package-lock.json
generated
20936
komga-webui/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -6,7 +6,8 @@
|
||||
"serve": "vue-cli-service serve --port 8081",
|
||||
"build": "vue-cli-service build",
|
||||
"test:unit": "vue-cli-service test:unit",
|
||||
"lint": "vue-cli-service lint --mode production"
|
||||
"lint": "vue-cli-service lint --mode production",
|
||||
"i18n:report": "vue-cli-service i18n:report --src './src/**/*.?(js|vue)' --locales './src/locales/**/*.json'"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.21.1",
|
||||
@ -18,6 +19,7 @@
|
||||
"qs": "^6.9.4",
|
||||
"vue": "^2.6.11",
|
||||
"vue-cookies": "^1.7.3",
|
||||
"vue-i18n": "^8.22.4",
|
||||
"vue-line-clamp": "^1.3.2",
|
||||
"vue-moment": "^4.1.0",
|
||||
"vue-read-more-smooth": "^0.1.8",
|
||||
@ -36,6 +38,7 @@
|
||||
"@types/lodash": "^4.14.158",
|
||||
"@types/vuedraggable": "^2.23.1",
|
||||
"@types/vuelidate": "^0.7.13",
|
||||
"@types/webpack": "^4.4.0",
|
||||
"@typescript-eslint/eslint-plugin": "^3.7.1",
|
||||
"@typescript-eslint/parser": "^3.7.1",
|
||||
"@vue/cli-plugin-babel": "^4.4.6",
|
||||
@ -61,7 +64,9 @@
|
||||
"ts-jest": "^26.1.4",
|
||||
"typeface-roboto": "0.0.75",
|
||||
"typescript": "^3.9.7",
|
||||
"vue-cli-plugin-i18n": "~1.0.1",
|
||||
"vue-cli-plugin-vuetify": "^2.0.7",
|
||||
"vue-i18n-extract": "^1.1.11",
|
||||
"vue-template-compiler": "^2.6.11",
|
||||
"vuetify-loader": "^1.6.0"
|
||||
}
|
||||
|
23
komga-webui/src/i18n.ts
Normal file
23
komga-webui/src/i18n.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import Vue from 'vue'
|
||||
import VueI18n, {LocaleMessages} from 'vue-i18n'
|
||||
|
||||
Vue.use(VueI18n)
|
||||
|
||||
function loadLocaleMessages (): LocaleMessages {
|
||||
const locales = require.context('./locales', true, /[A-Za-z0-9-_,\s]+\.json$/i)
|
||||
const messages: LocaleMessages = {}
|
||||
locales.keys().forEach(key => {
|
||||
const matched = key.match(/([A-Za-z0-9-_]+)\./i)
|
||||
if (matched && matched.length > 1) {
|
||||
const locale = matched[1]
|
||||
messages[locale] = locales(key)
|
||||
}
|
||||
})
|
||||
return messages
|
||||
}
|
||||
|
||||
export default new VueI18n({
|
||||
locale: process.env.VUE_APP_I18N_LOCALE || 'en',
|
||||
fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || 'en',
|
||||
messages: loadLocaleMessages(),
|
||||
})
|
12
komga-webui/src/locales/en.json
Normal file
12
komga-webui/src/locales/en.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"dashboard": {
|
||||
"recently_added_series": "Recently Added Series",
|
||||
"on_deck": "On Deck",
|
||||
"keep_reading": "Keep Reading",
|
||||
"recently_updated_series": "Recently Updated Series",
|
||||
"recently_added_books": "Recently Added Books"
|
||||
},
|
||||
"common": {
|
||||
"nothing_to_show": "Nothing to show"
|
||||
}
|
||||
}
|
5
komga-webui/src/locales/fr.json
Normal file
5
komga-webui/src/locales/fr.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"dashboard": {
|
||||
"recently_added_series": "Séries ajoutées récemment"
|
||||
}
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
import _, { LoDashStatic } from 'lodash'
|
||||
import _, {LoDashStatic} from 'lodash'
|
||||
import Vue from 'vue'
|
||||
import VueCookies from 'vue-cookies'
|
||||
// @ts-ignore
|
||||
import * as lineClamp from 'vue-line-clamp'
|
||||
import Vuelidate from 'vuelidate'
|
||||
import { sync } from 'vuex-router-sync'
|
||||
import {sync} from 'vuex-router-sync'
|
||||
import App from './App.vue'
|
||||
import actuator from './plugins/actuator.plugin'
|
||||
import httpPlugin from './plugins/http.plugin'
|
||||
@ -21,6 +21,7 @@ import vuetify from './plugins/vuetify'
|
||||
import './public-path'
|
||||
import router from './router'
|
||||
import store from './store'
|
||||
import i18n from './i18n'
|
||||
|
||||
Vue.use(Vuelidate)
|
||||
Vue.use(lineClamp)
|
||||
@ -50,6 +51,7 @@ new Vue({
|
||||
router,
|
||||
store,
|
||||
vuetify,
|
||||
i18n,
|
||||
render: h => h(App),
|
||||
}).$mount('#app')
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
<v-container fluid>
|
||||
<empty-state v-if="allEmpty"
|
||||
title="Nothing to show"
|
||||
:title="$t('common.nothing_to_show')"
|
||||
icon="mdi-help-circle"
|
||||
icon-color="secondary"
|
||||
>
|
||||
@ -28,7 +28,7 @@
|
||||
|
||||
<horizontal-scroller v-if="inProgressBooks.length !== 0" class="mb-4">
|
||||
<template v-slot:prepend>
|
||||
<div class="title">Keep Reading</div>
|
||||
<div class="title">{{ $t('dashboard.keep_reading') }}</div>
|
||||
</template>
|
||||
<template v-slot:content>
|
||||
<item-browser :items="inProgressBooks"
|
||||
@ -43,7 +43,7 @@
|
||||
|
||||
<horizontal-scroller v-if="onDeckBooks.length !== 0" class="mb-4">
|
||||
<template v-slot:prepend>
|
||||
<div class="title">On Deck</div>
|
||||
<div class="title">{{ $t('dashboard.on_deck') }}</div>
|
||||
</template>
|
||||
<template v-slot:content>
|
||||
<item-browser :items="onDeckBooks"
|
||||
@ -58,7 +58,7 @@
|
||||
|
||||
<horizontal-scroller v-if="newSeries.length !== 0" class="mb-4">
|
||||
<template v-slot:prepend>
|
||||
<div class="title">Recently Added Series</div>
|
||||
<div class="title">{{ $t('dashboard.recently_added_series') }}</div>
|
||||
</template>
|
||||
<template v-slot:content>
|
||||
<item-browser :items="newSeries"
|
||||
@ -73,7 +73,7 @@
|
||||
|
||||
<horizontal-scroller v-if="updatedSeries.length !== 0" class="mb-4">
|
||||
<template v-slot:prepend>
|
||||
<div class="title">Recently Updated Series</div>
|
||||
<div class="title">{{ $t('dashboard.recently_updated_series') }}</div>
|
||||
</template>
|
||||
<template v-slot:content>
|
||||
<item-browser :items="updatedSeries"
|
||||
@ -88,7 +88,7 @@
|
||||
|
||||
<horizontal-scroller v-if="latestBooks.length !== 0" class="mb-4">
|
||||
<template v-slot:prepend>
|
||||
<div class="title">Recently Added Books</div>
|
||||
<div class="title">{{ $t('dashboard.recently_added_books') }}</div>
|
||||
</template>
|
||||
<template v-slot:content>
|
||||
<item-browser :items="latestBooks"
|
||||
@ -110,9 +110,9 @@ import SeriesMultiSelectBar from '@/components/bars/SeriesMultiSelectBar.vue'
|
||||
import EmptyState from '@/components/EmptyState.vue'
|
||||
import HorizontalScroller from '@/components/HorizontalScroller.vue'
|
||||
import ItemBrowser from '@/components/ItemBrowser.vue'
|
||||
import { ReadStatus } from '@/types/enum-books'
|
||||
import { BookDto } from '@/types/komga-books'
|
||||
import { BOOK_CHANGED, LIBRARY_DELETED, SERIES_CHANGED } from '@/types/events'
|
||||
import {ReadStatus} from '@/types/enum-books'
|
||||
import {BookDto} from '@/types/komga-books'
|
||||
import {BOOK_CHANGED, LIBRARY_DELETED, SERIES_CHANGED} from '@/types/events'
|
||||
import Vue from 'vue'
|
||||
import {SeriesDto} from "@/types/komga-series";
|
||||
|
||||
|
@ -114,6 +114,18 @@
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
|
||||
<v-list>
|
||||
<v-list-item>
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-translate</v-icon>
|
||||
</v-list-item-icon>
|
||||
<v-select v-model="locale"
|
||||
:items="$i18n.availableLocales"
|
||||
>
|
||||
</v-select>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
|
||||
<v-spacer/>
|
||||
|
||||
<template v-slot:append>
|
||||
@ -136,10 +148,11 @@
|
||||
import Dialogs from '@/components/Dialogs.vue'
|
||||
import LibraryActionsMenu from '@/components/menus/LibraryActionsMenu.vue'
|
||||
import SearchBox from '@/components/SearchBox.vue'
|
||||
import { Theme } from '@/types/themes'
|
||||
import {Theme} from '@/types/themes'
|
||||
import Vue from 'vue'
|
||||
|
||||
const cookieTheme = 'theme'
|
||||
const cookieLocale = 'locale'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'home',
|
||||
@ -171,12 +184,22 @@ export default Vue.extend({
|
||||
}
|
||||
}
|
||||
|
||||
if (this.$cookies.isKey(cookieLocale)) {
|
||||
const locale = this.$cookies.get(cookieLocale)
|
||||
if (this.$i18n.availableLocales.includes(locale)) {
|
||||
this.$i18n.locale = locale
|
||||
}
|
||||
}
|
||||
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', this.systemThemeChange)
|
||||
},
|
||||
async beforeDestroy () {
|
||||
window.matchMedia('(prefers-color-scheme: dark)').removeEventListener('change', this.systemThemeChange)
|
||||
},
|
||||
computed: {
|
||||
locales (): string[] {
|
||||
return this.$i18n.availableLocales
|
||||
},
|
||||
libraries (): LibraryDto[] {
|
||||
return this.$store.state.komgaLibraries.libraries
|
||||
},
|
||||
@ -196,6 +219,17 @@ export default Vue.extend({
|
||||
}
|
||||
},
|
||||
},
|
||||
locale: {
|
||||
get: function (): string {
|
||||
return this.$i18n.locale
|
||||
},
|
||||
set: function (locale: string): void {
|
||||
if (this.$i18n.availableLocales.includes(locale)) {
|
||||
this.$i18n.locale = locale
|
||||
this.$cookies.set(cookieLocale, locale, Infinity)
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
toggleDrawer () {
|
||||
|
@ -13,7 +13,9 @@
|
||||
"types": [
|
||||
"webpack-env",
|
||||
"jest",
|
||||
"vuetify"
|
||||
"vuetify",
|
||||
"webpack",
|
||||
"webpack-env"
|
||||
],
|
||||
"paths": {
|
||||
"@/*": [
|
||||
@ -37,4 +39,4 @@
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ const _ = require('lodash')
|
||||
// vue.config.js
|
||||
module.exports = {
|
||||
publicPath: '/',
|
||||
|
||||
chainWebpack: (config) => {
|
||||
config.plugins.delete('prefetch') // conflicts with htmlInject
|
||||
config.plugins.delete('preload') // conflicts with htmlInject
|
||||
@ -34,4 +35,13 @@ module.exports = {
|
||||
config.plugin('momentLocalesPlugin')
|
||||
.use(momentLocalesPlugin)
|
||||
},
|
||||
|
||||
pluginOptions: {
|
||||
i18n: {
|
||||
locale: 'en',
|
||||
fallbackLocale: 'en',
|
||||
localeDir: 'locales',
|
||||
enableInSFC: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user