3
0

Apply i18n to the more complex Compose resources

This commit is contained in:
Tomaž Jerman 2021-09-14 13:24:22 +02:00
parent f457ee6c12
commit e8e998293d
21 changed files with 1570 additions and 12 deletions

View File

@ -12,6 +12,7 @@ endpoints:
authentication: []
imports:
- github.com/cortezaproject/corteza-server/pkg/label
- github.com/cortezaproject/corteza-server/pkg/locale
- sqlxTypes github.com/jmoiron/sqlx/types
- time
apis:
@ -148,6 +149,32 @@ endpoints:
type: string
title: Script to execute
required: true
- name: list resource
method: GET
title: List resource translations
path: "/{namespaceID}/locale"
parameters:
path:
- type: uint64
name: namespaceID
required: true
title: ID
- name: update resource
method: PATCH
title: Update resource translations
path: "/{namespaceID}/locale"
parameters:
path:
- type: uint64
name: namespaceID
required: true
title: ID
post:
- name: locale
type: locale.ResourceTranslationSet
title: Resource translations to upsert
required: true
- title: Pages
description: Compose pages
entrypoint: page
@ -155,6 +182,7 @@ endpoints:
authentication: []
imports:
- sqlxTypes github.com/jmoiron/sqlx/types
- github.com/cortezaproject/corteza-server/pkg/locale
- github.com/cortezaproject/corteza-server/pkg/label
parameters:
path:
@ -357,6 +385,33 @@ endpoints:
type: string
title: Script to execute
required: true
- name: list resource
method: GET
title: List resource translations
path: "/{pageID}/locale"
parameters:
path:
- type: uint64
name: pageID
required: true
title: ID
- name: update resource
method: PATCH
title: Update resource translations
path: "/{pageID}/locale"
parameters:
path:
- type: uint64
name: pageID
required: true
title: ID
post:
- name: locale
type: locale.ResourceTranslationSet
title: Resource translations to upsert
required: true
- title: Modules
description: Compose module definitions
entrypoint: module
@ -371,6 +426,7 @@ endpoints:
imports:
- sqlxTypes github.com/jmoiron/sqlx/types
- github.com/cortezaproject/corteza-server/compose/types
- github.com/cortezaproject/corteza-server/pkg/locale
- github.com/cortezaproject/corteza-server/pkg/label
- time
apis:
@ -501,6 +557,32 @@ endpoints:
type: string
title: Script to execute
required: true
- name: list resource
method: GET
title: List resource translations
path: "/{moduleID}/locale"
parameters:
path:
- type: uint64
name: moduleID
required: true
title: ID
- name: update resource
method: PATCH
title: Update resource translations
path: "/{moduleID}/locale"
parameters:
path:
- type: uint64
name: moduleID
required: true
title: ID
post:
- name: locale
type: locale.ResourceTranslationSet
title: Resource translations to upsert
required: true
- title: Records
description: Compose records
entrypoint: record

View File

@ -25,6 +25,8 @@ type (
Update(context.Context, *request.ModuleUpdate) (interface{}, error)
Delete(context.Context, *request.ModuleDelete) (interface{}, error)
TriggerScript(context.Context, *request.ModuleTriggerScript) (interface{}, error)
ListLocale(context.Context, *request.ModuleListLocale) (interface{}, error)
UpdateLocale(context.Context, *request.ModuleUpdateLocale) (interface{}, error)
}
// HTTP API interface
@ -35,6 +37,8 @@ type (
Update func(http.ResponseWriter, *http.Request)
Delete func(http.ResponseWriter, *http.Request)
TriggerScript func(http.ResponseWriter, *http.Request)
ListLocale func(http.ResponseWriter, *http.Request)
UpdateLocale func(http.ResponseWriter, *http.Request)
}
)
@ -134,6 +138,38 @@ func NewModule(h ModuleAPI) *Module {
return
}
api.Send(w, r, value)
},
ListLocale: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewModuleListLocale()
if err := params.Fill(r); err != nil {
api.Send(w, r, err)
return
}
value, err := h.ListLocale(r.Context(), params)
if err != nil {
api.Send(w, r, err)
return
}
api.Send(w, r, value)
},
UpdateLocale: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewModuleUpdateLocale()
if err := params.Fill(r); err != nil {
api.Send(w, r, err)
return
}
value, err := h.UpdateLocale(r.Context(), params)
if err != nil {
api.Send(w, r, err)
return
}
api.Send(w, r, value)
},
}
@ -148,5 +184,7 @@ func (h Module) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http
r.Post("/namespace/{namespaceID}/module/{moduleID}", h.Update)
r.Delete("/namespace/{namespaceID}/module/{moduleID}", h.Delete)
r.Post("/namespace/{namespaceID}/module/{moduleID}/trigger", h.TriggerScript)
r.Get("/namespace/{namespaceID}/module/{moduleID}/locale", h.ListLocale)
r.Patch("/namespace/{namespaceID}/module/{moduleID}/locale", h.UpdateLocale)
})
}

View File

@ -26,6 +26,8 @@ type (
Delete(context.Context, *request.NamespaceDelete) (interface{}, error)
Upload(context.Context, *request.NamespaceUpload) (interface{}, error)
TriggerScript(context.Context, *request.NamespaceTriggerScript) (interface{}, error)
ListLocale(context.Context, *request.NamespaceListLocale) (interface{}, error)
UpdateLocale(context.Context, *request.NamespaceUpdateLocale) (interface{}, error)
}
// HTTP API interface
@ -37,6 +39,8 @@ type (
Delete func(http.ResponseWriter, *http.Request)
Upload func(http.ResponseWriter, *http.Request)
TriggerScript func(http.ResponseWriter, *http.Request)
ListLocale func(http.ResponseWriter, *http.Request)
UpdateLocale func(http.ResponseWriter, *http.Request)
}
)
@ -152,6 +156,38 @@ func NewNamespace(h NamespaceAPI) *Namespace {
return
}
api.Send(w, r, value)
},
ListLocale: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewNamespaceListLocale()
if err := params.Fill(r); err != nil {
api.Send(w, r, err)
return
}
value, err := h.ListLocale(r.Context(), params)
if err != nil {
api.Send(w, r, err)
return
}
api.Send(w, r, value)
},
UpdateLocale: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewNamespaceUpdateLocale()
if err := params.Fill(r); err != nil {
api.Send(w, r, err)
return
}
value, err := h.UpdateLocale(r.Context(), params)
if err != nil {
api.Send(w, r, err)
return
}
api.Send(w, r, value)
},
}
@ -167,5 +203,7 @@ func (h Namespace) MountRoutes(r chi.Router, middlewares ...func(http.Handler) h
r.Delete("/namespace/{namespaceID}", h.Delete)
r.Post("/namespace/upload", h.Upload)
r.Post("/namespace/{namespaceID}/trigger", h.TriggerScript)
r.Get("/namespace/{namespaceID}/locale", h.ListLocale)
r.Patch("/namespace/{namespaceID}/locale", h.UpdateLocale)
})
}

View File

@ -28,6 +28,8 @@ type (
Delete(context.Context, *request.PageDelete) (interface{}, error)
Upload(context.Context, *request.PageUpload) (interface{}, error)
TriggerScript(context.Context, *request.PageTriggerScript) (interface{}, error)
ListLocale(context.Context, *request.PageListLocale) (interface{}, error)
UpdateLocale(context.Context, *request.PageUpdateLocale) (interface{}, error)
}
// HTTP API interface
@ -41,6 +43,8 @@ type (
Delete func(http.ResponseWriter, *http.Request)
Upload func(http.ResponseWriter, *http.Request)
TriggerScript func(http.ResponseWriter, *http.Request)
ListLocale func(http.ResponseWriter, *http.Request)
UpdateLocale func(http.ResponseWriter, *http.Request)
}
)
@ -188,6 +192,38 @@ func NewPage(h PageAPI) *Page {
return
}
api.Send(w, r, value)
},
ListLocale: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewPageListLocale()
if err := params.Fill(r); err != nil {
api.Send(w, r, err)
return
}
value, err := h.ListLocale(r.Context(), params)
if err != nil {
api.Send(w, r, err)
return
}
api.Send(w, r, value)
},
UpdateLocale: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewPageUpdateLocale()
if err := params.Fill(r); err != nil {
api.Send(w, r, err)
return
}
value, err := h.UpdateLocale(r.Context(), params)
if err != nil {
api.Send(w, r, err)
return
}
api.Send(w, r, value)
},
}
@ -205,5 +241,7 @@ func (h Page) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.H
r.Delete("/namespace/{namespaceID}/page/{pageID}", h.Delete)
r.Post("/namespace/{namespaceID}/page/{pageID}/attachment", h.Upload)
r.Post("/namespace/{namespaceID}/page/{pageID}/trigger", h.TriggerScript)
r.Get("/namespace/{namespaceID}/page/{pageID}/locale", h.ListLocale)
r.Patch("/namespace/{namespaceID}/page/{pageID}/locale", h.UpdateLocale)
})
}

View File

@ -38,6 +38,7 @@ type (
Module struct {
module service.ModuleService
locale service.ResourceTranslationService
namespace service.NamespaceService
ac moduleAccessController
}
@ -60,6 +61,7 @@ func (Module) New() *Module {
module: service.DefaultModule,
namespace: service.DefaultNamespace,
ac: service.DefaultAccessControl,
locale: service.DefaultResourceTranslation,
}
}
@ -92,6 +94,14 @@ func (ctrl *Module) Read(ctx context.Context, r *request.ModuleRead) (interface{
return ctrl.makePayload(ctx, mod, err)
}
func (ctrl *Module) ListLocale(ctx context.Context, r *request.ModuleListLocale) (interface{}, error) {
return ctrl.locale.Module(ctx, r.NamespaceID, r.ModuleID)
}
func (ctrl *Module) UpdateLocale(ctx context.Context, r *request.ModuleUpdateLocale) (interface{}, error) {
return api.OK(), ctrl.locale.Upsert(ctx, r.Locale)
}
func (ctrl *Module) Create(ctx context.Context, r *request.ModuleCreate) (interface{}, error) {
var (
err error

View File

@ -32,6 +32,7 @@ type (
Namespace struct {
namespace service.NamespaceService
locale service.ResourceTranslationService
attachment service.AttachmentService
ac namespaceAccessController
}
@ -52,6 +53,7 @@ type (
func (Namespace) New() *Namespace {
return &Namespace{
namespace: service.DefaultNamespace,
locale: service.DefaultResourceTranslation,
attachment: service.DefaultAttachment,
ac: service.DefaultAccessControl,
}
@ -103,6 +105,14 @@ func (ctrl Namespace) Read(ctx context.Context, r *request.NamespaceRead) (inter
return ctrl.makePayload(ctx, ns, err)
}
func (ctrl Namespace) ListLocale(ctx context.Context, r *request.NamespaceListLocale) (interface{}, error) {
return ctrl.locale.Namespace(ctx, r.NamespaceID)
}
func (ctrl Namespace) UpdateLocale(ctx context.Context, r *request.NamespaceUpdateLocale) (interface{}, error) {
return api.OK(), ctrl.locale.Upsert(ctx, r.Locale)
}
func (ctrl Namespace) Update(ctx context.Context, r *request.NamespaceUpdate) (interface{}, error) {
var (
err error

View File

@ -44,6 +44,7 @@ type (
Reorder(ctx context.Context, namespaceID, selfID uint64, pageIDs []uint64) error
}
locale service.ResourceTranslationService
namespace service.NamespaceService
attachment service.AttachmentService
ac pageAccessController
@ -60,6 +61,7 @@ type (
func (Page) New() *Page {
return &Page{
page: service.DefaultPage,
locale: service.DefaultResourceTranslation,
namespace: service.DefaultNamespace,
attachment: service.DefaultAttachment,
ac: service.DefaultAccessControl,
@ -125,7 +127,14 @@ func (ctrl *Page) Create(ctx context.Context, r *request.PageCreate) (interface{
func (ctrl *Page) Read(ctx context.Context, r *request.PageRead) (interface{}, error) {
mod, err := ctrl.page.FindByID(ctx, r.NamespaceID, r.PageID)
return ctrl.makePayload(ctx, mod, err)
}
func (ctrl *Page) ListLocale(ctx context.Context, r *request.PageListLocale) (interface{}, error) {
return ctrl.locale.Page(ctx, r.NamespaceID, r.PageID)
}
func (ctrl *Page) UpdateLocale(ctx context.Context, r *request.PageUpdateLocale) (interface{}, error) {
return api.OK(), ctrl.locale.Upsert(ctx, r.Locale)
}
func (ctrl *Page) Reorder(ctx context.Context, r *request.PageReorder) (interface{}, error) {

View File

@ -13,6 +13,7 @@ import (
"fmt"
"github.com/cortezaproject/corteza-server/compose/types"
"github.com/cortezaproject/corteza-server/pkg/label"
"github.com/cortezaproject/corteza-server/pkg/locale"
"github.com/cortezaproject/corteza-server/pkg/payload"
"github.com/go-chi/chi"
sqlxTypes "github.com/jmoiron/sqlx/types"
@ -193,6 +194,35 @@ type (
// Script to execute
Script string
}
ModuleListLocale struct {
// NamespaceID PATH parameter
//
// Namespace ID
NamespaceID uint64 `json:",string"`
// ModuleID PATH parameter
//
// ID
ModuleID uint64 `json:",string"`
}
ModuleUpdateLocale struct {
// NamespaceID PATH parameter
//
// Namespace ID
NamespaceID uint64 `json:",string"`
// ModuleID PATH parameter
//
// ID
ModuleID uint64 `json:",string"`
// Locale POST parameter
//
// ...
Locale locale.ResourceTranslationSet
}
)
// NewModuleList request
@ -770,3 +800,129 @@ func (r *ModuleTriggerScript) Fill(req *http.Request) (err error) {
return err
}
// NewModuleListLocale request
func NewModuleListLocale() *ModuleListLocale {
return &ModuleListLocale{}
}
// Auditable returns all auditable/loggable parameters
func (r ModuleListLocale) Auditable() map[string]interface{} {
return map[string]interface{}{
"namespaceID": r.NamespaceID,
"moduleID": r.ModuleID,
}
}
// Auditable returns all auditable/loggable parameters
func (r ModuleListLocale) GetNamespaceID() uint64 {
return r.NamespaceID
}
// Auditable returns all auditable/loggable parameters
func (r ModuleListLocale) GetModuleID() uint64 {
return r.ModuleID
}
// Fill processes request and fills internal variables
func (r *ModuleListLocale) Fill(req *http.Request) (err error) {
{
var val string
// path params
val = chi.URLParam(req, "namespaceID")
r.NamespaceID, err = payload.ParseUint64(val), nil
if err != nil {
return err
}
val = chi.URLParam(req, "moduleID")
r.ModuleID, err = payload.ParseUint64(val), nil
if err != nil {
return err
}
}
return err
}
// NewModuleUpdateLocale request
func NewModuleUpdateLocale() *ModuleUpdateLocale {
return &ModuleUpdateLocale{}
}
// Auditable returns all auditable/loggable parameters
func (r ModuleUpdateLocale) Auditable() map[string]interface{} {
return map[string]interface{}{
"namespaceID": r.NamespaceID,
"moduleID": r.ModuleID,
"locale": r.Locale,
}
}
// Auditable returns all auditable/loggable parameters
func (r ModuleUpdateLocale) GetNamespaceID() uint64 {
return r.NamespaceID
}
// Auditable returns all auditable/loggable parameters
func (r ModuleUpdateLocale) GetModuleID() uint64 {
return r.ModuleID
}
// Auditable returns all auditable/loggable parameters
func (r ModuleUpdateLocale) GetLocale() locale.ResourceTranslationSet {
return r.Locale
}
// Fill processes request and fills internal variables
func (r *ModuleUpdateLocale) Fill(req *http.Request) (err error) {
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
err = json.NewDecoder(req.Body).Decode(r)
switch {
case err == io.EOF:
err = nil
case err != nil:
return fmt.Errorf("error parsing http request body: %w", err)
}
}
{
if err = req.ParseForm(); err != nil {
return err
}
// POST params
//if val, ok := req.Form["locale[]"]; ok && len(val) > 0 {
// r.Locale, err = locale.ResourceTranslationSet(val), nil
// if err != nil {
// return err
// }
//}
}
{
var val string
// path params
val = chi.URLParam(req, "namespaceID")
r.NamespaceID, err = payload.ParseUint64(val), nil
if err != nil {
return err
}
val = chi.URLParam(req, "moduleID")
r.ModuleID, err = payload.ParseUint64(val), nil
if err != nil {
return err
}
}
return err
}

View File

@ -12,6 +12,7 @@ import (
"encoding/json"
"fmt"
"github.com/cortezaproject/corteza-server/pkg/label"
"github.com/cortezaproject/corteza-server/pkg/locale"
"github.com/cortezaproject/corteza-server/pkg/payload"
"github.com/go-chi/chi"
sqlxTypes "github.com/jmoiron/sqlx/types"
@ -164,6 +165,25 @@ type (
// Script to execute
Script string
}
NamespaceListLocale struct {
// NamespaceID PATH parameter
//
// ID
NamespaceID uint64 `json:",string"`
}
NamespaceUpdateLocale struct {
// NamespaceID PATH parameter
//
// ID
NamespaceID uint64 `json:",string"`
// Locale POST parameter
//
// ...
Locale locale.ResourceTranslationSet
}
)
// NewNamespaceList request
@ -692,3 +712,105 @@ func (r *NamespaceTriggerScript) Fill(req *http.Request) (err error) {
return err
}
// NewNamespaceListLocale request
func NewNamespaceListLocale() *NamespaceListLocale {
return &NamespaceListLocale{}
}
// Auditable returns all auditable/loggable parameters
func (r NamespaceListLocale) Auditable() map[string]interface{} {
return map[string]interface{}{
"namespaceID": r.NamespaceID,
}
}
// Auditable returns all auditable/loggable parameters
func (r NamespaceListLocale) GetNamespaceID() uint64 {
return r.NamespaceID
}
// Fill processes request and fills internal variables
func (r *NamespaceListLocale) Fill(req *http.Request) (err error) {
{
var val string
// path params
val = chi.URLParam(req, "namespaceID")
r.NamespaceID, err = payload.ParseUint64(val), nil
if err != nil {
return err
}
}
return err
}
// NewNamespaceUpdateLocale request
func NewNamespaceUpdateLocale() *NamespaceUpdateLocale {
return &NamespaceUpdateLocale{}
}
// Auditable returns all auditable/loggable parameters
func (r NamespaceUpdateLocale) Auditable() map[string]interface{} {
return map[string]interface{}{
"namespaceID": r.NamespaceID,
"locale": r.Locale,
}
}
// Auditable returns all auditable/loggable parameters
func (r NamespaceUpdateLocale) GetNamespaceID() uint64 {
return r.NamespaceID
}
// Auditable returns all auditable/loggable parameters
func (r NamespaceUpdateLocale) GetLocale() locale.ResourceTranslationSet {
return r.Locale
}
// Fill processes request and fills internal variables
func (r *NamespaceUpdateLocale) Fill(req *http.Request) (err error) {
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
err = json.NewDecoder(req.Body).Decode(r)
switch {
case err == io.EOF:
err = nil
case err != nil:
return fmt.Errorf("error parsing http request body: %w", err)
}
}
{
if err = req.ParseForm(); err != nil {
return err
}
// POST params
//if val, ok := req.Form["locale[]"]; ok && len(val) > 0 {
// r.Locale, err = locale.ResourceTranslationSet(val), nil
// if err != nil {
// return err
// }
//}
}
{
var val string
// path params
val = chi.URLParam(req, "namespaceID")
r.NamespaceID, err = payload.ParseUint64(val), nil
if err != nil {
return err
}
}
return err
}

View File

@ -12,6 +12,7 @@ import (
"encoding/json"
"fmt"
"github.com/cortezaproject/corteza-server/pkg/label"
"github.com/cortezaproject/corteza-server/pkg/locale"
"github.com/cortezaproject/corteza-server/pkg/payload"
"github.com/go-chi/chi"
sqlxTypes "github.com/jmoiron/sqlx/types"
@ -272,6 +273,35 @@ type (
// Script to execute
Script string
}
PageListLocale struct {
// NamespaceID PATH parameter
//
// Namespace ID
NamespaceID uint64 `json:",string"`
// PageID PATH parameter
//
// ID
PageID uint64 `json:",string"`
}
PageUpdateLocale struct {
// NamespaceID PATH parameter
//
// Namespace ID
NamespaceID uint64 `json:",string"`
// PageID PATH parameter
//
// ID
PageID uint64 `json:",string"`
// Locale POST parameter
//
// ...
Locale locale.ResourceTranslationSet
}
)
// NewPageList request
@ -1143,3 +1173,129 @@ func (r *PageTriggerScript) Fill(req *http.Request) (err error) {
return err
}
// NewPageListLocale request
func NewPageListLocale() *PageListLocale {
return &PageListLocale{}
}
// Auditable returns all auditable/loggable parameters
func (r PageListLocale) Auditable() map[string]interface{} {
return map[string]interface{}{
"namespaceID": r.NamespaceID,
"pageID": r.PageID,
}
}
// Auditable returns all auditable/loggable parameters
func (r PageListLocale) GetNamespaceID() uint64 {
return r.NamespaceID
}
// Auditable returns all auditable/loggable parameters
func (r PageListLocale) GetPageID() uint64 {
return r.PageID
}
// Fill processes request and fills internal variables
func (r *PageListLocale) Fill(req *http.Request) (err error) {
{
var val string
// path params
val = chi.URLParam(req, "namespaceID")
r.NamespaceID, err = payload.ParseUint64(val), nil
if err != nil {
return err
}
val = chi.URLParam(req, "pageID")
r.PageID, err = payload.ParseUint64(val), nil
if err != nil {
return err
}
}
return err
}
// NewPageUpdateLocale request
func NewPageUpdateLocale() *PageUpdateLocale {
return &PageUpdateLocale{}
}
// Auditable returns all auditable/loggable parameters
func (r PageUpdateLocale) Auditable() map[string]interface{} {
return map[string]interface{}{
"namespaceID": r.NamespaceID,
"pageID": r.PageID,
"locale": r.Locale,
}
}
// Auditable returns all auditable/loggable parameters
func (r PageUpdateLocale) GetNamespaceID() uint64 {
return r.NamespaceID
}
// Auditable returns all auditable/loggable parameters
func (r PageUpdateLocale) GetPageID() uint64 {
return r.PageID
}
// Auditable returns all auditable/loggable parameters
func (r PageUpdateLocale) GetLocale() locale.ResourceTranslationSet {
return r.Locale
}
// Fill processes request and fills internal variables
func (r *PageUpdateLocale) Fill(req *http.Request) (err error) {
if strings.ToLower(req.Header.Get("content-type")) == "application/json" {
err = json.NewDecoder(req.Body).Decode(r)
switch {
case err == io.EOF:
err = nil
case err != nil:
return fmt.Errorf("error parsing http request body: %w", err)
}
}
{
if err = req.ParseForm(); err != nil {
return err
}
// POST params
//if val, ok := req.Form["locale[]"]; ok && len(val) > 0 {
// r.Locale, err = locale.ResourceTranslationSet(val), nil
// if err != nil {
// return err
// }
//}
}
{
var val string
// path params
val = chi.URLParam(req, "namespaceID")
r.NamespaceID, err = payload.ParseUint64(val), nil
if err != nil {
return err
}
val = chi.URLParam(req, "pageID")
r.PageID, err = payload.ParseUint64(val), nil
if err != nil {
return err
}
}
return err
}

213
compose/service/locale.gen.go generated Normal file
View File

@ -0,0 +1,213 @@
package service
// This file is auto-generated.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//
// Definitions file that controls how this file is generated:
// - compose.module.yaml
// - compose.namespace.yaml
// - compose.page.yaml
import (
"context"
"github.com/cortezaproject/corteza-server/compose/types"
"github.com/cortezaproject/corteza-server/pkg/actionlog"
"github.com/cortezaproject/corteza-server/pkg/auth"
"github.com/cortezaproject/corteza-server/pkg/locale"
"github.com/cortezaproject/corteza-server/store"
systemTypes "github.com/cortezaproject/corteza-server/system/types"
)
type (
resourceTranslation struct {
actionlog actionlog.Recorder
locale locale.Resource
store store.Storer
ac localeAccessController
}
localeAccessController interface {
// CanManageResourceTranslation(context.Context) bool
}
ResourceTranslationService interface {
Module(ctx context.Context, namespaceID uint64, ID uint64) (locale.ResourceTranslationSet, error)
Namespace(ctx context.Context, ID uint64) (locale.ResourceTranslationSet, error)
Page(ctx context.Context, namespaceID uint64, ID uint64) (locale.ResourceTranslationSet, error)
Upsert(context.Context, locale.ResourceTranslationSet) error
Locale() locale.Resource
}
)
func ResourceTranslation(ls locale.Resource) *resourceTranslation {
return &resourceTranslation{
actionlog: DefaultActionlog,
store: DefaultStore,
locale: ls,
}
}
func (svc resourceTranslation) Upsert(ctx context.Context, rr locale.ResourceTranslationSet) (err error) {
// @todo AC
// @todo validation
defer locale.Global().ReloadResourceTranslations(ctx)
me := auth.GetIdentityFromContext(ctx)
// - group by resource
localeByRes := make(map[string]locale.ResourceTranslationSet)
for _, r := range rr {
localeByRes[r.Resource] = append(localeByRes[r.Resource], r)
}
// - for each resource, fetch the current state
sysLocale := make(systemTypes.ResourceTranslationSet, 0, len(rr))
for res, rr := range localeByRes {
current, _, err := store.SearchResourceTranslations(ctx, svc.store, systemTypes.ResourceTranslationFilter{
Resource: res,
})
if err != nil {
return err
}
// get deltas and prepare upsert accordingly
aux := current.New(rr)
aux.Walk(func(cc *systemTypes.ResourceTranslation) error {
cc.ID = nextID()
cc.CreatedAt = *now()
cc.CreatedBy = me.Identity()
return nil
})
sysLocale = append(sysLocale, aux...)
aux = current.Old(rr)
aux.Walk(func(cc *systemTypes.ResourceTranslation) error {
cc.UpdatedAt = now()
cc.UpdatedBy = me.Identity()
return nil
})
sysLocale = append(sysLocale, aux...)
}
err = store.UpsertResourceTranslation(ctx, svc.store, sysLocale...)
if err != nil {
return err
}
return nil
}
func (svc resourceTranslation) Locale() locale.Resource {
return svc.locale
}
func (svc resourceTranslation) Module(ctx context.Context, namespaceID uint64, ID uint64) (locale.ResourceTranslationSet, error) {
var (
err error
out locale.ResourceTranslationSet
res *types.Module
k types.LocaleKey
)
res, err = svc.loadModule(ctx, svc.store, namespaceID, ID)
if err != nil {
return nil, err
}
for _, tag := range svc.locale.Tags() {
k = types.LocaleKeyModuleName
out = append(out, &locale.ResourceTranslation{
Resource: res.ResourceTranslation(),
Lang: tag.String(),
Key: k.Path,
Msg: svc.locale.TRFor(tag, res.ResourceTranslation(), k.Path),
})
}
tmp, err := svc.moduleExtended(ctx, res)
return append(out, tmp...), err
}
func (svc resourceTranslation) Namespace(ctx context.Context, ID uint64) (locale.ResourceTranslationSet, error) {
var (
err error
out locale.ResourceTranslationSet
res *types.Namespace
k types.LocaleKey
)
res, err = svc.loadNamespace(ctx, svc.store, ID)
if err != nil {
return nil, err
}
for _, tag := range svc.locale.Tags() {
k = types.LocaleKeyNamespaceName
out = append(out, &locale.ResourceTranslation{
Resource: res.ResourceTranslation(),
Lang: tag.String(),
Key: k.Path,
Msg: svc.locale.TRFor(tag, res.ResourceTranslation(), k.Path),
})
k = types.LocaleKeyNamespaceSubtitle
out = append(out, &locale.ResourceTranslation{
Resource: res.ResourceTranslation(),
Lang: tag.String(),
Key: k.Path,
Msg: svc.locale.TRFor(tag, res.ResourceTranslation(), k.Path),
})
k = types.LocaleKeyNamespaceDescription
out = append(out, &locale.ResourceTranslation{
Resource: res.ResourceTranslation(),
Lang: tag.String(),
Key: k.Path,
Msg: svc.locale.TRFor(tag, res.ResourceTranslation(), k.Path),
})
}
return out, nil
}
func (svc resourceTranslation) Page(ctx context.Context, namespaceID uint64, ID uint64) (locale.ResourceTranslationSet, error) {
var (
err error
out locale.ResourceTranslationSet
res *types.Page
k types.LocaleKey
)
res, err = svc.loadPage(ctx, svc.store, namespaceID, ID)
if err != nil {
return nil, err
}
for _, tag := range svc.locale.Tags() {
k = types.LocaleKeyPageTitle
out = append(out, &locale.ResourceTranslation{
Resource: res.ResourceTranslation(),
Lang: tag.String(),
Key: k.Path,
Msg: svc.locale.TRFor(tag, res.ResourceTranslation(), k.Path),
})
k = types.LocaleKeyPageDescription
out = append(out, &locale.ResourceTranslation{
Resource: res.ResourceTranslation(),
Lang: tag.String(),
Key: k.Path,
Msg: svc.locale.TRFor(tag, res.ResourceTranslation(), k.Path),
})
}
tmp, err := svc.pageExtended(ctx, res)
return append(out, tmp...), err
}

150
compose/service/locale.go Normal file
View File

@ -0,0 +1,150 @@
package service
import (
"context"
"strconv"
"strings"
"github.com/cortezaproject/corteza-server/compose/types"
"github.com/cortezaproject/corteza-server/pkg/locale"
"github.com/cortezaproject/corteza-server/store"
"github.com/spf13/cast"
"golang.org/x/text/language"
)
func (svc resourceTranslation) moduleExtended(ctx context.Context, res *types.Module) (out locale.ResourceTranslationSet, err error) {
var (
k types.LocaleKey
)
for _, tag := range svc.locale.Tags() {
for _, f := range res.Fields {
k = types.LocaleKeyModuleFieldLabel
out = append(out, &locale.ResourceTranslation{
Resource: res.ResourceTranslation(),
Lang: tag.String(),
Key: k.Path,
Msg: svc.locale.TRFor(tag, res.ResourceTranslation(), k.Path),
})
// Extra field bits
converted, err := svc.moduleFieldValidatorErrorHandler(ctx, tag, f, k.Path)
if err != nil {
return nil, err
}
out = append(out, converted...)
}
}
return out, nil
}
func (svc resourceTranslation) moduleFieldValidatorErrorHandler(ctx context.Context, tag language.Tag, f *types.ModuleField, k string) (locale.ResourceTranslationSet, error) {
out := make(locale.ResourceTranslationSet, 0, 10)
for i, v := range f.Expressions.Validators {
vContentID := locale.ContentID(v.ValidatorID, i)
rpl := strings.NewReplacer(
"{{validatorID}}", strconv.FormatUint(vContentID, 10),
)
tKey := rpl.Replace(k)
out = append(out, &locale.ResourceTranslation{
Resource: f.ResourceTranslation(),
Lang: tag.String(),
Key: tKey,
Msg: svc.locale.TRFor(tag, f.ResourceTranslation(), tKey),
})
}
return out, nil
}
func (svc resourceTranslation) pageExtended(ctx context.Context, res *types.Page) (out locale.ResourceTranslationSet, err error) {
var (
k types.LocaleKey
)
for _, tag := range svc.locale.Tags() {
for i, block := range res.Blocks {
pbContentID := locale.ContentID(block.BlockID, i)
rpl := strings.NewReplacer(
"{{blockID}}", strconv.FormatUint(pbContentID, 10),
)
// base stuff
k = types.LocaleKeyPageBlockTitle
out = append(out, &locale.ResourceTranslation{
Resource: res.ResourceTranslation(),
Lang: tag.String(),
Key: rpl.Replace(k.Path),
Msg: svc.locale.TRFor(tag, res.ResourceTranslation(), rpl.Replace(k.Path)),
})
k = types.LocaleKeyPageBlockDescription
out = append(out, &locale.ResourceTranslation{
Resource: res.ResourceTranslation(),
Lang: tag.String(),
Key: rpl.Replace(k.Path),
Msg: svc.locale.TRFor(tag, res.ResourceTranslation(), rpl.Replace(k.Path)),
})
switch block.Kind {
case "Automation":
aux, err := svc.pageExtendedAutomatinBlock(tag, res, block, pbContentID, k)
if err != nil {
return nil, err
}
out = append(out, aux...)
}
}
}
return
}
func (svc resourceTranslation) pageExtendedAutomatinBlock(tag language.Tag, res *types.Page, block types.PageBlock, blockID uint64, k types.LocaleKey) (locale.ResourceTranslationSet, error) {
out := make(locale.ResourceTranslationSet, 0, 10)
bb, _ := block.Options["buttons"].([]interface{})
for j, auxBtn := range bb {
btn := auxBtn.(map[string]interface{})
bContentID := uint64(0)
if aux, ok := btn["buttonID"]; ok {
bContentID = cast.ToUint64(aux)
}
bContentID = locale.ContentID(bContentID, j)
rpl := strings.NewReplacer(
"{{blockID}}", strconv.FormatUint(blockID, 10),
"{{buttonID}}", strconv.FormatUint(bContentID, 10),
)
out = append(out, &locale.ResourceTranslation{
Resource: res.ResourceTranslation(),
Lang: tag.String(),
Key: rpl.Replace(k.Path),
Msg: svc.locale.TRFor(tag, res.ResourceTranslation(), rpl.Replace(k.Path)),
})
}
return out, nil
}
// Helper loaders
func (svc resourceTranslation) loadModule(ctx context.Context, s store.Storer, namespaceID, moduleID uint64) (m *types.Module, err error) {
return loadModule(ctx, s, moduleID)
}
func (svc resourceTranslation) loadNamespace(ctx context.Context, s store.Storer, namespaceID uint64) (m *types.Namespace, err error) {
return loadNamespace(ctx, s, namespaceID)
}
func (svc resourceTranslation) loadPage(ctx context.Context, s store.Storer, namespaceID, pageID uint64) (m *types.Page, err error) {
_, m, err = loadPage(ctx, s, namespaceID, pageID)
return m, err
}

View File

@ -16,6 +16,7 @@ import (
"github.com/cortezaproject/corteza-server/pkg/filter"
"github.com/cortezaproject/corteza-server/pkg/handle"
"github.com/cortezaproject/corteza-server/pkg/label"
"github.com/cortezaproject/corteza-server/pkg/locale"
"github.com/cortezaproject/corteza-server/store"
)
@ -25,6 +26,7 @@ type (
ac moduleAccessController
eventbus eventDispatcher
store store.Storer
locale ResourceTranslationService
}
moduleAccessController interface {
@ -66,6 +68,7 @@ func Module() *module {
eventbus: eventbus.Service(),
actionlog: DefaultActionlog,
store: DefaultStore,
locale: DefaultResourceTranslation,
}
}
@ -122,7 +125,23 @@ func (svc module) Find(ctx context.Context, filter types.ModuleFilter) (set type
return err
}
return loadModuleFields(ctx, svc.store, set...)
err = loadModuleFields(ctx, svc.store, set...)
if err != nil {
return err
}
// i18n
tag := locale.GetLanguageFromContext(ctx)
set.Walk(func(m *types.Module) error {
m.DecodeTranslations(svc.locale.Locale().ResourceTranslations(tag, m.ResourceTranslation()))
m.Fields.Walk(func(mf *types.ModuleField) error {
mf.DecodeTranslations(svc.locale.Locale().ResourceTranslations(tag, mf.ResourceTranslation()))
return nil
})
return nil
})
return nil
}()
return set, f, svc.recordAction(ctx, aProps, ModuleActionSearch, err)
@ -328,6 +347,18 @@ func (svc module) updater(ctx context.Context, namespaceID, moduleID uint64, act
}
}
// i18n
tt := m.EncodeTranslations()
for _, f := range m.Fields {
tt = append(tt, f.EncodeTranslations()...)
}
tt.SetLanguage(locale.GetLanguageFromContext(ctx))
err = svc.locale.Upsert(ctx, tt)
if err != nil {
return err
}
if changes&moduleLabelsChanged > 0 {
if err = label.Update(ctx, s, m); err != nil {
return

View File

@ -12,6 +12,7 @@ import (
"github.com/cortezaproject/corteza-server/pkg/eventbus"
"github.com/cortezaproject/corteza-server/pkg/handle"
"github.com/cortezaproject/corteza-server/pkg/label"
"github.com/cortezaproject/corteza-server/pkg/locale"
"github.com/cortezaproject/corteza-server/pkg/rbac"
"github.com/cortezaproject/corteza-server/store"
)
@ -22,6 +23,7 @@ type (
ac namespaceAccessController
eventbus eventDispatcher
store store.Storer
locale ResourceTranslationService
}
namespaceAccessController interface {
@ -61,6 +63,7 @@ func Namespace() *namespace {
eventbus: eventbus.Service(),
actionlog: DefaultActionlog,
store: DefaultStore,
locale: DefaultResourceTranslation,
}
}
@ -106,6 +109,13 @@ func (svc namespace) Find(ctx context.Context, filter types.NamespaceFilter) (se
return err
}
// i18n
tag := locale.GetLanguageFromContext(ctx)
set.Walk(func(n *types.Namespace) error {
n.DecodeTranslations(svc.locale.Locale().ResourceTranslations(tag, n.ResourceTranslation()))
return nil
})
if err = label.Load(ctx, svc.store, toLabeledNamespaces(set)...); err != nil {
return err
}
@ -265,6 +275,14 @@ func (svc namespace) updater(ctx context.Context, namespaceID uint64, action fun
}
}
// i18n
tt := ns.EncodeTranslations()
tt.SetLanguage(locale.GetLanguageFromContext(ctx))
err = DefaultResourceTranslation.Upsert(ctx, tt)
if err != nil {
return err
}
if changes&namespaceLabelsChanged > 0 {
if err = label.Update(ctx, s, ns); err != nil {
return

View File

@ -11,6 +11,7 @@ import (
"github.com/cortezaproject/corteza-server/pkg/eventbus"
"github.com/cortezaproject/corteza-server/pkg/handle"
"github.com/cortezaproject/corteza-server/pkg/label"
"github.com/cortezaproject/corteza-server/pkg/locale"
"github.com/cortezaproject/corteza-server/store"
)
@ -20,6 +21,7 @@ type (
ac pageAccessController
eventbus eventDispatcher
store store.Storer
locale ResourceTranslationService
}
pageAccessController interface {
@ -47,6 +49,7 @@ func Page() *page {
ac: DefaultAccessControl,
eventbus: eventbus.Service(),
store: DefaultStore,
locale: DefaultResourceTranslation,
}
}
@ -140,6 +143,13 @@ func (svc page) search(ctx context.Context, filter types.PageFilter) (set types.
return err
}
// i18n
tag := locale.GetLanguageFromContext(ctx)
set.Walk(func(p *types.Page) error {
p.DecodeTranslations(svc.locale.Locale().ResourceTranslations(tag, p.ResourceTranslation()))
return nil
})
return nil
}()
@ -350,6 +360,14 @@ func (svc page) updater(ctx context.Context, namespaceID, pageID uint64, action
}
}
// i18n
tt := p.EncodeTranslations()
tt.SetLanguage(locale.GetLanguageFromContext(ctx))
err = svc.locale.Upsert(ctx, tt)
if err != nil {
return err
}
if changes&pageLabelsChanged > 0 {
if err = label.Update(ctx, s, p); err != nil {
return
@ -385,6 +403,8 @@ func (svc page) lookup(ctx context.Context, namespaceID uint64, lookup func(*pag
return err
}
p.DecodeTranslations(svc.locale.Locale().ResourceTranslations(locale.GetLanguageFromContext(ctx), p.ResourceTranslation()))
aProps.setPage(p)
if !svc.ac.CanReadPage(ctx, p) {

View File

@ -15,6 +15,7 @@ import (
"github.com/cortezaproject/corteza-server/pkg/filter"
"github.com/cortezaproject/corteza-server/pkg/healthcheck"
"github.com/cortezaproject/corteza-server/pkg/id"
"github.com/cortezaproject/corteza-server/pkg/locale"
"github.com/cortezaproject/corteza-server/pkg/logger"
"github.com/cortezaproject/corteza-server/pkg/objstore"
"github.com/cortezaproject/corteza-server/pkg/objstore/minio"
@ -52,14 +53,15 @@ var (
// DefaultAccessControl Access control checking
DefaultAccessControl *accessControl
DefaultNamespace NamespaceService
DefaultImportSession ImportSessionService
DefaultRecord RecordService
DefaultModule ModuleService
DefaultChart *chart
DefaultPage *page
DefaultAttachment AttachmentService
DefaultNotification *notification
DefaultNamespace NamespaceService
DefaultImportSession ImportSessionService
DefaultRecord RecordService
DefaultModule ModuleService
DefaultChart *chart
DefaultPage *page
DefaultAttachment AttachmentService
DefaultNotification *notification
DefaultResourceTranslation ResourceTranslationService
// wrapper around time.Now() that will aid service testing
now = func() *time.Time {
@ -97,6 +99,7 @@ func Initialize(ctx context.Context, log *zap.Logger, s store.Storer, c Config)
DefaultActionlog = actionlog.NewService(DefaultStore, log, tee, policy)
}
DefaultResourceTranslation = ResourceTranslation(locale.Global())
DefaultAccessControl = AccessControl()
if DefaultObjectStore == nil {

310
compose/types/locale.gen.go generated Normal file
View File

@ -0,0 +1,310 @@
package types
// This file is auto-generated.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//
// Definitions file that controls how this file is generated:
// - compose.module-field.yaml
// - compose.module.yaml
// - compose.namespace.yaml
// - compose.page.yaml
import (
"fmt"
"github.com/cortezaproject/corteza-server/pkg/locale"
"strconv"
)
type (
LocaleKey struct {
Name string
Resource string
Path string
CustomHandler string
}
)
// Types and stuff
const (
ModuleFieldResourceTranslationType = "compose:module-field"
ModuleResourceTranslationType = "compose:module"
NamespaceResourceTranslationType = "compose:namespace"
PageResourceTranslationType = "compose:page"
)
var (
LocaleKeyModuleFieldLabel = LocaleKey{
Name: "label",
Resource: ModuleFieldResourceTranslationType,
Path: "label",
}
LocaleKeyModuleFieldValidatorError = LocaleKey{
Name: "validatorError",
Resource: ModuleFieldResourceTranslationType,
Path: "expression.validator.{{validatorID}}.error",
CustomHandler: "validatorError",
}
LocaleKeyModuleName = LocaleKey{
Name: "name",
Resource: ModuleResourceTranslationType,
Path: "name",
}
LocaleKeyNamespaceName = LocaleKey{
Name: "name",
Resource: NamespaceResourceTranslationType,
Path: "name",
}
LocaleKeyNamespaceSubtitle = LocaleKey{
Name: "subtitle",
Resource: NamespaceResourceTranslationType,
Path: "subtitle",
}
LocaleKeyNamespaceDescription = LocaleKey{
Name: "description",
Resource: NamespaceResourceTranslationType,
Path: "description",
}
LocaleKeyPageTitle = LocaleKey{
Name: "title",
Resource: PageResourceTranslationType,
Path: "title",
}
LocaleKeyPageDescription = LocaleKey{
Name: "description",
Resource: PageResourceTranslationType,
Path: "description",
}
LocaleKeyPageBlockTitle = LocaleKey{
Name: "blockTitle",
Resource: PageResourceTranslationType,
Path: "pageBlock.{{blockID}}.title",
}
LocaleKeyPageBlockDescription = LocaleKey{
Name: "blockDescription",
Resource: PageResourceTranslationType,
Path: "pageBlock.{{blockID}}.description",
}
LocaleKeyPageBlockAutomationButtonlabel = LocaleKey{
Name: "blockAutomationButtonlabel",
Resource: PageResourceTranslationType,
Path: "pageBlock.{{blockID}}.automation.{{buttonID}}.label",
}
)
// ResourceTranslation returns string representation of Locale resource for ModuleField by calling ModuleFieldResourceTranslation fn
//
// Locale resource is in the compose:module-field/... format
//
// This function is auto-generated
func (r ModuleField) ResourceTranslation() string {
return ModuleFieldResourceTranslation(r.NamespaceID, r.ModuleID, r.ID)
}
// ModuleFieldResourceTranslation returns string representation of Locale resource for ModuleField
//
// Locale resource is in the compose:module-field/... format
//
// This function is auto-generated
func ModuleFieldResourceTranslation(namespaceID uint64, moduleID uint64, id uint64) string {
cpts := []interface{}{ModuleFieldResourceTranslationType}
cpts = append(cpts, strconv.FormatUint(namespaceID, 10), strconv.FormatUint(moduleID, 10), strconv.FormatUint(id, 10))
return fmt.Sprintf(ModuleFieldResourceTranslationTpl(), cpts...)
}
// @todo template
func ModuleFieldResourceTranslationTpl() string {
return "%s/%s/%s/%s"
}
func (r *ModuleField) DecodeTranslations(tt locale.ResourceTranslationIndex) {
var aux *locale.ResourceTranslation
if aux = tt.FindByKey(LocaleKeyModuleFieldLabel.Path); aux != nil {
r.Label = aux.Msg
}
r.decodeTranslationsValidatorError(tt)
}
func (r *ModuleField) EncodeTranslations() (out locale.ResourceTranslationSet) {
out = locale.ResourceTranslationSet{
{
Resource: r.ResourceTranslation(),
Key: LocaleKeyModuleFieldLabel.Path,
Msg: r.Label,
},
}
out = append(out, r.encodeTranslationsValidatorError()...)
return out
}
// ResourceTranslation returns string representation of Locale resource for Module by calling ModuleResourceTranslation fn
//
// Locale resource is in the compose:module/... format
//
// This function is auto-generated
func (r Module) ResourceTranslation() string {
return ModuleResourceTranslation(r.NamespaceID, r.ID)
}
// ModuleResourceTranslation returns string representation of Locale resource for Module
//
// Locale resource is in the compose:module/... format
//
// This function is auto-generated
func ModuleResourceTranslation(namespaceID uint64, id uint64) string {
cpts := []interface{}{ModuleResourceTranslationType}
cpts = append(cpts, strconv.FormatUint(namespaceID, 10), strconv.FormatUint(id, 10))
return fmt.Sprintf(ModuleResourceTranslationTpl(), cpts...)
}
// @todo template
func ModuleResourceTranslationTpl() string {
return "%s/%s/%s"
}
func (r *Module) DecodeTranslations(tt locale.ResourceTranslationIndex) {
var aux *locale.ResourceTranslation
if aux = tt.FindByKey(LocaleKeyModuleName.Path); aux != nil {
r.Name = aux.Msg
}
r.decodeTranslations(tt)
}
func (r *Module) EncodeTranslations() (out locale.ResourceTranslationSet) {
out = locale.ResourceTranslationSet{
{
Resource: r.ResourceTranslation(),
Key: LocaleKeyModuleName.Path,
Msg: r.Name,
},
}
out = append(out, r.encodeTranslations()...)
return out
}
// ResourceTranslation returns string representation of Locale resource for Namespace by calling NamespaceResourceTranslation fn
//
// Locale resource is in the compose:namespace/... format
//
// This function is auto-generated
func (r Namespace) ResourceTranslation() string {
return NamespaceResourceTranslation(r.ID)
}
// NamespaceResourceTranslation returns string representation of Locale resource for Namespace
//
// Locale resource is in the compose:namespace/... format
//
// This function is auto-generated
func NamespaceResourceTranslation(id uint64) string {
cpts := []interface{}{NamespaceResourceTranslationType}
cpts = append(cpts, strconv.FormatUint(id, 10))
return fmt.Sprintf(NamespaceResourceTranslationTpl(), cpts...)
}
// @todo template
func NamespaceResourceTranslationTpl() string {
return "%s/%s"
}
func (r *Namespace) DecodeTranslations(tt locale.ResourceTranslationIndex) {
var aux *locale.ResourceTranslation
if aux = tt.FindByKey(LocaleKeyNamespaceName.Path); aux != nil {
r.Name = aux.Msg
}
if aux = tt.FindByKey(LocaleKeyNamespaceSubtitle.Path); aux != nil {
r.Meta.Subtitle = aux.Msg
}
if aux = tt.FindByKey(LocaleKeyNamespaceDescription.Path); aux != nil {
r.Meta.Description = aux.Msg
}
}
func (r *Namespace) EncodeTranslations() (out locale.ResourceTranslationSet) {
out = locale.ResourceTranslationSet{
{
Resource: r.ResourceTranslation(),
Key: LocaleKeyNamespaceName.Path,
Msg: r.Name,
},
{
Resource: r.ResourceTranslation(),
Key: LocaleKeyNamespaceSubtitle.Path,
Msg: r.Meta.Subtitle,
},
{
Resource: r.ResourceTranslation(),
Key: LocaleKeyNamespaceDescription.Path,
Msg: r.Meta.Description,
},
}
return out
}
// ResourceTranslation returns string representation of Locale resource for Page by calling PageResourceTranslation fn
//
// Locale resource is in the compose:page/... format
//
// This function is auto-generated
func (r Page) ResourceTranslation() string {
return PageResourceTranslation(r.NamespaceID, r.ID)
}
// PageResourceTranslation returns string representation of Locale resource for Page
//
// Locale resource is in the compose:page/... format
//
// This function is auto-generated
func PageResourceTranslation(namespaceID uint64, id uint64) string {
cpts := []interface{}{PageResourceTranslationType}
cpts = append(cpts, strconv.FormatUint(namespaceID, 10), strconv.FormatUint(id, 10))
return fmt.Sprintf(PageResourceTranslationTpl(), cpts...)
}
// @todo template
func PageResourceTranslationTpl() string {
return "%s/%s/%s"
}
func (r *Page) DecodeTranslations(tt locale.ResourceTranslationIndex) {
var aux *locale.ResourceTranslation
if aux = tt.FindByKey(LocaleKeyPageTitle.Path); aux != nil {
r.Title = aux.Msg
}
if aux = tt.FindByKey(LocaleKeyPageDescription.Path); aux != nil {
r.Description = aux.Msg
}
r.decodeTranslations(tt)
}
func (r *Page) EncodeTranslations() (out locale.ResourceTranslationSet) {
out = locale.ResourceTranslationSet{
{
Resource: r.ResourceTranslation(),
Key: LocaleKeyPageTitle.Path,
Msg: r.Title,
},
{
Resource: r.ResourceTranslation(),
Key: LocaleKeyPageDescription.Path,
Msg: r.Description,
},
}
out = append(out, r.encodeTranslations()...)
return out
}

View File

@ -4,6 +4,7 @@ import (
"time"
"github.com/cortezaproject/corteza-server/pkg/filter"
"github.com/cortezaproject/corteza-server/pkg/locale"
"github.com/jmoiron/sqlx/types"
)
@ -54,6 +55,16 @@ func (m Module) Clone() *Module {
return c
}
// We won't worry about fields at this point
func (m *Module) decodeTranslations(tt locale.ResourceTranslationIndex) {
return
}
// We won't worry about fields at this point
func (m *Module) encodeTranslations() (out locale.ResourceTranslationSet) {
return
}
// FindByHandle finds module by it's handle
func (set ModuleSet) FindByHandle(handle string) *Module {
for i := range set {

View File

@ -3,9 +3,13 @@ package types
import (
"database/sql/driver"
"encoding/json"
"github.com/cortezaproject/corteza-server/pkg/filter"
"sort"
"strconv"
"strings"
"time"
"github.com/cortezaproject/corteza-server/pkg/filter"
"github.com/cortezaproject/corteza-server/pkg/locale"
)
type (
@ -47,6 +51,41 @@ var (
_ sort.Interface = &ModuleFieldSet{}
)
func (f *ModuleField) decodeTranslationsValidatorError(tt locale.ResourceTranslationIndex) {
var aux *locale.ResourceTranslation
for i, e := range f.Expressions.Validators {
validatorID := locale.ContentID(e.ValidatorID, i)
rpl := strings.NewReplacer(
"{{validatorID}}", strconv.FormatUint(validatorID, 10),
)
if aux = tt.FindByKey(rpl.Replace(LocaleKeyModuleFieldValidatorError.Path)); aux != nil {
f.Expressions.Validators[i].Error = aux.Msg
}
}
}
func (m *ModuleField) encodeTranslationsValidatorError() (out locale.ResourceTranslationSet) {
out = make(locale.ResourceTranslationSet, 0, 3)
// Module field expressions
for i, e := range m.Expressions.Validators {
validatorID := locale.ContentID(e.ValidatorID, i)
rpl := strings.NewReplacer(
"{{validatorID}}", strconv.FormatUint(validatorID, 10),
)
out = append(out, &locale.ResourceTranslation{
Resource: m.ResourceTranslation(),
Key: rpl.Replace(LocaleKeyModuleFieldValidatorError.Path),
Msg: e.Error,
})
}
return
}
func (m ModuleField) Clone() *ModuleField {
return &m
}

View File

@ -20,8 +20,9 @@ type (
}
ModuleFieldValidator struct {
Test string `json:"test,omitempty"`
Error string `json:"error,omitempty"`
ValidatorID uint64 `json:"validatorID,string,omitempty"`
Test string `json:"test,omitempty"`
Error string `json:"error,omitempty"`
}
)

View File

@ -3,9 +3,13 @@ package types
import (
"database/sql/driver"
"encoding/json"
"strconv"
"strings"
"time"
"github.com/cortezaproject/corteza-server/pkg/filter"
"github.com/cortezaproject/corteza-server/pkg/locale"
"github.com/spf13/cast"
"github.com/pkg/errors"
)
@ -41,6 +45,7 @@ type (
PageBlocks []PageBlock
PageBlock struct {
BlockID uint64 `json:"blockID,string,omitempty"`
Title string `json:"title,omitempty"`
Description string `json:"description,omitempty"`
Options map[string]interface{} `json:"options,omitempty"`
@ -84,6 +89,104 @@ func (m Page) Clone() *Page {
return c
}
func (p *Page) decodeTranslations(tt locale.ResourceTranslationIndex) {
var aux *locale.ResourceTranslation
for i, block := range p.Blocks {
blockID := locale.ContentID(block.BlockID, i)
rpl := strings.NewReplacer(
"{{blockID}}", strconv.FormatUint(blockID, 10),
)
// - generic page block stuff
if aux = tt.FindByKey(rpl.Replace(LocaleKeyPageBlockTitle.Path)); aux != nil {
p.Blocks[i].Title = aux.Msg
}
if aux = tt.FindByKey(rpl.Replace(LocaleKeyPageBlockDescription.Path)); aux != nil {
p.Blocks[i].Description = aux.Msg
}
// - automation page block stuff
if block.Kind == "Automation" {
bb, _ := block.Options["buttons"].([]interface{})
for j, auxBtn := range bb {
btn := auxBtn.(map[string]interface{})
buttonID := uint64(0)
if aux, ok := btn["buttonID"]; ok {
buttonID = cast.ToUint64(aux)
}
buttonID = locale.ContentID(buttonID, j)
rpl := strings.NewReplacer(
"{{blockID}}", strconv.FormatUint(blockID, 10),
"{{buttonID}}", strconv.FormatUint(buttonID, 10),
)
if aux = tt.FindByKey(rpl.Replace(LocaleKeyPageBlockAutomationButtonlabel.Path)); aux != nil {
btn["label"] = aux.Msg
}
}
}
}
}
func (p *Page) encodeTranslations() (out locale.ResourceTranslationSet) {
out = make(locale.ResourceTranslationSet, 0, 3)
// Page blocks
for i, block := range p.Blocks {
blockID := locale.ContentID(block.BlockID, i)
rpl := strings.NewReplacer(
"{{blockID}}", strconv.FormatUint(uint64(blockID), 10),
)
// - generic page block stuff
out = append(out, &locale.ResourceTranslation{
Resource: p.ResourceTranslation(),
Key: rpl.Replace(LocaleKeyPageBlockTitle.Path),
Msg: block.Title,
})
out = append(out, &locale.ResourceTranslation{
Resource: p.ResourceTranslation(),
Key: rpl.Replace(LocaleKeyPageBlockDescription.Path),
Msg: block.Description,
})
// - automation page block stuff
if block.Kind == "Automation" {
bb, _ := block.Options["buttons"].([]interface{})
for j, auxBtn := range bb {
btn := auxBtn.(map[string]interface{})
if _, ok := btn["label"]; !ok {
continue
}
buttonID := uint64(0)
if aux, ok := btn["buttonID"]; ok {
buttonID = cast.ToUint64(aux)
}
buttonID = locale.ContentID(buttonID, j)
rpl := strings.NewReplacer(
"{{blockID}}", strconv.FormatUint(blockID, 10),
"{{buttonID}}", strconv.FormatUint(buttonID, 10),
)
out = append(out, &locale.ResourceTranslation{
Resource: p.ResourceTranslation(),
Key: rpl.Replace(LocaleKeyPageBlockAutomationButtonlabel.Path),
Msg: btn["label"].(string),
})
}
}
}
return
}
// FindByHandle finds page by it's handle
func (set PageSet) FindByHandle(handle string) *Page {
for i := range set {