How I Generated a 500-Page Localized Site Using Only PowerShell
DEV Community

How I Generated a 500-Page Localized Site Using Only PowerShell

As developers, we have a bad habit of over-engineering everything. When I decided to build jsonexlab.com to sell my focused Notion templates, my first instinct was to spin up a Next.js app.

I thought: "I'll need a database for the products, i18n for the languages, and a CMS for the blog." But then I looked at the requirements. I wasn't building a complex SaaS with user authentication. I was building a static catalog of digital products.

So, I did something crazy. I deleted the Node.js setup, opened PowerShell, and wrote a script to generate raw HTML. Here is how I did it, and why it works.

The "No Framework" Stack

  • Hosting: Cloudflare Pages (Free tier, unlimited bandwidth).
  • Generation: PowerShell scripts.
  • Styles: Plain CSS.
  • Payments: Suby (Crypto).
  • Email: Web3Forms + Make.com + Brevo.

The result? A site with 500+ pages in 28 languages, zero hydration errors, zero JS bundles, and load times measured in milliseconds.

The Challenge: Translating 28 Languages

I wanted to sell my templates in Europe, Asia, and South America. That meant 28 different languages. Doing this manually in React would have been a nightmare of JSON translation files.

Instead, I wrote a PowerShell script that took my base English HTML file and applied a dictionary of translations to it. Here is a simplified version of how the localization script works:

$translations = @{
  "es" = @{
    "You might also like" = "TambiΓ©n te puede gustar";
    "Get PDF" = "Obtener PDF";
  }
  "de" = @{
    "You might also like" = "Das kΓΆnnte dir auch gefallen";
    "Get PDF" = "PDF erhalten";
  }
}
foreach ($lang in $translations.Keys) {
  $html = [System.IO.File]::ReadAllText("base-template.html")
  foreach ($key in $translations[$lang].Keys) {
    $html = $html -replace [regex]::Escape($key), $translations[$lang][$key]
  }
  # Save to /es/index.html, /de/index.html, etc.
  [System.IO.File]::WriteAllText("$lang/index.html", $html)
}

To make Google happy, I also had to inject proper hreflang tags for all 28 languages into every single page. A simple loop handled that too.

The Real Challenge: Keeping Track of 30 Products

While the technical generation was fast, the business side was a mess. I had 30 different products: Debt Simulators, Freelancer Invoices, ADHD Planners. I was losing my mind trying to remember which product was linked to which blog post, or which language version needed updating.

I realized I was trying to build a system for my system. So, I built a simple Notion dashboard (ironically, using the same "anti-bloat" philosophy I sell). I tracked:

  • Product Status: (Draft, Finished, Live)
  • The Link Tree: (Which blog post links to which product)
  • The Tech Checklist: (Does it have an OG image? Is it in the sitemap?)

The Results

Speed: Because it's just static HTML, Cloudflare serves it instantly. No React hydration, no API calls, no database queries.

Cost: $0/month.

SEO: Because I control the raw HTML, I could perfectly inject JSON-LD schema (Product, BreadcrumbList, BlogPosting) without fighting a framework.

When Should You Do This?

If you are building a complex app with user accounts and real-time data, do not use PowerShell. Use Next.js, Remix, or whatever makes you happy.

But if you are building a content site, a landing page, or a digital product catalog, try going back to basics. Write a script that generates raw HTML. You might be surprised at how fast and simple it is.

Read on DEV Community ↗ ← Back to News

Comments

No comments yet. Start the discussion.