Locales
Locales define translations used by the OpenSya backend runtime.
They allow applications and modules to add new translation keys, override existing translations and support additional languages.
OpenSya automatically discovers locale files from the server/locales directory and merges them with the native runtime translations.
Filesystem Structure
Locale files are placed inside the server/locales directory.
server/locales/
├── fr/
│ └── common.json
└── en/
└── common.json
Each language has its own directory.
Each JSON file represents a translation namespace.
Adding Translations
You can add new translations by creating a JSON file inside a language directory.
{
"candidate": {
"created": "Candidat créé avec succès",
"not_found": "Candidat introuvable"
}
}
The translations are automatically loaded by the runtime.
Merging With Native Translations
OpenSya includes native translation files.
When you create a locale file with the same language and filename as a native locale, OpenSya merges your file with the native one.
Example:
server/locales/fr/common.json
+
native fr/common.json
↓
merged fr/common.json
This allows you to add or override specific translation keys without replacing the entire native translation file.
Overriding Existing Translations
You can override an existing translation by declaring the same key in your project locale file.
{
"session": {
"errors": {
"not_authorized": "Vous n'êtes pas autorisé à effectuer cette action."
}
}
}
If the key already exists in the native fr/common.json, your project value takes precedence.
Adding a New Language
You can add a new language by creating a new language directory.
server/locales/
└── wo/
└── common.json
Example:
{
"session": {
"errors": {
"not_authorized": "Amoo sañ-sañ ci jëf jii."
}
}
}
If the language does not exist natively, OpenSya creates and registers it during runtime initialization.
Namespaces
The filename represents the translation namespace.
server/locales/fr/common.json → common
server/locales/fr/session.json → session
server/locales/fr/errors.json → errors
Example:
{
"errors": {
"expired": "Votre session a expiré."
}
}
The namespace helps organize translations by domain.
Using Translations
Translations can be accessed using useTranslate() or $t.
Using useTranslate()
const t = useTranslate();
throw new Error(t('session.errors.not_authorized'));
Using $t
export default defineGuard(({ controllerOptions, request }) => {
if (!controllerOptions.roles) return;
if (!controllerOptions.roles.includes(request._user?.role)) {
return {
pass: false,
errorMessage: $t('session.errors.not_authorized'),
};
}
});
Both helpers resolve translations from the runtime i18n registry.
Common Use Cases
Locales are useful for:
| Use Case | Description |
|---|---|
Runtime errors | Translate errors returned by guards, services or controllers. |
Validation messages | Provide localized validation feedback. |
Module translations | Allow modules to expose their own translations. |
Native overrides | Customize built-in OpenSya messages. |
Runtime Discovery
During startup, OpenSya automatically:
- Discovers locale directories
- Loads JSON translation files
- Merges project locales with native locales
- Registers new languages
- Makes translations available through
useTranslate()and$t
Filesystem Discovery
↓
Locale Loading
↓
Native Locale Merge
↓
Language Registration
↓
Runtime Translation
Best Practices
Use clear and stable translation keys.
Prefer domain-based namespaces and nested keys.
{
"candidate": {
"errors": {
"not_found": "Candidate not found"
},
"messages": {
"created": "Candidate created successfully"
}
}
}
Avoid using long sentences as translation keys.
{
"Candidate was not found in the database": "Candidate was not found in the database"
}
Philosophy
Locales are part of the OpenSya runtime customization layer.
They allow recruitment and business platforms to adapt messages, errors and module text without modifying native runtime code.
This keeps applications customizable while preserving a clean and modular architecture.