211 lines
5.7 KiB
TypeScript
211 lines
5.7 KiB
TypeScript
import './scss/main.scss'
|
|
import { createApp } from 'vue'
|
|
import VueMatomo from 'vue-matomo'
|
|
import { createRouter, createWebHistory, RouterScrollBehavior } from 'vue-router'
|
|
import { createGettext } from 'vue3-gettext'
|
|
import App from './App.vue'
|
|
import Home from './views/Home.vue'
|
|
import Search from './views/Search.vue'
|
|
import CommonMixins from './mixins/CommonMixins'
|
|
import SafeHTML from './components/SafeHTML.vue'
|
|
import { loadServerConfig } from './shared/config'
|
|
|
|
const app = createApp(App)
|
|
|
|
// ############# I18N ##############
|
|
|
|
const availableLanguages = {
|
|
en_US: 'English',
|
|
fr_FR: 'Français',
|
|
cs: 'Čeština',
|
|
de: 'Deutsch',
|
|
el: 'ελληνικά',
|
|
es: 'Español',
|
|
gd: 'Gàidhlig',
|
|
gl: 'galego',
|
|
fa: 'فارسی',
|
|
hr: 'hrvatski',
|
|
ru: 'русский',
|
|
it: 'Italiano',
|
|
ja: '日本語',
|
|
sr_Cyrl: 'Српска ћирилица',
|
|
sv: 'svenska',
|
|
nl: 'Nederlands',
|
|
oc: 'Occitan',
|
|
sq: 'Shqip',
|
|
pt_BR: 'Português (Brasil)',
|
|
bn: 'বাংলা',
|
|
pl: 'Polski',
|
|
uk: 'Українська',
|
|
zh_Hant: '繁體中文(台灣)'
|
|
}
|
|
const aliasesLanguages = {
|
|
en: 'en_US',
|
|
fr: 'fr_FR',
|
|
br: 'pt_BR',
|
|
pt: 'pt_BR'
|
|
}
|
|
const allLocales = Object.keys(availableLanguages).concat(Object.keys(aliasesLanguages))
|
|
|
|
const defaultLanguage = 'en_US'
|
|
let currentLanguage = defaultLanguage
|
|
|
|
const basePath = import.meta.env.BASE_URL
|
|
const startRegexp = new RegExp('^' + basePath)
|
|
|
|
const paths = window.location.pathname
|
|
.replace(startRegexp, '')
|
|
.split('/')
|
|
|
|
const localePath = paths.length !== 0 ? paths[0] : ''
|
|
const languageFromLocalStorage = localStorage.getItem('language')
|
|
|
|
if (allLocales.includes(localePath)) {
|
|
currentLanguage = aliasesLanguages[localePath] ? aliasesLanguages[localePath] : localePath
|
|
localStorage.setItem('language', currentLanguage)
|
|
} else if (languageFromLocalStorage) {
|
|
currentLanguage = languageFromLocalStorage
|
|
} else {
|
|
const navigatorLanguage = window.navigator.language
|
|
const snakeCaseLanguage = navigatorLanguage.replace('-', '_')
|
|
currentLanguage = aliasesLanguages[snakeCaseLanguage] ? aliasesLanguages[snakeCaseLanguage] : snakeCaseLanguage
|
|
}
|
|
|
|
loadServerConfig()
|
|
.then(() => buildTranslationsPromise(defaultLanguage, currentLanguage))
|
|
.catch(err => {
|
|
console.error('Cannot load translations.', err)
|
|
|
|
return { default: {} }
|
|
})
|
|
.then(translations => {
|
|
const gettext = createGettext({
|
|
translations,
|
|
availableLanguages,
|
|
defaultLanguage: currentLanguage,
|
|
mutedLanguages: [ 'en_US' ]
|
|
})
|
|
|
|
app.use(gettext)
|
|
app.mixin(CommonMixins)
|
|
app.component('SafeHTML', SafeHTML)
|
|
|
|
// Routes
|
|
let routes = []
|
|
|
|
for (const locale of [ '' ].concat(allLocales)) {
|
|
const base = locale
|
|
? '/' + locale + '/'
|
|
: '/'
|
|
|
|
routes = routes.concat([
|
|
{
|
|
path: base,
|
|
component: Home
|
|
},
|
|
{
|
|
path: base + 'search',
|
|
component: Search
|
|
}
|
|
])
|
|
}
|
|
|
|
routes.push({
|
|
path: '/*',
|
|
// Don't want to create a 404 page
|
|
component: Search
|
|
})
|
|
|
|
const router = createRouter({
|
|
history: createWebHistory(),
|
|
scrollBehavior: buildScrollBehaviour(),
|
|
routes
|
|
})
|
|
|
|
// Stats Matomo
|
|
if (!(navigator.doNotTrack === 'yes' || navigator.doNotTrack === '1')) {
|
|
app.use(VueMatomo, {
|
|
// Configure your matomo server and site
|
|
host: 'https://stats.framasoft.org/',
|
|
siteId: 77,
|
|
|
|
// Enables automatically registering pageviews on the router
|
|
router,
|
|
|
|
// Require consent before sending tracking information to matomo
|
|
// Default: false
|
|
requireConsent: false,
|
|
|
|
// Whether to track the initial page view
|
|
// Default: true
|
|
trackInitialView: true,
|
|
|
|
// Changes the default .js and .php endpoint's filename
|
|
// Default: 'piwik'
|
|
trackerFileName: 'p',
|
|
|
|
enableLinkTracking: true
|
|
})
|
|
}
|
|
|
|
document.documentElement.lang = currentLanguage.split('_')[0]
|
|
|
|
app.use(router)
|
|
|
|
app.mount('#app')
|
|
})
|
|
.catch(err => console.error(err))
|
|
|
|
function buildTranslationsPromise (defaultLanguage, currentLanguage) {
|
|
const translations = {}
|
|
|
|
// No need to translate anything
|
|
if (currentLanguage === defaultLanguage) return Promise.resolve(translations)
|
|
|
|
// Fetch translations from server
|
|
const fromRemote = import(`./translations/${currentLanguage}.json`)
|
|
.then(module => {
|
|
const remoteTranslations = module.default
|
|
try {
|
|
localStorage.setItem('translations-v1-' + currentLanguage, JSON.stringify(remoteTranslations))
|
|
} catch (err) {
|
|
console.error('Cannot save translations in local storage.', err)
|
|
}
|
|
|
|
return Object.assign(translations, remoteTranslations)
|
|
})
|
|
|
|
// If we have a cache, try to
|
|
const fromLocalStorage = localStorage.getItem('translations-v1-' + currentLanguage)
|
|
if (fromLocalStorage) {
|
|
try {
|
|
Object.assign(translations, JSON.parse(fromLocalStorage))
|
|
|
|
return Promise.resolve(translations)
|
|
} catch (err) {
|
|
console.error('Cannot parse translations from local storage.', err)
|
|
}
|
|
}
|
|
|
|
return fromRemote
|
|
}
|
|
|
|
function buildScrollBehaviour (): RouterScrollBehavior {
|
|
const isBot = /bot|googlebot|crawler|spider|robot|crawling/i.test(navigator.userAgent)
|
|
const isGoogleCache = window.location.host === 'webcache.googleusercontent.com'
|
|
|
|
if (isBot || isGoogleCache) return undefined
|
|
|
|
return (to, from, savedPosition) => {
|
|
if (savedPosition) return savedPosition
|
|
if (to.hash) return { el: to.hash }
|
|
if (to.path === from.path) return undefined
|
|
|
|
// Have to use a promise here
|
|
// FIXME: https://github.com/vuejs/router/issues/1411
|
|
return new Promise(res => setTimeout(() => {
|
|
res({ top: 0, left: 0 })
|
|
}))
|
|
}
|
|
}
|