main.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. 'use strict'
  2. import 'femtocrank/style.css'
  3. import 'femtocrank/dark.css'
  4. import './style.css'
  5. import 'iconify-icon'
  6. import { createClient } from '@connectrpc/connect'
  7. import { createConnectTransport } from '@connectrpc/connect-web'
  8. import { OliveTinApiService } from './resources/scripts/gen/olivetin/api/v1/olivetin_pb'
  9. import { createApp, h } from 'vue'
  10. import { createI18n } from 'vue-i18n'
  11. import router from './resources/vue/router.js'
  12. import App from './resources/vue/App.vue'
  13. import { initWebsocket } from './js/websocket.js'
  14. import combinedTranslations from '../lang/combined_output.json'
  15. function getSelectedLanguage () {
  16. const storedLanguage = localStorage.getItem('olivetin-language')
  17. if (storedLanguage && storedLanguage !== 'auto') {
  18. return storedLanguage
  19. }
  20. if (storedLanguage === 'auto') {
  21. localStorage.removeItem('olivetin-language')
  22. }
  23. if (navigator.languages && navigator.languages.length > 0) {
  24. const available = Object.keys(combinedTranslations.messages || {})
  25. for (const candidate of navigator.languages) {
  26. const lowerCandidate = candidate.toLowerCase()
  27. const exact = available.find(locale => locale.toLowerCase() === lowerCandidate)
  28. if (exact) {
  29. return exact
  30. }
  31. const prefix = available.find(locale => locale.toLowerCase().startsWith(lowerCandidate.split('-')[0] + '-'))
  32. if (prefix) {
  33. return prefix
  34. }
  35. }
  36. }
  37. return 'en'
  38. }
  39. async function initClient () {
  40. const transport = createConnectTransport({
  41. baseUrl: window.location.protocol + '//' + window.location.host + '/api/'
  42. })
  43. window.client = createClient(OliveTinApiService, transport)
  44. window.initResponse = await window.client.init({})
  45. if (window.initResponse.enableCustomJs) {
  46. const script = document.createElement('script')
  47. script.src = '/custom-webui/custom.js'
  48. script.async = true
  49. script.id = 'olivetin-custom-js'
  50. document.head.appendChild(script)
  51. }
  52. const i18nSettings = createI18n({
  53. legacy: false,
  54. locale: getSelectedLanguage(),
  55. fallbackLocale: 'en',
  56. messages: combinedTranslations.messages,
  57. postTranslation: (translated) => {
  58. const params = new URLSearchParams(window.location.search)
  59. if (params.has('debug-translations')) {
  60. return '____'
  61. } else {
  62. return translated
  63. }
  64. }
  65. })
  66. return i18nSettings
  67. }
  68. function setupVue (i18nSettings) {
  69. const app = createApp(App)
  70. app.use(router)
  71. app.use(i18nSettings)
  72. window.i18n = i18nSettings.global
  73. app.mount('#app')
  74. }
  75. function setupErrorDisplay (errorMessage) {
  76. const ErrorApp = {
  77. render () {
  78. return h('section', { class: 'bad', style: 'padding: 2em; text-align: center; margin: 2em auto;' }, [
  79. h('h2', 'OliveTin Init Failed'),
  80. h('p', errorMessage),
  81. h('p', 'Please check your browser console for more details.')
  82. ])
  83. }
  84. }
  85. const app = createApp(ErrorApp)
  86. app.mount('#app')
  87. }
  88. async function main () {
  89. try {
  90. const i18nSettings = await initClient()
  91. initWebsocket()
  92. setupVue(i18nSettings)
  93. } catch (err) {
  94. const errorMessage = err.message || 'Failed to initialize. Please check your configuration and try again.'
  95. console.error('Init failed:', err)
  96. setupErrorDisplay(errorMessage)
  97. }
  98. }
  99. main()