Skip to content

Commit cad7afa

Browse files
akoclaude
andcommitted
feat: add Language column to catalog strings table (#83)
The strings FTS5 table stored translation text but discarded the language code. Add a Language column populated from the Text.Translations map key (e.g., "en_US", "nl_NL"). For non-translatable strings (URLs, documentation, log node names), Language is empty. Enables translation workflow queries: SELECT StringValue, Language, QualifiedName FROM catalog.strings WHERE Language = 'nl_NL'; -- Find missing translations SELECT s1.QualifiedName, s1.StringContext, s1.StringValue FROM catalog.strings s1 LEFT JOIN catalog.strings s2 ON s1.QualifiedName = s2.QualifiedName AND s1.StringContext = s2.StringContext AND s2.Language = 'nl_NL' WHERE s1.Language = 'en_US' AND s2.StringValue IS NULL; Fixes #83 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 2bd2739 commit cad7afa

File tree

2 files changed

+30
-29
lines changed

2 files changed

+30
-29
lines changed

mdl/catalog/builder_strings.go

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,20 @@ func (b *Builder) buildStrings() error {
1515
}
1616

1717
stmt, err := b.tx.Prepare(`
18-
INSERT INTO strings (QualifiedName, ObjectType, StringValue, StringContext, ModuleName)
19-
VALUES (?, ?, ?, ?, ?)
18+
INSERT INTO strings (QualifiedName, ObjectType, StringValue, StringContext, Language, ModuleName)
19+
VALUES (?, ?, ?, ?, ?, ?)
2020
`)
2121
if err != nil {
2222
return err
2323
}
2424
defer stmt.Close()
2525

2626
count := 0
27-
insert := func(qn, objType, value, ctx, module string) {
27+
insert := func(qn, objType, value, ctx, lang, module string) {
2828
if value == "" {
2929
return
3030
}
31-
stmt.Exec(qn, objType, value, ctx, module)
31+
stmt.Exec(qn, objType, value, ctx, lang, module)
3232
count++
3333
}
3434

@@ -40,16 +40,16 @@ func (b *Builder) buildStrings() error {
4040
moduleName := b.hierarchy.getModuleName(moduleID)
4141
qn := moduleName + "." + pg.Name
4242

43-
// Page title translations
43+
// Page title translations (with language code)
4444
if pg.Title != nil && pg.Title.Translations != nil {
45-
for _, t := range pg.Title.Translations {
46-
insert(qn, "PAGE", t, "page_title", moduleName)
45+
for lang, t := range pg.Title.Translations {
46+
insert(qn, "PAGE", t, "page_title", lang, moduleName)
4747
}
4848
}
4949

50-
// Page URL
50+
// Page URL (no language)
5151
if pg.URL != "" {
52-
insert(qn, "PAGE", pg.URL, "page_url", moduleName)
52+
insert(qn, "PAGE", pg.URL, "page_url", "", moduleName)
5353
}
5454
}
5555
}
@@ -62,9 +62,9 @@ func (b *Builder) buildStrings() error {
6262
moduleName := b.hierarchy.getModuleName(moduleID)
6363
qn := moduleName + "." + mf.Name
6464

65-
// Documentation
65+
// Documentation (no language)
6666
if mf.Documentation != "" {
67-
insert(qn, "MICROFLOW", mf.Documentation, "documentation", moduleName)
67+
insert(qn, "MICROFLOW", mf.Documentation, "documentation", "", moduleName)
6868
}
6969

7070
// Extract strings from activities
@@ -82,8 +82,8 @@ func (b *Builder) buildStrings() error {
8282

8383
for _, val := range enum.Values {
8484
if val.Caption != nil && val.Caption.Translations != nil {
85-
for _, t := range val.Caption.Translations {
86-
insert(qn, "ENUMERATION", t, "enum_caption", moduleName)
85+
for lang, t := range val.Caption.Translations {
86+
insert(qn, "ENUMERATION", t, "enum_caption", lang, moduleName)
8787
}
8888
}
8989
}
@@ -99,13 +99,13 @@ func (b *Builder) buildStrings() error {
9999
qn := moduleName + "." + wf.Name
100100

101101
if wf.WorkflowName != "" {
102-
insert(qn, "WORKFLOW", wf.WorkflowName, "workflow_name", moduleName)
102+
insert(qn, "WORKFLOW", wf.WorkflowName, "workflow_name", "", moduleName)
103103
}
104104
if wf.WorkflowDescription != "" {
105-
insert(qn, "WORKFLOW", wf.WorkflowDescription, "workflow_description", moduleName)
105+
insert(qn, "WORKFLOW", wf.WorkflowDescription, "workflow_description", "", moduleName)
106106
}
107107
if wf.Documentation != "" {
108-
insert(qn, "WORKFLOW", wf.Documentation, "documentation", moduleName)
108+
insert(qn, "WORKFLOW", wf.Documentation, "documentation", "", moduleName)
109109
}
110110

111111
if wf.Flow != nil {
@@ -119,23 +119,23 @@ func (b *Builder) buildStrings() error {
119119
}
120120

121121
// extractWorkflowFlowStrings extracts strings from workflow activities recursively.
122-
func extractWorkflowFlowStrings(flow *workflows.Flow, qn, moduleName string, insert func(string, string, string, string, string)) {
122+
func extractWorkflowFlowStrings(flow *workflows.Flow, qn, moduleName string, insert func(string, string, string, string, string, string)) {
123123
for _, act := range flow.Activities {
124124
if act.GetCaption() != "" {
125-
insert(qn, "WORKFLOW", act.GetCaption(), "activity_caption", moduleName)
125+
insert(qn, "WORKFLOW", act.GetCaption(), "activity_caption", "", moduleName)
126126
}
127127

128128
switch a := act.(type) {
129129
case *workflows.UserTask:
130130
if a.TaskName != "" {
131-
insert(qn, "WORKFLOW", a.TaskName, "task_name", moduleName)
131+
insert(qn, "WORKFLOW", a.TaskName, "task_name", "", moduleName)
132132
}
133133
if a.TaskDescription != "" {
134-
insert(qn, "WORKFLOW", a.TaskDescription, "task_description", moduleName)
134+
insert(qn, "WORKFLOW", a.TaskDescription, "task_description", "", moduleName)
135135
}
136136
for _, outcome := range a.Outcomes {
137137
if outcome.Caption != "" {
138-
insert(qn, "WORKFLOW", outcome.Caption, "outcome_caption", moduleName)
138+
insert(qn, "WORKFLOW", outcome.Caption, "outcome_caption", "", moduleName)
139139
}
140140
if outcome.Flow != nil {
141141
extractWorkflowFlowStrings(outcome.Flow, qn, moduleName, insert)
@@ -170,7 +170,7 @@ func extractWorkflowFlowStrings(flow *workflows.Flow, qn, moduleName string, ins
170170
}
171171

172172
// extractActivityStrings extracts string literals from microflow/nanoflow activities.
173-
func extractActivityStrings(oc *microflows.MicroflowObjectCollection, qn, objType, moduleName string, insert func(string, string, string, string, string)) {
173+
func extractActivityStrings(oc *microflows.MicroflowObjectCollection, qn, objType, moduleName string, insert func(string, string, string, string, string, string)) {
174174
if oc == nil {
175175
return
176176
}
@@ -184,23 +184,23 @@ func extractActivityStrings(oc *microflows.MicroflowObjectCollection, qn, objTyp
184184
switch a := act.Action.(type) {
185185
case *microflows.LogMessageAction:
186186
if a.MessageTemplate != nil && a.MessageTemplate.Translations != nil {
187-
for _, t := range a.MessageTemplate.Translations {
188-
insert(qn, objType, t, "log_message", moduleName)
187+
for lang, t := range a.MessageTemplate.Translations {
188+
insert(qn, objType, t, "log_message", lang, moduleName)
189189
}
190190
}
191191
if a.LogNodeName != "" {
192-
insert(qn, objType, a.LogNodeName, "log_node", moduleName)
192+
insert(qn, objType, a.LogNodeName, "log_node", "", moduleName)
193193
}
194194
case *microflows.ShowMessageAction:
195195
if a.Template != nil && a.Template.Translations != nil {
196-
for _, t := range a.Template.Translations {
197-
insert(qn, objType, t, "show_message", moduleName)
196+
for lang, t := range a.Template.Translations {
197+
insert(qn, objType, t, "show_message", lang, moduleName)
198198
}
199199
}
200200
case *microflows.ValidationFeedbackAction:
201201
if a.Template != nil && a.Template.Translations != nil {
202-
for _, t := range a.Template.Translations {
203-
insert(qn, objType, t, "validation_message", moduleName)
202+
for lang, t := range a.Template.Translations {
203+
insert(qn, objType, t, "validation_message", lang, moduleName)
204204
}
205205
}
206206
}

mdl/catalog/tables.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,7 @@ func (c *Catalog) createTables() error {
827827
ObjectType,
828828
StringValue,
829829
StringContext,
830+
Language,
830831
ModuleName
831832
)`,
832833

0 commit comments

Comments
 (0)