Internationalization (i18n)
Design on Web supports multiple languages with a built-in translation system. The editor ships with English and Indonesian locales, and you can add custom locales for any language.
Built-in Locales
Supported Locales
| Name | Type | Default | Description |
|---|---|---|---|
en | locale | — | English (default) |
id | locale | — | Indonesian (Bahasa Indonesia) |
Changing Language
Switch the editor language at runtime using the I18nManager singleton. You also need to update the Zustand store so that React components re-render with the new locale.
import { I18nManager } from '@design-on-web/shared';
// Change to Indonesian
I18nManager.instance.setLocale('id');
// Also update the store so UI re-renders
engine.getStore().getState().setLocale('id');
// Switch back to English
I18nManager.instance.setLocale('en');
engine.getStore().getState().setLocale('en');
// Get current locale
const currentLocale = I18nManager.instance.getLocale();
// Returns: 'en' | 'id'I18nManager.setLocale() and store.setLocale() must be called. The I18nManager handles the actual translation lookup, while the store triggers React re-renders.Adding Custom Locales
Register a custom locale by providing a translation object with all required keys. Missing keys will fall back to the English translation.
import { I18nManager } from '@design-on-web/shared';
// Register a custom locale (French)
I18nManager.instance.registerLocale('fr', {
// Toolbar
'toolbar.select': 'S\u00e9lectionner (V)',
'toolbar.text': 'Texte (T)',
'toolbar.shapes': 'Formes (S)',
'toolbar.draw': 'Dessiner (D)',
'toolbar.image': 'Image (I)',
'toolbar.undo': 'Annuler',
'toolbar.redo': 'R\u00e9tablir',
'toolbar.export': 'Exporter',
'toolbar.zoom_in': 'Zoom avant',
'toolbar.zoom_out': 'Zoom arri\u00e8re',
'toolbar.zoom_fit': 'Ajuster',
'toolbar.zoom_reset': 'R\u00e9initialiser le zoom',
// Panels
'panel.templates': 'Mod\u00e8les',
'panel.elements': '\u00c9l\u00e9ments',
'panel.uploads': 'T\u00e9l\u00e9chargements',
'panel.pages': 'Pages',
'panel.layers': 'Calques',
'panel.properties': 'Propri\u00e9t\u00e9s',
'panel.history': 'Historique',
'panel.draw': 'Dessin',
// Properties
'property.position': 'Position',
'property.size': 'Taille',
'property.rotation': 'Rotation',
'property.opacity': 'Opacit\u00e9',
'property.fill': 'Remplissage',
'property.stroke': 'Contour',
'property.corner_radius': 'Rayon de coin',
'property.font_family': 'Police',
'property.font_size': 'Taille de police',
'property.font_weight': 'Graisse',
'property.text_align': 'Alignement',
'property.line_height': 'Interligne',
'property.char_spacing': 'Espacement',
// ... remaining keys
});
// Activate the new locale
I18nManager.instance.setLocale('fr');
engine.getStore().getState().setLocale('fr');useTranslation Hook
Use the useTranslation hook in custom React components to access the translation function.
import { useTranslation } from '@design-on-web/ui';
function MyCustomPanel() {
const { t, locale } = useTranslation();
return (
<div>
<h3>{t('panel.properties')}</h3>
<label>{t('property.fill')}</label>
<p>Current locale: {locale}</p>
</div>
);
}useTranslation Return Value
| Name | Type | Default | Description |
|---|---|---|---|
t(key) | (key: string) => string | — | Translation function — returns the translated string for the given key |
locale | string | — | Current active locale code |
Translation Keys Reference
The editor uses approximately 150 translation keys organized into these categories:
- Toolbar — ~15 keys for toolbar buttons and tooltips
- Panel titles — ~10 keys for sidebar panel headings
- Property labels — ~25 keys for the property panel
- Layer panel — ~10 keys for layer actions
- Export dialog — ~15 keys for export UI
- Drawing — ~8 keys for the draw panel
- Common actions — ~15 keys for shared UI strings
- Version history — ~8 keys for the history panel
- Templates — ~6 keys for the template panel
// Translation keys are organized by category:
// Toolbar (~15 keys)
'toolbar.select' // "Select (V)"
'toolbar.text' // "Text (T)"
'toolbar.shapes' // "Shapes (S)"
'toolbar.draw' // "Draw (D)"
'toolbar.image' // "Image (I)"
'toolbar.undo' // "Undo"
'toolbar.redo' // "Redo"
'toolbar.export' // "Export"
'toolbar.zoom_in' // "Zoom In"
'toolbar.zoom_out' // "Zoom Out"
'toolbar.zoom_fit' // "Fit to Screen"
'toolbar.zoom_reset' // "Reset Zoom"
'toolbar.delete' // "Delete"
'toolbar.duplicate' // "Duplicate"
'toolbar.language' // "Language"
// Panel titles (~10 keys)
'panel.templates' // "Templates"
'panel.elements' // "Elements"
'panel.uploads' // "Uploads"
'panel.pages' // "Pages"
'panel.layers' // "Layers"
'panel.properties' // "Properties"
'panel.history' // "History"
'panel.draw' // "Draw"
'panel.icons' // "Icons"
'panel.text' // "Text"
// Property labels (~25 keys)
'property.position' // "Position"
'property.size' // "Size"
'property.rotation' // "Rotation"
'property.opacity' // "Opacity"
'property.fill' // "Fill"
'property.fill_type' // "Fill Type"
'property.stroke' // "Stroke"
'property.stroke_width' // "Stroke Width"
'property.corner_radius' // "Corner Radius"
'property.font_family' // "Font Family"
'property.font_size' // "Font Size"
'property.font_weight' // "Font Weight"
'property.font_style' // "Font Style"
'property.text_align' // "Text Align"
'property.line_height' // "Line Height"
'property.char_spacing' // "Character Spacing"
'property.shadow' // "Shadow"
'property.outline' // "Outline"
'property.decoration' // "Decoration"
'property.gradient_angle' // "Gradient Angle"
'property.gradient_type' // "Gradient Type"
// Layer panel (~10 keys)
'layer.lock' // "Lock"
'layer.unlock' // "Unlock"
'layer.hide' // "Hide"
'layer.show' // "Show"
'layer.rename' // "Rename"
'layer.delete' // "Delete"
'layer.bring_forward' // "Bring Forward"
'layer.send_backward' // "Send Backward"
'layer.bring_to_front' // "Bring to Front"
'layer.send_to_back' // "Send to Back"
// Export dialog (~15 keys)
'export.title' // "Export"
'export.format' // "Format"
'export.quality' // "Quality"
'export.resolution' // "Resolution"
'export.transparent' // "Transparent Background"
'export.all_pages' // "All Pages"
'export.current_page' // "Current Page"
'export.download' // "Download"
'export.cancel' // "Cancel"
// Drawing (~8 keys)
'draw.brush_type' // "Brush Type"
'draw.pencil' // "Pencil"
'draw.spray' // "Spray"
'draw.circle' // "Circle"
'draw.brush_size' // "Brush Size"
'draw.brush_color' // "Brush Color"
'draw.brush_opacity' // "Brush Opacity"
// Common actions (~15 keys)
'action.save' // "Save"
'action.cancel' // "Cancel"
'action.apply' // "Apply"
'action.delete' // "Delete"
'action.duplicate' // "Duplicate"
'action.add_page' // "Add Page"
'action.delete_page' // "Delete Page"
'action.search' // "Search"
'action.no_results' // "No results found"
'action.loading' // "Loading..."
'action.confirm' // "Are you sure?"
// Version history (~8 keys)
'history.save_version' // "Save Version"
'history.restore' // "Restore"
'history.preview' // "Preview"
'history.apply' // "Apply"
'history.cancel_preview' // "Cancel Preview"
'history.delete' // "Delete"
'history.rename' // "Rename"
'history.max_reached' // "Maximum snapshots reached"
// Templates (~6 keys)
'template.apply' // "Apply Template"
'template.save_as' // "Save as Template"
'template.all' // "All"
'template.search' // "Search templates..."
'template.confirm_apply' // "This will replace current content. Continue?"
'template.name' // "Template Name"UI: Language Selector
The toolbar includes a language selector dropdown (globe icon) that lets users switch between registered locales at runtime. The entire editor UI updates immediately without a page reload.
I18nManager.setLocale()programmatically instead.