diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..debae5f --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,9 @@ +{ + "permissions": { + "allow": [ + "Bash(gleam build:*)" + ], + "deny": [], + "ask": [] + } +} \ No newline at end of file diff --git a/src/g18n/dev.gleam b/src/g18n/dev.gleam index 3dca8ef..3936045 100644 --- a/src/g18n/dev.gleam +++ b/src/g18n/dev.gleam @@ -1,6 +1,7 @@ import argv import filepath import g18n +import g18n/locale import gleam/bool import gleam/dict import gleam/io @@ -20,6 +21,8 @@ import trie /// gleam run generate # Generate from flat JSON files /// gleam run generate --nested # Generate from nested JSON files /// gleam run generate -- po # Generate from PO files +/// gleam run report # Show translation report +/// gleam run report --primary # Set primary locale for comparison /// gleam run help # Show help /// gleam run # Show help (default) /// ``` @@ -28,6 +31,8 @@ pub fn main() { ["generate"] -> generate_command() ["generate", "--nested"] -> generate_nested_command() ["generate", "--po"] -> generate_po_command() + ["report"] -> report_command("") + ["report", "--primary", locale] -> report_command(locale) ["help"] -> help_command() [] -> help_command() _ -> { @@ -66,6 +71,13 @@ fn generate_po_command() { } } +fn report_command(primary_locale: String) { + case generate_translation_report(primary_locale) { + Ok(_) -> Nil + Error(msg) -> io.println_error(snag.pretty_print(msg)) + } +} + fn help_command() { io.println("g18n CLI - Internationalization for Gleam") io.println("") @@ -77,6 +89,8 @@ fn help_command() { io.println( " generate --po Generate Gleam module from PO files (gettext)", ) + io.println(" report Show translation coverage report") + io.println(" report --primary Set primary locale for comparison") io.println(" help Show this help message") io.println("") io.println("Flat JSON usage:") @@ -136,6 +150,58 @@ fn generate_po_translations() -> SnagResult(String) { Ok(output_path) } +fn generate_translation_report(primary_locale: String) -> SnagResult(Nil) { + use project_name <- result.try(get_project_name()) + use locale_files <- result.try(find_locale_files(project_name)) + use locale_data <- result.try(load_all_locales(locale_files)) + + // Determine primary locale + let primary = case primary_locale { + "" -> { + case locale_data { + [first, ..] -> first.0 + [] -> "en" + } + } + locale -> locale + } + + // Find primary locale data + case list.find(locale_data, fn(pair) { pair.0 == primary }) { + Ok(#(_, primary_translations)) -> { + io.println("📊 Translation Validation Report") + io.println("Primary locale: " <> primary) + io.println("") + + // Generate reports for each locale compared to primary + list.each(locale_data, fn(pair) { + let #(locale_code, translations) = pair + + // Create locale for validation + case locale.new(string.replace(locale_code, each: "_", with: "-")) { + Ok(target_locale) -> { + let report = g18n.validate_translations(primary_translations, translations, target_locale) + io.println("🌍 " <> locale_code <> ":") + io.println(g18n.export_validation_report(report)) + io.println("") + } + Error(_) -> { + io.println("❌ Invalid locale code: " <> locale_code) + io.println("") + } + } + }) + + Ok(Nil) + } + Error(_) -> { + io.println("❌ Primary locale '" <> primary <> "' not found!") + io.println("Available locales: " <> string.join(list.map(locale_data, fn(pair) { pair.0 }), ", ")) + snag.error("Primary locale not found") + } + } +} + fn format() { shellout.command("gleam", ["format"], in: find_root("."), opt: []) |> snag.map_error(fn(_) { "Could not format generated file" }) diff --git a/src/g18n_dev/translations/de.json b/src/g18n_dev/translations/de.json new file mode 100644 index 0000000..29e0915 --- /dev/null +++ b/src/g18n_dev/translations/de.json @@ -0,0 +1,18 @@ +{ + "app.title": "Meine Anwendung", + "app.description": "Eine Beispielanwendung zum Testen von Übersetzungen", + "nav.home": "Startseite", + "nav.about": "Über uns", + "nav.contact": "Kontakt", + "user.login": "Anmelden", + "user.logout": "Abmelden", + "user.profile": "Profil", + "user.settings": "Einstellungen", + "messages.welcome": "Willkommen in unserer App!", + "messages.goodbye": "Danke, dass Sie unsere App nutzen!", + "errors.not_found": "Seite nicht gefunden", + "errors.server_error": "Interner Serverfehler", + "buttons.save": "Speichern", + "buttons.cancel": "Abbrechen", + "buttons.delete": "Löschen" +} \ No newline at end of file diff --git a/src/g18n_dev/translations/en.json b/src/g18n_dev/translations/en.json new file mode 100644 index 0000000..354eabe --- /dev/null +++ b/src/g18n_dev/translations/en.json @@ -0,0 +1,18 @@ +{ + "app.title": "My Application", + "app.description": "A sample application for testing translations", + "nav.home": "Home", + "nav.about": "About", + "nav.contact": "Contact", + "user.login": "Login", + "user.logout": "Logout", + "user.profile": "Profile", + "user.settings": "Settings", + "messages.welcome": "Welcome to our app!", + "messages.goodbye": "Thanks for using our app!", + "errors.not_found": "Page not found", + "errors.server_error": "Internal server error", + "buttons.save": "Save", + "buttons.cancel": "Cancel", + "buttons.delete": "Delete" +} \ No newline at end of file diff --git a/src/g18n_dev/translations/es.json b/src/g18n_dev/translations/es.json new file mode 100644 index 0000000..78b1c1e --- /dev/null +++ b/src/g18n_dev/translations/es.json @@ -0,0 +1,15 @@ +{ + "app.title": "Mi Aplicación", + "app.description": "Una aplicación de ejemplo para probar traducciones", + "nav.home": "Inicio", + "nav.about": "Acerca de", + "nav.contact": "Contacto", + "user.login": "Iniciar sesión", + "user.logout": "Cerrar sesión", + "user.profile": "Perfil", + "messages.welcome": "¡Bienvenido a nuestra aplicación!", + "messages.goodbye": "¡Gracias por usar nuestra aplicación!", + "errors.not_found": "Página no encontrada", + "buttons.save": "Guardar", + "buttons.cancel": "Cancelar" +} \ No newline at end of file diff --git a/src/g18n_dev/translations/fr.json b/src/g18n_dev/translations/fr.json new file mode 100644 index 0000000..89cea60 --- /dev/null +++ b/src/g18n_dev/translations/fr.json @@ -0,0 +1,10 @@ +{ + "app.title": "Mon Application", + "nav.home": "Accueil", + "nav.about": "À propos", + "user.login": "Connexion", + "user.logout": "Déconnexion", + "messages.welcome": "Bienvenue dans notre application!", + "errors.not_found": "Page non trouvée", + "buttons.save": "Enregistrer" +} \ No newline at end of file