Translating statics, fields and labels

Translating static variables, fields and labels

The straightforward way to translate strings in SilverStripe is using the _t( ... ) method on them. However there some situations where you can't use it - or at least not in that straightforward way.

 Translating static variables using a getter

From the PHP manual: 'static properties may only be initialized using a literal or constant; expressions are not allowed.' One way to overcome this in SilverStripe is the use of a getter:

static $SomeVar = 'some value';

function getSomeVar() {
	return _t('ThisClass.SOMEVAR', $this->stat('SomeVar'));
}

Now, if you add $SomeVar in your template, SilverStripe will use getSomeVar() to parse it.

 More then one possible translation

Sometimes you won't know in advance what value a static var will have. Suppose there are three values to choose from. You'd need three possible translations that you want the textcollector to find. Enter the provideI18nEntities() method:

class MyExample extends DataObject implements i18nEntityProvider {

	static $TimeOfDay = 'morning'; // default

	// prepare a couple of strings for translation
	function provideI18nEntities() {
		$entities = parent::provideI18nEntities

		$entities['MyExample.morning'] = array('morning');  
		$entities['MyExample.afternoon'] = array('afternoon');
		$entities['MyExample.evening'] = array('evening');

		return $entities;
	}
}

Running the textcollector would result in the following entry in the en_US.php language file:

$lang['en_US']['MyExample']['morning'] = 'morning';
$lang['en_US']['MyExample']['afternoon'] = 'afternoon';
$lang['en_US']['MyExample']['evening'] = 'evening';

And then again: the getter, that will select the right translation, based on the current value of the variable:

function getTimeOfDay() {
	return _t("MyExample." . $this->stat('TimeOfDay'), $value);
}

This can now be referred to from the template as:

The time of day is: $TimeOfDay

 Translating field labels

In some situations custom getters won't work - especially when SilverStripe uses scaffolding to create forms. But now there's another hook: SilverStripe will call on the DataObject::FieldLabels() method to provide it with an array of fields and their labels. So to provide the correct translation for a label, we need to override the FieldLabels() method in our custom DataObject class. Something like:

class MyExample extends DataObject implements i18nEntityProvider {

	static $db = array(
		'Name' => 'Varchar',
		...
	);

	function fieldLabels($includerelations = true) {
		$labels = parent::fieldLabels($includerelations);

		// add a translation to the $labels array for each db field
		// if $includerelations == true (and it normally is) you need to add 
		// the db_ prefix, cause that's what SS will look for
		foreach($this->stat('db') as $key => $value) {
			$labels[$key] = _t("MyExample.db_{$key}", $key);
		}

		return $labels;
	}

Now you need to make sure that these translations again exist in the language file, so you must to provide them for the textcollector. Note: in scaffolding, SilverStripe wants the keys for these translations to have a prefix refering to the type of relation: db, has_one, has_many etc.:

function provideI18nEntities() {
	$entities = parent::provideI18nEntities();

	// provide translations for $db fields
	foreach($this->stat('db') as $key => $value) {
		$entities["MyExample.db_{$key}"] = array($key);
	}

	// provide translations for $has_one fields
	foreach($this->stat('has_one') as $key => $value) {
		$entities["MyExample.has_one_{$key}"] = array($key);
	}
	return $entities;
}

Effectively, a field called 'Name' and a has_one relation called 'Image' will end up in the language file like so:

$lang['en_US']['MyExample']['db_Name'] = 'Name';
$lang['en_US']['MyExample']['has_one_Image'] = 'Image';

 Special labels: summary and searchable

Special labels for fields like $summary_fields and $searchable_fields are treated in a similar fashion as normal field labels. But in this case there's no need for relational prefixes. And since you know in advance which fields you're using, you can also skip the provideI18nEntities() method and provide translations as straight strings.

Mind these fields can refer to fields within related objects or even to functions, so they need not be real database fields at all. Something like this will work (textcollector will spot these translations):

static $summary_fields = array(
	'Name',          // db Name field
	'Image.ID',      // ID of a has_one Image
	'MyFunc'         // return value of some function 
);

function fieldLabels($includerelations = true) {
	$labels = parent::fieldLabels($includerelations);

	$labels['Name'] = _t('MyExample.NAME', 'Last name');
	$labels['Image.ID'] = _t('MyExample.NAME', 'Image ID');
	$labels['MyFunc'] = _t('MyExample.MYFUNC', 'Function result');

	return $labels;
} 

 Translating default values

Default values are the values that form fields are set to when a form is first opened for a new record. These values need to be set before the form is created. Normally you would do something like this:

static $db = array(
	'Name' => 'Varchar'
);

static $defaults = array(
	'Name' => 'Enter your name here'
);

And again: you can't just use the _t( ... ) method here. But that's where the PopulateDefaults() method comes to the rescue! SilverStripe will call it to collect its default values and we can hook into this function to define our translations:

static $db = array(
	'Name' => 'Varchar',
);


public function populateDefaults(){
	parent::populateDefaults();

	// create a default value for the 'Name' field
	$this->Name = _t('MyExample.DEFAULT_NAME', 'Enter your name here');   
}

Note: a default value is only offered when an object is newly created in the CMS, it is skipped on opening previously stored records - for obvious reasons...

Comments

Het versturen van reacties is uitgeschakeld.

RSS feed voor reacties op deze pagina