Monday, December 2, 2013

National Library of the Netherlands - Migrating multilingual xHTML from a shoe-box to Drupal 7

In fact I am a very lazy person. That's why I studied theoretical physics. In school I simply compared the number and thickness of the books for the different studies, and concluded that physics must be the one where this laziness would prosper most.
Feynman diagrams
The thing is, as soon as you understand a part of physics, you can stop reading. Not so with history, not so with all other subjects. They require hard mental labour.
(I have to find some apology for studying philosopy lateron, so any suggestions are welcome....)

Hail Laziness
Laziness is one of the least respected human inclinations.  If there where no lazy people, no one would have invented the car, the combine, the phone et cetera. We would all be working our asses off all day in the fields, pushing little grains out of their stalks one by one. Books would have no indexes. Skyscrapers no elevators. Chairs no legs.

Royal Library of the Netherlands
One fine day (early 2012) we got like the following request from the Royal Library.

On the left we've got twenty shoeboxes of HTML, and on the right we have a brand new core structure for the website in Drupal 7: Contenttypes, Display Suite, Views and all.
Could you please import the information from the shoeboxes into the Drupal 7 system. Thankyouverymuch and Yesterday would be fine.

Being Lazy we simply said: Yes, of course we can. There is nothing we can't do.
And then imagine the soundtrack of Jaws on the background........

Delusions of simplicity
We said so because the concept in itself is very simple.

      Here we have content A, B and C. In booklet X.
      There, on the other side, is a new booklet Y.
      Now copy A, B and C to booklet Y.

      X( A B C )         -->        Y( A B C )

What the hell were you thinking!
The source being ante-diluvian xHTML, more or less templated,  from which we had to sift images, downloads and all other digital objects, parse all content from all these different structured pages, and then load and upload everything in the totally different structured Drupal 7 system.

Book of Hours of Simon de Varie. Paris, 1455;  Tours, c. 1455.
Vellum, 99 leaves, 116 x 85 mm. - 74 G 37a, fol. 1v-2r
We're talking repeatable fieldcollections in repeatable fieldcollections,  migrating source images to different caching formats, programmatically generating en configuring viewmodes, and showing them via the Display Suite and the Media module, which at the time was still in the development phase. And apart from that, there was still development going on the the target Drupal site.
Oh Yeah, and did I mention the multilingual part? English and Dutch.

So it's a project with a big red rubber stamped warning on the cover:

      Send project manager to 
      high altitude trainingcamp 
      before start!

Or, stated differently, in common ICT jargon: Blood, Sweat and Tears ahead.

Analysis: Dance like a butterfly...
The approach we used was the equivalent of dance like a butterfly and sting like a bee in webdevelopment. There is no way to oversee all problems in this kind of large projects concerning conversions between two totally different systems. In the quotation we made, which needed to be fixed price, we tried to include some bleeding control, but we knew beforehand that we were entering the Swamp part of our Portfolio. 
It proved for instance especially difficult to emulate the maintenance features in the old system, which was an xml based editor. There was no way we could migrate these features to the new D7 setup.  We were down to analysing every feature and  approach it from a totally different angle in D7.
Another unexpected tricky part was recalculating all internal links in the site. We had to iterate all pages aproximately twenty times before we had all link types covered. Some linkit, some entityreferences, some link fields, et cetera.
Don't get me started...
For the sake of your mental health I will not elaborate on the technical details, anyone interested can contact me directly, but it's a lot like this
    $file2 = file_save_data($image2, 'public://'.$filename2,FILE_EXISTS_RENAME);
    $field_collection_item->field_afbeelding=array(LANGUAGE_NONE => array('1' => (array)$file2));

    $field_collection_item->field_alttekst[LANGUAGE_NONE][0]['value'] = $animageobject->alt;
    $field_collection_item->field_titletekst[LANGUAGE_NONE][0]['value'] = $animageobject->title;

and than for days on end....
(And as for the bleeding part: Whoever thought up the idea of littering PHP code with all these dollar signs?)

5% inspiration, 99% iteration
I think we did about ten migrations. And after every migration the Royal Library checked the new site and discovered some new features or parts that weren't specified but certainly needed to be migrated as well. The Math was never right!

Never again!
And when you are finaly finished, and the site is migrated and the Royal Library is happy, the first three days you say to yourself: Never again. Behind every mountain there was another mountain, behind every tree there was a madman with an axe, behind every solution there appeared a brand new grinning unexpected problem produced by the very same solution, with five other problems stacked up his sleeve.
But on the fourth day you realise how much fun we had, how much we learnt about the internal workings of Drupal.

Geek sucks
I sometimes mind the Geeky part of my work, days of trying to get a certain piece of code right, minimal pixel adjustment feuds with the designers, that stuff. But when the subject matter itself is something like the Royal Library content, or digital heritage projects in general, I might just possibly be able to live with that.

Saturday, November 30, 2013

Drupal 7 - Moving the messages text from a zone to a region in an Omega subtheme

The messages always mess up my page layout, so I usually simply want them on the top of my page content.

1. remove message from its default postion
1.a  Copy  zone--content.tpl.php to your subtheme's template directory (if you have not done that already)
1.b Remove these lines
  <?php  if ($messages): ?>
      <div id="messages" class="grid-<?php print $columns; ?>"><?php print $messages; ?></div>
    <?php endif; ?>

2. transfer the messages variable to the region template
2.a Open template.php
2.b add a preprocess functio, or modify if you alreay have one

 function THEMENAME_preprocess_region(&$vars) {
      $theme = alpha_get_theme();
     if ($vars['elements']['#region'] == 'content') {
       $vars['messages'] = $theme->page['messages'];


3. add the messages to the region template
Just write anywhere you want in the template
    <?php if ($messages): ?>
      <div id="messages" class="grid-<?php print $columns; ?>"><?php print $messages; ?></div>
    <?php endif; ?>

Drupal 7 - Adding multiple javascript files to an Omega subtheme

Adding a javascript to an Omega subtheme is a bit complex.
I'd rather use  scripts[] = js/chr.js in the info file, which works by the way, but for some reason you first need to add the js file as a library, and then enable it in the settings.
(see and
I this example I add one library containing two javascript files.

0. Add your javascript files in the js folder of your theme
(in this example I use files chr.js and chr2.js)

1. Add some code like this to your theme's info file

libraries[chromega][name] = CHR KHR main javascript
libraries[chromega][description] = Quirqks and Jeeeequery fun for th CHR website
libraries[chromega][js][0][file] = chr.js
libraries[chromega][js][0][options][weight] = 1
libraries[chromega][js][1][file] = chr2.js
libraries[chromega][js][1][options][weight] = 2

(you can use any name where I use chromega)

2. Go to your theme's settings page

3. Select tab toggle libraries and add your custom library

4. Clear you cache  

5. and then GO javascripting
(I always forget the structure for the D7 javascript files so thats why I add this wonderfull example)

// JavaScript Document
(function ($) {
 //////////////////////////////////////////////////////////////////////////////////////// All code here
   $(document).ready(function() {
     // maak op d ehomepage beide blokken even lang
  function dotherightthing(){
      alert('Do the right thing!');
 ////////////////////////////////////////////////////////////////////////////////////////  end of all code


Nota bene

For some reason this (lazy) way of adding the javascript in the template file does not work

function themename_preprocess_page(&$variables) {
  drupal_add_js(path_to_theme() . '/js/chr.js');

Friday, November 29, 2013

Drupal 7 - Adding captcha to a webform

Another thing I always have to lookup while it is so simple....
1. install the captcha and image captcha module

2. go to configuration > people > captcha

3. Add form id
Add the form id of the forms to which you want to add a captcha challenge on the bottom of this page and select the captcha type

You can find the id by opening the form an looking in the HTML. There you find an id like: webform-client-form-75

<form accept-charset="UTF-8" id="webform-client-form-75" method="post" action="/en/order" enctype="multipart/form-data" class="webform-client-form">

NB! Replace all hyphens by underscores!

webform-client-form-75    ->    webform_client_form_75

4. Translation
If you have a multilingual site and want to translate the description, you have to do this partly on the capcha configuration page, partly via the normal Drupa interface translation.
(which is rather stupid)

captcha config
For instance, as I am Dutch (although also half Frysian) I always translate
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.
To a bit archaic
Deze vraag wordt gebruikt om te testen indien u een menselijke bezoeker bent teneinde spam-inzendingen te vermijden.

Interface translation
What code is in the image? *To
Welke code ziet u in de afbeelding?: *
Enter the characters shown in the image.
Which is more or less a useless repetition of the previous sentence I think, to
Vul bovenstaande code in.

5. State of Bliss
And then, your webform will contain a captcha. Rejoice!

For Drupal 8: see this post

Thursday, November 28, 2013

Drupal 7 - Changing the default file type icons without hacking core

A lot of time the designers want the icons just a little bit different than they are in drupal core. So, being lazy, I always just replaced the icons in core with the designer icons ad made a remark in my upgrade doc for that particular site.

A better way to achieve this is to just change the file icon path in your theme and put the modified icons somewehere outside the drupal core, so as being ably to upgrade your site and modules without any extra configuration steps.

function THEMENAME_file_icon($vars) {
  $file = $vars['file'];
  $icon_directory = drupal_get_path('theme', 'THEMENAME') . '/images/file_icons';
  $mime = check_plain($file->filemime);
  $icon_url = file_icon_url($file, $icon_directory);
  return '<img alt="" class="file-icon" src="' . $icon_url . '" title="' . $mime . '" />';

Copy the map modules/file/icons to a the images directory in your theme.
Rename the map file_icons
Change any image in this map to your (or your beloved designers) liking and you're set.

Monday, November 25, 2013

Drupal 7 - Presave a node (or doing custom validation and/or manipulation on field values)

I now have the simple specification that I have a text field in a Node which always needs to be uppercase, whatever the editor enters in the field. As a second specification I also want all spaces removed from the field values.
I could not find an example snippet to start up from, so I thought better publish this, maybe someone else will have  an easier live than me....

Field x: user may enter any character, but on saving the field all characters will be uppercased.
Field x: Also, alle whitespaces will be removed from the string

1. Create a module, in this example called customchr.
1. a Create info file

name = Custom CHR
description = Custum manipulations for the CHR site
package = Overboord
core = 7.x

2. Create module file customchr.module

function customchr_node_presave($node) {
  if ($node->type == 'publication') {
    // convert to uppercase
    // strip all whitespaces
    $node->field_publication_code[und][0][value]= preg_replace('/\s+/', '', $tempstring);

Drupal 7 - Theming file field for documents

What seems to be a really simple task for any Drupalist got me really walking the ceiling this evening.
I just want to display my filefields, for the document, as a download limk with an icon denoting the file type and with the filesize mentioned. It seems to me that that should be the default way to show a download, but it is not.
After playing with the custom field formatters for a while, I used an easier approach.

1. Go to view modes and add a viewmode
2. give it a understandablen namen (vm_file_icon_download_size)
3. Check file
4. save
5. go to structure > file types (or older Drupal version you can find that under configuration)
6. click 'manage display' in the document row
7. click on tab 'custom display settings'
8. check the new view mode you just added
it appears as a tab in the top of your page
7. click on this tab and then click on manage file display
8. Choose table of files
Drupal will then show a rather ugly table with all element I want, the icon, the filename, the size.
I can rewrite the css to make it all a bit less ugly

.file.file-document table thead {

.file.file-document table, .file.file-document table tr  {
      background-color: #FFFFFF;  
.file.file-document table td  {

The link in the display will then look like

BUG: Description bug
But when you enable a description this still won't show.
This is caused by a bug in the file entity module.
Using the patch resolves this issue

Wednesday, November 20, 2013

Drupal 7 - how to create a views block of all referenced nodes in the entity reference fields

I did this so many times but every time I seem to have to start all over again. Reason to write it all up and publish it here.
Others may have done this before and much better.

Drupal 7, Views, entity reference (multilingual)
In have contenttype A which contains an entity referemce field that can make a reference to contenttype B.

A. View of items referencing
I also want to display the list of all node C and D referring to the current project. Here I also want to show multiple fields from the referring node linking to the referring node itself.

I my case contenttype A is a project, and contenttype B are Institutes cooperating on these projects. Contenttypes C and D are articles and publications which are refer to the project in question.

B. View of referenced items
On displaying a contenttype A node I want to display some of the fields from the referenced node (contenttype B) in a sidebar.

How to A. View of items referencing
A.1 Create a new view
A.1.1 Call it f.i.  'related'
A.1.2 Choose fields for the format

A.2 Open the 'Advanced' tab on the right hand side
A.3 Click the Add button behind relationships
A.4 Select
(you have ond eof these for every entity reference field in your contenttype)
In my case I have A bridge to the Content entity that is referenced via field_project_institutes
A.5 Click Apply
A.6 On the next screen check Require this relationshop
You can also change the name of the identifier but I never see a reason for this.

In this example it is called:Content entity referenced from field_project_institutes
Now we need an argument to provide to the relationship, and the argument will be the nid of the current contenttype A node. To do this you have to provide a contextual filter
A.7 Click the Add button behind contextual filters
A.8 Check Content: Nid
A.9 Click Apply
A.10 A new screen: Choose the relationship you just made
In this example it is called:Content entity referenced from field_project_institutes
A.11 Select Provide a default value under When the filter value is not available
A.12 Under Type select Content id from url
A.13 Then, under When the filter value IS available or a default is provided check the Specify validation criteria box
A.14 Under Validator choose content and then check the contenttype b. The contenttype that is referred to, not the contenttype that contains the reference field.
A.15 Under Filter value format choose Node ID
A.16 Under Action to take if filter does not validate choose Hide view
A.17 Apply
A.18 Save your block view

How to B: View of referenced items
B.1 Create a new view
B.1.1 Call it f.i.  'related'
B.1.2 Choose fields for the format

B.2 Open the 'Advanced' tab on the right hand side
B.3 Click the Add button behind relationships
B.4 Select
B.5 Click Apply
B.6 On the next screen check Require this relationshop
You can also change the name of the identifier but I never see a reason for this.
B.6.1 and click Apply

In this example it is called:Content referencing Content from field_project_institutes
Now we need an argument to provide to the relationship, and the argument will be the nid of the current contenttype A node. To do this you have to provide a contextual filter
B.7 Click the Add button behind contextual filters
B.8 Check Content: Nid
B.9 Click Apply
B.10 A new screen: Choose the relationship you just made
In this example it is called:Content referencing Content from field_project_institutes
B.11 Select Provide a default value under When the filter value is not available
B.12 Under Type select Content id from url
B.13 Save your viws, and place ypur block in the correct region...

Suppose you want to show an image field from the node that is referred to in the sidebar, linking to this orihinal node. Seems an easy task doesn't it?
No. The problem is that you can easily ad the field to the view, select its viewmode, but wehn you want to link this field to the containing node, all html cleaners protest:
Adding the link aroudn the field does not work in this case, the a tag contains the div tag.  Rewriting the output presents me with the samen problem.
The way i figured it out finally was to
a. Add the content path, as a field (use absoklute and hide from display)
b. Add the image, set its view mode but then strip all html tags except <img>
c. Create a global text field, and there rewrite the output to
something like <a href="[path]">[field_institute_logo]</a>
d. But you still have a problem than because the field_field_institute_logo value containes stripped text from html that is normally hidden to users. So then just create a field template for this global text field removing everything from there except the a and im tags and inner attributes.
$output = preg_replace('#.*?(<(img|a).+?>).*?#is', '$1', $output);

Node reference
On trying the same with nodereference I got really stuck but solved it eventually....

1. add relationships
2. search for the noderefence field you want (NB NOT with ' - reverse')
(this is the node reference field in the node referring to the node type entity B)
(In my case, Inhoud: Verwijzing (field_verwijzing) )
3. Click apply (remember the name of the relationship*)
4. Select 'Require this relationship'
5. click apply
5. Add contextual filter
6. Chose Content: Nid
7. Click apply
8. Choose the relationship you just made (*)
9. Under When the filter value is not available choose 'provide default value'
9.1 Choose 'Content id from Url'
10. Under when the filter value is avaialable or a default is providedselect 'Specify validation citeria'
10. 1 (Depending on the install there should be an extra box , but in some installs the box wont show up, and you have to click apply and then click on the contextual filter again before you can add these criteria)
Under Validator choose Content
10.2  Under contenttypes choose your contenttype B
10.3 Under filter value format choose 'Node ID'
10.4 Under action to take when filter value does not validat Choose 'Hide view'

Friday, November 1, 2013

Dupal 7 - Media and View modes - How to get an image style as a view mode in the list in the media browser

I've been battling with this for quite some time, so maybe someone else be happy with this post.
You define an Image style and want to be able to select this style in the display setting for your content type, or in the display settings for a field in a view.
Here is a simple flowchart to achieve this.

1.define a new image style
1.1 go to administration > Configuration > Media
1.2 add image style
1.3 give it a descriptional name
f.i. call it verylargeimage
1.3 add effects
f.i. set scale and crop
Width 624
height 400

1.4 update style

2. create a corresponding view mode
Do this with display suite or with entity view mode
example here is done with Display suite
2.1 got to administration > Structure > Display Suite > View Modes [tab]
2.2 click add a view mode
2.3 Give it a name you can easily relate to the image style
In this example f.i. vm_verylargeimage
2.4 Select the file checkbox
2.5 Click Save

3. Connect the style and the view mode
3. 1 Navigate to Administer -> Configuration ->Media -> File Types
If you are using Media 2.x, then the File types has moved to Administer -> Structure -> File Types.

3.2 Click on manage display on the image row
3.3 open tab (under left) custom display settings
3.4 check the checkbox in front of youre viewmode name
In this example vm_verylargeimage
3.5 In the upper right corner you see your viewmode added to the viewmodes menu
3.6 Click on manage file display
3.7 Click on your viewmode
In this example vm_verylargeimage
3.8 Select under Enabled displays 'Image'
3.9 Select your image style on the bottom of the page

In the display settings for the field in your contenttype, or your view, you can now choose the corresponding view mode.
  • Drupal 7
  • Media
  • view modes

Sunday, October 20, 2013

Setup a Drupal 7 Multilingual site

This post is about how to setup a multilingual website with content translation.

I will do another post about entitity translation, but setting up a site with entity translation is, in my opinion, not ready for production releases. [*]

1. Install a Drupal 7 site
2. download needed interface translations
for drupal core from here:
3. save them
(the languages you plan to install) in /profiles/standard/translations/
4. Enable locale and content translation (are in drupal core)
5. Download and install
internationalization (i18n)
You need this module when for instance you have a node page as your front page, and automatically wnat yo switch this to the german version when changing language.
localization update
Provides automatic downloads and updates for translations.
6. Under internationalization choose 
which modules tom enable
menu translation
You have to make a choice: If both (or all of) your siets wille have the exact same sytructure, with all content translated, you will be verwy happy with the menu translation module. Its a RAD feature for the menu's. But when you have sites which have a different structure for all language versions, this module will make you very, very, verry unhappy.  Then you'll be better of with simply maken menu blocks and showing them dependent on the language.
In this showcase We'll be using this, cause the language versions of the site will be exactly congruent.
path translation
Normal nodes and users will be codennecte in translation sets. But to be able to add a language switch to for instance a page view, or a panel page, you will need path translations.
translation sets
This will couple the different language versions (which are nodes) in a language set.
String translation
Enables translations for string in modules, templates etcetera (added with the t-function) that are not added to the po files. Not strickly neccesary but come in handy.
Multilingual content
Also not strickly neccesary but helps the workflow. You can set default languages, lock node translations on existing nodes, etcetera.
Field translation
This option is also not a content deirected translation module, bu helps the workflow. You can translate texts associated with field settings etcetera. So helpfull when you have a multilingual site and want users or administrators to see help texts et cetera in their own language.
There is another module 'entity translations' which deals with the language versions of fields within a node, but thats quite another story...
Block languages
You definitely want that. It enables you to handle blocks just as you handle nodes. You can translate a block, and set for which langua version it has to appear.
Multilingual select
When you want to be able to select languages in a view, you need this module. Variable translation
You need this module for instance when yoy want to set a different homepage, and the homepage being a specific node, on for each language version.
5. Go to configuration /admin/config
6. Go to languages /admin/config/regional/language
7. add the languages you need
 (im my case I installed germand and french next to english, and disable french because the site will for now be english/german, and in a later stage be extended with the french version.
8. Add language prefixes to the path
That's on the language pag, /admin/config/regional/language, and click on edit behind each alnguage
The custom way is to add the language code as a path prefix.
In my case 'en' for english, 'de' for german (as in 'deutch') and 'fr' for french.
(on existing siytes this option wil defenitely break all existing nodes paths! So google around how to avoid that.) [*]
9. Language detection
While you are still on the language page, click the tab 'Dtection and selection'
Simply choose Determine the language from the URL (Path prefix or domain).
(there is a lot to say about the other options, but we simply skip that for another day)[*]
10. Import core (and module) interface languages
If you've saved the language po files on de server in the map profiles/standard/translations during install of teh language this languager file will be imported.
Otherwise you have to download the po file later, go to configuration, admin/config, and under regional and language, select translate interface: Translate the interface. Then choose the import tab, and the rest is just following orders...

10.1 Automation
Because you've installed the internationalization update module, you also have a tab 'update' on this page, where you can check which module ranslations have not been added yet...
Now you can dowmnload and import alle these files by hand, but a better way is to simply push the update button  underneath your page. get a cup of coffe, eat some bisquits, talk to the wife (or the man), play with your children. Drupal automatically imports all translation files needed.

11. Enable multilingual contentypes
Go to each translatable contenttype and under publishing options enable the 'multilingual settings with translation'.
Dont't forget the translation part. You won't be the first frantically looking for this translate tab
Go to the multilingual settings under the same contenttype and choose the settings you want. I usually do this

12. Multilingual paths

If you've not yet installed pathauto, do so immediately!
Because you want to make your paths also multilingual, so if you have a standard in your autopath for for instance a contenttype 'loveletters', say 'love-letters/[node:title]' you can set  a pattern for the french version like 'lettres-d-amour/[node:title]'
You'll probably also need transliteration
To convert any diacritic characters like the æ danish.
After installingTransliteration, go to Configuration > Search and metadata > Url aliases > Settings
There check the option ' Transliterate prior to creating alias' and 'Reduce strings to letters and numbers'.
A page with 'Jæle' in the name will then be saved with an url 'jaele'.

13. Roles
Create an editor role, an set permissions for this role for the site maintainers.

14. Homepage
In my case I wil need two (and lateronon three) nodes for each language version to be the homepage.
The homepage wil consist of some views and block.
Fisrst I add a node for the english frontpage, and tranlate this one for the german frontpage.
We need now to have Variable and Variable translation installed.
Go to configuration, regional and language, multilingual settings, the variables tab.
Choose the site information sub tab and select the deafult front page.
Better is to select all options given there.
Now go to the configuration > site information page. And add the url to the default front page.
It's best to add it with the node path like node/2'. (no slash in front)
Select one of the the other languages on the top of the configuration page (which is simply a menu for the language contect of the translateble variables in the current configuration page) to change the setting for these languages.
NB! The configuration page has a language prefix before it, which may be confusing.
If you go to the home page and change languages with the language switch, you'll see everything works hunky dory.

15. Multilingual menu's
One way to ad multil;ingual menu's is to simply add menu blocks, and make them visible on the basis of the language of the current page.
But as I am building a website with equivalent structures, I want every menu and item to be translatable.
15. 1
Go to configuration, regional and language, multilingual settings, the variables tab. Then select the Menu settings tab.
15.2 Select the 'Source for the Main links' to be translatable.
15.3 Create an new menu item (say Top menu)
15.4 Set ' Translate and Localize. Menu items with language will allow translations. Menu items without language will be localized. ' under Multilingual options.
15.5 Click the translate tab and change menu name for every language.
15.5 Go to structure, content types and add thin menu to all contentypes that you will possibly link to from this menu.

16. Translatable blocks
It is of course quite handy to be able to create translations of block. Thats working now if you've followed the instructions above.
One thing though is that you are defauylt only allowed to translate plain text. So if youve made a block with filtered html content, and try to translate that, you get an error message.
You have to go to admin/config/regional/i18n/strings and allow translation for filtered html and full html also.

17. User profiles
The problem is that, unless you install entity translation, which has some major flaws in D7 (honestly, the ast time I did a major check on that was about a year ago) de option of adding fields to the account, does not allow for translation of the content.
I tried out Profile2, but that module strangely enough does not support translations. Not even the entity translation of the fields. (Or at least not that I could find a way to accomplish this.....)
SolutionThe solution I came up was to use entity translation just for the users, and use the other translation modules for the rest of the site.
17.1 Install Entity translation
17.2 Navigate to Configuration > Regional and Language >  Entity translation
17.3 Open tab 'Translatable entity types'
17.4 enable user and disable node
(In this case I do not want to use this possibility and it only clutteres my maintenance interface)
17.5 Enable the module Field translations
17.6 Go to Configuration > People > Account settings and open tab manage fields
17.7 Add any fields you like and in each field check the option under 'Field translation': users may translate this field
(The module field translations is something totally different and just supports the translation of the labels, not of the field content itself, which come in handy but is not allied to the translatiom of the field contents)
17.8 On adding fields choose wisely if you also want them on the registration form, and if you want them translatebale....

18. Images
Wel, there's a subject that sometime makes my head spin. An imafe is a file, and for most files in a multisite setup the german file needs to be different form the english file, and the freanch file and the indian file. So, any filefield you setup as an normal field.
On translating the node you reove the otherlanguage file and replace it with an upload in the language you are translating to.
But: Images are different.
18.1 Specifications
Usually you probably ussually want to use the same image on both language versions, but, and there the is problem, you want to be able to translate the alt, title and caption of the image.
On the other hand, somatime the image contains a lot of language (charts, graphs, et cetera) in which case you want to be able to remove the image just like the normal file case, and replace it with another.
So we want the same setup for an image as for a file, so that on translation you can chroose wether you remove the image or not. But, while keeping the same image, you do want to translate the alt and title texts.
(In this example I could not get the media widget in ckeditor to work, so in the end I skipped media as a ckeditor widget and chose for a hybrid solution, using the media widget for the filefields and IMCE for the image uploads in teh RTEditor.)
18.2 MEDIA settings
18.2.1 Go to admin > configuration > regional and anguage > entity translation
18.2.2 Add 'file' to the translatable entity types.
This merely adds the possibility of entity translation to the file type
18.2.3 Go to structure > file types > image > manage fields
18.2.4 Click on edit in tge alt and title row and enable translation under 'Users may translate this field.'
Then, for every image there is a link 'add {language} translation' en de media popup widget
Thats is to say: there should be.
For my install (Media 7.x-2.0-alpha3 and file entity 7.x-2.0-alpha3) the link only appears when your admin interface is in the language of the other (nonn sourec) language.
So, I habe an Eglish site with a second language german. To be able to translate the alt and title values, I need to translate the node, save it, switch to the german interface, edit the node, open the media widget for the image and only then the add translation link is visible....

18.3 IMCE settings
Is specified a few specific folders for the file uploads on certain contenttypes.
I created two subdirectories in the files folder where the file fields mentioned above save their images. Fo IMCE I added a profile that only has access to those folders>
Now placing an image in the wysiwyg editor is ok. Translation of alt and title works the same as the translation of the text.

19. Entity references
Well, there are really some annoying problems with entity reference and a multilanguage site.
19.1  Entity reference autocomplete uses interface language instead of the node's.
What this means is that when you edit a french node in the english admin interface, it will only show english nodes
There is an option to filter the autocomplete function using an "entity reference" view. But there is also only the option of using the 'current usres' language, and that is teh interface language.
So the only way to solve this is to always switch to the interface language of the node you are editing, and then the autocomplete will show the correct nodes in the same language as the nod eyou are editing.
But this is annoying and error prone
19.2 translation workflow
Another thing is you would like a translation workflow where the entity reference field in Node x in language A to referenced node y in  language A, should automatically translate to an reference entity field in node xt (translation of x in language B) to referenced node yt (translation of y in language B).
This is not the case. The referenced entity in node xt in language B is pointing to node y in language
(Adding the Translation redirect more or less solves this problem for unauthenticated user, biy redirecting them to the translated versions of the 'wrong' links, but thats not really a solution.)

The combination of 19.1 and 19.2 make translation of an entity reference field very cumbersome and error prone!
I tried using the entity reference field translatable with entity translation and not translatable with entity translation. The issue remains!houtje-touwtje solution
A solution is to switch your admin interface when translating or editing a node.
It would solve the problem, which I think is Drupal core, but it is a rather quirky solution cause a maintainer would probably have his/hers admininterface language stable.
There used to be such a setting "Switch interface language to fit node language when creating or editing a translation" but that is gone now. For some bad reasons I think.

Links for this issue

sandbox project dedicated to solving this issue (no solution)
referencing the same problem
referencing the same problem
No solution either

20. Multilingual page views
The path to a page view is alwas the same, and for some solutions it will be better to have a single page view, as opposed to having to add two the same views for a single view. And then again, the opposite language fview will be accessible from the other language to.
Solution is then to install i18n page views
This module a new page view type: The only difference is that you can define different paths for your language versions.
Furthermore the paths connect the page view just like a translation set, so the language swich works just as designed.

21. The trouble with field collections
There is a flaw in the field collection module when it comes to content translation.
Suppose you create a new contenttype and add a  (repeatable) fieldcollections to it.  Create a node and fill alle fields, also some field collections. Then create a translation for this node.

Bug: The fieldcollections in that translations will then have the same entity id as the ones in the node in the original source language. So you end up with two nodes sharing the same field collections field. What then happens on editing the fieldcollection fields  in language x, the corresponding fields in language y then also get edited.
They are the same.
(Enabling entity tranlation on these field collection fields creates other problems which I will not elaborate on at this point.)
This problem does not arise twhen you add new field to both nodes in the translation set, after they have been created. Then these fields are two different entities and unique for either node.
There is a long discussion going on about the patch for the field translation module, but in the meantime there is a solution which works great for my sites. I did not think this one up myself but it is conceived by a guy called Martin. Hook into the translation workflow, and remove the id for the fieldcollection entities when the original node is cloned.

Just build a module, add this code

function MyModule_field_attach_presave($entity_type, $entity) {
    // Clear the item_id on the field collection entity before saving in order to force
    // creation of a new field collection rather than overwriting the original
    if (empty($entity->is_new)) {
        if ($entity_type == 'field_collection_item') {
            if (isset($entity->item_id)) {
                $entity->item_id ='';


X. Search
If you've setup the site as mentioned above, search will default be set so that when you search content, you'll only get the content in the language version you are in now. So that is good. Praise Drupal!

Friday, September 27, 2013

Warning - Dutch fairy tale

Het verhaal van de Kapper van Hamelen

Er was eens een stadje (lang geleden maar niet zo ver weg) waar een verschrikkelijke rattenplaag heerste. Wat de mensen ook deden, niets hielp om de ratten te verjagen. Op het laatst zaten ze 's ochtends brutaal op de nachtkastjes te piepen, ze sliepen bij de mensen in de bedden, en ze vraten alles op.

Op een goede dag kwam er een kapper op bezoek in het stadje. "Wat is er aan de hand?" vroeg hij toen hij de mensen treurig en ongekamd over de straten zag sjokken. "O, het is vreselijk!" zeiden de mensen. "De hele stad zit vol met die stinkende, smerige ratten. En niets helpt!" De kapper fronste zijn wenkbrauwen. "Niets helpt?" "Nee, we hebben alles al geprobeerd!" Daarop meldde de kapper zich bij het stadbestuur en zei daar dat hij, tegen een niet onaanzienlijke vergoeding, dit varkentje wel kon wassen. De burgemeester beloofde hem daarop een kruiwagen vol goud, en de kapper zei dat iedereen die nacht binnen moest blijven met de slaapmuts stijf over het hoofd getrokken.

En zo geschiedde het. De hele nacht was de kapper druk in de weer, en toen de mensen de volgende morgen wakker werden, en verwachtten (hoewel met enige twijfel, ik bedoel maar, wat kan zo'n kapper nou?) dat alle ratten verdwenen zouden zijn, was dit tot hun verbazing toch niet het geval. De ratten waren er nog steeds, overal, op de tafeltjes, de kastjes, in de gordijnen en op de grond. Alleen waren ze nu allen keurig geknipt, hun vacht zag er glanzend en geborsteld uit en ze roken heerlijk naar rozen of viooltjes.

De burgers waren woedend, en de burgermeester weigerde de kapper zijn goud te betalen. "Maar ik heb het probleem opgelost!" Schreeuwde de woedende kapper, die er niets van begreep. En als dank voor zijn harde werk die nacht, werd de kapper het stadje uitgeschopt. Slechts een paar mensen zagen de woede in zijn ogen, en hoorden hem mompelen. "Wacht maar, dit zet ik jullie betaald!" "Is het misschien toch niet eerlijk om hem op zijn minst een deel van het goud te betalen?" vroeg een van hen. Maar de burgermeester schudde zijn hoofd. "Van zo'n kapper hebben wij niets te duchten. Het is een charlatan."

Die avond gingen de mensen sjacherijnig en moe weer naar bed, omringd door duizenden geurende, zijdezachte ratten. (Sommigen moesten hun kinderen zelfs verbieden de knaagdieren te knuffelen en te aaien.) Maar toen ze de volgende morgen wakker werden ontdekten ze wat de kapper had bedoeld met 'dit zet ik jullie betaald'. Al hun kinderen, hun onschuldige kinderen, waren die nacht, zonder uitzondering, prachtig geknipt. De een nog mooier dan de ander.

I met a fish today

I met a fish today.

A fish with no legs, no hair and no voice to speak of.
And this fish wanted to be a bird.
(I know these things; fishes wanting to be birds, cows longing for blood, horses dreaming of hatching)
So I knitted it some wings and taugth it how to fly.

And the fish asked howcome
- the trees
- the why of them branching
- the uses of vertigo
- the absence of teeth
And I told it all these things.

Except for the teeth, cause you never know...

Monday, July 1, 2013

The words without my sister

(About the work of my sister, Jenne Bleijenburg.)

My sister did not speak until she was four. When you look at old family pictures, you see this rather wild girl, mostly smiling, eyes wide open, lots of hair.  Bruises, bleeding lips, that kind of a girl.  But she did not speak. If my parents wanted to know something from her, they asked me or my other sister:
"So, what's with Jenne?"
"She wants a cookie."
When she finally started talking she could utter whole and grammatically correct sentences, so there was no cognitive defect or something. Just no need and no desire for words.
c Jenne Bleijenburg
Would I be turtle?

The language of my sister
We are a talking species, we need to grasp our life in words, in some mystical stuff we call 'meaning'. But my sister, I think, growing up in her speechless universe, gained some extra space in her brain just for images, reserved for just looking at things and people without the necessity to describe or explain it. This 'wordless' mode of looking at - and understanding - the world is what I think makes her work this powerful. 

Game of subscripts
I often play a game with her photographs: I try to think of subscripts that extend the image. The more I can think of, the better the image is.
But every subscript is a bit like raping the image, because the subscripts flatten the image as a meaningful object on its own.

Unwrapping the visible universe
The second important thing to know about my sister is that she would always guess what was in a present before unwrapping it. I do not credit her with telepathic powers or something like that, but she sees trails  in the universe that I don't.

c Jenne Bleijenburg
There 'll be dragons
Jennes elevator pitch
Jenne is looking for the states in the universe where the image escapes the narrative. 
She herself would never formulate it like this. But I think she should.

People and pots
Jenne started as an abstract painter, but switched to photography. In the beginning she made only still lifes, still lifes  like poems. A scarred bowl and a rusty pot, a shiny apple someone forgot to eat. The only thing moving in those pictures is time; time passed by.
Later on she started photographing people.
And I must say, I like the people best. Apples are for eating, bridges for crossing rivers, landscapes to get lost,  but people are for looking at, for relating to.
And with people she does the same as with the apples and the pots; she decides where the image is necessary. Jenne, on pointing her camera on these people, knows she is intruding. It makes her feel uncomfortable.
A person is not a pot. But that is exactly what you see in most of her work; she herself is always part of the image.
c Jenne Bleijenburg
The eye of god

The eye of god
Photography has the pretence of truth. The camera is like the eye of a god, being able to freeze any moment, analyze it, ponder on it, traverse it in all different directions and look at it from all angles and perspectives.
A photograph pretends to be time undressed, shameless and naked to the bone.
But it is not.
There is no truth in the image. Truth only exists in the mind. And the camera never sees what we see, or what the gods see. The camera is just a small machine.

Egbert Bleijenburg, groningen, juli 1 2013

Saturday, February 16, 2013

Access is King

I have a dream; That all man, black and white, yellow and brown, rich and poor, and especially the poor, will be connected to the web. Just as the roads are free for travelling, internet connection should be free. Should be considered to be a basic human right.
The web has become one of the main intellectual infrastructures of humanity. Just like the roads are the basic infrastructure of a country, and are therefore free to be used by anyone in the possession of legs, a bike, a car, so I think  access to the internet should be free for everyone.

1938, none of the events depicted here, 
have had any consequences for world war II
Life as cartoon character
I must admit I lack the knowledge to support this statement based on sound economic arguments. I studied physics and philosophy, and now I have this here webdevelopment-company. I usually barely understand what my accountant tells me. 
But I am convinced that the world will benefit should we decide to support this freedom of access. Akin to the OLPC project, the UN should flood the whole world with basic rechargable, reusable consoles. 
The web will feed an new enlightenment, just like the invention of the printing press fed the enlightment by flooding the market with a tsunami of affordable books.

There are billions of minds capable of becoming scholars, solving the unsolvable environmental and social problems.
Hiding connectivity from these masses on economic grounds, or on whatever ground, is like a man denying some parts his brains oxygen. (There could be economic sound reasons to do so...)
No one is his right mind would decide to do that. But that is just what we do to the world. 
Let's see the group of all our minds as the brains of the world: A large part is not, or barely, connected to the other part.
The world now behaves like a man with his corpus callossum dissected: Weird, and in hindsight perplexed about its own actions.
All these unconnected people, they are like cures for cancer, aids, malaria etcetera, written on paper and stored in sealed cannisters on the planet Xon234523.
They contribute to world development just as much as any cartoon character in a single comic from 1938.

A live without connection to the web is a live lost. Acces is King, and purpose and invention are its children. The internet is this great new toy, humanities one-stop-shop library, it's the parallel universe where we store all our knowledge(and porn of course). If all man are created equal, than all man should be given access, and the basic means to access this web. I believe then, and only then, the world will thrive and prosper.

Tuesday, January 22, 2013

The EU Directive 2009/136/EC virus

All sites in europe are now affected by a brand new virus known by its technical name "EU Directive 2009/136/EC".  Or more commonly known als the "Allow this site to use cookies" popup.

We want to place our cookies.
It's annoying. At least I think it is annoying. All sites ask me the same thing, over and over, in an autistic repetition that reminds of Dr. Christian Szell in Marathon Man. 
Is it save?
Is it save?
Is it save? 

Do you allow our cookies? Do you know our cookies? Do you love our cookies? Do you want our cookies?
They will enrich your experience!

No! It is not save. Yes it is save.

And we are all like little cyber versions of Dustin Hofmann. We don't know if it is save! We haven't got the slightest idea if we want this website to place its cookies! We most of the time don't care. We simply want to browse, browse, browse.....
I don't know about you, but as long as my virusscanners don't warn me for a site, I always click 'Ok' or 'Agree'.

Stupid solution
So there is a law. Ok, we have to deal with that.
A law is a law is a law is a law, as the poem goes. 
And for all purposes and intentions, it is a good law. The web is a dangerous place to be, spammers and vendors trying to analyze our inner thoughts and our deepest intentions, to make us buy their stuff, or for them to steal stuff from us.

But whoever thought up the solution to place the responsibility for compliance by all website owners? Not that that is a unreasonable choice, but what a waste of time!
Now hordes of developers and siteowners have to read the law, understand its implications, and try to design a way to comply. And the method of compliance is not a simple extraction proces, the law does not define specifications for compliance. You build something and hope you comply. Or better, you read a lot of discussions about how others are doing this, do a lot of copy paste, implement this and think you comply. Different solutions for all different implementations.
But all this development time would be time better spent trying to solve global warming, world hunger, read Wittgenstein or watch quiz-programs on tv. (If anyone still does that nowadays)

The good solution: An EU App
This one always agrees.
So, is there a better way to implement this law?
Yes, of course there is.
The EU should provide a browser App, along with the law itself,  that makes it possible for every user to easily see the cookies used on a site, to easily find info about the cookies used, and to easily allow or block these cookies, and remember this for ever and ever.
The App should be included in every new browser version, and in all minor upgrades.
Interface and interaction should be the same for all browsers.
When the EU should have funded development of this App, that would have been community money well spent because the distributed and parallel development of solutions for all specific cases is a waste of creative energy and time.
Time that should have been spent adding value to the web instead of compliance.

EU Directive 2009/136/EC

Wednesday, January 16, 2013


So, I will start a blog about my company.  

The reasons and objectives of this blog will be explained later.
Honestly:  Because I haven't got the faintest Idea of these objectives at the moment. 

The main motivation is that my work sometimes seems like sitting at the bottom of a very deep pit, working the machinery of a whole and exciting world above me. I work in the engine room of the web, and a simple blog is something on a deck of one of the cruisers.

This is what we do: We build software for the web that most of the time does not work, break down, crash, makes me wanna scream and tear my hair out. And then one of my clients calls me and I am totally confident that it will all work out. Yes, no problem, deadline will be adhered to, problems will be solved, mountains climbed, countries conquered. 
And in the end it always does work out. I solve the puzzle, or we solve the puzzle to be precise.

I build whole stories made of spaghetti-like modules that all knit together something that works. We xml, soap, php, parse, sql like these are verbs instead of nouns.  Whole days long, behind the little screens, sitting in awkward positions drinking coffee, talking jibberish and using google as a shoulder to cry on. Or as an older and wiser friend, but one who most of the time does not pay enough attention to my specific problems, or the exact context of my specific problems.

The web is a slippery environment: There are the different browsers, Operation systems, changing API's, services, dll's, changing scripting versions, preferred protocols et cetera.
Whatever works today may not work tomorrow. It sometimes feels like when you measure the height of a mountain wearing a blue hat, the height will differ from when you measure it wearing a red hat. Or it appears to be no mountain at all, but a valley, or a monkey, or the way an old man can look at girls passing by.....