refactor: Remove config, display, and i18n packages (#26)

Removes the following unused packages:
- pkg/config
- pkg/display
- pkg/i18n

Also removes the dependencies from pkg/runtime and cleans up the go.mod and go.sum files.

Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
This commit is contained in:
Snider 2025-11-13 16:45:48 +00:00 committed by GitHub
parent 623f05ffc1
commit 614aed51ba
26 changed files with 5 additions and 8125 deletions

5
go.mod
View file

@ -4,19 +4,17 @@ go 1.25
require (
github.com/ProtonMail/go-crypto v1.3.0
github.com/adrg/xdg v0.5.3
github.com/nicksnyder/go-i18n/v2 v2.6.0
github.com/pkg/sftp v1.13.10
github.com/skeema/knownhosts v1.3.2
github.com/stretchr/testify v1.11.1
github.com/wailsapp/wails/v3 v3.0.0-alpha.37
golang.org/x/crypto v0.43.0
golang.org/x/text v0.30.0
)
require (
dario.cat/mergo v1.0.2 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/adrg/xdg v0.5.3 // indirect
github.com/bep/debounce v1.2.1 // indirect
github.com/cloudflare/circl v1.6.1 // indirect
github.com/cyphar/filepath-securejoin v0.5.1 // indirect
@ -52,6 +50,7 @@ require (
github.com/xanzy/ssh-agent v0.3.3 // indirect
golang.org/x/net v0.46.0 // indirect
golang.org/x/sys v0.37.0 // indirect
golang.org/x/text v0.30.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect

4
go.sum
View file

@ -1,7 +1,5 @@
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
@ -78,8 +76,6 @@ github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHP
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/nicksnyder/go-i18n/v2 v2.6.0 h1:C/m2NNWNiTB6SK4Ao8df5EWm3JETSTIGNXBpMJTxzxQ=
github.com/nicksnyder/go-i18n/v2 v2.6.0/go.mod h1:88sRqr0C6OPyJn0/KRNaEz1uWorjxIKP7rUUcvycecE=
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
github.com/pjbgf/sha1cd v0.5.0 h1:a+UkboSi1znleCDUNT3M5YxjOnN1fz2FhN48FlwCxs0=

View file

@ -1,22 +0,0 @@
package config
import (
"github.com/Snider/Core/pkg/config/internal"
"github.com/Snider/Core/pkg/core"
)
// Options holds configuration for the config service.
type Options = internal.Options
// Service provides access to the application's configuration.
type Service = internal.Service
// New is the constructor for static dependency injection.
func New() (*Service, error) {
return internal.New()
}
// Register is the constructor for dynamic dependency injection.
func Register(c *core.Core) (any, error) {
return internal.Register(c)
}

View file

@ -1,206 +0,0 @@
package config
import (
"os"
"path/filepath"
"testing"
"github.com/Snider/Core/pkg/core"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
const appName = "lethean"
const configFileName = "config.json"
// setupTestEnv creates a temporary home directory for testing and ensures a clean environment.
func setupTestEnv(t *testing.T) (string, func()) {
tempHomeDir, err := os.MkdirTemp("", "test_home_*")
require.NoError(t, err, "Failed to create temp home directory")
oldHome := os.Getenv("HOME")
os.Setenv("HOME", tempHomeDir)
// Unset XDG vars to ensure HOME is used for path resolution, creating a hermetic test.
oldXdgData, hadXdgData := os.LookupEnv("XDG_DATA_HOME")
oldXdgCache, hadXdgCache := os.LookupEnv("XDG_CACHE_HOME")
require.NoError(t, os.Unsetenv("XDG_DATA_HOME"))
require.NoError(t, os.Unsetenv("XDG_CACHE_HOME"))
cleanup := func() {
os.Setenv("HOME", oldHome)
if hadXdgData {
os.Setenv("XDG_DATA_HOME", oldXdgData)
} else {
os.Unsetenv("XDG_DATA_HOME")
}
if hadXdgCache {
os.Setenv("XDG_CACHE_HOME", oldXdgCache)
} else {
os.Unsetenv("XDG_CACHE_HOME")
}
os.RemoveAll(tempHomeDir)
}
return tempHomeDir, cleanup
}
func TestConfigService(t *testing.T) {
t.Run("New service creates default config", func(t *testing.T) {
_, cleanup := setupTestEnv(t)
defer cleanup()
serviceInstance, err := New()
require.NoError(t, err, "New() failed")
// Check that the config file was created
assert.FileExists(t, serviceInstance.ConfigPath, "config.json was not created")
// Check default values
assert.Equal(t, "en", serviceInstance.Language, "Expected default language 'en'")
})
t.Run("New service loads existing config", func(t *testing.T) {
tempHomeDir, cleanup := setupTestEnv(t)
defer cleanup()
// Manually create a config file with non-default values
configDir := filepath.Join(tempHomeDir, appName, "config")
require.NoError(t, os.MkdirAll(configDir, os.ModePerm), "Failed to create test config dir")
configPath := filepath.Join(configDir, configFileName)
customConfig := `{"language": "fr", "features": ["beta-testing"]}`
require.NoError(t, os.WriteFile(configPath, []byte(customConfig), 0644), "Failed to write custom config file")
serviceInstance, err := New()
require.NoError(t, err, "New() failed while loading existing config")
assert.Equal(t, "fr", serviceInstance.Language, "Expected language 'fr'")
assert.True(t, serviceInstance.IsFeatureEnabled("beta-testing"), "Expected 'beta-testing' feature to be enabled")
assert.False(t, serviceInstance.IsFeatureEnabled("alpha-testing"), "Did not expect 'alpha-testing' to be enabled")
})
t.Run("Set and Get", func(t *testing.T) {
_, cleanup := setupTestEnv(t)
defer cleanup()
s, err := New()
require.NoError(t, err, "New() failed")
key := "language"
expectedValue := "de"
require.NoError(t, s.Set(key, expectedValue), "Set() failed")
var actualValue string
require.NoError(t, s.Get(key, &actualValue), "Get() failed")
assert.Equal(t, expectedValue, actualValue, "Get() returned unexpected value")
})
}
func TestIsFeatureEnabled(t *testing.T) {
_, cleanup := setupTestEnv(t)
defer cleanup()
s, err := New()
require.NoError(t, err)
// Test with no features enabled
assert.False(t, s.IsFeatureEnabled("beta-feature"))
// Enable a feature
err = s.Set("features", []string{"beta-feature", "alpha-testing"})
require.NoError(t, err)
// Test for an enabled feature
assert.True(t, s.IsFeatureEnabled("beta-feature"))
// Test for another enabled feature
assert.True(t, s.IsFeatureEnabled("alpha-testing"))
// Test for a disabled feature
assert.False(t, s.IsFeatureEnabled("gamma-feature"))
// Test with an empty string
assert.False(t, s.IsFeatureEnabled(""))
}
func TestSet_Good(t *testing.T) {
_, cleanup := setupTestEnv(t)
defer cleanup()
s, err := New()
require.NoError(t, err, "New() failed")
// Test setting a string value
err = s.Set("language", "de")
assert.NoError(t, err)
var lang string
err = s.Get("language", &lang)
assert.NoError(t, err)
assert.Equal(t, "de", lang)
// Test setting a slice value
err = s.Set("features", []string{"new-feature"})
assert.NoError(t, err)
var features []string
err = s.Get("features", &features)
assert.NoError(t, err)
assert.Equal(t, []string{"new-feature"}, features)
}
func TestSet_Bad(t *testing.T) {
_, cleanup := setupTestEnv(t)
defer cleanup()
s, err := New()
require.NoError(t, err, "New() failed")
// Test setting a value with the wrong type
err = s.Set("language", 123)
assert.Error(t, err)
// Test setting a non-existent key
err = s.Set("nonExistentKey", "value")
assert.Error(t, err)
}
func TestSet_Ugly(t *testing.T) {
_, cleanup := setupTestEnv(t)
defer cleanup()
s, err := New()
require.NoError(t, err, "New() failed")
// This should not panic
assert.NotPanics(t, func() {
err = s.Set("features", nil)
})
assert.NoError(t, err)
// Verify the slice is now nil
var features []string
err = s.Get("features", &features)
assert.NoError(t, err)
assert.Nil(t, features)
// Test with a nil slice
err = s.Set("features", nil)
require.NoError(t, err)
assert.False(t, s.IsFeatureEnabled("beta-feature"))
}
func TestRegister_Good(t *testing.T) {
_, cleanup := setupTestEnv(t)
defer cleanup()
c, err := core.New()
require.NoError(t, err)
svc, err := Register(c)
assert.NoError(t, err)
assert.NotNil(t, svc)
configSvc, ok := svc.(*Service)
assert.True(t, ok)
assert.NotNil(t, configSvc.Runtime)
}

View file

@ -1,184 +0,0 @@
package internal
import (
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// setupTestEnv creates a temporary home directory for testing and ensures a clean environment.
func setupTestEnv(t *testing.T) (string, func()) {
tempHomeDir, err := os.MkdirTemp("", "test_home_*")
require.NoError(t, err, "Failed to create temp home directory")
oldHome := os.Getenv("HOME")
os.Setenv("HOME", tempHomeDir)
// Unset XDG vars to ensure HOME is used for path resolution, creating a hermetic test.
oldXdgData, hadXdgData := os.LookupEnv("XDG_DATA_HOME")
oldXdgCache, hadXdgCache := os.LookupEnv("XDG_CACHE_HOME")
require.NoError(t, os.Unsetenv("XDG_DATA_HOME"))
require.NoError(t, os.Unsetenv("XDG_CACHE_HOME"))
cleanup := func() {
os.Setenv("HOME", oldHome)
if hadXdgData {
os.Setenv("XDG_DATA_HOME", oldXdgData)
} else {
os.Unsetenv("XDG_DATA_HOME")
}
if hadXdgCache {
os.Setenv("XDG_CACHE_HOME", oldXdgCache)
} else {
os.Unsetenv("XDG_CACHE_HOME")
}
os.RemoveAll(tempHomeDir)
}
return tempHomeDir, cleanup
}
func TestConfigService(t *testing.T) {
t.Run("New service creates default config", func(t *testing.T) {
_, cleanup := setupTestEnv(t)
defer cleanup()
serviceInstance, err := New()
require.NoError(t, err, "New() failed")
// Check that the config file was created
assert.FileExists(t, serviceInstance.ConfigPath, "config.json was not created")
// Check default values
assert.Equal(t, "en", serviceInstance.Language, "Expected default language 'en'")
})
t.Run("New service loads existing config", func(t *testing.T) {
tempHomeDir, cleanup := setupTestEnv(t)
defer cleanup()
// Manually create a config file with non-default values
configDir := filepath.Join(tempHomeDir, appName, "config")
require.NoError(t, os.MkdirAll(configDir, os.ModePerm), "Failed to create test config dir")
configPath := filepath.Join(configDir, configFileName)
customConfig := `{"language": "fr", "features": ["beta-testing"]}`
require.NoError(t, os.WriteFile(configPath, []byte(customConfig), 0644), "Failed to write custom config file")
serviceInstance, err := New()
require.NoError(t, err, "New() failed while loading existing config")
assert.Equal(t, "fr", serviceInstance.Language, "Expected language 'fr'")
assert.True(t, serviceInstance.IsFeatureEnabled("beta-testing"), "Expected 'beta-testing' feature to be enabled")
assert.False(t, serviceInstance.IsFeatureEnabled("alpha-testing"), "Did not expect 'alpha-testing' to be enabled")
})
t.Run("Set and Get", func(t *testing.T) {
_, cleanup := setupTestEnv(t)
defer cleanup()
s, err := New()
require.NoError(t, err, "New() failed")
key := "language"
expectedValue := "de"
require.NoError(t, s.Set(key, expectedValue), "Set() failed")
var actualValue string
require.NoError(t, s.Get(key, &actualValue), "Get() failed")
assert.Equal(t, expectedValue, actualValue, "Get() returned unexpected value")
})
}
func TestIsFeatureEnabled(t *testing.T) {
_, cleanup := setupTestEnv(t)
defer cleanup()
s, err := New()
require.NoError(t, err)
// Test with no features enabled
assert.False(t, s.IsFeatureEnabled("beta-feature"))
// Enable a feature
s.Features = []string{"beta-feature", "alpha-testing"}
// Test for an enabled feature
assert.True(t, s.IsFeatureEnabled("beta-feature"))
// Test for another enabled feature
assert.True(t, s.IsFeatureEnabled("alpha-testing"))
// Test for a disabled feature
assert.False(t, s.IsFeatureEnabled("gamma-feature"))
// Test with an empty string
assert.False(t, s.IsFeatureEnabled(""))
// Test with a nil slice
s.Features = nil
assert.False(t, s.IsFeatureEnabled("beta-feature"))
}
func TestSet_Good(t *testing.T) {
_, cleanup := setupTestEnv(t)
defer cleanup()
s, err := New()
require.NoError(t, err, "New() failed")
// Test setting a string value
err = s.Set("language", "de")
assert.NoError(t, err)
var lang string
err = s.Get("language", &lang)
assert.NoError(t, err)
assert.Equal(t, "de", lang)
// Test setting a slice value
err = s.Set("features", []string{"new-feature"})
assert.NoError(t, err)
var features []string
err = s.Get("features", &features)
assert.NoError(t, err)
assert.Equal(t, []string{"new-feature"}, features)
}
func TestSet_Bad(t *testing.T) {
_, cleanup := setupTestEnv(t)
defer cleanup()
s, err := New()
require.NoError(t, err, "New() failed")
// Test setting a value with the wrong type
err = s.Set("language", 123)
assert.Error(t, err)
// Test setting a non-existent key
err = s.Set("nonExistentKey", "value")
assert.Error(t, err)
}
func TestSet_Ugly(t *testing.T) {
_, cleanup := setupTestEnv(t)
defer cleanup()
s, err := New()
require.NoError(t, err, "New() failed")
// This should not panic
assert.NotPanics(t, func() {
err = s.Set("features", nil)
})
assert.NoError(t, err)
// Verify the slice is now nil
var features []string
err = s.Get("features", &features)
assert.NoError(t, err)
assert.Nil(t, features)
}

View file

@ -1,207 +0,0 @@
package internal
import (
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
"reflect"
"strings"
"github.com/Snider/Core/pkg/core"
"github.com/adrg/xdg"
)
const appName = "lethean"
const configFileName = "config.json"
// Options holds configuration for the config service.
type Options struct{}
// Service provides access to the application's configuration.
// It handles loading, saving, and providing access to configuration values.
type Service struct {
*core.Runtime[Options] `json:"-"`
// Persistent fields, saved to config.json.
ConfigPath string `json:"configPath,omitempty"`
UserHomeDir string `json:"userHomeDir,omitempty"`
RootDir string `json:"rootDir,omitempty"`
CacheDir string `json:"cacheDir,omitempty"`
ConfigDir string `json:"configDir,omitempty"`
DataDir string `json:"dataDir,omitempty"`
WorkspaceDir string `json:"workspaceDir,omitempty"`
DefaultRoute string `json:"default_route"`
Features []string `json:"features"`
Language string `json:"language"`
}
// createServiceInstance contains the common logic for initializing a Service struct.
func createServiceInstance() (*Service, error) {
// --- Path and Directory Setup ---
homeDir, err := os.UserHomeDir()
if err != nil {
return nil, fmt.Errorf("could not resolve user home directory: %w", err)
}
userHomeDir := filepath.Join(homeDir, appName)
rootDir, err := xdg.DataFile(appName)
if err != nil {
return nil, fmt.Errorf("could not resolve data directory: %w", err)
}
cacheDir, err := xdg.CacheFile(appName)
if err != nil {
return nil, fmt.Errorf("could not resolve cache directory: %w", err)
}
s := &Service{
UserHomeDir: userHomeDir,
RootDir: rootDir,
CacheDir: cacheDir,
ConfigDir: filepath.Join(userHomeDir, "config"),
DataDir: filepath.Join(userHomeDir, "data"),
WorkspaceDir: filepath.Join(userHomeDir, "workspace"),
DefaultRoute: "/",
Features: []string{},
Language: "en",
}
s.ConfigPath = filepath.Join(s.ConfigDir, configFileName)
dirs := []string{s.RootDir, s.ConfigDir, s.DataDir, s.CacheDir, s.WorkspaceDir, s.UserHomeDir}
for _, dir := range dirs {
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
return nil, fmt.Errorf("could not create directory %s: %w", dir, err)
}
}
// --- Load or Create Configuration ---
if data, err := os.ReadFile(s.ConfigPath); err == nil {
// Config file exists, load it.
if err := json.Unmarshal(data, s); err != nil {
return nil, fmt.Errorf("failed to unmarshal config: %w", err)
}
} else if os.IsNotExist(err) {
// Config file does not exist, create it with default values.
if err := s.Save(); err != nil {
return nil, fmt.Errorf("failed to create default config file: %w", err)
}
} else {
// Another error occurred reading the file.
return nil, fmt.Errorf("failed to read config file: %w", err)
}
return s, nil
}
// New is the constructor for static dependency injection.
// It creates a Service instance without initializing the core.Runtime field.
func New() (*Service, error) {
return createServiceInstance()
}
// Register is the constructor for dynamic dependency injection (used with core.WithService).
// It creates a Service instance and initializes its core.Runtime field.
func Register(c *core.Core) (any, error) {
s, err := createServiceInstance()
if err != nil {
return nil, err
}
// Defensive check: createServiceInstance should not return nil service with nil error
if s == nil {
return nil, errors.New("config: createServiceInstance returned a nil service instance with no error")
}
s.Runtime = core.NewRuntime(c, Options{})
return s, nil
}
// Save writes the current configuration to config.json.
func (s *Service) Save() error {
data, err := json.MarshalIndent(s, "", " ")
if err != nil {
return fmt.Errorf("failed to marshal config: %w", err)
}
if err := os.WriteFile(s.ConfigPath, data, 0644); err != nil {
return fmt.Errorf("failed to write config file: %w", err)
}
return nil
}
// Get retrieves a configuration value by its key.
func (s *Service) Get(key string, out any) error {
val := reflect.ValueOf(s).Elem()
typ := val.Type()
for i := 0; i < val.NumField(); i++ {
field := typ.Field(i)
jsonTag := field.Tag.Get("json")
if jsonTag != "" && jsonTag != "-" {
jsonName := strings.Split(jsonTag, ",")[0]
if strings.EqualFold(jsonName, key) {
outVal := reflect.ValueOf(out)
if outVal.Kind() != reflect.Ptr || outVal.IsNil() {
return errors.New("output argument must be a non-nil pointer")
}
targetVal := outVal.Elem()
srcVal := val.Field(i)
if !srcVal.Type().AssignableTo(targetVal.Type()) {
return fmt.Errorf("cannot assign config value of type %s to output of type %s", srcVal.Type(), targetVal.Type())
}
targetVal.Set(srcVal)
return nil
}
}
}
return fmt.Errorf("key '%s' not found in config", key)
}
// IsFeatureEnabled checks if a specific feature is enabled in the config.
func (s *Service) IsFeatureEnabled(feature string) bool {
for _, f := range s.Features {
if f == feature {
return true
}
}
return false
}
// Set updates a configuration value and saves the config.
func (s *Service) Set(key string, v any) error {
val := reflect.ValueOf(s).Elem()
typ := val.Type()
for i := 0; i < val.NumField(); i++ {
field := typ.Field(i)
jsonTag := field.Tag.Get("json")
if jsonTag != "" && jsonTag != "-" {
jsonName := strings.Split(jsonTag, ",")[0]
if strings.EqualFold(jsonName, key) {
fieldVal := val.Field(i)
if !fieldVal.CanSet() {
return fmt.Errorf("cannot set config field for key '%s'", key)
}
if v == nil {
switch fieldVal.Kind() {
case reflect.Pointer, reflect.Interface, reflect.Map, reflect.Slice, reflect.Func:
fieldVal.Set(reflect.Zero(fieldVal.Type()))
return s.Save()
default:
return fmt.Errorf("type mismatch for key '%s': expected %s, got nil", key, fieldVal.Type())
}
}
newVal := reflect.ValueOf(v)
if !newVal.Type().AssignableTo(fieldVal.Type()) {
return fmt.Errorf("type mismatch for key '%s': expected %s, got %s", key, fieldVal.Type(), newVal.Type())
}
fieldVal.Set(newVal)
return s.Save()
}
}
}
return fmt.Errorf("key '%s' not found in config", key)
}

View file

@ -1,8 +0,0 @@
package display
import "github.com/wailsapp/wails/v3/pkg/application"
// ActionOpenWindow is an IPC message used to request a new window.
type ActionOpenWindow struct {
application.WebviewWindowOptions
}

View file

@ -1,159 +0,0 @@
package display
import (
"context"
"fmt"
"github.com/Snider/Core/pkg/core"
"github.com/wailsapp/wails/v3/pkg/application"
"github.com/wailsapp/wails/v3/pkg/events"
)
// Options holds configuration for the display service.
type Options struct{}
// Service manages windowing, dialogs, and other visual elements.
type Service struct {
*core.Runtime[Options]
config core.Config
}
// newDisplayService contains the common logic for initializing a Service struct.
func newDisplayService() (*Service, error) {
return &Service{}, nil
}
// New is the constructor for static dependency injection.
// It creates a Service instance without initializing the core.Runtime field.
func New() (*Service, error) {
s, err := newDisplayService()
if err != nil {
return nil, err
}
return s, nil
}
// Register is the constructor for dynamic dependency injection (used with core.WithService).
// It creates a Service instance and initializes its core.Runtime field.
func Register(c *core.Core) (any, error) {
s, err := newDisplayService()
if err != nil {
return nil, err
}
s.Runtime = core.NewRuntime(c, Options{})
return s, nil
}
func (s *Service) ServiceName() string { return "github.com/Snider/Core/display" }
// HandleIPCEvents processes IPC messages and performs actions such as opening windows or initializing services based on message types.
func (s *Service) HandleIPCEvents(c *core.Core, msg core.Message) error {
switch m := msg.(type) {
case map[string]any:
if action, ok := m["action"].(string); ok && action == "display.open_window" {
return s.handleOpenWindowAction(m)
}
case ActionOpenWindow:
_, err := s.NewWithStruct(&m.WebviewWindowOptions)
return err
case core.ActionServiceStartup:
return s.ServiceStartup(context.Background(), application.ServiceOptions{})
default:
c.App.Logger.Error("Display: Unknown message type", "type", fmt.Sprintf("%T", m))
}
return nil
}
// handleOpenWindowAction processes a message to configure and create a new window using specified name and options.
func (s *Service) handleOpenWindowAction(msg map[string]any) error {
opts := application.WebviewWindowOptions{}
if name, ok := msg["name"].(string); ok {
opts.Name = name
}
if optsMap, ok := msg["options"].(map[string]any); ok {
if title, ok := optsMap["Title"].(string); ok {
opts.Title = title
}
if width, ok := optsMap["Width"].(float64); ok {
opts.Width = int(width)
}
if height, ok := optsMap["Height"].(float64); ok {
opts.Height = int(height)
}
}
s.Core().App.Window.NewWithOptions(opts)
return nil
}
// ShowEnvironmentDialog displays a dialog containing detailed information about the application's runtime environment.
func (s *Service) ShowEnvironmentDialog() {
envInfo := s.Core().App.Env.Info()
details := fmt.Sprintf(`Environment Information:\n\nOperating System: %s\nArchitecture: %s\nDebug Mode: %t\n\nDark Mode: %t\n\nPlatform Information:`,
envInfo.OS,
envInfo.Arch,
envInfo.Debug,
s.Core().App.Env.IsDarkMode()) // Use d.core.App
// Add platform-specific details
for key, value := range envInfo.PlatformInfo {
details += fmt.Sprintf("\n%s: %v", key, value)
}
if envInfo.OSInfo != nil {
details += fmt.Sprintf("\n\nOS Details:\nName: %s\nVersion: %s",
envInfo.OSInfo.Name,
envInfo.OSInfo.Version)
}
dialog := s.Core().App.Dialog.Info()
dialog.SetTitle("Environment Information")
dialog.SetMessage(details)
dialog.Show()
}
// ServiceStartup initializes the display service and sets up the main application window and system tray.
func (s *Service) ServiceStartup(context.Context, application.ServiceOptions) error {
s.Core().App.Logger.Info("Display service started")
s.buildMenu()
s.systemTray()
// This will be updated to use the restored OpenWindow method
return s.OpenWindow()
}
// OpenWindow creates a new window with the default options.
func (s *Service) OpenWindow(opts ...core.WindowOption) error {
// Default options
winOpts := &core.WindowConfig{
Name: "main",
Title: "Core",
Width: 1280,
Height: 800,
URL: "/",
}
// Apply options
for _, opt := range opts {
opt.Apply(winOpts)
}
// Create Wails window options
wailsOpts := application.WebviewWindowOptions{
Name: winOpts.Name,
Title: winOpts.Title,
Width: winOpts.Width,
Height: winOpts.Height,
URL: winOpts.URL,
}
s.Core().App.Window.NewWithOptions(wailsOpts)
return nil
}
// monitorScreenChanges listens for theme change events and logs when screen configuration changes occur.
func (s *Service) monitorScreenChanges() {
s.Core().App.Event.OnApplicationEvent(events.Common.ThemeChanged, func(event *application.ApplicationEvent) {
s.Core().App.Logger.Info("Screen configuration changed")
})
}

View file

@ -1,44 +0,0 @@
package display
import (
"testing"
"github.com/Snider/Core/pkg/core"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// newTestCore creates a new core instance with essential services for testing.
func newTestCore(t *testing.T) *core.Core {
// We need a real wails app for the display service to function.
// This setup will be more complex than for other services.
// For now, we can use a simplified core instance.
coreInstance, err := core.New()
require.NoError(t, err)
return coreInstance
}
func TestNew(t *testing.T) {
service, err := New()
assert.NoError(t, err)
assert.NotNil(t, service, "New() should return a non-nil service instance")
}
func TestRegister(t *testing.T) {
coreInstance := newTestCore(t)
service, err := Register(coreInstance)
require.NoError(t, err)
assert.NotNil(t, service, "Register() should return a non-nil service instance")
}
func TestOpenWindow(t *testing.T) {
// This test is complex to set up properly without a running Wails application.
// A true functional test would require a more elaborate test harness that
// can initialize the Wails runtime.
// For now, we can perform a basic smoke test.
t.Run("basic window open smoke test", func(t *testing.T) {
// Skipping this test for now as it requires a running app instance.
t.Skip("Skipping OpenWindow test as it requires a running Wails application instance.")
})
}

View file

@ -1,32 +0,0 @@
package display
import (
"runtime"
"github.com/wailsapp/wails/v3/pkg/application"
)
// buildMenu creates and sets the main application menu.
func (s *Service) buildMenu() {
appMenu := s.Core().App.Menu.New()
if runtime.GOOS == "darwin" {
appMenu.AddRole(application.AppMenu)
}
appMenu.AddRole(application.FileMenu)
appMenu.AddRole(application.ViewMenu)
appMenu.AddRole(application.EditMenu)
workspace := appMenu.AddSubmenu("Workspace")
workspace.Add("New").OnClick(func(ctx *application.Context) { /* TODO */ })
workspace.Add("List").OnClick(func(ctx *application.Context) { /* TODO */ })
// Add brand-specific menu items
//if s.brand == DeveloperHub {
// appMenu.AddSubmenu("Developer")
//}
appMenu.AddRole(application.WindowMenu)
appMenu.AddRole(application.HelpMenu)
s.Core().App.Menu.Set(appMenu)
}

View file

@ -1,72 +0,0 @@
package display
import (
_ "embed"
"github.com/wailsapp/wails/v3/pkg/application"
)
// setupTray configures and creates the system tray icon and menu.
func (s *Service) systemTray() {
systray := s.Core().App.SystemTray.New()
systray.SetTooltip("Core")
systray.SetLabel("Core")
//appTrayIcon, _ := d.assets.ReadFile("assets/apptray.png")
//
//if runtime.GOOS == "darwin" {
// systray.SetTemplateIcon(appTrayIcon)
//} else {
// // Support for light/dark mode icons
// systray.SetDarkModeIcon(appTrayIcon)
// systray.SetIcon(appTrayIcon)
//}
// Create a hidden window for the system tray menu to interact with
trayWindow, _ := s.NewWithStruct(&Window{
Name: "system-tray",
Title: "System Tray Status",
URL: "system-tray.html",
Width: 400,
Frameless: true,
Hidden: true,
})
systray.AttachWindow(trayWindow).WindowOffset(5)
// --- Build Tray Menu ---
trayMenu := s.Core().App.Menu.New()
trayMenu.Add("Open Desktop").OnClick(func(ctx *application.Context) {
for _, window := range s.Core().App.Window.GetAll() {
window.Show()
}
})
trayMenu.Add("Close Desktop").OnClick(func(ctx *application.Context) {
for _, window := range s.Core().App.Window.GetAll() {
window.Hide()
}
})
trayMenu.Add("Environment Info").OnClick(func(ctx *application.Context) {
s.ShowEnvironmentDialog()
})
// Add brand-specific menu items
//switch d.brand {
//case AdminHub:
// trayMenu.Add("Manage Workspace").OnClick(func(ctx *application.Context) { /* TODO */ })
//case ServerHub:
// trayMenu.Add("Server Control").OnClick(func(ctx *application.Context) { /* TODO */ })
//case GatewayHub:
// trayMenu.Add("Routing Table").OnClick(func(ctx *application.Context) { /* TODO */ })
//case DeveloperHub:
// trayMenu.Add("Debug Console").OnClick(func(ctx *application.Context) { /* TODO */ })
//case ClientHub:
// trayMenu.Add("Connect").OnClick(func(ctx *application.Context) { /* TODO */ })
// trayMenu.Add("Disconnect").OnClick(func(ctx *application.Context) { /* TODO */ })
//}
trayMenu.AddSeparator()
trayMenu.Add("Quit").OnClick(func(ctx *application.Context) {
s.Core().App.Quit()
})
systray.SetMenu(trayMenu)
}

View file

@ -1,93 +0,0 @@
package display
import (
"github.com/wailsapp/wails/v3/pkg/application"
)
type WindowOption func(*application.WebviewWindowOptions) error
type Window = application.WebviewWindowOptions
func WindowName(s string) WindowOption {
return func(o *Window) error {
o.Name = s
return nil
}
}
func WindowTitle(s string) WindowOption {
return func(o *Window) error {
o.Title = s
return nil
}
}
func WindowURL(s string) WindowOption {
return func(o *Window) error {
o.URL = s
return nil
}
}
func WindowWidth(i int) WindowOption {
return func(o *Window) error {
o.Width = i
return nil
}
}
func WindowHeight(i int) WindowOption {
return func(o *Window) error {
o.Height = i
return nil
}
}
func applyOptions(opts ...WindowOption) *Window {
w := &Window{}
if opts == nil {
return w
}
for _, o := range opts {
if err := o(w); err != nil {
return nil
}
}
return w
}
// NewWithStruct creates a new window using the provided options and returns its handle.
func (s *Service) NewWithStruct(options *Window) (*application.WebviewWindow, error) {
return s.Core().App.Window.NewWithOptions(*options), nil
}
// NewWithOptions creates a new window by applying a series of options.
func (s *Service) NewWithOptions(opts ...WindowOption) (*application.WebviewWindow, error) {
return s.NewWithStruct(applyOptions(opts...))
}
// NewWithURL creates a new default window pointing to the specified URL.
func (s *Service) NewWithURL(url string) (*application.WebviewWindow, error) {
return s.NewWithOptions(
WindowURL(url),
WindowTitle("Core"),
WindowHeight(900),
WindowWidth(1280),
)
}
//// OpenWindow is a convenience method that creates and shows a window from a set of options.
//func (s *Service) OpenWindow(opts ...WindowOption) error {
// _, err := s.NewWithOptions(opts...)
// return err
//}
// SelectDirectory opens a directory selection dialog and returns the selected path.
func (s *Service) SelectDirectory() (string, error) {
dialog := application.OpenFileDialog()
dialog.SetTitle("Select Project Directory")
return dialog.PromptForSingleSelection()
}
var instance *Window
func (s *Service) Window() *Window { return instance }

File diff suppressed because it is too large Load diff

View file

@ -1,187 +0,0 @@
package i18n
import (
"context"
"embed"
"encoding/json"
"fmt"
"os"
"strings"
"github.com/Snider/Core/pkg/core"
"github.com/nicksnyder/go-i18n/v2/i18n"
"github.com/wailsapp/wails/v3/pkg/application"
"golang.org/x/text/language"
)
//go:embed locales/*.json
var localeFS embed.FS
// Options holds configuration for the i18n service.
type Options struct{}
// Service provides internationalization and localization.
type Service struct {
*core.Runtime[Options]
bundle *i18n.Bundle
localizer *i18n.Localizer
availableLangs []language.Tag
}
// newI18nService contains the common logic for initializing a Service struct.
func newI18nService() (*Service, error) {
bundle := i18n.NewBundle(language.English)
bundle.RegisterUnmarshalFunc("json", json.Unmarshal)
availableLangs, err := getAvailableLanguages()
if err != nil {
return nil, err
}
for _, lang := range availableLangs {
filePath := fmt.Sprintf("locales/%s.json", lang.String())
if _, err := bundle.LoadMessageFileFS(localeFS, filePath); err != nil {
return nil, fmt.Errorf("failed to load message file %s: %w", filePath, err)
}
}
s := &Service{
bundle: bundle,
availableLangs: availableLangs,
}
// Language will be set during ServiceStartup after config is available.
return s, nil
}
// New is the constructor for static dependency injection.
// It creates a Service instance without initializing the core.Runtime field.
// Dependencies are passed directly here.
func New() (*Service, error) {
s, err := newI18nService()
if err != nil {
return nil, err
}
return s, nil
}
// Register is the constructor for dynamic dependency injection (used with core.WithService).
// It creates a Service instance and initializes its core.Runtime field.
// Dependencies are injected during ServiceStartup.
func Register(c *core.Core) (any, error) {
s, err := newI18nService()
if err != nil {
return nil, err
}
s.Runtime = core.NewRuntime(c, Options{})
return s, nil
}
// HandleIPCEvents processes IPC messages, including injecting dependencies on startup.
func (s *Service) HandleIPCEvents(c *core.Core, msg core.Message) error {
switch m := msg.(type) {
case core.ActionServiceStartup:
return s.ServiceStartup(context.Background(), application.ServiceOptions{})
default:
c.App.Logger.Error("Display: Unknown message type", "type", fmt.Sprintf("%T", m))
}
return nil
}
// ServiceStartup is called when the app starts, after dependencies are injected.
func (s *Service) ServiceStartup(context.Context, application.ServiceOptions) error {
// Determine initial language after config is available.
initialLang := "en"
var lang string
_ = s.Config().Get("language", &lang)
if lang != "" {
initialLang = lang
}
err := s.SetLanguage(initialLang)
if err != nil {
return err
}
s.Core().App.Logger.Info("I18n service started")
return nil
}
// --- Language Management ---
func getAvailableLanguages() ([]language.Tag, error) {
files, err := localeFS.ReadDir("locales")
if err != nil {
return nil, fmt.Errorf("failed to read embedded locales directory: %w", err)
}
var availableLangs []language.Tag
for _, file := range files {
lang := strings.TrimSuffix(file.Name(), ".json")
tag := language.Make(lang)
availableLangs = append(availableLangs, tag)
}
return availableLangs, nil
}
func detectLanguage(supported []language.Tag) (string, error) {
langEnv := os.Getenv("LANG")
if langEnv == "" {
return "", nil
}
baseLang := strings.Split(langEnv, ".")[0]
parsedLang, err := language.Parse(baseLang)
if err != nil {
return "", fmt.Errorf("failed to parse language tag '%s': %w", baseLang, err)
}
if len(supported) == 0 {
return "", nil
}
matcher := language.NewMatcher(supported)
_, index, confidence := matcher.Match(parsedLang)
if confidence >= language.Low {
return supported[index].String(), nil
}
return "", nil
}
// --- Public Service Methods ---
func (s *Service) SetLanguage(lang string) error {
requestedLang, err := language.Parse(lang)
if err != nil {
return fmt.Errorf("i18n: failed to parse language tag \"%s\": %w", lang, err)
}
if len(s.availableLangs) == 0 {
return fmt.Errorf("i18n: no available languages loaded in the bundle")
}
matcher := language.NewMatcher(s.availableLangs)
bestMatch, _, confidence := matcher.Match(requestedLang)
if confidence == language.No {
return fmt.Errorf("i18n: unsupported language: %s", lang)
}
s.localizer = i18n.NewLocalizer(s.bundle, bestMatch.String())
return nil
}
func (s *Service) Translate(messageID string) string {
translation, err := s.localizer.Localize(&i18n.LocalizeConfig{MessageID: messageID})
if err != nil {
fmt.Fprintf(os.Stderr, "i18n: translation for key \"%s\" not found\n", messageID)
return messageID
}
return translation
}
// Ensure Service implements the core.I18n interface.
var _ core.I18n = (*Service)(nil)
// SetBundle is a test helper to inject a bundle.
func (s *Service) SetBundle(bundle *i18n.Bundle) {
s.bundle = bundle
}

View file

@ -1,69 +0,0 @@
package i18n
import (
"encoding/json"
"testing"
"github.com/Snider/Core/pkg/core"
"github.com/nicksnyder/go-i18n/v2/i18n"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/text/language"
)
func newTestBundle() *i18n.Bundle {
bundle := i18n.NewBundle(language.English)
bundle.RegisterUnmarshalFunc("json", json.Unmarshal)
bundle.MustParseMessageFileBytes([]byte(`{
"hello": "Hello"
}`), "en.json")
bundle.MustParseMessageFileBytes([]byte(`{
"hello": "Bonjour"
}`), "fr.json")
return bundle
}
func TestNew(t *testing.T) {
s, err := New()
assert.NoError(t, err)
assert.NotNil(t, s)
}
func TestRegister(t *testing.T) {
c, err := core.New()
require.NoError(t, err)
s, err := Register(c)
assert.NoError(t, err)
assert.NotNil(t, s)
}
func TestSetLanguage(t *testing.T) {
s, err := New()
require.NoError(t, err)
s.SetBundle(newTestBundle())
err = s.SetLanguage("en")
assert.NoError(t, err)
err = s.SetLanguage("fr")
assert.NoError(t, err)
err = s.SetLanguage("invalid")
assert.Error(t, err)
}
func TestTranslate(t *testing.T) {
s, err := New()
require.NoError(t, err)
s.SetBundle(newTestBundle())
err = s.SetLanguage("en")
require.NoError(t, err)
assert.Equal(t, "Hello", s.Translate("hello"))
err = s.SetLanguage("fr")
require.NoError(t, err)
assert.Equal(t, "Bonjour", s.Translate("hello"))
}

View file

@ -1,157 +0,0 @@
{
"app.boot.download-check": "Nach Updates suchen",
"app.boot.folder-check": "Setup-Check",
"app.boot.loaded-runtime": "Anwendung geladen",
"app.boot.server-check": "Überprüfung des Servers",
"app.boot.start-runtime": "Desktop starten",
"app.core.ui.search": "Suchen",
"app.lthn.chain.daemons.lethean-blockchain-export": "Blockchain-Export",
"app.lthn.chain.daemons.lethean-blockchain-import": "Blockchain-Import",
"app.lthn.chain.daemons.lethean-wallet-cli": "Brieftasche CLI",
"app.lthn.chain.daemons.lethean-wallet-rpc": "Wallet-RPC",
"app.lthn.chain.daemons.lethean-wallet-vpn-rpc": "Exit-Knoten-Wallet",
"app.lthn.chain.daemons.letheand": "Blockchain-Dienst",
"app.lthn.chain.desc.no_transactions": "In diesem Block waren keine Transaktionen enthalten",
"app.lthn.chain.description": "Lethean (LTHN) Blockchain-Statistiken",
"app.lthn.chain.heading": "Lethean Blockchain-Statistiken",
"app.lthn.chain.menu.blocks": "Blöcke",
"app.lthn.chain.menu.configuration": "Aufbau",
"app.lthn.chain.menu.raw_data": "Rohblockdaten",
"app.lthn.chain.menu.stats": "Statistiken",
"app.lthn.chain.table.age": "Alter",
"app.lthn.chain.table.depth": "Tiefe",
"app.lthn.chain.table.difficulty": "Schwierigkeit",
"app.lthn.chain.table.height": "Höhe",
"app.lthn.chain.table.reward": "BELOHNUNG",
"app.lthn.chain.table.time": "Zeit",
"app.lthn.chain.table.title.chain-status": "Blockchain-Status",
"app.lthn.chain.table.title.recent-blocks": "Kürzlich erstellte Blöcke",
"app.lthn.chain.title": "Blockchain Explorer",
"app.lthn.chain.words.alt_blocks_count": "Alt-Blöcke",
"app.lthn.chain.words.block_size": "Block Größe",
"app.lthn.chain.words.block_size_limit": "Begrenzung der Blockgröße",
"app.lthn.chain.words.chain_stat": "Kettenstatistik",
"app.lthn.chain.words.chain_stat_value": "Knoten gemeldeter Wert",
"app.lthn.chain.words.cumulative_difficulty": "Kumulative Schwierigkeit",
"app.lthn.chain.words.depth": "Tiefe vom oberen Block",
"app.lthn.chain.words.difficulty": "Schwierigkeit",
"app.lthn.chain.words.grey_peerlist_size": "P2P graue Kollegen",
"app.lthn.chain.words.hash": "Hash",
"app.lthn.chain.words.height": "Höhe",
"app.lthn.chain.words.incoming_connections_count": "P2P-Eingang",
"app.lthn.chain.words.install-blockchain": "Blockchain installieren",
"app.lthn.chain.words.last_block_time": "Synchronisiert mit Block:",
"app.lthn.chain.words.loading-data": "Laden von Blockchain-Daten",
"app.lthn.chain.words.major_version": "Hauptversion",
"app.lthn.chain.words.miner_transaction": "Miner-Transaktion",
"app.lthn.chain.words.miner_tx": "POW Miner-Transaktion",
"app.lthn.chain.words.minor_version": "Nebenversion",
"app.lthn.chain.words.nonce": "Lösung blockieren",
"app.lthn.chain.words.orphan_status": "Gültiger Block",
"app.lthn.chain.words.outgoing_connections_count": "P2P-Ausgang",
"app.lthn.chain.words.reward": "BELOHNUNG",
"app.lthn.chain.words.start_time": "Startzeit",
"app.lthn.chain.words.status": "Status",
"app.lthn.chain.words.target": "Ziel",
"app.lthn.chain.words.target_height": "Zielhöhe",
"app.lthn.chain.words.testnet": "Testnetz",
"app.lthn.chain.words.timestamp": "Zeitstempel",
"app.lthn.chain.words.top_height": "NEUESTER BLOCK",
"app.lthn.chain.words.tx_count": "Transaktionen insgesamt",
"app.lthn.chain.words.tx_pool_size": "ausstehende Transaktionen",
"app.lthn.chain.words.unlock_time": "Block entsperren",
"app.lthn.chain.words.valid": "Gültiger Block",
"app.lthn.chain.words.version": "Version der Blockstruktur",
"app.lthn.chain.words.white_peerlist_size": "P2P-Whitelist",
"app.lthn.console.title": "Konsole",
"app.lthn.wallet.button.create-wallet": "Brieftasche erstellen",
"app.lthn.wallet.button.restore-wallet": "Brieftasche wiederherstellen",
"app.lthn.wallet.button.unlock-wallet": "Freischalten",
"app.lthn.wallet.label.address": "Adresse",
"app.lthn.wallet.label.autosave": "Offene Brieftasche speichern",
"app.lthn.wallet.label.filename": "Dateiname",
"app.lthn.wallet.label.restore-height": "Höhe wiederherstellen",
"app.lthn.wallet.label.spend-key": "Schlüssel ausgeben",
"app.lthn.wallet.label.view-key": "Ansichtsschlüssel",
"app.lthn.wallet.label.wallet-password": "Brieftaschen-Passwort",
"app.lthn.wallet.label.wallet-password-confirm": "Passwort bestätigen",
"app.lthn.wallet.titles.new-wallet": "Neue Brieftasche erstellen",
"app.lthn.wallet.titles.restore-keys": "Von Schlüsseln wiederherstellen",
"app.lthn.wallet.titles.restore-seed": "Wiederherstellung aus Samen",
"app.lthn.wallet.titles.unlock-wallet": "Brieftasche entsperren",
"app.lthn.wallet.titles.wallet-transactions": "Wallet-Transaktionen",
"app.market.apps": "App-Marktplatz",
"app.market.dashboard": "Instrumententafel",
"app.market.installed": "Installierte Apps",
"app.market.no-apps-installed": "Sie haben keine Apps installiert.",
"app.market.view-installable-apps": "Installierbare Apps anzeigen",
"app.title": "Lethean Desktop",
"charts.network-hashrate.subtitle": "Daten bereitgestellt von",
"charts.network-hashrate.title": "Netzwerk-Hash-Rate",
"lang.de": "Deutsche",
"lang.en": "Englisch",
"lang.es": "Spanisch",
"lang.fr": "Französisch",
"lang.ru": "Russisch",
"lang.uk": "Ukrainisch (Ukraine)",
"lang.zh": "Chinesisch",
"menu.about": "Über",
"menu.activity": "Aktivität",
"menu.api": "api",
"menu.blockchain": "Blockchain",
"menu.build": "Bauen",
"menu.dashboard": "Instrumententafel",
"menu.docs": "Dokumentation",
"menu.documentation": "Dokumentation",
"menu.explorer": "Forscher",
"menu.help": "Hilfe",
"menu.hub-admin": "Administrator",
"menu.hub-client": "Klient",
"menu.hub-developer": "Entwickler",
"menu.hub-gateway": "TOR",
"menu.hub-server": "Server-Hub",
"menu.info": "info",
"menu.logout": "Abmelden",
"menu.mining": "Bergbau",
"menu.settings": "die Einstellungen",
"menu.vpn": "VPN",
"menu.wallet": "Brieftasche",
"menu.your-profile": "Dein Profil ",
"view.dashboard.description": "Lethean (LTHN) Web-App",
"view.dashboard.heading": "Lethean-Dashboard",
"view.dashboard.title": "Lethean (LTHN)",
"view.wallets.description": "Krypto-Wallet-Manager",
"view.wallets.heading": "Wallet-Manager",
"view.wallets.title": "Geldbörsen",
"words.actions.add": "Hinzufügen",
"words.actions.clone": "Klon",
"words.actions.edit": "Bearbeiten",
"words.actions.install": "Installieren",
"words.actions.new": "Neu",
"words.actions.remove": "Löschen",
"words.actions.report": "Bericht",
"words.actions.save": "sparen",
"words.states.installing": "Installieren",
"words.states.installing_desc": "Wir laden die ausführbaren Blockchain-Dateien von GitHub in Ihr Lethean-Benutzerverzeichnis herunter.",
"words.states.loading": "Wird geladen",
"words.states.not_installed": "Nicht installiert",
"words.states.not_installed_desc": "Klicken Sie auf Blockchain installieren, um die neueste Lethean Blockchain CLI . herunterzuladen",
"words.things.button": "Taste",
"words.things.documentation": "Dokumentation",
"words.things.menu": "Speisekarte",
"words.things.mining-pool": "Bergbaupool",
"words.things.page": "Seite",
"words.things.problem": "Problem",
"words.things.type": "Art",
"words.time.past.day": "vor einem Tag",
"words.time.past.days": "Vor Tagen",
"words.time.past.hour": "vor einer Stunde",
"words.time.past.hours": "Vor Stunden",
"words.time.past.minute": "vor einer Minute",
"words.time.past.minutes": "Vor ein paar Minuten",
"words.time.past.month": "vor einem Monat",
"words.time.past.months": " vor wenigen Monaten",
"words.time.past.seconds": "vor ein paar Sekunden",
"words.time.past.year": "vor einem Jahr",
"words.time.past.years": "vor Jahren"
}

View file

@ -1,157 +0,0 @@
{
"app.boot.download-check": "Checking for Updates",
"app.boot.folder-check": "Setup Check",
"app.boot.loaded-runtime": "Application Loaded",
"app.boot.server-check": "Checking Server",
"app.boot.start-runtime": "Starting Desktop",
"app.core.ui.search": "Search",
"app.lthn.chain.daemons.lethean-blockchain-export": "Blockchain Export",
"app.lthn.chain.daemons.lethean-blockchain-import": "Blockchain Import",
"app.lthn.chain.daemons.lethean-wallet-cli": "Wallet CLI",
"app.lthn.chain.daemons.lethean-wallet-rpc": "Wallet RPC",
"app.lthn.chain.daemons.lethean-wallet-vpn-rpc": "Exit Node Wallet",
"app.lthn.chain.daemons.letheand": "Blockchain Service",
"app.lthn.chain.desc.no_transactions": "There were no transactions included in this block",
"app.lthn.chain.description": "Lethean (LTHN) Blockchain Stats",
"app.lthn.chain.heading": "Lethean Blockchain Stats",
"app.lthn.chain.menu.blocks": "Blocks",
"app.lthn.chain.menu.configuration": "Configuration",
"app.lthn.chain.menu.raw_data": "Raw Block Data",
"app.lthn.chain.menu.stats": "Stats",
"app.lthn.chain.table.age": "Age",
"app.lthn.chain.table.depth": "Depth",
"app.lthn.chain.table.difficulty": "Difficulty",
"app.lthn.chain.table.height": "Height",
"app.lthn.chain.table.reward": "Reward",
"app.lthn.chain.table.time": "Time",
"app.lthn.chain.table.title.chain-status": "Blockchain Status",
"app.lthn.chain.table.title.recent-blocks": "Recently Created Blocks",
"app.lthn.chain.title": "Blockchain Explorer",
"app.lthn.chain.words.alt_blocks_count": "Alt Blocks",
"app.lthn.chain.words.block_size": "Block Size",
"app.lthn.chain.words.block_size_limit": "Block Size Limit",
"app.lthn.chain.words.chain_stat": "Chain Stats",
"app.lthn.chain.words.chain_stat_value": "Node Reported Value",
"app.lthn.chain.words.cumulative_difficulty": "Cumulative Difficulty",
"app.lthn.chain.words.depth": "Depth from Top Block",
"app.lthn.chain.words.difficulty": "Difficulty",
"app.lthn.chain.words.grey_peerlist_size": "P2P Grey Peers",
"app.lthn.chain.words.hash": "Hash",
"app.lthn.chain.words.height": "Height",
"app.lthn.chain.words.incoming_connections_count": "P2P Incoming",
"app.lthn.chain.words.install-blockchain": "Install Blockchain",
"app.lthn.chain.words.last_block_time": "Synchronised to Block:",
"app.lthn.chain.words.loading-data": "Loading Blockchain Data",
"app.lthn.chain.words.major_version": "Major Version",
"app.lthn.chain.words.miner_transaction": "Miner Transaction",
"app.lthn.chain.words.miner_tx": "POW Miner Transaction",
"app.lthn.chain.words.minor_version": "Minor Version",
"app.lthn.chain.words.nonce": "Block Solution",
"app.lthn.chain.words.orphan_status": "Valid Block",
"app.lthn.chain.words.outgoing_connections_count": "P2P Out",
"app.lthn.chain.words.reward": "Reward",
"app.lthn.chain.words.start_time": "Start Time",
"app.lthn.chain.words.status": "Status",
"app.lthn.chain.words.target": "Target",
"app.lthn.chain.words.target_height": "Target Height",
"app.lthn.chain.words.testnet": "Testnet",
"app.lthn.chain.words.timestamp": "Timestamp",
"app.lthn.chain.words.top_height": "Newest Block",
"app.lthn.chain.words.tx_count": "Total Transactions",
"app.lthn.chain.words.tx_pool_size": "Pending Transactions",
"app.lthn.chain.words.unlock_time": "Unlock Block",
"app.lthn.chain.words.valid": "Valid Block",
"app.lthn.chain.words.version": "Block Structure Version",
"app.lthn.chain.words.white_peerlist_size": "P2P Whitelist",
"app.lthn.console.title": "Console",
"app.lthn.wallet.button.create-wallet": "Create Wallet",
"app.lthn.wallet.button.restore-wallet": "Restore Wallet",
"app.lthn.wallet.button.unlock-wallet": "Unlock",
"app.lthn.wallet.label.address": "Address",
"app.lthn.wallet.label.autosave": "Save Open Wallet",
"app.lthn.wallet.label.filename": "Filename",
"app.lthn.wallet.label.restore-height": "Restore Height",
"app.lthn.wallet.label.spend-key": "Spend Key",
"app.lthn.wallet.label.view-key": "View Key",
"app.lthn.wallet.label.wallet-password": "Wallet Password",
"app.lthn.wallet.label.wallet-password-confirm": "Confirm Password",
"app.lthn.wallet.titles.new-wallet": "Make New Wallet",
"app.lthn.wallet.titles.restore-keys": "Restore From Keys",
"app.lthn.wallet.titles.restore-seed": "Restore From Seed",
"app.lthn.wallet.titles.unlock-wallet": "Unlock Wallet",
"app.lthn.wallet.titles.wallet-transactions": "Wallet Transactions",
"app.market.apps": "App Marketplace",
"app.market.dashboard": "Dashboard",
"app.market.installed": "Installed Apps",
"app.market.no-apps-installed": "You have no apps installed.",
"app.market.view-installable-apps": "View Installable Apps",
"app.title": "Lethean Desktop",
"charts.network-hashrate.subtitle": "Data Provided by",
"charts.network-hashrate.title": "Network Hash Rate",
"lang.de": "German",
"lang.en": "English",
"lang.es": "Spanish",
"lang.fr": "French",
"lang.ru": "Russian",
"lang.uk": "Ukrainian (Ukraine)",
"lang.zh": "Chinese",
"menu.about": "About",
"menu.activity": "Activity",
"menu.api": "api",
"menu.blockchain": "Blockchain",
"menu.build": "Build",
"menu.dashboard": "Dashboard",
"menu.docs": "Documentation",
"menu.documentation": "Documentation",
"menu.explorer": "Explorer",
"menu.help": "Help",
"menu.hub-admin": "Admin Hub",
"menu.hub-client": "Client Hub",
"menu.hub-developer": "Developer",
"menu.hub-gateway": "Gateway",
"menu.hub-server": "Server Hub",
"menu.info": "info",
"menu.logout": "Sign Out",
"menu.mining": "Mining",
"menu.settings": "Settings",
"menu.vpn": "VPN",
"menu.wallet": "Wallet",
"menu.your-profile": "Your Profile",
"view.dashboard.description": "Lethean (LTHN) Web app",
"view.dashboard.heading": "Lethean Dashboard",
"view.dashboard.title": "Lethean (LTHN)",
"view.wallets.description": "Crypto Wallet Manager",
"view.wallets.heading": "Wallet Manager",
"view.wallets.title": "Wallets",
"words.actions.add": "Add",
"words.actions.clone": "Clone",
"words.actions.edit": "Edit",
"words.actions.install": "Install",
"words.actions.new": "New",
"words.actions.remove": "Remove",
"words.actions.report": "Report",
"words.actions.save": "Save",
"words.states.installing": "Installing",
"words.states.installing_desc": "We are downloading the blockchain executables from GitHub to your Lethean user directory.",
"words.states.loading": "Loading",
"words.states.not_installed": "Not Installed",
"words.states.not_installed_desc": "Click Install Blockchain to download the latest Lethean Blockchain CLI",
"words.things.button": "Button",
"words.things.documentation": "Documentation",
"words.things.menu": "Menu",
"words.things.mining-pool": "Mining Pool",
"words.things.page": "Page",
"words.things.problem": "Problem",
"words.things.type": "Type",
"words.time.past.day": "a day ago",
"words.time.past.days": "days ago",
"words.time.past.hour": "an hour ago",
"words.time.past.hours": "hours ago",
"words.time.past.minute": "a minute ago",
"words.time.past.minutes": "minutes ago",
"words.time.past.month": "a month ago",
"words.time.past.months": " months ago",
"words.time.past.seconds": "a few seconds ago",
"words.time.past.year": "a year ago",
"words.time.past.years": "years ago"
}

View file

@ -1,157 +0,0 @@
{
"app.boot.download-check": "Comprobando actualizaciones",
"app.boot.folder-check": "Comprobación de configuración",
"app.boot.loaded-runtime": "Aplicación cargada",
"app.boot.server-check": "Servidor de comprobación",
"app.boot.start-runtime": "Iniciar escritorio",
"app.core.ui.search": "Buscar",
"app.lthn.chain.daemons.lethean-blockchain-export": "Exportación de Blockchain",
"app.lthn.chain.daemons.lethean-blockchain-import": "Importación de Blockchain",
"app.lthn.chain.daemons.lethean-wallet-cli": "CLI de Wallet",
"app.lthn.chain.daemons.lethean-wallet-rpc": "Monedero RPC",
"app.lthn.chain.daemons.lethean-wallet-vpn-rpc": "Salir de la billetera del nodo",
"app.lthn.chain.daemons.letheand": "Servicio Blockchain",
"app.lthn.chain.desc.no_transactions": "No hubo transacciones incluidas en este bloque",
"app.lthn.chain.description": "Estadísticas de Blockchain de Lethean (LTHN)",
"app.lthn.chain.heading": "Estadísticas de Lethean Blockchain",
"app.lthn.chain.menu.blocks": "bloques",
"app.lthn.chain.menu.configuration": "Configuración",
"app.lthn.chain.menu.raw_data": "Datos de bloque sin procesar",
"app.lthn.chain.menu.stats": "Estadísticas",
"app.lthn.chain.table.age": "años",
"app.lthn.chain.table.depth": "Profundidad",
"app.lthn.chain.table.difficulty": "Dificultad",
"app.lthn.chain.table.height": "Altura",
"app.lthn.chain.table.reward": "recompensa",
"app.lthn.chain.table.time": "hora",
"app.lthn.chain.table.title.chain-status": "Estado de blockchain",
"app.lthn.chain.table.title.recent-blocks": "Bloques creados recientemente",
"app.lthn.chain.title": "Explorador de blockchain",
"app.lthn.chain.words.alt_blocks_count": "Bloques alternativos",
"app.lthn.chain.words.block_size": "Tamaño de bloque",
"app.lthn.chain.words.block_size_limit": "Límite de tamaño de bloque",
"app.lthn.chain.words.chain_stat": "Estadísticas de la cadena",
"app.lthn.chain.words.chain_stat_value": "Valor informado del nodo",
"app.lthn.chain.words.cumulative_difficulty": "Dificultad Acumulativa",
"app.lthn.chain.words.depth": "Profundidad desde el bloque superior",
"app.lthn.chain.words.difficulty": "Dificultad",
"app.lthn.chain.words.grey_peerlist_size": "Compañeros grises P2P",
"app.lthn.chain.words.hash": "Picadillo",
"app.lthn.chain.words.height": "Altura",
"app.lthn.chain.words.incoming_connections_count": "P2P entrante",
"app.lthn.chain.words.install-blockchain": "Instalar Blockchain",
"app.lthn.chain.words.last_block_time": "Sincronizado para bloquear:",
"app.lthn.chain.words.loading-data": "Cargando datos de Blockchain",
"app.lthn.chain.words.major_version": "versión principal",
"app.lthn.chain.words.miner_transaction": "Transacción minera",
"app.lthn.chain.words.miner_tx": "Transacción de minero POW",
"app.lthn.chain.words.minor_version": "versión menor",
"app.lthn.chain.words.nonce": "Solución de bloque",
"app.lthn.chain.words.orphan_status": "Bloque válido",
"app.lthn.chain.words.outgoing_connections_count": "P2P hacia fuera",
"app.lthn.chain.words.reward": "recompensa",
"app.lthn.chain.words.start_time": "Hora de inicio",
"app.lthn.chain.words.status": "Estado",
"app.lthn.chain.words.target": "Objetivo",
"app.lthn.chain.words.target_height": "Altura objetivo",
"app.lthn.chain.words.testnet": "Testnet",
"app.lthn.chain.words.timestamp": "marca de tiempo",
"app.lthn.chain.words.top_height": "Bloque más nuevo",
"app.lthn.chain.words.tx_count": "Transacciones totales",
"app.lthn.chain.words.tx_pool_size": "Transacciones pendientes",
"app.lthn.chain.words.unlock_time": "Desbloquear bloque",
"app.lthn.chain.words.valid": "Bloque válido",
"app.lthn.chain.words.version": "Versión de estructura de bloque",
"app.lthn.chain.words.white_peerlist_size": "Lista blanca P2P",
"app.lthn.console.title": "Consola",
"app.lthn.wallet.button.create-wallet": "Crear billetera",
"app.lthn.wallet.button.restore-wallet": "Restaurar billetera",
"app.lthn.wallet.button.unlock-wallet": "Desbloquear",
"app.lthn.wallet.label.address": "Dirección",
"app.lthn.wallet.label.autosave": "Guardar billetera abierta",
"app.lthn.wallet.label.filename": "Nombre del archivo",
"app.lthn.wallet.label.restore-height": "Restaurar altura",
"app.lthn.wallet.label.spend-key": "Gastar clave",
"app.lthn.wallet.label.view-key": "Ver clave",
"app.lthn.wallet.label.wallet-password": "Contraseña de billetera",
"app.lthn.wallet.label.wallet-password-confirm": "Confirmar contraseña",
"app.lthn.wallet.titles.new-wallet": "Crear nueva billetera",
"app.lthn.wallet.titles.restore-keys": "Restaurar desde claves",
"app.lthn.wallet.titles.restore-seed": "Restaurar de semilla",
"app.lthn.wallet.titles.unlock-wallet": "Desbloquear billetera",
"app.lthn.wallet.titles.wallet-transactions": "Transacciones de billetera",
"app.market.apps": "Mercado de aplicaciones",
"app.market.dashboard": "Tablero",
"app.market.installed": "Aplicaciones instaladas",
"app.market.no-apps-installed": "No tienes aplicaciones instaladas.",
"app.market.view-installable-apps": "Ver aplicaciones instalables",
"app.title": "Escritorio Lethean",
"charts.network-hashrate.subtitle": "Datos proporcionados por",
"charts.network-hashrate.title": "Tasa de hash de red",
"lang.de": "alemán",
"lang.en": "Inglés",
"lang.es": "español",
"lang.fr": "francés",
"lang.ru": "ruso",
"lang.uk": "Ucraniano (Ucrania)",
"lang.zh": "chino",
"menu.about": "Acerca De",
"menu.activity": "Actividad",
"menu.api": "api",
"menu.blockchain": "Blockchain",
"menu.build": "Construir",
"menu.dashboard": "Tablero",
"menu.docs": "Documentación",
"menu.documentation": "Documentación",
"menu.explorer": "explorador",
"menu.help": "Ayuda",
"menu.hub-admin": "Administración",
"menu.hub-client": "Cliente",
"menu.hub-developer": "Desarrollador",
"menu.hub-gateway": "Puerta",
"menu.hub-server": "Centro de servidores",
"menu.info": "información",
"menu.logout": "Desconectar",
"menu.mining": "Minería",
"menu.settings": "Ajustes",
"menu.vpn": "VPN",
"menu.wallet": "billetera",
"menu.your-profile": "Tu perfil",
"view.dashboard.description": "Aplicación web Lethean (LTHN)",
"view.dashboard.heading": "Panel de Lethean",
"view.dashboard.title": "Lethean (LTHN)",
"view.wallets.description": "Administrador de criptomonedas",
"view.wallets.heading": "Administrador de billetera",
"view.wallets.title": "carteras",
"words.actions.add": "Añadir",
"words.actions.clone": "Clon",
"words.actions.edit": "Editar",
"words.actions.install": "instalar",
"words.actions.new": "nuevo",
"words.actions.remove": "retirar",
"words.actions.report": "informe",
"words.actions.save": "Salvar",
"words.states.installing": "Instalando",
"words.states.installing_desc": "Estamos descargando los ejecutables de blockchain de GitHub a su directorio de usuario de Lethean.",
"words.states.loading": "Cargando",
"words.states.not_installed": "No instalado",
"words.states.not_installed_desc": "Haga clic en Instalar Blockchain para descargar la última CLI de Lethean Blockchain",
"words.things.button": "Botón",
"words.things.documentation": "Documentación",
"words.things.menu": "menú",
"words.things.mining-pool": "Pool de minería",
"words.things.page": "Página",
"words.things.problem": "Problema",
"words.things.type": "Tipo",
"words.time.past.day": "HACE UN DIA",
"words.time.past.days": "hace días",
"words.time.past.hour": "hace una hora",
"words.time.past.hours": "horas atras",
"words.time.past.minute": "hace un minuto",
"words.time.past.minutes": "hace minutos",
"words.time.past.month": "hace un mes",
"words.time.past.months": " Hace meses",
"words.time.past.seconds": "hace unos segundos",
"words.time.past.year": "hace un año",
"words.time.past.years": "Hace años que"
}

View file

@ -1,157 +0,0 @@
{
"app.boot.download-check": "Vérification des mises à jour",
"app.boot.folder-check": "Vérification de la configuration",
"app.boot.loaded-runtime": "Application chargée",
"app.boot.server-check": "Vérification du serveur",
"app.boot.start-runtime": "Démarrage du bureau",
"app.core.ui.search": "Recherche",
"app.lthn.chain.daemons.lethean-blockchain-export": "Exportation de la blockchain",
"app.lthn.chain.daemons.lethean-blockchain-import": "Importation de blockchain",
"app.lthn.chain.daemons.lethean-wallet-cli": "Portefeuille CLI",
"app.lthn.chain.daemons.lethean-wallet-rpc": "Portefeuille RPC",
"app.lthn.chain.daemons.lethean-wallet-vpn-rpc": "Quitter le portefeuille de nœuds",
"app.lthn.chain.daemons.letheand": "Service de blockchain",
"app.lthn.chain.desc.no_transactions": "Il n'y avait aucune transaction incluse dans ce bloc",
"app.lthn.chain.description": "Statistiques de la chaîne de blocs Lethean (LTHN)",
"app.lthn.chain.heading": "Statistiques Lethean Blockchain",
"app.lthn.chain.menu.blocks": "Des blocs",
"app.lthn.chain.menu.configuration": "Configuration",
"app.lthn.chain.menu.raw_data": "Données de bloc brutes",
"app.lthn.chain.menu.stats": "statistiques",
"app.lthn.chain.table.age": "âge",
"app.lthn.chain.table.depth": "Profondeur",
"app.lthn.chain.table.difficulty": "difficulté",
"app.lthn.chain.table.height": "la taille",
"app.lthn.chain.table.reward": "Récompensé",
"app.lthn.chain.table.time": "Temps",
"app.lthn.chain.table.title.chain-status": "Statut de la blockchain",
"app.lthn.chain.table.title.recent-blocks": "Blocs récemment créés",
"app.lthn.chain.title": "Explorateur de blockchain",
"app.lthn.chain.words.alt_blocks_count": "Blocs alternatifs",
"app.lthn.chain.words.block_size": "Taille de bloc",
"app.lthn.chain.words.block_size_limit": "Limite de taille de bloc",
"app.lthn.chain.words.chain_stat": "Statistiques de la chaîne",
"app.lthn.chain.words.chain_stat_value": "Valeur signalée par le nœud",
"app.lthn.chain.words.cumulative_difficulty": "Difficulté cumulée",
"app.lthn.chain.words.depth": "Profondeur à partir du bloc supérieur",
"app.lthn.chain.words.difficulty": "difficulté",
"app.lthn.chain.words.grey_peerlist_size": "Pairs gris P2P",
"app.lthn.chain.words.hash": "Hacher",
"app.lthn.chain.words.height": "la taille",
"app.lthn.chain.words.incoming_connections_count": "P2P entrant",
"app.lthn.chain.words.install-blockchain": "Installer la blockchain",
"app.lthn.chain.words.last_block_time": "Synchronisé pour bloquer :",
"app.lthn.chain.words.loading-data": "Chargement des données de la blockchain",
"app.lthn.chain.words.major_version": "Version majeure",
"app.lthn.chain.words.miner_transaction": "Transaction de mineur",
"app.lthn.chain.words.miner_tx": "Transaction de mineur POW",
"app.lthn.chain.words.minor_version": "Version mineure",
"app.lthn.chain.words.nonce": "Bloquer la solution",
"app.lthn.chain.words.orphan_status": "Bloc valide",
"app.lthn.chain.words.outgoing_connections_count": "Sortie P2P",
"app.lthn.chain.words.reward": "Récompensé",
"app.lthn.chain.words.start_time": "Heure de début",
"app.lthn.chain.words.status": "Statut",
"app.lthn.chain.words.target": "Cible",
"app.lthn.chain.words.target_height": "Hauteur cible",
"app.lthn.chain.words.testnet": "Réseau de test",
"app.lthn.chain.words.timestamp": "horodatage",
"app.lthn.chain.words.top_height": "Bloc le plus récent",
"app.lthn.chain.words.tx_count": "Transactions totales",
"app.lthn.chain.words.tx_pool_size": "Opérations en attente",
"app.lthn.chain.words.unlock_time": "Débloquer le bloc",
"app.lthn.chain.words.valid": "Bloc valide",
"app.lthn.chain.words.version": "Version de structure de bloc",
"app.lthn.chain.words.white_peerlist_size": "Liste blanche P2P",
"app.lthn.console.title": "Console",
"app.lthn.wallet.button.create-wallet": "Créer un portefeuille",
"app.lthn.wallet.button.restore-wallet": "Restaurer le portefeuille",
"app.lthn.wallet.button.unlock-wallet": "Ouvrir",
"app.lthn.wallet.label.address": "Adresse",
"app.lthn.wallet.label.autosave": "Enregistrer le portefeuille ouvert",
"app.lthn.wallet.label.filename": "Nom de fichier",
"app.lthn.wallet.label.restore-height": "Restaurer la hauteur",
"app.lthn.wallet.label.spend-key": "Dépenser la clé",
"app.lthn.wallet.label.view-key": "Afficher la clé",
"app.lthn.wallet.label.wallet-password": "Mot de passe portefeuille",
"app.lthn.wallet.label.wallet-password-confirm": "Confirmez le mot de passe",
"app.lthn.wallet.titles.new-wallet": "Créer un nouveau portefeuille",
"app.lthn.wallet.titles.restore-keys": "Restaurer à partir des clés",
"app.lthn.wallet.titles.restore-seed": "Restaurer à partir de la graine",
"app.lthn.wallet.titles.unlock-wallet": "Déverrouiller le portefeuille",
"app.lthn.wallet.titles.wallet-transactions": "Transactions de portefeuille",
"app.market.apps": "Marché d'applications",
"app.market.dashboard": "Tableau de bord",
"app.market.installed": "Applications installées",
"app.market.no-apps-installed": "Aucune application n'est installée.",
"app.market.view-installable-apps": "Afficher les applications installables",
"app.title": "Bureau Lethean",
"charts.network-hashrate.subtitle": "Données fournies par",
"charts.network-hashrate.title": "Taux de hachage du réseau",
"lang.de": "Allemand",
"lang.en": "Anglais",
"lang.es": "Espanol",
"lang.fr": "Français",
"lang.ru": "Russe",
"lang.uk": "Ukrainien (Ukraine)",
"lang.zh": "chinois",
"menu.about": "A Propos",
"menu.activity": "activité",
"menu.api": "api",
"menu.blockchain": "Blockchain",
"menu.build": "Build",
"menu.dashboard": "Tableau de bord",
"menu.docs": "Documentation",
"menu.documentation": "Documentation",
"menu.explorer": "Explorateur",
"menu.help": "Aide",
"menu.hub-admin": "Administrateur",
"menu.hub-client": "Client",
"menu.hub-developer": "Développeur",
"menu.hub-gateway": "PASSERELLE",
"menu.hub-server": "Centre de serveurs",
"menu.info": "info",
"menu.logout": "Se déconnecter",
"menu.mining": "Exploitation minière",
"menu.settings": "Réglages",
"menu.vpn": "VPN",
"menu.wallet": "Portefeuille",
"menu.your-profile": "Votre profil",
"view.dashboard.description": "Application Web Lethean (LTHN)",
"view.dashboard.heading": "Tableau de bord Léthéan",
"view.dashboard.title": "Lethean (LTHN)",
"view.wallets.description": "Gestionnaire de portefeuille crypto",
"view.wallets.heading": "Gestionnaire de portefeuille",
"view.wallets.title": "Portefeuilles",
"words.actions.add": "Ajouter",
"words.actions.clone": "Cloner",
"words.actions.edit": "Modifier",
"words.actions.install": "Installer",
"words.actions.new": "Nouveau",
"words.actions.remove": "Retirer",
"words.actions.report": "rapport",
"words.actions.save": "sauvegarder",
"words.states.installing": "L'installation",
"words.states.installing_desc": "Nous téléchargeons les exécutables blockchain de GitHub dans votre répertoire utilisateur Lethean.",
"words.states.loading": "Chargement",
"words.states.not_installed": "Pas installé",
"words.states.not_installed_desc": "Cliquez sur Installer Blockchain pour télécharger la dernière CLI Lethean Blockchain",
"words.things.button": "Bouton",
"words.things.documentation": "Documentation",
"words.things.menu": "menu",
"words.things.mining-pool": "Piscine minière",
"words.things.page": "Page",
"words.things.problem": "Problème",
"words.things.type": "Type",
"words.time.past.day": "il y a un jour",
"words.time.past.days": "il y a quelques jours",
"words.time.past.hour": "il y a une heure",
"words.time.past.hours": "il y a des heures",
"words.time.past.minute": "Il y'a une minute",
"words.time.past.minutes": "il y a quelques minutes",
"words.time.past.month": "il y a un mois",
"words.time.past.months": " il y a des mois",
"words.time.past.seconds": "il ya quelques secondes",
"words.time.past.year": "il y a un an",
"words.time.past.years": "il y a des années"
}

View file

@ -1,157 +0,0 @@
{
"app.boot.download-check": "Проверка обновлений",
"app.boot.folder-check": "Проверка установки",
"app.boot.loaded-runtime": "Приложение загружено",
"app.boot.server-check": "Проверка сервера",
"app.boot.start-runtime": "Запуск рабочего стола",
"app.core.ui.search": "Поиск",
"app.lthn.chain.daemons.lethean-blockchain-export": "Блокчейн Экспорт",
"app.lthn.chain.daemons.lethean-blockchain-import": "Блокчейн Импорт",
"app.lthn.chain.daemons.lethean-wallet-cli": "Кошелек CLI",
"app.lthn.chain.daemons.lethean-wallet-rpc": "Кошелек RPC",
"app.lthn.chain.daemons.lethean-wallet-vpn-rpc": "Выход из кошелька узла",
"app.lthn.chain.daemons.letheand": "Блокчейн Сервис",
"app.lthn.chain.desc.no_transactions": "В этом блоке не было включенных транзакций",
"app.lthn.chain.description": "Статистика блокчейна Lethean (LTHN)",
"app.lthn.chain.heading": "Статистика Lethean Blockchain",
"app.lthn.chain.menu.blocks": "блоки",
"app.lthn.chain.menu.configuration": "конфигурация",
"app.lthn.chain.menu.raw_data": "Необработанные данные блока",
"app.lthn.chain.menu.stats": "Статистика",
"app.lthn.chain.table.age": "возраст",
"app.lthn.chain.table.depth": "Глубина",
"app.lthn.chain.table.difficulty": "Сложность",
"app.lthn.chain.table.height": "Высота",
"app.lthn.chain.table.reward": "Награда",
"app.lthn.chain.table.time": "Время",
"app.lthn.chain.table.title.chain-status": "Статус блокчейна",
"app.lthn.chain.table.title.recent-blocks": "Недавно созданные блоки",
"app.lthn.chain.title": "Исследователь блокчейн",
"app.lthn.chain.words.alt_blocks_count": "Альтернативные блоки",
"app.lthn.chain.words.block_size": "Размер блока",
"app.lthn.chain.words.block_size_limit": "Ограничение размера блока",
"app.lthn.chain.words.chain_stat": "Цепная статистика",
"app.lthn.chain.words.chain_stat_value": "Сообщаемое значение узла",
"app.lthn.chain.words.cumulative_difficulty": "Суммарная сложность",
"app.lthn.chain.words.depth": "Глубина от верхнего блока",
"app.lthn.chain.words.difficulty": "Сложность",
"app.lthn.chain.words.grey_peerlist_size": "P2P Серые узлы",
"app.lthn.chain.words.hash": "Хэш",
"app.lthn.chain.words.height": "Высота",
"app.lthn.chain.words.incoming_connections_count": "P2P In",
"app.lthn.chain.words.install-blockchain": "Установить блокчейн",
"app.lthn.chain.words.last_block_time": "Синхронизировано с блоком:",
"app.lthn.chain.words.loading-data": "Загрузка данных блокчейна",
"app.lthn.chain.words.major_version": "основная версия",
"app.lthn.chain.words.miner_transaction": "Шахтерская транзакция",
"app.lthn.chain.words.miner_tx": "Транзакция POW Miner",
"app.lthn.chain.words.minor_version": "минорная версия",
"app.lthn.chain.words.nonce": "Блочное решение",
"app.lthn.chain.words.orphan_status": "Действительный блок",
"app.lthn.chain.words.outgoing_connections_count": "P2P Out",
"app.lthn.chain.words.reward": "Награда",
"app.lthn.chain.words.start_time": "Начальное время",
"app.lthn.chain.words.status": "Статус",
"app.lthn.chain.words.target": "цель",
"app.lthn.chain.words.target_height": "Высота",
"app.lthn.chain.words.testnet": "Тестовая сеть",
"app.lthn.chain.words.timestamp": "Метка времени",
"app.lthn.chain.words.top_height": "Крайний блок",
"app.lthn.chain.words.tx_count": "Всего транзакций",
"app.lthn.chain.words.tx_pool_size": "Незавершенные транзакции",
"app.lthn.chain.words.unlock_time": "Разблокировать Блок",
"app.lthn.chain.words.valid": "Действительный блок",
"app.lthn.chain.words.version": "Версия структуры блока",
"app.lthn.chain.words.white_peerlist_size": "P2P Белый список",
"app.lthn.console.title": "Приставка",
"app.lthn.wallet.button.create-wallet": "Создать кошелек",
"app.lthn.wallet.button.restore-wallet": "Восстановить кошелек",
"app.lthn.wallet.button.unlock-wallet": "отпереть",
"app.lthn.wallet.label.address": "Адрес",
"app.lthn.wallet.label.autosave": "Сохранить открытый кошелек",
"app.lthn.wallet.label.filename": "Имя файла",
"app.lthn.wallet.label.restore-height": "С какого блока восстанавливаем?",
"app.lthn.wallet.label.spend-key": "Spend key",
"app.lthn.wallet.label.view-key": "View Key",
"app.lthn.wallet.label.wallet-password": "Пароль кошелька",
"app.lthn.wallet.label.wallet-password-confirm": "Подтвердите Пароль",
"app.lthn.wallet.titles.new-wallet": "Сделать новый кошелек",
"app.lthn.wallet.titles.restore-keys": "Восстановить из ключей",
"app.lthn.wallet.titles.restore-seed": "Восстановить из seed",
"app.lthn.wallet.titles.unlock-wallet": "Разблокировать кошелек",
"app.lthn.wallet.titles.wallet-transactions": "Транзакции",
"app.market.apps": "Магазин приложений",
"app.market.dashboard": "Приборная доска",
"app.market.installed": "Установленные приложения",
"app.market.no-apps-installed": "У вас не установлены приложения.",
"app.market.view-installable-apps": "Просмотр устанавливаемых приложений",
"app.title": "Lethean Рабочий стол",
"charts.network-hashrate.subtitle": "Данные предоставлены",
"charts.network-hashrate.title": "Скорость хэширования в сети",
"lang.de": "Немецкий",
"lang.en": "Английский",
"lang.es": "Испанский",
"lang.fr": "Французский",
"lang.ru": "Русский",
"lang.uk": "Украинский (Украина)",
"lang.zh": "Китайский язык",
"menu.about": "Около",
"menu.activity": "Активность",
"menu.api": "api",
"menu.blockchain": "Blockchain",
"menu.build": "Сборка",
"menu.dashboard": "Дашборд",
"menu.docs": "Документация",
"menu.documentation": "Документация",
"menu.explorer": "Explorer",
"menu.help": "Помощь",
"menu.hub-admin": "Админ",
"menu.hub-client": "Клиент",
"menu.hub-developer": "Разработчик",
"menu.hub-gateway": "Шлюз",
"menu.hub-server": "Серверный концентратор",
"menu.info": "Информация",
"menu.logout": "Выход",
"menu.mining": "Горнодобывающая промышленность",
"menu.settings": "Настройки",
"menu.vpn": "VPN",
"menu.wallet": "Кошелек",
"menu.your-profile": "Ваш профиль",
"view.dashboard.description": "Веб-приложение Lethean (LTHN)",
"view.dashboard.heading": "Панель управления Lethean",
"view.dashboard.title": "Lethean (LTHN)",
"view.wallets.description": "Менеджер крипто-кошелька",
"view.wallets.heading": "Менеджер кошелька",
"view.wallets.title": "Кошелёк",
"words.actions.add": "Добавить",
"words.actions.clone": "Клонировать",
"words.actions.edit": "Редактировать",
"words.actions.install": "Установка",
"words.actions.new": "Новый",
"words.actions.remove": "Удалить",
"words.actions.report": "Отчет",
"words.actions.save": "Сохранить",
"words.states.installing": "Установка",
"words.states.installing_desc": "Мы загружаем исполняемые файлы блокчейна с GitHub в ваш каталог пользователей Lethean.",
"words.states.loading": "погрузка",
"words.states.not_installed": "Не установлено",
"words.states.not_installed_desc": "Нажмите «Установить блокчейн», чтобы загрузить последнюю версию интерфейса командной строки Lethean Blockchain.",
"words.things.button": "Кнопка",
"words.things.documentation": "Документация",
"words.things.menu": "Меню",
"words.things.mining-pool": "Майнинг пул",
"words.things.page": "Страница",
"words.things.problem": "Проблема",
"words.things.type": "Тип",
"words.time.past.day": "Предыдущий день",
"words.time.past.days": "дней назад",
"words.time.past.hour": "час назад",
"words.time.past.hours": "несколько часов назад",
"words.time.past.minute": "минуту назад",
"words.time.past.minutes": "несколько минут назад",
"words.time.past.month": "месяц назад",
"words.time.past.months": " несколько месяцев назад",
"words.time.past.seconds": "несколько секунд назад",
"words.time.past.year": "год назад",
"words.time.past.years": "много лет назад"
}

View file

@ -1,157 +0,0 @@
{
"app.boot.download-check": "Перевірка наявності оновлень",
"app.boot.folder-check": "Перевірка налаштування",
"app.boot.loaded-runtime": "Завантажено програму",
"app.boot.server-check": "Перевірка сервера",
"app.boot.start-runtime": "Запуск робочого столу",
"app.core.ui.search": "Пошук",
"app.lthn.chain.daemons.lethean-blockchain-export": "Експорт блокчейну",
"app.lthn.chain.daemons.lethean-blockchain-import": "Імпорт блокчейну",
"app.lthn.chain.daemons.lethean-wallet-cli": "CLI гаманця",
"app.lthn.chain.daemons.lethean-wallet-rpc": "RPC Wallet",
"app.lthn.chain.daemons.lethean-wallet-vpn-rpc": "Вийдіть з Node Wallet",
"app.lthn.chain.daemons.letheand": "Сервіс блокчейн",
"app.lthn.chain.desc.no_transactions": "Не було жодних транзакцій, включених до цього блоку",
"app.lthn.chain.description": "Статистика блокчейну Lethean (LTHN).",
"app.lthn.chain.heading": "Статистика блокчейну Lethean",
"app.lthn.chain.menu.blocks": "Блоки",
"app.lthn.chain.menu.configuration": "Конфігурація",
"app.lthn.chain.menu.raw_data": "Необроблені дані блоку",
"app.lthn.chain.menu.stats": "Статистика",
"app.lthn.chain.table.age": "Вік",
"app.lthn.chain.table.depth": "Глибина",
"app.lthn.chain.table.difficulty": "складність",
"app.lthn.chain.table.height": "Висота",
"app.lthn.chain.table.reward": "Нагорода",
"app.lthn.chain.table.time": "Час",
"app.lthn.chain.table.title.chain-status": "Стан блокчейну",
"app.lthn.chain.table.title.recent-blocks": "Нещодавно створені блоки",
"app.lthn.chain.title": "Blockchain Explorer",
"app.lthn.chain.words.alt_blocks_count": "Альтернативні блоки",
"app.lthn.chain.words.block_size": "Розмір блоку",
"app.lthn.chain.words.block_size_limit": "Обмеження розміру блоку",
"app.lthn.chain.words.chain_stat": "Статистика ланцюга",
"app.lthn.chain.words.chain_stat_value": "Повідомлене значення вузла",
"app.lthn.chain.words.cumulative_difficulty": "Сукупна складність",
"app.lthn.chain.words.depth": "Глибина від верхнього блоку",
"app.lthn.chain.words.difficulty": "складність",
"app.lthn.chain.words.grey_peerlist_size": "P2P Grey Peers",
"app.lthn.chain.words.hash": "Хеш",
"app.lthn.chain.words.height": "Висота",
"app.lthn.chain.words.incoming_connections_count": "P2P вхідні",
"app.lthn.chain.words.install-blockchain": "Встановіть блокчейн",
"app.lthn.chain.words.last_block_time": "Синхронізовано з блокуванням:",
"app.lthn.chain.words.loading-data": "Завантаження даних Blockchain",
"app.lthn.chain.words.major_version": "Основна версія",
"app.lthn.chain.words.miner_transaction": "Транзакція майнера",
"app.lthn.chain.words.miner_tx": "Транзакція майнера для військовополонених",
"app.lthn.chain.words.minor_version": "Друга версія",
"app.lthn.chain.words.nonce": "Блок рішення",
"app.lthn.chain.words.orphan_status": "Дійсний блок",
"app.lthn.chain.words.outgoing_connections_count": "Вихід P2P",
"app.lthn.chain.words.reward": "Нагорода",
"app.lthn.chain.words.start_time": "Час початку",
"app.lthn.chain.words.status": "статус",
"app.lthn.chain.words.target": "Ціль",
"app.lthn.chain.words.target_height": "Цільова висота",
"app.lthn.chain.words.testnet": "Testnet",
"app.lthn.chain.words.timestamp": "Відмітка часу",
"app.lthn.chain.words.top_height": "Найновіший блок",
"app.lthn.chain.words.tx_count": "Загальна кількість транзакцій",
"app.lthn.chain.words.tx_pool_size": "Транзакції в очікуванні",
"app.lthn.chain.words.unlock_time": "Розблокувати блок",
"app.lthn.chain.words.valid": "Дійсний блок",
"app.lthn.chain.words.version": "Версія блокової структури",
"app.lthn.chain.words.white_peerlist_size": "Білий список P2P",
"app.lthn.console.title": "консоль",
"app.lthn.wallet.button.create-wallet": "створити гаманець",
"app.lthn.wallet.button.restore-wallet": "Відновити гаманець",
"app.lthn.wallet.button.unlock-wallet": "розблокувати",
"app.lthn.wallet.label.address": "Адреса",
"app.lthn.wallet.label.autosave": "Зберегти Відкрийте гаманець",
"app.lthn.wallet.label.filename": "Ім'я файлу",
"app.lthn.wallet.label.restore-height": "Відновити висоту",
"app.lthn.wallet.label.spend-key": "Ключ витрат",
"app.lthn.wallet.label.view-key": "Ключ перегляду",
"app.lthn.wallet.label.wallet-password": "Пароль гаманця",
"app.lthn.wallet.label.wallet-password-confirm": "Підтвердьте пароль",
"app.lthn.wallet.titles.new-wallet": "Створіть новий гаманець",
"app.lthn.wallet.titles.restore-keys": "Відновити з ключів",
"app.lthn.wallet.titles.restore-seed": "Відновити з насіння",
"app.lthn.wallet.titles.unlock-wallet": "Розблокувати гаманець",
"app.lthn.wallet.titles.wallet-transactions": "Трансакції гаманця",
"app.market.apps": "App Marketplace",
"app.market.dashboard": "Панель приладів",
"app.market.installed": "Встановлені програми",
"app.market.no-apps-installed": "У вас не встановлено жодної програми.",
"app.market.view-installable-apps": "Переглянути додатки, які можна встановити",
"app.title": "Lethean Робочий стіл",
"charts.network-hashrate.subtitle": "Дані надані",
"charts.network-hashrate.title": "Швидкість хеш-мережі",
"lang.de": "Німецька",
"lang.en": "Англійська",
"lang.es": "Іспанська",
"lang.fr": "Французька",
"lang.ru": "російський",
"lang.uk": "українська (Україна)",
"lang.zh": "Китайська",
"menu.about": "Про",
"menu.activity": "Діяльність",
"menu.api": "Api",
"menu.blockchain": "Блокчейн",
"menu.build": "Будувати",
"menu.dashboard": "Панель приладів",
"menu.docs": "Документація",
"menu.documentation": "Документація",
"menu.explorer": "Explorer",
"menu.help": "Довідка",
"menu.hub-admin": "Адмін",
"menu.hub-client": "Клієнт",
"menu.hub-developer": "Розробник",
"menu.hub-gateway": "Шлюз",
"menu.hub-server": "Центр серверів",
"menu.info": "інформація",
"menu.logout": "Вийти з аккаунта",
"menu.mining": "Видобуток корисних копалин",
"menu.settings": "налаштування",
"menu.vpn": "VPN",
"menu.wallet": "Гаманець",
"menu.your-profile": "Ваш профіль",
"view.dashboard.description": "Веб-додаток Lethean (LTHN).",
"view.dashboard.heading": "Приладова панель Lethean",
"view.dashboard.title": "Lethean (LTHN)",
"view.wallets.description": "Менеджер криптовалютного гаманця",
"view.wallets.heading": "Менеджер гаманця",
"view.wallets.title": "Гаманці",
"words.actions.add": "Додати",
"words.actions.clone": "Клон",
"words.actions.edit": "редагувати",
"words.actions.install": "встановити",
"words.actions.new": "новий",
"words.actions.remove": "Видалити",
"words.actions.report": "звіт",
"words.actions.save": "зберегти",
"words.states.installing": "Встановлення",
"words.states.installing_desc": "Ми завантажуємо виконувані файли блокчейна з GitHub у ваш каталог користувачів Lethean.",
"words.states.loading": "Завантаження",
"words.states.not_installed": "Не встановлено",
"words.states.not_installed_desc": "Натисніть Встановити Blockchain, щоб завантажити останню версію Lethean Blockchain CLI",
"words.things.button": "Кнопка",
"words.things.documentation": "Документація",
"words.things.menu": "меню",
"words.things.mining-pool": "Майнінг-пул",
"words.things.page": "сторінка",
"words.things.problem": "Проблема",
"words.things.type": "Тип",
"words.time.past.day": "день тому",
"words.time.past.days": "днів тому",
"words.time.past.hour": "годину тому",
"words.time.past.hours": "годин тому",
"words.time.past.minute": "хвилину тому",
"words.time.past.minutes": "хвилин тому",
"words.time.past.month": "місяць тому",
"words.time.past.months": " місяців тому",
"words.time.past.seconds": "кілька секунд тому",
"words.time.past.year": "рік назад",
"words.time.past.years": "багато років тому"
}

View file

@ -1,157 +0,0 @@
{
"app.boot.download-check": "查询更新",
"app.boot.folder-check": "设置检查",
"app.boot.loaded-runtime": "应用程序已加载",
"app.boot.server-check": "检查服务器",
"app.boot.start-runtime": "启动桌面",
"app.core.ui.search": "搜索",
"app.lthn.chain.daemons.lethean-blockchain-export": "区块链导出",
"app.lthn.chain.daemons.lethean-blockchain-import": "区块链导入",
"app.lthn.chain.daemons.lethean-wallet-cli": "钱包命令行界面(CLI)",
"app.lthn.chain.daemons.lethean-wallet-rpc": "钱包远程过程调用(RPC)",
"app.lthn.chain.daemons.lethean-wallet-vpn-rpc": "出口节点钱包",
"app.lthn.chain.daemons.letheand": "区块链服务",
"app.lthn.chain.desc.no_transactions": "此区块中不包含任何交易",
"app.lthn.chain.description": "Lethean (LTHN) 区块链统计",
"app.lthn.chain.heading": "Lethean 区块链统计数据",
"app.lthn.chain.menu.blocks": "块",
"app.lthn.chain.menu.configuration": "组态",
"app.lthn.chain.menu.raw_data": "原始块数据",
"app.lthn.chain.menu.stats": "统计资料",
"app.lthn.chain.table.age": "年龄",
"app.lthn.chain.table.depth": "深度",
"app.lthn.chain.table.difficulty": "困难",
"app.lthn.chain.table.height": "高度",
"app.lthn.chain.table.reward": "奖励",
"app.lthn.chain.table.time": "时间",
"app.lthn.chain.table.title.chain-status": "区块链状态",
"app.lthn.chain.table.title.recent-blocks": "最近创建的块",
"app.lthn.chain.title": "区块链浏览器",
"app.lthn.chain.words.alt_blocks_count": "替代块",
"app.lthn.chain.words.block_size": "块大小",
"app.lthn.chain.words.block_size_limit": "块大小限制",
"app.lthn.chain.words.chain_stat": "连锁统计",
"app.lthn.chain.words.chain_stat_value": "节点报告值",
"app.lthn.chain.words.cumulative_difficulty": "累积难度",
"app.lthn.chain.words.depth": "顶块深度",
"app.lthn.chain.words.difficulty": "困难",
"app.lthn.chain.words.grey_peerlist_size": "P2P 灰色同行",
"app.lthn.chain.words.hash": "哈希",
"app.lthn.chain.words.height": "高度",
"app.lthn.chain.words.incoming_connections_count": "P2P传入",
"app.lthn.chain.words.install-blockchain": "安装区块链",
"app.lthn.chain.words.last_block_time": "同步到块:",
"app.lthn.chain.words.loading-data": "加载区块链数据",
"app.lthn.chain.words.major_version": "主要版本",
"app.lthn.chain.words.miner_transaction": "",
"app.lthn.chain.words.miner_tx": "POW 矿工交易",
"app.lthn.chain.words.minor_version": "次要版本",
"app.lthn.chain.words.nonce": "块解决方案",
"app.lthn.chain.words.orphan_status": "有效区块",
"app.lthn.chain.words.outgoing_connections_count": "点对点输出",
"app.lthn.chain.words.reward": "奖励",
"app.lthn.chain.words.start_time": "开始时间",
"app.lthn.chain.words.status": "状态",
"app.lthn.chain.words.target": "目标",
"app.lthn.chain.words.target_height": "目标高度",
"app.lthn.chain.words.testnet": "测试网",
"app.lthn.chain.words.timestamp": "时间戳",
"app.lthn.chain.words.top_height": "最新区块",
"app.lthn.chain.words.tx_count": "交易总额",
"app.lthn.chain.words.tx_pool_size": "待交易",
"app.lthn.chain.words.unlock_time": "解锁方块",
"app.lthn.chain.words.valid": "有效区块",
"app.lthn.chain.words.version": "块结构版本",
"app.lthn.chain.words.white_peerlist_size": "P2P白名单",
"app.lthn.console.title": "安慰",
"app.lthn.wallet.button.create-wallet": "创建钱包",
"app.lthn.wallet.button.restore-wallet": "恢复钱包",
"app.lthn.wallet.button.unlock-wallet": "开锁",
"app.lthn.wallet.label.address": "地址",
"app.lthn.wallet.label.autosave": "保存开设钱包",
"app.lthn.wallet.label.filename": "文件名",
"app.lthn.wallet.label.restore-height": "恢复高度",
"app.lthn.wallet.label.spend-key": "花费密钥",
"app.lthn.wallet.label.view-key": "查看密钥",
"app.lthn.wallet.label.wallet-password": "钱包密码",
"app.lthn.wallet.label.wallet-password-confirm": "确认密码",
"app.lthn.wallet.titles.new-wallet": "创建新钱包",
"app.lthn.wallet.titles.restore-keys": "恢复钱包(密钥)",
"app.lthn.wallet.titles.restore-seed": "恢复钱包(种子)",
"app.lthn.wallet.titles.unlock-wallet": "解锁钱包",
"app.lthn.wallet.titles.wallet-transactions": "钱包交易",
"app.market.apps": "应用市场",
"app.market.dashboard": "仪表板",
"app.market.installed": "已安装的应用程序",
"app.market.no-apps-installed": "您没有安装任何应用程序。",
"app.market.view-installable-apps": "查看可安装的应用程序",
"app.title": "Lethean 桌面",
"charts.network-hashrate.subtitle": "数据提供者",
"charts.network-hashrate.title": "网络哈希率",
"lang.de": "德语",
"lang.en": "英语",
"lang.es": "西班牙语",
"lang.fr": "法国",
"lang.ru": "俄语",
"lang.uk": "乌克兰语(乌克兰)",
"lang.zh": "中文",
"menu.about": "关于",
"menu.activity": "活动",
"menu.api": "应用程序接口(API)",
"menu.blockchain": "区块链",
"menu.build": "建立",
"menu.dashboard": "仪表盘",
"menu.docs": "文档",
"menu.documentation": "文档",
"menu.explorer": "资源管理器",
"menu.help": "帮助",
"menu.hub-admin": "行政",
"menu.hub-client": "客户",
"menu.hub-developer": "开发人员",
"menu.hub-gateway": "网关",
"menu.hub-server": "服务器中心",
"menu.info": "信息",
"menu.logout": "登出",
"menu.mining": "矿业",
"menu.settings": "设置",
"menu.vpn": "虚拟专用网",
"menu.wallet": "钱包",
"menu.your-profile": "您的个人资料",
"view.dashboard.description": "Lethean (LTHN) 网络应用程序",
"view.dashboard.heading": "Lethean仪表盘",
"view.dashboard.title": "Lethean (LTHN)",
"view.wallets.description": "加密钱包管理器",
"view.wallets.heading": "钱包管理器",
"view.wallets.title": "皮夹",
"words.actions.add": "添加",
"words.actions.clone": "复制",
"words.actions.edit": "编辑",
"words.actions.install": "安装",
"words.actions.new": "新",
"words.actions.remove": "去掉",
"words.actions.report": "报告",
"words.actions.save": "保存",
"words.states.installing": "正在安装",
"words.states.installing_desc": "我们正在将区块链可执行文件从 GitHub 下载到您的 Lethean 用户目录。",
"words.states.loading": "装载",
"words.states.not_installed": "未安装",
"words.states.not_installed_desc": "单击安装区块链以下载最新的 Lethean 区块链命令行界面(CLI)",
"words.things.button": "按键",
"words.things.documentation": "文档",
"words.things.menu": "菜单",
"words.things.mining-pool": "矿池",
"words.things.page": "页面",
"words.things.problem": "问题",
"words.things.type": "类型",
"words.time.past.day": "一天前",
"words.time.past.days": "几天前",
"words.time.past.hour": "一小时前",
"words.time.past.hours": "小时前",
"words.time.past.minute": "一分钟前",
"words.time.past.minutes": "几分钟前",
"words.time.past.month": "一个月前",
"words.time.past.months": " 几个月前",
"words.time.past.seconds": "几秒钟前",
"words.time.past.year": "一年前",
"words.time.past.years": "几年前"
}

View file

@ -1,3 +0,0 @@
{
"greeting": "Hello"
}

View file

@ -1,3 +0,0 @@
{
"greeting": "Hola"
}

View file

@ -4,11 +4,8 @@ import (
"context"
"fmt"
"github.com/Snider/Core/pkg/config"
"github.com/Snider/Core/pkg/core"
"github.com/Snider/Core/pkg/crypt"
"github.com/Snider/Core/pkg/display"
"github.com/Snider/Core/pkg/i18n"
"github.com/Snider/Core/pkg/workspace"
"github.com/wailsapp/wails/v3/pkg/application"
)
@ -18,10 +15,7 @@ import (
type Runtime struct {
app *application.App
Core *core.Core
Config *config.Service
Display *display.Service
Crypt *crypt.Service
I18n *i18n.Service
Workspace *workspace.Service
}
@ -35,7 +29,7 @@ func NewWithFactories(app *application.App, factories map[string]ServiceFactory)
core.WithWails(app),
}
for _, name := range []string{"config", "display", "crypt", "i18n", "workspace"} {
for _, name := range []string{"crypt", "workspace"} {
factory, ok := factories[name]
if !ok {
return nil, fmt.Errorf("service %s factory not provided", name)
@ -55,22 +49,10 @@ func NewWithFactories(app *application.App, factories map[string]ServiceFactory)
}
// --- Type Assertions ---
configSvc, ok := services["config"].(*config.Service)
if !ok {
return nil, fmt.Errorf("config service has unexpected type")
}
displaySvc, ok := services["display"].(*display.Service)
if !ok {
return nil, fmt.Errorf("display service has unexpected type")
}
cryptSvc, ok := services["crypt"].(*crypt.Service)
if !ok {
return nil, fmt.Errorf("crypt service has unexpected type")
}
i18nSvc, ok := services["i18n"].(*i18n.Service)
if !ok {
return nil, fmt.Errorf("i18n service has unexpected type")
}
workspaceSvc, ok := services["workspace"].(*workspace.Service)
if !ok {
return nil, fmt.Errorf("workspace service has unexpected type")
@ -79,10 +61,7 @@ func NewWithFactories(app *application.App, factories map[string]ServiceFactory)
rt := &Runtime{
app: app,
Core: coreInstance,
Config: configSvc,
Display: displaySvc,
Crypt: cryptSvc,
I18n: i18nSvc,
Workspace: workspaceSvc,
}
@ -92,10 +71,7 @@ func NewWithFactories(app *application.App, factories map[string]ServiceFactory)
// New creates and wires together all application services.
func New(app *application.App) (*Runtime, error) {
return NewWithFactories(app, map[string]ServiceFactory{
"config": func() (any, error) { return config.New() },
"display": func() (any, error) { return display.New() },
"crypt": func() (any, error) { return crypt.New() },
"i18n": func() (any, error) { return i18n.New() },
"workspace": func() (any, error) { return workspace.New() },
})
}

View file

@ -4,10 +4,7 @@ import (
"errors"
"testing"
"github.com/Snider/Core/pkg/config"
"github.com/Snider/Core/pkg/crypt"
"github.com/Snider/Core/pkg/display"
"github.com/Snider/Core/pkg/i18n"
"github.com/Snider/Core/pkg/runtime"
"github.com/Snider/Core/pkg/workspace"
"github.com/stretchr/testify/assert"
@ -27,20 +24,14 @@ func TestNew(t *testing.T) {
name: "Good path",
app: nil,
factories: map[string]runtime.ServiceFactory{
"config": func() (any, error) { return &config.Service{}, nil },
"display": func() (any, error) { return &display.Service{}, nil },
"crypt": func() (any, error) { return &crypt.Service{}, nil },
"i18n": func() (any, error) { return &i18n.Service{}, nil },
"workspace": func() (any, error) { return &workspace.Service{}, nil },
},
expectErr: false,
checkRuntime: func(t *testing.T, rt *runtime.Runtime) {
assert.NotNil(t, rt)
assert.NotNil(t, rt.Core)
assert.NotNil(t, rt.Config)
assert.NotNil(t, rt.Display)
assert.NotNil(t, rt.Crypt)
assert.NotNil(t, rt.I18n)
assert.NotNil(t, rt.Workspace)
},
},
@ -48,10 +39,7 @@ func TestNew(t *testing.T) {
name: "Factory returns an error",
app: nil,
factories: map[string]runtime.ServiceFactory{
"config": func() (any, error) { return &config.Service{}, nil },
"display": func() (any, error) { return &display.Service{}, nil },
"crypt": func() (any, error) { return nil, errors.New("crypt service failed") },
"i18n": func() (any, error) { return &i18n.Service{}, nil },
"workspace": func() (any, error) { return &workspace.Service{}, nil },
},
expectErr: true,
@ -61,23 +49,17 @@ func TestNew(t *testing.T) {
name: "Factory returns wrong type",
app: nil,
factories: map[string]runtime.ServiceFactory{
"config": func() (any, error) { return &config.Service{}, nil },
"display": func() (any, error) { return "not a display service", nil },
"crypt": func() (any, error) { return &crypt.Service{}, nil },
"i18n": func() (any, error) { return &i18n.Service{}, nil },
"crypt": func() (any, error) { return "not a crypt service", nil },
"workspace": func() (any, error) { return &workspace.Service{}, nil },
},
expectErr: true,
expectErrStr: "display service has unexpected type",
expectErrStr: "crypt service has unexpected type",
},
{
name: "With non-nil app",
app: &application.App{},
factories: map[string]runtime.ServiceFactory{
"config": func() (any, error) { return &config.Service{}, nil },
"display": func() (any, error) { return &display.Service{}, nil },
"crypt": func() (any, error) { return &crypt.Service{}, nil },
"i18n": func() (any, error) { return &i18n.Service{}, nil },
"workspace": func() (any, error) { return &workspace.Service{}, nil },
},
expectErr: false,