Translation System
MMO-DEV WEB uses a translation system based on Symfony Translation with ICU MessageFormat support.
The |trans filter
Basic usage
Basic usage
{{ 'Welcome'|trans }}
{# Looks up the translation in the default domain (messages) #}
{{ 'site.welcome_message'|trans }}
Specifying a domain
Specifying a domain
{{ 'login.title'|trans({}, 'user') }}
{# Looks up the translation in the "user" domain #}
{{ 'nav.home'|trans({}, 'navigation') }}
{{ 'market.buy_button'|trans({}, 'market') }}
Substitution parameters
Substitution parameters
{{ 'Hello, %name%!'|trans({'%name%': user.name}) }}
{{ 'You have %count% messages'|trans({'%count%': count}, 'cabinet') }}
Translation file structure
Translation files are located in the Language/ directory:
Available domains
| Domain | Description |
|---|---|
common | Common phrases (buttons, statuses, errors) |
site | Main site texts |
user | Authentication, registration, profile |
cabinet | User dashboard |
admin | Admin panel |
navigation | Navigation menu |
market | Game store |
forum | Forum |
news | News |
tickets | Ticket system |
Translation file format
Each translation file is a PHP file that returns an array:
// Language/en/common.php
return [
'save' => 'Save',
'cancel' => 'Cancel',
'delete' => 'Delete',
'edit' => 'Edit',
'loading' => 'Loading...',
'error.not_found' => 'Not Found',
'error.access_denied' => 'Access Denied',
'status.active' => 'Active',
'status.inactive' => 'Inactive',
];
// Language/en/common.php
return [
'save' => 'Save',
'cancel' => 'Cancel',
'delete' => 'Delete',
'edit' => 'Edit',
'loading' => 'Loading...',
'error.not_found' => 'Not Found',
'error.access_denied' => 'Access Denied',
'status.active' => 'Active',
'status.inactive' => 'Inactive',
];
ICU MessageFormat
ICU MessageFormat is used for complex translations.
Plurals
// Language/en/cabinet.php
return [
'messages_count' => '{count, plural,
one {# message}
other {# messages}
}',
];
Plurals
{{ 'messages_count'|trans({count: 1}, 'cabinet') }}
{# 1 message #}
{{ 'messages_count'|trans({count: 3}, 'cabinet') }}
{# 3 messages #}
{{ 'messages_count'|trans({count: 5}, 'cabinet') }}
{# 5 messages #}
Gender
return [
'user_action' => '{gender, select,
male {He updated the profile}
female {She updated the profile}
other {The profile was updated}
}',
];
Gender
{{ 'user_action'|trans({gender: user.gender}, 'user') }}
Ordinal numbers
return [
'place' => '{place, selectordinal,
one {#st place}
two {#nd place}
few {#rd place}
other {#th place}
}',
];
Combining patterns
return [
'welcome' => '{gender, select,
male {Dear {name}, you have {count, plural,
one {# new notification}
other {# new notifications}
}}
female {Dear {name}, you have {count, plural,
one {# new notification}
other {# new notifications}
}}
other {Hello, {name}! You have {count, plural,
one {# new notification}
other {# new notifications}
}}
}',
];
Combining patterns
{{ 'welcome'|trans({
gender: user.gender,
name: user.name,
count: notifications|length
}, 'site') }}
Fallback locales
If a translation is not found in the current locale, the system looks for it in the fallback locale:
Request: de -> Fallback: en -> Fallback: ru
Lookup order:
- Current locale (
de) - First fallback (
en) - Primary fallback (
ru) - Translation key as-is
Usage in JavaScript
Translations can be passed to JavaScript via data attributes or a global object:
Usage in JavaScript
<div data-confirm="{{ 'Are you sure?'|trans({}, 'common') }}">
<script>
const translations = {{ {
save: 'save'|trans({}, 'common'),
cancel: 'cancel'|trans({}, 'common'),
confirm: 'confirm'|trans({}, 'common')
}|json_encode|raw }};
</script>