Coordination intelligence by AstraNL. Addresses a need seen in 48 real open-source requests.
Language switching is a straightforward pattern once you separate content from logic. This guide covers the core approach, working code, and what breaks most implementations.
Store translatable strings separately from your code, load the right language based on user selection, and swap content without reloading. Three parts:
Create a directory structure and store translations as JSON objects keyed by language:
locales/
en.json
es.json
fr.json
File: locales/en.json
{
"header": {
"title": "Welcome",
"subtitle": "Choose your language"
},
"button": {
"submit": "Submit",
"cancel": "Cancel"
}
}
File: locales/es.json
{
"header": {
"title": "Bienvenido",
"subtitle": "Elige tu idioma"
},
"button": {
"submit": "Enviar",
"cancel": "Cancelar"
}
}
Create a simple class or module to load, store, and retrieve translations:
class LanguageManager {
constructor(defaultLanguage = 'en') {
this.currentLanguage = defaultLanguage;
this.translations = {};
this.listeners = [];
}
async loadLanguage(lang) {
try {
const response = await fetch(`/locales/${lang}.json`);
this.translations[lang] = await response.json();
this.currentLanguage = lang;
this.notifyListeners();
} catch (error) {
console.error(`Failed to load language: ${lang}`, error);
}
}
get(key) {
const keys = key.split('.');
let value = this.translations[this.currentLanguage];
for (const k of keys) {
value = value?.[k];
}
return value || key;
}
setLanguage(lang) {
if (this.translations[lang]) {
this.currentLanguage = lang;
this.notifyListeners();
}
}
subscribe(callback) {
this.listeners.push(callback);
}
notifyListeners() {
this.listeners.forEach(cb => cb(this.currentLanguage));
}
}
HTML example:
<!DOCTYPE html>
<html>
<head>
<title>i18n Example</title>
</head>
<body>
<div id="app">
<h1 id="title"></h1>
<p id="subtitle"></p>
<button id="submit"></button>
<div>
<label for="lang-select">Language:</label>
<select id="lang-select">
<option value="en">English</option>
<option value="es">Español</option>
<option value="fr">Français</option>
</select>
</div>
</div>
<script>
const i18n = new LanguageManager('en');
// Load initial language
i18n.loadLanguage('en');
// Update UI when language changes
const updateUI = () => {
document.getElementById('title').textContent = i18n.get('header.title');
document.getElementById('subtitle').textContent = i18n.get('header.subtitle');
document.getElementById('submit').textContent = i18n.get('button.submit');
};
i18n.subscribe(updateUI);
updateUI();
// Handle language selection
document.getElementById('lang-select').addEventListener('change', (e) => {
i18n.loadLanguage(e.target.value);
});
</script>
</body>
</html>
Wrap the manager in a context or state management:
React example:
const I18nContext = React.createContext();
function App() {
const [i18n
Published by AstraNL coordination infrastructure. AI-assisted drafting (EU AI Act Art. 50).