Translations API
The Translations module provides internationalization (i18n) support for WinnetouJs applications.
Import
import {
updateTranslations,
changeLang,
} from "winnetoujs/modules/translations";
Functions
updateTranslations()
Initializes the translation system with base language and configuration.
Signature:
updateTranslations(config: TranslationConfig): Promise<void>
Parameters:
config- Configuration objectstringsClass: Record<string, string>- Base language object (from JS/TS file)translationsPublicPath: string- Public path where JSON translation files are served
Returns: Promise<void> - Resolves when translations are initialized
Usage:
With .then():
import { updateTranslations } from "winnetoujs/modules/translations";
import strings from "./translations/en-us";
updateTranslations({
stringsClass: strings,
translationsPublicPath: "/translations",
}).then(() => {
startApp();
});
function startApp() {
console.log("App started with translations");
// Your app initialization
}
With await:
import { updateTranslations } from "winnetoujs/modules/translations";
import strings from "./translations/en-us";
await updateTranslations({
stringsClass: strings,
translationsPublicPath: "/translations",
});
function startApp() {
console.log("App started with translations");
// Your app initialization
}
startApp();
Important: Always use .then() or await before starting your app to ensure translations are loaded.
changeLang()
Changes the current application language.
Signature:
changeLang(
languageCode: string,
reload?: boolean
): void
Parameters:
languageCode- The language code matching the JSON filename (e.g.,"pt-br","es-es")reload- Optional. Iftrue, reloads the page after changing language (default:false)
Returns: void
Usage:
With page reload:
import { changeLang } from "winnetoujs/modules/translations";
changeLang("pt-br", true); // Changes to Portuguese and reloads page
changeLang("es-es", true); // Changes to Spanish and reloads page
changeLang("fr-fr", true); // Changes to French and reloads page
Without page reload:
changeLang("pt-br", false); // Changes to Portuguese without reload
changeLang("es-es"); // Changes to Spanish without reload (default)
Features:
- Loads corresponding JSON file from
translationsPublicPath - Updates
W.stringsobject - Saves language preference to localStorage
- Optionally reloads page for complete UI update
Important: To use changeLang(), you must have a corresponding JSON file (e.g., pt-br.json) in the translationsPublicPath folder.
Base Language Setup
Creating Base Language File
Create your original language as a JavaScript or TypeScript file (not JSON):
src/translations/en-us.js
import { W } from "winnetoujs";
export default W.strings = {
// App general
appTitle: "My Application",
appDescription: "A powerful application",
// Navigation
home: "Home",
about: "About",
contact: "Contact",
settings: "Settings",
// Actions
save: "Save",
cancel: "Cancel",
delete: "Delete",
edit: "Edit",
submit: "Submit",
// Messages
welcomeMessage: "Welcome!",
successMessage: "Success",
errorMessage: "Error occurred",
};
TypeScript version:
import { W } from "winnetoujs";
export default W.strings = {
appTitle: "My Application",
appDescription: "A powerful application",
home: "Home",
about: "About",
// ... more strings
} as const;
Benefits of JS/TS base language:
- F12 navigation to string definitions
- Reverse F12 to find string usage
- IDE autocomplete support
- Type safety with TypeScript
- Better refactoring support
Translation Files
JSON Translation Files
Create JSON files for additional languages in the public translations folder:
public/translations/pt-br.json
{
"appTitle": "Minha Aplicação",
"appDescription": "Uma aplicação poderosa",
"home": "Início",
"about": "Sobre",
"contact": "Contato",
"settings": "Configurações",
"save": "Salvar",
"cancel": "Cancelar",
"delete": "Excluir",
"edit": "Editar",
"submit": "Enviar",
"welcomeMessage": "Bem-vindo!",
"successMessage": "Sucesso",
"errorMessage": "Ocorreu um erro"
}
public/translations/es-es.json
{
"appTitle": "Mi Aplicación",
"appDescription": "Una aplicación potente",
"home": "Inicio",
"about": "Acerca de",
"contact": "Contacto",
"settings": "Configuración",
"save": "Guardar",
"cancel": "Cancelar",
"delete": "Eliminar",
"edit": "Editar",
"submit": "Enviar",
"welcomeMessage": "¡Bienvenido!",
"successMessage": "Éxito",
"errorMessage": "Ocurrió un error"
}
Important: Do NOT create a JSON file for your base language (e.g., en-us.json). This ensures localStorage is cleared and strings load from the JS file for better efficiency.
Using Translations in Constructos
Basic Usage
Reference strings from the imported strings object:
import { W } from "winnetoujs";
import { $header } from "./header.wcto";
import strings from "./translations/en-us";
new $header({
title: strings.appTitle,
subtitle: strings.appDescription,
}).create("#app");
Dynamic Content
import strings from "./translations/en-us";
function renderWelcome(username) {
new $welcome({
message: `${strings.welcomeMessage}, ${username}!`,
}).create("#app");
}
Form Labels
import strings from "./translations/en-us";
new $loginForm({
usernameLabel: strings.username,
passwordLabel: strings.password,
submitButton: strings.login,
cancelButton: strings.cancel,
}).create("#app");
Best Practices
String Organization
Group strings by feature:
export default W.strings = {
// Navigation
nav_home: "Home",
nav_about: "About",
nav_contact: "Contact",
// Forms
form_submit: "Submit",
form_cancel: "Cancel",
form_reset: "Reset",
// Validation
validation_required: "This field is required",
validation_email: "Invalid email address",
validation_minLength: "Minimum {0} characters",
// Messages
msg_success: "Operation successful",
msg_error: "An error occurred",
msg_loading: "Loading...",
};
String Naming Conventions
Use consistent prefixes:
export default W.strings = {
// btn_ for buttons
btn_save: "Save",
btn_cancel: "Cancel",
btn_delete: "Delete",
// lbl_ for labels
lbl_username: "Username",
lbl_password: "Password",
lbl_email: "Email",
// msg_ for messages
msg_welcome: "Welcome",
msg_goodbye: "Goodbye",
// err_ for errors
err_notFound: "Not found",
err_unauthorized: "Unauthorized",
};
Translation File Structure
Mirror the base language structure in JSON:
{
"nav_home": "Início",
"nav_about": "Sobre",
"nav_contact": "Contato",
"form_submit": "Enviar",
"form_cancel": "Cancelar",
"form_reset": "Redefinir",
"validation_required": "Este campo é obrigatório",
"validation_email": "Endereço de e-mail inválido",
"validation_minLength": "Mínimo de {0} caracteres"
}
Common Patterns
Language Selector
import { W } from "winnetoujs";
import { changeLang } from "winnetoujs/modules/translations";
import { $languageSelector } from "./components.wcto";
import strings from "./translations/en-us";
new $languageSelector({
label: strings.selectLanguage,
options: [
{ value: "en-us", label: "English" },
{ value: "pt-br", label: "Português" },
{ value: "es-es", label: "Español" },
{ value: "fr-fr", label: "Français" },
],
onchange: W.fx(select => {
const selectedLang = select.value;
if (selectedLang !== "en-us") {
changeLang(selectedLang, true);
} else {
changeLang("en-us", true);
}
}, "this"),
}).create("#header");
Language Toggle Button
import { changeLang } from "winnetoujs/modules/translations";
import { $langButton } from "./components.wcto";
import strings from "./translations/en-us";
const languages = ["en-us", "pt-br", "es-es"];
let currentIndex = 0;
new $langButton({
text: strings.changeLanguage,
onclick: W.fx(() => {
currentIndex = (currentIndex + 1) % languages.length;
const nextLang = languages[currentIndex];
changeLang(nextLang, true);
}),
}).create("#header");
Persistent Language Preference
import { W } from "winnetoujs";
import {
updateTranslations,
changeLang,
} from "winnetoujs/modules/translations";
import strings from "./translations/en-us";
// Initialize with saved language
async function initTranslations() {
await updateTranslations({
stringsClass: strings,
translationsPublicPath: "/translations",
});
// Check for saved language preference
const savedLang = W.getMutable("preferredLanguage");
if (savedLang && savedLang !== "en-us") {
changeLang(savedLang, false);
}
startApp();
}
// Save language preference when changing
function setLanguage(lang) {
W.setMutable("preferredLanguage", lang);
changeLang(lang, true);
}
initTranslations();
String Interpolation
import strings from "./translations/en-us";
// Base string with placeholder
export default W.strings = {
welcomeUser: "Welcome, {0}!",
itemsCount: "You have {0} items in your cart",
dateFormat: "Today is {0}",
};
// Helper function for interpolation
function interpolate(str, ...args) {
return str.replace(/{(\d+)}/g, (match, index) => {
return typeof args[index] !== "undefined" ? args[index] : match;
});
}
// Usage
const username = "John";
const message = interpolate(strings.welcomeUser, username);
// Result: "Welcome, John!"
const count = 5;
const cartMessage = interpolate(strings.itemsCount, count);
// Result: "You have 5 items in your cart"
Pluralization Helper
import strings from "./translations/en-us";
export default W.strings = {
item_one: "1 item",
item_other: "{0} items",
};
function pluralize(count, singular, plural) {
return count === 1
? singular.replace("{0}", count)
: plural.replace("{0}", count);
}
// Usage
const count = 5;
const text = pluralize(count, strings.item_one, strings.item_other);
// Result: "5 items"
Date and Number Formatting
import strings from "./translations/en-us";
export default W.strings = {
locale: "en-US",
currency: "USD",
};
function formatCurrency(amount) {
return new Intl.NumberFormat(strings.locale, {
style: "currency",
currency: strings.currency,
}).format(amount);
}
function formatDate(date) {
return new Intl.DateTimeFormat(strings.locale, {
year: "numeric",
month: "long",
day: "numeric",
}).format(date);
}
// Usage
console.log(formatCurrency(99.99)); // "$99.99"
console.log(formatDate(new Date())); // "October 14, 2025"
Re-rendering UI on Language Change
import { changeLang } from "winnetoujs/modules/translations";
import strings from "./translations/en-us";
class App {
constructor() {
this.render();
}
render() {
new $header({
title: strings.appTitle,
}).create("#app", { clear: true });
new $navigation({
home: strings.home,
about: strings.about,
contact: strings.contact,
}).create("#app");
}
changeLanguage(lang) {
changeLang(lang, false);
// Wait a bit for strings to update
setTimeout(() => {
this.render();
}, 100);
}
}
const app = new App();