Translate a Drupal 7 custom module via l10n_update

It is really a big deal to manage translations of custom module in Drupal 7 expecially if you have a multisite installation.

Problem

We want use a .po file to translate a custom module programmatically, i.e. without forcing a redactor to do dangerous manual operations.

Furthermore we want have our module always accompained by its translations.

Solution

First of all we need to have l10n_update module installed.

Than we can declare the hook “l10n_update_projects_alter” which allow to set a remote path where the .po file is hosted.

Normally the path should be a remote, indipendent one, but in most cases we would like to have the .po file inside the website itself (i.e. not a separeted environment).

Take a look to the code below in which I declare a .po file that is in the module folder, in particular in “translations” subfolder.

As you can see the file name contains the parameter %language. In this case the filename would be ModuleName.LanguageCode.po.

/**
 * Alter the list of project to be updated by Localization Update.
 *
 * L10n_update uses the same list of projects as update module. Using this hook
 * the list can be altered. This hook is typically used to alter the following
 * values from the .info file:
 *  - interface translation project
 *  - l10n path.
 *
 * @param array $projects
 *   Array of projects.
 */
function my_module_name_l10n_update_projects_alter(array &$projects) {
  // Setting module name.
  $name = 'my_module_name';
  // Setting the path of .po files.
  $pathToModule = drupal_get_path('module', $name);
  $pathToPo = $pathToModule . '/translations/';
  $poFileName = $name . '.%language.po';
  // Getting url to po
  $urlToPoFolder = file_create_url($pathToPo);
  $urlToPoFile = $urlToPoFolder . $poFileName;

  /**
   * In case of S3 filesystem uncomment the code below.
   */
  // Instead of the default ftp.drupal.org we use the file system of the test
  // instance to simulate a remote file location.
  //$wrapper = file_stream_wrapper_get_instance_by_uri('public://');
  //$remote_url = $wrapper->getExternalUrl() . '/remote/';

  // With this hook it is also possible to add a new project which does not
  // exist as a real module or theme project but is treated by the localization
  // update module as one. The below data is the minimum to be specified.
  // As in the previous example the 'l10n path' element is optional.
  $projects[$name] = array(
    'project_type'  => 'module',
    'name' => $name,
    'info' => array(
      'name' => 'My Module name',
      'interface translation project' => $name,
      'version' => '7.x-1.0',
      'core' => '7.x',
      'l10n path' => $urlToPoFile,
    ),
  );
}

Furthermore with the following snippet, I have manually (i.e. programmatically) forced the module to update its translations.

// Getting dependencies.
module_load_include('inc','l10n_update','l10n_update.translation');
module_load_include('inc','l10n_update','l10n_update.fetch');


$projects = ['my_module_name'];


$options = _l10n_update_default_update_options();
$options['customized'] = true;
$options['use_remote'] = true;
$options['overwrite_options']['customized'] = true;

l10n_update_clear_status();
$batch = l10n_update_batch_update_build($projects, [], $options);
batch_set($batch);

The .po files have been extracted thanks to Translation Template Extractor.

Drupal 7 campi condizionali nei form con gli states

Oggi voglio presentarvi gli states degli elementi di un form Drupal.

Il problema

Vogliamo per un motivo o per un altro nascondere selettivamente dei campi in determinate condizioni, senza scrivere dei JS da aggiungere al form, massimizzando la manutenibilità del codice.

Tutto questo è consentito dagli states degli elementi del form di Drupal che consentono di inserire una logica con stati e condizioni in grado ad esempio di nascondere un campo se una checkbox è flaggata oppure mostrare un campo e renderlo obbligatorio.

Esempio:

Poniamoci nel caso in cui abbiamo un modulo di inserimento (un form insomma) di richieste di supporto in cui abbiamo un campo di tipo select chiamato “Oggetto” con varie opzioni selezionabili. Una di queste opzioni è “Altro”, se “Altro” è selezionato allora bisogna mostrare un campo (normalmente nascosto) chiamato “oggetto altro”.

Un codice di questo tipo risolve assolve al compito:

$form['subject_other'] = array(
  '#states' => array(
    // Show the subject_other if subject value is other.
    'visible' => array(
      ':input[name="subject"]' => array('value' => 'other'),
    ),
    'required' => array(
      ':input[name="subject"]' => array('value' => 'other'),
    ),
  ),
);

Interessante analizzare la funzione drupal_process_states poiché essa mostra tutti gli stati e le condizioni possibili, che per comodità riporto qui sotto:

I possibili stati di un elemento (del form) sono:

  • enabled
  • disabled
  • required
  • optional
  • visible
  • invisible
  • checked
  • unchecked
  • expanded
  • collapsed

Le possibili condizioni (che su drupal.org chiama remote conditions) sono:

  • empty
  • filled
  • checked
  • unchecked
  • expanded
  • collapsed
  • value

Gli stati che seguono possono essere utilizzati sia come stati di un elemento (primo gruppo) sia come condizioni remote (secondo gruppo):

  • relevant
  • irrelevant
  • valid
  • invalid
  • touched
  • untouched
  • readwrite
  • readonly

Tuttavia il funzionamento di quest’ultimo gruppo di stati non è garantito in ogni scenario, poiché le funzionalità che ne derivano sono molto dipendenti dal browser dal quale vengono eseguite.

Dalla versione 7.14 di Drupal è anche possibile usare OR e XOR.

Spero di essere stato utile.

NOTA: Un discorso del tutto analogo può essere fatto per Drupal 8 che, sebbene abbia stravolto la maggior parte delle funzionalità di Drupal 7, implementa questa degli states degli elementi del form in maniera similare.

Drupal 8 creare link html da file id (fid)

Per i nostalgici di Drupal 7 che hanno provato disperatamente a districarsi tra le varie classi introdotte in Drupal 8, ebbene sappiate che:

  1. per quello che può servire, godete della mia solidarietà
  2. dopo varie peripezie sono riuscito ad ottenere un codice utile a generare il famigerato html

Ecco il codice di esempio testato su Drupal 8.5.x

use Drupal\file\Entity\File;
use Drupal\Core\Link;
use Drupal\Core\Url;

$fid = 123; // <- your file id here

$uri = File::load($fid)->getFileUri();
$url = Url::fromUri(file_create_url($uri));
$link = Link::fromTextAndUrl('somestring', $url);
$link = $link->toRenderable();

print render($link); // <- this is HTML!!! YEAH!

spero che questo codice vi sia di aiuto.

Fatemi sapere, nei commenti, se questa cosa vi risolve il problema.