Tooling: goopt-i18n-gen
goopt-i18n-gen is a powerful command-line tool designed to automate and streamline the entire internationalization (i18n) workflow for goopt applications. It helps you add, manage, and validate translations with minimal effort.
Key Features
- Type-Safe Key Generation: Converts your JSON translation files into type-safe Go constants, preventing typos and enabling autocompletion.
- Source Code Auditing: Scans your Go source files for
gooptstructs and automatically generatedescKeytags. - Translation Stubbing: Uses your existing
desc:"..."tags to create initial translations in your JSON files. - String Extraction: Analyzes your code to find hardcoded user-facing strings and helps you replace them with translation calls.
- Validation: Ensures that every
descKeyin your code has a corresponding entry in your translation files.
Installation
go install github.com/napalu/goopt/v2/cmd/goopt-i18n-gen@latest
For a complete, runnable demonstration of the workflows described below, see the i18n-codegen-demo example.
Workflow 1: Adding i18n to an Existing goopt App
This is the recommended “360° workflow” for retrofitting an existing application that already uses goopt with desc tags.
The Chicken-and-Egg Problem
If you manually add descKey tags to your code before the translations exist in your JSON files, goopt will display the raw keys (e.g., app.flag.verbose_desc) to the user. This workflow avoids that broken state.
The Golden Rule: Translations first, descKey tags second!
Step-by-Step Guide
- Initial State: Start with a standard
gooptstruct usingdesctags.type AppConfig struct { Verbose bool `goopt:"short:v;desc:Enable verbose output"` } - Initialize and Generate Translations: Use the
auditcommand to find fields needing i18n and populate your locale file. This step does not modify your Go code.# Create an empty locales/en.json if it doesn't exist goopt-i18n-gen -i locales/en.json init # Analyze code and generate translations into the JSON file goopt-i18n-gen -i locales/en.json audit -d -g --key-prefix appYour
locales/en.jsonfile will now contain the generated translation:{ "app.app_config.verbose_desc": "Enable verbose output" } - Update Source Code with
descKeyTags: Now that the translations exist, it’s safe to add thedescKeytags. Use the-u(auto-update) flag to do this automatically.# This command modifies your Go source files. goopt-i18n-gen -i locales/en.json audit -d -u --key-prefix appYour struct is now safely updated:
type AppConfig struct { Verbose bool `goopt:"short:v;desc:Enable verbose output;descKey:app.app_config.verbose_desc"` } - Generate Type-Safe Constants: Finally, generate the type-safe Go constants from your JSON file(s).
goopt-i18n-gen -i "locales/*.json" generate -o messages/keys.go -p messages
Workflow 2: Extracting Hardcoded Strings
For applications with hardcoded strings outside of goopt tags (e.g., in fmt.Println calls), use the extract command.
Comment-Based Migration (Recommended)
This safe, iterative workflow adds // i18n-todo: comments to your code, allowing for manual review.
- Extract and Comment:
goopt-i18n-gen -i "locales/*.json" extractYour code will be updated:
// Before: fmt.Println("Starting server...") // After: fmt.Println("Starting server...") // i18n-todo: app.extracted.starting_server -
Review and Update: Manually replace the commented lines with translation calls. You can mark them as
// i18n-doneor// i18n-skipto track progress. - Auto-Transform (Optional): After your review, you can automatically transform all remaining
i18n-todocomments into translation calls.goopt-i18n-gen -i "locales/*.json" extract -u --tr-pattern "tr.T"
Handling Structured Logging (slog)
When using structured loggers like slog, you need to prevent the extraction of logging keys (e.g., "user_id", "request_id"). The most effective way is to skip all strings that don’t contain whitespace.
# This command correctly extracts "User logged in" but skips "user_id".
goopt-i18n-gen -i "locales/*.json" extract -S "^[^\s]+$"
This pattern is highly recommended for any project using structured logging.
Full Command Reference
Global Options
-i, --input: Input JSON files (e.g.,"locales/*.json"). Required.-v, --verbose: Enable verbose output.-l, --language: Set the tool’s own output language (en,de,fr).
init
Initializes empty translation files.
goopt-i18n-gen -i locales/en.json init
audit
Scans Go source files for goopt fields and helps generate descKey tags and translations.
--files: Go source files to scan (default:*.go).-d, --generate-desc-keys: Generate suggestions fordescKeytags.-g, --generate-missing: Generate stub entries for missing keys in JSON files.-u, --auto-update: Modifies source files to automatically adddescKeytags.-n, --dry-run: Preview changes without modifying files.--key-prefix: Prefix for generated keys (e.g.,app).--backup-dir: Directory for backup files (default:.goopt-i18n-backup).
extract Command
Extracts string literals from Go source files.
-s, --files: Go files to scan (default:**/*.go).-m, --match-only: Regex to include only matching strings.-S, --skip-match: Regex to exclude matching strings.-P, --key-prefix: Prefix for generated keys (default:app.extracted).-l, --min-length: Minimum string length (default:2).-u, --auto-update: Update source files (adds comments or replaces strings).-n, --dry-run: Preview changes without modifying files.--tr-pattern: The translator call pattern to use for replacement (e.g.,tr.T).--transform-mode: What to transform:user-facing(default),with-comments,all-marked,all.--keep-comments: Keepi18n-*comments after replacement.--clean-comments: Remove alli18n-*comments from source files.--backup-dir: Directory for backup files.--user-facing-regex: Regex to identify custom user-facing functions.--format-function-regex: Regex and argument index for custom format functions (e.g.,"MyLogf:1")
generate
Generates a type-safe Go constants file.
-o, --output: Output Go file path. Required.-p, --package: Go package name for the generated file.
validate
Checks that all descKey tags in your code have translations.
-s, --scan: Go source files to scan.--strict: Exit with a non-zero status code on failure (for CI/CD).
add
Programmatically adds new keys to locale files.
-k, --key: The key to add.-V, --value: The value for the key.-F, --from-file: A JSON file containing key-value pairs to add.-m, --mode: How to handle existing keys (skip,replace,error).
sync
Ensures all locale files contain the same set of keys.
-t, --target: Target files to sync against the-ireference files.-r, --remove-extra: Remove keys from target files that don’t exist in the reference.