Translatable
class Translatable extends DataExtension implements PermissionProvider (View source)
The Translatable decorator allows your DataObjects to have versions in different languages, defining which fields are can be translated. Translatable can be applied to any DataObject} subclass, but is mostly used with {@link SiteTree.
Translatable is compatible with the Versioned extension. To avoid cluttering up the database-schema of the 99% of sites without multiple languages, the translation-feature is disabled by default.
Locales (e.g. 'en_US') are used in Translatable for identifying a record by language, see section "Locales and Language Tags".
Configuration
The extension is automatically enabled for SiteTree and SiteConfig records, if they can be found. Add the following to your config.yml in order to register a custom class:
MyClass:
extensions:
Translatable
Make sure to rebuild the database through /dev/build after enabling translatable. Use the correct set_default_locale() before building the database for the first time, as this locale will be written on all new records.
"Default" locales
Important: If the "default language" of your site is not US-English (en_US), please ensure to set the appropriate default language for your content before building the database with Translatable enabled:
Translatable::set_default_locale(<locale>); // e.g. 'de_DE' or 'fr_FR'
For the Translatable class, a "locale" consists of a language code plus a region code separated by an underscore, for example "de_AT" for German language ("de") in the region Austria ("AT"). See http://www.w3.org/International/articles/language-tags/ for a detailed description.
Usage
Getting a translation for an existing instance:
$translatedObj = Translatable::get_one_by_locale('MyObject', 'de_DE');
Getting a translation for an existing instance:
$obj = DataObject::get_by_id('MyObject', 99); // original language
$translatedObj = $obj->getTranslation('de_DE');
Getting translations through Translatable::set_current_locale(). This is not a recommended approach, but sometimes inavoidable (e.g. for Versioned methods).
$origLocale = Translatable::get_current_locale();
Translatable::set_current_locale('de_DE');
$obj = Versioned::get_one_by_stage('MyObject', "ID = 99");
Translatable::set_current_locale($origLocale);
Creating a translation:
$obj = new MyObject();
$translatedObj = $obj->createTranslation('de_DE');
Usage for SiteTree
Translatable can be used for subclasses of SiteTree, it is automatically configured if this class is foun.
If a child page translation is requested without the parent page already having a translation in this language, the extension will recursively create translations up the tree. Caution: The "URLSegment" property is enforced to be unique across languages by auto-appending the language code at the end. You'll need to ensure that the appropriate "reading language" is set before showing links to other pages on a website through $_GET['locale']. Pages in different languages can have different publication states through the Versioned extension.
Note: You can't get Children() for a parent page in a different language through set_current_locale(). Get the translated parent first.
// wrong
Translatable::set_current_locale('de_DE');
$englishParent->Children();
// right
$germanParent = $englishParent->getTranslation('de_DE');
$germanParent->Children();
Translation groups
Each translation can have one or more related pages in other languages. This relation is optional, meaning you can create translations which have no representation in the "default language". This means you can have a french translation with a german original, without either of them having a representation in the default english language tree. Caution: There is no versioning for translation groups, meaning associating an object with a group will affect both stage and live records.
SiteTree database table (abbreviated) ^ ID ^ URLSegment ^ Title ^ Locale ^ | 1 | about-us | About us | en_US | | 2 | ueber-uns | Über uns | de_DE | | 3 | contact | Contact | en_US |
SiteTree_translationgroups database table ^ TranslationGroupID ^ OriginalID ^ | 99 | 1 | | 99 | 2 | | 199 | 3 |
Character Sets
Caution: Does not apply any character-set conversion, it is assumed that all content is stored and represented in UTF-8 (Unicode). Please make sure your database and HTML-templates adjust to this.
Permissions
Authors without administrative access need special permissions to edit locales other than the default locale.
- TRANSLATE_ALL: Translate into all locales
- Translate_
: Translate a specific locale. Only available for all locales set in Translatable::set_allowed_locales()
.
Note: If user-specific view permissions are required, please overload SiteTree->canView()
.
Uninstalling/Disabling
Disabling Translatable after creating translations will lead to all pages being shown in the default sitetree regardless of their language. It is advised to start with a new database after uninstalling Translatable, or manually filter out translated objects through their "Locale" property in the database.
Constants
QUERY_LOCALE_FILTER_ENABLED |
|
Properties
protected | SS_Object | $owner | The object this extension is applied to. |
from Extension |
protected | DataObject | $ownerBaseClass | The base class that this extension was applied to; $this->owner must be one of these |
from Extension |
public | $class | from Extension | ||
protected static | string | $default_locale | The 'default' language. |
|
protected static | string | $current_locale | The language in which we are reading dataobjects. |
|
protected static | mixed | $tableList | A cached list of existing tables |
|
protected | array | $translatableFields | An array of fields that can be translated. |
|
protected | array | $original_values | A map of the field values of the original (untranslated) DataObject record |
|
protected static | bool | $locale_filter_enabled | If this is set to TRUE then augmentSQL() will automatically add a filter clause to limit queries to the current get_current_locale(). This camn be disabled using disable_locale_filter() |
|
protected static | array | $allowed_locales | ||
public static | bool | $enable_siteconfig_generation | Enables automatic population of SiteConfig fields using createTranslation if created outside of the Translatable module |
Methods
Called when this extension is added to a particular class
Helper method to strip eval'ed arguments from a string thats passed to DataObject::$extensions or Object::add_extension().
Changes any SELECT query thats not filtering on an ID to limit by the current language defined in get_current_locale().
Create
_translation database table to enable tracking of "translation groups" in which each related translation of an object acts as a sibling, rather than a parent->child relation.Recursively creates translations for parent pages in this language if they aren't existing already. This is a necessity to make nested pages accessible in a translated CMS page tree.
Define extra database fields
If the record is not shown in the default language, this method will try to autoselect a master language which is shown alongside the normal formfields as a readonly representation.
This function is used to provide modifications to the form used for front end forms. DataObject->getFrontEndFields()
This is used to provide modifications to the form actions used in the CMS. DataObject->getCMSActions().
this function is used to provide modifications to the summary fields in CMS by the extension By default, the summaryField() of its owner will merge more fields defined in the extension's $extra_fields['summary_fields']
this function is used to provide modifications to the fields labels in CMS by the extension By default, the fieldLabels() of its owner will merge more fields defined in the extension's $extra_fields['field_labels']
Choose the language the site is currently on.
Set default language. Please set this value before creating any database records (like pages), as this locale will be attached to all new records.
Set the reading language, either namespaced to 'site' (website content) or 'cms' (management backend). This value is used in augmentSQL() to "auto-filter" all SELECT queries by this language.
Get a singleton instance of a class in the given language.
Get all the instances of the given class translated to the given language
Enables automatic filtering by locale. This is normally called after is has been disabled using disable_locale_filter().
Disables automatic locale filtering in augmentSQL(). This can be re-enabled using enable_locale_filter().
Gets all locales that a member can access as defined by $allowed_locales and canTranslate().
Get a list of languages in which a given element has been translated.
Add a record to a "translation group", so its relationship to other translations based off the same object can be determined later on.
Determine if a table needs Versioned support This is called at db/build time
Note: The bulk of logic is in ModelAsController->getNestedController() and ContentController->handleRequest()
Attempt to get the page for a link in the default language that has been translated.
This method can be called multiple times on the same FieldList because it checks which fields have already been added or modified.
Get the names of all translatable fields on this class as a numeric array.
Return the base table - the class that directly extends DataObject.
Gets all related translations for the current object, excluding itself. See getTranslation() to retrieve a single translated object.
Gets an existing translation based on the language code.
When the SiteConfig object is automatically instantiated, we should ensure that
- All SiteConfig objects belong to the same group
- Defaults are correctly initiated from the base object
- The creation mechanism uses the createTranslation function in order to be consistent This function ensures that any already created "vanilla" SiteConfig object is populated correctly with translated values.
Creates a new translation for the owner object of this decorator.
Caution: Does not consider the canEdit() permissions.
Returns TRUE if the current record has a translation in this language.
Returns markup for insertion into a HTML4/XHTML compliant section, listing all available translations of a page.
Return a map of permission codes to add to the dropdown shown in the Security section of the CMS.
Get a list of languages with at least one element translated in (including the default language)
Get the RelativeLink value for a home page in another locale. This is found by searching for the default home page in the default language, then returning the link to the translated version (if one exists).
Define all locales which in which a new translation is allowed.
Get all locales which are generally permitted to be translated.
No description
No description
Determines if the record has a locale, and if this locale is different from the "default locale" set in Translatable::default_locale().
Return a piece of text to keep DataObject cache keys appropriately specific
Extends the SiteTree::validURLSegment() method, to do checks appropriate to Translatable
Details
__construct($translatableFields = null)
Construct a new Translatable object.
$translatableFields |
static
add_to_class(string $class, string $extensionClass, mixed $args = null)
Called when this extension is added to a particular class
setOwner(SS_Object $owner, string $ownerBaseClass = null)
Set the owner of this extension.
clearOwner()
No description
SS_Object
getOwner()
Returns the owner of this extension.
static string
get_classname_without_arguments(string $extensionStr)
Helper method to strip eval'ed arguments from a string thats passed to DataObject::$extensions or Object::add_extension().
static
get_extra_config($class, $extensionClass, $args = null)
No description
static
unload_extra_statics($class, $extension)
No description
validate(ValidationResult $validationResult)
Hook for extension-specific validation.
augmentSQL(SQLQuery $query, DataQuery $dataQuery = null)
Changes any SELECT query thats not filtering on an ID to limit by the current language defined in get_current_locale().
It falls back to "Locale='' OR Lang IS NULL" and assumes that this implies querying for the default language.
Use disable_locale_filter() to temporarily disable this "auto-filtering".
augmentDatabase()
Create
_translation database table to enable tracking of "translation groups" in which each related translation of an object acts as a sibling, rather than a parent->child relation.
augmentWrite(array $manipulation)
Augment a write-record request.
array | $manipulation | Array of operations to augment. |
onBeforeWrite()
Recursively creates translations for parent pages in this language if they aren't existing already. This is a necessity to make nested pages accessible in a translated CMS page tree.
It would be more userfriendly to grey out untranslated pages, but this involves complicated special cases in AllChildrenIncludingDeleted().
SiteTree->onBeforeWrite() will ensure that each translation will get a unique URL across languages, by means of SiteTree::get_by_link() and Translatable->alternateGetByURL().
onAfterWrite()
No description
onBeforeDelete()
Remove the record from the translation group mapping.
onAfterDelete()
No description
requireDefaultRecords()
No description
Find more appropriate place to hook into database building
populateDefaults()
Hooks into the DataObject::populateDefaults() method
can($member)
No description
canEdit($member)
No description
canDelete($member)
No description
canCreate($member)
No description
array
extraStatics($class = null, $extension = null)
Define extra database fields
Return a map where the keys are db, has_one, etc, and the values are additional fields/relations to be defined.
updateCMSFields(FieldList $fields)
If the record is not shown in the default language, this method will try to autoselect a master language which is shown alongside the normal formfields as a readonly representation.
This gives translators a powerful tool for their translation workflow without leaving the translated page interface. Translatable also adds a new tab "Translation" which shows existing translations, as well as a formaction to create new translations based on a dropdown with available languages.
This method can be called multiple times on the same FieldList because it checks which fields have already been added or modified.
This is specific to SiteTree and CMSMain Implement a special "translation mode" which triggers display of the readonly fields, so you can translation INTO the "default language" while seeing readonly fields as well.
updateFrontEndFields(FieldList $fields)
This function is used to provide modifications to the form used for front end forms. DataObject->getFrontEndFields()
Caution: Use FieldList->push() to add fields.
updateCMSActions(FieldList $actions)
This is used to provide modifications to the form actions used in the CMS. DataObject->getCMSActions().
updateSummaryFields(array $fields)
this function is used to provide modifications to the summary fields in CMS by the extension By default, the summaryField() of its owner will merge more fields defined in the extension's $extra_fields['summary_fields']
updateFieldLabels(array $labels)
this function is used to provide modifications to the fields labels in CMS by the extension By default, the fieldLabels() of its owner will merge more fields defined in the extension's $extra_fields['field_labels']
static
reset()
Reset static configuration variables to their default values
static string
choose_site_locale($langsAvailable = array())
Choose the language the site is currently on.
If $_GET['locale'] is currently set, then that locale will be used. Otherwise the member preference (if logged in) or default locale will be used.
Re-implement cookie and member option
static string
default_locale()
Get the current reading language.
This value has to be set before the schema is built with translatable enabled, any changes after this can cause unintended side-effects.
static
set_default_locale($locale)
Set default language. Please set this value before creating any database records (like pages), as this locale will be attached to all new records.
static string
get_current_locale()
Get the current reading language.
If its not chosen, call choose_site_locale().
static
set_current_locale($locale)
Set the reading language, either namespaced to 'site' (website content) or 'cms' (management backend). This value is used in augmentSQL() to "auto-filter" all SELECT queries by this language.
See disable_locale_filter() on how to override this behaviour temporarily.
static DataObject
get_one_by_locale(string $class, string $locale, string $filter = '', bool $cache = false, string $orderby = "")
Get a singleton instance of a class in the given language.
static mixed
get_by_locale(string $class, string $locale, string $filter = '', string $sort = '', string $join = "", string $limit = "")
Get all the instances of the given class translated to the given language
static bool
locale_filter_enabled()
No description
static
enable_locale_filter($enabled = true)
Enables automatic filtering by locale. This is normally called after is has been disabled using disable_locale_filter().
static bool
disable_locale_filter()
Disables automatic locale filtering in augmentSQL(). This can be re-enabled using enable_locale_filter().
Note that all places that disable the locale filter should generally re-enable it before returning from that block of code (function, etc). This is made easier by using the following pattern:
$enabled = Translatable::disable_locale_filter();
// do some work here
Translatable::enable_locale_filter($enabled);
return $whateverYouNeedTO;
By using this pattern, the call to enable the filter will not re-enable it if it was not enabled initially. That will keep code that called your function from breaking if it had already disabled the locale filter since it will not expect calling your function to change the global state by re-enabling the filter.
array
getTranslatedLocales()
Gets all translations for this specific page.
Doesn't include the language of the current record.
array
getAllowedLocalesForMember(Member $member)
Gets all locales that a member can access as defined by $allowed_locales and canTranslate().
If $allowed_locales is not set and
the user has the TRANSLATE_ALL
permission,
the method will return all available locales in the system.
static array
get_langs_by_id(string $class, int $id)
deprecated
deprecated 2.4 Use {@link getTranslations()}
Get a list of languages in which a given element has been translated.
static
enable()
deprecated
deprecated 2.4 Use SiteTree::add_extension('Translatable')
Enables the multilingual feature
static
disable()
deprecated
deprecated 2.4 Use SiteTree::remove_extension('Translatable')
Disable the multilingual feature
static bool
is_enabled()
deprecated
deprecated 2.4 Use SiteTree::has_extension('Translatable')
Check whether multilingual support has been enabled
protected bool
filtersOnLocale(SQLQuery $query)
Check if a given SQLQuery filters on the Locale field
addTranslationGroup(int $originalID, bool $overwrite = false)
Add a record to a "translation group", so its relationship to other translations based off the same object can be determined later on.
See class header for further comments.
int
getTranslationGroup()
Gets the translation group for the current record.
This ID might equal the record ID, but doesn't have to - it just points to one "original" record in the list.
removeTranslationGroup()
Removes a record from the translation group lookup table.
Makes no assumptions on other records in the group - meaning if this happens to be the last record assigned to the group, this group ceases to exist.
bool
isVersionedTable(string $table)
Determine if a table needs Versioned support This is called at db/build time
contentcontrollerInit($controller)
Note: The bulk of logic is in ModelAsController->getNestedController() and ContentController->handleRequest()
modelascontrollerInit($controller)
No description
initgetEditForm($controller)
No description
SiteTree
alternateGetByLink(string $URLSegment, int|null $parentID)
Attempt to get the page for a link in the default language that has been translated.
applyTranslatableFieldsUpdate($fields, $type)
No description
updateSettingsFields($fields)
No description
updateRelativeLink($base, $action)
No description
protected
addTranslatableFields($fields)
This method can be called multiple times on the same FieldList because it checks which fields have already been added or modified.
array
getTranslatableFields()
Get the names of all translatable fields on this class as a numeric array.
Integrate with blacklist once branches/translatable is merged back.
string
baseTable($stage = null)
Return the base table - the class that directly extends DataObject.
extendWithSuffix($table)
No description
DataObjectSet
getTranslations(string $locale = null, string $stage = null)
DataObject
getTranslation(string $locale, $stage = null)
Gets an existing translation based on the language code.
Use hasTranslation() as a quicker alternative to check for an existing translation without getting the actual object.
protected
populateSiteConfigDefaults()
When the SiteConfig object is automatically instantiated, we should ensure that
- All SiteConfig objects belong to the same group
- Defaults are correctly initiated from the base object
- The creation mechanism uses the createTranslation function in order to be consistent This function ensures that any already created "vanilla" SiteConfig object is populated correctly with translated values.
This function DOES populate the ID field with the newly created object ID
DataObject
createTranslation(string $locale, bool $saveTranslation = true)
Creates a new translation for the owner object of this decorator.
Checks getTranslation() to return an existing translation instead of creating a duplicate. Writes the record to the database before returning it. Use this method if you want the "translation group" mechanism to work, meaning that an object knows which group of translations it belongs to. For "original records" which are not created through this method, the "translation group" is set in onAfterWrite().
bool
canTranslate(DataObject|int $member = null, string $locale)
Caution: Does not consider the canEdit() permissions.
bool
hasTranslation(string $locale)
Returns TRUE if the current record has a translation in this language.
Use getTranslation() to get the actual translated record from the database.
AllChildrenIncludingDeleted($context = null)
No description
string
MetaTags($tags)
Returns markup for insertion into a HTML4/XHTML compliant section, listing all available translations of a page.
providePermissions()
Return a map of permission codes to add to the dropdown shown in the Security section of the CMS.
array( 'VIEW_SITE' => 'View the site', );
static array
get_existing_content_languages(string $className = 'SiteTree', string $where = '')
Get a list of languages with at least one element translated in (including the default language)
static string
get_homepage_link_by_locale($locale)
Get the RelativeLink value for a home page in another locale. This is found by searching for the default home page in the default language, then returning the link to the translated version (if one exists).
static
get_homepage_urlsegment_by_locale($locale)
deprecated
deprecated 2.4 Use {@link Translatable::get_homepage_link_by_locale()}
No description
static
set_allowed_locales($locales)
Define all locales which in which a new translation is allowed.
Checked in canTranslate().
static array
get_allowed_locales()
Get all locales which are generally permitted to be translated.
Use canTranslate() to check if a specific member has permission to translate a record.
static
get_homepage_urlsegment_by_language($locale)
deprecated
deprecated 2.4 Use get_homepage_urlsegment_by_locale()
No description
static
is_default_lang()
deprecated
deprecated 2.4 Use custom check: self::$default_locale == self::get_current_locale()
No description
static
set_default_lang($lang)
deprecated
deprecated 2.4 Use set_default_locale()
No description
static
get_default_lang()
deprecated
deprecated 2.4 Use get_default_locale()
No description
static
current_lang()
deprecated
deprecated 2.4 Use get_current_locale()
No description
static
set_reading_lang($lang)
deprecated
deprecated 2.4 Use set_current_locale()
No description
static
get_reading_lang()
deprecated
deprecated 2.4 Use get_reading_locale()
No description
static
default_lang()
deprecated
deprecated 2.4 Use default_locale()
No description
static
get_by_lang($class, $lang, $filter = '', $sort = '', $join = "", $limit = "", $containerClass = "DataObjectSet", $having = "")
deprecated
deprecated 2.4 Use get_by_locale()
No description
static
get_one_by_lang($class, $lang, $filter = '', $cache = false, $orderby = "")
deprecated
deprecated 2.4 Use get_one_by_locale()
No description
bool
isTranslation()
deprecated
deprecated 2.4
Determines if the record has a locale, and if this locale is different from the "default locale" set in Translatable::default_locale().
Does not look at translation groups to see if the record is based on another record.
static
choose_site_lang($langsAvail = null)
deprecated
deprecated 2.4 Use choose_site_locale()
No description
getTranslatedLangs()
deprecated
deprecated 2.4 Use getTranslatedLocales()
No description
cacheKeyComponent()
Return a piece of text to keep DataObject cache keys appropriately specific
bool
augmentValidURLSegment()
Extends the SiteTree::validURLSegment() method, to do checks appropriate to Translatable