provisioning/tools/codegen/form_string_extractor.nu
2026-01-14 02:59:52 +00:00

196 lines
6.7 KiB
Plaintext

# Form String Extractor
# Extracts user-facing strings from TypeDialog TOML forms for i18n
# Generates Fluent keys and string catalogs
use std
# Extract strings from a single TOML form file
export def extract-form-strings [
form_path: string
] {
let content = (open $form_path)
let extracted = (
if ($content | has "elements") {
$content.elements | reduce -f [] { |elem, acc|
let elem_name = ($elem | get name? | default "unknown")
let prompt_entry = (
if ($elem | has "prompt") {
let prompt = ($elem | get prompt)
if ($prompt != null) and ($prompt != "") {
[{
key: $"form-($elem_name)-prompt"
en: $prompt
type: "prompt"
}]
} else {
[]
}
} else {
[]
}
)
let help_entry = (
if ($elem | has "help") {
let help = ($elem | get help)
if ($help != null) and ($help != "") {
[{
key: $"form-($elem_name)-help"
en: $help
type: "help"
}]
} else {
[]
}
} else {
[]
}
)
let placeholder_entry = (
if ($elem | has "placeholder") {
let placeholder = ($elem | get placeholder)
if ($placeholder != null) and ($placeholder != "") {
[{
key: $"form-($elem_name)-placeholder"
en: $placeholder
type: "placeholder"
}]
} else {
[]
}
} else {
[]
}
)
let options_entries = (
if ($elem | has "options") and ($elem.type == "select") {
$elem.options | reduce -f [] { |opt, opts_acc|
let label_entry = (
if ($opt | has "label") {
[{
key: $"form-($elem_name)-option-($opt.value)"
en: ($opt | get label)
type: "option_label"
}]
} else {
[]
}
)
let desc_entry = (
if ($opt | has "description") {
[{
key: $"form-($elem_name)-desc-($opt.value)"
en: ($opt | get description)
type: "option_desc"
}]
} else {
[]
}
)
$opts_acc | append $label_entry | append $desc_entry | flatten
}
} else {
[]
}
)
let title_entry = (
if ($elem | has "title") {
let title = ($elem | get title)
if ($title != null) and ($title != "") {
[{
key: $"section-($elem_name)-title"
en: $title
type: "section_title"
}]
} else {
[]
}
} else {
[]
}
)
let desc_entry = (
if ($elem | has "description") and ($elem.type == "section_header") {
let desc = ($elem | get description)
if ($desc != null) and ($desc != "") {
[{
key: $"section-($elem_name)-desc"
en: $desc
type: "section_desc"
}]
} else {
[]
}
} else {
[]
}
)
$acc
| append $prompt_entry
| append $help_entry
| append $placeholder_entry
| append $options_entries
| append $title_entry
| append $desc_entry
| flatten
}
} else {
[]
}
)
# Extract from load_fragments references
# Note: Fragments are loaded recursively - future enhancement
$extracted
}
# Generate Fluent format from string catalog
export def generate-fluent [
strings: list
--language: string = "en-US"
] {
let header = $"# Auto-generated Fluent translations\n# Language: ($language)\n# Generated by form_string_extractor.nu\n\n"
let fluent_entries = (
$strings
| reduce -f [] { |str, acc|
let source = (if $language == "en-US" { $str.en } else { "TODO" })
let line = ($str.key + " = " + $source)
$acc | append $line
}
| str join "\n"
)
$header + $fluent_entries + "\n"
}
# Count unique strings across forms
export def count-strings [
forms_list: list
] {
$forms_list | reduce -f {total: 0, by_type: {}} { |form_path, acc|
let strings = (extract-form-strings $form_path)
let new_total = ($acc.total + ($strings | length))
let new_by_type = ($strings | reduce -f $acc.by_type { |str, type_acc|
let type_key = $str.type
let current_count = (if ($type_acc | has $type_key) { ($type_acc | get $type_key) } else { 0 })
$type_acc | insert $type_key ($current_count + 1)
})
{
total: $new_total
by_type: $new_by_type
}
}
}