PHPackages                             bummzack/translatable-dataobject - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. bummzack/translatable-dataobject

ActiveSilverstripe-module

bummzack/translatable-dataobject
================================

Silverstripe Translatable extension for DataObjects

2.1(7y ago)187.0k12[7 issues](https://github.com/bummzack/translatable-dataobject/issues)1MITPHP

Since Jun 2Pushed 7y ago3 watchersCompare

[ Source](https://github.com/bummzack/translatable-dataobject)[ Packagist](https://packagist.org/packages/bummzack/translatable-dataobject)[ Docs](https://github.com/bummzack/translatable-dataobject)[ RSS](/packages/bummzack-translatable-dataobject/feed)WikiDiscussions master Synced 3d ago

READMEChangelog (1)Dependencies (2)Versions (8)Used By (1)

translatable-dataobject
=======================

[](#translatable-dataobject)

An extension for SilverStripe 3.1 that adds translations of fields to DataObjects. Instead of creating new rows for translations, translations are added as columns. This way, there's only one DataObject instance which is consistent across all localizations, but which has localized fields.

This module requires the [translatable module](https://github.com/silverstripe/silverstripe-translatable) to be installed. Credit goes to Uncle Cheese which inspired my with his [TranslatableDataObject](http://www.leftandmain.com/silverstripe-tips/2012/04/03/translatabledataobject-insanely-simple-translation/)

Requirements
------------

[](#requirements)

- [SilverStripe 3.1 or newer](https://docs.silverstripe.org/en/3.2/getting_started/composer/)
- [translatable module](https://github.com/silverstripe/silverstripe-translatable)

Installation
------------

[](#installation)

Use [composer](https://getcomposer.org/):

```
composer require bummzack/translatable-dataobject

```

Alternatively clone/download this repository into a folder in your SilverStripe installation folder.

Usage
-----

[](#usage)

### Defining content locales

[](#defining-content-locales)

The ideal/recommended way to define the locales for the modules is to set the allowed locales for the Translatable module. That way, the available locales are consistent throughout the CMS. Example:

```
Translatable::set_allowed_locales(array('en_US', 'fr_FR', 'de_DE'));
```

If you would like to set the locales for the `translatable-dataobject` module manually/separately, you can specify them via YAML config:

```
# in your mysite/_config/config.yml

TranslatableDataObject:
  locales:
    - en_US
    - fr_FR
```

If both of these calls are being omitted, the module will get the locales from the site content using:

```
Translatable::get_existing_content_languages()
```

Using this setup requires you to run `dev/build` whenever you add a new translation language to the system though.

### Enabling translations

[](#enabling-translations)

To make a DataObject translatable, add the `TranslatableDataObject`extension via YAML config file, like so:

```
# in your mysite/_config/config.yml

MyDataObject:
  extensions:
    - TranslatableDataObject
```

Run `dev/build` afterwards, so that the additional DB fields can be created. By default, all `Varchar`, `Text` and `HTMLText` fields will be translated, while all other fields remain untouched. To alter these default-fields, you can configure them like this:

```
# in your mysite/_config/config.yml

# Translate only 'Varchar' and 'HTMLText' fields per default
TranslatableDataObject:
  default_field_types:
    - Varchar
    - HTMLText
```

If you would like to specify the fields to localize manually, you can add them via `translatable_fields` YAML config:

```
# in your mysite/_config/config.yml
# Example with parameters

MyDataObject:
  extensions:
    - TranslatableDataObject
  translatable_fields:
    - Content
    - Title
```

Alternatively, you can also set the fields to translate in a static field on your DataObject. So inside your `MyDataObject`class you could add something like this:

```
// create translatable fields for 'Title' and 'Content'
private static $translatable_fields = array(
    'Title', 'Content'
);
```

### Translations in the CMS

[](#translations-in-the-cms)

Imagine you have a `TestimonialPage` that `has_many` testimonials and you're managing these Testimonials in a `GridField`.

#### The DataObject (Testimonial)

[](#the-dataobject-testimonial)

Let's start with the `Testimonial` DataObject:

```
class Testimonial extends DataObject
{
    private static $db = array(
        'Title' => 'Varchar',
        'Content' => 'HTMLText'
    );

    private static $has_one = array(
        'TestimonialPage' => 'TestimonialPage'
    );

    private static $extensions = array(
        'TranslatableDataObject'
    );

    private static $translatable_fields = array(
        'Title',
        'Content'
    );
}
```

Most of this should look familiar. We add the `TranslatableDataObject` extension and declare which fields should be translated by setting `translatable_fields`. The very same could also be done via YAML config (see config examples above).

#### The page (TestimonialPage)

[](#the-page-testimonialpage)

Now for the Testimonial-Page:

```
class TestimonialPage extends Page
{
    private static $has_many = array(
        'Testimonials' => 'Testimonial'
    );

    public function getCMSFields()
    {
        $fields = parent::getCMSFields();

        // manage testimonials
        $gridConfig = GridFieldConfig_RelationEditor::create();
        $gridField = new GridField('Testimonials', 'Testimonials', $this->Master()->Testimonials(), $gridConfig);
        $gridField->setModelClass('Testimonial');
        $fields->addFieldsToTab('Root.Testimonials', $gridField);

        return $fields;
    }
}

class TestimonialPage_Controller extends Page_Controller
{

}
```

This looks even more like a regular page and you probably wonder what's so special here. The only thing that changed is that we use `$this->Master()->Testimonials()` instead of `$this->Testimonials()` as the GridField datasource. With this setup, you should be able to switch between different languages in the CMS and edit the testimonials each in the current language. *Give it a try*

#### Forms and ModelAdmin

[](#forms-and-modeladmin)

The `TranslatableDataObject` extension comes with several helper methods that will make it easier for you to build translatable forms for the CMS. The default behavior (if you don't implement `getCMSFields` yourself, also known as scaffolding) is that you'll only see the form fields for the currently active locale, which is ideal if you're working in the *Pages* section of the CMS where you're always working in one language tree. For locales other than the default locale, you'll see the original content as a read-only field below each form-field (same behavior as the translatable module provides for pages).

Of course you can also implement the `getCMSFields` method yourself. Here's an example:

```
public function getCMSFields()
{
    $titleField = new TextField('Title');
    $contentField = new HtmlEditorField('Content');

    // transform the fields if we're not in the default locale
    if(Translatable::default_locale() != Translatable::get_current_locale()) {
        $transformation = new TranslatableFormFieldTransformation($this);
        $titleField = $transformation->transformFormField($titleField);
        $contentField = $transformation->transformFormField($contentField);
    }

    return new FieldList(
        $titleField,
        $contentField
    );
}
```

When we're not in the default locale, we transform the fields using a `TranslatableFormFieldTransformation` instance. This is very similar to what you're probably used to from the translatable module with its `Translatable_Transformation`. What this does is: It takes the given form-field and replaces it's name and content with the translated content. The original content will appear as *read-only* below the form field.

If you wish to get an input field for the current locale, there's a helper method for that called `getLocalizedFormField`. It will automatically create an appropriate input field for the given field name. So if your field is of type `Varchar`, you'll get a `TextField` instance. A `HTMLText` will return a `HtmlEditorField` instance etc.

Example:

```
public function getCMSFields()
{
    // get the current locale
    $locale = Translatable::get_current_locale();

    return new FieldList(
        $this->getLocalizedFormField('Title', $locale),
        $this->getLocalizedFormField('Content', $locale)
    );
}
```

Using the `TranslatableFormFieldTransformation` class or the `getLocalizedFormField` method should provide enough tools to build custom backend forms for most of your needs.

There's another helper method which is especially useful in a `ModelAdmin` context (because in *ModelAdmin* you're not working in one locale as it's the case with the *Pages* section). The helper method is called `getTranslatableTabSet` and will give you a `TabSet` with an individual Tab for every language. Here's how you use it:

```
public function getCMSFields(){
    $fields = new FieldList();
    $fields->add($this->getTranslatableTabSet());
    return $fields;
}
```

Doing this will give you a tab for each language, each tab containing the translatable form fields. If you have fields that aren't being translated, yet still need to be edited via backend, do something along these lines:

```
public function getCMSFields(){
    $fields = new FieldList();
    $fields->add($this->getTranslatableTabSet());

    // add all "Global" fields to another tab
    $fields->addFieldsToTab('Root.Global', array(
        new TextField('NotTranslatedField'),
        new UploadField('MyImage')
        // etc...
    ));

    return $fields;
}
```

### Files and Images

[](#files-and-images)

Usually you'll also want to translate some fields of the file class. Enabling translation is simple by adding the following configuration:

```
# in your mysite/_config/config.yml

# Make 'Title' and 'Content' of Files translatable
File:
  extensions:
    - TranslatableDataObject
    - TranslatedFile
  translatable_fields:
    - Title
    - Content
```

The `TranslatedFile` extension will generate a tab per language within the `Files` Section of the CMS. In addition it adds a helper method (`getUploadEditorFields`) to use when within a locale-context. You can use this to provide translated fields for editing files in a `UploadField`. Here's an example:

```
$imageUpload = UploadField::create('Image');
$imageUpload->setFileEditFields('getUploadEditorFields');
```

### Usage and templates

[](#usage-and-templates)

Whenever you'll have to access your DataObjects, remember to use `$this->Master()->Relation()` instead of `$this->Relation()`.

`Master()` is a handy method in `translatable-dataobject/code/extensions/TranslatableUtility.php`. This extension will automatically be added to each `SiteTree` object with the installation of the translatable-dataobject module. It's a helper-method to get the master-translation of a page and can also be very useful in templates. So if you would like to output all testimonials in a template, you'd use:

```
    $Title
    $Content

        $T(Title)
        $T(Content)

```

Another helpful method to be used in templates is `Languages`. It will return an `ArrayList` with all information you need to build a language-navigation. Drop something like this in your template:

```

        $Language

```

Or you can just include a prepackaged template:

```

```

This will create a list of all available content-languages. The link will point to the translated page or to the home-page of that language if there's no translation in that language.

Todo:
-----

[](#todo)

- CMS UI improvements
- Better integration with existing components such as the GridField
- Better access for relations (eg. get the translated page when getting a has\_one relation)

Limitations
-----------

[](#limitations)

**The module currently only supports translations of DB fields that are part of the `DataObject` itself. Fields that are being added by extensions aren't translatable.**

Since this extension adds more fields to a table, it is important to note that the number of localized fields and the number of languages could cause problems with the underlying database. Imagine a DataObject with 10 localizable fields and a site that will be translated into 5 other languages. This would add 50 columns to the table.

According to the MySQL documentation, the hard-limit of columns for a MySQL table is at `4096`, which should be sufficient for most setups. Other RDBMS might have other limitations though.

###  Health Score

35

—

LowBetter than 79% of packages

Maintenance12

Infrequent updates — may be unmaintained

Popularity29

Limited adoption so far

Community21

Small or concentrated contributor base

Maturity68

Established project with proven stability

 Bus Factor1

Top contributor holds 91.3% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~229 days

Recently: every ~305 days

Total

7

Last Release

2623d ago

Major Versions

1.0.4 → 2.02019-01-17

### Community

Maintainers

![](https://www.gravatar.com/avatar/ace339d9696dfdf9e2f3c6abc212a3abb390b0b51fff48285036b7da8f0be098?d=identicon)[bummzack](/maintainers/bummzack)

---

Top Contributors

[![bummzack](https://avatars.githubusercontent.com/u/1006185?v=4)](https://github.com/bummzack "bummzack (63 commits)")[![dkliemsch](https://avatars.githubusercontent.com/u/13777159?v=4)](https://github.com/dkliemsch "dkliemsch (2 commits)")[![anselmdk](https://avatars.githubusercontent.com/u/1316533?v=4)](https://github.com/anselmdk "anselmdk (1 commits)")[![DrMartinGonzo](https://avatars.githubusercontent.com/u/11061711?v=4)](https://github.com/DrMartinGonzo "DrMartinGonzo (1 commits)")[![welano24](https://avatars.githubusercontent.com/u/94623854?v=4)](https://github.com/welano24 "welano24 (1 commits)")[![wernerkrauss](https://avatars.githubusercontent.com/u/1043925?v=4)](https://github.com/wernerkrauss "wernerkrauss (1 commits)")

---

Tags

silverstripetranslatabledataobject

### Embed Badge

![Health badge](/badges/bummzack-translatable-dataobject/health.svg)

```
[![Health](https://phpackages.com/badges/bummzack-translatable-dataobject/health.svg)](https://phpackages.com/packages/bummzack-translatable-dataobject)
```

###  Alternatives

[tractorcow/silverstripe-fluent

Simple localisation for Silverstripe

92421.6k26](/packages/tractorcow-silverstripe-fluent)[axllent/silverstripe-version-truncator

Automatically delete old versioned Silverstripe records from the database

3673.1k3](/packages/axllent-silverstripe-version-truncator)[g4b0/searchable-dataobjects

This module adds DataObjects to frontend search

254.9k](/packages/g4b0-searchable-dataobjects)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
