Difference between revisions of "Adding multilang fields"

From EPrints Documentation
Jump to: navigation, search
Line 1: Line 1:
This page explains how to add multilingual fields in EPrints and how they can be integrated with it.
+
EPrints' builtin fields are not multilingual, in the sense that there is only one version of each field. This page explains how to add multilingual versions of existing fields in EPrints and how they can be integrated with it.
 +
 
 +
== Multilang fields and EPrints ==
 +
EPrints supports the '''multilang''' field type (see [[Multilang]] for more details) which allow a user to insert different content for different languages. There are a few limitations with '''multilang''' fields though:
 +
 
 +
* When its value is printed it is shown in all languages which contain content.
 +
* If a basic EPrints field's type is replaced to become '''multilang''' (like '''title''' and '''abstract'''), EPrints functionality breaks because it expects one output.
 +
 
 +
So this article explains how we can replace a basic field, the '''title''' field, with a multilingual one.
  
 
== How to add a custom, multilingual field ==
 
== How to add a custom, multilingual field ==
In order to add a new field in EPrints (such as the '''ml_title''' field), a few things need to take place:
+
Replacing an EPrints basic field, like the '''title''' field, involves a few steps. First, a new field needs to be created that will be able to store information for different languages; this field will be of type '''multilang'''. Next, the basic field's type needs to be replaced with one that is able to use our newly created field as its storage place. This field type will use a function wrapper for storing and retrieving information from the '''multilang''' field, hence the '''title''' field will become a calculated field.
  
* A new field type needs to be created that will help our field to implement some of EPrints logic. Our field type is called virtualwithvalue.
+
So, in order to add multilingual support for the '''title''' field, the following things actions need to take place:
* The field's name and functionality needs to be introduced to the EPrints system via a configuration file located in '''~eprints/archives/<reponame>/cfg/cfg.d/'''.
+
 
 +
* A new field type needs to be created that will help our '''title''' field to implement some of EPrints logic. Our field type is called '''virtualwithvalue'''.
 +
* A new '''multilang''' field needs to be created that will store our multilingual information. We will call this field '''ml_title'''.
 +
* '''ml_title''' field and '''title''' field's functionality need to be introduced to the EPrints system via a configuration file located in '''~eprints/archives/<reponame>/cfg/cfg.d/'''.
 
* EPrints' database needs to be updated to include the new field. This is achieved when user eprints executes (from his home directory):
 
* EPrints' database needs to be updated to include the new field. This is achieved when user eprints executes (from his home directory):
 
<source lang="bash">
 
<source lang="bash">
 
$ ./bin/epadmin update reponame
 
$ ./bin/epadmin update reponame
 
</source>
 
</source>
* The appropriate phrases need to be added for each field and for each supported language.
+
* The appropriate phrases need to be added for the '''ml_title''' field on each supported language.
* The workflow needs to be edited in order to contain the new fields - and not include the original ones. The new fields contain custom lookup scripts.
+
* The '''title''' field needs to be replaced with '''ml_title''' in the workflow.
* EPrints advanced and simple search functionality needs to take the new fields into account.
+
* '''ml_title''' field in the workflow will contain a custom lookup script.
 +
* The '''title''' field needs to be replaced with '''ml_title''' in the simple and advanced search scripts.
 
* The repository needs to be reloaded, by running:
 
* The repository needs to be reloaded, by running:
 
<source lang="bash">
 
<source lang="bash">
Line 19: Line 31:
  
 
The following sections explain each step in detail, where we are using '''ml_title''' as our example field. The code snippets are just for demonstration purposes (and proof of concept). If you want to see the final, working implementation, you should look at the source code of the plugin.
 
The following sections explain each step in detail, where we are using '''ml_title''' as our example field. The code snippets are just for demonstration purposes (and proof of concept). If you want to see the final, working implementation, you should look at the source code of the plugin.
 +
  
 
== Adding a new field type ==
 
== Adding a new field type ==

Revision as of 08:55, 7 June 2016

EPrints' builtin fields are not multilingual, in the sense that there is only one version of each field. This page explains how to add multilingual versions of existing fields in EPrints and how they can be integrated with it.

Multilang fields and EPrints

EPrints supports the multilang field type (see Multilang for more details) which allow a user to insert different content for different languages. There are a few limitations with multilang fields though:

  • When its value is printed it is shown in all languages which contain content.
  • If a basic EPrints field's type is replaced to become multilang (like title and abstract), EPrints functionality breaks because it expects one output.

So this article explains how we can replace a basic field, the title field, with a multilingual one.

How to add a custom, multilingual field

Replacing an EPrints basic field, like the title field, involves a few steps. First, a new field needs to be created that will be able to store information for different languages; this field will be of type multilang. Next, the basic field's type needs to be replaced with one that is able to use our newly created field as its storage place. This field type will use a function wrapper for storing and retrieving information from the multilang field, hence the title field will become a calculated field.

So, in order to add multilingual support for the title field, the following things actions need to take place:

  • A new field type needs to be created that will help our title field to implement some of EPrints logic. Our field type is called virtualwithvalue.
  • A new multilang field needs to be created that will store our multilingual information. We will call this field ml_title.
  • ml_title field and title field's functionality need to be introduced to the EPrints system via a configuration file located in ~eprints/archives/<reponame>/cfg/cfg.d/.
  • EPrints' database needs to be updated to include the new field. This is achieved when user eprints executes (from his home directory):
$ ./bin/epadmin update reponame
  • The appropriate phrases need to be added for the ml_title field on each supported language.
  • The title field needs to be replaced with ml_title in the workflow.
  • ml_title field in the workflow will contain a custom lookup script.
  • The title field needs to be replaced with ml_title in the simple and advanced search scripts.
  • The repository needs to be reloaded, by running:
$ ./bin/epadmin reload reponame

within eprints user's home directory.

The following sections explain each step in detail, where we are using ml_title as our example field. The code snippets are just for demonstration purposes (and proof of concept). If you want to see the final, working implementation, you should look at the source code of the plugin.


Adding a new field type

In order to create a multiple-language field we have to create an appropriate field type. EPrints' MetaField is a perfect candidate for this, and we need to extend it and override its get_value and set_value functions for the field to work properly with the rest of EPrints API, as well as its get_property_defaults function to sort out warnings for default values. The following code could be a rough implementation of such a field:

package EPrints::MetaField::Virtualwithvalue;

use strict;
use warnings;

use EPrints::MetaField;

our @ISA = qw( EPrints::MetaField );

use strict;

sub get_property_defaults
{
    my ( $self ) = @_;
    my %defaults = $self->SUPER::get_property_defaults;
    $defaults{get_value} = $EPrints::MetaField::UNDEF;
    $defaults{set_value} = $EPrints::MetaField::UNDEF;

    return %defaults;
}

sub get_value
{
    my( $self, $object ) = @_;
    if ( defined $self->get_property("get_value") )
    {
        return $self->call_property( "get_value", $object);
    }
    return undef;
}

sub set_value
{
     my( $self, $object, $value ) = @_;
     if ( defined $self->get_property("set_value") )
     {
         return $self->call_property( "set_value", $object, $value);
     }
     return undef;
}

We could save this file in ~eprints/lib/plugins/EPrints/MetaField/Virtualwithvalue.pm.

Introducing ml_title field in EPrints

To inform EPrints about our new field (that will be of type virtualwithvalue), we should create a configuration file, eg: ~eprints/archives/<reponame>/cfg/cfg.d/zz_multilang_field.pl with content like the following:

#define local fields
my $local_fields = [
{
    name => 'ml_title',
    type => 'multilang',
    multiple => 1,
    fields => [ { sub_name => "text", type => "longtext", input_rows => 3, make_single_value_orderkey => 'EPrints::Extras::english_title_orderkey' } ],
    input_add_boxes => 1,
},

{
    name => 'title',
    type => 'virtualwithvalue',
    virtual => 1,

    get_value => sub
    {
        my ($eprint) = @_;
        if ($eprint->is_set('ml_title'))
        {
            my $lang = $eprint->repository->get_langid;
            my $lang_set = 0;
            my $vals = $eprint->get_value('ml_title');
            my $title = '';
            if (!$lang)
            {
                $lang_set = 1;
            }
            else
            {
                # set the default lang's text as title
                foreach my $v1 (@{$vals})
                {
                    if ($v1->{lang} eq $lang)
                    {
                        $title = $v1->{text};
                    }
                }
            }
            # if the language is not set or I can't find an abstract in the 
            # user's language, get the first object's text as abstract
            if ($lang_set or $title eq '')
            {
                $title = $vals->[0]->{text};
            }
            return $title;

        }
        return undef;
    },

    set_value => sub
    {
        my ($eprint, $value) = @_;
        my $lang = 'en';
        #only use this on imports, NOT if the value is already set
        if ($eprint->is_set('ml_title'))
        {
            return;
        }
        if ($value)
        {
            $eprint->set_value('ml_title', [{lang=>$lang, text=>$value}]);
        }
    }
},
];

#create lookup hash of local field names
my $local_fieldnames = {};

foreach my $f (@{$local_fields})
{
    $local_fieldnames->{$f->{name}} = 1;
}

#merge in existing field configurations
foreach my $f (@{$c->{fields}->{eprint}})
{
    if (!$local_fieldnames->{$f->{name}})
    {
     push @{$local_fields}, $f;
    }
}

#overwrite original array of configured fields
$c->{fields}->{eprint} = $local_fields;

Where we can see that our new ml_title field is of type multilang (EPrints multilingual field type) and the field title has changed to be of type virtualwithvalue and now implements the two aforementioned functions: get_value and set_value. Both these functions are used by EPrints API, and their existence, as well as their return values, are critical for EPrints to work properly. Their names imply their functionality. In the end of our example code, one can see how a custom field can be added in the list of EPrints fields.

What has happened in effect is that the title field has become a calculated field that gets or sets its value in its corresponding multilingual field. So each new record now has a multilingual field which it accesses via the interface provided by the calculated field (of type virtualwithvalue).

The reason we don't set title field to be of type multilang in the first place is that many EPrints functions expect only one value from the title (and abstract) field, and multilang fields don't support such functionality, so EPrints produces errors. By using and extending calculated fields (like MetaFields), we can calculate and produce always a single output for the multilang field (based on some condition) via its get_value function; its set_value function is used for populating our ml_title field's values.