summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--client/client.go173
-rw-r--r--client/client_test.go2
-rw-r--r--client/locales/da/messages.gotext.json392
-rw-r--r--client/locales/de/messages.gotext.json392
-rw-r--r--client/locales/en/messages.gotext.json466
-rw-r--r--client/locales/es/messages.gotext.json392
-rw-r--r--client/locales/fr/messages.gotext.json392
-rw-r--r--client/locales/it/messages.gotext.json392
-rw-r--r--client/locales/nl/messages.gotext.json392
-rw-r--r--client/locales/uk/messages.gotext.json392
-rw-r--r--client/zgotext.go272
-rw-r--r--exports/exports.go33
-rw-r--r--go.mod15
-rw-r--r--go.sum7
-rw-r--r--i18nerr/i18nerr.go145
-rw-r--r--internal/server/server.go10
-rw-r--r--types/error/error.go24
-rw-r--r--wrappers/python/eduvpn_common/main.py18
19 files changed, 3796 insertions, 116 deletions
diff --git a/.gitignore b/.gitignore
index 2ce1749..2a7401f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,6 @@
*.iml
.idea/
.DS_Store
+
+# locales
+/client/locales/*/out.gotext.json
diff --git a/client/client.go b/client/client.go
index 124d9b5..3c18027 100644
--- a/client/client.go
+++ b/client/client.go
@@ -1,13 +1,15 @@
+//go:generate go run golang.org/x/text/cmd/gotext -srclang=en update -out=zgotext.go -lang=da,de,en,es,fr,it,nl,ukr
+
// Package client implements the public interface for creating eduVPN/Let's Connect! clients
package client
import (
"context"
- "fmt"
"strings"
"sync"
"time"
+ "github.com/eduvpn/eduvpn-common/i18nerr"
"github.com/eduvpn/eduvpn-common/internal/config"
"github.com/eduvpn/eduvpn-common/internal/discovery"
"github.com/eduvpn/eduvpn-common/internal/failover"
@@ -73,15 +75,6 @@ func userAgentName(clientID string) string {
}
}
-func (c *Client) logError(err error) {
- // Logs the error with the same level/verbosity as the error
- if c.Debug {
- log.Logger.Inherit(err, fmt.Sprintf("\nwith stacktrace: %s\n", err.(*errors.Error).ErrorStack()))
- } else {
- log.Logger.Inherit(err, "")
- }
-}
-
func (c *Client) isLetsConnect() bool {
// see https://git.sr.ht/~fkooman/vpn-user-portal/tree/v3/item/src/OAuth/VpnClientDb.php
return strings.HasPrefix(c.Name, "org.letsconnect-vpn.app")
@@ -121,7 +114,7 @@ type Client struct {
func (c *Client) updateTokens(srv server.Server) error {
if c.TokenGetter == nil {
- return errors.New("no tokken getter defined")
+ return errors.New("no token getter defined")
}
pSrv, err := c.pubCurrentServer(srv)
if err != nil {
@@ -168,10 +161,10 @@ func (c *Client) forwardTokens(srv server.Server) error {
func (c *Client) goTransition(id fsm.StateID) error {
handled, err := c.FSM.GoTransition(id)
if err != nil {
- return err
+ return i18nerr.Wrapf(err, "Internal state transition error")
}
if !handled {
- log.Logger.Debugf("transition not handled by the client: %s", GetStateName(id))
+ log.Logger.Debugf("transition not handled by the client to internal state: '%s'", GetStateName(id))
}
return nil
}
@@ -188,11 +181,11 @@ func New(name string, version string, directory string, stateCallback func(FSMSt
c = &Client{}
if !isAllowedClientID(name) {
- return nil, errors.Errorf("client ID is not allowed: '%v', see https://git.sr.ht/~fkooman/vpn-user-portal/tree/v3/item/src/OAuth/VpnClientDb.php for a list of allowed IDs", name)
+ return nil, i18nerr.Newf("The client registered with an invalid client ID: '%v'", name)
}
if len([]rune(version)) > 20 {
- return nil, errors.Errorf("version is not allowed: '%s', must be max 20 characters", version)
+ return nil, i18nerr.Newf("The client registered with an invalid version: '%v'", version)
}
// Initialize the logger
@@ -202,7 +195,7 @@ func New(name string, version string, directory string, stateCallback func(FSMSt
}
if err = log.Logger.Init(lvl, directory); err != nil {
- return nil, err
+ return nil, i18nerr.Wrapf(err, "The log file with directory: '%s' failed to initialize", directory)
}
// set client name
@@ -235,11 +228,11 @@ func New(name string, version string, directory string, stateCallback func(FSMSt
// Registering means updating the FSM to get to the initial state correctly
func (c *Client) Register() error {
if !c.FSM.InState(StateDeregistered) {
- return errors.Errorf("fsm attempt to register while in '%v'", c.FSM.Current)
+ return i18nerr.Wrapf(errors.New("The client tried to re-initialize without deregistering first"), "Client has an invalid state")
}
err := c.goTransition(StateNoServer)
if err != nil {
- return errors.WrapPrefix(err, "failed to register", 0)
+ return err
}
return nil
}
@@ -253,7 +246,7 @@ func (c *Client) Deregister() {
// Save the config
if err := c.Config.Save(&c); err != nil {
- log.Logger.Infof("c.Config.Save failed: %s\nstacktrace:\n%s", err.Error(), err.(*errors.Error).ErrorStack())
+ log.Logger.Infof("failed saving state configuration: '%v'", err)
}
// Empty out the state
@@ -265,15 +258,9 @@ func (c *Client) Deregister() {
// If this is the case then a previous version of the list is returned if there is any.
// This takes into account the frequency of updates, see: https://github.com/eduvpn/documentation/blob/v3/SERVER_DISCOVERY.md#organization-list.
func (c *Client) DiscoOrganizations(ck *cookie.Cookie) (orgs *discotypes.Organizations, err error) {
- defer func() {
- if err != nil {
- c.logError(err)
- }
- }()
-
// Not supported with Let's Connect!
if c.isLetsConnect() {
- return nil, errors.Errorf("discovery with Let's Connect is not supported")
+ return nil, i18nerr.Newf("Server/organization discovery with Let's Connect is not supported")
}
// Mark organizations as expired if we have not set an organization yet
@@ -281,8 +268,11 @@ func (c *Client) DiscoOrganizations(ck *cookie.Cookie) (orgs *discotypes.Organiz
c.Discovery.MarkOrganizationsExpired()
}
- // TODO: pass a context
- return c.Discovery.Organizations(ck.Context())
+ orgs, err = c.Discovery.Organizations(ck.Context())
+ if err != nil {
+ err = i18nerr.Wrap(err, "An error occurred after getting the discovery files for the list of organizations")
+ }
+ return
}
// DiscoServers gets the servers list from the discovery server
@@ -290,19 +280,16 @@ func (c *Client) DiscoOrganizations(ck *cookie.Cookie) (orgs *discotypes.Organiz
// If this is the case then a previous version of the list is returned if there is any.
// This takes into account the frequency of updates, see: https://github.com/eduvpn/documentation/blob/v3/SERVER_DISCOVERY.md#server-list.
func (c *Client) DiscoServers(ck *cookie.Cookie) (dss *discotypes.Servers, err error) {
- defer func() {
- if err != nil {
- c.logError(err)
- }
- }()
-
// Not supported with Let's Connect!
if c.isLetsConnect() {
- return nil, errors.Errorf("discovery with Let's Connect is not supported")
+ return nil, i18nerr.Newf("Server/organization discovery with Let's Connect is not supported")
}
- // TODO: pass a context
- return c.Discovery.Servers(ck.Context())
+ dss, err = c.Discovery.Servers(ck.Context())
+ if err != nil {
+ err = i18nerr.Wrap(err, "An error occurred after getting the discovery files for the list of servers")
+ }
+ return
}
// ExpiryTimes returns the different Unix timestamps regarding expiry
@@ -314,17 +301,15 @@ func (c *Client) ExpiryTimes() (*srvtypes.Expiry, error) {
// Get current expiry time
srv, err := c.Servers.Current()
if err != nil {
- c.logError(err)
- return nil, err
+ return nil, i18nerr.Wrap(err, "The current server could not be found when getting it for expiry")
}
b, err := srv.Base()
if err != nil {
- c.logError(err)
return nil, err
}
if b.StartTime.IsZero() {
- return nil, errors.New("start time is zero, did you get a configuration?")
+ return nil, i18nerr.New("No start time is defined for this server")
}
bT := b.RenewButtonTime()
@@ -387,7 +372,7 @@ func (c *Client) callbacks(ck *cookie.Cookie, srv server.Server, forceauth bool)
if srv.NeedsLocation() {
err := c.locationCallback(ck)
if err != nil {
- return err
+ return i18nerr.Wrap(err, "The secure internet location could not be set")
}
}
@@ -412,7 +397,7 @@ func (c *Client) callbacks(ck *cookie.Cookie, srv server.Server, forceauth bool)
}
err := c.loginCallback(ck, srv)
if err != nil {
- return err
+ return i18nerr.Wrap(err, "The authorization procedure failed to complete")
}
}
err = c.goTransition(StateAuthorized)
@@ -426,19 +411,18 @@ func (c *Client) callbacks(ck *cookie.Cookie, srv server.Server, forceauth bool)
func (c *Client) profileCallback(ck *cookie.Cookie, srv server.Server) error {
vp, err := server.HasValidProfile(ck.Context(), srv, c.SupportsWireguard)
if err != nil {
- return err
+ log.Logger.Warningf("failed to determine whether the current protocol is valid with error: %v", err)
}
if !vp {
- b, err := srv.Base()
+ vps, err := server.ValidProfiles(srv, c.SupportsWireguard)
if err != nil {
- return err
+ return i18nerr.Wrapf(err, "No suitable profiles could be found")
}
- ps := b.Profiles.Public()
errChan := make(chan error)
go func() {
err := c.FSM.GoTransitionRequired(StateAskProfile, &srvtypes.RequiredAskTransition{
C: ck,
- Data: ps,
+ Data: vps.Public(),
})
if err != nil {
errChan <- err
@@ -446,11 +430,11 @@ func (c *Client) profileCallback(ck *cookie.Cookie, srv server.Server) error {
}()
pID, err := ck.Receive(errChan)
if err != nil {
- return err
+ return i18nerr.Wrapf(err, "Profile with ID: '%s' could not be set", pID)
}
err = server.Profile(srv, pID)
if err != nil {
- return err
+ return i18nerr.Wrapf(err, "Profile with ID: '%s' could not be obtained from the server", pID)
}
}
err = c.goTransition(StateChosenProfile)
@@ -473,13 +457,13 @@ func (c *Client) AddServer(ck *cookie.Cookie, identifier string, _type srvtypes.
}
// If we must run callbacks, go to the previous state if we're not in it
if !ni && !c.FSM.InState(previousState) {
- c.FSM.GoTransition(previousState)
+ c.FSM.GoTransition(previousState) //nolint:errcheck
}
}()
if !ni {
- // This only returns a boolean if it was handled
err = c.goTransition(StateLoadingServer)
+ // this is already wrapped in an UI error
if err != nil {
return err
}
@@ -488,7 +472,7 @@ func (c *Client) AddServer(ck *cookie.Cookie, identifier string, _type srvtypes.
if _type != srvtypes.TypeSecureInternet {
identifier, err = http.EnsureValidURL(identifier, true)
if err != nil {
- return err
+ return i18nerr.Wrapf(err, "The identifier that was passed to the library is incorrect")
}
}
@@ -498,11 +482,11 @@ func (c *Client) AddServer(ck *cookie.Cookie, identifier string, _type srvtypes.
case srvtypes.TypeInstituteAccess:
dSrv, err := c.Discovery.ServerByURL(identifier, "institute_access")
if err != nil {
- return err
+ return i18nerr.Wrapf(err, "Could not retrieve institute access server with URL: '%s' from discovery", identifier)
}
srv, err = c.Servers.AddInstituteAccess(ck.Context(), c.Name ,dSrv)
if err != nil {
- return err
+ return i18nerr.Wrapf(err, "The institute access server with URL: '%s' could not be added", identifier)
}
case srvtypes.TypeSecureInternet:
dOrg, dSrv, err := c.Discovery.SecureHomeArgs(identifier)
@@ -511,19 +495,19 @@ func (c *Client) AddServer(ck *cookie.Cookie, identifier string, _type srvtypes.
// Note that in the docs it states that it only should happen when the Org ID doesn't exist
// However, this is nice as well because it also catches the error where the SecureInternetHome server is not found
c.Discovery.MarkOrganizationsExpired()
- return err
+ return i18nerr.Wrapf(err, "The secure internet server with organisation ID: '%s' could not be retrieved from discovery", identifier)
}
srv, err = c.Servers.AddSecureInternet(ck.Context(), c.Name, dOrg, dSrv)
if err != nil {
- return err
+ return i18nerr.Wrapf(err, "The secure internet server with organisation ID: '%s' could not be added", identifier)
}
case srvtypes.TypeCustom:
srv, err = c.Servers.AddCustom(ck.Context(), c.Name, identifier)
if err != nil {
- return err
+ return i18nerr.Wrapf(err, "The custom server with URL: '%s' could not be added", identifier)
}
default:
- return errors.Errorf("not a valid server type: %v", _type)
+ return i18nerr.Newf("Server type: '%v' is not valid to be added", _type)
}
// if we are non interactive, we run no callbacks
@@ -533,6 +517,7 @@ func (c *Client) AddServer(ck *cookie.Cookie, identifier string, _type srvtypes.
// callbacks
err = c.callbacks(ck, srv, false)
+ // error is already UI wrapped
if err != nil {
return err
}
@@ -562,16 +547,13 @@ func (c *Client) config(ck *cookie.Cookie, srv server.Server, pTCP bool, forceAu
cfgS, err := server.Config(ck.Context(), srv, c.SupportsWireguard, pTCP)
if err != nil {
- return nil, err
+ return nil, i18nerr.Wrap(err, "The VPN configuration could not be obtained")
}
p, err := server.CurrentProfile(srv)
if err != nil {
- return nil, err
+ return nil, i18nerr.Wrap(err, "The current profile could not be found")
}
pcfg := cfgS.Public(p.DefaultGateway)
- if err != nil {
- return nil, err
- }
return &pcfg, nil
}
@@ -587,7 +569,7 @@ func (c *Client) server(identifier string, _type srvtypes.Type) (srv server.Serv
srv, err = c.Servers.CustomServer(identifier)
setter = c.Servers.SetCustom
default:
- return nil, nil, errors.Errorf("not a valid server type: %v", _type)
+ return nil, nil, i18nerr.Newf("Not a valid server type: %v", _type)
}
return srv, setter, err
}
@@ -599,18 +581,16 @@ func (c *Client) GetConfig(ck *cookie.Cookie, identifier string, _type srvtypes.
previousState := c.FSM.Current
defer func() {
if err == nil {
- c.FSM.GoTransition(StateGotConfig)
- } else {
- if !c.FSM.InState(previousState) {
- // go back to the previous state if an error occurred
- c.FSM.GoTransition(previousState)
- }
+ c.FSM.GoTransition(StateGotConfig) //nolint:errcheck
+ } else if !c.FSM.InState(previousState) {
+ // go back to the previous state if an error occurred
+ c.FSM.GoTransition(previousState) //nolint:errcheck
}
}()
if _type != srvtypes.TypeSecureInternet {
identifier, err = http.EnsureValidURL(identifier, true)
if err != nil {
- return nil, err
+ return nil, i18nerr.Wrapf(err, "Identifier: '%s' for server with type: '%d' is not valid", identifier, _type)
}
}
err = c.goTransition(StateLoadingServer)
@@ -625,10 +605,9 @@ func (c *Client) GetConfig(ck *cookie.Cookie, identifier string, _type srvtypes.
err = server.RefreshEndpoints(ck.Context(), srv)
// If we get a canceled error, return that, otherwise just log the error
- cErr := context.Canceled
if err != nil {
- if errors.As(err, &cErr) {
- return nil, err
+ if errors.Is(err, context.Canceled) {
+ return nil, i18nerr.Wrap(err, "The operation for getting a VPN configuration was canceled")
}
log.Logger.Warningf("failed to refresh server endpoints: %v", err)
@@ -638,6 +617,7 @@ func (c *Client) GetConfig(ck *cookie.Cookie, identifier string, _type srvtypes.
cfg, err = c.config(ck, srv, pTCP, false)
tErr := &oauth.TokensInvalidError{}
if err != nil && errors.As(err, &tErr) {
+ log.Logger.Debugf("the tokens were invalid, trying again...")
cfg, err = c.config(ck, srv, pTCP, true)
}
@@ -656,7 +636,7 @@ func (c *Client) GetConfig(ck *cookie.Cookie, identifier string, _type srvtypes.
// set the current server
if err = set(srv); err != nil {
- return nil, err
+ return nil, i18nerr.Wrapf(err, "Failed to set the server with identifier: '%s' as the current", identifier)
}
return cfg, nil
@@ -666,19 +646,25 @@ func (c *Client) RemoveServer(identifier string, _type srvtypes.Type) (err error
if _type != srvtypes.TypeSecureInternet {
identifier, err = http.EnsureValidURL(identifier, true)
if err != nil {
- return err
+ return i18nerr.Wrapf(err, "Identifier: '%s' for server with type: '%d' is not valid for removal", identifier, _type)
}
}
+ // miscellaneous error
+ var mErr error
switch _type {
case srvtypes.TypeInstituteAccess:
- return c.Servers.RemoveInstituteAccess(identifier)
+ mErr = c.Servers.RemoveInstituteAccess(identifier)
case srvtypes.TypeSecureInternet:
- return c.Servers.RemoveSecureInternet(identifier)
+ mErr = c.Servers.RemoveSecureInternet(identifier)
case srvtypes.TypeCustom:
- return c.Servers.RemoveCustom(identifier)
+ mErr = c.Servers.RemoveCustom(identifier)
default:
- return errors.Errorf("not a valid server type: %v", _type)
+ return i18nerr.Newf("Not a valid server type: %v", _type)
+ }
+ if mErr != nil {
+ log.Logger.Debugf("failed to remove server with identifier: '%s' and type: '%d', error: %v", identifier, _type, mErr)
}
+ return nil
}
func (c *Client) CurrentServer() (*srvtypes.Current, error) {
@@ -759,7 +745,7 @@ func (c *Client) pubServer(srv server.Server) (interface{}, error) {
func (c *Client) ServerList() (*srvtypes.List, error) {
if c.FSM.InState(StateDeregistered) {
- return nil, errors.New("client is not registered")
+ return nil, i18nerr.New("Client is not registered")
}
var customServers []srvtypes.Server
for _, v := range c.Servers.CustomServers.Map {
@@ -821,7 +807,7 @@ func (c *Client) Cleanup(ck *cookie.Cookie) (err error) {
// get the current server
srv, err := c.Servers.Current()
if err != nil {
- return err
+ return i18nerr.Wrap(err, "Failed to get the current server to cleanup the connection")
}
err = c.updateTokens(srv)
if err != nil {
@@ -829,7 +815,7 @@ func (c *Client) Cleanup(ck *cookie.Cookie) (err error) {
}
err = server.Disconnect(ck.Context(), srv)
if err != nil {
- return err
+ return i18nerr.Wrap(err, "Failed to cleanup the VPN connection for the current server")
}
err = c.forwardTokens(srv)
if err != nil {
@@ -840,11 +826,11 @@ func (c *Client) Cleanup(ck *cookie.Cookie) (err error) {
func (c *Client) SetSecureLocation(ck *cookie.Cookie, countryCode string) (err error) {
if c.isLetsConnect() {
- return errors.Errorf("setting a secure internet location with Let's Connect! is not supported")
+ return i18nerr.Newf("Setting a secure internet location with Let's Connect! is not supported")
}
if !c.Servers.HasSecureInternet() {
- return errors.Errorf("no secure internet server available to set a location for")
+ return i18nerr.Newf("No secure internet server available to set a location for")
}
dSrv, err := c.Discovery.ServerByCountryCode(countryCode)
@@ -860,13 +846,13 @@ func (c *Client) RenewSession(ck *cookie.Cookie) (err error) {
defer c.mu.Unlock()
srv, err := c.Servers.Current()
if err != nil {
- return err
+ return i18nerr.Wrap(err, "Failed to get current server for renewing the session")
}
// The server has not been chosen yet, this means that we want to manually renew
// TODO: is this needed?
if !c.FSM.InState(StateChosenServer) {
- c.FSM.GoTransition(StateLoadingServer)
- c.FSM.GoTransition(StateChosenServer)
+ c.FSM.GoTransition(StateLoadingServer) //nolint:errcheck
+ c.FSM.GoTransition(StateChosenServer) //nolint:errcheck
}
// update tokens in the end
defer func() {
@@ -884,12 +870,17 @@ func (c *Client) RenewSession(ck *cookie.Cookie) (err error) {
func (c *Client) StartFailover(ck *cookie.Cookie, gateway string, mtu int, readRxBytes func() (int64, error)) (bool, error) {
f := failover.New(readRxBytes)
- return f.Start(ck.Context(), gateway, mtu)
+ d, err := f.Start(ck.Context(), gateway, mtu)
+ if err != nil {
+ return d, i18nerr.Wrapf(err, "Failover failed to complete with gateway: '%s' and mtu: '%d'", gateway, mtu)
+ }
+ return d, nil
}
func (c *Client) SetState(state FSMStateID) error {
c.mu.Lock()
defer c.mu.Unlock()
+ curr := c.FSM.Current
_, err := c.FSM.GoTransition(state)
if err != nil {
// self-transitions are only debug errors
@@ -897,7 +888,7 @@ func (c *Client) SetState(state FSMStateID) error {
log.Logger.Debugf("attempt an invalid self-transition: %s", c.FSM.GetStateName(state))
return nil
}
- return err
+ return i18nerr.Wrapf(err, "Failed internal state transition requested by the client from: '%s' to '%s'", GetStateName(curr), GetStateName(state))
}
return nil
}
diff --git a/client/client_test.go b/client/client_test.go
index 7077ce4..e60fd46 100644
--- a/client/client_test.go
+++ b/client/client_test.go
@@ -462,7 +462,7 @@ func TestInvalidClientID(t *testing.T) {
if err == nil {
t.Fatalf("expected invalid register with clientID: %v, but got no error", k)
}
- if !strings.HasPrefix(err.Error(), "client ID is not allowed") {
+ if !strings.HasPrefix(err.Error(), "The client registered with an invalid client ID") {
t.Fatalf("register error has invalid prefix: %v", err.Error())
}
}
diff --git a/client/locales/da/messages.gotext.json b/client/locales/da/messages.gotext.json
new file mode 100644
index 0000000..1e788ae
--- /dev/null
+++ b/client/locales/da/messages.gotext.json
@@ -0,0 +1,392 @@
+{
+ "language": "da",
+ "messages": [
+ {
+ "id": "Internal state transition error",
+ "message": "Internal state transition error",
+ "translation": ""
+ },
+ {
+ "id": "The client registered with an invalid client ID: '{Name}'",
+ "message": "The client registered with an invalid client ID: '{Name}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Name",
+ "string": "%[1]v",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "name"
+ }
+ ]
+ },
+ {
+ "id": "The client registered with an invalid version: '{Version}'",
+ "message": "The client registered with an invalid version: '{Version}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Version",
+ "string": "%[1]v",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "version"
+ }
+ ]
+ },
+ {
+ "id": "The log file with directory: '{Directory}' failed to initialize",
+ "message": "The log file with directory: '{Directory}' failed to initialize",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Directory",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "directory"
+ }
+ ]
+ },
+ {
+ "id": "Client has an invalid state",
+ "message": "Client has an invalid state",
+ "translation": ""
+ },
+ {
+ "id": "Server/organization discovery with Let's Connect is not supported",
+ "message": "Server/organization discovery with Let's Connect is not supported",
+ "translation": ""
+ },
+ {
+ "id": "An error occurred after getting the discovery files for the list of organizations",
+ "message": "An error occurred after getting the discovery files for the list of organizations",
+ "translation": ""
+ },
+ {
+ "id": "An error occurred after getting the discovery files for the list of servers",
+ "message": "An error occurred after getting the discovery files for the list of servers",
+ "translation": ""
+ },
+ {
+ "id": "The current server could not be found when getting it for expiry",
+ "message": "The current server could not be found when getting it for expiry",
+ "translation": ""
+ },
+ {
+ "id": "The secure internet location could not be set",
+ "message": "The secure internet location could not be set",
+ "translation": ""
+ },
+ {
+ "id": "The authorization procedure failed to complete",
+ "message": "The authorization procedure failed to complete",
+ "translation": ""
+ },
+ {
+ "id": "No suitable profiles could be found",
+ "message": "No suitable profiles could be found",
+ "translation": ""
+ },
+ {
+ "id": "Profile with ID: '{PID}' could not be set",
+ "message": "Profile with ID: '{PID}' could not be set",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "PID",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "pID"
+ }
+ ]
+ },
+ {
+ "id": "Profile with ID: '{PID}' could not be obtained from the server",
+ "message": "Profile with ID: '{PID}' could not be obtained from the server",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "PID",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "pID"
+ }
+ ]
+ },
+ {
+ "id": "The identifier that was passed to the library is incorrect",
+ "message": "The identifier that was passed to the library is incorrect",
+ "translation": ""
+ },
+ {
+ "id": "Could not retrieve institute access server with URL: '{Identifier}' from discovery",
+ "message": "Could not retrieve institute access server with URL: '{Identifier}' from discovery",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The institute access server with URL: '{Identifier}' could not be added",
+ "message": "The institute access server with URL: '{Identifier}' could not be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The secure internet server with organisation ID: '{Identifier}' could not be retrieved from discovery",
+ "message": "The secure internet server with organisation ID: '{Identifier}' could not be retrieved from discovery",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The secure internet server with organisation ID: '{Identifier}' could not be added",
+ "message": "The secure internet server with organisation ID: '{Identifier}' could not be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The custom server with URL: '{Identifier}' could not be added",
+ "message": "The custom server with URL: '{Identifier}' could not be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "Server type: '{Type}' is not valid to be added",
+ "message": "Server type: '{Type}' is not valid to be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Type",
+ "string": "%[1]v",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 1,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "The VPN configuration could not be obtained",
+ "message": "The VPN configuration could not be obtained",
+ "translation": ""
+ },
+ {
+ "id": "The current profile could not be found",
+ "message": "The current profile could not be found",
+ "translation": ""
+ },
+ {
+ "id": "Not a valid server type: {Type}",
+ "message": "Not a valid server type: {Type}",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Type",
+ "string": "%[1]v",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 1,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid",
+ "message": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ },
+ {
+ "id": "Type",
+ "string": "%[2]d",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 2,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "The operation for getting a VPN configuration was canceled",
+ "message": "The operation for getting a VPN configuration was canceled",
+ "translation": ""
+ },
+ {
+ "id": "Failed to set the server with identifier: '{Identifier}' as the current",
+ "message": "Failed to set the server with identifier: '{Identifier}' as the current",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid for removal",
+ "message": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid for removal",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ },
+ {
+ "id": "Type",
+ "string": "%[2]d",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 2,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "Failed to get the current server to cleanup the connection",
+ "message": "Failed to get the current server to cleanup the connection",
+ "translation": ""
+ },
+ {
+ "id": "Failed to cleanup the VPN connection for the current server",
+ "message": "Failed to cleanup the VPN connection for the current server",
+ "translation": ""
+ },
+ {
+ "id": "Setting a secure internet location with Let's Connect! is not supported",
+ "message": "Setting a secure internet location with Let's Connect! is not supported",
+ "translation": ""
+ },
+ {
+ "id": "No secure internet server available to set a location for",
+ "message": "No secure internet server available to set a location for",
+ "translation": ""
+ },
+ {
+ "id": "Failed to get current server for renewing the session",
+ "message": "Failed to get current server for renewing the session",
+ "translation": ""
+ },
+ {
+ "id": "Failover failed to complete with gateway: '{Gateway}' and mtu: '{Mtu}'",
+ "message": "Failover failed to complete with gateway: '{Gateway}' and mtu: '{Mtu}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Gateway",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "gateway"
+ },
+ {
+ "id": "Mtu",
+ "string": "%[2]d",
+ "type": "int",
+ "underlyingType": "int",
+ "argNum": 2,
+ "expr": "mtu"
+ }
+ ]
+ },
+ {
+ "id": "Failed internal state transition requested by the client from: '{StateNamecurr}' to '{StateNamestate}'",
+ "message": "Failed internal state transition requested by the client from: '{StateNamecurr}' to '{StateNamestate}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "StateNamecurr",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "GetStateName(curr)"
+ },
+ {
+ "id": "StateNamestate",
+ "string": "%[2]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 2,
+ "expr": "GetStateName(state)"
+ }
+ ]
+ },
+ {
+ "id": "timeout reached",
+ "message": "timeout reached",
+ "translation": ""
+ },
+ {
+ "id": "with cause:",
+ "message": "with cause:",
+ "translation": ""
+ }
+ ]
+} \ No newline at end of file
diff --git a/client/locales/de/messages.gotext.json b/client/locales/de/messages.gotext.json
new file mode 100644
index 0000000..68119d3
--- /dev/null
+++ b/client/locales/de/messages.gotext.json
@@ -0,0 +1,392 @@
+{
+ "language": "de",
+ "messages": [
+ {
+ "id": "Internal state transition error",
+ "message": "Internal state transition error",
+ "translation": ""
+ },
+ {
+ "id": "The client registered with an invalid client ID: '{Name}'",
+ "message": "The client registered with an invalid client ID: '{Name}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Name",
+ "string": "%[1]v",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "name"
+ }
+ ]
+ },
+ {
+ "id": "The client registered with an invalid version: '{Version}'",
+ "message": "The client registered with an invalid version: '{Version}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Version",
+ "string": "%[1]v",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "version"
+ }
+ ]
+ },
+ {
+ "id": "The log file with directory: '{Directory}' failed to initialize",
+ "message": "The log file with directory: '{Directory}' failed to initialize",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Directory",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "directory"
+ }
+ ]
+ },
+ {
+ "id": "Client has an invalid state",
+ "message": "Client has an invalid state",
+ "translation": ""
+ },
+ {
+ "id": "Server/organization discovery with Let's Connect is not supported",
+ "message": "Server/organization discovery with Let's Connect is not supported",
+ "translation": ""
+ },
+ {
+ "id": "An error occurred after getting the discovery files for the list of organizations",
+ "message": "An error occurred after getting the discovery files for the list of organizations",
+ "translation": ""
+ },
+ {
+ "id": "An error occurred after getting the discovery files for the list of servers",
+ "message": "An error occurred after getting the discovery files for the list of servers",
+ "translation": ""
+ },
+ {
+ "id": "The current server could not be found when getting it for expiry",
+ "message": "The current server could not be found when getting it for expiry",
+ "translation": ""
+ },
+ {
+ "id": "The secure internet location could not be set",
+ "message": "The secure internet location could not be set",
+ "translation": ""
+ },
+ {
+ "id": "The authorization procedure failed to complete",
+ "message": "The authorization procedure failed to complete",
+ "translation": ""
+ },
+ {
+ "id": "No suitable profiles could be found",
+ "message": "No suitable profiles could be found",
+ "translation": ""
+ },
+ {
+ "id": "Profile with ID: '{PID}' could not be set",
+ "message": "Profile with ID: '{PID}' could not be set",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "PID",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "pID"
+ }
+ ]
+ },
+ {
+ "id": "Profile with ID: '{PID}' could not be obtained from the server",
+ "message": "Profile with ID: '{PID}' could not be obtained from the server",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "PID",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "pID"
+ }
+ ]
+ },
+ {
+ "id": "The identifier that was passed to the library is incorrect",
+ "message": "The identifier that was passed to the library is incorrect",
+ "translation": ""
+ },
+ {
+ "id": "Could not retrieve institute access server with URL: '{Identifier}' from discovery",
+ "message": "Could not retrieve institute access server with URL: '{Identifier}' from discovery",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The institute access server with URL: '{Identifier}' could not be added",
+ "message": "The institute access server with URL: '{Identifier}' could not be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The secure internet server with organisation ID: '{Identifier}' could not be retrieved from discovery",
+ "message": "The secure internet server with organisation ID: '{Identifier}' could not be retrieved from discovery",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The secure internet server with organisation ID: '{Identifier}' could not be added",
+ "message": "The secure internet server with organisation ID: '{Identifier}' could not be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The custom server with URL: '{Identifier}' could not be added",
+ "message": "The custom server with URL: '{Identifier}' could not be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "Server type: '{Type}' is not valid to be added",
+ "message": "Server type: '{Type}' is not valid to be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Type",
+ "string": "%[1]v",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 1,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "The VPN configuration could not be obtained",
+ "message": "The VPN configuration could not be obtained",
+ "translation": ""
+ },
+ {
+ "id": "The current profile could not be found",
+ "message": "The current profile could not be found",
+ "translation": ""
+ },
+ {
+ "id": "Not a valid server type: {Type}",
+ "message": "Not a valid server type: {Type}",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Type",
+ "string": "%[1]v",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 1,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid",
+ "message": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ },
+ {
+ "id": "Type",
+ "string": "%[2]d",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 2,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "The operation for getting a VPN configuration was canceled",
+ "message": "The operation for getting a VPN configuration was canceled",
+ "translation": ""
+ },
+ {
+ "id": "Failed to set the server with identifier: '{Identifier}' as the current",
+ "message": "Failed to set the server with identifier: '{Identifier}' as the current",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid for removal",
+ "message": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid for removal",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ },
+ {
+ "id": "Type",
+ "string": "%[2]d",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 2,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "Failed to get the current server to cleanup the connection",
+ "message": "Failed to get the current server to cleanup the connection",
+ "translation": ""
+ },
+ {
+ "id": "Failed to cleanup the VPN connection for the current server",
+ "message": "Failed to cleanup the VPN connection for the current server",
+ "translation": ""
+ },
+ {
+ "id": "Setting a secure internet location with Let's Connect! is not supported",
+ "message": "Setting a secure internet location with Let's Connect! is not supported",
+ "translation": ""
+ },
+ {
+ "id": "No secure internet server available to set a location for",
+ "message": "No secure internet server available to set a location for",
+ "translation": ""
+ },
+ {
+ "id": "Failed to get current server for renewing the session",
+ "message": "Failed to get current server for renewing the session",
+ "translation": ""
+ },
+ {
+ "id": "Failover failed to complete with gateway: '{Gateway}' and mtu: '{Mtu}'",
+ "message": "Failover failed to complete with gateway: '{Gateway}' and mtu: '{Mtu}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Gateway",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "gateway"
+ },
+ {
+ "id": "Mtu",
+ "string": "%[2]d",
+ "type": "int",
+ "underlyingType": "int",
+ "argNum": 2,
+ "expr": "mtu"
+ }
+ ]
+ },
+ {
+ "id": "Failed internal state transition requested by the client from: '{StateNamecurr}' to '{StateNamestate}'",
+ "message": "Failed internal state transition requested by the client from: '{StateNamecurr}' to '{StateNamestate}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "StateNamecurr",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "GetStateName(curr)"
+ },
+ {
+ "id": "StateNamestate",
+ "string": "%[2]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 2,
+ "expr": "GetStateName(state)"
+ }
+ ]
+ },
+ {
+ "id": "timeout reached",
+ "message": "timeout reached",
+ "translation": ""
+ },
+ {
+ "id": "with cause:",
+ "message": "with cause:",
+ "translation": ""
+ }
+ ]
+} \ No newline at end of file
diff --git a/client/locales/en/messages.gotext.json b/client/locales/en/messages.gotext.json
new file mode 100644
index 0000000..15502ba
--- /dev/null
+++ b/client/locales/en/messages.gotext.json
@@ -0,0 +1,466 @@
+{
+ "language": "en",
+ "messages": [
+ {
+ "id": "Internal state transition error",
+ "message": "Internal state transition error",
+ "translation": "Internal state transition error",
+ "translatorComment": "Copied from source.",
+ "fuzzy": true
+ },
+ {
+ "id": "The client registered with an invalid client ID: '{Name}'",
+ "message": "The client registered with an invalid client ID: '{Name}'",
+ "translation": "The client registered with an invalid client ID: '{Name}'",
+ "translatorComment": "Copied from source.",
+ "placeholders": [
+ {
+ "id": "Name",
+ "string": "%[1]v",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "name"
+ }
+ ],
+ "fuzzy": true
+ },
+ {
+ "id": "The client registered with an invalid version: '{Version}'",
+ "message": "The client registered with an invalid version: '{Version}'",
+ "translation": "The client registered with an invalid version: '{Version}'",
+ "translatorComment": "Copied from source.",
+ "placeholders": [
+ {
+ "id": "Version",
+ "string": "%[1]v",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "version"
+ }
+ ],
+ "fuzzy": true
+ },
+ {
+ "id": "The log file with directory: '{Directory}' failed to initialize",
+ "message": "The log file with directory: '{Directory}' failed to initialize",
+ "translation": "The log file with directory: '{Directory}' failed to initialize",
+ "translatorComment": "Copied from source.",
+ "placeholders": [
+ {
+ "id": "Directory",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "directory"
+ }
+ ],
+ "fuzzy": true
+ },
+ {
+ "id": "Client has an invalid state",
+ "message": "Client has an invalid state",
+ "translation": "Client has an invalid state",
+ "translatorComment": "Copied from source.",
+ "fuzzy": true
+ },
+ {
+ "id": "Server/organization discovery with Let's Connect is not supported",
+ "message": "Server/organization discovery with Let's Connect is not supported",
+ "translation": "Server/organization discovery with Let's Connect is not supported",
+ "translatorComment": "Copied from source.",
+ "fuzzy": true
+ },
+ {
+ "id": "An error occurred after getting the discovery files for the list of organizations",
+ "message": "An error occurred after getting the discovery files for the list of organizations",
+ "translation": "An error occurred after getting the discovery files for the list of organizations",
+ "translatorComment": "Copied from source.",
+ "fuzzy": true
+ },
+ {
+ "id": "An error occurred after getting the discovery files for the list of servers",
+ "message": "An error occurred after getting the discovery files for the list of servers",
+ "translation": "An error occurred after getting the discovery files for the list of servers",
+ "translatorComment": "Copied from source.",
+ "fuzzy": true
+ },
+ {
+ "id": "The current server could not be found when getting it for expiry",
+ "message": "The current server could not be found when getting it for expiry",
+ "translation": "The current server could not be found when getting it for expiry",
+ "translatorComment": "Copied from source.",
+ "fuzzy": true
+ },
+ {
+ "id": "The secure internet location could not be set",
+ "message": "The secure internet location could not be set",
+ "translation": "The secure internet location could not be set",
+ "translatorComment": "Copied from source.",
+ "fuzzy": true
+ },
+ {
+ "id": "The authorization procedure failed to complete",
+ "message": "The authorization procedure failed to complete",
+ "translation": "The authorization procedure failed to complete",
+ "translatorComment": "Copied from source.",
+ "fuzzy": true
+ },
+ {
+ "id": "No suitable profiles could be found",
+ "message": "No suitable profiles could be found",
+ "translation": "No suitable profiles could be found",
+ "translatorComment": "Copied from source.",
+ "fuzzy": true
+ },
+ {
+ "id": "Profile with ID: '{PID}' could not be set",
+ "message": "Profile with ID: '{PID}' could not be set",
+ "translation": "Profile with ID: '{PID}' could not be set",
+ "translatorComment": "Copied from source.",
+ "placeholders": [
+ {
+ "id": "PID",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "pID"
+ }
+ ],
+ "fuzzy": true
+ },
+ {
+ "id": "Profile with ID: '{PID}' could not be obtained from the server",
+ "message": "Profile with ID: '{PID}' could not be obtained from the server",
+ "translation": "Profile with ID: '{PID}' could not be obtained from the server",
+ "translatorComment": "Copied from source.",
+ "placeholders": [
+ {
+ "id": "PID",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "pID"
+ }
+ ],
+ "fuzzy": true
+ },
+ {
+ "id": "The identifier that was passed to the library is incorrect",
+ "message": "The identifier that was passed to the library is incorrect",
+ "translation": "The identifier that was passed to the library is incorrect",
+ "translatorComment": "Copied from source.",
+ "fuzzy": true
+ },
+ {
+ "id": "Could not retrieve institute access server with URL: '{Identifier}' from discovery",
+ "message": "Could not retrieve institute access server with URL: '{Identifier}' from discovery",
+ "translation": "Could not retrieve institute access server with URL: '{Identifier}' from discovery",
+ "translatorComment": "Copied from source.",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ],
+ "fuzzy": true
+ },
+ {
+ "id": "The institute access server with URL: '{Identifier}' could not be added",
+ "message": "The institute access server with URL: '{Identifier}' could not be added",
+ "translation": "The institute access server with URL: '{Identifier}' could not be added",
+ "translatorComment": "Copied from source.",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ],
+ "fuzzy": true
+ },
+ {
+ "id": "The secure internet server with organisation ID: '{Identifier}' could not be retrieved from discovery",
+ "message": "The secure internet server with organisation ID: '{Identifier}' could not be retrieved from discovery",
+ "translation": "The secure internet server with organisation ID: '{Identifier}' could not be retrieved from discovery",
+ "translatorComment": "Copied from source.",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ],
+ "fuzzy": true
+ },
+ {
+ "id": "The secure internet server with organisation ID: '{Identifier}' could not be added",
+ "message": "The secure internet server with organisation ID: '{Identifier}' could not be added",
+ "translation": "The secure internet server with organisation ID: '{Identifier}' could not be added",
+ "translatorComment": "Copied from source.",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ],
+ "fuzzy": true
+ },
+ {
+ "id": "The custom server with URL: '{Identifier}' could not be added",
+ "message": "The custom server with URL: '{Identifier}' could not be added",
+ "translation": "The custom server with URL: '{Identifier}' could not be added",
+ "translatorComment": "Copied from source.",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ],
+ "fuzzy": true
+ },
+ {
+ "id": "Server type: '{Type}' is not valid to be added",
+ "message": "Server type: '{Type}' is not valid to be added",
+ "translation": "Server type: '{Type}' is not valid to be added",
+ "translatorComment": "Copied from source.",
+ "placeholders": [
+ {
+ "id": "Type",
+ "string": "%[1]v",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 1,
+ "expr": "_type"
+ }
+ ],
+ "fuzzy": true
+ },
+ {
+ "id": "The VPN configuration could not be obtained",
+ "message": "The VPN configuration could not be obtained",
+ "translation": "The VPN configuration could not be obtained",
+ "translatorComment": "Copied from source.",
+ "fuzzy": true
+ },
+ {
+ "id": "The current profile could not be found",
+ "message": "The current profile could not be found",
+ "translation": "The current profile could not be found",
+ "translatorComment": "Copied from source.",
+ "fuzzy": true
+ },
+ {
+ "id": "Not a valid server type: {Type}",
+ "message": "Not a valid server type: {Type}",
+ "translation": "Not a valid server type: {Type}",
+ "translatorComment": "Copied from source.",
+ "placeholders": [
+ {
+ "id": "Type",
+ "string": "%[1]v",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 1,
+ "expr": "_type"
+ }
+ ],
+ "fuzzy": true
+ },
+ {
+ "id": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid",
+ "message": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid",
+ "translation": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid",
+ "translatorComment": "Copied from source.",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ },
+ {
+ "id": "Type",
+ "string": "%[2]d",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 2,
+ "expr": "_type"
+ }
+ ],
+ "fuzzy": true
+ },
+ {
+ "id": "The operation for getting a VPN configuration was canceled",
+ "message": "The operation for getting a VPN configuration was canceled",
+ "translation": "The operation for getting a VPN configuration was canceled",
+ "translatorComment": "Copied from source.",
+ "fuzzy": true
+ },
+ {
+ "id": "Failed to set the server with identifier: '{Identifier}' as the current",
+ "message": "Failed to set the server with identifier: '{Identifier}' as the current",
+ "translation": "Failed to set the server with identifier: '{Identifier}' as the current",
+ "translatorComment": "Copied from source.",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ],
+ "fuzzy": true
+ },
+ {
+ "id": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid for removal",
+ "message": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid for removal",
+ "translation": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid for removal",
+ "translatorComment": "Copied from source.",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ },
+ {
+ "id": "Type",
+ "string": "%[2]d",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 2,
+ "expr": "_type"
+ }
+ ],
+ "fuzzy": true
+ },
+ {
+ "id": "Failed to get the current server to cleanup the connection",
+ "message": "Failed to get the current server to cleanup the connection",
+ "translation": "Failed to get the current server to cleanup the connection",
+ "translatorComment": "Copied from source.",
+ "fuzzy": true
+ },
+ {
+ "id": "Failed to cleanup the VPN connection for the current server",
+ "message": "Failed to cleanup the VPN connection for the current server",
+ "translation": "Failed to cleanup the VPN connection for the current server",
+ "translatorComment": "Copied from source.",
+ "fuzzy": true
+ },
+ {
+ "id": "Setting a secure internet location with Let's Connect! is not supported",
+ "message": "Setting a secure internet location with Let's Connect! is not supported",
+ "translation": "Setting a secure internet location with Let's Connect! is not supported",
+ "translatorComment": "Copied from source.",
+ "fuzzy": true
+ },
+ {
+ "id": "No secure internet server available to set a location for",
+ "message": "No secure internet server available to set a location for",
+ "translation": "No secure internet server available to set a location for",
+ "translatorComment": "Copied from source.",
+ "fuzzy": true
+ },
+ {
+ "id": "Failed to get current server for renewing the session",
+ "message": "Failed to get current server for renewing the session",
+ "translation": "Failed to get current server for renewing the session",
+ "translatorComment": "Copied from source.",
+ "fuzzy": true
+ },
+ {
+ "id": "Failover failed to complete with gateway: '{Gateway}' and mtu: '{Mtu}'",
+ "message": "Failover failed to complete with gateway: '{Gateway}' and mtu: '{Mtu}'",
+ "translation": "Failover failed to complete with gateway: '{Gateway}' and mtu: '{Mtu}'",
+ "translatorComment": "Copied from source.",
+ "placeholders": [
+ {
+ "id": "Gateway",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "gateway"
+ },
+ {
+ "id": "Mtu",
+ "string": "%[2]d",
+ "type": "int",
+ "underlyingType": "int",
+ "argNum": 2,
+ "expr": "mtu"
+ }
+ ],
+ "fuzzy": true
+ },
+ {
+ "id": "Failed internal state transition requested by the client from: '{StateNamecurr}' to '{StateNamestate}'",
+ "message": "Failed internal state transition requested by the client from: '{StateNamecurr}' to '{StateNamestate}'",
+ "translation": "Failed internal state transition requested by the client from: '{StateNamecurr}' to '{StateNamestate}'",
+ "translatorComment": "Copied from source.",
+ "placeholders": [
+ {
+ "id": "StateNamecurr",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "GetStateName(curr)"
+ },
+ {
+ "id": "StateNamestate",
+ "string": "%[2]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 2,
+ "expr": "GetStateName(state)"
+ }
+ ],
+ "fuzzy": true
+ },
+ {
+ "id": "timeout reached",
+ "message": "timeout reached",
+ "translation": "timeout reached",
+ "translatorComment": "Copied from source.",
+ "fuzzy": true
+ },
+ {
+ "id": "with cause:",
+ "message": "with cause:",
+ "translation": "with cause:",
+ "translatorComment": "Copied from source.",
+ "fuzzy": true
+ }
+ ]
+} \ No newline at end of file
diff --git a/client/locales/es/messages.gotext.json b/client/locales/es/messages.gotext.json
new file mode 100644
index 0000000..6c93919
--- /dev/null
+++ b/client/locales/es/messages.gotext.json
@@ -0,0 +1,392 @@
+{
+ "language": "es",
+ "messages": [
+ {
+ "id": "Internal state transition error",
+ "message": "Internal state transition error",
+ "translation": ""
+ },
+ {
+ "id": "The client registered with an invalid client ID: '{Name}'",
+ "message": "The client registered with an invalid client ID: '{Name}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Name",
+ "string": "%[1]v",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "name"
+ }
+ ]
+ },
+ {
+ "id": "The client registered with an invalid version: '{Version}'",
+ "message": "The client registered with an invalid version: '{Version}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Version",
+ "string": "%[1]v",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "version"
+ }
+ ]
+ },
+ {
+ "id": "The log file with directory: '{Directory}' failed to initialize",
+ "message": "The log file with directory: '{Directory}' failed to initialize",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Directory",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "directory"
+ }
+ ]
+ },
+ {
+ "id": "Client has an invalid state",
+ "message": "Client has an invalid state",
+ "translation": ""
+ },
+ {
+ "id": "Server/organization discovery with Let's Connect is not supported",
+ "message": "Server/organization discovery with Let's Connect is not supported",
+ "translation": ""
+ },
+ {
+ "id": "An error occurred after getting the discovery files for the list of organizations",
+ "message": "An error occurred after getting the discovery files for the list of organizations",
+ "translation": ""
+ },
+ {
+ "id": "An error occurred after getting the discovery files for the list of servers",
+ "message": "An error occurred after getting the discovery files for the list of servers",
+ "translation": ""
+ },
+ {
+ "id": "The current server could not be found when getting it for expiry",
+ "message": "The current server could not be found when getting it for expiry",
+ "translation": ""
+ },
+ {
+ "id": "The secure internet location could not be set",
+ "message": "The secure internet location could not be set",
+ "translation": ""
+ },
+ {
+ "id": "The authorization procedure failed to complete",
+ "message": "The authorization procedure failed to complete",
+ "translation": ""
+ },
+ {
+ "id": "No suitable profiles could be found",
+ "message": "No suitable profiles could be found",
+ "translation": ""
+ },
+ {
+ "id": "Profile with ID: '{PID}' could not be set",
+ "message": "Profile with ID: '{PID}' could not be set",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "PID",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "pID"
+ }
+ ]
+ },
+ {
+ "id": "Profile with ID: '{PID}' could not be obtained from the server",
+ "message": "Profile with ID: '{PID}' could not be obtained from the server",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "PID",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "pID"
+ }
+ ]
+ },
+ {
+ "id": "The identifier that was passed to the library is incorrect",
+ "message": "The identifier that was passed to the library is incorrect",
+ "translation": ""
+ },
+ {
+ "id": "Could not retrieve institute access server with URL: '{Identifier}' from discovery",
+ "message": "Could not retrieve institute access server with URL: '{Identifier}' from discovery",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The institute access server with URL: '{Identifier}' could not be added",
+ "message": "The institute access server with URL: '{Identifier}' could not be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The secure internet server with organisation ID: '{Identifier}' could not be retrieved from discovery",
+ "message": "The secure internet server with organisation ID: '{Identifier}' could not be retrieved from discovery",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The secure internet server with organisation ID: '{Identifier}' could not be added",
+ "message": "The secure internet server with organisation ID: '{Identifier}' could not be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The custom server with URL: '{Identifier}' could not be added",
+ "message": "The custom server with URL: '{Identifier}' could not be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "Server type: '{Type}' is not valid to be added",
+ "message": "Server type: '{Type}' is not valid to be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Type",
+ "string": "%[1]v",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 1,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "The VPN configuration could not be obtained",
+ "message": "The VPN configuration could not be obtained",
+ "translation": ""
+ },
+ {
+ "id": "The current profile could not be found",
+ "message": "The current profile could not be found",
+ "translation": ""
+ },
+ {
+ "id": "Not a valid server type: {Type}",
+ "message": "Not a valid server type: {Type}",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Type",
+ "string": "%[1]v",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 1,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid",
+ "message": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ },
+ {
+ "id": "Type",
+ "string": "%[2]d",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 2,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "The operation for getting a VPN configuration was canceled",
+ "message": "The operation for getting a VPN configuration was canceled",
+ "translation": ""
+ },
+ {
+ "id": "Failed to set the server with identifier: '{Identifier}' as the current",
+ "message": "Failed to set the server with identifier: '{Identifier}' as the current",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid for removal",
+ "message": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid for removal",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ },
+ {
+ "id": "Type",
+ "string": "%[2]d",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 2,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "Failed to get the current server to cleanup the connection",
+ "message": "Failed to get the current server to cleanup the connection",
+ "translation": ""
+ },
+ {
+ "id": "Failed to cleanup the VPN connection for the current server",
+ "message": "Failed to cleanup the VPN connection for the current server",
+ "translation": ""
+ },
+ {
+ "id": "Setting a secure internet location with Let's Connect! is not supported",
+ "message": "Setting a secure internet location with Let's Connect! is not supported",
+ "translation": ""
+ },
+ {
+ "id": "No secure internet server available to set a location for",
+ "message": "No secure internet server available to set a location for",
+ "translation": ""
+ },
+ {
+ "id": "Failed to get current server for renewing the session",
+ "message": "Failed to get current server for renewing the session",
+ "translation": ""
+ },
+ {
+ "id": "Failover failed to complete with gateway: '{Gateway}' and mtu: '{Mtu}'",
+ "message": "Failover failed to complete with gateway: '{Gateway}' and mtu: '{Mtu}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Gateway",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "gateway"
+ },
+ {
+ "id": "Mtu",
+ "string": "%[2]d",
+ "type": "int",
+ "underlyingType": "int",
+ "argNum": 2,
+ "expr": "mtu"
+ }
+ ]
+ },
+ {
+ "id": "Failed internal state transition requested by the client from: '{StateNamecurr}' to '{StateNamestate}'",
+ "message": "Failed internal state transition requested by the client from: '{StateNamecurr}' to '{StateNamestate}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "StateNamecurr",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "GetStateName(curr)"
+ },
+ {
+ "id": "StateNamestate",
+ "string": "%[2]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 2,
+ "expr": "GetStateName(state)"
+ }
+ ]
+ },
+ {
+ "id": "timeout reached",
+ "message": "timeout reached",
+ "translation": ""
+ },
+ {
+ "id": "with cause:",
+ "message": "with cause:",
+ "translation": ""
+ }
+ ]
+} \ No newline at end of file
diff --git a/client/locales/fr/messages.gotext.json b/client/locales/fr/messages.gotext.json
new file mode 100644
index 0000000..0e793f1
--- /dev/null
+++ b/client/locales/fr/messages.gotext.json
@@ -0,0 +1,392 @@
+{
+ "language": "fr",
+ "messages": [
+ {
+ "id": "Internal state transition error",
+ "message": "Internal state transition error",
+ "translation": ""
+ },
+ {
+ "id": "The client registered with an invalid client ID: '{Name}'",
+ "message": "The client registered with an invalid client ID: '{Name}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Name",
+ "string": "%[1]v",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "name"
+ }
+ ]
+ },
+ {
+ "id": "The client registered with an invalid version: '{Version}'",
+ "message": "The client registered with an invalid version: '{Version}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Version",
+ "string": "%[1]v",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "version"
+ }
+ ]
+ },
+ {
+ "id": "The log file with directory: '{Directory}' failed to initialize",
+ "message": "The log file with directory: '{Directory}' failed to initialize",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Directory",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "directory"
+ }
+ ]
+ },
+ {
+ "id": "Client has an invalid state",
+ "message": "Client has an invalid state",
+ "translation": ""
+ },
+ {
+ "id": "Server/organization discovery with Let's Connect is not supported",
+ "message": "Server/organization discovery with Let's Connect is not supported",
+ "translation": ""
+ },
+ {
+ "id": "An error occurred after getting the discovery files for the list of organizations",
+ "message": "An error occurred after getting the discovery files for the list of organizations",
+ "translation": ""
+ },
+ {
+ "id": "An error occurred after getting the discovery files for the list of servers",
+ "message": "An error occurred after getting the discovery files for the list of servers",
+ "translation": ""
+ },
+ {
+ "id": "The current server could not be found when getting it for expiry",
+ "message": "The current server could not be found when getting it for expiry",
+ "translation": ""
+ },
+ {
+ "id": "The secure internet location could not be set",
+ "message": "The secure internet location could not be set",
+ "translation": ""
+ },
+ {
+ "id": "The authorization procedure failed to complete",
+ "message": "The authorization procedure failed to complete",
+ "translation": ""
+ },
+ {
+ "id": "No suitable profiles could be found",
+ "message": "No suitable profiles could be found",
+ "translation": ""
+ },
+ {
+ "id": "Profile with ID: '{PID}' could not be set",
+ "message": "Profile with ID: '{PID}' could not be set",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "PID",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "pID"
+ }
+ ]
+ },
+ {
+ "id": "Profile with ID: '{PID}' could not be obtained from the server",
+ "message": "Profile with ID: '{PID}' could not be obtained from the server",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "PID",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "pID"
+ }
+ ]
+ },
+ {
+ "id": "The identifier that was passed to the library is incorrect",
+ "message": "The identifier that was passed to the library is incorrect",
+ "translation": ""
+ },
+ {
+ "id": "Could not retrieve institute access server with URL: '{Identifier}' from discovery",
+ "message": "Could not retrieve institute access server with URL: '{Identifier}' from discovery",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The institute access server with URL: '{Identifier}' could not be added",
+ "message": "The institute access server with URL: '{Identifier}' could not be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The secure internet server with organisation ID: '{Identifier}' could not be retrieved from discovery",
+ "message": "The secure internet server with organisation ID: '{Identifier}' could not be retrieved from discovery",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The secure internet server with organisation ID: '{Identifier}' could not be added",
+ "message": "The secure internet server with organisation ID: '{Identifier}' could not be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The custom server with URL: '{Identifier}' could not be added",
+ "message": "The custom server with URL: '{Identifier}' could not be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "Server type: '{Type}' is not valid to be added",
+ "message": "Server type: '{Type}' is not valid to be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Type",
+ "string": "%[1]v",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 1,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "The VPN configuration could not be obtained",
+ "message": "The VPN configuration could not be obtained",
+ "translation": ""
+ },
+ {
+ "id": "The current profile could not be found",
+ "message": "The current profile could not be found",
+ "translation": ""
+ },
+ {
+ "id": "Not a valid server type: {Type}",
+ "message": "Not a valid server type: {Type}",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Type",
+ "string": "%[1]v",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 1,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid",
+ "message": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ },
+ {
+ "id": "Type",
+ "string": "%[2]d",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 2,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "The operation for getting a VPN configuration was canceled",
+ "message": "The operation for getting a VPN configuration was canceled",
+ "translation": ""
+ },
+ {
+ "id": "Failed to set the server with identifier: '{Identifier}' as the current",
+ "message": "Failed to set the server with identifier: '{Identifier}' as the current",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid for removal",
+ "message": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid for removal",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ },
+ {
+ "id": "Type",
+ "string": "%[2]d",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 2,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "Failed to get the current server to cleanup the connection",
+ "message": "Failed to get the current server to cleanup the connection",
+ "translation": ""
+ },
+ {
+ "id": "Failed to cleanup the VPN connection for the current server",
+ "message": "Failed to cleanup the VPN connection for the current server",
+ "translation": ""
+ },
+ {
+ "id": "Setting a secure internet location with Let's Connect! is not supported",
+ "message": "Setting a secure internet location with Let's Connect! is not supported",
+ "translation": ""
+ },
+ {
+ "id": "No secure internet server available to set a location for",
+ "message": "No secure internet server available to set a location for",
+ "translation": ""
+ },
+ {
+ "id": "Failed to get current server for renewing the session",
+ "message": "Failed to get current server for renewing the session",
+ "translation": ""
+ },
+ {
+ "id": "Failover failed to complete with gateway: '{Gateway}' and mtu: '{Mtu}'",
+ "message": "Failover failed to complete with gateway: '{Gateway}' and mtu: '{Mtu}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Gateway",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "gateway"
+ },
+ {
+ "id": "Mtu",
+ "string": "%[2]d",
+ "type": "int",
+ "underlyingType": "int",
+ "argNum": 2,
+ "expr": "mtu"
+ }
+ ]
+ },
+ {
+ "id": "Failed internal state transition requested by the client from: '{StateNamecurr}' to '{StateNamestate}'",
+ "message": "Failed internal state transition requested by the client from: '{StateNamecurr}' to '{StateNamestate}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "StateNamecurr",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "GetStateName(curr)"
+ },
+ {
+ "id": "StateNamestate",
+ "string": "%[2]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 2,
+ "expr": "GetStateName(state)"
+ }
+ ]
+ },
+ {
+ "id": "timeout reached",
+ "message": "timeout reached",
+ "translation": ""
+ },
+ {
+ "id": "with cause:",
+ "message": "with cause:",
+ "translation": ""
+ }
+ ]
+} \ No newline at end of file
diff --git a/client/locales/it/messages.gotext.json b/client/locales/it/messages.gotext.json
new file mode 100644
index 0000000..ca5bf05
--- /dev/null
+++ b/client/locales/it/messages.gotext.json
@@ -0,0 +1,392 @@
+{
+ "language": "it",
+ "messages": [
+ {
+ "id": "Internal state transition error",
+ "message": "Internal state transition error",
+ "translation": ""
+ },
+ {
+ "id": "The client registered with an invalid client ID: '{Name}'",
+ "message": "The client registered with an invalid client ID: '{Name}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Name",
+ "string": "%[1]v",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "name"
+ }
+ ]
+ },
+ {
+ "id": "The client registered with an invalid version: '{Version}'",
+ "message": "The client registered with an invalid version: '{Version}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Version",
+ "string": "%[1]v",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "version"
+ }
+ ]
+ },
+ {
+ "id": "The log file with directory: '{Directory}' failed to initialize",
+ "message": "The log file with directory: '{Directory}' failed to initialize",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Directory",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "directory"
+ }
+ ]
+ },
+ {
+ "id": "Client has an invalid state",
+ "message": "Client has an invalid state",
+ "translation": ""
+ },
+ {
+ "id": "Server/organization discovery with Let's Connect is not supported",
+ "message": "Server/organization discovery with Let's Connect is not supported",
+ "translation": ""
+ },
+ {
+ "id": "An error occurred after getting the discovery files for the list of organizations",
+ "message": "An error occurred after getting the discovery files for the list of organizations",
+ "translation": ""
+ },
+ {
+ "id": "An error occurred after getting the discovery files for the list of servers",
+ "message": "An error occurred after getting the discovery files for the list of servers",
+ "translation": ""
+ },
+ {
+ "id": "The current server could not be found when getting it for expiry",
+ "message": "The current server could not be found when getting it for expiry",
+ "translation": ""
+ },
+ {
+ "id": "The secure internet location could not be set",
+ "message": "The secure internet location could not be set",
+ "translation": ""
+ },
+ {
+ "id": "The authorization procedure failed to complete",
+ "message": "The authorization procedure failed to complete",
+ "translation": ""
+ },
+ {
+ "id": "No suitable profiles could be found",
+ "message": "No suitable profiles could be found",
+ "translation": ""
+ },
+ {
+ "id": "Profile with ID: '{PID}' could not be set",
+ "message": "Profile with ID: '{PID}' could not be set",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "PID",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "pID"
+ }
+ ]
+ },
+ {
+ "id": "Profile with ID: '{PID}' could not be obtained from the server",
+ "message": "Profile with ID: '{PID}' could not be obtained from the server",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "PID",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "pID"
+ }
+ ]
+ },
+ {
+ "id": "The identifier that was passed to the library is incorrect",
+ "message": "The identifier that was passed to the library is incorrect",
+ "translation": ""
+ },
+ {
+ "id": "Could not retrieve institute access server with URL: '{Identifier}' from discovery",
+ "message": "Could not retrieve institute access server with URL: '{Identifier}' from discovery",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The institute access server with URL: '{Identifier}' could not be added",
+ "message": "The institute access server with URL: '{Identifier}' could not be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The secure internet server with organisation ID: '{Identifier}' could not be retrieved from discovery",
+ "message": "The secure internet server with organisation ID: '{Identifier}' could not be retrieved from discovery",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The secure internet server with organisation ID: '{Identifier}' could not be added",
+ "message": "The secure internet server with organisation ID: '{Identifier}' could not be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The custom server with URL: '{Identifier}' could not be added",
+ "message": "The custom server with URL: '{Identifier}' could not be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "Server type: '{Type}' is not valid to be added",
+ "message": "Server type: '{Type}' is not valid to be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Type",
+ "string": "%[1]v",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 1,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "The VPN configuration could not be obtained",
+ "message": "The VPN configuration could not be obtained",
+ "translation": ""
+ },
+ {
+ "id": "The current profile could not be found",
+ "message": "The current profile could not be found",
+ "translation": ""
+ },
+ {
+ "id": "Not a valid server type: {Type}",
+ "message": "Not a valid server type: {Type}",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Type",
+ "string": "%[1]v",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 1,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid",
+ "message": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ },
+ {
+ "id": "Type",
+ "string": "%[2]d",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 2,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "The operation for getting a VPN configuration was canceled",
+ "message": "The operation for getting a VPN configuration was canceled",
+ "translation": ""
+ },
+ {
+ "id": "Failed to set the server with identifier: '{Identifier}' as the current",
+ "message": "Failed to set the server with identifier: '{Identifier}' as the current",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid for removal",
+ "message": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid for removal",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ },
+ {
+ "id": "Type",
+ "string": "%[2]d",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 2,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "Failed to get the current server to cleanup the connection",
+ "message": "Failed to get the current server to cleanup the connection",
+ "translation": ""
+ },
+ {
+ "id": "Failed to cleanup the VPN connection for the current server",
+ "message": "Failed to cleanup the VPN connection for the current server",
+ "translation": ""
+ },
+ {
+ "id": "Setting a secure internet location with Let's Connect! is not supported",
+ "message": "Setting a secure internet location with Let's Connect! is not supported",
+ "translation": ""
+ },
+ {
+ "id": "No secure internet server available to set a location for",
+ "message": "No secure internet server available to set a location for",
+ "translation": ""
+ },
+ {
+ "id": "Failed to get current server for renewing the session",
+ "message": "Failed to get current server for renewing the session",
+ "translation": ""
+ },
+ {
+ "id": "Failover failed to complete with gateway: '{Gateway}' and mtu: '{Mtu}'",
+ "message": "Failover failed to complete with gateway: '{Gateway}' and mtu: '{Mtu}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Gateway",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "gateway"
+ },
+ {
+ "id": "Mtu",
+ "string": "%[2]d",
+ "type": "int",
+ "underlyingType": "int",
+ "argNum": 2,
+ "expr": "mtu"
+ }
+ ]
+ },
+ {
+ "id": "Failed internal state transition requested by the client from: '{StateNamecurr}' to '{StateNamestate}'",
+ "message": "Failed internal state transition requested by the client from: '{StateNamecurr}' to '{StateNamestate}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "StateNamecurr",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "GetStateName(curr)"
+ },
+ {
+ "id": "StateNamestate",
+ "string": "%[2]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 2,
+ "expr": "GetStateName(state)"
+ }
+ ]
+ },
+ {
+ "id": "timeout reached",
+ "message": "timeout reached",
+ "translation": ""
+ },
+ {
+ "id": "with cause:",
+ "message": "with cause:",
+ "translation": ""
+ }
+ ]
+} \ No newline at end of file
diff --git a/client/locales/nl/messages.gotext.json b/client/locales/nl/messages.gotext.json
new file mode 100644
index 0000000..58411b9
--- /dev/null
+++ b/client/locales/nl/messages.gotext.json
@@ -0,0 +1,392 @@
+{
+ "language": "nl",
+ "messages": [
+ {
+ "id": "Internal state transition error",
+ "message": "Internal state transition error",
+ "translation": ""
+ },
+ {
+ "id": "The client registered with an invalid client ID: '{Name}'",
+ "message": "The client registered with an invalid client ID: '{Name}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Name",
+ "string": "%[1]v",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "name"
+ }
+ ]
+ },
+ {
+ "id": "The client registered with an invalid version: '{Version}'",
+ "message": "The client registered with an invalid version: '{Version}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Version",
+ "string": "%[1]v",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "version"
+ }
+ ]
+ },
+ {
+ "id": "The log file with directory: '{Directory}' failed to initialize",
+ "message": "The log file with directory: '{Directory}' failed to initialize",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Directory",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "directory"
+ }
+ ]
+ },
+ {
+ "id": "Client has an invalid state",
+ "message": "Client has an invalid state",
+ "translation": ""
+ },
+ {
+ "id": "Server/organization discovery with Let's Connect is not supported",
+ "message": "Server/organization discovery with Let's Connect is not supported",
+ "translation": ""
+ },
+ {
+ "id": "An error occurred after getting the discovery files for the list of organizations",
+ "message": "An error occurred after getting the discovery files for the list of organizations",
+ "translation": ""
+ },
+ {
+ "id": "An error occurred after getting the discovery files for the list of servers",
+ "message": "An error occurred after getting the discovery files for the list of servers",
+ "translation": ""
+ },
+ {
+ "id": "The current server could not be found when getting it for expiry",
+ "message": "The current server could not be found when getting it for expiry",
+ "translation": ""
+ },
+ {
+ "id": "The secure internet location could not be set",
+ "message": "The secure internet location could not be set",
+ "translation": ""
+ },
+ {
+ "id": "The authorization procedure failed to complete",
+ "message": "The authorization procedure failed to complete",
+ "translation": ""
+ },
+ {
+ "id": "No suitable profiles could be found",
+ "message": "No suitable profiles could be found",
+ "translation": ""
+ },
+ {
+ "id": "Profile with ID: '{PID}' could not be set",
+ "message": "Profile with ID: '{PID}' could not be set",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "PID",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "pID"
+ }
+ ]
+ },
+ {
+ "id": "Profile with ID: '{PID}' could not be obtained from the server",
+ "message": "Profile with ID: '{PID}' could not be obtained from the server",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "PID",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "pID"
+ }
+ ]
+ },
+ {
+ "id": "The identifier that was passed to the library is incorrect",
+ "message": "The identifier that was passed to the library is incorrect",
+ "translation": ""
+ },
+ {
+ "id": "Could not retrieve institute access server with URL: '{Identifier}' from discovery",
+ "message": "Could not retrieve institute access server with URL: '{Identifier}' from discovery",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The institute access server with URL: '{Identifier}' could not be added",
+ "message": "The institute access server with URL: '{Identifier}' could not be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The secure internet server with organisation ID: '{Identifier}' could not be retrieved from discovery",
+ "message": "The secure internet server with organisation ID: '{Identifier}' could not be retrieved from discovery",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The secure internet server with organisation ID: '{Identifier}' could not be added",
+ "message": "The secure internet server with organisation ID: '{Identifier}' could not be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The custom server with URL: '{Identifier}' could not be added",
+ "message": "The custom server with URL: '{Identifier}' could not be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "Server type: '{Type}' is not valid to be added",
+ "message": "Server type: '{Type}' is not valid to be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Type",
+ "string": "%[1]v",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 1,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "The VPN configuration could not be obtained",
+ "message": "The VPN configuration could not be obtained",
+ "translation": ""
+ },
+ {
+ "id": "The current profile could not be found",
+ "message": "The current profile could not be found",
+ "translation": ""
+ },
+ {
+ "id": "Not a valid server type: {Type}",
+ "message": "Not a valid server type: {Type}",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Type",
+ "string": "%[1]v",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 1,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid",
+ "message": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ },
+ {
+ "id": "Type",
+ "string": "%[2]d",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 2,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "The operation for getting a VPN configuration was canceled",
+ "message": "The operation for getting a VPN configuration was canceled",
+ "translation": ""
+ },
+ {
+ "id": "Failed to set the server with identifier: '{Identifier}' as the current",
+ "message": "Failed to set the server with identifier: '{Identifier}' as the current",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid for removal",
+ "message": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid for removal",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ },
+ {
+ "id": "Type",
+ "string": "%[2]d",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 2,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "Failed to get the current server to cleanup the connection",
+ "message": "Failed to get the current server to cleanup the connection",
+ "translation": ""
+ },
+ {
+ "id": "Failed to cleanup the VPN connection for the current server",
+ "message": "Failed to cleanup the VPN connection for the current server",
+ "translation": ""
+ },
+ {
+ "id": "Setting a secure internet location with Let's Connect! is not supported",
+ "message": "Setting a secure internet location with Let's Connect! is not supported",
+ "translation": ""
+ },
+ {
+ "id": "No secure internet server available to set a location for",
+ "message": "No secure internet server available to set a location for",
+ "translation": ""
+ },
+ {
+ "id": "Failed to get current server for renewing the session",
+ "message": "Failed to get current server for renewing the session",
+ "translation": ""
+ },
+ {
+ "id": "Failover failed to complete with gateway: '{Gateway}' and mtu: '{Mtu}'",
+ "message": "Failover failed to complete with gateway: '{Gateway}' and mtu: '{Mtu}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Gateway",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "gateway"
+ },
+ {
+ "id": "Mtu",
+ "string": "%[2]d",
+ "type": "int",
+ "underlyingType": "int",
+ "argNum": 2,
+ "expr": "mtu"
+ }
+ ]
+ },
+ {
+ "id": "Failed internal state transition requested by the client from: '{StateNamecurr}' to '{StateNamestate}'",
+ "message": "Failed internal state transition requested by the client from: '{StateNamecurr}' to '{StateNamestate}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "StateNamecurr",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "GetStateName(curr)"
+ },
+ {
+ "id": "StateNamestate",
+ "string": "%[2]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 2,
+ "expr": "GetStateName(state)"
+ }
+ ]
+ },
+ {
+ "id": "timeout reached",
+ "message": "timeout reached",
+ "translation": ""
+ },
+ {
+ "id": "with cause:",
+ "message": "with cause:",
+ "translation": ""
+ }
+ ]
+} \ No newline at end of file
diff --git a/client/locales/uk/messages.gotext.json b/client/locales/uk/messages.gotext.json
new file mode 100644
index 0000000..55cd77f
--- /dev/null
+++ b/client/locales/uk/messages.gotext.json
@@ -0,0 +1,392 @@
+{
+ "language": "uk",
+ "messages": [
+ {
+ "id": "Internal state transition error",
+ "message": "Internal state transition error",
+ "translation": ""
+ },
+ {
+ "id": "The client registered with an invalid client ID: '{Name}'",
+ "message": "The client registered with an invalid client ID: '{Name}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Name",
+ "string": "%[1]v",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "name"
+ }
+ ]
+ },
+ {
+ "id": "The client registered with an invalid version: '{Version}'",
+ "message": "The client registered with an invalid version: '{Version}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Version",
+ "string": "%[1]v",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "version"
+ }
+ ]
+ },
+ {
+ "id": "The log file with directory: '{Directory}' failed to initialize",
+ "message": "The log file with directory: '{Directory}' failed to initialize",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Directory",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "directory"
+ }
+ ]
+ },
+ {
+ "id": "Client has an invalid state",
+ "message": "Client has an invalid state",
+ "translation": ""
+ },
+ {
+ "id": "Server/organization discovery with Let's Connect is not supported",
+ "message": "Server/organization discovery with Let's Connect is not supported",
+ "translation": ""
+ },
+ {
+ "id": "An error occurred after getting the discovery files for the list of organizations",
+ "message": "An error occurred after getting the discovery files for the list of organizations",
+ "translation": ""
+ },
+ {
+ "id": "An error occurred after getting the discovery files for the list of servers",
+ "message": "An error occurred after getting the discovery files for the list of servers",
+ "translation": ""
+ },
+ {
+ "id": "The current server could not be found when getting it for expiry",
+ "message": "The current server could not be found when getting it for expiry",
+ "translation": ""
+ },
+ {
+ "id": "The secure internet location could not be set",
+ "message": "The secure internet location could not be set",
+ "translation": ""
+ },
+ {
+ "id": "The authorization procedure failed to complete",
+ "message": "The authorization procedure failed to complete",
+ "translation": ""
+ },
+ {
+ "id": "No suitable profiles could be found",
+ "message": "No suitable profiles could be found",
+ "translation": ""
+ },
+ {
+ "id": "Profile with ID: '{PID}' could not be set",
+ "message": "Profile with ID: '{PID}' could not be set",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "PID",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "pID"
+ }
+ ]
+ },
+ {
+ "id": "Profile with ID: '{PID}' could not be obtained from the server",
+ "message": "Profile with ID: '{PID}' could not be obtained from the server",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "PID",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "pID"
+ }
+ ]
+ },
+ {
+ "id": "The identifier that was passed to the library is incorrect",
+ "message": "The identifier that was passed to the library is incorrect",
+ "translation": ""
+ },
+ {
+ "id": "Could not retrieve institute access server with URL: '{Identifier}' from discovery",
+ "message": "Could not retrieve institute access server with URL: '{Identifier}' from discovery",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The institute access server with URL: '{Identifier}' could not be added",
+ "message": "The institute access server with URL: '{Identifier}' could not be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The secure internet server with organisation ID: '{Identifier}' could not be retrieved from discovery",
+ "message": "The secure internet server with organisation ID: '{Identifier}' could not be retrieved from discovery",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The secure internet server with organisation ID: '{Identifier}' could not be added",
+ "message": "The secure internet server with organisation ID: '{Identifier}' could not be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "The custom server with URL: '{Identifier}' could not be added",
+ "message": "The custom server with URL: '{Identifier}' could not be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "Server type: '{Type}' is not valid to be added",
+ "message": "Server type: '{Type}' is not valid to be added",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Type",
+ "string": "%[1]v",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 1,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "The VPN configuration could not be obtained",
+ "message": "The VPN configuration could not be obtained",
+ "translation": ""
+ },
+ {
+ "id": "The current profile could not be found",
+ "message": "The current profile could not be found",
+ "translation": ""
+ },
+ {
+ "id": "Not a valid server type: {Type}",
+ "message": "Not a valid server type: {Type}",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Type",
+ "string": "%[1]v",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 1,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid",
+ "message": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ },
+ {
+ "id": "Type",
+ "string": "%[2]d",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 2,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "The operation for getting a VPN configuration was canceled",
+ "message": "The operation for getting a VPN configuration was canceled",
+ "translation": ""
+ },
+ {
+ "id": "Failed to set the server with identifier: '{Identifier}' as the current",
+ "message": "Failed to set the server with identifier: '{Identifier}' as the current",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ }
+ ]
+ },
+ {
+ "id": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid for removal",
+ "message": "Identifier: '{Identifier}' for server with type: '{Type}' is not valid for removal",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Identifier",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "identifier"
+ },
+ {
+ "id": "Type",
+ "string": "%[2]d",
+ "type": "github.com/eduvpn/eduvpn-common/types/server.Type",
+ "underlyingType": "int8",
+ "argNum": 2,
+ "expr": "_type"
+ }
+ ]
+ },
+ {
+ "id": "Failed to get the current server to cleanup the connection",
+ "message": "Failed to get the current server to cleanup the connection",
+ "translation": ""
+ },
+ {
+ "id": "Failed to cleanup the VPN connection for the current server",
+ "message": "Failed to cleanup the VPN connection for the current server",
+ "translation": ""
+ },
+ {
+ "id": "Setting a secure internet location with Let's Connect! is not supported",
+ "message": "Setting a secure internet location with Let's Connect! is not supported",
+ "translation": ""
+ },
+ {
+ "id": "No secure internet server available to set a location for",
+ "message": "No secure internet server available to set a location for",
+ "translation": ""
+ },
+ {
+ "id": "Failed to get current server for renewing the session",
+ "message": "Failed to get current server for renewing the session",
+ "translation": ""
+ },
+ {
+ "id": "Failover failed to complete with gateway: '{Gateway}' and mtu: '{Mtu}'",
+ "message": "Failover failed to complete with gateway: '{Gateway}' and mtu: '{Mtu}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "Gateway",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "gateway"
+ },
+ {
+ "id": "Mtu",
+ "string": "%[2]d",
+ "type": "int",
+ "underlyingType": "int",
+ "argNum": 2,
+ "expr": "mtu"
+ }
+ ]
+ },
+ {
+ "id": "Failed internal state transition requested by the client from: '{StateNamecurr}' to '{StateNamestate}'",
+ "message": "Failed internal state transition requested by the client from: '{StateNamecurr}' to '{StateNamestate}'",
+ "translation": "",
+ "placeholders": [
+ {
+ "id": "StateNamecurr",
+ "string": "%[1]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 1,
+ "expr": "GetStateName(curr)"
+ },
+ {
+ "id": "StateNamestate",
+ "string": "%[2]s",
+ "type": "string",
+ "underlyingType": "string",
+ "argNum": 2,
+ "expr": "GetStateName(state)"
+ }
+ ]
+ },
+ {
+ "id": "timeout reached",
+ "message": "timeout reached",
+ "translation": ""
+ },
+ {
+ "id": "with cause:",
+ "message": "with cause:",
+ "translation": ""
+ }
+ ]
+} \ No newline at end of file
diff --git a/client/zgotext.go b/client/zgotext.go
new file mode 100644
index 0000000..b1720a4
--- /dev/null
+++ b/client/zgotext.go
@@ -0,0 +1,272 @@
+// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
+
+package client
+
+import (
+ "golang.org/x/text/language"
+ "golang.org/x/text/message"
+ "golang.org/x/text/message/catalog"
+)
+
+type dictionary struct {
+ index []uint32
+ data string
+}
+
+func (d *dictionary) Lookup(key string) (data string, ok bool) {
+ p, ok := messageKeyToIndex[key]
+ if !ok {
+ return "", false
+ }
+ start, end := d.index[p], d.index[p+1]
+ if start == end {
+ return "", false
+ }
+ return d.data[start:end], true
+}
+
+func init() {
+ dict := map[string]catalog.Dictionary{
+ "da": &dictionary{index: daIndex, data: daData},
+ "de": &dictionary{index: deIndex, data: deData},
+ "dnk": &dictionary{index: dnkIndex, data: dnkData},
+ "en": &dictionary{index: enIndex, data: enData},
+ "es": &dictionary{index: esIndex, data: esData},
+ "fr": &dictionary{index: frIndex, data: frData},
+ "it": &dictionary{index: itIndex, data: itData},
+ "nl": &dictionary{index: nlIndex, data: nlData},
+ "uk": &dictionary{index: ukIndex, data: ukData},
+ }
+ fallback := language.MustParse("en")
+ cat, err := catalog.NewFromMap(dict, catalog.Fallback(fallback))
+ if err != nil {
+ panic(err)
+ }
+ message.DefaultCatalog = cat
+}
+
+var messageKeyToIndex = map[string]int{
+ "An error occurred after getting the discovery files for the list of organizations": 6,
+ "An error occurred after getting the discovery files for the list of servers": 7,
+ "Client has an invalid state": 4,
+ "Could not retrieve institute access server with URL: '%s' from discovery": 15,
+ "Failed internal state transition requested by the client from: '%s' to '%s'": 34,
+ "Failed to cleanup the VPN connection for the current server": 29,
+ "Failed to get current server for renewing the session": 32,
+ "Failed to get the current server to cleanup the connection": 28,
+ "Failed to set the server with identifier: '%s' as the current": 26,
+ "Failover failed to complete with gateway: '%s' and mtu: '%d'": 33,
+ "Identifier: '%s' for server with type: '%d' is not valid": 24,
+ "Identifier: '%s' for server with type: '%d' is not valid for removal": 27,
+ "Internal state transition error": 0,
+ "No secure internet server available to set a location for": 31,
+ "No suitable profiles could be found": 11,
+ "Not a valid server type: %v": 23,
+ "Profile with ID: '%s' could not be obtained from the server": 13,
+ "Profile with ID: '%s' could not be set": 12,
+ "Server type: '%v' is not valid to be added": 20,
+ "Server/organization discovery with Let's Connect is not supported": 5,
+ "Setting a secure internet location with Let's Connect! is not supported": 30,
+ "The VPN configuration could not be obtained": 21,
+ "The authorization procedure failed to complete": 10,
+ "The client registered with an invalid client ID: '%v'": 1,
+ "The client registered with an invalid version: '%v'": 2,
+ "The current profile could not be found": 22,
+ "The current server could not be found when getting it for expiry": 8,
+ "The custom server with URL: '%s' could not be added": 19,
+ "The identifier that was passed to the library is incorrect": 14,
+ "The institute access server with URL: '%s' could not be added": 16,
+ "The log file with directory: '%s' failed to initialize": 3,
+ "The operation for getting a VPN configuration was canceled": 25,
+ "The secure internet location could not be set": 9,
+ "The secure internet server with organisation ID: '%s' could not be added": 18,
+ "The secure internet server with organisation ID: '%s' could not be retrieved from discovery": 17,
+ "timeout reached": 35,
+ "with cause:": 36,
+}
+
+var daIndex = []uint32{ // 38 elements
+ // Entry 0 - 1F
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ // Entry 20 - 3F
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000,
+} // Size: 176 bytes
+
+const daData string = ""
+
+var deIndex = []uint32{ // 38 elements
+ // Entry 0 - 1F
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ // Entry 20 - 3F
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000,
+} // Size: 176 bytes
+
+const deData string = ""
+
+var dnkIndex = []uint32{ // 38 elements
+ // Entry 0 - 1F
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ // Entry 20 - 3F
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000,
+} // Size: 176 bytes
+
+const dnkData string = ""
+
+var enIndex = []uint32{ // 38 elements
+ // Entry 0 - 1F
+ 0x00000000, 0x00000020, 0x00000059, 0x00000090,
+ 0x000000ca, 0x000000e6, 0x00000128, 0x0000017a,
+ 0x000001c6, 0x00000207, 0x00000235, 0x00000264,
+ 0x00000288, 0x000002b2, 0x000002f1, 0x0000032c,
+ 0x00000378, 0x000003b9, 0x00000418, 0x00000464,
+ 0x0000049b, 0x000004c9, 0x000004f5, 0x0000051c,
+ 0x0000053b, 0x0000057a, 0x000005b5, 0x000005f6,
+ 0x00000641, 0x0000067c, 0x000006b8, 0x00000700,
+ // Entry 20 - 3F
+ 0x0000073a, 0x00000770, 0x000007b3, 0x00000805,
+ 0x00000815, 0x00000821,
+} // Size: 176 bytes
+
+const enData string = "" + // Size: 2081 bytes
+ "\x02Internal state transition error\x02The client registered with an inv" +
+ "alid client ID: '%[1]v'\x02The client registered with an invalid version" +
+ ": '%[1]v'\x02The log file with directory: '%[1]s' failed to initialize" +
+ "\x02Client has an invalid state\x02Server/organization discovery with Le" +
+ "t's Connect is not supported\x02An error occurred after getting the disc" +
+ "overy files for the list of organizations\x02An error occurred after get" +
+ "ting the discovery files for the list of servers\x02The current server c" +
+ "ould not be found when getting it for expiry\x02The secure internet loca" +
+ "tion could not be set\x02The authorization procedure failed to complete" +
+ "\x02No suitable profiles could be found\x02Profile with ID: '%[1]s' coul" +
+ "d not be set\x02Profile with ID: '%[1]s' could not be obtained from the " +
+ "server\x02The identifier that was passed to the library is incorrect\x02" +
+ "Could not retrieve institute access server with URL: '%[1]s' from discov" +
+ "ery\x02The institute access server with URL: '%[1]s' could not be added" +
+ "\x02The secure internet server with organisation ID: '%[1]s' could not b" +
+ "e retrieved from discovery\x02The secure internet server with organisati" +
+ "on ID: '%[1]s' could not be added\x02The custom server with URL: '%[1]s'" +
+ " could not be added\x02Server type: '%[1]v' is not valid to be added\x02" +
+ "The VPN configuration could not be obtained\x02The current profile could" +
+ " not be found\x02Not a valid server type: %[1]v\x02Identifier: '%[1]s' f" +
+ "or server with type: '%[2]d' is not valid\x02The operation for getting a" +
+ " VPN configuration was canceled\x02Failed to set the server with identif" +
+ "ier: '%[1]s' as the current\x02Identifier: '%[1]s' for server with type:" +
+ " '%[2]d' is not valid for removal\x02Failed to get the current server to" +
+ " cleanup the connection\x02Failed to cleanup the VPN connection for the " +
+ "current server\x02Setting a secure internet location with Let's Connect!" +
+ " is not supported\x02No secure internet server available to set a locati" +
+ "on for\x02Failed to get current server for renewing the session\x02Failo" +
+ "ver failed to complete with gateway: '%[1]s' and mtu: '%[2]d'\x02Failed " +
+ "internal state transition requested by the client from: '%[1]s' to '%[2]" +
+ "s'\x02timeout reached\x02with cause:"
+
+var esIndex = []uint32{ // 38 elements
+ // Entry 0 - 1F
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ // Entry 20 - 3F
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000,
+} // Size: 176 bytes
+
+const esData string = ""
+
+var frIndex = []uint32{ // 38 elements
+ // Entry 0 - 1F
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ // Entry 20 - 3F
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000,
+} // Size: 176 bytes
+
+const frData string = ""
+
+var itIndex = []uint32{ // 38 elements
+ // Entry 0 - 1F
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ // Entry 20 - 3F
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000,
+} // Size: 176 bytes
+
+const itData string = ""
+
+var nlIndex = []uint32{ // 38 elements
+ // Entry 0 - 1F
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ // Entry 20 - 3F
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000,
+} // Size: 176 bytes
+
+const nlData string = ""
+
+var ukIndex = []uint32{ // 38 elements
+ // Entry 0 - 1F
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ // Entry 20 - 3F
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000,
+} // Size: 176 bytes
+
+const ukData string = ""
+
+// Total table size 3665 bytes (3KiB); checksum: 21098CA7
diff --git a/exports/exports.go b/exports/exports.go
index 0e557fa..4a92f1a 100644
--- a/exports/exports.go
+++ b/exports/exports.go
@@ -1,6 +1,6 @@
// package main implements the main exported API to be used by other languages
// Some notes:
-// - Errors are returned as c strings, free them using FreeString. Same is the case for other string types, you should also free them
+// - Errors are returned as JSON c strings. The JSON type is defined in types/error/error.go Error. Free them using FreeString. Same is the case for other string types, you should also free them
// - Types are converted from the Go representation to C using JSON strings
// - Cookies are used for cancellation, just fancy contexts. Create a cookie using `CookieNew`, pass it to the function that needs one as the first argument. To cancel the function, call `CookieCancel`, passing in the same cookie as argument
// - Cookies must also be freed, by using the CookieDelete function if the cookie is no longer needed
@@ -47,9 +47,11 @@ import (
"github.com/go-errors/errors"
"github.com/eduvpn/eduvpn-common/client"
+ "github.com/eduvpn/eduvpn-common/i18nerr"
"github.com/eduvpn/eduvpn-common/internal/log"
"github.com/eduvpn/eduvpn-common/types/cookie"
srvtypes "github.com/eduvpn/eduvpn-common/types/server"
+ errtypes "github.com/eduvpn/eduvpn-common/types/error"
)
var VPNState *client.Client
@@ -58,7 +60,22 @@ func getCError(err error) *C.char {
if err == nil {
return nil
}
- return C.CString(err.Error())
+ retErr := errtypes.Error{
+ Message: errtypes.Translated{
+ "en": err.Error(),
+ },
+ Misc: false,
+ }
+ v, ok := err.(*i18nerr.Error)
+ if ok {
+ retErr.Message = v.Translations()
+ retErr.Misc = v.Misc
+ }
+ retData, err := getReturnData(retErr)
+ if err != nil {
+ return C.CString("failed to get error return")
+ }
+ return C.CString(retData)
}
func getReturnData(data interface{}) (string, error) {
@@ -112,7 +129,7 @@ func getVPNState() (*client.Client, error) {
// - Write the state graph to a file in the configDirectory. This can be used to create a FSM png file with mermaid https://mermaid.js.org/
//
// After registering, the FSM is initialized and the state transition NO_SERVER should have been completed
-// If some error occurs during registering, it is returned as a C string
+// If some error occurs during registering, it is returned as a types/error/error.go Error
//
//export Register
func Register(
@@ -157,7 +174,7 @@ func Register(
// Expiry times are just fields that represent unix timestamps at which to do certain events regarding expiry,
// e.g. when to show the renew button, when to show expiry notifications
// The expiry times structure is defined in types/server/server.go `Expiry`
-// If some error occurs during registering, it is returned as a C string
+// If some error occurs, it is returned as types/error/error.go Error
//
//export ExpiryTimes
func ExpiryTimes() (*C.char, *C.char) {
@@ -203,7 +220,7 @@ func Deregister() *C.char {
//
// ni stands for non-interactive. If non-zero, any state transitions will not be run.
// This ni flag is useful for preprovisioned servers. For normal usage, you want to set this to zero (meaning: False)
-// If the server cannot be added it returns the error as a string
+// If the server cannot be added it returns the error as types/error/error.go Error
// Note that the server is removed when an error has occured
// The following state callbacks are mandatory to handle:
// - OAUTH_STARTED: This indicates that the OAuth procedure has been started, it returns the URL as the data.
@@ -230,7 +247,7 @@ func AddServer(c C.uintptr_t, _type C.int, id *C.char, ni C.int) *C.char {
// - In case of secure internet: The organization ID
// - In case of custom server: The base URL
// - In case of institute access: The base URL
-// If the server cannot be removed it returns the error as a string
+// If the server cannot be removed it returns the error types/error/error.go Error
// Note that the server is not removed when an error has occured
//
//export RemoveServer
@@ -295,7 +312,7 @@ func ServerList() (*C.char, *C.char) {
// - In case of custom server: The base URL
// - In case of institute access: The base URL
// pTCP is if we prefer TCP or not to get the configuration, non-zero means yes
-// If the server cannot be added it returns the error as a string
+// If the server cannot be added it returns the error as types/error/error.go Error
// Note that the server is removed when an error has occured
// The current state callbacks MUST be handled
// - ASK_PROFILE: This asks the client for profile.
@@ -329,7 +346,7 @@ func ServerList() (*C.char, *C.char) {
//
// After getting a configuration, the FSM moves to the GOT_CONFIG state
// The return data is the configuration, marshalled as JSON and defined in types/server/server.go Configuration
-// This is nil if an error is returned as a string
+// This is nil if an error is returned as types/error/error.go Error
//
//export GetConfig
func GetConfig(c C.uintptr_t, _type C.int, id *C.char, pTCP C.int) (*C.char, *C.char) {
diff --git a/go.mod b/go.mod
index 71b28ef..9d83c74 100644
--- a/go.mod
+++ b/go.mod
@@ -3,13 +3,20 @@ module github.com/eduvpn/eduvpn-common
go 1.18
require (
- github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267
+ github.com/jedisct1/go-minisign v0.0.0-20230513092556-d96eb068239a
+ github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8
+ golang.org/x/text v0.9.0
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
)
require (
+ golang.org/x/mod v0.8.0 // indirect
+ golang.org/x/tools v0.6.0 // indirect
+)
+
+require (
github.com/go-errors/errors v1.4.2
- golang.org/x/crypto v0.12.0 // indirect
- golang.org/x/net v0.14.0
- golang.org/x/sys v0.11.0 // indirect
+ golang.org/x/crypto v0.9.0 // indirect
+ golang.org/x/net v0.10.0
+ golang.org/x/sys v0.8.0 // indirect
)
diff --git a/go.sum b/go.sum
index b762812..db4b368 100644
--- a/go.sum
+++ b/go.sum
@@ -3,16 +3,15 @@ github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3Bop
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/jedisct1/go-minisign v0.0.0-20230211184525-1f273d8dc776 h1:WXhZ7psl6HhDDW58rDWIJE6oB0ETjaQA4U6d8U7lMyg=
github.com/jedisct1/go-minisign v0.0.0-20230211184525-1f273d8dc776/go.mod h1:09CTTv5TZgz94QHts03Xnuzy5LmxCE8BNqQRFigO5gA=
-github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 h1:TMtDYDHKYY15rFihtRfck/bfFqNfvcabqvXAFQfAUpY=
-github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267/go.mod h1:h1nSAbGFqGVzn6Jyl1R/iCcBUHN4g+gW1u9CoBTrb9E=
+github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
+github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
-golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
-golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
+golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
diff --git a/i18nerr/i18nerr.go b/i18nerr/i18nerr.go
new file mode 100644
index 0000000..813d287
--- /dev/null
+++ b/i18nerr/i18nerr.go
@@ -0,0 +1,145 @@
+// package i18nerr implements errors with internationalization using gotext
+package i18nerr
+
+import (
+ "context"
+ "errors"
+ "sync"
+
+ "github.com/eduvpn/eduvpn-common/internal/log"
+
+ "golang.org/x/text/language"
+ "golang.org/x/text/message"
+)
+
+var printers sync.Map
+var once sync.Once
+
+
+// TranslatedInner defines errors that are used as inner causes but are still translated because they can happen frequently
+func TranslatedInner(inner error) (string, bool) {
+ unwrapped := inner
+ for errors.Unwrap(unwrapped) != nil {
+ unwrapped = errors.Unwrap(unwrapped)
+ }
+
+ switch {
+ case errors.Is(inner, context.DeadlineExceeded):
+ return printerOrNew(language.English).Sprintf("timeout reached"), false
+ case errors.Is(inner, context.Canceled):
+ return unwrapped.Error(), true
+ }
+ return unwrapped.Error(), false
+}
+
+// Error wraps an actual error with the translation key
+// This translation key is later used to lookup translation
+// The inner error always consists of the translation key and some formatting
+type Error struct {
+ key message.Reference
+ args []interface{}
+ wrapped *Error
+ Misc bool
+}
+
+func (e *Error) translated(t language.Tag) string {
+ once.Do(func() {
+ inititializeLangs()
+ })
+ msg := printerOrNew(t).Sprintf(e.key, e.args)
+ if e.wrapped != nil {
+ return msg + " " + printerOrNew(t).Sprintf("with cause:") + " " + e.wrapped.Error()
+ }
+ return msg
+}
+
+// Error gets the error string
+// it does this by simply forwarding the error method from the actual inner error
+func (e *Error) Error() string {
+ return e.translated(language.English)
+}
+
+// Translations returns all the translations for the error including the source translation (english)
+func (e *Error) Translations() map[string]string {
+ translations := make(map[string]string)
+ // add the source transltaion first
+ source := e.Error()
+ translations[language.English.String()] = source
+ for _, t := range message.DefaultCatalog.Languages() {
+ // already added
+ if t == language.English {
+ continue
+ }
+ // get the final translation string for the tag
+ // and add it if it's not equal to the english version
+ f := e.translated(t)
+ if f != source {
+ translations[t.String()] = f
+ }
+ }
+ return translations
+}
+
+
+// Unwrap returns the unwrapped error
+// it does this by unwrapping the inner error
+func (e *Error) Unwrap() error {
+ if e.wrapped == nil {
+ return nil
+ }
+ return e.wrapped.Unwrap()
+}
+
+// printerOrNew gets a message printer from the global printers map using the tag 'tag'
+// If the printer cannot be found in the sync map, we return a new printer
+func printerOrNew(tag language.Tag) *message.Printer {
+ v, ok := printers.Load(tag)
+ if !ok {
+ log.Logger.Debugf("i18n: could not load printer with tag: '%v' from map", tag)
+ return message.NewPrinter(tag)
+ }
+ p, ok := v.(*message.Printer)
+ if !ok {
+ log.Logger.Debugf("i18n: could not load printer with tag: '%v' as the type is not correct: '%T'", tag, p)
+ return message.NewPrinter(tag)
+ }
+ return p
+}
+
+// New creates a new i18n error using a message reference
+func New(key message.Reference) *Error {
+ _ = printerOrNew(language.English).Sprint(key)
+ return &Error{key: key}
+}
+
+// Newf creates a new i18n error using a message reference and arguments.
+// It formats this with fmt.Errorf
+func Newf(key message.Reference, args ...interface{}) *Error {
+ _ = printerOrNew(language.English).Sprintf(key, args...)
+ return &Error{key: key, args: args}
+}
+
+// Wrap creates a new i18n error using an error to be wrapped 'err' and a prefix message reference 'key'.
+// It formats this with fmt.Errorf
+func Wrap(err error, key message.Reference) *Error {
+ _ = printerOrNew(language.English).Sprintf(key)
+ t, misc := TranslatedInner(err)
+ return &Error{key: key, wrapped: &Error{key: t, Misc: misc}, Misc: misc}
+}
+
+// Wrapf creates a new i18n error using an error to be wrapped 'err' and a prefix message reference 'key' with format arguments 'args'.
+// It formats this with fmt.Errorf
+func Wrapf(err error, key message.Reference, args ...interface{}) *Error {
+ _ = printerOrNew(language.English).Sprintf(key, args...)
+ t, misc := TranslatedInner(err)
+ return &Error{key: key, args: args, wrapped: &Error{key: t, Misc: misc}, Misc: misc}
+}
+
+// initializeLangs initializes the printers from the default catalog into the sync map
+// we cannot do this in init() because this is too early
+func inititializeLangs() {
+ log.Logger.Debugf("i18n: initializing languages...")
+ for _, t := range message.DefaultCatalog.Languages() {
+ printers.Store(t, message.NewPrinter(t))
+ }
+}
diff --git a/internal/server/server.go b/internal/server/server.go
index c34158a..45d6ccd 100644
--- a/internal/server/server.go
+++ b/internal/server/server.go
@@ -77,7 +77,7 @@ func CurrentProfile(srv Server) (*profile.Profile, error) {
return nil, errors.Errorf("profile not found: " + pID)
}
-func ValidProfiles(srv Server, wireguardSupport bool) (*[]profile.Profile, error) {
+func ValidProfiles(srv Server, wireguardSupport bool) (*profile.Info, error) {
// No error wrapping here otherwise we wrap it too much
b, err := srv.Base()
if err != nil {
@@ -87,7 +87,12 @@ func ValidProfiles(srv Server, wireguardSupport bool) (*[]profile.Profile, error
if len(ps) == 0 {
return nil, errors.Errorf("no profiles found with supported protocols")
}
- return &ps, nil
+ return &profile.Info{
+ Current: b.Profiles.Current,
+ Info: profile.ListInfo{
+ ProfileList: ps,
+ },
+ }, nil
}
func Profile(srv Server, id string) error {
@@ -190,6 +195,7 @@ func HasValidProfile(ctx context.Context, srv Server, wireguardSupport bool) (bo
}
}
+ // there are multiple profiles and no selection has been made
if len(b.Profiles.Info.ProfileList) != 1 && b.Profiles.Current == "" {
return false, nil
}
diff --git a/types/error/error.go b/types/error/error.go
new file mode 100644
index 0000000..9697e9d
--- /dev/null
+++ b/types/error/error.go
@@ -0,0 +1,24 @@
+package err
+
+// Translated defines the type for translated strings
+// It is a map from language tags to error messages
+type Translated map[string]string
+
+// Error is the struct that defines the public error types
+// This contains the error message with translations
+// And other info
+type Error struct {
+ // Message defines the error message
+ // It is a map from language tags to messages
+ // If a language is not translated, the whole language tag key is missing
+ // E.g. compare (english and french translations)
+ // {"en": "hello", "fr": "bonjour"}
+ // and
+ // {"en": "hello"}
+ // English is always present and should be used as a fallback
+ Message Translated `json:"message"`
+
+ // Misc indicates whether or not this error is only there for miscellaneous purposes
+ // If this is set to True, the client UI SHOULD NOT show this error
+ Misc bool `json:"misc"`
+}
diff --git a/wrappers/python/eduvpn_common/main.py b/wrappers/python/eduvpn_common/main.py
index f3639e0..335b78c 100644
--- a/wrappers/python/eduvpn_common/main.py
+++ b/wrappers/python/eduvpn_common/main.py
@@ -1,4 +1,5 @@
import ctypes
+import json
from enum import IntEnum
from typing import Any, Callable, Iterator, Optional
@@ -17,14 +18,19 @@ from eduvpn_common.state import State
class WrappedError(Exception):
- pass
+ def __init__(self, translations, language, misc):
+ self.translations = translations
+ self.language = language
+ self.misc = misc
+ def __str__(self) -> str:
+ print(self.translations)
+ return self.translations[self.language]
-def forwardError(error: bytes | str):
- # TODO: HACK, remove this
- if isinstance(error, str):
- raise WrappedError(error)
- raise WrappedError(error.decode("utf-8"))
+
+def forwardError(error: str):
+ d = json.loads(error)
+ raise WrappedError(d["message"], "en", d["misc"])
class ServerType(IntEnum):