# 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 } } }