romance_core/addon/
i18n.rs1use crate::addon::Addon;
2use anyhow::Result;
3use std::path::Path;
4
5pub struct I18nAddon;
6
7impl Addon for I18nAddon {
8 fn name(&self) -> &str {
9 "i18n"
10 }
11
12 fn check_prerequisites(&self, project_root: &Path) -> Result<()> {
13 super::check_romance_project(project_root)
14 }
15
16 fn is_already_installed(&self, project_root: &Path) -> bool {
17 project_root.join("backend/src/i18n.rs").exists()
18 }
19
20 fn install(&self, project_root: &Path) -> Result<()> {
21 install_i18n(project_root)
22 }
23
24 fn uninstall(&self, project_root: &Path) -> Result<()> {
25 use colored::Colorize;
26
27 println!("{}", "Uninstalling i18n (internationalization)...".bold());
28
29 if super::remove_file_if_exists(&project_root.join("backend/src/i18n.rs"))? {
31 println!(" {} backend/src/i18n.rs", "delete".red());
32 }
33 if super::remove_file_if_exists(&project_root.join("frontend/src/lib/i18n.ts"))? {
34 println!(" {} frontend/src/lib/i18n.ts", "delete".red());
35 }
36
37 let locales_dir = project_root.join("backend/locales");
39 if locales_dir.exists() {
40 std::fs::remove_dir_all(&locales_dir)?;
41 println!(" {} backend/locales/", "delete".red());
42 }
43
44 super::remove_mod_from_main(project_root, "i18n")?;
46
47 super::remove_line_from_file(
49 &project_root.join("backend/src/routes/mod.rs"),
50 "locale_middleware",
51 )?;
52
53 super::remove_feature_flag(project_root, "i18n")?;
55
56 crate::ai_context::regenerate(project_root).ok();
58
59 println!();
60 println!(
61 "{}",
62 "i18n (internationalization) uninstalled successfully."
63 .green()
64 .bold()
65 );
66
67 Ok(())
68 }
69}
70
71fn install_i18n(project_root: &Path) -> Result<()> {
72 use crate::template::TemplateEngine;
73 use crate::utils;
74 use colored::Colorize;
75 use tera::Context;
76
77 println!("{}", "Installing i18n (internationalization)...".bold());
78
79 let engine = TemplateEngine::new()?;
80 let ctx = Context::new();
81
82 let content = engine.render("addon/i18n/i18n.rs.tera", &ctx)?;
84 utils::write_file(&project_root.join("backend/src/i18n.rs"), &content)?;
85 println!(" {} backend/src/i18n.rs", "create".green());
86
87 let content = engine.render("addon/i18n/en.json.tera", &ctx)?;
89 utils::write_file(&project_root.join("backend/locales/en.json"), &content)?;
90 println!(" {} backend/locales/en.json", "create".green());
91
92 let content = engine.render("addon/i18n/ru.json.tera", &ctx)?;
94 utils::write_file(&project_root.join("backend/locales/ru.json"), &content)?;
95 println!(" {} backend/locales/ru.json", "create".green());
96
97 let content = engine.render("addon/i18n/i18n_frontend.ts.tera", &ctx)?;
99 utils::write_file(&project_root.join("frontend/src/lib/i18n.ts"), &content)?;
100 println!(" {} frontend/src/lib/i18n.ts", "create".green());
101
102 super::add_mod_to_main(project_root, "i18n")?;
104
105 utils::insert_at_marker(
107 &project_root.join("backend/src/routes/mod.rs"),
108 "// === ROMANCE:MIDDLEWARE ===",
109 " .layer(axum::middleware::from_fn(crate::i18n::locale_middleware))",
110 )?;
111
112 crate::generator::auth::insert_cargo_dependency(
114 &project_root.join("backend/Cargo.toml"),
115 &[("serde_json", r#""1""#)],
116 )?;
117
118 super::update_feature_flag(project_root, "i18n", true)?;
120
121 println!();
122 println!(
123 "{}",
124 "i18n (internationalization) installed successfully!"
125 .green()
126 .bold()
127 );
128 println!(" Locale files: backend/locales/en.json, backend/locales/ru.json");
129 println!(" Backend usage: i18n::t(\"en\", \"common.success\")");
130 println!(" Frontend usage: import {{ t }} from '@/lib/i18n'");
131 println!(" The Accept-Language middleware extracts locale from request headers.");
132 println!(" Access locale in handlers via: request.extensions().get::<i18n::Locale>()");
133
134 Ok(())
135}