From 33cb974d393cc69edced4f8e13b73a3882e34fec Mon Sep 17 00:00:00 2001 From: Nicko Guyer Date: Mon, 16 May 2022 16:19:16 -0400 Subject: [PATCH 1/4] Add language tag to FFM, FFE, FFC, etc Signed-off-by: Nicko Guyer --- pkg/config/config.go | 2 - pkg/config/config_test.go | 9 +- pkg/i18n/en_base_config_descriptions.go | 118 ++++++++++++------------ pkg/i18n/en_base_error_messages.go | 112 +++++++++++----------- pkg/i18n/messages.go | 62 +++++++------ pkg/i18n/messages_test.go | 54 ++++++++--- 6 files changed, 193 insertions(+), 164 deletions(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index 7410959..1b4b6af 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -150,8 +150,6 @@ func RootConfigReset(setServiceDefaults ...func()) { for _, fn := range setServiceDefaults { fn() } - - i18n.SetLang(viper.GetString(string(Lang))) } // ReadConfig initializes the config diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 984bb13..f9459f0 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -30,6 +30,7 @@ import ( "github.com/hyperledger/firefly-common/pkg/i18n" "github.com/spf13/viper" "github.com/stretchr/testify/assert" + "golang.org/x/text/language" ) const configDir = "../../test/data/config" @@ -314,10 +315,10 @@ func TestGenerateConfigMarkdown(t *testing.T) { key3 := AddRootKey("level1_1.level2_2.level3") key4 := AddRootKey("level1_2.level2.level3") - i18n.FFC(fmt.Sprintf("config.%s", key1), "Description 1", "Type 1") - i18n.FFC(fmt.Sprintf("config.%s", key2), "Description 2", "Type 2") - i18n.FFC("config.global.level2_2.level3", "Description 3", "Type 3") - i18n.FFC(fmt.Sprintf("config.%s", key4), "Description 4", "Type 4") + i18n.FFC(language.AmericanEnglish, fmt.Sprintf("config.%s", key1), "Description 1", "Type 1") + i18n.FFC(language.AmericanEnglish, fmt.Sprintf("config.%s", key2), "Description 2", "Type 2") + i18n.FFC(language.AmericanEnglish, "config.global.level2_2.level3", "Description 3", "Type 3") + i18n.FFC(language.AmericanEnglish, fmt.Sprintf("config.%s", key4), "Description 4", "Type 4") RootConfigReset(func() { viper.SetDefault(string(key1), "val1") diff --git a/pkg/i18n/en_base_config_descriptions.go b/pkg/i18n/en_base_config_descriptions.go index 07ded96..0e75c2a 100644 --- a/pkg/i18n/en_base_config_descriptions.go +++ b/pkg/i18n/en_base_config_descriptions.go @@ -16,6 +16,8 @@ package i18n +import "golang.org/x/text/language" + var TimeDurationType = "[`time.Duration`](https://pkg.go.dev/time#Duration)" var TimeFormatType = "[Time format](https://pkg.go.dev/time#pkg-constants) `string`" var ByteSizeType = "[`BytesSize`](https://pkg.go.dev/github.com/docker/go-units#BytesSize)" @@ -29,70 +31,70 @@ var IgnoredType = "IGNORE" //revive:disable var ( - ConfigGlobalConnectionTimeout = FFC("config.global.connectionTimeout", "The maximum amount of time that a connection is allowed to remain with no data transmitted", TimeDurationType) - ConfigGlobalRequestTimeout = FFC("config.global.requestTimeout", "The maximum amount of time that a request is allowed to remain open", TimeDurationType) + ConfigGlobalConnectionTimeout = FFC(language.AmericanEnglish, "config.global.connectionTimeout", "The maximum amount of time that a connection is allowed to remain with no data transmitted", TimeDurationType) + ConfigGlobalRequestTimeout = FFC(language.AmericanEnglish, "config.global.requestTimeout", "The maximum amount of time that a request is allowed to remain open", TimeDurationType) - ConfigGlobalRetryEnabled = FFC("config.global.retry.enabled", "Enables retries", BooleanType) - ConfigGlobalRetryFactor = FFC("config.global.retry.factor", "The retry backoff factor", FloatType) - ConfigGlobalRetryInitDelay = FFC("config.global.retry.initDelay", "The initial retry delay", TimeDurationType) - ConfigGlobalRetryInitialDelay = FFC("config.global.retry.initialDelay", "The initial retry delay", TimeDurationType) - ConfigGlobalRetryMaxDelay = FFC("config.global.retry.maxDelay", "The maximum retry delay", TimeDurationType) - ConfigGlobalRetryMaxAttempts = FFC("config.global.retry.maxAttempts", "The maximum number attempts", IntType) - ConfigGlobalRetryCount = FFC("config.global.retry.count", "The maximum number of times to retry", IntType) - ConfigGlobalInitWaitTime = FFC("config.global.retry.initWaitTime", "The initial retry delay", TimeDurationType) - ConfigGlobalMaxWaitTime = FFC("config.global.retry.maxWaitTime", "The maximum retry delay", TimeDurationType) + ConfigGlobalRetryEnabled = FFC(language.AmericanEnglish, "config.global.retry.enabled", "Enables retries", BooleanType) + ConfigGlobalRetryFactor = FFC(language.AmericanEnglish, "config.global.retry.factor", "The retry backoff factor", FloatType) + ConfigGlobalRetryInitDelay = FFC(language.AmericanEnglish, "config.global.retry.initDelay", "The initial retry delay", TimeDurationType) + ConfigGlobalRetryInitialDelay = FFC(language.AmericanEnglish, "config.global.retry.initialDelay", "The initial retry delay", TimeDurationType) + ConfigGlobalRetryMaxDelay = FFC(language.AmericanEnglish, "config.global.retry.maxDelay", "The maximum retry delay", TimeDurationType) + ConfigGlobalRetryMaxAttempts = FFC(language.AmericanEnglish, "config.global.retry.maxAttempts", "The maximum number attempts", IntType) + ConfigGlobalRetryCount = FFC(language.AmericanEnglish, "config.global.retry.count", "The maximum number of times to retry", IntType) + ConfigGlobalInitWaitTime = FFC(language.AmericanEnglish, "config.global.retry.initWaitTime", "The initial retry delay", TimeDurationType) + ConfigGlobalMaxWaitTime = FFC(language.AmericanEnglish, "config.global.retry.maxWaitTime", "The maximum retry delay", TimeDurationType) - ConfigGlobalUsername = FFC("config.global.auth.username", "Username", StringType) - ConfigGlobalPassword = FFC("config.global.auth.password", "Password", StringType) + ConfigGlobalUsername = FFC(language.AmericanEnglish, "config.global.auth.username", "Username", StringType) + ConfigGlobalPassword = FFC(language.AmericanEnglish, "config.global.auth.password", "Password", StringType) - ConfigGlobalSize = FFC("config.global.cache.size", "The size of the cache", ByteSizeType) - ConfigGlobalTTL = FFC("config.global.cache.ttl", "The time to live (TTL) for the cache", TimeDurationType) + ConfigGlobalSize = FFC(language.AmericanEnglish, "config.global.cache.size", "The size of the cache", ByteSizeType) + ConfigGlobalTTL = FFC(language.AmericanEnglish, "config.global.cache.ttl", "The time to live (TTL) for the cache", TimeDurationType) - ConfigGlobaltWsHeartbeatInterval = FFC("config.global.ws.heartbeatInterval", "The amount of time to wait between heartbeat signals on the WebSocket connection", TimeDurationType) - ConfigGlobalWsInitialConnectAttempts = FFC("config.global.ws.initialConnectAttempts", "The number of attempts FireFly will make to connect to the WebSocket when starting up, before failing", IntType) - ConfigGlobalWsPath = FFC("config.global.ws.path", "The WebSocket sever URL to which FireFly should connect", "WebSocket URL "+StringType) - ConfigGlobalWsReadBufferSize = FFC("config.global.ws.readBufferSize", "The size in bytes of the read buffer for the WebSocket connection", ByteSizeType) - ConfigGlobalWsWriteBufferSize = FFC("config.global.ws.writeBufferSize", "The size in bytes of the write buffer for the WebSocket connection", ByteSizeType) + ConfigGlobaltWsHeartbeatInterval = FFC(language.AmericanEnglish, "config.global.ws.heartbeatInterval", "The amount of time to wait between heartbeat signals on the WebSocket connection", TimeDurationType) + ConfigGlobalWsInitialConnectAttempts = FFC(language.AmericanEnglish, "config.global.ws.initialConnectAttempts", "The number of attempts FireFly will make to connect to the WebSocket when starting up, before failing", IntType) + ConfigGlobalWsPath = FFC(language.AmericanEnglish, "config.global.ws.path", "The WebSocket sever URL to which FireFly should connect", "WebSocket URL "+StringType) + ConfigGlobalWsReadBufferSize = FFC(language.AmericanEnglish, "config.global.ws.readBufferSize", "The size in bytes of the read buffer for the WebSocket connection", ByteSizeType) + ConfigGlobalWsWriteBufferSize = FFC(language.AmericanEnglish, "config.global.ws.writeBufferSize", "The size in bytes of the write buffer for the WebSocket connection", ByteSizeType) - ConfigGlobalTLSCaFile = FFC("config.global.tls.caFile", "The path to the CA file for TLS on this API", StringType) - ConfigGlobalTLSCertFile = FFC("config.global.tls.certFile", "The path to the certificate file for TLS on this API", StringType) - ConfigGlobalTLSClientAuth = FFC("config.global.tls.clientAuth", "Enables or disables client auth for TLS on this API", StringType) - ConfigGlobalTLSEnabled = FFC("config.global.tls.enabled", "Enables or disables TLS on this API", BooleanType) - ConfigGlobalTLSKeyFile = FFC("config.global.tls.keyFile", "The path to the private key file for TLS on this API", StringType) - ConfigGlobalTLSHandshakeTimeout = FFC("config.global.tlsHandshakeTimeout", "The maximum amount of time to wait for a successful TLS handshake", TimeDurationType) + ConfigGlobalTLSCaFile = FFC(language.AmericanEnglish, "config.global.tls.caFile", "The path to the CA file for TLS on this API", StringType) + ConfigGlobalTLSCertFile = FFC(language.AmericanEnglish, "config.global.tls.certFile", "The path to the certificate file for TLS on this API", StringType) + ConfigGlobalTLSClientAuth = FFC(language.AmericanEnglish, "config.global.tls.clientAuth", "Enables or disables client auth for TLS on this API", StringType) + ConfigGlobalTLSEnabled = FFC(language.AmericanEnglish, "config.global.tls.enabled", "Enables or disables TLS on this API", BooleanType) + ConfigGlobalTLSKeyFile = FFC(language.AmericanEnglish, "config.global.tls.keyFile", "The path to the private key file for TLS on this API", StringType) + ConfigGlobalTLSHandshakeTimeout = FFC(language.AmericanEnglish, "config.global.tlsHandshakeTimeout", "The maximum amount of time to wait for a successful TLS handshake", TimeDurationType) - ConfigGlobalBodyTemplate = FFC("config.global.bodyTemplate", "The body go template string to use when making HTTP requests", GoTemplateType) - ConfigGlobalCustomClient = FFC("config.global.customClient", "Used for testing purposes only", IgnoredType) - ConfigGlobalExpectContinueTimeout = FFC("config.global.expectContinueTimeout", "See [ExpectContinueTimeout in the Go docs](https://pkg.go.dev/net/http#Transport)", TimeDurationType) - ConfigGlobalHeaders = FFC("config.global.headers", "Adds custom headers to HTTP requests", MapStringStringType) - ConfigGlobalIdleTimeout = FFC("config.global.idleTimeout", "The max duration to hold a HTTP keepalive connection between calls", TimeDurationType) - ConfigGlobalMaxIdleConns = FFC("config.global.maxIdleConns", "The max number of idle connections to hold pooled", IntType) - ConfigGlobalMethod = FFC("config.global.method", "The HTTP method to use when making requests to the Address Resolver", StringType) + ConfigGlobalBodyTemplate = FFC(language.AmericanEnglish, "config.global.bodyTemplate", "The body go template string to use when making HTTP requests", GoTemplateType) + ConfigGlobalCustomClient = FFC(language.AmericanEnglish, "config.global.customClient", "Used for testing purposes only", IgnoredType) + ConfigGlobalExpectContinueTimeout = FFC(language.AmericanEnglish, "config.global.expectContinueTimeout", "See [ExpectContinueTimeout in the Go docs](https://pkg.go.dev/net/http#Transport)", TimeDurationType) + ConfigGlobalHeaders = FFC(language.AmericanEnglish, "config.global.headers", "Adds custom headers to HTTP requests", MapStringStringType) + ConfigGlobalIdleTimeout = FFC(language.AmericanEnglish, "config.global.idleTimeout", "The max duration to hold a HTTP keepalive connection between calls", TimeDurationType) + ConfigGlobalMaxIdleConns = FFC(language.AmericanEnglish, "config.global.maxIdleConns", "The max number of idle connections to hold pooled", IntType) + ConfigGlobalMethod = FFC(language.AmericanEnglish, "config.global.method", "The HTTP method to use when making requests to the Address Resolver", StringType) - ConfigLang = FFC("config.lang", "Default language for translation (API calls may support language override using headers)", StringType) - ConfigLogCompress = FFC("config.log.compress", "Determines if the rotated log files should be compressed using gzip", BooleanType) - ConfigLogFilename = FFC("config.log.filename", "Filename is the file to write logs to. Backup log files will be retained in the same directory", StringType) - ConfigLogFilesize = FFC("config.log.filesize", "MaxSize is the maximum size the log file before it gets rotated", ByteSizeType) - ConfigLogForceColor = FFC("config.log.forceColor", "Force color to be enabled, even when a non-TTY output is detected", BooleanType) - ConfigLogLevel = FFC("config.log.level", "The log level - error, warn, info, debug, trace", StringType) - ConfigLogMaxAge = FFC("config.log.maxAge", "The maximum time to retain old log files based on the timestamp encoded in their filename.", TimeDurationType) - ConfigLogMaxBackups = FFC("config.log.maxBackups", "Maximum number of old log files to retain", IntType) - ConfigLogNoColor = FFC("config.log.noColor", "Force color to be disabled, event when TTY output is detected", BooleanType) - ConfigLogTimeFormat = FFC("config.log.timeFormat", "Custom time format for logs", TimeFormatType) - ConfigLogUtc = FFC("config.log.utc", "Use UTC timestamps for logs", BooleanType) - ConfigLogIncludeCodeInfo = FFC("config.log.includeCodeInfo", "Enables the report caller for including the calling file and line number, and the calling function. If using text logs, it uses the logrus text format rather than the default prefix format.", BooleanType) - ConfigLogJSONEnabled = FFC("config.log.json.enabled", "Enables JSON formatted logs rather than text. All log color settings are ignored when enabled.", BooleanType) - ConfigLogJSONTimestampField = FFC("config.log.json.fields.timestamp", "Configures the JSON key containing the timestamp of the log", StringType) - ConfigLogJSONLevelField = FFC("config.log.json.fields.level", "Configures the JSON key containing the log level", StringType) - ConfigLogJSONMessageField = FFC("config.log.json.fields.message", "Configures the JSON key containing the log message", StringType) - ConfigLogJSONFuncField = FFC("config.log.json.fields.func", "Configures the JSON key containing the calling function", StringType) - ConfigLogJSONFileField = FFC("config.log.json.fields.file", "configures the JSON key containing the calling file", StringType) - ConfigCorsCredentials = FFC("config.cors.credentials", "CORS setting to control whether a browser allows credentials to be sent to this API", BooleanType) + ConfigLang = FFC(language.AmericanEnglish, "config.lang", "Default language for translation (API calls may support language override using headers)", StringType) + ConfigLogCompress = FFC(language.AmericanEnglish, "config.log.compress", "Determines if the rotated log files should be compressed using gzip", BooleanType) + ConfigLogFilename = FFC(language.AmericanEnglish, "config.log.filename", "Filename is the file to write logs to. Backup log files will be retained in the same directory", StringType) + ConfigLogFilesize = FFC(language.AmericanEnglish, "config.log.filesize", "MaxSize is the maximum size the log file before it gets rotated", ByteSizeType) + ConfigLogForceColor = FFC(language.AmericanEnglish, "config.log.forceColor", "Force color to be enabled, even when a non-TTY output is detected", BooleanType) + ConfigLogLevel = FFC(language.AmericanEnglish, "config.log.level", "The log level - error, warn, info, debug, trace", StringType) + ConfigLogMaxAge = FFC(language.AmericanEnglish, "config.log.maxAge", "The maximum time to retain old log files based on the timestamp encoded in their filename.", TimeDurationType) + ConfigLogMaxBackups = FFC(language.AmericanEnglish, "config.log.maxBackups", "Maximum number of old log files to retain", IntType) + ConfigLogNoColor = FFC(language.AmericanEnglish, "config.log.noColor", "Force color to be disabled, event when TTY output is detected", BooleanType) + ConfigLogTimeFormat = FFC(language.AmericanEnglish, "config.log.timeFormat", "Custom time format for logs", TimeFormatType) + ConfigLogUtc = FFC(language.AmericanEnglish, "config.log.utc", "Use UTC timestamps for logs", BooleanType) + ConfigLogIncludeCodeInfo = FFC(language.AmericanEnglish, "config.log.includeCodeInfo", "Enables the report caller for including the calling file and line number, and the calling function. If using text logs, it uses the logrus text format rather than the default prefix format.", BooleanType) + ConfigLogJSONEnabled = FFC(language.AmericanEnglish, "config.log.json.enabled", "Enables JSON formatted logs rather than text. All log color settings are ignored when enabled.", BooleanType) + ConfigLogJSONTimestampField = FFC(language.AmericanEnglish, "config.log.json.fields.timestamp", "Configures the JSON key containing the timestamp of the log", StringType) + ConfigLogJSONLevelField = FFC(language.AmericanEnglish, "config.log.json.fields.level", "Configures the JSON key containing the log level", StringType) + ConfigLogJSONMessageField = FFC(language.AmericanEnglish, "config.log.json.fields.message", "Configures the JSON key containing the log message", StringType) + ConfigLogJSONFuncField = FFC(language.AmericanEnglish, "config.log.json.fields.func", "Configures the JSON key containing the calling function", StringType) + ConfigLogJSONFileField = FFC(language.AmericanEnglish, "config.log.json.fields.file", "configures the JSON key containing the calling file", StringType) + ConfigCorsCredentials = FFC(language.AmericanEnglish, "config.cors.credentials", "CORS setting to control whether a browser allows credentials to be sent to this API", BooleanType) - ConfigCorsDebug = FFC("config.global.cors.debug", "Whether debug is enabled for the CORS implementation", BooleanType) - ConfigCorsEnabled = FFC("config.global.cors.enabled", "Whether CORS is enabled", BooleanType) - ConfigCorsHeaders = FFC("config.global.cors.headers", "CORS setting to control the allowed headers", StringType) - ConfigCorsMaxAge = FFC("config.global.cors.maxAge", "The maximum age a browser should rely on CORS checks", TimeDurationType) - ConfigCorsMethods = FFC("config.global.cors.methods", " CORS setting to control the allowed methods", StringType) - ConfigCorsOrigins = FFC("config.global.cors.origins", "CORS setting to control the allowed origins", StringType) + ConfigCorsDebug = FFC(language.AmericanEnglish, "config.global.cors.debug", "Whether debug is enabled for the CORS implementation", BooleanType) + ConfigCorsEnabled = FFC(language.AmericanEnglish, "config.global.cors.enabled", "Whether CORS is enabled", BooleanType) + ConfigCorsHeaders = FFC(language.AmericanEnglish, "config.global.cors.headers", "CORS setting to control the allowed headers", StringType) + ConfigCorsMaxAge = FFC(language.AmericanEnglish, "config.global.cors.maxAge", "The maximum age a browser should rely on CORS checks", TimeDurationType) + ConfigCorsMethods = FFC(language.AmericanEnglish, "config.global.cors.methods", " CORS setting to control the allowed methods", StringType) + ConfigCorsOrigins = FFC(language.AmericanEnglish, "config.global.cors.origins", "CORS setting to control the allowed origins", StringType) ) diff --git a/pkg/i18n/en_base_error_messages.go b/pkg/i18n/en_base_error_messages.go index ac1eaf4..b68c57a 100644 --- a/pkg/i18n/en_base_error_messages.go +++ b/pkg/i18n/en_base_error_messages.go @@ -16,6 +16,8 @@ package i18n +import "golang.org/x/text/language" + var ( registeredPrefixes = map[string]string{ "FF00": "FireFly Common Utilities", @@ -28,59 +30,59 @@ var ( //revive:disable var ( - MsgConfigFailed = FFE("FF00101", "Failed to read config", 500) - MsgBigIntTooLarge = FFE("FF00103", "Byte length of serialized integer is too large %d (max=%d)") - MsgBigIntParseFailed = FFE("FF00104", "Failed to parse JSON value '%s' into BigInt") - MsgTypeRestoreFailed = FFE("FF00105", "Failed to restore type '%T' into '%T'") - MsgInvalidHex = FFE("FF00106", "Invalid hex supplied", 400) - MsgInvalidWrongLenB32 = FFE("FF00107", "Byte length must be 32 (64 hex characters)", 400) - MsgUnknownValidatorType = FFE("FF00108", "Unknown validator type: '%s'", 400) - MsgDataValueIsNull = FFE("FF00109", "Data value is null", 400) - MsgBlobMismatchSealingData = FFE("FF00110", "Blob mismatch when sealing data") - MsgUnknownFieldValue = FFE("FF00111", "Unknown %s '%v'", 400) - MsgMissingRequiredField = FFE("FF00112", "Field '%s' is required", 400) - MsgDataInvalidHash = FFE("FF00113", "Invalid data: hashes do not match Hash=%s Expected=%s", 400) - MsgNilID = FFE("FF00114", "ID is nil") - MsgGroupMustHaveMembers = FFE("FF00115", "Group must have at least one member", 400) - MsgEmptyMemberIdentity = FFE("FF00116", "Identity is blank in member %d") - MsgEmptyMemberNode = FFE("FF00117", "Node is blank in member %d") - MsgDuplicateMember = FFE("FF00118", "Member %d is a duplicate org+node combination: %s", 400) - MsgGroupInvalidHash = FFE("FF00119", "Invalid group: hashes do not match Hash=%s Expected=%s", 400) - MsgInvalidDIDForType = FFE("FF00120", "Invalid FireFly DID '%s' for type='%s' namespace='%s' name='%s'", 400) - MsgCustomIdentitySystemNS = FFE("FF00121", "Custom identities cannot be defined in the '%s' namespace", 400) - MsgSystemIdentityCustomNS = FFE("FF00122", "System identities must be defined in the '%s' namespace", 400) - MsgNilParentIdentity = FFE("FF00124", "Identity of type '%s' must have a valid parent", 400) - MsgNilOrNullObject = FFE("FF00125", "Object is null") - MsgUnknownIdentityType = FFE("FF00126", "Unknown identity type: %s", 400) - MsgJSONObjectParseFailed = FFE("FF00127", "Failed to parse '%s' as JSON") - MsgNilDataReferenceSealFail = FFE("FF00128", "Invalid message: nil data reference at index %d", 400) - MsgDupDataReferenceSealFail = FFE("FF00129", "Invalid message: duplicate data reference at index %d", 400) - MsgInvalidTXTypeForMessage = FFE("FF00130", "Invalid transaction type for sending a message: %s", 400) - MsgVerifyFailedNilHashes = FFE("FF00131", "Invalid message: nil hashes", 400) - MsgVerifyFailedInvalidHashes = FFE("FF00132", "Invalid message: hashes do not match Hash=%s Expected=%s DataHash=%s DataHashExpected=%s", 400) - MsgDuplicateArrayEntry = FFE("FF00133", "Duplicate %s at index %d: '%s'", 400) - MsgTooManyItems = FFE("FF00134", "Maximum number of %s items is %d (supplied=%d)", 400) - MsgFieldTooLong = FFE("FF00135", "Field '%s' maximum length is %d", 400) - MsgTimeParseFail = FFE("FF00136", "Cannot parse time as RFC3339, Unix, or UnixNano: '%s'", 400) - MsgDurationParseFail = FFE("FF00137", "Unable to parse '%s' as duration string, or millisecond number", 400) - MsgInvalidUUID = FFE("FF00138", "Invalid UUID supplied", 400) - MsgSafeCharsOnly = FFE("FF00139", "Field '%s' must include only alphanumerics (a-zA-Z0-9), dot (.), dash (-) and underscore (_)", 400) - MsgInvalidName = FFE("FF00140", "Field '%s' must be 1-64 characters, including alphanumerics (a-zA-Z0-9), dot (.), dash (-) and underscore (_), and must start/end in an alphanumeric", 400) - MsgNoUUID = FFE("FF00141", "Field '%s' must not be a UUID", 400) - MsgInvalidFilterField = FFE("FF00142", "Unknown filter '%s'", 400) - MsgInvalidValueForFilterField = FFE("FF00143", "Unable to parse value for filter '%s'", 400) - MsgFieldMatchNoNull = FFE("FF00144", "Comparison operator for field '%s' cannot accept a null value", 400) - MsgFieldTypeNoStringMatching = FFE("FF00145", "Field '%s' of type '%s' does not support partial or case-insensitive string matching", 400) - MsgWSSendTimedOut = FFE("FF00146", "Websocket send timed out") - MsgWSClosing = FFE("FF00147", "Websocket closing") - MsgWSConnectFailed = FFE("FF00148", "Websocket connect failed") - MsgInvalidURL = FFE("FF00149", "Invalid URL: '%s'") - MsgWSHeartbeatTimeout = FFE("FF00150", "Websocket heartbeat timed out after %.2fms", 500) - MsgAPIServerStartFailed = FFE("FF00151", "Unable to start listener on %s: %s") - MsgInvalidCAFile = FFE("FF00152", "Invalid CA certificates file") - MsgTLSConfigFailed = FFE("FF00153", "Failed to initialize TLS configuration") - MsgContextCanceled = FFE("FF00154", "Context canceled") - MsgConnectorFailInvoke = FFE("FF00155", "Connector request failed. requestId=%s failed to call connector API") - MsgConnectorInvalidContentType = FFE("FF00156", "Connector request failed. requestId=%s invalid response content type: %s") - MsgConnectorError = FFE("FF00157", "Connector request failed. requestId=%s reason=%s error: %s") + MsgConfigFailed = FFE(language.AmericanEnglish, "FF00101", "Failed to read config", 500) + MsgBigIntTooLarge = FFE(language.AmericanEnglish, "FF00103", "Byte length of serialized integer is too large %d (max=%d)") + MsgBigIntParseFailed = FFE(language.AmericanEnglish, "FF00104", "Failed to parse JSON value '%s' into BigInt") + MsgTypeRestoreFailed = FFE(language.AmericanEnglish, "FF00105", "Failed to restore type '%T' into '%T'") + MsgInvalidHex = FFE(language.AmericanEnglish, "FF00106", "Invalid hex supplied", 400) + MsgInvalidWrongLenB32 = FFE(language.AmericanEnglish, "FF00107", "Byte length must be 32 (64 hex characters)", 400) + MsgUnknownValidatorType = FFE(language.AmericanEnglish, "FF00108", "Unknown validator type: '%s'", 400) + MsgDataValueIsNull = FFE(language.AmericanEnglish, "FF00109", "Data value is null", 400) + MsgBlobMismatchSealingData = FFE(language.AmericanEnglish, "FF00110", "Blob mismatch when sealing data") + MsgUnknownFieldValue = FFE(language.AmericanEnglish, "FF00111", "Unknown %s '%v'", 400) + MsgMissingRequiredField = FFE(language.AmericanEnglish, "FF00112", "Field '%s' is required", 400) + MsgDataInvalidHash = FFE(language.AmericanEnglish, "FF00113", "Invalid data: hashes do not match Hash=%s Expected=%s", 400) + MsgNilID = FFE(language.AmericanEnglish, "FF00114", "ID is nil") + MsgGroupMustHaveMembers = FFE(language.AmericanEnglish, "FF00115", "Group must have at least one member", 400) + MsgEmptyMemberIdentity = FFE(language.AmericanEnglish, "FF00116", "Identity is blank in member %d") + MsgEmptyMemberNode = FFE(language.AmericanEnglish, "FF00117", "Node is blank in member %d") + MsgDuplicateMember = FFE(language.AmericanEnglish, "FF00118", "Member %d is a duplicate org+node combination: %s", 400) + MsgGroupInvalidHash = FFE(language.AmericanEnglish, "FF00119", "Invalid group: hashes do not match Hash=%s Expected=%s", 400) + MsgInvalidDIDForType = FFE(language.AmericanEnglish, "FF00120", "Invalid FireFly DID '%s' for type='%s' namespace='%s' name='%s'", 400) + MsgCustomIdentitySystemNS = FFE(language.AmericanEnglish, "FF00121", "Custom identities cannot be defined in the '%s' namespace", 400) + MsgSystemIdentityCustomNS = FFE(language.AmericanEnglish, "FF00122", "System identities must be defined in the '%s' namespace", 400) + MsgNilParentIdentity = FFE(language.AmericanEnglish, "FF00124", "Identity of type '%s' must have a valid parent", 400) + MsgNilOrNullObject = FFE(language.AmericanEnglish, "FF00125", "Object is null") + MsgUnknownIdentityType = FFE(language.AmericanEnglish, "FF00126", "Unknown identity type: %s", 400) + MsgJSONObjectParseFailed = FFE(language.AmericanEnglish, "FF00127", "Failed to parse '%s' as JSON") + MsgNilDataReferenceSealFail = FFE(language.AmericanEnglish, "FF00128", "Invalid message: nil data reference at index %d", 400) + MsgDupDataReferenceSealFail = FFE(language.AmericanEnglish, "FF00129", "Invalid message: duplicate data reference at index %d", 400) + MsgInvalidTXTypeForMessage = FFE(language.AmericanEnglish, "FF00130", "Invalid transaction type for sending a message: %s", 400) + MsgVerifyFailedNilHashes = FFE(language.AmericanEnglish, "FF00131", "Invalid message: nil hashes", 400) + MsgVerifyFailedInvalidHashes = FFE(language.AmericanEnglish, "FF00132", "Invalid message: hashes do not match Hash=%s Expected=%s DataHash=%s DataHashExpected=%s", 400) + MsgDuplicateArrayEntry = FFE(language.AmericanEnglish, "FF00133", "Duplicate %s at index %d: '%s'", 400) + MsgTooManyItems = FFE(language.AmericanEnglish, "FF00134", "Maximum number of %s items is %d (supplied=%d)", 400) + MsgFieldTooLong = FFE(language.AmericanEnglish, "FF00135", "Field '%s' maximum length is %d", 400) + MsgTimeParseFail = FFE(language.AmericanEnglish, "FF00136", "Cannot parse time as RFC3339, Unix, or UnixNano: '%s'", 400) + MsgDurationParseFail = FFE(language.AmericanEnglish, "FF00137", "Unable to parse '%s' as duration string, or millisecond number", 400) + MsgInvalidUUID = FFE(language.AmericanEnglish, "FF00138", "Invalid UUID supplied", 400) + MsgSafeCharsOnly = FFE(language.AmericanEnglish, "FF00139", "Field '%s' must include only alphanumerics (a-zA-Z0-9), dot (.), dash (-) and underscore (_)", 400) + MsgInvalidName = FFE(language.AmericanEnglish, "FF00140", "Field '%s' must be 1-64 characters, including alphanumerics (a-zA-Z0-9), dot (.), dash (-) and underscore (_), and must start/end in an alphanumeric", 400) + MsgNoUUID = FFE(language.AmericanEnglish, "FF00141", "Field '%s' must not be a UUID", 400) + MsgInvalidFilterField = FFE(language.AmericanEnglish, "FF00142", "Unknown filter '%s'", 400) + MsgInvalidValueForFilterField = FFE(language.AmericanEnglish, "FF00143", "Unable to parse value for filter '%s'", 400) + MsgFieldMatchNoNull = FFE(language.AmericanEnglish, "FF00144", "Comparison operator for field '%s' cannot accept a null value", 400) + MsgFieldTypeNoStringMatching = FFE(language.AmericanEnglish, "FF00145", "Field '%s' of type '%s' does not support partial or case-insensitive string matching", 400) + MsgWSSendTimedOut = FFE(language.AmericanEnglish, "FF00146", "Websocket send timed out") + MsgWSClosing = FFE(language.AmericanEnglish, "FF00147", "Websocket closing") + MsgWSConnectFailed = FFE(language.AmericanEnglish, "FF00148", "Websocket connect failed") + MsgInvalidURL = FFE(language.AmericanEnglish, "FF00149", "Invalid URL: '%s'") + MsgWSHeartbeatTimeout = FFE(language.AmericanEnglish, "FF00150", "Websocket heartbeat timed out after %.2fms", 500) + MsgAPIServerStartFailed = FFE(language.AmericanEnglish, "FF00151", "Unable to start listener on %s: %s") + MsgInvalidCAFile = FFE(language.AmericanEnglish, "FF00152", "Invalid CA certificates file") + MsgTLSConfigFailed = FFE(language.AmericanEnglish, "FF00153", "Failed to initialize TLS configuration") + MsgContextCanceled = FFE(language.AmericanEnglish, "FF00154", "Context canceled") + MsgConnectorFailInvoke = FFE(language.AmericanEnglish, "FF00155", "Connector request failed. requestId=%s failed to call connector API") + MsgConnectorInvalidContentType = FFE(language.AmericanEnglish, "FF00156", "Connector request failed. requestId=%s invalid response content type: %s") + MsgConnectorError = FFE(language.AmericanEnglish, "FF00157", "Connector request failed. requestId=%s reason=%s error: %s") ) diff --git a/pkg/i18n/messages.go b/pkg/i18n/messages.go index 3d61e66..3e0bd30 100644 --- a/pkg/i18n/messages.go +++ b/pkg/i18n/messages.go @@ -36,13 +36,22 @@ type ErrorMessageKey MessageKey type ConfigMessageKey MessageKey // Expand for use in docs and logging - returns a translated message, translated the language of the context +// If a translation is not found for the language of the context, the default language text will be returned instead func Expand(ctx context.Context, key MessageKey, inserts ...interface{}) string { - return pFor(ctx).Sprintf(string(key), inserts...) + translation := pFor(ctx).Sprintf(string(key), inserts...) + if translation != string(key) { + return translation + } + return defaultLangPrinter.Sprintf(string(key), inserts...) } // ExpandWithCode for use in error scenarios - returns a translated message with a "MSG012345:" prefix, translated the language of the context func ExpandWithCode(ctx context.Context, key MessageKey, inserts ...interface{}) string { - return string(key) + ": " + pFor(ctx).Sprintf(string(key), inserts...) + translation := string(key) + ": " + pFor(ctx).Sprintf(string(key), inserts...) + if translation != string(key)+": "+string(key) { + return translation + } + return string(key) + ": " + defaultLangPrinter.Sprintf(string(key), inserts...) } // WithLang sets the language on the context @@ -54,21 +63,14 @@ type ( ctxLangKey struct{} ) -// en language is special, as the definition of each key comes directly with the english language description -var enLang = language.MustParse("en") - -var serverLangs = []language.Tag{ - language.AmericanEnglish, // Only English currently supported -} - -var langMatcher = language.NewMatcher(serverLangs) - var statusHints = map[string]int{} var fieldTypes = map[string]string{} var msgIDUniq = map[string]bool{} +var defaultLangPrinter = message.NewPrinter(language.AmericanEnglish) + // FFE is the translations helper to register an error message -func FFE(key, enTranslation string, statusHint ...int) ErrorMessageKey { +func FFE(language language.Tag, key, enTranslation string, statusHint ...int) ErrorMessageKey { validPrefix := false for rp := range registeredPrefixes { if strings.HasPrefix(key, rp) { @@ -79,7 +81,7 @@ func FFE(key, enTranslation string, statusHint ...int) ErrorMessageKey { if !validPrefix { panic(fmt.Sprintf("Message ID %s does not use one of the registered prefixes in the common utility package", key)) } - msgID := FFM(key, enTranslation) + msgID := FFM(language, key, enTranslation) if len(statusHint) > 0 { statusHints[key] = statusHint[0] } @@ -87,28 +89,26 @@ func FFE(key, enTranslation string, statusHint ...int) ErrorMessageKey { } // FFM is the enTranslations helper to define a new message (not used in translation files) -func FFM(key, enTranslation string) MessageKey { - if _, exists := msgIDUniq[key]; exists { +func FFM(language language.Tag, key, translation string) MessageKey { + if checkKeyExists(language, key) { panic(fmt.Sprintf("Message ID %s re-used", key)) } - msgIDUniq[key] = true - _ = message.Set(enLang, key, catalog.String(enTranslation)) + setKeyExists(language, key) + _ = message.Set(language, key, catalog.String(translation)) return MessageKey(key) } // FFC is the enTranslations helper to define a configuration key description and type -func FFC(key, enTranslation string, fieldType string) ConfigMessageKey { - if _, exists := msgIDUniq[key]; exists { +func FFC(language language.Tag, key, translation string, fieldType string) ConfigMessageKey { + if checkKeyExists(language, key) { panic(fmt.Sprintf("Config ID %s re-used", key)) } - msgIDUniq[key] = true + setKeyExists(language, key) fieldTypes[key] = fieldType - _ = message.Set(enLang, key, catalog.String(enTranslation)) + _ = message.Set(language, key, catalog.String(translation)) return ConfigMessageKey(key) } -var defaultLangPrinter *message.Printer - func pFor(ctx context.Context) *message.Printer { lang := ctx.Value(ctxLangKey{}) if lang == nil { @@ -118,16 +118,9 @@ func pFor(ctx context.Context) *message.Printer { } func init() { - SetLang("en") msgIDUniq = map[string]bool{} // Clear out that memory as no longer needed } -func SetLang(lang string) { - // Allow a lang var to be used - tag, _, _ := langMatcher.Match(language.Make(lang)) - defaultLangPrinter = message.NewPrinter(tag) -} - func GetStatusHint(code string) (int, bool) { i, ok := statusHints[code] return i, ok @@ -137,3 +130,12 @@ func GetFieldType(code string) (string, bool) { s, ok := fieldTypes[code] return s, ok } + +func setKeyExists(language language.Tag, key string) { + msgIDUniq[fmt.Sprintf("%s_%s", language, key)] = true + fmt.Println(msgIDUniq) +} + +func checkKeyExists(language language.Tag, key string) bool { + return msgIDUniq[fmt.Sprintf("%s_%s", language, key)] +} diff --git a/pkg/i18n/messages_test.go b/pkg/i18n/messages_test.go index 71f7a1f..7a92d5c 100644 --- a/pkg/i18n/messages_test.go +++ b/pkg/i18n/messages_test.go @@ -25,26 +25,45 @@ import ( ) var ( - TestError1 = FFE("FF99900", "Test error 1: %s") - TestError2 = FFE("FF99901", "Test error 2: %s") - TestError3 = FFE("FF99902", "Test error 3", 400) - TestConfig1 = FFC("config.something.1", "Test config field 1", "some type") + TestError1 = FFE(language.AmericanEnglish, "FF99900", "Test error 1: %s") + TestError2 = FFE(language.AmericanEnglish, "FF99901", "Test error 2: %s") + TestError3 = FFE(language.AmericanEnglish, "FF99902", "Test error 3", 400) + TestConfig1 = FFC(language.AmericanEnglish, "config.something.1", "Test config field 1", "some type") + + TestError1Lang2 = FFE(language.Spanish, "FF99900", "Error de prueba 1: %s") + TestConfig1Lang2 = FFC(language.Spanish, "config.something.1", "campo de configuración de prueba", "some type") ) func TestExpand(t *testing.T) { - lang := language.Make("en") - ctx := WithLang(context.Background(), lang) + ctx := WithLang(context.Background(), language.AmericanEnglish) str := Expand(ctx, MessageKey(TestError1), "myinsert") assert.Equal(t, "Test error 1: myinsert", str) } +func TestExpandLanguageFallback(t *testing.T) { + ctx := WithLang(context.Background(), language.Spanish) + str := Expand(ctx, MessageKey(TestError2), "myinsert") + assert.Equal(t, "Test error 2: myinsert", str) +} + func TestExpandWithCode(t *testing.T) { - lang := language.Make("en") - ctx := WithLang(context.Background(), lang) + ctx := WithLang(context.Background(), language.AmericanEnglish) + str := ExpandWithCode(ctx, MessageKey(TestError2), "myinsert") + assert.Equal(t, "FF99901: Test error 2: myinsert", str) +} + +func TestExpandWithCodeLangaugeFallback(t *testing.T) { + ctx := WithLang(context.Background(), language.Spanish) str := ExpandWithCode(ctx, MessageKey(TestError2), "myinsert") assert.Equal(t, "FF99901: Test error 2: myinsert", str) } +func TestExpandWithCodeLang2(t *testing.T) { + ctx := WithLang(context.Background(), language.Spanish) + str := ExpandWithCode(ctx, MessageKey(TestError1), "myinsert") + assert.Equal(t, "FF99900: Error de prueba 1: myinsert", str) +} + func TestGetStatusHint(t *testing.T) { code, ok := GetStatusHint(string(TestError3)) assert.True(t, ok) @@ -52,25 +71,30 @@ func TestGetStatusHint(t *testing.T) { } func TestDuplicateKey(t *testing.T) { - FFM("FF109999", "test1") + FFM(language.AmericanEnglish, "FF109999", "test1") assert.Panics(t, func() { - FFM("FF109999", "test2") + FFM(language.AmericanEnglish, "FF109999", "test2") }) } func TestInvalidPrefixKey(t *testing.T) { assert.Panics(t, func() { - FFE("ABCD1234", "test1") + FFE(language.AmericanEnglish, "ABCD1234", "test1") }) } func TestConfigMessageKey(t *testing.T) { - lang := language.Make("en") - ctx := WithLang(context.Background(), lang) + ctx := WithLang(context.Background(), language.AmericanEnglish) str := Expand(ctx, MessageKey(TestConfig1)) assert.Equal(t, "Test config field 1", str) } +func TestConfigMessageKeyLang2(t *testing.T) { + ctx := WithLang(context.Background(), language.Spanish) + str := Expand(ctx, MessageKey(TestConfig1)) + assert.Equal(t, "campo de configuración de prueba", str) +} + func TestGetFieldType(t *testing.T) { fieldType, ok := GetFieldType(string(TestConfig1)) assert.True(t, ok) @@ -78,8 +102,8 @@ func TestGetFieldType(t *testing.T) { } func TestDuplicateConfigKey(t *testing.T) { - FFC("config.test.2", "test2 description", "type") + FFC(language.AmericanEnglish, "config.test.2", "test2 description", "type") assert.Panics(t, func() { - FFC("config.test.2", "test2 dupe", "dupe type") + FFC(language.AmericanEnglish, "config.test.2", "test2 dupe", "dupe type") }) } From d5fa19e2db2f5a5f304a51cf76f83b971ab35612 Mon Sep 17 00:00:00 2001 From: Nicko Guyer Date: Mon, 16 May 2022 16:28:37 -0400 Subject: [PATCH 2/4] Update GitHub workflow to Go 1.17 Signed-off-by: Nicko Guyer --- .github/workflows/go.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 8687e99..8f8b634 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -18,7 +18,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v2 with: - go-version: 1.16 + go-version: 1.17 - name: Build and Test run: make From a5147358c2f7cc8acd885664ccb6777c1565611e Mon Sep 17 00:00:00 2001 From: Nicko Guyer Date: Tue, 17 May 2022 09:06:12 -0400 Subject: [PATCH 3/4] Restore SetLang() function in i18n Signed-off-by: Nicko Guyer --- pkg/config/config.go | 2 ++ pkg/i18n/messages.go | 16 ++++++++++++---- pkg/i18n/messages_test.go | 20 ++++++++++++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index 1b4b6af..7410959 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -150,6 +150,8 @@ func RootConfigReset(setServiceDefaults ...func()) { for _, fn := range setServiceDefaults { fn() } + + i18n.SetLang(viper.GetString(string(Lang))) } // ReadConfig initializes the config diff --git a/pkg/i18n/messages.go b/pkg/i18n/messages.go index 3e0bd30..b0a444e 100644 --- a/pkg/i18n/messages.go +++ b/pkg/i18n/messages.go @@ -42,7 +42,7 @@ func Expand(ctx context.Context, key MessageKey, inserts ...interface{}) string if translation != string(key) { return translation } - return defaultLangPrinter.Sprintf(string(key), inserts...) + return fallbackLangPrinter.Sprintf(string(key), inserts...) } // ExpandWithCode for use in error scenarios - returns a translated message with a "MSG012345:" prefix, translated the language of the context @@ -51,7 +51,7 @@ func ExpandWithCode(ctx context.Context, key MessageKey, inserts ...interface{}) if translation != string(key)+": "+string(key) { return translation } - return string(key) + ": " + defaultLangPrinter.Sprintf(string(key), inserts...) + return string(key) + ": " + fallbackLangPrinter.Sprintf(string(key), inserts...) } // WithLang sets the language on the context @@ -67,7 +67,7 @@ var statusHints = map[string]int{} var fieldTypes = map[string]string{} var msgIDUniq = map[string]bool{} -var defaultLangPrinter = message.NewPrinter(language.AmericanEnglish) +var fallbackLangPrinter = message.NewPrinter(language.AmericanEnglish) // FFE is the translations helper to register an error message func FFE(language language.Tag, key, enTranslation string, statusHint ...int) ErrorMessageKey { @@ -109,6 +109,8 @@ func FFC(language language.Tag, key, translation string, fieldType string) Confi return ConfigMessageKey(key) } +var defaultLangPrinter *message.Printer + func pFor(ctx context.Context) *message.Printer { lang := ctx.Value(ctxLangKey{}) if lang == nil { @@ -118,9 +120,16 @@ func pFor(ctx context.Context) *message.Printer { } func init() { + SetLang("en") msgIDUniq = map[string]bool{} // Clear out that memory as no longer needed } +func SetLang(lang string) { + // Allow a lang var to be used + tag := message.MatchLanguage(lang) + defaultLangPrinter = message.NewPrinter(tag) +} + func GetStatusHint(code string) (int, bool) { i, ok := statusHints[code] return i, ok @@ -133,7 +142,6 @@ func GetFieldType(code string) (string, bool) { func setKeyExists(language language.Tag, key string) { msgIDUniq[fmt.Sprintf("%s_%s", language, key)] = true - fmt.Println(msgIDUniq) } func checkKeyExists(language language.Tag, key string) bool { diff --git a/pkg/i18n/messages_test.go b/pkg/i18n/messages_test.go index 7a92d5c..0be19f6 100644 --- a/pkg/i18n/messages_test.go +++ b/pkg/i18n/messages_test.go @@ -40,6 +40,26 @@ func TestExpand(t *testing.T) { assert.Equal(t, "Test error 1: myinsert", str) } +func TestExpandNoLangContext(t *testing.T) { + ctx := context.Background() + str := Expand(ctx, MessageKey(TestError1), "myinsert") + assert.Equal(t, "Test error 1: myinsert", str) +} + +func TestExpandNoLangContextLang2(t *testing.T) { + ctx := context.Background() + SetLang("es") + str := Expand(ctx, MessageKey(TestError1), "myinsert") + assert.Equal(t, "Error de prueba 1: myinsert", str) +} + +func TestExpandNoLangContextLang2Fallback(t *testing.T) { + ctx := context.Background() + SetLang("es") + str := Expand(ctx, MessageKey(TestError2), "myinsert") + assert.Equal(t, "Test error 2: myinsert", str) +} + func TestExpandLanguageFallback(t *testing.T) { ctx := WithLang(context.Background(), language.Spanish) str := Expand(ctx, MessageKey(TestError2), "myinsert") From 8437537359c1a6017b5f88779689730fd09345f4 Mon Sep 17 00:00:00 2001 From: Nicko Guyer Date: Wed, 18 May 2022 14:30:23 -0400 Subject: [PATCH 4/4] Add example translation file for another language Signed-off-by: Nicko Guyer --- pkg/i18n/en_base_config_descriptions.go | 120 +++++++++++---------- pkg/i18n/en_base_error_messages.go | 114 ++++++++++---------- pkg/i18n/es/es_base_config_descriptions.go | 31 ++++++ pkg/i18n/messages.go | 12 +-- 4 files changed, 158 insertions(+), 119 deletions(-) create mode 100644 pkg/i18n/es/es_base_config_descriptions.go diff --git a/pkg/i18n/en_base_config_descriptions.go b/pkg/i18n/en_base_config_descriptions.go index 0e75c2a..2af282b 100644 --- a/pkg/i18n/en_base_config_descriptions.go +++ b/pkg/i18n/en_base_config_descriptions.go @@ -29,72 +29,76 @@ var FloatType = "`boolean`" var MapStringStringType = "`map[string]string`" var IgnoredType = "IGNORE" +var ffc = func(key, translation, fieldType string) ConfigMessageKey { + return FFC(language.AmericanEnglish, key, translation, fieldType) +} + //revive:disable var ( - ConfigGlobalConnectionTimeout = FFC(language.AmericanEnglish, "config.global.connectionTimeout", "The maximum amount of time that a connection is allowed to remain with no data transmitted", TimeDurationType) - ConfigGlobalRequestTimeout = FFC(language.AmericanEnglish, "config.global.requestTimeout", "The maximum amount of time that a request is allowed to remain open", TimeDurationType) + ConfigGlobalConnectionTimeout = ffc("config.global.connectionTimeout", "The maximum amount of time that a connection is allowed to remain with no data transmitted", TimeDurationType) + ConfigGlobalRequestTimeout = ffc("config.global.requestTimeout", "The maximum amount of time that a request is allowed to remain open", TimeDurationType) - ConfigGlobalRetryEnabled = FFC(language.AmericanEnglish, "config.global.retry.enabled", "Enables retries", BooleanType) - ConfigGlobalRetryFactor = FFC(language.AmericanEnglish, "config.global.retry.factor", "The retry backoff factor", FloatType) - ConfigGlobalRetryInitDelay = FFC(language.AmericanEnglish, "config.global.retry.initDelay", "The initial retry delay", TimeDurationType) - ConfigGlobalRetryInitialDelay = FFC(language.AmericanEnglish, "config.global.retry.initialDelay", "The initial retry delay", TimeDurationType) - ConfigGlobalRetryMaxDelay = FFC(language.AmericanEnglish, "config.global.retry.maxDelay", "The maximum retry delay", TimeDurationType) - ConfigGlobalRetryMaxAttempts = FFC(language.AmericanEnglish, "config.global.retry.maxAttempts", "The maximum number attempts", IntType) - ConfigGlobalRetryCount = FFC(language.AmericanEnglish, "config.global.retry.count", "The maximum number of times to retry", IntType) - ConfigGlobalInitWaitTime = FFC(language.AmericanEnglish, "config.global.retry.initWaitTime", "The initial retry delay", TimeDurationType) - ConfigGlobalMaxWaitTime = FFC(language.AmericanEnglish, "config.global.retry.maxWaitTime", "The maximum retry delay", TimeDurationType) + ConfigGlobalRetryEnabled = ffc("config.global.retry.enabled", "Enables retries", BooleanType) + ConfigGlobalRetryFactor = ffc("config.global.retry.factor", "The retry backoff factor", FloatType) + ConfigGlobalRetryInitDelay = ffc("config.global.retry.initDelay", "The initial retry delay", TimeDurationType) + ConfigGlobalRetryInitialDelay = ffc("config.global.retry.initialDelay", "The initial retry delay", TimeDurationType) + ConfigGlobalRetryMaxDelay = ffc("config.global.retry.maxDelay", "The maximum retry delay", TimeDurationType) + ConfigGlobalRetryMaxAttempts = ffc("config.global.retry.maxAttempts", "The maximum number attempts", IntType) + ConfigGlobalRetryCount = ffc("config.global.retry.count", "The maximum number of times to retry", IntType) + ConfigGlobalInitWaitTime = ffc("config.global.retry.initWaitTime", "The initial retry delay", TimeDurationType) + ConfigGlobalMaxWaitTime = ffc("config.global.retry.maxWaitTime", "The maximum retry delay", TimeDurationType) - ConfigGlobalUsername = FFC(language.AmericanEnglish, "config.global.auth.username", "Username", StringType) - ConfigGlobalPassword = FFC(language.AmericanEnglish, "config.global.auth.password", "Password", StringType) + ConfigGlobalUsername = ffc("config.global.auth.username", "Username", StringType) + ConfigGlobalPassword = ffc("config.global.auth.password", "Password", StringType) - ConfigGlobalSize = FFC(language.AmericanEnglish, "config.global.cache.size", "The size of the cache", ByteSizeType) - ConfigGlobalTTL = FFC(language.AmericanEnglish, "config.global.cache.ttl", "The time to live (TTL) for the cache", TimeDurationType) + ConfigGlobalSize = ffc("config.global.cache.size", "The size of the cache", ByteSizeType) + ConfigGlobalTTL = ffc("config.global.cache.ttl", "The time to live (TTL) for the cache", TimeDurationType) - ConfigGlobaltWsHeartbeatInterval = FFC(language.AmericanEnglish, "config.global.ws.heartbeatInterval", "The amount of time to wait between heartbeat signals on the WebSocket connection", TimeDurationType) - ConfigGlobalWsInitialConnectAttempts = FFC(language.AmericanEnglish, "config.global.ws.initialConnectAttempts", "The number of attempts FireFly will make to connect to the WebSocket when starting up, before failing", IntType) - ConfigGlobalWsPath = FFC(language.AmericanEnglish, "config.global.ws.path", "The WebSocket sever URL to which FireFly should connect", "WebSocket URL "+StringType) - ConfigGlobalWsReadBufferSize = FFC(language.AmericanEnglish, "config.global.ws.readBufferSize", "The size in bytes of the read buffer for the WebSocket connection", ByteSizeType) - ConfigGlobalWsWriteBufferSize = FFC(language.AmericanEnglish, "config.global.ws.writeBufferSize", "The size in bytes of the write buffer for the WebSocket connection", ByteSizeType) + ConfigGlobaltWsHeartbeatInterval = ffc("config.global.ws.heartbeatInterval", "The amount of time to wait between heartbeat signals on the WebSocket connection", TimeDurationType) + ConfigGlobalWsInitialConnectAttempts = ffc("config.global.ws.initialConnectAttempts", "The number of attempts FireFly will make to connect to the WebSocket when starting up, before failing", IntType) + ConfigGlobalWsPath = ffc("config.global.ws.path", "The WebSocket sever URL to which FireFly should connect", "WebSocket URL "+StringType) + ConfigGlobalWsReadBufferSize = ffc("config.global.ws.readBufferSize", "The size in bytes of the read buffer for the WebSocket connection", ByteSizeType) + ConfigGlobalWsWriteBufferSize = ffc("config.global.ws.writeBufferSize", "The size in bytes of the write buffer for the WebSocket connection", ByteSizeType) - ConfigGlobalTLSCaFile = FFC(language.AmericanEnglish, "config.global.tls.caFile", "The path to the CA file for TLS on this API", StringType) - ConfigGlobalTLSCertFile = FFC(language.AmericanEnglish, "config.global.tls.certFile", "The path to the certificate file for TLS on this API", StringType) - ConfigGlobalTLSClientAuth = FFC(language.AmericanEnglish, "config.global.tls.clientAuth", "Enables or disables client auth for TLS on this API", StringType) - ConfigGlobalTLSEnabled = FFC(language.AmericanEnglish, "config.global.tls.enabled", "Enables or disables TLS on this API", BooleanType) - ConfigGlobalTLSKeyFile = FFC(language.AmericanEnglish, "config.global.tls.keyFile", "The path to the private key file for TLS on this API", StringType) - ConfigGlobalTLSHandshakeTimeout = FFC(language.AmericanEnglish, "config.global.tlsHandshakeTimeout", "The maximum amount of time to wait for a successful TLS handshake", TimeDurationType) + ConfigGlobalTLSCaFile = ffc("config.global.tls.caFile", "The path to the CA file for TLS on this API", StringType) + ConfigGlobalTLSCertFile = ffc("config.global.tls.certFile", "The path to the certificate file for TLS on this API", StringType) + ConfigGlobalTLSClientAuth = ffc("config.global.tls.clientAuth", "Enables or disables client auth for TLS on this API", StringType) + ConfigGlobalTLSEnabled = ffc("config.global.tls.enabled", "Enables or disables TLS on this API", BooleanType) + ConfigGlobalTLSKeyFile = ffc("config.global.tls.keyFile", "The path to the private key file for TLS on this API", StringType) + ConfigGlobalTLSHandshakeTimeout = ffc("config.global.tlsHandshakeTimeout", "The maximum amount of time to wait for a successful TLS handshake", TimeDurationType) - ConfigGlobalBodyTemplate = FFC(language.AmericanEnglish, "config.global.bodyTemplate", "The body go template string to use when making HTTP requests", GoTemplateType) - ConfigGlobalCustomClient = FFC(language.AmericanEnglish, "config.global.customClient", "Used for testing purposes only", IgnoredType) - ConfigGlobalExpectContinueTimeout = FFC(language.AmericanEnglish, "config.global.expectContinueTimeout", "See [ExpectContinueTimeout in the Go docs](https://pkg.go.dev/net/http#Transport)", TimeDurationType) - ConfigGlobalHeaders = FFC(language.AmericanEnglish, "config.global.headers", "Adds custom headers to HTTP requests", MapStringStringType) - ConfigGlobalIdleTimeout = FFC(language.AmericanEnglish, "config.global.idleTimeout", "The max duration to hold a HTTP keepalive connection between calls", TimeDurationType) - ConfigGlobalMaxIdleConns = FFC(language.AmericanEnglish, "config.global.maxIdleConns", "The max number of idle connections to hold pooled", IntType) - ConfigGlobalMethod = FFC(language.AmericanEnglish, "config.global.method", "The HTTP method to use when making requests to the Address Resolver", StringType) + ConfigGlobalBodyTemplate = ffc("config.global.bodyTemplate", "The body go template string to use when making HTTP requests", GoTemplateType) + ConfigGlobalCustomClient = ffc("config.global.customClient", "Used for testing purposes only", IgnoredType) + ConfigGlobalExpectContinueTimeout = ffc("config.global.expectContinueTimeout", "See [ExpectContinueTimeout in the Go docs](https://pkg.go.dev/net/http#Transport)", TimeDurationType) + ConfigGlobalHeaders = ffc("config.global.headers", "Adds custom headers to HTTP requests", MapStringStringType) + ConfigGlobalIdleTimeout = ffc("config.global.idleTimeout", "The max duration to hold a HTTP keepalive connection between calls", TimeDurationType) + ConfigGlobalMaxIdleConns = ffc("config.global.maxIdleConns", "The max number of idle connections to hold pooled", IntType) + ConfigGlobalMethod = ffc("config.global.method", "The HTTP method to use when making requests to the Address Resolver", StringType) - ConfigLang = FFC(language.AmericanEnglish, "config.lang", "Default language for translation (API calls may support language override using headers)", StringType) - ConfigLogCompress = FFC(language.AmericanEnglish, "config.log.compress", "Determines if the rotated log files should be compressed using gzip", BooleanType) - ConfigLogFilename = FFC(language.AmericanEnglish, "config.log.filename", "Filename is the file to write logs to. Backup log files will be retained in the same directory", StringType) - ConfigLogFilesize = FFC(language.AmericanEnglish, "config.log.filesize", "MaxSize is the maximum size the log file before it gets rotated", ByteSizeType) - ConfigLogForceColor = FFC(language.AmericanEnglish, "config.log.forceColor", "Force color to be enabled, even when a non-TTY output is detected", BooleanType) - ConfigLogLevel = FFC(language.AmericanEnglish, "config.log.level", "The log level - error, warn, info, debug, trace", StringType) - ConfigLogMaxAge = FFC(language.AmericanEnglish, "config.log.maxAge", "The maximum time to retain old log files based on the timestamp encoded in their filename.", TimeDurationType) - ConfigLogMaxBackups = FFC(language.AmericanEnglish, "config.log.maxBackups", "Maximum number of old log files to retain", IntType) - ConfigLogNoColor = FFC(language.AmericanEnglish, "config.log.noColor", "Force color to be disabled, event when TTY output is detected", BooleanType) - ConfigLogTimeFormat = FFC(language.AmericanEnglish, "config.log.timeFormat", "Custom time format for logs", TimeFormatType) - ConfigLogUtc = FFC(language.AmericanEnglish, "config.log.utc", "Use UTC timestamps for logs", BooleanType) - ConfigLogIncludeCodeInfo = FFC(language.AmericanEnglish, "config.log.includeCodeInfo", "Enables the report caller for including the calling file and line number, and the calling function. If using text logs, it uses the logrus text format rather than the default prefix format.", BooleanType) - ConfigLogJSONEnabled = FFC(language.AmericanEnglish, "config.log.json.enabled", "Enables JSON formatted logs rather than text. All log color settings are ignored when enabled.", BooleanType) - ConfigLogJSONTimestampField = FFC(language.AmericanEnglish, "config.log.json.fields.timestamp", "Configures the JSON key containing the timestamp of the log", StringType) - ConfigLogJSONLevelField = FFC(language.AmericanEnglish, "config.log.json.fields.level", "Configures the JSON key containing the log level", StringType) - ConfigLogJSONMessageField = FFC(language.AmericanEnglish, "config.log.json.fields.message", "Configures the JSON key containing the log message", StringType) - ConfigLogJSONFuncField = FFC(language.AmericanEnglish, "config.log.json.fields.func", "Configures the JSON key containing the calling function", StringType) - ConfigLogJSONFileField = FFC(language.AmericanEnglish, "config.log.json.fields.file", "configures the JSON key containing the calling file", StringType) - ConfigCorsCredentials = FFC(language.AmericanEnglish, "config.cors.credentials", "CORS setting to control whether a browser allows credentials to be sent to this API", BooleanType) + ConfigLang = ffc("config.lang", "Default language for translation (API calls may support language override using headers)", StringType) + ConfigLogCompress = ffc("config.log.compress", "Determines if the rotated log files should be compressed using gzip", BooleanType) + ConfigLogFilename = ffc("config.log.filename", "Filename is the file to write logs to. Backup log files will be retained in the same directory", StringType) + ConfigLogFilesize = ffc("config.log.filesize", "MaxSize is the maximum size the log file before it gets rotated", ByteSizeType) + ConfigLogForceColor = ffc("config.log.forceColor", "Force color to be enabled, even when a non-TTY output is detected", BooleanType) + ConfigLogLevel = ffc("config.log.level", "The log level - error, warn, info, debug, trace", StringType) + ConfigLogMaxAge = ffc("config.log.maxAge", "The maximum time to retain old log files based on the timestamp encoded in their filename.", TimeDurationType) + ConfigLogMaxBackups = ffc("config.log.maxBackups", "Maximum number of old log files to retain", IntType) + ConfigLogNoColor = ffc("config.log.noColor", "Force color to be disabled, event when TTY output is detected", BooleanType) + ConfigLogTimeFormat = ffc("config.log.timeFormat", "Custom time format for logs", TimeFormatType) + ConfigLogUtc = ffc("config.log.utc", "Use UTC timestamps for logs", BooleanType) + ConfigLogIncludeCodeInfo = ffc("config.log.includeCodeInfo", "Enables the report caller for including the calling file and line number, and the calling function. If using text logs, it uses the logrus text format rather than the default prefix format.", BooleanType) + ConfigLogJSONEnabled = ffc("config.log.json.enabled", "Enables JSON formatted logs rather than text. All log color settings are ignored when enabled.", BooleanType) + ConfigLogJSONTimestampField = ffc("config.log.json.fields.timestamp", "Configures the JSON key containing the timestamp of the log", StringType) + ConfigLogJSONLevelField = ffc("config.log.json.fields.level", "Configures the JSON key containing the log level", StringType) + ConfigLogJSONMessageField = ffc("config.log.json.fields.message", "Configures the JSON key containing the log message", StringType) + ConfigLogJSONFuncField = ffc("config.log.json.fields.func", "Configures the JSON key containing the calling function", StringType) + ConfigLogJSONFileField = ffc("config.log.json.fields.file", "configures the JSON key containing the calling file", StringType) + ConfigCorsCredentials = ffc("config.cors.credentials", "CORS setting to control whether a browser allows credentials to be sent to this API", BooleanType) - ConfigCorsDebug = FFC(language.AmericanEnglish, "config.global.cors.debug", "Whether debug is enabled for the CORS implementation", BooleanType) - ConfigCorsEnabled = FFC(language.AmericanEnglish, "config.global.cors.enabled", "Whether CORS is enabled", BooleanType) - ConfigCorsHeaders = FFC(language.AmericanEnglish, "config.global.cors.headers", "CORS setting to control the allowed headers", StringType) - ConfigCorsMaxAge = FFC(language.AmericanEnglish, "config.global.cors.maxAge", "The maximum age a browser should rely on CORS checks", TimeDurationType) - ConfigCorsMethods = FFC(language.AmericanEnglish, "config.global.cors.methods", " CORS setting to control the allowed methods", StringType) - ConfigCorsOrigins = FFC(language.AmericanEnglish, "config.global.cors.origins", "CORS setting to control the allowed origins", StringType) + ConfigCorsDebug = ffc("config.global.cors.debug", "Whether debug is enabled for the CORS implementation", BooleanType) + ConfigCorsEnabled = ffc("config.global.cors.enabled", "Whether CORS is enabled", BooleanType) + ConfigCorsHeaders = ffc("config.global.cors.headers", "CORS setting to control the allowed headers", StringType) + ConfigCorsMaxAge = ffc("config.global.cors.maxAge", "The maximum age a browser should rely on CORS checks", TimeDurationType) + ConfigCorsMethods = ffc("config.global.cors.methods", " CORS setting to control the allowed methods", StringType) + ConfigCorsOrigins = ffc("config.global.cors.origins", "CORS setting to control the allowed origins", StringType) ) diff --git a/pkg/i18n/en_base_error_messages.go b/pkg/i18n/en_base_error_messages.go index b68c57a..f03158e 100644 --- a/pkg/i18n/en_base_error_messages.go +++ b/pkg/i18n/en_base_error_messages.go @@ -28,61 +28,65 @@ var ( } ) +var ffe = func(key, translation string, statusHint ...int) ErrorMessageKey { + return FFE(language.AmericanEnglish, key, translation, statusHint...) +} + //revive:disable var ( - MsgConfigFailed = FFE(language.AmericanEnglish, "FF00101", "Failed to read config", 500) - MsgBigIntTooLarge = FFE(language.AmericanEnglish, "FF00103", "Byte length of serialized integer is too large %d (max=%d)") - MsgBigIntParseFailed = FFE(language.AmericanEnglish, "FF00104", "Failed to parse JSON value '%s' into BigInt") - MsgTypeRestoreFailed = FFE(language.AmericanEnglish, "FF00105", "Failed to restore type '%T' into '%T'") - MsgInvalidHex = FFE(language.AmericanEnglish, "FF00106", "Invalid hex supplied", 400) - MsgInvalidWrongLenB32 = FFE(language.AmericanEnglish, "FF00107", "Byte length must be 32 (64 hex characters)", 400) - MsgUnknownValidatorType = FFE(language.AmericanEnglish, "FF00108", "Unknown validator type: '%s'", 400) - MsgDataValueIsNull = FFE(language.AmericanEnglish, "FF00109", "Data value is null", 400) - MsgBlobMismatchSealingData = FFE(language.AmericanEnglish, "FF00110", "Blob mismatch when sealing data") - MsgUnknownFieldValue = FFE(language.AmericanEnglish, "FF00111", "Unknown %s '%v'", 400) - MsgMissingRequiredField = FFE(language.AmericanEnglish, "FF00112", "Field '%s' is required", 400) - MsgDataInvalidHash = FFE(language.AmericanEnglish, "FF00113", "Invalid data: hashes do not match Hash=%s Expected=%s", 400) - MsgNilID = FFE(language.AmericanEnglish, "FF00114", "ID is nil") - MsgGroupMustHaveMembers = FFE(language.AmericanEnglish, "FF00115", "Group must have at least one member", 400) - MsgEmptyMemberIdentity = FFE(language.AmericanEnglish, "FF00116", "Identity is blank in member %d") - MsgEmptyMemberNode = FFE(language.AmericanEnglish, "FF00117", "Node is blank in member %d") - MsgDuplicateMember = FFE(language.AmericanEnglish, "FF00118", "Member %d is a duplicate org+node combination: %s", 400) - MsgGroupInvalidHash = FFE(language.AmericanEnglish, "FF00119", "Invalid group: hashes do not match Hash=%s Expected=%s", 400) - MsgInvalidDIDForType = FFE(language.AmericanEnglish, "FF00120", "Invalid FireFly DID '%s' for type='%s' namespace='%s' name='%s'", 400) - MsgCustomIdentitySystemNS = FFE(language.AmericanEnglish, "FF00121", "Custom identities cannot be defined in the '%s' namespace", 400) - MsgSystemIdentityCustomNS = FFE(language.AmericanEnglish, "FF00122", "System identities must be defined in the '%s' namespace", 400) - MsgNilParentIdentity = FFE(language.AmericanEnglish, "FF00124", "Identity of type '%s' must have a valid parent", 400) - MsgNilOrNullObject = FFE(language.AmericanEnglish, "FF00125", "Object is null") - MsgUnknownIdentityType = FFE(language.AmericanEnglish, "FF00126", "Unknown identity type: %s", 400) - MsgJSONObjectParseFailed = FFE(language.AmericanEnglish, "FF00127", "Failed to parse '%s' as JSON") - MsgNilDataReferenceSealFail = FFE(language.AmericanEnglish, "FF00128", "Invalid message: nil data reference at index %d", 400) - MsgDupDataReferenceSealFail = FFE(language.AmericanEnglish, "FF00129", "Invalid message: duplicate data reference at index %d", 400) - MsgInvalidTXTypeForMessage = FFE(language.AmericanEnglish, "FF00130", "Invalid transaction type for sending a message: %s", 400) - MsgVerifyFailedNilHashes = FFE(language.AmericanEnglish, "FF00131", "Invalid message: nil hashes", 400) - MsgVerifyFailedInvalidHashes = FFE(language.AmericanEnglish, "FF00132", "Invalid message: hashes do not match Hash=%s Expected=%s DataHash=%s DataHashExpected=%s", 400) - MsgDuplicateArrayEntry = FFE(language.AmericanEnglish, "FF00133", "Duplicate %s at index %d: '%s'", 400) - MsgTooManyItems = FFE(language.AmericanEnglish, "FF00134", "Maximum number of %s items is %d (supplied=%d)", 400) - MsgFieldTooLong = FFE(language.AmericanEnglish, "FF00135", "Field '%s' maximum length is %d", 400) - MsgTimeParseFail = FFE(language.AmericanEnglish, "FF00136", "Cannot parse time as RFC3339, Unix, or UnixNano: '%s'", 400) - MsgDurationParseFail = FFE(language.AmericanEnglish, "FF00137", "Unable to parse '%s' as duration string, or millisecond number", 400) - MsgInvalidUUID = FFE(language.AmericanEnglish, "FF00138", "Invalid UUID supplied", 400) - MsgSafeCharsOnly = FFE(language.AmericanEnglish, "FF00139", "Field '%s' must include only alphanumerics (a-zA-Z0-9), dot (.), dash (-) and underscore (_)", 400) - MsgInvalidName = FFE(language.AmericanEnglish, "FF00140", "Field '%s' must be 1-64 characters, including alphanumerics (a-zA-Z0-9), dot (.), dash (-) and underscore (_), and must start/end in an alphanumeric", 400) - MsgNoUUID = FFE(language.AmericanEnglish, "FF00141", "Field '%s' must not be a UUID", 400) - MsgInvalidFilterField = FFE(language.AmericanEnglish, "FF00142", "Unknown filter '%s'", 400) - MsgInvalidValueForFilterField = FFE(language.AmericanEnglish, "FF00143", "Unable to parse value for filter '%s'", 400) - MsgFieldMatchNoNull = FFE(language.AmericanEnglish, "FF00144", "Comparison operator for field '%s' cannot accept a null value", 400) - MsgFieldTypeNoStringMatching = FFE(language.AmericanEnglish, "FF00145", "Field '%s' of type '%s' does not support partial or case-insensitive string matching", 400) - MsgWSSendTimedOut = FFE(language.AmericanEnglish, "FF00146", "Websocket send timed out") - MsgWSClosing = FFE(language.AmericanEnglish, "FF00147", "Websocket closing") - MsgWSConnectFailed = FFE(language.AmericanEnglish, "FF00148", "Websocket connect failed") - MsgInvalidURL = FFE(language.AmericanEnglish, "FF00149", "Invalid URL: '%s'") - MsgWSHeartbeatTimeout = FFE(language.AmericanEnglish, "FF00150", "Websocket heartbeat timed out after %.2fms", 500) - MsgAPIServerStartFailed = FFE(language.AmericanEnglish, "FF00151", "Unable to start listener on %s: %s") - MsgInvalidCAFile = FFE(language.AmericanEnglish, "FF00152", "Invalid CA certificates file") - MsgTLSConfigFailed = FFE(language.AmericanEnglish, "FF00153", "Failed to initialize TLS configuration") - MsgContextCanceled = FFE(language.AmericanEnglish, "FF00154", "Context canceled") - MsgConnectorFailInvoke = FFE(language.AmericanEnglish, "FF00155", "Connector request failed. requestId=%s failed to call connector API") - MsgConnectorInvalidContentType = FFE(language.AmericanEnglish, "FF00156", "Connector request failed. requestId=%s invalid response content type: %s") - MsgConnectorError = FFE(language.AmericanEnglish, "FF00157", "Connector request failed. requestId=%s reason=%s error: %s") + MsgConfigFailed = ffe("FF00101", "Failed to read config", 500) + MsgBigIntTooLarge = ffe("FF00103", "Byte length of serialized integer is too large %d (max=%d)") + MsgBigIntParseFailed = ffe("FF00104", "Failed to parse JSON value '%s' into BigInt") + MsgTypeRestoreFailed = ffe("FF00105", "Failed to restore type '%T' into '%T'") + MsgInvalidHex = ffe("FF00106", "Invalid hex supplied", 400) + MsgInvalidWrongLenB32 = ffe("FF00107", "Byte length must be 32 (64 hex characters)", 400) + MsgUnknownValidatorType = ffe("FF00108", "Unknown validator type: '%s'", 400) + MsgDataValueIsNull = ffe("FF00109", "Data value is null", 400) + MsgBlobMismatchSealingData = ffe("FF00110", "Blob mismatch when sealing data") + MsgUnknownFieldValue = ffe("FF00111", "Unknown %s '%v'", 400) + MsgMissingRequiredField = ffe("FF00112", "Field '%s' is required", 400) + MsgDataInvalidHash = ffe("FF00113", "Invalid data: hashes do not match Hash=%s Expected=%s", 400) + MsgNilID = ffe("FF00114", "ID is nil") + MsgGroupMustHaveMembers = ffe("FF00115", "Group must have at least one member", 400) + MsgEmptyMemberIdentity = ffe("FF00116", "Identity is blank in member %d") + MsgEmptyMemberNode = ffe("FF00117", "Node is blank in member %d") + MsgDuplicateMember = ffe("FF00118", "Member %d is a duplicate org+node combination: %s", 400) + MsgGroupInvalidHash = ffe("FF00119", "Invalid group: hashes do not match Hash=%s Expected=%s", 400) + MsgInvalidDIDForType = ffe("FF00120", "Invalid FireFly DID '%s' for type='%s' namespace='%s' name='%s'", 400) + MsgCustomIdentitySystemNS = ffe("FF00121", "Custom identities cannot be defined in the '%s' namespace", 400) + MsgSystemIdentityCustomNS = ffe("FF00122", "System identities must be defined in the '%s' namespace", 400) + MsgNilParentIdentity = ffe("FF00124", "Identity of type '%s' must have a valid parent", 400) + MsgNilOrNullObject = ffe("FF00125", "Object is null") + MsgUnknownIdentityType = ffe("FF00126", "Unknown identity type: %s", 400) + MsgJSONObjectParseFailed = ffe("FF00127", "Failed to parse '%s' as JSON") + MsgNilDataReferenceSealFail = ffe("FF00128", "Invalid message: nil data reference at index %d", 400) + MsgDupDataReferenceSealFail = ffe("FF00129", "Invalid message: duplicate data reference at index %d", 400) + MsgInvalidTXTypeForMessage = ffe("FF00130", "Invalid transaction type for sending a message: %s", 400) + MsgVerifyFailedNilHashes = ffe("FF00131", "Invalid message: nil hashes", 400) + MsgVerifyFailedInvalidHashes = ffe("FF00132", "Invalid message: hashes do not match Hash=%s Expected=%s DataHash=%s DataHashExpected=%s", 400) + MsgDuplicateArrayEntry = ffe("FF00133", "Duplicate %s at index %d: '%s'", 400) + MsgTooManyItems = ffe("FF00134", "Maximum number of %s items is %d (supplied=%d)", 400) + MsgFieldTooLong = ffe("FF00135", "Field '%s' maximum length is %d", 400) + MsgTimeParseFail = ffe("FF00136", "Cannot parse time as RFC3339, Unix, or UnixNano: '%s'", 400) + MsgDurationParseFail = ffe("FF00137", "Unable to parse '%s' as duration string, or millisecond number", 400) + MsgInvalidUUID = ffe("FF00138", "Invalid UUID supplied", 400) + MsgSafeCharsOnly = ffe("FF00139", "Field '%s' must include only alphanumerics (a-zA-Z0-9), dot (.), dash (-) and underscore (_)", 400) + MsgInvalidName = ffe("FF00140", "Field '%s' must be 1-64 characters, including alphanumerics (a-zA-Z0-9), dot (.), dash (-) and underscore (_), and must start/end in an alphanumeric", 400) + MsgNoUUID = ffe("FF00141", "Field '%s' must not be a UUID", 400) + MsgInvalidFilterField = ffe("FF00142", "Unknown filter '%s'", 400) + MsgInvalidValueForFilterField = ffe("FF00143", "Unable to parse value for filter '%s'", 400) + MsgFieldMatchNoNull = ffe("FF00144", "Comparison operator for field '%s' cannot accept a null value", 400) + MsgFieldTypeNoStringMatching = ffe("FF00145", "Field '%s' of type '%s' does not support partial or case-insensitive string matching", 400) + MsgWSSendTimedOut = ffe("FF00146", "Websocket send timed out") + MsgWSClosing = ffe("FF00147", "Websocket closing") + MsgWSConnectFailed = ffe("FF00148", "Websocket connect failed") + MsgInvalidURL = ffe("FF00149", "Invalid URL: '%s'") + MsgWSHeartbeatTimeout = ffe("FF00150", "Websocket heartbeat timed out after %.2fms", 500) + MsgAPIServerStartFailed = ffe("FF00151", "Unable to start listener on %s: %s") + MsgInvalidCAFile = ffe("FF00152", "Invalid CA certificates file") + MsgTLSConfigFailed = ffe("FF00153", "Failed to initialize TLS configuration") + MsgContextCanceled = ffe("FF00154", "Context canceled") + MsgConnectorFailInvoke = ffe("FF00155", "Connector request failed. requestId=%s failed to call connector API") + MsgConnectorInvalidContentType = ffe("FF00156", "Connector request failed. requestId=%s invalid response content type: %s") + MsgConnectorError = ffe("FF00157", "Connector request failed. requestId=%s reason=%s error: %s") ) diff --git a/pkg/i18n/es/es_base_config_descriptions.go b/pkg/i18n/es/es_base_config_descriptions.go new file mode 100644 index 0000000..66d022e --- /dev/null +++ b/pkg/i18n/es/es_base_config_descriptions.go @@ -0,0 +1,31 @@ +// Copyright © 2022 Kaleido, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package es + +import ( + "github.com/hyperledger/firefly-common/pkg/i18n" + "golang.org/x/text/language" +) + +var ffc = func(key, translation, fieldType string) i18n.ConfigMessageKey { + return i18n.FFC(language.Spanish, key, translation, fieldType) +} + +//revive:disable +var ( + ConfigGlobalConnectionTimeout = ffc("config.global.connectionTimeout", "La cantidad máxima de tiempo que una conexión puede permanecer sin datos transmitidos", i18n.TimeDurationType) +) diff --git a/pkg/i18n/messages.go b/pkg/i18n/messages.go index b0a444e..b5f5bf1 100644 --- a/pkg/i18n/messages.go +++ b/pkg/i18n/messages.go @@ -69,8 +69,8 @@ var msgIDUniq = map[string]bool{} var fallbackLangPrinter = message.NewPrinter(language.AmericanEnglish) -// FFE is the translations helper to register an error message -func FFE(language language.Tag, key, enTranslation string, statusHint ...int) ErrorMessageKey { +// FFE is the translation helper to register an error message +func FFE(language language.Tag, key, translation string, statusHint ...int) ErrorMessageKey { validPrefix := false for rp := range registeredPrefixes { if strings.HasPrefix(key, rp) { @@ -81,14 +81,14 @@ func FFE(language language.Tag, key, enTranslation string, statusHint ...int) Er if !validPrefix { panic(fmt.Sprintf("Message ID %s does not use one of the registered prefixes in the common utility package", key)) } - msgID := FFM(language, key, enTranslation) + msgID := FFM(language, key, translation) if len(statusHint) > 0 { statusHints[key] = statusHint[0] } return ErrorMessageKey(msgID) } -// FFM is the enTranslations helper to define a new message (not used in translation files) +// FFM is the translation helper to define a new message (not used in translation files) func FFM(language language.Tag, key, translation string) MessageKey { if checkKeyExists(language, key) { panic(fmt.Sprintf("Message ID %s re-used", key)) @@ -98,8 +98,8 @@ func FFM(language language.Tag, key, translation string) MessageKey { return MessageKey(key) } -// FFC is the enTranslations helper to define a configuration key description and type -func FFC(language language.Tag, key, translation string, fieldType string) ConfigMessageKey { +// FFC is the translation helper to define a configuration key description and type +func FFC(language language.Tag, key, translation, fieldType string) ConfigMessageKey { if checkKeyExists(language, key) { panic(fmt.Sprintf("Config ID %s re-used", key)) }