#![allow(clippy::unwrap_used, clippy::expect_used)]
use anyhow::Result;
use http_handle::Server;
use ssg::plugin::{PluginContext, PluginManager};
use ssg::search::{LocalizedSearchPlugin, SearchLabels};
use ssg::seo::SeoPlugin;
use staticdatagen::compiler::service::compile;
use std::fs;
use std::path::Path;
const LANGUAGES: &[(&str, &str)] = &[
("en", "English"),
("fr", "Français"),
("ar", "العربية"),
("bn", "বাংলা"),
("cs", "Čeština"),
("de", "Deutsch"),
("es", "Español"),
("ha", "Hausa"),
("he", "עברית"),
("hi", "हिन्दी"),
("id", "Indonesia"),
("it", "Italiano"),
("ja", "日本語"),
("ko", "한국어"),
("nl", "Nederlands"),
("pl", "Polski"),
("pt", "Português"),
("ro", "Română"),
("ru", "Русский"),
("sv", "Svenska"),
("th", "ไทย"),
("tl", "Filipino"),
("tr", "Türkçe"),
("uk", "Українська"),
("vi", "Tiếng Việt"),
("yo", "Yorùbá"),
("zh", "简体中文"),
("zh-tw", "繁體中文"),
];
fn main() -> Result<()> {
let languages: Vec<&str> =
LANGUAGES.iter().map(|(code, _)| *code).collect();
let public_root = Path::new("./examples/public");
fs::create_dir_all(public_root)?;
for lang in &languages {
println!("Processing language: {lang}");
let build_dir = Path::new("./examples/build").join(lang);
let site_dir = public_root.join(lang);
let content_dir = Path::new("./examples/content").join(lang);
let template_dir = Path::new("./examples/templates").join(lang);
println!(" 🔍 Compiling content for language: {lang}...");
match compile(&build_dir, &content_dir, &site_dir, &template_dir) {
Ok(()) => println!(
" ✅ Successfully compiled static site for language: {lang}"
),
Err(e) => {
println!(" ❌ Error compiling site for {lang}: {e:?}");
return Err(e);
}
}
let mut plugins = PluginManager::new();
plugins.register(SeoPlugin);
plugins.register(LocalizedSearchPlugin::new(SearchLabels::for_locale(
lang,
)));
let ctx = PluginContext::new(
&content_dir,
&build_dir,
&site_dir,
&template_dir,
);
plugins.run_after_compile(&ctx)?;
println!(" 🔌 Plugins complete for {lang}");
}
{
use ssg::i18n::{I18nConfig, I18nPlugin, UrlPrefixStrategy};
let i18n_cfg = I18nConfig {
default_locale: "en".to_string(),
locales: languages.iter().map(|s| (*s).to_string()).collect(),
url_prefix: UrlPrefixStrategy::SubPath,
};
let i18n_plugin = I18nPlugin::new(i18n_cfg);
let ctx = PluginContext::new(
Path::new("./examples/content"),
Path::new("./examples/build"),
public_root,
Path::new("./examples/templates"),
);
use ssg::plugin::Plugin;
i18n_plugin.after_compile(&ctx)?;
println!(" 🌍 I18nPlugin injected hreflang + language switcher");
}
let en_root = public_root.join("en");
if en_root.exists() {
copy_dir_recursive(&en_root, public_root)?;
println!(" ✅ Promoted English to site root");
}
let host = std::env::var("SSG_HOST")
.ok()
.filter(|v| !v.is_empty())
.unwrap_or_else(|| "127.0.0.1".to_string());
let port = std::env::var("SSG_PORT")
.ok()
.and_then(|v| v.parse::<u16>().ok())
.unwrap_or(3000);
let bind = format!("{host}:{port}");
let server = Server::builder()
.address(&bind)
.document_root(public_root.to_str().unwrap())
.custom_header("Permissions-Policy", "browsing-topics=()")
.build()
.map_err(|e| anyhow::anyhow!("{e}"))?;
println!("Serving site at http://{bind}");
let _ = server.start();
Ok(())
}
fn copy_dir_recursive(src: &Path, dst: &Path) -> Result<()> {
if !dst.exists() {
fs::create_dir_all(dst)?;
}
for entry in fs::read_dir(src)? {
let entry = entry?;
let file_type = entry.file_type()?;
let dst_path = dst.join(entry.file_name());
if file_type.is_dir() {
copy_dir_recursive(&entry.path(), &dst_path)?;
} else {
let _ = fs::copy(entry.path(), &dst_path)?;
}
}
Ok(())
}