Static site built with vanilla HTML, CSS, and JavaScript. No build tools, no frameworks. Just native browser APIs and Bootstrap 5 for layout.
Philosophy: Keep it simple. Add complexity only when necessary.
Could've used i18next, but that's 50KB+ for something I can do in ~100 lines.
Language detection:
- localStorage (
languagekey) - remembers user choice - Browser language (
navigator.language) - Fallback to English
Translation keys:
- Flat JSON:
{"title": "...", "role": "..."} - No nesting (keeps it simple)
- Same keys across all languages (en, es, fr, pt)
HTML usage:
<p data-translate="role">Default text</p>
<img data-translate-alt="imageAlt" alt="Default" />SEO: Updates <title>, meta description, and Open Graph tags on language change.
Supports both browser and Jest:
// Browser: global functions
if (typeof window !== "undefined") {
window.setLanguage = setLanguage;
}
// Jest: CommonJS exports
if (typeof module !== "undefined" && module.exports) {
module.exports = { setLanguage, ... };
}No build step needed. Works everywhere.
Standard <select> can't do glassmorphism without hacky CSS. Custom dropdown gives full control.
Features:
- Click outside to close
- Keyboard accessible
- Pure JavaScript (no libs)
Base styles = mobile. Enhance for desktop:
.custom-select {
width: 110px;
} /* mobile */
@media (min-width: 992px) {
.custom-select {
width: 150px;
} /* desktop */
}:root {
--clr-navy: #070f2b;
--clr-gradient-mid: #3572ef;
--clr-linkedin: #2856c7;
}Glassmorphism:
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);SVG colors: Use filters instead of multiple files:
filter: brightness(0) invert(1); /* white */
filter: brightness(0) invert(0); /* dark */What's tested:
- Translation loading (success + errors)
- DOM updates (textContent, alt, meta tags)
- localStorage integration
- Dropdown behavior
What's not:
- Browser APIs (tested by browsers)
- Bootstrap (tested by Bootstrap)
- DOMContentLoaded listener (manual test)
ESLint 9+ requires it. Multiple environments need different globals:
- Browser JS:
setLanguage,getCurrentLanguage - Test files:
describe,test,expect - Node scripts:
module,require
{
"singleQuote": false,
"trailingComma": "none",
"arrowParens": "always",
"tabWidth": 4
}Personal preference from C#/TypeScript background.
Need DOM APIs without a browser. Jest runs tests in Node.js with simulated DOM.
On Pull Request:
- Format check (Prettier)
- Lint (ESLint)
- Tests (Jest with coverage)
- Upload coverage artifactOn Push to Main:
- All PR checks
- Build (prepare src/ folder)
- Deploy to GitHub PagesBranch Protection: Direct pushes to main are blocked. Must use PRs.
Configuration:
- Source: GitHub Actions (not branch-based)
- Deploys:
./srcdirectory - URL: https://fernandotonacoder.github.io
No build step needed - just copy static files.
- Async translation loading (non-blocking)
- Only loads selected language
- System fonts (no font loading)
- Total JS: ~250 lines
- Page load: < 1s on 3G
- Add to all 4 locale files
- Use
data-translate="key"in HTML - Test manually
- Create
/locales/{code}.json - Update
supportedLangsintranslations.js - Update
languageNamesincustom-select.js - Add HTML option