Improve i18n handling (#5342)

This commit is contained in:
Michael Geers 2022-12-03 14:32:53 +01:00 • committed by GitHub
parent 2fdb2eb37f
commit 5ddf3c841f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 1552 additions and 3309 deletions

View file

@ -3,7 +3,7 @@ import "bootstrap/dist/css/bootstrap.min.css";
import "bootstrap";
import smoothscroll from "smoothscroll-polyfill";
import VueNumber from "vue-number-animation";
import i18n from "./js/i18n";
import setupI18n from "./js/i18n";
import "./css/app.css";
import { watchThemeChanges } from "./js/theme";
@ -11,6 +11,6 @@ smoothscroll.polyfill();
watchThemeChanges();
export const setupVue3 = defineSetupVue3(({ app }) => {
app.use(i18n);
app.use(setupI18n());
app.use(VueNumber);
});

View file

@ -1,8 +0,0 @@
package i18n
import (
"embed"
)
//go:embed *.toml
var LocaleFS embed.FS

View file

@ -15,7 +15,7 @@ dark = "Design: donker"
availableShort = "update"
availableLong = "update beschikbaar"
modalTitle = "Update beschikbaar"
modalUpdateStarted = "Evcc zal herstarten na de update.."
modalUpdateStarted = "Evcc zal herstarten na de update."
modalInstalledVersion = "Huidige versie"
modalNoReleaseNotes = "Geen release notes beschikbaar. Meer informatie over de nieuwe versie vind je hier:"
modalCancel = "Annuleer"

View file

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="de">
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />

View file

@ -2,8 +2,10 @@ import axios from "axios";
const { protocol, hostname, port, pathname } = window.location;
const base = protocol + "//" + hostname + (port ? ":" + port : "") + pathname;
const api = axios.create({
baseURL: protocol + "//" + hostname + (port ? ":" + port : "") + pathname + "api/",
baseURL: base + "api/",
headers: {
Accept: "application/json",
},
@ -19,4 +21,12 @@ api.interceptors.response.use(
return Promise.reject(error);
}
);
export default api;
export const i18n = axios.create({
baseURL: base + "i18n/",
headers: {
Accept: "application/toml",
},
});

View file

@ -6,8 +6,8 @@ import { createApp, h } from "vue";
import { createMetaManager, plugin as metaPlugin } from "vue-meta";
import App from "./views/App.vue";
import VueNumber from "vue-number-animation";
import router from "./router";
import i18n from "./i18n";
import setupRouter from "./router";
import setupI18n from "./i18n";
import featureflags from "./featureflags";
import { watchThemeChanges } from "./theme";
@ -64,8 +64,9 @@ const app = createApp({
},
});
const i18n = setupI18n();
app.use(i18n);
app.use(router);
app.use(setupRouter(i18n));
app.use(createMetaManager());
app.use(metaPlugin);
app.use(featureflags);

View file

@ -1,13 +1,8 @@
import toml from "toml";
import { nextTick } from "vue";
import { createI18n } from "vue-i18n";
import de from "../i18n/de.toml";
import en from "../i18n/en.toml";
import fr from "../i18n/fr.toml";
import it from "../i18n/it.toml";
import lt from "../i18n/lt.toml";
import nl from "../i18n/nl.toml";
import nb_no from "../i18n/nb_NO.toml";
import pl from "../i18n/pl.toml";
import pt from "../i18n/pt.toml";
import en from "../../i18n/en.toml";
import { i18n as i18nApi } from "./api";
const PREFERRED_LOCALE_KEY = "preferred_locale";
@ -20,8 +15,43 @@ function getBrowserLocale() {
return navigatorLocale.trim().split(/-|_/)[0];
}
export default createI18n({
locale: window.localStorage[PREFERRED_LOCALE_KEY] || getBrowserLocale(),
fallbackLocale: "en",
messages: { de, en, fr, it, lt, nb_no, nl, pl, pt },
});
function getLocale() {
return window.localStorage[PREFERRED_LOCALE_KEY] || getBrowserLocale();
}
export default function setupI18n() {
const i18n = createI18n({
legacy: true,
silentFallbackWarn: true,
silentTranslationWarn: true,
locale: "en",
fallbackLocale: "en",
messages: { en },
});
setI18nLanguage(i18n, getLocale());
return i18n;
}
export function setI18nLanguage(i18n, locale) {
i18n.global.locale = locale;
document.querySelector("html").setAttribute("lang", locale);
}
async function loadLocaleMessages(i18n, locale) {
try {
const response = await i18nApi.get(`${locale}.toml`, { params: { v: window.evcc?.version } });
const messages = toml.parse(response.data);
i18n.global.setLocaleMessage(locale, messages);
} catch (e) {
console.error(`unable to load translation for [${locale}]`, e);
}
return nextTick();
}
export async function ensureCurrentLocaleMessages(i18n) {
const { locale } = i18n.global;
if (!i18n.global.availableLocales.includes(locale)) {
await loadLocaleMessages(i18n, locale);
}
}

View file

@ -2,11 +2,19 @@ import { createRouter, createWebHashHistory } from "vue-router";
import Main from "./views/Main.vue";
import ChargingSessions from "./views/ChargingSessions.vue";
import { ensureCurrentLocaleMessages } from "./i18n";
export default createRouter({
history: createWebHashHistory(),
routes: [
{ path: "/", component: Main, props: true },
{ path: "/sessions", component: ChargingSessions, props: true },
],
});
export default function setupRouter(i18n) {
const router = createRouter({
history: createWebHashHistory(),
routes: [
{ path: "/", component: Main, props: true },
{ path: "/sessions", component: ChargingSessions, props: true },
],
});
router.beforeEach(async () => {
await ensureCurrentLocaleMessages(i18n);
return true;
});
return router;
}

File diff suppressed because one or more lines are too long

74
dist/assets/index.4e414929.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

6
dist/index.html vendored
View file

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="de">
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
@ -20,8 +20,8 @@
<meta name="theme-color" content="#020318" />
<title>evcc</title>
<script type="module" crossorigin src="./assets/index.841a487a.js"></script>
<link rel="stylesheet" href="./assets/index.932fb253.css">
<script type="module" crossorigin src="./assets/index.4e414929.js"></script>
<link rel="stylesheet" href="./assets/index.14ecea29.css">
</head>
<body>

3
go.mod
View file

@ -114,6 +114,9 @@ require (
github.com/felixge/httpsnoop v1.0.3 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/glebarez/go-sqlite v1.19.2 // indirect
github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1
github.com/go-http-utils/fresh v0.0.0-20161124030543-7231e26a4b27 // indirect
github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.5.1 // indirect
github.com/go-playground/locales v0.14.0 // indirect

6
go.sum
View file

@ -264,6 +264,12 @@ github.com/glebarez/sqlite v1.5.0/go.mod h1:0wzXzTvfVJIN2GqRhCdMbnYd+m+aH5/QV7B3
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1 h1:zga7zaRE8HCbWjcXMDlfvmQtH0/kMVLo7cQ48dy6kWg=
github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1/go.mod h1:PumS+5d59wmAGsZo6IfRpVNaJUq+6xjC4Utt/k8GO6Q=
github.com/go-http-utils/fresh v0.0.0-20161124030543-7231e26a4b27 h1:O6yi4xa9b2DMosGsXzlMe2E9qXgXCVkRLCoRX+5amxI=
github.com/go-http-utils/fresh v0.0.0-20161124030543-7231e26a4b27/go.mod h1:AYvN8omj7nKLmbcXS2dyABYU6JB1Lz1bHmkkq1kf4I4=
github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a h1:v6zMvHuY9yue4+QkG/HQ/W67wvtQmWJ4SDo9aK/GIno=
github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a/go.mod h1:I79BieaU4fxrw4LMXby6q5OS9XnoR9UIKLOzDFjUmuw=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=

View file

@ -15,7 +15,7 @@ dark = "Design: dark"
availableShort = "update"
availableLong = "update available"
modalTitle = "Update available"
modalUpdateStarted = "Evcc will restart after the update.."
modalUpdateStarted = "Evcc will restart after the update."
modalInstalledVersion = "Currently installed version"
modalNoReleaseNotes = "No release notes available. More information about the new version can be found here:"
modalCancel = "Cancel"

220
i18n/nl.toml Normal file
View file

@ -0,0 +1,220 @@
[header]
sessions = "Laadsessies"
docs = "Documentatie"
blog = "Blog"
github = "GitHub"
login = "Voertuig logins"
about = "Over evcc"
[header.theme]
auto = "Design: systeem"
light = "Design: licht"
dark = "Design: donker"
[footer.version]
availableShort = "update"
availableLong = "update beschikbaar"
modalTitle = "Update beschikbaar"
modalUpdateStarted = "Evcc zal herstarten na de update."
modalInstalledVersion = "Huidige versie"
modalNoReleaseNotes = "Geen release notes beschikbaar. Meer informatie over de nieuwe versie vind je hier:"
modalCancel = "Annuleer"
modalUpdate = "Update"
modalUpdateNow = "Nu updaten"
modalDownload = "Download"
modalUpdateStatusStart = "Update gestart:"
modalUpdateStatusFailed = "Update mislukt:"
[footer.savings]
tabTitle = "Mijn data"
footerShort = "{percent}% PV"
footerLong = "{percent}% zonne-energie"
modalTitle = "Energieoverzicht"
since = "sinds {since}"
percentTitle = "Zonne-energie"
percentSelf = "{self} kWh PV"
percentGrid = "{grid} kWh afgenomen"
priceTitle = "Energieprijs"
priceFeedIn = "{feedInPrice} injectie"
priceGrid = "{gridPrice} afname"
savingsTitle = "Besparing"
savingsComparedToGrid = "i.v.m. netafname"
savingsTotalEnergy = "{total} kWh geladen"
[footer.community]
tabTitle = "Live community"
power = "Laadvermogen"
powerSub1 = "{activeClients} van {totalClients} deelnemers"
powerSub2 = "zijn nu aan het laden"
greenShare = "Zonne-energie"
greenShareSub1 = "van de energie"
greenShareSub2 = "komt van PV & batterijopslag"
greenEnergy = "Zonne-energie"
greenEnergySub1 = "geladen met evcc"
greenEnergySub2 = "sinds oktober 2022"
[footer.telemetry]
optIn = "Ik wil mijn data ook bijdragen."
optInMoreDetails = "Meer info is {0} beschikbaar."
optInMoreDetailsLink = "hier"
optInSponsorship = "(Sponsoring nodig)"
[footer.sponsor]
titleSponsor = "Je bent een sponsor!"
titleNoSponsor = "Sponsor ons"
thanks = "Bedankt voor je hulp, {sponsor}! Je helpt ons bij de verdere ontwikkeling van evcc."
confetti = "Klaar voor confetti?"
supportUs = "Onze missie: Van laden op zonne-energie de standaard maken. Help ons en draag financieel bij aan evcc."
sticker = "… of evcc stickers?"
confettiPromise = "Er zullen stickers en digitale confetti zijn ;)"
becomeSponsor = "Word sponsor"
[notifications]
modalTitle = "Notificaties"
dismissAll = "Alles verwijderen"
[main]
vehicles = "Parking"
[main.energyflow]
noEnergy = "Geen meter data"
homePower = "Consumptie"
pvProduction = "Productie"
loadpoints = "Laadpunt | Laadpunt | {count} Laadpunten"
battery = "Batterij"
batteryCharge = "Batterij laden"
batteryDischarge = "Batterij ontladen"
gridImport = "Netafname"
selfConsumption = "Zelfverbruik"
pvExport = "Netinjectie"
[main.mode]
off = "Uit"
minpv = "Min+PV"
pv = "PV"
now = "Snel"
[main.loadpoint]
fallbackName = "Laadpunt"
remoteDisabledSoft = "{source}: adaptief PV-laden uitgeschakeld"
remoteDisabledHard = "{source}: uitgeschakeld"
power = "Snelheid"
charged = "Geladen"
duration = "Duur"
remaining = "Resterend"
[main.loadpointSettings]
title = 'Instellingen "{0}"'
vehicle = "Voertuig"
currents = "Opladen"
default = "standaard"
disclaimerHint = "Letop:"
disclaimerText = "Instellingen worden niet bijgehouden. Ze worden gereset bij het herstarten van de server."
[main.loadpointSettings.minSoC]
label = "Min batterijniveau"
description = 'Noodbereik. Voertuig wordt "snel" geladen tot {0}% in PV mode. Daarna wordt enkel de PV-overschot gebruikt.'
[main.loadpointSettings.phasesConfigured]
label = "Fasen"
phases_0 = "automatisch wisselend"
phases_1 = "1 fase"
phases_1_hint = "({min} - {max})"
phases_3 = "3 fasen"
phases_3_hint = "({min} - {max})"
[main.loadpointSettings.maxCurrent]
label = "Max. vermogen"
[main.loadpointSettings.minCurrent]
label = "Min. vermogen"
[main.vehicle]
fallbackName = "Voertuig"
vehicleSoC = "Batterijniveau"
targetSoC = "Limiet"
none = "Geen voertuig"
unknown = "Gast"
changeVehicle = "Wijzig voertuig"
detectionActive = "Voertuig detecteren ..."
[main.vehicleSoC]
disconnected = "niet verbonden"
charging = "laden"
ready = "klaar"
connected = "verbonden"
vehicleTarget = "Voertuiglimiet: {soc}%"
[main.vehicleStatus]
minCharge = "laden naar {soc}% minimum."
waitForVehicle = "Klaar. Wachten op voertuig."
vehicleTargetReached = "Voertuiglimiet {soc}% bereikt."
charging = "Laden."
targetChargePlanned = "Doel gepland. Starten op {time}."
targetChargeWaitForVehicle = "Doel gepland. Wachten op voertuig."
targetChargeActive = "Doelladen actief."
connected = "Verbonden."
pvDisable = "Onvoldoende PV overschot beschikbaar. Pauzeren over {remaining}."
pvEnable = "Voldoende PV overschot beschikbaar. Starten over {remaining}."
scale1p = "Wisselen naar 1 fase over {remaining}."
scale3p = "Wisselen naar 3 fasen over {remaining}."
disconnected = "Niet verbonden."
unknown = ""
[main.provider]
login = "aanmelden"
logout = "afmelden"
[main.targetCharge]
title = "Doel"
inactiveLabel = "Ingestelde tijd"
activeLabel = "{time}"
modalTitle = "Stel tijd in"
setTargetTime = "geen"
description = "Tegen wanneer moet het voertuig geladen zijn naar {targetSoC}%?"
today = "Vandaag"
tomorrow = "Morgen"
targetIsInThePast = "De ingestelde tijd ligt in het verleden"
remove = "Verwijder"
activate = "Activeer"
experimentalLabel = "Experimenteel"
experimentalText = "Deze feature werkt nog niet perfect. Rapporteer ongewenst gedrag op"
[main.targetEnergy]
label = "Limiet"
noLimit = "geen"
[startupError]
title = "Start Error"
description = "Check je evcc configuratie. Helpt de foutboodschap je niet, bekijk dan de {0}."
discussions = "GitHub Discussions"
hint = "Je kan deze boodschap ook krijgen bij een kapot toestel (inverter, meter, ...). Check je network connectie."
configuration = "Config"
configFile = "Gebruikt configuratiebestand:"
lineError = "Fout gedetecteerd op {0}."
lineErrorLink = "lijn {0}"
fixAndRestart = "Verhelp het probleem en herstart de server."
restartButton = "Herstart"
[sessions]
title = "Laadsessies"
downloadCsv = "Download CSV"
loadpoint = "Laadpunt"
vehicle = "Voertuig"
energy = "Geladen"
date = "Periode"
[sessions.csv]
loadpoint = "Laadpunt"
vehicle = "Voertuig"
odometer = "kilometerstand (km)"
identifier = "ID"
chargedenergy = "Energie (kWh)"
meterstart = "Meter Start (kWh)"
meterstop = "Meter Stop (kWh)"
created = "Gestart"
finished = "Beëindigd"
[offline]
message = "Geen verbinding met de server."
reload = "Opnieuw laden?"

24
main.go
View file

@ -9,23 +9,35 @@ import (
"time"
"github.com/evcc-io/evcc/cmd"
"github.com/evcc-io/evcc/server"
"github.com/evcc-io/evcc/server/assets"
_ "github.com/evcc-io/evcc/util/goversion" // require minimum go version
)
//go:embed dist
var assets embed.FS
var (
//go:embed dist
web embed.FS
//go:embed i18n/*.toml
i18n embed.FS
)
// init loads embedded assets unless live assets are already loaded
func init() {
// TODO remove this once Go 1.20 is out with it.
rand.Seed(time.Now().UnixNano())
if server.Assets == nil {
fsys, err := fs.Sub(assets, "dist")
if !assets.Live() {
var err error
assets.Web, err = fs.Sub(web, "dist")
if err != nil {
panic(err)
}
assets.I18n, err = fs.Sub(i18n, "i18n")
if err != nil {
panic(err)
}
server.Assets = fsys
}
}

4256
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -18,9 +18,11 @@
"bootstrap": "^5.2.2",
"canvas-confetti": "^1.4.0",
"smoothscroll-polyfill": "^0.4.4",
"toml": "^3.0.0",
"vite-plugin-toml": "^0.5.0",
"vue": "^3.2.29",
"vue-hot-reload-api": "^2.3.4",
"vue-i18n": "^9.1.9",
"vue-i18n": "^9.2.2",
"vue-meta": "^3.0.0-alpha.2",
"vue-number-animation": "^1.1.2",
"vue-router": "^4.0.12"
@ -29,7 +31,6 @@
"@babel/core": "^7.17.2",
"@histoire/plugin-vue": "^0.11.6",
"@vue/compiler-sfc": "^3.2.30",
"babel-loader": "^8.2.3",
"eslint": "^8.27.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-import": "^2.25.3",
@ -38,14 +39,11 @@
"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-vue": "^9.3.0",
"histoire": "^0.11.6",
"html-webpack-plugin": "^5.5.0",
"postcss-custom-media": "^8.0.2",
"prettier": "^2.5.1",
"prettier-plugin-toml": "^0.3.1",
"rollup-plugin-analyzer": "^4.0.0",
"vite": "^3.0.4",
"vite-plugin-toml": "^0.4.0",
"vue-eslint-parser": "^9.1.0",
"vue-loader": "^17.0.0"
"vue-eslint-parser": "^9.1.0"
},
"engines": {
"npm": ">=8.0.0",

View file

@ -1,5 +0,0 @@
const postcssCustomMedia = require("postcss-custom-media");
module.exports = {
plugins: [postcssCustomMedia()],
};

16
server/assets/assets.go Normal file
View file

@ -0,0 +1,16 @@
package assets
import "io/fs"
var (
// Web is the embedded dist file system
Web fs.FS
// I18n is the embedded i18n file system
I18n fs.FS
)
// Live indicates assets are passed-through from filesystem
func Live() bool {
return Web != nil
}

View file

@ -0,0 +1,12 @@
//go:build !release
package assets
import (
"os"
)
func init() {
Web = os.DirFS("dist")
I18n = os.DirFS("i18n")
}

View file

@ -2,20 +2,18 @@ package server
import (
"fmt"
"io/fs"
"net/http"
"time"
"github.com/evcc-io/evcc/core/site"
"github.com/evcc-io/evcc/server/assets"
"github.com/evcc-io/evcc/util"
"github.com/evcc-io/evcc/util/telemetry"
"github.com/go-http-utils/etag"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
)
// Assets is the embedded assets file system
var Assets fs.FS
type route struct {
Methods []string
Pattern string
@ -53,11 +51,15 @@ func NewHTTPd(addr string, hub *SocketHub) *HTTPd {
// static - individual handlers per root and folders
static := router.PathPrefix("/").Subrouter()
static.Use(handlers.CompressHandler)
static.Use(handlers.CompressHandler, func(h http.Handler) http.Handler {
return etag.Handler(h, false)
})
static.HandleFunc("/", indexHandler())
for _, dir := range []string{"assets", "meta"} {
static.PathPrefix("/" + dir).Handler(http.FileServer(http.FS(Assets)))
static.PathPrefix("/" + dir).Handler(http.FileServer(http.FS(assets.Web)))
}
static.PathPrefix("/i18n").Handler(http.StripPrefix("/i18n", http.FileServer(http.FS(assets.I18n))))
srv := &HTTPd{
Server: &http.Server{

View file

@ -15,6 +15,7 @@ import (
"github.com/evcc-io/evcc/core/db"
"github.com/evcc-io/evcc/core/loadpoint"
"github.com/evcc-io/evcc/core/site"
"github.com/evcc-io/evcc/server/assets"
dbserver "github.com/evcc-io/evcc/server/db"
"github.com/evcc-io/evcc/util"
"github.com/evcc-io/evcc/util/locale"
@ -28,7 +29,7 @@ func indexHandler() http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=UTF-8")
indexTemplate, err := fs.ReadFile(Assets, "index.html")
indexTemplate, err := fs.ReadFile(assets.Web, "index.html")
if err != nil {
log.FATAL.Print("httpd: failed to load embedded template:", err.Error())
log.FATAL.Print("Make sure templates are included using the `release` build tag or use `make build`")

View file

@ -1,11 +0,0 @@
//go:build !release
package server
import (
"os"
)
func init() {
Assets = os.DirFS("dist")
}

View file

@ -2,10 +2,11 @@ package locale
import (
"fmt"
"io/fs"
"github.com/BurntSushi/toml"
"github.com/cloudfoundry/jibber_jabber"
assets "github.com/evcc-io/evcc/assets/i18n"
"github.com/evcc-io/evcc/server/assets"
"github.com/evcc-io/evcc/util/locale/internal"
"github.com/nicksnyder/go-i18n/v2/i18n"
"golang.org/x/text/language"
@ -25,13 +26,13 @@ func Init() error {
Bundle = i18n.NewBundle(language.English)
Bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal)
dir, err := assets.LocaleFS.ReadDir(".")
dir, err := fs.ReadDir(assets.I18n, ".")
if err != nil {
panic(err)
}
for _, d := range dir {
if _, err := Bundle.LoadMessageFileFS(assets.LocaleFS, d.Name()); err != nil {
if _, err := Bundle.LoadMessageFileFS(assets.I18n, d.Name()); err != nil {
return fmt.Errorf("loading locales failed: %w", err)
}
}

View file

@ -1,6 +1,7 @@
import { defineConfig } from "vite";
import vuePlugin from "@vitejs/plugin-vue";
import { ViteToml } from "vite-plugin-toml";
//import analyze from "rollup-plugin-analyzer";
export default defineConfig({
root: "./assets",
@ -20,6 +21,7 @@ export default defineConfig({
port: 7071,
proxy: {
"/api": "http://localhost:7070",
"/i18n": "http://localhost:7070",
"/ws": { target: "ws://localhost:7070", ws: true },
},
},
@ -32,5 +34,6 @@ export default defineConfig({
},
}),
ViteToml(),
//analyze(),
],
});