Catégories
Astuces et Design

Utilisation de Markdown et de la localisation dans l'éditeur de blocs WordPress

Si nous devons montrer la documentation à l'utilisateur directement dans l'éditeur WordPress, quelle est la meilleure façon de le faire?

L'éditeur de blocs étant basé sur React, nous pourrions être tentés d'utiliser des composants React et du code HTML pour la documentation. C'est l'approche que j'ai suivie dans mon article précédent, qui montrait un moyen d'afficher la documentation dans une fenêtre modale.

Mais cette solution n'est pas irréprochable, car l'ajout de documentation via des composants React et du code HTML pourrait devenir très verbeux, pour ne pas dire difficile à maintenir. Par exemple, le modal de l'image ci-dessus contient la documentation dans un composant React comme celui-ci:

const CacheControlDescription = () => {
  return (
    

The Cache-Control header will contain the minimum max-age value from all fields/directives involved in the request, or no-store if the max-age is 0

  ) }

Utiliser Markdown au lieu de HTML peut faciliter le travail. Par exemple, la documentation ci-dessus pourrait être déplacée hors du composant React et dans un fichier Markdown comme /docs/cache-control.md:

The Cache-Control header will contain the minimum max-age value from all fields/directives involved in the request, or `no-store` if the max-age is 0

Quels sont les avantages et les inconvénients de l'utilisation de Markdown par rapport au HTML pur?

Avantages Désavantages
✅ L'écriture de Markdown est plus facile et plus rapide que HTML ❌ La documentation ne peut pas contenir de composants React
✅ La documentation peut être conservée séparément du code source du bloc (même sur un dépôt séparé) ❌ Nous ne pouvons pas utiliser le __ fonction (qui permet de localiser le contenu à travers .po fichiers) pour afficher du texte
✅ Les éditeurs de copie peuvent modifier la documentation sans craindre de casser le code
✅ Le code de la documentation n'est pas ajouté à l'élément JavaScript du bloc, qui peut alors se charger plus rapidement

Concernant les inconvénients, ne pas pouvoir utiliser les composants React peut ne pas être un problème, du moins pour une documentation simple. Le manque de localisation, cependant, est un problème majeur. Texte dans le composant React ajouté via JavaScript __ La fonction peut être extraite et remplacée à l'aide de traductions à partir de fichiers POT. Le contenu de Markdown ne peut pas accéder à cette fonctionnalité.

La prise en charge de la localisation de la documentation est obligatoire, nous devrons donc la compenser. Dans cet article, nous poursuivrons deux objectifs:

  • Utilisation de Markdown pour écrire de la documentation (affichée par un bloc de l'éditeur WordPress)
  • Traduire la documentation dans la langue de l’utilisateur

Commençons!

Chargement du contenu Markdown

Avoir créé un fichier Markdown /docs/cache-control.md, nous pouvons importer son contenu (déjà rendu au format HTML) et l'injecter dans le composant React comme ceci:

import CacheControlDocumentation from '../docs/cache-control.md';


const CacheControlDescription = () => {
  return (
    
  ); }

Cette solution repose sur webpack, le bundler de modules situé au cœur de l'éditeur WordPress.

Veuillez noter que l'éditeur WordPress utilise actuellement le webpack 4.42, cependant, la documentation affichée en amont sur le site de webpack correspond à la version 5 (qui est toujours en beta). La documentation de la version 4 se trouve dans un sous-site.

Le contenu est transformé de Markdown en HTML via les chargeurs de webpack, pour lesquels le bloc doit personnaliser sa configuration Webpack, en ajoutant les règles pour utiliser markdown-loader et html-loader.

Pour ce faire, ajoutez un fichier, webpack.config.js, à la racine du bloc avec ce code:

// This is the default webpack configuration from Gutenberg
const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );


// Customize adding the required rules for the block
module.exports = {
  ...defaultConfig,
  module: {
    ...defaultConfig.module,
    rules: (
      ...defaultConfig.module.rules,
      {
        test: /.md$/,
        use: (
          {
            loader: "html-loader"
          },
          {
            loader: "markdown-loader"
          }
        )
      }
    ),
  },
};

Et installez les packages correspondants:

npm install --save-dev markdown-loader html-loader

Appliquons une petite amélioration pendant que nous y sommes. Le dossier docs peut contenir la documentation des composants situés n'importe où dans le projet. Pour ne pas avoir à calculer le chemin relatif de chaque composant vers ce dossier, nous pouvons ajouter un alias, @docs, dans webpack.config.js résoudre le dossier /docs:

const path = require( 'path' );
config.resolve.alias( '@docs' ) = path.resolve( process.cwd(), 'docs/' )

Désormais, les importations sont simplifiées:

import CacheControlDocumentation from '@docs/cache-control.md';

C'est tout! Nous pouvons maintenant injecter de la documentation à partir de fichiers Markdown externes dans le composant React.

Traduire la documentation dans la langue de l’utilisateur

Nous ne pouvons pas traduire les chaînes via .po pour le contenu Markdown, mais il existe une alternative: produire différents fichiers Markdown pour différentes langues. Ensuite, au lieu d'avoir un seul fichier (/docs/cache-control.md), nous pouvons avoir un fichier par langue, chacun stocké sous le code de langue correspondant:

  • /docs/en/cache-control.md
  • /docs/fr/cache-control.md
  • /docs/zh/cache-control.md
  • etc.

Nous pourrions également prendre en charge les traductions pour les deux langues et région, de sorte que l'anglais américain et britannique puissent avoir des versions différentes, et par défaut la version linguistique uniquement lorsqu'une traduction pour une région n'est pas fournie (par ex. "en_CA" est géré par "en"):

  • /docs/en_US/cache-control.md
  • /docs/en_GB/cache-control.md
  • /docs/en/cache-control.md

Pour simplifier les choses, je vais seulement expliquer comment prendre en charge différentes langues, sans régions. Mais le code est à peu près le même.

Le code démontré dans cet article peut également être vu dans le code source d'un plugin WordPress que j'ai créé.

Fournir la langue de l'utilisateur au bloc

La langue de l'utilisateur dans WordPress peut être récupérée à partir de get_locale(). Étant donné que les paramètres régionaux incluent le code de langue et la région (comme "en_US"), nous l'analysons pour extraire le code du langage par lui-même:

function get_locale_language(): string 
{
  $localeParts = explode( '_', get_locale() );
  return $localeParts(0);
}

À travers wp_localize_script(), nous fournissons le code de langue au bloc, comme le userLang propriété sous une variable globale (qui, dans ce cas, est graphqlApiCacheControl):

// The block was registered as $blockScriptRegistrationName
wp_localize_script(
  $blockScriptRegistrationName,
  'graphqlApiCacheControl',
  (
    'userLang' => get_locale_language(),
  )
);

Le code de langue de l'utilisateur est désormais disponible sur le bloc:

const lang = window.graphqlApiCacheControl.userLang; 

Importations dynamiques

Nous ne pouvons connaître la langue de l'utilisateur qu'au moment de l'exécution. Cependant, le import la déclaration est statique, pas dynamique. Par conséquent, nous ne pouvons pas faire ceci:

// `lang` contains the user's language
import CacheControlDocumentation from '@docs/${ lang }/cache-control.md';

Cela dit, webpack nous permet de charger dynamiquement des modules via le import fonction qui, par défaut, divise le module demandé en un bloc séparé (c'est-à-dire qu'il n'est pas inclus dans le principal compilé build/index.js fichier) à charger paresseusement.

Ce comportement convient pour afficher la documentation sur une fenêtre modale, qui est déclenchée par une action de l'utilisateur et non chargée à l'avance. import doit recevoir des informations sur l'emplacement du module, donc ce code fonctionne:

import( `@docs/${ lang }/cache-control.md` ).then( module => {
  // ...
});

Mais ce code apparemment similaire ne permet pas:

const dynamicModule = `@docs/${ lang }/cache-control.md`
import( dynamicModule ).then( module => {
  // ...
});

Le contenu du fichier est accessible sous clé default de l'objet importé:

const cacheControlContent = import( `@docs/${ lang }/cache-control.md` ).then( obj => obj.default )

Nous pouvons généraliser cette logique dans une fonction appelée getMarkdownContent, en passant le nom du fichier Markdown à côté de la langue:

const getMarkdownContent = ( fileName, lang ) => {
  return import( `@docs/${ lang }/${ fileName }.md` )
    .then( obj => obj.default )
} 

Gérer les morceaux

Pour garder les éléments de bloc organisés, gardons les blocs de documentation groupés dans le /docs sous-dossier (à créer dans le build/ dossier) et donnez-leur des noms de fichiers descriptifs.

Ensuite, avoir deux documents (cache-control.md et cache-purging.md) en trois langues (anglais, français et chinois mandarin), les morceaux suivants seront produits:

  • build/docs/en-cache-control-md.js
  • build/docs/fr-cache-control-md.js
  • build/docs/zh-cache-control-md.js
  • build/docs/en-cache-purging-md.js
  • build/docs/fr-cache-purging-md.js
  • build/docs/zh-cache-purging-md.js

Ceci est accompli en utilisant le commentaire magique /* webpackChunkName: "docs/(request)" */ juste avant le import argument:

const getMarkdownContent = ( fileName, lang ) => {
  return import( /* webpackChunkName: "docs/(request)" */ `@docs/${ lang }/${ fileName }.md` )
    .then(obj => obj.default)
} 

Définition du chemin public pour les blocs

webpack sait où récupérer les morceaux, grâce au publicPath option de configuration. S'il n'est pas fourni, l'URL actuelle de l'éditeur WordPress, /wp-admin/, est utilisé, produisant un 404 puisque les morceaux sont situés ailleurs. Pour mon bloc, ils sont sous /wp-content/plugins/graphql-api/blocks/cache-control/build/.

Si le bloc est pour notre propre usage, nous pouvons coder en dur publicPath dans webpack.config.js, ou fournissez-le via un ASSET_PATH variable d'environnement. Sinon, nous devons transmettre le chemin public au bloc lors de l'exécution. Pour ce faire, nous calculons l'URL du bloc build/ dossier:

$blockPublicPath = plugin_dir_url( __FILE__ ) . '/blocks/cache-control/build/';

Ensuite, nous l'injectons du côté JavaScript en localisant le bloc:

// The block was registered as $blockScriptRegistrationName
wp_localize_script(
    $blockScriptRegistrationName,
    'graphqlApiCacheControl',
    (
      //...
      'publicPath' => $blockPublicPath,
    )
);

Et puis nous fournissons le chemin public vers le __webpack_public_path__ Variable JavaScript:

__webpack_public_path__ = window.graphqlApiCacheControl.publicPath;

Revenir à une langue par défaut

Que se passerait-il s'il n'y avait pas de traduction pour la langue de l'utilisateur? Dans ce cas, appeler getMarkdownContent lancera une erreur.

Par exemple, lorsque la langue est définie sur l'allemand, la console du navigateur affichera ceci:

Uncaught (in promise) Error: Cannot find module './de/cache-control.md'

La solution est d'attraper l'erreur puis de renvoyer le contenu dans une langue par défaut, qui est toujours satisfaite par le bloc:

const getMarkdownContentOrUseDefault = ( fileName, defaultLang, lang ) => {
  return getMarkdownContent( fileName, lang )
    .catch( err => getMarkdownContent( fileName, defaultLang ) )
}

Veuillez noter le comportement différent du codage de la documentation en HTML dans le composant React et en tant que fichier Markdown externe, lorsque la traduction est incomplète. Dans le premier cas, si une chaîne a été traduite mais qu'une autre ne l'a pas été (dans le .po file), le composant React finira par afficher des langues mixtes. C’est tout ou rien dans le second cas: soit la documentation est entièrement traduite, soit elle ne l’est pas.

Mettre la documentation dans le modal

À présent, nous pouvons récupérer la documentation à partir du fichier Markdown. Voyons comment l'afficher dans le modal.

Nous emballons d'abord Gutenberg Modal composant, pour injecter le contenu au format HTML:

import { Modal } from '@wordpress/components';


const ContentModal = ( props ) => {
  const { content } = props;
  return (
    
      
      ); };

Ensuite, nous récupérons le contenu du fichier Markdown et le passons au modal en tant que prop en utilisant un hook d'état appelé page. Le chargement dynamique du contenu est une opération asynchrone, nous devons donc également utiliser un hook d'effet pour effectuer un effet secondaire dans le composant. Nous devons lire le contenu du fichier Markdown une seule fois, nous passons donc un tableau vide comme second argument à useEffect (ou le crochet continuerait à se déclencher):

import { useState, useEffect } from '@wordpress/element';

const CacheControlContentModal = ( props ) => {
  const fileName = 'cache-control'
  const lang = window.graphqlApiCacheControl.userLang
  const defaultLang = 'en'


  const ( page, setPage ) = useState( () );


  useEffect(() => {
    getMarkdownContentOrUseDefault( fileName, defaultLang, lang ).then( value => {
      setPage( value )
    });
  }, () );


  return (
    
  );
};

Voyons que cela fonctionne. Veuillez noter comment le bloc contenant la documentation est chargé paresseusement (c'est-à-dire qu'il est déclenché lorsque le bloc est édité):

Tadaaaaaaaa 🎉

La rédaction de documentation n'est peut-être pas votre chose préférée dans le monde, mais la rendre facile à écrire et à maintenir peut vous aider à vous en débarrasser.

Utiliser Markdown au lieu du HTML pur est certainement une façon de le faire. J'espère que l'approche que nous venons de décrire améliore non seulement votre flux de travail, mais vous apporte également une belle amélioration pour vos utilisateurs de WordPress.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *