A Dutch-language static version of firstlinesoftware.com, hosted on GitHub Pages at nl.firstlinesoftware.com.
wget --page-requisites \
--span-hosts \
--convert-links \
--no-host-directories \
--adjust-extension \
-e robots=off \
https://firstlinesoftware.com/--convert-links rewrites absolute URLs to relative ones in index.html.
--adjust-extension appends .css/.js to files that have query strings
(e.g. style.alt.css?ver=123 → saved as style.alt.css?ver=123.css).
Important: wget overwrites index.html with a fresh English copy. Apply
all Dutch translations after running wget, not before.
Some assets are injected at runtime by JavaScript and are not reachable by wget's static crawler. Download them manually:
# HubSpot form CSS (injected by forms/v2.js)
curl -o wp-content/themes/cleanslate/althubspot.css \
"https://firstlinesoftware.com/wp-content/themes/cleanslate/althubspot.css?ver=..."Check the browser Network tab for any remaining 404s after first deploy.
wget saves files with a literal ? in the filename when the source URL had
a query string (e.g. theme.js?ver=1773578688, lucide.woff2?t=123).
These are fine for genuine local assets (theme JS/CSS, fonts).
Do not commit local copies of external Google service scripts. wget will
download gtag/js?id=..., optimize.js?id=..., ai/gen-app-builder/client?hl=...,
and GTM's ns.html?id=... as local files, but these scripts update frequently
and must stay on their original CDN URLs. Restore them in index.html:
<!-- Google Analytics -->
<script src="https://www.googletagmanager.com/gtag/js?id=GT-NFB2FD3" ...></script>
<!-- Google Optimize -->
<script src="https://www.googleoptimize.com/optimize.js?id=OPT-K6FFQ3T"></script>
<!-- Google AI search widget -->
<script src="https://cloud.google.com/ai/gen-app-builder/client?hl=en_US"></script>
<!-- GTM noscript iframe -->
<iframe src="https://www.googletagmanager.com/ns.html?id=GTM-NJLPZ5R" ...></iframe>Also delete pagead/ — it's a Google Ads conversion pixel response page, not
needed in the repo.
How the ?ver=... theme files are served locally (Python http.server):
The HTML references them with URL-encoded %3F (e.g. src="theme.js%3Fver=...").
The browser sends %3F as part of the path (not a query string), so Python
decodes it to ? and finds the file on disk.
For files where the browser sends a real query string (e.g. althubspot.css?ver=...),
Python's http.server strips the query part and serves althubspot.css — so
save those without the ?ver=... suffix.
Translations were applied via Python str.replace() after fetching. Watch out for:
- HTML entities: the source HTML uses
&(not&) and’(not') - Unicode characters that look like spaces/newlines: U+2028 (LINE SEPARATOR), U+00A0 (non-breaking space), U+2019 (right single quote)
- Always inspect raw bytes when a replacement fails:
open(f, 'rb').read()
Key metadata changes for Dutch:
<html lang="nl-NL">
<meta property="og:locale" content="nl_NL" />
<meta property="og:url" content="https://nl.firstlinesoftware.com/" />
<!-- JSON-LD -->
"inLanguage": "nl-NL"Dutch words are longer than English on average. Check for overflow/wrapping problems using Playwright + headless Chromium:
# Accurate visual line count using Range.getClientRects()
# (scrollHeight/lineHeight gives false positives due to CSS margins)
def visual_lines(el):
return el.evaluate('''e => {
const range = document.createRange();
range.selectNodeContents(e);
const ys = new Set([...range.getClientRects()].map(r => Math.round(r.top)));
return ys.size;
}''')Fix overflow with CSS hyphenation (added to <head>):
<style>
body { hyphens: auto; -webkit-hyphens: auto; }
a.button, button, nav a, .footer-nav a { hyphens: none; -webkit-hyphens: none; }
</style>Shorten translations for narrow containers (mode panes ~312px, SDLC section ~530px, leadership figcaptions, stats labels).
The WordPress Cookiebot plugin uses data-implementation="wp", which causes
uc.js to fetch /{cbid}/cc.js from your own domain — a dynamic WordPress
endpoint that doesn't exist on a static site.
Use the standard (non-WordPress) Cookiebot embed instead:
<script id="Cookiebot"
src="https://consent.cookiebot.com/uc.js"
data-cbid="990e16bd-2861-4a00-a4ea-4dbe73a34971"
data-blockingmode="auto">
</script>- No
data-implementation="wp"— everything loads from Cookiebot's CDN - No
data-georegions— that's also WordPress-plugin-specific - The CBID
990e16bd...is configured fornl.firstlinesoftware.comin the Cookiebot admin (different from the main site's CBID066e3009...)
Copyright © 2026 First Line Software B.V. (KVK 58362126)When firstlinesoftware.com is updated:
- Run the wget command above (saves fresh assets, overwrites
index.html) - Re-apply Dutch translations to the new
index.html - Check for new dynamically loaded assets in the browser Network tab
- Run the Playwright layout checker for new overflow issues
- Commit and push