Multilingual content in Drupal 8: a highly evolved permutated API. DrupalCamp Vienna 2013 Francesco Placella



Similar documents
The truth about Drupal

How To Fix A Bug In Drupal 8.Dev

Entites in Drupal 8. Sascha Grossenbacher Christophe Galli

Drupal 8 The site builder's release

Linked Data Publishing with Drupal

Migrating into Drupal 8

MASTER DRUPAL 7 MODULE DEVELOPMENT

API Architecture. for the Data Interoperability at OSU initiative

The following is a comparison between CiviCRM, RedHen and CRM Core which are the leading option for CRM in the Drupal Community.

Drupal 8. Core and API Changes Shabir Ahmad MS Software Engg. NUST Principal Software Engineser PHP/Drupal

Everything you ever wanted to know about Drupal 8*

Who? Wolfgang Ziegler (fago) Klaus Purer (klausi) Sebastian Gilits (sepgil) epiqo Austrian based Drupal company Drupal Austria user group

Configuration Management in Drupal 8. Andrea Pescetti Nuvole

Drupal Module Development

A (Web) Face for Radio. NPR and Drupal7 David Moore

Migrating into Drupal 8 Migrando a Drupal 8

Faichi Solutions. The Changing Face of Drupal with Drupal 8

Data Warehouse and Business Intelligence Testing: Challenges, Best Practices & the Solution

Introduction to Module Development

Things Made Easy: One Click CMS Integration with Solr & Drupal

Simple Tips to Improve Drupal Performance: No Coding Required. By Erik Webb, Senior Technical Consultant, Acquia

Drupal Training Modules 2015

The Search API in Drupal 8. Thomas Seidl (drunken monkey)

Creating a Drupal 8 theme from scratch

Reference Model for Cloud Applications CONSIDERATIONS FOR SW VENDORS BUILDING A SAAS SOLUTION

Drupal and ArcGIS Yes, it can be done. Frank McLean Developer

Commerce Services Documentation

Advanced Object Oriented Database access using PDO. Marcus Börger

Magento Extension Developer s Guide

Table of Contents. Magento Certified Developer Exam Study Guide

How to pull content from the PMP into Core Publisher

WHAT'S NEW IN SHAREPOINT 2013 WEB CONTENT MANAGEMENT

J j enterpririse. Oracle Application Express 3. Develop Native Oracle database-centric web applications quickly and easily with Oracle APEX

Cache All The Things

Getting Started with Telerik Data Access. Contents

Magento Certified Developer Exam Exam: M70-101

#d8rules - Support the Rules module for Drupal 8

Drupal 8 Development Retrospective. A timeline and retrospective from a core contributor

PEGA MOBILITY A PEGA PLATFORM WHITEPAPER

A Data API for Drupal 7: Key steps to enabling transactional web service support

Simba Apache Cassandra ODBC Driver

Sage Intelligence Sage 100 ERP Intelligence Reporting Release Notes

Getting Content into Drupal Using Migrate

Beyond The Web Drupal Meets The Desktop (And Mobile) Justin Miller Code Sorcery Workshop, LLC

How is it helping? PragmatiQa XOData : Overview with an Example. P a g e Doc Version : 1.3

PHP Language Binding Guide For The Connection Cloud Web Services

Tobby Hagler, Phase2 Technology

MA-WA1920: Enterprise iphone and ipad Programming

Middleware- Driven Mobile Applications

Drupal for Designers

Beginning Oracle. Application Express 4. Doug Gault. Timothy St. Hilaire. Karen Cannell. Martin D'Souza. Patrick Cimolini

CHAPTER 1: CLIENT/SERVER INTEGRATED DEVELOPMENT ENVIRONMENT (C/SIDE)

Change Color for Export from Light Green to Orange when it Completes with Errors (31297)

Developing Microsoft SharePoint Server 2013 Advanced Solutions

Programmabilty. Programmability in Microsoft Dynamics AX Microsoft Dynamics AX White Paper

Building native mobile apps for Digital Factory

CTC What's New?

COURSE CONTENT Big Data and Hadoop Training

BUILDING MULTILINGUAL WEBSITES WITH DRUPAL 7

database abstraction layer database abstraction layers in PHP Lukas Smith BackendMedia

Frequently Asked Questions Sage Pastel Intelligence Reporting

Symfony vs. Integrating products when to use a framework

EnterpriseLink Benefits

Responsive Web Design. birds of feather

Course Code NCS2013: SharePoint 2013 No-code Solutions for Office 365 and On-premises

Android Developer Fundamental 1

Auditing Drupal sites for performance, content and optimal configuration

Database Programming with PL/SQL: Learning Objectives

Peer 1 Hosting Multisite

The Tiny Book of Rules

by

Financial Management System

SharePoint Checklist and Resources

Database Forms and Reports Tutorial

Configuring CQ Security

Programming in C# with Microsoft Visual Studio 2010

OpenText Information Hub (ihub) 3.1 and 3.1.1

Bubble Code Review for Magento

Business Application

External Network & Web Application Assessment. For The XXX Group LLC October 2012

Snare System Version Release Notes

XTM Drupal Connector. A Translation Management Tool Plugin

Ektron to EPiServer Digital Experience Cloud: Information Architecture

Author: Ryan J Adams. Overview. Central Management Server. Security. Advantages

How To Migrate Qi Analyst To A New Database On A Microsoft Access (Windows) From A New Version Of Qi.Io To A Newer Version Of A New Qi 8.0 (Windows 7.3

GETTING STARTED WITH DRUPAL. by Stephen Cross

Transcription:

Multilingual content in Drupal 8: a highly evolved permutated API DrupalCamp Vienna 2013 Francesco Placella

Francesco Placella // plach From Venice, Italy Studied at Ca' Foscari University Owner at PSEGNO Drupal since 2006 http://twitter.com/plach

Outline Drupal 7: a bit of history Drupal 8: entity API overview The content translation UI Entity storage and querying The entity translation API What's left?

D7 Field Language API Anatomy of field data $entity->{$field_name}[$langcode][$delta][$column] Field translatability $node->body['en'][0]['value'] $node->body['de'][0]['value'] $node->field_tags[language_none][0]['tid'] Field attach behavior all languages for storage single language for forms and view Good consistency vs bad DX

D7 Entity Language API Incomplete Entity API in core entity_language($langcode) Entity API module $entity_wrapper->language($langcode) $entity->gettranslation($property, $langcode = NULL) Entity Translation module CRUD hooks hook_entity_translation_insert(... ) hook_entity_translation_update(... ) hook_entity_translation_delete(... ) Spread in three places and inconsistent

D7 translation models Two competing approaches to translating content node translation (core) field translation (core API + contrib UI) https://drupal.org/project/entity_translation Why not node translation? only nodes problems with references sharing data across translations

D8 translation model Having two models in core is bad site builders have to choose one developers have to support both everyone has to understand both Increased cognitive / operative / maintenance burden The solution: an unified model every piece of entity data is translatable only one entity for each translation set

D8 Entity API Classed objects encapsulated data interfaces and swappable implementations More (swappable) controllers storage, form, translation, render, access, Entity Field API improved DX! unified API for fields (base / dynamic) field definitions (Typed Data API)

The Content Translation UI Content Content entity Applies to any translatable entity type Translatability has column granularity entity type bundle field column Exploits language-aware entity forms Is enhanced through translation controllers

Entity Storage... Every field needs to be translatable: how? D7 has just a one-off solution Title module D7 fields have native multilingual storage We need multilingual storage for every field The Entity Storage API per-entity storage instead of per-field storage storage-agnostic entities

and Querying No fixed storage layout for fields Data is retrieved by querying + loading Entity Query (EFQ v2) multiple / swappable query back-ends improved condition interface unified interface (similar to DBTNG) AND/OR condition groups support for joins and aggregation Entity caching and lazy-loading

Multilingual entity queries The Entity Query API does not make any assumption on language conditions $result = \Drupal::entityQuery('node') ->condition('promote', 1) ->condition('status', 1) ->execute(); // Nodes with one published/promoted translation $result = \Drupal::entityQuery('node') ->condition('promote', 1) ->condition('status', 1) ->condition('langcode', 'en') ->execute(); // Nodes with one english promoted translation $result = \Drupal::entityQuery('node') ->condition('promote', 1) ->condition('status', 1) ->condition('default_langcode', 1) ->execute(); // Nodes with promoted original values

Core SQL storage Dynamic fields still have per-field tables native multilingual support Base fields get a table layout supporting multilingual base table revision table (base) field data table (base) field revision data table Only the base table is required

SQL storage performance This table layout imposes a performance penalty on monolingual sites on query composite PKs, additional joins on save additional records stored How to mitigate that? automatically generate tables dynamically switch table layout Potential improvement by disabling (unused) revision support

The Entity Translation API Every entity translation is a different translation object (thanks @Crell) $value = $entity->foo->value; $translation = $entity->gettranslation('it'); $it_value = $translation->foo->value; Field language is no longer exposed in the public API Unified and streamlined existing APIs native hooks

Accessing field data We no longer need to worry about field translatability D7 // Determine the $active_langcode somehow. $field = field_info_field('field_foo'); $langcode = field_is_translatable($entity_type, $field)? $active_langcode : LANGUAGE_NONE; $value = $entity->field_foo[$langcode][0]['value']; D8 // Determine the $active_langcode somehow. $translation = $entity->gettranslation($active_langcode); $value = $translation->field_foo->value; The entity system handles it internally

The active language Translation objects are plain entity objects D7 function entity_do_stuff($entity, $langcode = NULL) { if (!isset($langcode)) { $langcode = $GLOBALS['language_content']->language; } $field = field_info_field('field_foo'); $langcode = field_is_translatable($entity_type, $field)? $langcode : LANGUAGE_NONE; if (!empty($entity->field_foo[$langcode])) { $value = $entity->field_foo[$langcode][0]['value']; // do stuff } } No need to pass along the active language

The active language (2) D8 $langcode = Drupal::languageManager() ->getlanguage(language::type_content); $translation = $entity->gettranslation($langcode); entity_do_stuff($translation); function entity_do_stuff(entityinterface $entity) { $value = $entity->field_foo->value; $langcode = $entity->language()->id; // do stuff } Just figure out the active language once No need to pass it along Language-agnostic code!

Determining the active language In D7 only features field language fallback function field_attach_view($entity_type, $entity, $view_mode, $langcode = NULL, $options = array()) { $display_language = field_language($entity_type, $entity, NULL, $langcode); $options['language'] = $display_language; $null = NULL; $output = _field_invoke_default('view', $entity_type, $entity, $view_mode, $null, $options); return $output; } field_language() makes sense / can be used only in rendering contexts if a field value is empty another value in a different language is picked

Determining the active language (2) D8 features a reusable entity language negotiation API public function viewentity(entityinterface $entity, $view_mode = 'full', $langcode = NULL) { $langcode = NULL; // Defaults to the current language $translation = $this->entitymanager ->gettranslationfromcontext($entity, $langcode); $build = entity_do_stuff($translation, 'full'); return $build; } negotiation is applied to the whole entity negotiation is alterable by modules empty values will just not be displayed

Determining the active language (3) A context can be provided function node_tokens($type, $tokens, array $data = array(), array $options = array()) { if (!isset($options['langcode'])) { $langcode = Language::LANGCODE_DEFAULT; } // The default operation is 'entity_view'. $context = array('operation' => 'node_tokens'); $translation = \Drupal::entityManager() ->gettranslationfromcontext( $data['node'], $langcode, $context ); $items = $translation->get('body'); // do stuff } the default behavior works correctly for rendering and forms

API use cases: shared data Field data is shared among all the translation objects $entity->langcode->value = 'en'; $translation = $entity->gettranslation('it'); $en_value = $entity->field_foo->value; $it_value = $translation->field_foo->value; $entity->field_untranslatable->value = 'foo'; $translation->field_untranslatable->value = 'bar'; $value = $entity->field_untranslatable->value; // $value is 'bar' Updated values are available for all the translation objects

API use cases: instantiating translations A translation object can be instantiated from any entity / translation object $entity->langcode->value = 'en'; $translation = $entity->gettranslation('it'); $langcode = $translation->language()->id; // $langcode is 'it'; $untranslated_entity = $translation->getuntranslated(); $langcode = $untranslated_entity->language()->id; // $langcode is 'en'; $identical = $entity === $untranslated_entity; // $identical is TRUE $entity_langcode = $translation->getuntranslated()->language()->id; // $entity_langcode is 'en'

API use cases: translation handling // Acting an all translations. $languages = $entity->gettranslationlanguages(); foreach ($languages as $langcode => $language) { $translation = $entity->gettranslation($langcode); entity_do_stuff($translation); } if (!$entity->hastranslation('fr')) { $translation = $entity ->addtranslation('fr', array('field_foo' => 'bag')); } // Which is equivalent to the following code, although if an // invalid language code is specified an exception is thrown. $translation = $entity->gettranslation('fr'); $translation->field_foo->value = 'bag'; // Accessing a field on a removed translation object causes an // exception to be thrown. $translation = $entity->gettranslation('it'); $entity->removetranslation('it'); $value = $translation->field_foo->value; // throws an exception

API use cases: storage hooks When entity translations are added to or removed from the storage the following hooks are fired respectively: hook_entity_translation_insert() hook_entity_translation_delete()

What is missing? Completing Entity Query conversion https://drupal.org/node/2068325 Dynamic SQL storage multilingual support for all core entity types https://drupal.org/node/1498720 Make base field definitions translatable https://drupal.org/node/2111887 (node) UX improvements

The Migration API Upgrade from D7 migrate node-based translations https://drupal.org/node/1952044 migrate field data https://drupal.org/node/2137917 (contrib) migrate Entity Translation data https://drupal.org/node/2073467 Support dynamic table layout switching when data is available? <g>

More links Entity Translation API https://drupal.org/node/2040323 Entity Storage https://drupal.org/node/1722906 http://bit.ly/1cbftu2 (Prague notes) Content Translation UI http://bit.ly/sjnfzw (celebration video)

Questions?

Thank you!