diff --git a/assets/static/template.go b/assets/static/template.go index f2a511cd2..b6ff989a8 100644 --- a/assets/static/template.go +++ b/assets/static/template.go @@ -38,21 +38,23 @@ func (t *Template) Translations() []assets.TemplateTranslation { // TemplateTranslation represents a single template translation type TemplateTranslation struct { - Channel_ *assets.ChannelReference `json:"channel" validate:"required"` - Content_ string `json:"content" validate:"required"` - Locale_ i18n.Locale `json:"locale" validate:"required"` - Namespace_ string `json:"namespace"` - VariableCount_ int `json:"variable_count"` + Channel_ *assets.ChannelReference `json:"channel" validate:"required"` + Content_ string `json:"content" validate:"required"` + Locale_ i18n.Locale `json:"locale" validate:"required"` + Namespace_ string `json:"namespace"` + VariableCount_ int `json:"variable_count"` + Params_ map[string][]TemplateParam `json:"params"` } // NewTemplateTranslation creates a new template translation -func NewTemplateTranslation(channel *assets.ChannelReference, locale i18n.Locale, content string, variableCount int, namespace string) *TemplateTranslation { +func NewTemplateTranslation(channel *assets.ChannelReference, locale i18n.Locale, content string, variableCount int, namespace string, params map[string][]TemplateParam) *TemplateTranslation { return &TemplateTranslation{ Channel_: channel, Content_: content, Namespace_: namespace, Locale_: locale, VariableCount_: variableCount, + Params_: params, } } @@ -70,3 +72,29 @@ func (t *TemplateTranslation) VariableCount() int { return t.VariableCount_ } // Channel returns the channel this template translation is for func (t *TemplateTranslation) Channel() *assets.ChannelReference { return t.Channel_ } + +// Params returns the params for this template translation +func (t *TemplateTranslation) Params() map[string][]assets.TemplateParam { + prs := make(map[string][]assets.TemplateParam, len(t.Params_)) + for k, v := range t.Params_ { + compParams := make([]assets.TemplateParam, len(v)) + for i, pr := range v { + compParams[i] = (assets.TemplateParam)(&pr) + } + prs[k] = compParams + } + return prs +} + +// TemplateParam represents a single parameter for a template translation +type TemplateParam struct { + Type_ string `json:"type"` +} + +// Type returns the type for this parameter +func (t *TemplateParam) Type() string { return t.Type_ } + +// NewTemplateParam creates a new template param +func NewTemplateParam(paramType string) TemplateParam { + return TemplateParam{Type_: paramType} +} diff --git a/assets/static/template_test.go b/assets/static/template_test.go index 1136bc8bb..20efb52f3 100644 --- a/assets/static/template_test.go +++ b/assets/static/template_test.go @@ -12,12 +12,16 @@ import ( func TestTemplate(t *testing.T) { channel := assets.NewChannelReference("Test Channel", "ffffffff-9b24-92e1-ffff-ffffb207cdb4") - translation := NewTemplateTranslation(channel, i18n.Locale("eng-US"), "Hello {{1}}", 1, "0162a7f4_dfe4_4c96_be07_854d5dba3b2b") + tp1 := NewTemplateParam("text") + assert.Equal(t, "text", tp1.Type()) + + translation := NewTemplateTranslation(channel, i18n.Locale("eng-US"), "Hello {{1}}", 1, "0162a7f4_dfe4_4c96_be07_854d5dba3b2b", map[string][]TemplateParam{"body": {tp1}}) assert.Equal(t, channel, translation.Channel()) assert.Equal(t, i18n.Locale("eng-US"), translation.Locale()) assert.Equal(t, "Hello {{1}}", translation.Content()) assert.Equal(t, 1, translation.VariableCount()) assert.Equal(t, "0162a7f4_dfe4_4c96_be07_854d5dba3b2b", translation.Namespace()) + assert.Equal(t, map[string][]assets.TemplateParam{"body": {(assets.TemplateParam)(&tp1)}}, translation.Params()) template := NewTemplate(assets.TemplateUUID("8a9c1f73-5059-46a0-ba4a-6390979c01d3"), "hello", []*TemplateTranslation{translation}) assert.Equal(t, assets.TemplateUUID("8a9c1f73-5059-46a0-ba4a-6390979c01d3"), template.UUID()) diff --git a/assets/template.go b/assets/template.go index d30bf608a..3a72fdf64 100644 --- a/assets/template.go +++ b/assets/template.go @@ -42,6 +42,11 @@ type Template interface { Translations() []TemplateTranslation } +// TemplateParam is a parameter for template translation +type TemplateParam interface { + Type() string +} + // TemplateTranslation represents a single translation for a specific template and channel type TemplateTranslation interface { Content() string @@ -49,6 +54,7 @@ type TemplateTranslation interface { Namespace() string VariableCount() int Channel() *ChannelReference + Params() map[string][]TemplateParam } // TemplateReference is used to reference a Template diff --git a/flows/actions/send_msg.go b/flows/actions/send_msg.go index faf86d969..e6b75704a 100644 --- a/flows/actions/send_msg.go +++ b/flows/actions/send_msg.go @@ -1,12 +1,16 @@ package actions import ( + "strconv" + "strings" + "github.com/nyaruka/gocommon/i18n" "github.com/nyaruka/gocommon/urns" "github.com/nyaruka/gocommon/uuids" "github.com/nyaruka/goflow/assets" "github.com/nyaruka/goflow/flows" "github.com/nyaruka/goflow/flows/events" + "github.com/nyaruka/goflow/utils" ) func init() { @@ -52,9 +56,10 @@ type SendMsgAction struct { // Templating represents the templating that should be used if possible type Templating struct { - UUID uuids.UUID `json:"uuid" validate:"required,uuid4"` - Template *assets.TemplateReference `json:"template" validate:"required"` - Variables []string `json:"variables" engine:"localized,evaluated"` + UUID uuids.UUID `json:"uuid" validate:"required,uuid4"` + Template *assets.TemplateReference `json:"template" validate:"required"` + Variables []string `json:"variables" engine:"localized,evaluated"` + Params map[string]flows.ComponentVariables `json:"params"` } // LocalizationUUID gets the UUID which identifies this object for localization @@ -99,35 +104,19 @@ func (a *SendMsgAction) Execute(run flows.Run, step flows.Step, logModifier flow channelRef := assets.NewChannelReference(dest.Channel.UUID(), dest.Channel.Name()) // do we have a template defined? - var templating *flows.MsgTemplating + var msg *flows.MsgOut if template != nil { - // looks for a translation in the contact locale or environment default - locales := []i18n.Locale{ - run.Session().MergedEnvironment().DefaultLocale(), - run.Session().Environment().DefaultLocale(), + locales := []i18n.Locale{run.Session().MergedEnvironment().DefaultLocale(), run.Session().Environment().DefaultLocale()} + templateTranslation := template.FindTranslation(dest.Channel, locales) + if templateTranslation != nil { + msg = getTemplatingMsg(a, run, urn, channelRef, templateTranslation, evaluatedAttachments, evaluatedQuickReplies, unsendableReason, logEvent) } + } - translation := template.FindTranslation(dest.Channel, locales) - if translation != nil { - localizedVariables, _ := run.GetTextArray(uuids.UUID(a.Templating.UUID), "variables", a.Templating.Variables, nil) - - // evaluate our variables - evaluatedVariables := make([]string, len(localizedVariables)) - for i, variable := range localizedVariables { - sub, err := run.EvaluateTemplate(variable) - if err != nil { - logEvent(events.NewError(err)) - } - evaluatedVariables[i] = sub - } - - evaluatedText = translation.Substitute(evaluatedVariables) - templating = flows.NewMsgTemplating(a.Templating.Template, evaluatedVariables, translation.Namespace()) - locale = translation.Locale() - } + if msg == nil { + msg = flows.NewMsgOut(urn, channelRef, evaluatedText, evaluatedAttachments, evaluatedQuickReplies, nil, a.Topic, locale, unsendableReason) } - msg := flows.NewMsgOut(urn, channelRef, evaluatedText, evaluatedAttachments, evaluatedQuickReplies, templating, a.Topic, locale, unsendableReason) logEvent(events.NewMsgCreated(msg)) } @@ -140,3 +129,55 @@ func (a *SendMsgAction) Execute(run flows.Run, step flows.Step, logModifier flow return nil } + +func getTemplatingMsg(action *SendMsgAction, run flows.Run, urn urns.URN, channelRef *assets.ChannelReference, templateTranslation *flows.TemplateTranslation, evaluatedAttachments []utils.Attachment, evaluatedQuickReplies []string, unsendableReason flows.UnsendableReason, logEvent flows.EventCallback) *flows.MsgOut { + evaluatedParams := make(map[string]flows.ComponentVariables) + + if bodyComp, ok := action.Templating.Params["body"]; ok { + localizedVariables, _ := run.GetTextArray(uuids.UUID(action.Templating.UUID), "variables", action.Templating.Variables, nil) + evaluatedVariables := make([]string, len(localizedVariables)) + for i, variable := range localizedVariables { + sub, err := run.EvaluateTemplate(variable) + if err != nil { + logEvent(events.NewError(err)) + } + evaluatedVariables[i] = sub + } + + evaluatedParams["body"] = flows.ComponentVariables{UUID: bodyComp.UUID, Variables: evaluatedVariables} + } + + for compKey, compVars := range action.Templating.Params { + + var evaluatedComponentVariables []string + if strings.HasPrefix(compKey, "button.") { + qrIndex, err := strconv.Atoi(strings.TrimPrefix(compKey, "button.")) + if err != nil { + logEvent(events.NewError(err)) + } + paramValue := evaluatedQuickReplies[qrIndex] + evaluatedComponentVariables = []string{paramValue} + + } else { + + localizedComponentVariables, _ := run.GetTextArray(uuids.UUID(compVars.UUID), "variables", compVars.Variables, nil) + evaluatedComponentVariables = make([]string, len(localizedComponentVariables)) + for i, variable := range localizedComponentVariables { + sub, err := run.EvaluateTemplate(variable) + if err != nil { + logEvent(events.NewError(err)) + } + evaluatedComponentVariables[i] = sub + } + } + evaluatedParams[compKey] = flows.ComponentVariables{UUID: compVars.UUID, Variables: evaluatedComponentVariables} + + } + + evaluatedText := templateTranslation.Substitute(evaluatedParams["body"].Variables) + + templating := flows.NewMsgTemplating(action.Templating.Template, evaluatedParams["body"].Variables, templateTranslation.Namespace(), evaluatedParams) + locale := templateTranslation.Locale() + + return flows.NewMsgOut(urn, channelRef, evaluatedText, evaluatedAttachments, evaluatedQuickReplies, templating, action.Topic, locale, unsendableReason) +} diff --git a/flows/actions/testdata/_assets.json b/flows/actions/testdata/_assets.json index 8231c750c..ce93326c1 100644 --- a/flows/actions/testdata/_assets.json +++ b/flows/actions/testdata/_assets.json @@ -257,7 +257,17 @@ "name": "My Android Phone" }, "locale": "eng-US", - "content": "Hi {{1}}, who's an excellent {{2}}?" + "content": "Hi {{1}}, who's an excellent {{2}}?", + "params": { + "body": [ + { + "type": "text" + }, + { + "type": "text" + } + ] + } }, { "channel": { @@ -265,7 +275,17 @@ "name": "My Android Phone" }, "locale": "spa", - "content": "Hola {{1}}, quien es un {{2}} excelente?" + "content": "Hola {{1}}, quien es un {{2}} excelente?", + "params": { + "body": [ + { + "type": "text" + }, + { + "type": "text" + } + ] + } } ] }, diff --git a/flows/actions/testdata/send_msg.json b/flows/actions/testdata/send_msg.json index d822fa210..5cd314a60 100644 --- a/flows/actions/testdata/send_msg.json +++ b/flows/actions/testdata/send_msg.json @@ -347,6 +347,7 @@ "text": "Hi @contact.name, who's a good boy?", "templating": { "uuid": "9c4bf5b5-3aa4-48ec-9bb9-424a9cbc6785", + "params": null, "template": { "uuid": "b620b463-8d15-427f-b2e3-4f44f9f071ec", "name": "missing" @@ -419,6 +420,12 @@ "text": "Hi Ryan Lewis, who's a good boy?", "templating": { "uuid": "9c4bf5b5-3aa4-48ec-9bb9-424a9cbc6785", + "params": { + "body": { + "uuid": "74d59988-18c0-4919-9cb4-9f9e3847ed50", + "variables": ["@contact.name", "boy"] + } + }, "template": { "uuid": "5722e1fd-fe32-4e74-ac78-3cf41a6adb7e", "name": "affirmation" @@ -444,6 +451,12 @@ }, "text": "Hi Ryan Lewis, who's an excellent boy?", "templating": { + "params": { + "body": { + "uuid": "74d59988-18c0-4919-9cb4-9f9e3847ed50", + "variables": ["Ryan Lewis", "boy"] + } + }, "template": { "uuid": "5722e1fd-fe32-4e74-ac78-3cf41a6adb7e", "name": "affirmation" @@ -491,6 +504,12 @@ "text": "Hi Ryan Lewis, who's a good boy?", "templating": { "uuid": "9c4bf5b5-3aa4-48ec-9bb9-424a9cbc6785", + "params": { + "body": { + "uuid": "74d59988-18c0-4919-9cb4-9f9e3847ed50", + "variables": ["@contact.name", "boy"] + } + }, "template": { "uuid": "5722e1fd-fe32-4e74-ac78-3cf41a6adb7e", "name": "affirmation" @@ -508,6 +527,9 @@ "@contact.name", "niño" ] + }, + "74d59988-18c0-4919-9cb4-9f9e3847ed50": { + "variables": ["@contact.name", "niño"] } } }, @@ -525,6 +547,12 @@ }, "text": "Hola Ryan Lewis, quien es un niño excelente?", "templating": { + "params": { + "body": { + "uuid": "74d59988-18c0-4919-9cb4-9f9e3847ed50", + "variables": ["Ryan Lewis", "niño"] + } + }, "template": { "uuid": "5722e1fd-fe32-4e74-ac78-3cf41a6adb7e", "name": "affirmation" @@ -573,6 +601,7 @@ "text": "Hi there, it's time to get up!", "templating": { "uuid": "2edc8dfd-aef0-41cf-a900-8a71bdb00900", + "params": null, "template": { "uuid": "2edc8dfd-aef0-41cf-a900-8a71bdb00900", "name": "wakeup" @@ -594,6 +623,7 @@ }, "text": "Hi there, it's time to get up!", "templating": { + "params": {}, "template": { "uuid": "2edc8dfd-aef0-41cf-a900-8a71bdb00900", "name": "wakeup" @@ -631,6 +661,7 @@ "uuid": "4f0510e9-7e41-4f83-aaa3-59b6e9a17e70", "text": "Hi Ryan, wakeup!", "templating": { + "params": null, "uuid": "dce1ab9c-81d7-4e2f-b7d6-33e577c731ba", "template": { "uuid": "2edc8dfd-aef0-41cf-a900-8a71bdb00900", @@ -662,6 +693,7 @@ }, "text": "Hi there, it's time to get up!", "templating": { + "params": {}, "template": { "uuid": "2edc8dfd-aef0-41cf-a900-8a71bdb00900", "name": "wakeup" @@ -770,5 +802,171 @@ "waiting_exits": [], "parent_refs": [] } + }, + { + "description": "Use template translation with attachments and quick replies and localized", + "action": { + "type": "send_msg", + "uuid": "ad154980-7bf7-4ab8-8728-545fd6378912", + "text": "Hi Ryan Lewis, who's a good boy?", + "attachments": [ + "image:http://example.com/red.jpg" + ], + "quick_replies": [ + "Yes", + "No" + ], + "templating": { + "uuid": "9c4bf5b5-3aa4-48ec-9bb9-424a9cbc6785", + "params": { + "header":{ + "uuid": "98788f6d-775e-4c6c-a11c-d6169c3551c1", + "variables": ["http://example.com/red.jpg"] + }, + "body": { + "uuid": "74d59988-18c0-4919-9cb4-9f9e3847ed50", + "variables": ["@contact.name", "boy"] + }, + "button.0": { + "uuid": "31cd12f7-5a8d-4421-a289-d47cdfb7cff1", + "variables": ["no_used"] + }, + "button.1": { + "uuid": "67ed8f42-4fce-4e8a-b788-8a7afc9b02ea", + "variables": ["no_used"] + } + }, + "template": { + "uuid": "5722e1fd-fe32-4e74-ac78-3cf41a6adb7e", + "name": "affirmation" + }, + "variables": [ + "@contact.name", + "boy" + ] + } + }, + "localization": { + "spa": { + "ad154980-7bf7-4ab8-8728-545fd6378912": { + "text": [ + "Hola!" + ], + "attachments": [ + "image:http://example.com/rojo.jpg" + ], + "quick_replies": [ + "Si", + "No" + ] + }, + "9c4bf5b5-3aa4-48ec-9bb9-424a9cbc6785": { + "variables": [ + "@contact.name", + "niño" + ] + }, + "98788f6d-775e-4c6c-a11c-d6169c3551c1": { + "variables": [ + "image:http://example.com/rojo.jpg" + ] + }, + "f383e94d-0598-4fd9-81d7-f0aea397d63b": { + "variables": ["niño"] + }, + "74d59988-18c0-4919-9cb4-9f9e3847ed50": { + "variables": ["@contact.name", "niño"] + } + } + }, + "events": [ + { + "type": "msg_created", + "created_on": "2018-10-18T14:20:30.000123456Z", + "step_uuid": "59d74b86-3e2f-4a93-aece-b05d2fdcde0c", + "msg": { + "uuid": "9688d21d-95aa-4bed-afc7-f31b35731a3d", + "urn": "tel:+12065551212?channel=57f1078f-88aa-46f4-a59a-948a5739c03d&id=123", + "channel": { + "uuid": "57f1078f-88aa-46f4-a59a-948a5739c03d", + "name": "My Android Phone" + }, + "text": "Hola Ryan Lewis, quien es un niño excelente?", + "attachments": [ + "image:http://example.com/rojo.jpg" + ], + "quick_replies": [ + "Si", + "No" + ], + "templating": { + "params": { + "body": { + "uuid": "74d59988-18c0-4919-9cb4-9f9e3847ed50", + "variables": ["Ryan Lewis", "niño"] + }, + "header": { + "uuid": "98788f6d-775e-4c6c-a11c-d6169c3551c1", + "variables": ["image:http://example.com/rojo.jpg"] + }, + "button.0": { + "uuid": "31cd12f7-5a8d-4421-a289-d47cdfb7cff1", + "variables": ["Si"] + }, + "button.1": { + "uuid": "67ed8f42-4fce-4e8a-b788-8a7afc9b02ea", + "variables": ["No"] + } + }, + "template": { + "uuid": "5722e1fd-fe32-4e74-ac78-3cf41a6adb7e", + "name": "affirmation" + }, + "variables": [ + "Ryan Lewis", + "niño" + ], + "namespace": "" + }, + "locale": "spa" + } + } + ], + "templates": [ + "Hi Ryan Lewis, who's a good boy?", + "Hola!", + "image:http://example.com/red.jpg", + "image:http://example.com/rojo.jpg", + "Yes", + "No", + "Si", + "No", + "@contact.name", + "boy", + "@contact.name", + "niño" + ], + "localizables": [ + "Hi Ryan Lewis, who's a good boy?", + "image:http://example.com/red.jpg", + "Yes", + "No", + "@contact.name", + "boy" + ], + "inspection": { + "dependencies": [ + { + "uuid": "5722e1fd-fe32-4e74-ac78-3cf41a6adb7e", + "name": "affirmation", + "type": "template" + } + ], + "issues": [], + "results": [], + "waiting_exits": [], + "parent_refs": [] + } } + ] \ No newline at end of file diff --git a/flows/msg.go b/flows/msg.go index 924c00327..d4330025e 100644 --- a/flows/msg.go +++ b/flows/msg.go @@ -168,11 +168,17 @@ func (m *MsgOut) Locale() i18n.Locale { return m.Locale_ } // UnsendableReason returns the reason this message can't be sent (if any) func (m *MsgOut) UnsendableReason() UnsendableReason { return m.UnsendableReason_ } +type ComponentVariables struct { + UUID uuids.UUID `json:"uuid"` + Variables []string `json:"variables"` +} + // MsgTemplating represents any substituted message template that should be applied when sending this message type MsgTemplating struct { - Template_ *assets.TemplateReference `json:"template"` - Variables_ []string `json:"variables,omitempty"` - Namespace_ string `json:"namespace"` + Template_ *assets.TemplateReference `json:"template"` + Variables_ []string `json:"variables,omitempty"` + Namespace_ string `json:"namespace"` + Params_ map[string]ComponentVariables `json:"params"` } // Template returns the template this msg template is for @@ -184,12 +190,16 @@ func (t MsgTemplating) Variables() []string { return t.Variables_ } // Namespace returns the namespace that should be for the template func (t MsgTemplating) Namespace() string { return t.Namespace_ } +// Params returns the params that should be used for the template +func (t MsgTemplating) Params() map[string]ComponentVariables { return t.Params_ } + // NewMsgTemplating creates and returns a new msg template -func NewMsgTemplating(template *assets.TemplateReference, variables []string, namespace string) *MsgTemplating { +func NewMsgTemplating(template *assets.TemplateReference, variables []string, namespace string, params map[string]ComponentVariables) *MsgTemplating { return &MsgTemplating{ Template_: template, Variables_: variables, Namespace_: namespace, + Params_: params, } } diff --git a/flows/msg_test.go b/flows/msg_test.go index 0b254a241..1aabdc080 100644 --- a/flows/msg_test.go +++ b/flows/msg_test.go @@ -156,3 +156,39 @@ func TestBroadcastTranslations(t *testing.T) { assert.NoError(t, err) assert.Equal(t, flows.BroadcastTranslations{"spa": {Text: "Adios"}}, bt) } + +func TestMsgTemplating(t *testing.T) { + uuids.SetGenerator(uuids.NewSeededGenerator(12345)) + defer uuids.SetGenerator(uuids.DefaultGenerator) + + templateRef := assets.NewTemplateReference("61602f3e-f603-4c70-8a8f-c477505bf4bf", "Affirmation") + + msgTemplating := flows.NewMsgTemplating(templateRef, []string{"@contact.name", "boy"}, "0162a7f4_dfe4_4c96_be07_854d5dba3b2b", map[string]flows.ComponentVariables{"body": flows.ComponentVariables{UUID: "61f38f46-a856-4f90-899e-905691784159", Variables: []string{"@contact.name", "boy"}}}) + + assert.Equal(t, templateRef, msgTemplating.Template()) + assert.Equal(t, []string{"@contact.name", "boy"}, msgTemplating.Variables()) + assert.Equal(t, "0162a7f4_dfe4_4c96_be07_854d5dba3b2b", msgTemplating.Namespace()) + assert.Equal(t, map[string]flows.ComponentVariables{"body": flows.ComponentVariables{UUID: "61f38f46-a856-4f90-899e-905691784159", Variables: []string{"@contact.name", "boy"}}}, msgTemplating.Params()) + + // test marshaling our msg + marshaled, err := jsonx.Marshal(msgTemplating) + require.NoError(t, err) + + test.AssertEqualJSON(t, []byte(`{ + "namespace":"0162a7f4_dfe4_4c96_be07_854d5dba3b2b", + "params":{ + "body":{ + "uuid":"61f38f46-a856-4f90-899e-905691784159", + "variables": ["@contact.name", "boy"] + } + }, + "template":{ + "name":"Affirmation", + "uuid":"61602f3e-f603-4c70-8a8f-c477505bf4bf" + }, + "variables":[ + "@contact.name", + "boy" + ] + }`), marshaled, "JSON mismatch") +} diff --git a/flows/template_test.go b/flows/template_test.go index 8bc6f4187..1672c2c4e 100644 --- a/flows/template_test.go +++ b/flows/template_test.go @@ -26,7 +26,7 @@ func TestTemplateTranslation(t *testing.T) { channel := assets.NewChannelReference("0bce5fd3-c215-45a0-bcb8-2386eb194175", "Test Channel") for i, tc := range tcs { - tt := flows.NewTemplateTranslation(static.NewTemplateTranslation(channel, i18n.Locale("eng-US"), tc.Content, len(tc.Variables), "a6a8863e_7879_4487_ad24_5e2ea429027c")) + tt := flows.NewTemplateTranslation(static.NewTemplateTranslation(channel, i18n.Locale("eng-US"), tc.Content, len(tc.Variables), "a6a8863e_7879_4487_ad24_5e2ea429027c", map[string][]static.TemplateParam{})) result := tt.Substitute(tc.Variables) assert.Equal(t, tc.Expected, result, "%d: unexpected template substitution", i) } @@ -39,10 +39,10 @@ func TestTemplate(t *testing.T) { channel1Ref := assets.NewChannelReference(channel1.UUID(), channel1.Name()) channel2Ref := assets.NewChannelReference(channel2.UUID(), channel2.Name()) - tt1 := static.NewTemplateTranslation(channel1Ref, i18n.Locale("eng"), "Hello {{1}}", 1, "") - tt2 := static.NewTemplateTranslation(channel1Ref, i18n.Locale("spa-EC"), "Que tal {{1}}", 1, "") - tt3 := static.NewTemplateTranslation(channel1Ref, i18n.Locale("spa-ES"), "Hola {{1}}", 1, "") - tt4 := static.NewTemplateTranslation(channel2Ref, i18n.Locale("en"), "Hello {{1}}", 1, "") + tt1 := static.NewTemplateTranslation(channel1Ref, i18n.Locale("eng"), "Hello {{1}}", 1, "", map[string][]static.TemplateParam{}) + tt2 := static.NewTemplateTranslation(channel1Ref, i18n.Locale("spa-EC"), "Que tal {{1}}", 1, "", map[string][]static.TemplateParam{}) + tt3 := static.NewTemplateTranslation(channel1Ref, i18n.Locale("spa-ES"), "Hola {{1}}", 1, "", map[string][]static.TemplateParam{}) + tt4 := static.NewTemplateTranslation(channel2Ref, i18n.Locale("en"), "Hello {{1}}", 1, "", map[string][]static.TemplateParam{}) template := flows.NewTemplate(static.NewTemplate("c520cbda-e118-440f-aaf6-c0485088384f", "greeting", []*static.TemplateTranslation{tt1, tt2, tt3, tt4})) tas := flows.NewTemplateAssets([]assets.Template{template})