localization

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 7, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package localization owns translation bundles: one JSON document per microservice, environment and locale, published to the LOCALIZATION KV bucket at key "{envID}.{microserviceID}.{locale}".

The locale is validated rather than taken as given, because it is a key component — a locale carrying a dot would produce a key no consumer can parse back into its three parts. Bundle size is checked against the KV value limit before the database write, so an oversized bundle is refused outright instead of being committed as a row that can never reach a consumer.

Index

Constants

This section is empty.

Variables

View Source
var ErrBundleTooLarge = errors.New("bundle json exceeds the maximum value size")

ErrBundleTooLarge rejects a bundle bigger than a KV value may be. Accepting it would return a 201 for a row that can never be published, so the write would look successful while consumers never saw it.

View Source
var ErrConflict = errors.New("localization was modified by someone else")

ErrConflict is returned when an update carried an expected UPDATED_AT that no longer matches the stored row: somebody else edited it first. Distinct so a handler can map it to HTTP 409.

View Source
var ErrEnvironmentNotFound = errors.New("environment not found")
View Source
var ErrInvalidBundleJSON = errors.New("invalid bundle json")
View Source
var ErrInvalidEnvironmentID = errors.New("invalid environment id")
View Source
var ErrInvalidLocale = errors.New("invalid locale")
View Source
var ErrInvalidLocalizationID = errors.New("invalid localization id")
View Source
var ErrInvalidMicroserviceID = errors.New("invalid microservice id")
View Source
var ErrLocalizationExists = errors.New("localization for this microservice, environment and locale already exists")

ErrLocalizationExists collides with the natural unique key (MICROSERVICE_ID, ENVIRONMENT_ID, LOCALE). Distinct so a handler can map it to HTTP 409.

View Source
var ErrLocalizationNotFound = errors.New("localization not found")
View Source
var ErrMicroserviceNotFound = errors.New("microservice not found")

Referential integrity is checked before the insert so a missing parent row surfaces as a 404 instead of an opaque foreign-key failure.

Functions

This section is empty.

Types

type Filter

type Filter struct {
	Page
	MicroserviceID int64
	EnvironmentID  int64
	Locale         string
}

Filter narrows the localization list. Zero values match everything.

type Handler

type Handler struct {
	// contains filtered or unexported fields
}

func NewHandler

func NewHandler(service *Service) *Handler

func (*Handler) CreateLocalization

func (h *Handler) CreateLocalization(w http.ResponseWriter, r *http.Request)

POST /localization

func (*Handler) DeleteLocalization

func (h *Handler) DeleteLocalization(w http.ResponseWriter, r *http.Request)

DELETE /localization/{id}

func (*Handler) GetLocalization

func (h *Handler) GetLocalization(w http.ResponseWriter, r *http.Request)

GET /localization/lookup/{msId}/{envId}/{locale}

func (*Handler) GetLocalizationByID

func (h *Handler) GetLocalizationByID(w http.ResponseWriter, r *http.Request)

GET /localization/{id}

func (*Handler) ListLocalizations

func (h *Handler) ListLocalizations(w http.ResponseWriter, r *http.Request)

GET /localization?microserviceId=&environmentId=&locale=&limit=&offset=

func (*Handler) UpdateLocalization

func (h *Handler) UpdateLocalization(w http.ResponseWriter, r *http.Request)

PUT /localization/values

type Localization

type Localization struct {
	ID             int64           `json:"id"`
	MicroserviceID int64           `json:"microserviceId"`
	EnvironmentID  int64           `json:"environmentId"`
	Locale         string          `json:"locale"` // e.g. "pt-BR", "en-US"
	BundleJSON     json.RawMessage `json:"bundleJson"`
	UpdatedAt      time.Time       `json:"updatedAt"`

	// ExpectedUpdatedAt opts an update into optimistic concurrency: the write
	// only applies while the stored row still carries this timestamp, so two
	// admins editing the same bundle no longer silently overwrite each other.
	// Absent (nil) keeps the original last-write-wins behaviour.
	ExpectedUpdatedAt *time.Time `json:"expectedUpdatedAt,omitempty"`
}

Localization is one translation bundle for a (microservice, environment, locale) tuple. The whole locale is stored as a single JSON bundle so apps load a locale atomically and KV holds one entry per locale.

type Page

type Page struct {
	Limit  int
	Offset int
}

Page bounds a list query. The service normalises it, so a repository can bind both values as given.

type PostgresRepository

type PostgresRepository struct {
	// contains filtered or unexported fields
}

func NewPostgresRepository

func NewPostgresRepository(db *sql.DB) *PostgresRepository

func (*PostgresRepository) CreateLocalization

func (r *PostgresRepository) CreateLocalization(ctx context.Context, input Localization) (*Localization, error)

func (*PostgresRepository) DeleteLocalization

func (r *PostgresRepository) DeleteLocalization(ctx context.Context, id int64) (*Localization, error)

func (*PostgresRepository) GetLocalization

func (r *PostgresRepository) GetLocalization(ctx context.Context, microserviceID, environmentID int64, locale string) (*Localization, error)

func (*PostgresRepository) GetLocalizationByID

func (r *PostgresRepository) GetLocalizationByID(ctx context.Context, id int64) (*Localization, error)

func (*PostgresRepository) ListAllForReconcile

func (r *PostgresRepository) ListAllForReconcile(ctx context.Context, since time.Time) ([]Localization, error)

ListAllForReconcile returns localization bundles to republish to KV. A zero `since` sweeps every row; otherwise only rows changed at or after `since`.

func (*PostgresRepository) ListLocalizations

func (r *PostgresRepository) ListLocalizations(ctx context.Context, filter Filter) ([]Localization, error)

func (*PostgresRepository) UpdateLocalization

func (r *PostgresRepository) UpdateLocalization(ctx context.Context, input Localization) (*Localization, error)

type Repository

type Repository interface {
	GetLocalizationByID(ctx context.Context, id int64) (*Localization, error)
	GetLocalization(ctx context.Context, microserviceID, environmentID int64, locale string) (*Localization, error)
	UpdateLocalization(ctx context.Context, input Localization) (*Localization, error)

	ListLocalizations(ctx context.Context, filter Filter) ([]Localization, error)
	CreateLocalization(ctx context.Context, input Localization) (*Localization, error)
	// DeleteLocalization returns the row it removed, so the caller can derive
	// the KV key it has to purge.
	DeleteLocalization(ctx context.Context, id int64) (*Localization, error)
}

type SQLiteRepository

type SQLiteRepository struct {
	// contains filtered or unexported fields
}

SQLiteRepository backs the local test stack (see internal/database/sqlite.go). Same tables and columns as PostgreSQL; only the bind syntax differs (? vs $1).

func NewSQLiteRepository

func NewSQLiteRepository(db *sql.DB) *SQLiteRepository

func (*SQLiteRepository) CreateLocalization

func (r *SQLiteRepository) CreateLocalization(ctx context.Context, input Localization) (*Localization, error)

func (*SQLiteRepository) DeleteLocalization

func (r *SQLiteRepository) DeleteLocalization(ctx context.Context, id int64) (*Localization, error)

func (*SQLiteRepository) GetLocalization

func (r *SQLiteRepository) GetLocalization(ctx context.Context, microserviceID, environmentID int64, locale string) (*Localization, error)

func (*SQLiteRepository) GetLocalizationByID

func (r *SQLiteRepository) GetLocalizationByID(ctx context.Context, id int64) (*Localization, error)

func (*SQLiteRepository) ListAllForReconcile

func (r *SQLiteRepository) ListAllForReconcile(ctx context.Context, since time.Time) ([]Localization, error)

func (*SQLiteRepository) ListLocalizations

func (r *SQLiteRepository) ListLocalizations(ctx context.Context, filter Filter) ([]Localization, error)

func (*SQLiteRepository) UpdateLocalization

func (r *SQLiteRepository) UpdateLocalization(ctx context.Context, input Localization) (*Localization, error)

type Service

type Service struct {
	// contains filtered or unexported fields
}

func NewService

func NewService(repo Repository, pub messaging.ConfigPublisher) *Service

func (*Service) CreateLocalization

func (s *Service) CreateLocalization(ctx context.Context, req Localization) (*Localization, error)

func (*Service) DeleteLocalization

func (s *Service) DeleteLocalization(ctx context.Context, id int64) error

DeleteLocalization removes the row and the KV key it fed. Waiting for the next full reconcile to prune the key would leave consumers serving a deleted locale for up to a whole interval.

func (*Service) GetLocalization

func (s *Service) GetLocalization(ctx context.Context, microserviceID, environmentID int64, locale string) (*Localization, error)

func (*Service) GetLocalizationByID

func (s *Service) GetLocalizationByID(ctx context.Context, id int64) (*Localization, error)

func (*Service) ListLocalizations

func (s *Service) ListLocalizations(ctx context.Context, filter Filter) ([]Localization, error)

func (*Service) UpdateLocalization

func (s *Service) UpdateLocalization(ctx context.Context, req Localization) (*Localization, error)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL