Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

We've moved the forum!

Please use forum.silverstripe.org for any new questions (announcement).
The forum archive will stick around, but will be read only.

You can also use our Slack channel or StackOverflow to ask for help.
Check out our community overview for more options to contribute.

Data Model Questions /

Moderators: martimiz, Sean, Ed, biapar, Willr, Ingo, swaiba

DataObject partial translation


Go to End


1348 Views

Avatar
dreadman

Community Member, 1 Post

24 December 2011 at 5:15am

Edited: 24/12/2011 5:19am

hey there,

I'm working on a small Google Maps project at the moment. This involves a lot of DataObjects representing markers on my map. Of course by translating the page in other languages the coordinates of my markers stay the same. So I figured out an imo simple way for an universal method for the partial translation of my DataObjects. There are still some small problems, but for now I just want to know what you guys think about it and what could be done better. I'm far away from being a pro, so there will be space for improvements, thats for sure ;)

Right, here is what I did.

At first I created an basic object which holds the language and the relationship to the DataObject, that will be partly translatable.

class TranslatedObjectPart extends DataObject
{
    static $db = array (
        'Lang' => 'Varchar(10)'
    );

    static $has_one = array (
        'TranslatableDataObject' => 'TranslatableDataObject'
    );

    public function getCMSFields() {
        $allowedLang = Translatable::get_allowed_locales();
        if (empty($allowedLang))
            $allowedLang[] = i18n::default_locale ();
        $langs = array_combine($allowedLang, $allowedLang);
        
        return new FieldSet(
            new DropdownField('Lang', 'Sprache', $langs)
        );
    }
}

Then I have an object, which actually holds one (or possibly more) parts, which can be created in every language you get from Translatable::get_allowed_locales(). The thing I like is that basicly you can translate any data type, not only text. For example you could add a has_one relation to an Image or any other DataObject. I hope you know, what I mean ;)

class TranslatedText extends TranslatedObjectPart
{
    static $db = array (
        'Text' => 'Text'
    );

    public function getCMSFields() {
        $f = parent::getCMSFields();
        $f->insertAfter(new TextareaField('Text'), "Lang");
        return $f;
    }
}

After that I made a base class for any DataObject, which should be partially translated. This class is very simple, it just deletes all of it8s (partial) translations before it gets deleted.

class TranslatableDataObject extends DataObject {
    function onBeforeDelete() {
        parent::onBeforeDelete();
        $translations = DataObject::get("TranslatedObjectPart", "TranslatableDataObjectID = $this->ID");
        foreach ($translations->toArray() as $tran)
            $tran->delete();
    }
}

Finally, my object which gets translated. I was surprised that you can insert a DataObjectManager into a popup, which itself ist opened by a DOM from a Page, but it works :) Now I can add translations for the Title, while the rest stays the same. Using TitleInCurrentLang() I get the translation of the Title or the normal Title as fallback.

class MyDataObject extends TranslatableDataObject
{
    static $db = array (
        'Title' => 'Text',
        'CenterLat' => 'Double',
        'CenterLng' => 'Double',
	'MapZoom' => 'Int'
    );

    static $has_many = array (
        'TranslatedTitle' => 'TranslatedText'
    );

    public function getCMSFields() {        
        return new FieldSet(
            new TextField('Title','Titel'),
            new DataObjectManager(
                $this, // Controller
                'TranslatedTitle', // Source name
                'TranslatedText', // Source class
                array(
                    'Text' => 'Titel',
                    'Lang' => 'Sprache'
                ),
                'getCMSFields()'
            ),
            new NumericField('CenterLat', 'Breitengrad des Mittepunkts (zB 50.12345)', 0.00000),
            new NumericField('CenterLng', 'Längengrad  des Mittepunkts (zB 11.12345)', 0.00000),
            new NumericField('MapZoom', 'Zoomstufe der Karte', 2)
        );
    }
    
    function TitleInCurrentLang(){
        $lang = Translatable::get_current_locale();
        $title = DataObject::get_one("TranslatedText", "TranslatableDataObjectID = $this->ID AND Lang = '$lang'");
        if ($title)
            return $title->Text;
        return $this->ViewTitle;
    }    
}

However, there are some little drawbacks with this approach. The popup in the popup is opened at the bottom (not really a problem). And because of the filter in the DataObject::get_one() call inside TitleInCurrentLang() I can only have one TranslatedText per TranslatableDataObject, in more general terms only one object extending TranslatedObjectPart of the same class per TranslatableDataObject. I have some small ideas to work this out...and maybe you guys can give me a push in the right direction? ;)

Anyway, thats it for now, I'm going home. Merry Chrismas to you all.

dreadman