Compare commits

..

5 Commits

20 changed files with 800 additions and 60 deletions

View File

@@ -37,6 +37,9 @@ func (a *Addon) GetRemoteRelease() (body []byte, err error) {
func (a *Addon) HasBreakingChanges(lhsToc, rhsToc string) bool {
lhsLines := strings.Split(lhsToc, "\n")
rhsLines := strings.Split(rhsToc, "\n")
if len(lhsLines) != len(rhsLines) {
return true
}
for i, lhsLine := range lhsLines {
rhsLine := rhsLines[i]
lhsLine = strings.TrimSpace(lhsLine)
@@ -74,14 +77,43 @@ func UpdateFile(localPath string, data []byte) (err error) {
return nil
}
func (a *Addon) Update(body []byte) (err error) {
func (a *Addon) Update(body []byte) (hasBreakingChanges bool, err error) {
log.Printf("Updating %s", a.Name)
zipReader, err := zip.NewReader(bytes.NewReader(body), int64(len(body)))
if err != nil {
return fmt.Errorf("error creating zip reader: %w", err)
return false, fmt.Errorf("error creating zip reader: %w", err)
}
log.Printf("Found %d files", len(zipReader.File))
hasBreakingChanges := false
// Yes it is quite ugly iterating twice doing the same work
// Maybe I fix it later but definitely not now
for _, file := range zipReader.File {
if strings.HasSuffix(file.Name, ".toc") {
localToc, err := os.ReadFile(a.GetLocalTocPath())
if err != nil {
if os.IsNotExist(err) {
localToc = []byte{}
} else {
return false, fmt.Errorf("error reading local toc: %w", err)
}
}
fileHandle, err := file.Open()
if err != nil {
return false, fmt.Errorf("error opening file: %w", err)
}
fileData, err := io.ReadAll(fileHandle)
if err != nil {
return false, fmt.Errorf("error reading file: %w", err)
}
if a.HasBreakingChanges(string(localToc), string(fileData)) {
Warning.Printf("Has breaking changes")
hasBreakingChanges = true
}
}
}
for _, file := range zipReader.File {
if file.FileInfo().IsDir() {
continue
@@ -89,39 +121,25 @@ func (a *Addon) Update(body []byte) (err error) {
log.Printf("Found file %s", file.Name)
fileHandle, err := file.Open()
if err != nil {
return fmt.Errorf("error opening file: %w", err)
return false, fmt.Errorf("error opening file: %w", err)
}
fileData, err := io.ReadAll(fileHandle)
if err != nil {
return fmt.Errorf("error reading file: %w", err)
}
if strings.HasSuffix(file.Name, ".toc") {
localToc, err := os.ReadFile(a.GetLocalTocPath())
if err != nil {
if os.IsNotExist(err) {
localToc = []byte{}
} else {
return fmt.Errorf("error reading local toc: %w", err)
}
}
if a.HasBreakingChanges(string(localToc), string(fileData)) {
log.Printf("Has breaking changes")
hasBreakingChanges = true
}
return false, fmt.Errorf("error reading file: %w", err)
}
localPath := filepath.Join(settings.GamePath, "Interface", "AddOns", file.Name)
log.Printf("Updating file %s", localPath)
err = UpdateFile(localPath, fileData)
if err != nil {
return fmt.Errorf("error updating file: %w", err)
return false, fmt.Errorf("error updating file: %w", err)
}
}
if hasBreakingChanges {
Warning.Printf("Has breaking changes")
}
return nil
return hasBreakingChanges, nil
}
func (a *Addon) GetLocalTocPath() string {
return filepath.Join(settings.GamePath, "Interface", "AddOns", a.Name, a.Name+".toc")

View File

@@ -36,18 +36,18 @@ func (a *AddonService) GetLocalVersion(name string) (string, error) {
return addon.GetLocalVersion()
}
func (a *AddonService) UpdateAddon(name string) (addon Addon, err error) {
addon, err = a.GetAddon(name)
func (a *AddonService) UpdateAddon(name string) (hasBreakingChanges bool, err error) {
addon, err := a.GetAddon(name)
if err != nil {
return
return false, err
}
release, err := addon.GetRemoteRelease()
if err != nil {
return
}
err = addon.Update(release)
hasBreakingChanges, err = addon.Update(release)
if err != nil {
return
}
return addon, nil
return hasBreakingChanges, nil
}

80
addon_test.go Normal file
View File

@@ -0,0 +1,80 @@
package main
import (
"testing"
)
// Compare identical TOC strings returns false for breaking changes
func TestHasBreakingChangesWithIdenticalTOCs(t *testing.T) {
addon := &Addon{}
toc := `## Interface: 70300
## Title: Channeler
## Version: 1.6.0
## Notes: Automatically sets up chat channels
## Author: Cyka
#core
Channeler.lua`
result := addon.HasBreakingChanges(toc, toc)
if result {
t.Errorf("Expected HasBreakingChanges to return false for identical TOCs, got true")
}
}
// Compare empty TOC strings returns false
func TestHasBreakingChangesWithEmptyTOCs(t *testing.T) {
addon := &Addon{}
result := addon.HasBreakingChanges("", "")
if result {
t.Errorf("Expected HasBreakingChanges to return false for empty TOCs, got true")
}
}
// Compare TOC strings with different content returns true for breaking changes
func TestCompareTocStringsDifferentContent(t *testing.T) {
addon := &Addon{}
lhsToc := "## Interface: 70300\n## Title: Channeler\nChanneler.lua"
rhsToc := "## Interface: 70300\n## Title: Channeler\nDifferentFile.lua"
result := addon.HasBreakingChanges(lhsToc, rhsToc)
if !result {
t.Errorf("Expected breaking changes, but got none")
}
}
// Compare TOC strings with different content returns true for breaking changes
func TestCompareTocStringsNewFile(t *testing.T) {
addon := &Addon{}
lhsToc := "## Interface: 70300\n## Title: Channeler\nChanneler.lua"
rhsToc := "## Interface: 70300\n## Title: Channeler\nChanneler.lua\nNewFile.lua"
result := addon.HasBreakingChanges(lhsToc, rhsToc)
if !result {
t.Errorf("Expected breaking changes, but got none")
}
}
// Compare TOC strings with same content but different whitespace returns false
func TestCompareTocStringsSameContentDifferentWhitespace(t *testing.T) {
addon := &Addon{}
lhsToc := "## Interface: 70300\n## Title: Channeler\nChanneler.lua"
rhsToc := "## Interface: 70300 \n## Title: Channeler \nChanneler.lua"
result := addon.HasBreakingChanges(lhsToc, rhsToc)
if result {
t.Errorf("Expected no breaking changes, but got some")
}
}
// Compare TOC strings with matching header lines (##) returns false
func TestCompareTocStringsMatchingHeaderLines(t *testing.T) {
addon := &Addon{}
lhsToc := "## Interface: 70300\n## Title: Channeler\n## Version: 1.6.0"
rhsToc := "## Interface: 70300\n## Title: Channeler\n## Version: 1.6.0"
result := addon.HasBreakingChanges(lhsToc, rhsToc)
if result {
t.Errorf("Expected no breaking changes, but got some")
}
}

18
app.go
View File

@@ -76,9 +76,9 @@ func (a *App) GetAddonLocalVersion(name string) (res StringResponse) {
return res
}
func (a *App) UpdateAddon(name string) (res AddonResponse) {
addon, err := addonService.UpdateAddon(name)
res.Data = addon
func (a *App) UpdateAddon(name string) (res BoolResponse) {
hasBreakingChanges, err := addonService.UpdateAddon(name)
res.Data = hasBreakingChanges
if err != nil {
res.Error = err.Error()
}
@@ -125,3 +125,15 @@ func (a *App) SelectDirectory() (res StringResponse) {
res.Data = path
return
}
func (a *App) GetLocale() string {
if settings.Locale == "" {
return "en"
}
return settings.Locale
}
func (a *App) SetLocale(locale string) error {
settings.Locale = locale
return SaveSettings(*settings)
}

View File

@@ -1,14 +1,14 @@
{
"name": "frontend",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-check --tsconfig ./tsconfig.json"
},
"name": "frontend",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-check --tsconfig ./tsconfig.json"
},
"devDependencies": {
"@fortawesome/fontawesome-svg-core": "^6.5.2",
"@fortawesome/free-brands-svg-icons": "^6.5.2",
@@ -31,6 +31,7 @@
"autoprefixer": "^10.4.20",
"chart.js": "^4.4.3",
"regression": "^2.0.1",
"svelte-chartjs": "^3.1.5"
"svelte-chartjs": "^3.1.5",
"svelte-i18n": "^4.0.1"
}
}

View File

@@ -1 +1 @@
49014f28d86d4ca6427e970cf696170b
26349183f2bc5b05555ae3d7ca598d6d

470
frontend/pnpm-lock.yaml generated
View File

@@ -20,6 +20,9 @@ importers:
svelte-chartjs:
specifier: ^3.1.5
version: 3.1.5(chart.js@4.4.3)(svelte@3.59.2)
svelte-i18n:
specifier: ^4.0.1
version: 4.0.1(svelte@3.59.2)
devDependencies:
'@fortawesome/fontawesome-svg-core':
specifier: ^6.5.2
@@ -76,18 +79,171 @@ packages:
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
engines: {node: '>=10'}
'@esbuild/aix-ppc64@0.19.12':
resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [aix]
'@esbuild/android-arm64@0.19.12':
resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==}
engines: {node: '>=12'}
cpu: [arm64]
os: [android]
'@esbuild/android-arm@0.15.18':
resolution: {integrity: sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==}
engines: {node: '>=12'}
cpu: [arm]
os: [android]
'@esbuild/android-arm@0.19.12':
resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==}
engines: {node: '>=12'}
cpu: [arm]
os: [android]
'@esbuild/android-x64@0.19.12':
resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==}
engines: {node: '>=12'}
cpu: [x64]
os: [android]
'@esbuild/darwin-arm64@0.19.12':
resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==}
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
'@esbuild/darwin-x64@0.19.12':
resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==}
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
'@esbuild/freebsd-arm64@0.19.12':
resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==}
engines: {node: '>=12'}
cpu: [arm64]
os: [freebsd]
'@esbuild/freebsd-x64@0.19.12':
resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==}
engines: {node: '>=12'}
cpu: [x64]
os: [freebsd]
'@esbuild/linux-arm64@0.19.12':
resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==}
engines: {node: '>=12'}
cpu: [arm64]
os: [linux]
'@esbuild/linux-arm@0.19.12':
resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==}
engines: {node: '>=12'}
cpu: [arm]
os: [linux]
'@esbuild/linux-ia32@0.19.12':
resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==}
engines: {node: '>=12'}
cpu: [ia32]
os: [linux]
'@esbuild/linux-loong64@0.15.18':
resolution: {integrity: sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==}
engines: {node: '>=12'}
cpu: [loong64]
os: [linux]
'@esbuild/linux-loong64@0.19.12':
resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==}
engines: {node: '>=12'}
cpu: [loong64]
os: [linux]
'@esbuild/linux-mips64el@0.19.12':
resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==}
engines: {node: '>=12'}
cpu: [mips64el]
os: [linux]
'@esbuild/linux-ppc64@0.19.12':
resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [linux]
'@esbuild/linux-riscv64@0.19.12':
resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==}
engines: {node: '>=12'}
cpu: [riscv64]
os: [linux]
'@esbuild/linux-s390x@0.19.12':
resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==}
engines: {node: '>=12'}
cpu: [s390x]
os: [linux]
'@esbuild/linux-x64@0.19.12':
resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==}
engines: {node: '>=12'}
cpu: [x64]
os: [linux]
'@esbuild/netbsd-x64@0.19.12':
resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==}
engines: {node: '>=12'}
cpu: [x64]
os: [netbsd]
'@esbuild/openbsd-x64@0.19.12':
resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==}
engines: {node: '>=12'}
cpu: [x64]
os: [openbsd]
'@esbuild/sunos-x64@0.19.12':
resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==}
engines: {node: '>=12'}
cpu: [x64]
os: [sunos]
'@esbuild/win32-arm64@0.19.12':
resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==}
engines: {node: '>=12'}
cpu: [arm64]
os: [win32]
'@esbuild/win32-ia32@0.19.12':
resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==}
engines: {node: '>=12'}
cpu: [ia32]
os: [win32]
'@esbuild/win32-x64@0.19.12':
resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==}
engines: {node: '>=12'}
cpu: [x64]
os: [win32]
'@formatjs/ecma402-abstract@2.3.2':
resolution: {integrity: sha512-6sE5nyvDloULiyOMbOTJEEgWL32w+VHkZQs8S02Lnn8Y/O5aQhjOEXwWzvR7SsBE/exxlSpY2EsWZgqHbtLatg==}
'@formatjs/fast-memoize@2.2.6':
resolution: {integrity: sha512-luIXeE2LJbQnnzotY1f2U2m7xuQNj2DA8Vq4ce1BY9ebRZaoPB1+8eZ6nXpLzsxuW5spQxr7LdCg+CApZwkqkw==}
'@formatjs/icu-messageformat-parser@2.9.8':
resolution: {integrity: sha512-hZlLNI3+Lev8IAXuwehLoN7QTKqbx3XXwFW1jh0AdIA9XJdzn9Uzr+2LLBspPm/PX0+NLIfykj/8IKxQqHUcUQ==}
'@formatjs/icu-skeleton-parser@1.8.12':
resolution: {integrity: sha512-QRAY2jC1BomFQHYDMcZtClqHR55EEnB96V7Xbk/UiBodsuFc5kujybzt87+qj1KqmJozFhk6n4KiT1HKwAkcfg==}
'@formatjs/intl-localematcher@0.5.10':
resolution: {integrity: sha512-af3qATX+m4Rnd9+wHcjJ4w2ijq+rAVP3CCinJQvFv1kgSu1W6jypUmvleJxcewdxmutM8dmIRZFxO/IQBZmP2Q==}
'@fortawesome/fontawesome-common-types@6.6.0':
resolution: {integrity: sha512-xyX0X9mc0kyz9plIyryrRbl7ngsA9jz77mCZJsUkLl+ZKs0KWObgaEBoSgQiYWAsSmjz/yjl0F++Got0Mdp4Rw==}
engines: {node: '>=6'}
@@ -243,6 +399,10 @@ packages:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
engines: {node: '>= 8.10.0'}
cli-color@2.0.4:
resolution: {integrity: sha512-zlnpg0jNcibNrO7GG9IeHH7maWFeCz+Ja1wx/7tZNU5ASSSSZ+/qZciM0/LHCYxSdqv5h2sdbQ/PXYdOuetXvA==}
engines: {node: '>=0.10'}
color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
@@ -266,6 +426,10 @@ packages:
engines: {node: '>=4'}
hasBin: true
d@1.0.2:
resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==}
engines: {node: '>=0.12'}
debug@4.3.6:
resolution: {integrity: sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==}
engines: {node: '>=6.0'}
@@ -275,6 +439,9 @@ packages:
supports-color:
optional: true
decimal.js@10.4.3:
resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==}
deepmerge@4.3.1:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
engines: {node: '>=0.10.0'}
@@ -301,9 +468,23 @@ packages:
emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
es5-ext@0.10.64:
resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==}
engines: {node: '>=0.10'}
es6-iterator@2.0.3:
resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==}
es6-promise@3.3.1:
resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==}
es6-symbol@3.1.4:
resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==}
engines: {node: '>=0.12'}
es6-weak-map@2.0.3:
resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==}
esbuild-android-64@0.15.18:
resolution: {integrity: sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==}
engines: {node: '>=12'}
@@ -429,10 +610,28 @@ packages:
engines: {node: '>=12'}
hasBin: true
esbuild@0.19.12:
resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==}
engines: {node: '>=12'}
hasBin: true
escalade@3.1.2:
resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==}
engines: {node: '>=6'}
esniff@2.0.1:
resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==}
engines: {node: '>=0.10'}
estree-walker@2.0.2:
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
event-emitter@0.3.5:
resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==}
ext@1.7.0:
resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==}
fast-glob@3.3.2:
resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==}
engines: {node: '>=8.6.0'}
@@ -478,6 +677,12 @@ packages:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
deprecated: Glob versions prior to v9 are no longer supported
globalyzer@0.1.0:
resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==}
globrex@0.1.2:
resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==}
graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
@@ -499,6 +704,9 @@ packages:
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
intl-messageformat@10.7.11:
resolution: {integrity: sha512-IB2N1tmI24k2EFH3PWjU7ivJsnWyLwOWOva0jnXFa29WzB6fb0JZ5EMQGu+XN5lDtjHYFo0/UooP67zBwUg7rQ==}
is-binary-path@2.1.0:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
engines: {node: '>=8'}
@@ -523,6 +731,9 @@ packages:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'}
is-promise@2.2.2:
resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==}
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
@@ -551,6 +762,9 @@ packages:
lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
lru-queue@0.1.0:
resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==}
magic-string@0.25.9:
resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
@@ -558,6 +772,10 @@ packages:
resolution: {integrity: sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==}
engines: {node: '>=12'}
memoizee@0.4.17:
resolution: {integrity: sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==}
engines: {node: '>=0.12'}
merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
@@ -603,6 +821,9 @@ packages:
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
next-tick@1.1.0:
resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
node-releases@2.0.18:
resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==}
@@ -833,6 +1054,13 @@ packages:
peerDependencies:
svelte: ^3.19.0 || ^4.0.0
svelte-i18n@4.0.1:
resolution: {integrity: sha512-jaykGlGT5PUaaq04JWbJREvivlCnALtT+m87Kbm0fxyYHynkQaxQMnIKHLm2WeIuBRoljzwgyvz0Z6/CMwfdmQ==}
engines: {node: '>= 16'}
hasBin: true
peerDependencies:
svelte: ^3 || ^4 || ^5
svelte-preprocess@4.10.7:
resolution: {integrity: sha512-sNPBnqYD6FnmdBrUmBCaqS00RyCsCpj2BG58A1JBswNF7b0OKviwxqVrOL/CKyJrLSClrSeqQv5BXNg2RUbPOw==}
engines: {node: '>= 9.11.2'}
@@ -897,6 +1125,13 @@ packages:
thenify@3.3.1:
resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
timers-ext@0.1.8:
resolution: {integrity: sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==}
engines: {node: '>=0.12'}
tiny-glob@0.2.9:
resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==}
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
@@ -907,6 +1142,9 @@ packages:
tslib@2.6.3:
resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==}
type@2.7.3:
resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==}
typescript@4.9.5:
resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==}
engines: {node: '>=4.2.0'}
@@ -979,12 +1217,107 @@ snapshots:
'@alloc/quick-lru@5.2.0': {}
'@esbuild/aix-ppc64@0.19.12':
optional: true
'@esbuild/android-arm64@0.19.12':
optional: true
'@esbuild/android-arm@0.15.18':
optional: true
'@esbuild/android-arm@0.19.12':
optional: true
'@esbuild/android-x64@0.19.12':
optional: true
'@esbuild/darwin-arm64@0.19.12':
optional: true
'@esbuild/darwin-x64@0.19.12':
optional: true
'@esbuild/freebsd-arm64@0.19.12':
optional: true
'@esbuild/freebsd-x64@0.19.12':
optional: true
'@esbuild/linux-arm64@0.19.12':
optional: true
'@esbuild/linux-arm@0.19.12':
optional: true
'@esbuild/linux-ia32@0.19.12':
optional: true
'@esbuild/linux-loong64@0.15.18':
optional: true
'@esbuild/linux-loong64@0.19.12':
optional: true
'@esbuild/linux-mips64el@0.19.12':
optional: true
'@esbuild/linux-ppc64@0.19.12':
optional: true
'@esbuild/linux-riscv64@0.19.12':
optional: true
'@esbuild/linux-s390x@0.19.12':
optional: true
'@esbuild/linux-x64@0.19.12':
optional: true
'@esbuild/netbsd-x64@0.19.12':
optional: true
'@esbuild/openbsd-x64@0.19.12':
optional: true
'@esbuild/sunos-x64@0.19.12':
optional: true
'@esbuild/win32-arm64@0.19.12':
optional: true
'@esbuild/win32-ia32@0.19.12':
optional: true
'@esbuild/win32-x64@0.19.12':
optional: true
'@formatjs/ecma402-abstract@2.3.2':
dependencies:
'@formatjs/fast-memoize': 2.2.6
'@formatjs/intl-localematcher': 0.5.10
decimal.js: 10.4.3
tslib: 2.6.3
'@formatjs/fast-memoize@2.2.6':
dependencies:
tslib: 2.6.3
'@formatjs/icu-messageformat-parser@2.9.8':
dependencies:
'@formatjs/ecma402-abstract': 2.3.2
'@formatjs/icu-skeleton-parser': 1.8.12
tslib: 2.6.3
'@formatjs/icu-skeleton-parser@1.8.12':
dependencies:
'@formatjs/ecma402-abstract': 2.3.2
tslib: 2.6.3
'@formatjs/intl-localematcher@0.5.10':
dependencies:
tslib: 2.6.3
'@fortawesome/fontawesome-common-types@6.6.0': {}
'@fortawesome/fontawesome-svg-core@6.6.0':
@@ -1144,6 +1477,14 @@ snapshots:
optionalDependencies:
fsevents: 2.3.3
cli-color@2.0.4:
dependencies:
d: 1.0.2
es5-ext: 0.10.64
es6-iterator: 2.0.3
memoizee: 0.4.17
timers-ext: 0.1.8
color-convert@2.0.1:
dependencies:
color-name: 1.1.4
@@ -1162,10 +1503,17 @@ snapshots:
cssesc@3.0.0: {}
d@1.0.2:
dependencies:
es5-ext: 0.10.64
type: 2.7.3
debug@4.3.6:
dependencies:
ms: 2.1.2
decimal.js@10.4.3: {}
deepmerge@4.3.1: {}
detect-indent@6.1.0: {}
@@ -1182,8 +1530,33 @@ snapshots:
emoji-regex@9.2.2: {}
es5-ext@0.10.64:
dependencies:
es6-iterator: 2.0.3
es6-symbol: 3.1.4
esniff: 2.0.1
next-tick: 1.1.0
es6-iterator@2.0.3:
dependencies:
d: 1.0.2
es5-ext: 0.10.64
es6-symbol: 3.1.4
es6-promise@3.3.1: {}
es6-symbol@3.1.4:
dependencies:
d: 1.0.2
ext: 1.7.0
es6-weak-map@2.0.3:
dependencies:
d: 1.0.2
es5-ext: 0.10.64
es6-iterator: 2.0.3
es6-symbol: 3.1.4
esbuild-android-64@0.15.18:
optional: true
@@ -1269,8 +1642,52 @@ snapshots:
esbuild-windows-64: 0.15.18
esbuild-windows-arm64: 0.15.18
esbuild@0.19.12:
optionalDependencies:
'@esbuild/aix-ppc64': 0.19.12
'@esbuild/android-arm': 0.19.12
'@esbuild/android-arm64': 0.19.12
'@esbuild/android-x64': 0.19.12
'@esbuild/darwin-arm64': 0.19.12
'@esbuild/darwin-x64': 0.19.12
'@esbuild/freebsd-arm64': 0.19.12
'@esbuild/freebsd-x64': 0.19.12
'@esbuild/linux-arm': 0.19.12
'@esbuild/linux-arm64': 0.19.12
'@esbuild/linux-ia32': 0.19.12
'@esbuild/linux-loong64': 0.19.12
'@esbuild/linux-mips64el': 0.19.12
'@esbuild/linux-ppc64': 0.19.12
'@esbuild/linux-riscv64': 0.19.12
'@esbuild/linux-s390x': 0.19.12
'@esbuild/linux-x64': 0.19.12
'@esbuild/netbsd-x64': 0.19.12
'@esbuild/openbsd-x64': 0.19.12
'@esbuild/sunos-x64': 0.19.12
'@esbuild/win32-arm64': 0.19.12
'@esbuild/win32-ia32': 0.19.12
'@esbuild/win32-x64': 0.19.12
escalade@3.1.2: {}
esniff@2.0.1:
dependencies:
d: 1.0.2
es5-ext: 0.10.64
event-emitter: 0.3.5
type: 2.7.3
estree-walker@2.0.2: {}
event-emitter@0.3.5:
dependencies:
d: 1.0.2
es5-ext: 0.10.64
ext@1.7.0:
dependencies:
type: 2.7.3
fast-glob@3.3.2:
dependencies:
'@nodelib/fs.stat': 2.0.5
@@ -1327,6 +1744,10 @@ snapshots:
once: 1.4.0
path-is-absolute: 1.0.1
globalyzer@0.1.0: {}
globrex@0.1.2: {}
graceful-fs@4.2.11: {}
hasown@2.0.2:
@@ -1347,6 +1768,13 @@ snapshots:
inherits@2.0.4: {}
intl-messageformat@10.7.11:
dependencies:
'@formatjs/ecma402-abstract': 2.3.2
'@formatjs/fast-memoize': 2.2.6
'@formatjs/icu-messageformat-parser': 2.9.8
tslib: 2.6.3
is-binary-path@2.1.0:
dependencies:
binary-extensions: 2.3.0
@@ -1365,6 +1793,8 @@ snapshots:
is-number@7.0.0: {}
is-promise@2.2.2: {}
isexe@2.0.0: {}
jackspeak@3.4.3:
@@ -1385,6 +1815,10 @@ snapshots:
lru-cache@10.4.3: {}
lru-queue@0.1.0:
dependencies:
es5-ext: 0.10.64
magic-string@0.25.9:
dependencies:
sourcemap-codec: 1.4.8
@@ -1393,6 +1827,17 @@ snapshots:
dependencies:
sourcemap-codec: 1.4.8
memoizee@0.4.17:
dependencies:
d: 1.0.2
es5-ext: 0.10.64
es6-weak-map: 2.0.3
event-emitter: 0.3.5
is-promise: 2.2.2
lru-queue: 0.1.0
next-tick: 1.1.0
timers-ext: 0.1.8
merge2@1.4.1: {}
micromatch@4.0.7:
@@ -1430,6 +1875,8 @@ snapshots:
nanoid@3.3.7: {}
next-tick@1.1.0: {}
node-releases@2.0.18: {}
normalize-path@3.0.0: {}
@@ -1650,6 +2097,17 @@ snapshots:
dependencies:
svelte: 3.59.2
svelte-i18n@4.0.1(svelte@3.59.2):
dependencies:
cli-color: 2.0.4
deepmerge: 4.3.1
esbuild: 0.19.12
estree-walker: 2.0.2
intl-messageformat: 10.7.11
sade: 1.8.1
svelte: 3.59.2
tiny-glob: 0.2.9
svelte-preprocess@4.10.7(postcss-load-config@4.0.2(postcss@8.4.41))(postcss@8.4.41)(sass@1.77.8)(svelte@3.59.2)(typescript@4.9.5):
dependencies:
'@types/pug': 2.0.10
@@ -1710,6 +2168,16 @@ snapshots:
dependencies:
any-promise: 1.3.0
timers-ext@0.1.8:
dependencies:
es5-ext: 0.10.64
next-tick: 1.1.0
tiny-glob@0.2.9:
dependencies:
globalyzer: 0.1.0
globrex: 0.1.2
to-regex-range@5.0.1:
dependencies:
is-number: 7.0.0
@@ -1718,6 +2186,8 @@ snapshots:
tslib@2.6.3: {}
type@2.7.3: {}
typescript@4.9.5: {}
update-browserslist-db@1.1.0(browserslist@4.23.3):

View File

@@ -66,7 +66,22 @@ toast('Hello World', {
<Toaster hotkey={['KeyC']} />
-->
<svelte:window on:keydown={keyDown} />
<Toaster theme="dark" expand visibleToasts={9} />
<Toaster
theme="dark"
expand
visibleToasts={9}
position="bottom-center"
offset="40px"
closeButton
richColors
toastOptions={{
classes: {
toast: 'min-w-[600px] p-4',
title: 'text-lg font-bold',
description: 'text-base'
}
}}
/>
<template>
<Header />
<main class="flex-1">

View File

@@ -1,10 +1,15 @@
<script lang="ts">
import { GetAddonLocalVersion, GetAddonRemoteVersion, UpdateAddon } from "$wails/main/App";
import { type main } from "$wails/models";
import { toast } from "svelte-sonner";
import { _ } from 'svelte-i18n';
export let addon: main.Addon;
let localVersion = "0.0.0";
let remoteVersion = "0.0.0";
let upToDate = true;
let isUpdating = false;
GetAddonLocalVersion(addon.name).then((res) => {
localVersion = res.data;
});
@@ -12,11 +17,33 @@
remoteVersion = res.data;
});
$: upToDate = localVersion === remoteVersion;
async function updateAddon() {
isUpdating = true;
const res = await UpdateAddon(addon.name);
if (res.error) {
console.error(res.error);
toast.error($_('toasts.updateFailed', { values: { name: addon.name } }), {
classes: {
toast: 'bg-red-600'
}
});
} else {
if (res.data) {
toast.error($_('toasts.updateBreakingChanges', { values: { name: addon.name } }), {
classes: {
toast: 'bg-red-600'
},
description: $_('toasts.restartRequired')
});
} else {
toast.success($_('toasts.updateSuccessful', { values: { name: addon.name } }), {
classes: {
toast: 'bg-green-600'
},
description: $_('toasts.reloadRequired')
});
}
}
GetAddonLocalVersion(addon.name).then((res) => {
localVersion = res.data;
@@ -24,16 +51,29 @@
GetAddonRemoteVersion(addon.name).then((res) => {
remoteVersion = res.data;
});
isUpdating = false;
}
</script>
<div class="bg-gray-900 text-white p-4 m-3 mx-2 rounded-lg">
<div class="text-white p-4 m-3 mx-2 rounded-lg bg-gray-900">
<h2 class="text-2xl font-bold">{addon.name}</h2>
<p class="text-gray-300">Local Version: {localVersion}</p>
<p class="text-gray-300">Remote Version: {remoteVersion}</p>
<p class="text-gray-300">{$_('common.localVersion')}: {localVersion}</p>
<p class="text-gray-300">{$_('common.remoteVersion')}: {remoteVersion}</p>
{#if upToDate}
<button class="bg-green-500 disabled text-white p-2 my-2 cursor-default rounded-lg">Up to date</button>
<button class="bg-green-400 disabled text-white p-2 my-2 cursor-default rounded-lg w-32 h-10">
{$_('common.upToDate')}
</button>
{:else}
<button class="bg-blue-500 text-white p-2 my-2 rounded-lg" on:click={updateAddon}>Update</button>
<button
class="bg-blue-500 text-white p-2 my-2 rounded-lg w-32 h-10 hover:bg-blue-600 disabled:opacity-50 disabled:cursor-not-allowed"
on:click={updateAddon}
disabled={isUpdating}
>
{#if isUpdating}
{$_('common.updating')}
{:else}
{$_('common.update')}
{/if}
</button>
{/if}
</div>

View File

@@ -1,5 +1,7 @@
<script>
import { GetGamePath, IsGamePathValid, SelectDirectory, SetGamePath } from "$wails/main/App";
import { _ } from 'svelte-i18n';
import LanguageSwitcher from './LanguageSwitcher.svelte';
let name = "Yggdrasil";
let description = "The wow addon manager";
@@ -37,7 +39,9 @@
<header class="bg-gray-900 text-white py-4">
<div class="container mx-auto px-4 relative">
<div class="flex justify-between items-center">
<div class="flex-1"></div>
<div class="flex-1">
<LanguageSwitcher />
</div>
<h1 class="text-3xl font-bold text-center relative flex-1">
{name}
</h1>
@@ -54,7 +58,7 @@
/>
<path d="M6 12a2 2 0 012-2h8a2 2 0 012 2v2a2 2 0 01-2 2H8a2 2 0 01-2-2v-2z" />
</svg>
{gamePathValid ? "Change Game Path" : "Set Game Path"}
{gamePathValid ? $_('common.changeGamePath') : $_('common.setGamePath')}
</button>
</div>
</div>

View File

@@ -0,0 +1,26 @@
<script lang="ts">
import { locale, isLoading } from 'svelte-i18n';
import { GetLocale, SetLocale } from '$wails/main/App';
const languages = [
{ code: 'en', name: 'EN' },
{ code: 'ru', name: 'RU' }
];
async function setLanguage(lang: string) {
$locale = lang;
await SetLocale(lang);
}
</script>
<div class="flex gap-1">
{#each languages as lang}
<button
class="px-3 py-1 rounded-lg transition-colors {$locale === lang.code ? 'bg-blue-500 text-white' : 'bg-gray-800 text-gray-300 hover:bg-gray-700'}"
on:click={() => setLanguage(lang.code)}
disabled={$isLoading}
>
{lang.name}
</button>
{/each}
</div>

View File

@@ -0,0 +1,16 @@
import { addMessages, init, waitLocale } from 'svelte-i18n';
import { GetLocale } from '$wails/main/App';
import en from './translations/en.json';
import ru from './translations/ru.json';
addMessages('en', en);
addMessages('ru', ru);
// Initialize with stored locale or fallback to browser locale
export const i18nInit = GetLocale().then(storedLocale => {
init({
fallbackLocale: 'en',
initialLocale: storedLocale || navigator.language.split('-')[0]
});
return waitLocale();
});

View File

@@ -0,0 +1,19 @@
{
"common": {
"upToDate": "Up to date",
"update": "Update",
"updating": "Updating...",
"localVersion": "Local Version",
"remoteVersion": "Remote Version",
"changeGamePath": "Change Game Path",
"setGamePath": "Set Game Path",
"gamePathNotValid": "Game path is not valid"
},
"toasts": {
"updateFailed": "Failed to update {name}",
"updateSuccessful": "{name} updated successfully!",
"updateBreakingChanges": "{name} updated with breaking changes!",
"restartRequired": "Please restart your game to apply the update.",
"reloadRequired": "You may /reload ingame to apply the update."
}
}

View File

@@ -0,0 +1,19 @@
{
"common": {
"upToDate": "Актуально",
"update": "Обновить",
"updating": "Обновление...",
"localVersion": "Локальная версия",
"remoteVersion": "Удаленная версия",
"changeGamePath": "Изменить путь к игре",
"setGamePath": "Указать путь к игре",
"gamePathNotValid": "Путь к игре недействителен"
},
"toasts": {
"updateFailed": "Не удалось обновить {name}",
"updateSuccessful": "{name} успешно обновлен!",
"updateBreakingChanges": "{name} обновлен с критическими изменениями!",
"restartRequired": "Пожалуйста, перезапустите игру, чтобы применить обновление.",
"reloadRequired": "Вы можете использовать /reload в игре, чтобы применить обновление."
}
}

View File

@@ -2,6 +2,7 @@
import AddonCard from "$lib/components/AddonCard.svelte";
import { GetAddons, IsGamePathValid } from "$wails/main/App";
import { type main } from "$wails/models";
import { _ } from 'svelte-i18n';
let addons: { [key: string]: main.Addon } = {};
GetAddons().then((res) => {
@@ -12,7 +13,6 @@
}
});
let gamePath = "";
let gamePathValid = false;
IsGamePathValid().then((res) => {
if (res.error) {
@@ -32,7 +32,7 @@
</div>
{:else}
<div class="flex flex-col items-center justify-center h-full">
<p class="text-gray-300">Game path is not valid</p>
<p class="text-gray-300">{$_('common.gamePathNotValid')}</p>
</div>
{/if}
</template>

View File

@@ -1,8 +1,15 @@
import './style.css'
import App from './App.svelte'
import { i18nInit } from './lib/i18n/i18n'
const app = new App({
target: document.getElementById('app')
const element = document.getElementById('app')
if (!element) throw new Error('Could not find app element')
// Initialize app after i18n is ready
const appPromise = i18nInit.then(() => {
return new App({
target: element
})
})
export default app
export default appPromise

View File

@@ -14,10 +14,14 @@ export function GetAddons():Promise<main.AddonsResponse>;
export function GetGamePath():Promise<main.StringResponse>;
export function GetLocale():Promise<string>;
export function IsGamePathValid():Promise<main.BoolResponse>;
export function SelectDirectory():Promise<main.StringResponse>;
export function SetGamePath(arg1:string):Promise<main.StringResponse>;
export function UpdateAddon(arg1:string):Promise<main.AddonResponse>;
export function SetLocale(arg1:string):Promise<void>;
export function UpdateAddon(arg1:string):Promise<main.BoolResponse>;

View File

@@ -26,6 +26,10 @@ export function GetGamePath() {
return window['go']['main']['App']['GetGamePath']();
}
export function GetLocale() {
return window['go']['main']['App']['GetLocale']();
}
export function IsGamePathValid() {
return window['go']['main']['App']['IsGamePathValid']();
}
@@ -38,6 +42,10 @@ export function SetGamePath(arg1) {
return window['go']['main']['App']['SetGamePath'](arg1);
}
export function SetLocale(arg1) {
return window['go']['main']['App']['SetLocale'](arg1);
}
export function UpdateAddon(arg1) {
return window['go']['main']['App']['UpdateAddon'](arg1);
}

View File

@@ -36,6 +36,7 @@ var addonService *AddonService
type Settings struct {
GamePath string `json:"gamePath"`
Addons map[string]Addon `json:"addons"`
Locale string `json:"locale"`
}
func SaveSettings(settings Settings) error {
@@ -81,8 +82,8 @@ func main() {
err = wails.Run(&options.App{
Title: "wails-template",
Width: 700,
Height: 700,
Width: 800,
Height: 600,
AssetServer: &assetserver.Options{
Assets: assets,
},

View File

@@ -1 +1 @@
{"gamePath":"C:\\Games\\WoWRuski","addons":{"Channeler":{"name":"Channeler","url":"https://git.site.quack-lab.dev/dave/wow_channeler"},"Dechickenator":{"name":"Dechickenator","url":"https://git.site.quack-lab.dev/dave/wow_dechickenator"},"Heimdall":{"name":"Heimdall","url":"https://git.site.quack-lab.dev/dave/wow-Heimdall"}}}
{"gamePath":"C:\\Games\\WoWRuski","addons":{"Channeler":{"name":"Channeler","url":"https://git.site.quack-lab.dev/dave/wow_channeler"},"Dechickenator":{"name":"Dechickenator","url":"https://git.site.quack-lab.dev/dave/wow_dechickenator"},"Heimdall":{"name":"Heimdall","url":"https://git.site.quack-lab.dev/dave/wow-Heimdall"}},"locale":"en"}