or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

configuration.mddata-sourcing.mdfile-handling.mdincremental-builds.mdindex.mdmultilingual.md
tile.json

multilingual.mddocs/

Multilingual Support

Comprehensive language and translation support for multilingual Drupal sites with configurable language handling, entity filtering, and translation management.

Capabilities

Language Configuration

Complete language configuration for multilingual sites with translation support and language code handling.

/**
 * Language configuration for multilingual Drupal sites
 */
interface LanguageConfig {
  /** Default language code (required) */
  defaultLanguage: string;
  /** Array of enabled language codes or renamed language objects (required) */
  enabledLanguages: (string | RenamedLangCode)[];
  /** Filter API responses by current language (optional) */
  filterByLanguages?: boolean;
  /** Entity types that support translation (required) */
  translatableEntities: string[];
  /** Entity types that don't support translation (required) */
  nonTranslatableEntities: string[];
}

interface RenamedLangCode {
  /** Original Drupal language code */
  langCode: string;
  /** Alias to use in Gatsby */
  as: string;
}

Usage Examples:

{
  resolve: `gatsby-source-drupal`,
  options: {
    baseUrl: `https://multilingual-site.com/`,
    languageConfig: {
      defaultLanguage: 'en',
      enabledLanguages: [
        'en',      // English
        'fr',      // French  
        'es',      // Spanish
        'de',      // German
        // Renamed language code
        {
          langCode: 'en-gb',  // Drupal language code
          as: 'uk'           // Use 'uk' in Gatsby
        }
      ],
      filterByLanguages: true, // Filter API responses by language
      translatableEntities: [
        'node--article',
        'node--page', 
        'taxonomy_term--category'
      ],
      nonTranslatableEntities: [
        'file--file',
        'user--user',
        'taxonomy_term--tags'
      ],
    },
  },
}

Renamed Language Code Support

Handle language codes that differ between Drupal and your Gatsby site structure.

/**
 * Renamed language code mapping
 * Allows using different language codes in Gatsby than in Drupal
 */
interface RenamedLangCode {
  langCode: string; // Original Drupal language code
  as: string;       // Alias to use in Gatsby
}

Usage Examples:

// Configuration with renamed languages
languageConfig: {
  defaultLanguage: 'en',
  enabledLanguages: [
    'en',
    'fr',
    {
      langCode: 'zh-hans', // Drupal uses simplified Chinese
      as: 'cn'            // Gatsby uses 'cn' for URLs/routing
    },
    {
      langCode: 'pt-br',   // Drupal Brazilian Portuguese
      as: 'br'            // Gatsby uses 'br'
    }
  ],
  // ... other config
}

// Results in node IDs like:
// - English: "en.article-123"
// - Chinese: "cn.article-123" (instead of "zh-hans.article-123")
// - Portuguese: "br.article-123" (instead of "pt-br.article-123")

Language-Aware Node ID Generation

Node IDs are created with language codes to maintain proper separation of translated content.

/**
 * Creates versioned node ID with language code support
 * Handles language fallbacks and renamed language codes
 */
function createNodeIdWithVersion(params: {
  id: string;
  type: string;
  langcode: string;
  revisionId?: string;
  entityReferenceRevisions: string[];
  typePrefix?: string;
}): string;

Language handling logic:

  • Non-translatable entities use defaultLanguage
  • Renamed language codes are converted to their alias
  • Disabled languages fall back to defaultLanguage
  • Default format: {langcode}.{id} or {typePrefix}.{langcode}.{id}

Translation Entity Filtering

Configure which entity types support translation to optimize data fetching and node creation.

/**
 * Entity types that support translation
 * These entities will be fetched for each enabled language
 */
translatableEntities: string[];

/**
 * Entity types that don't support translation  
 * These entities use the default language regardless of context
 */
nonTranslatableEntities: string[];

Usage Examples:

// Typical translatable entities
translatableEntities: [
  'node--article',           // Articles
  'node--page',             // Basic pages
  'node--product',          // Products
  'taxonomy_term--category', // Categories
  'menu_link_content--main' // Menu items
]

// Typical non-translatable entities
nonTranslatableEntities: [
  'file--file',             // Files
  'user--user',             // Users
  'taxonomy_term--tags',    // Tags (if not translated)
  'webform--contact'        // Forms
]

Language-Specific API Requests

The plugin makes separate API requests for each language to ensure complete translation coverage.

/**
 * Language-aware API URL construction
 * Builds URLs with language prefixes for translatable entities
 */
// For default language: /jsonapi/node/article
// For other languages: /{langcode}/jsonapi/node/article
// Unless baseUrl already includes language: /en/jsonapi/node/article

The plugin handles:

  • Default language at root URL
  • Language-prefixed URLs for translations
  • Sites with language in base URL
  • Language-specific filtering when filterByLanguages: true

Content Filtering by Language

Optional filtering to fetch only content in specific languages on each request.

/**
 * Filter API responses by current language
 * When true, only content matching the current request language is returned
 */
filterByLanguages?: boolean;

Usage Examples:

// Without filtering - all languages fetched per request
filterByLanguages: false, // Default
// Results in larger API responses but complete data

// With filtering - only current language per request  
filterByLanguages: true,
// Results in smaller API responses, more targeted requests

Language Detection and Fallbacks

Language Code Normalization

The plugin normalizes language codes to ensure consistency across the system:

// Language normalization process:
// 1. Check if entity type is non-translatable -> use defaultLanguage
// 2. Check for renamed language codes -> use alias
// 3. Check if language is enabled -> use as-is
// 4. Fallback to defaultLanguage for disabled languages

Non-Translatable Entity Handling

Non-translatable entities always use the default language to prevent null results:

// File entities don't translate, so always use default language
if (options?.languageConfig?.nonTranslatableEntities?.includes(type) &&
    options.languageConfig.defaultLanguage) {
  langcode = options.languageConfig.defaultLanguage;
}

Multilingual Query Patterns

Querying Translated Content

# Query all articles (all languages)
{
  allNodeArticle {
    nodes {
      title
      langcode
      path {
        alias
      }
    }
  }
}

# Query articles in specific language
{
  allNodeArticle(filter: { langcode: { eq: "fr" } }) {
    nodes {
      title
      body {
        processed
      }
    }
  }
}

# Query with language fallback logic
{
  allNodeArticle(filter: { langcode: { in: ["fr", "en"] } }) {
    nodes {
      title
      langcode
      # Relationships work across languages
      author___NODE {
        name
      }
    }
  }
}

Language-Aware Relationships

Relationships are resolved with language context:

// Relationship processing considers root node language
const rootNodeLanguage = getOptions().languageConfig ? node.langcode : 'und';

// Referenced nodes use the same language context
const referencedNodeId = createNodeId(
  createNodeIdWithVersion({
    id: data.id,
    type: data.type,
    langcode: rootNodeLanguage,
    // ... other params
  })
);

Advanced Configuration Patterns

Mixed Language Sites

For sites with both translated and non-translated content:

languageConfig: {
  defaultLanguage: 'en',
  enabledLanguages: ['en', 'fr', 'es'],
  filterByLanguages: false, // Get all translations in single requests
  translatableEntities: [
    'node--article',     // Articles are translated
    'node--page',        // Pages are translated
  ],
  nonTranslatableEntities: [
    'node--product',     // Products not translated (English only)
    'file--file',        // Files never translated
    'user--user',        // Users not translated
  ],
}

Regional Language Variants

Handle regional language variants with renamed codes:

languageConfig: {
  defaultLanguage: 'en',
  enabledLanguages: [
    'en',                    // Default English
    { langCode: 'en-gb', as: 'en_uk' },  // UK English
    { langCode: 'en-au', as: 'en_au' },  // Australian English
    { langCode: 'fr-ca', as: 'fr_ca' },  // Canadian French
    'fr',                    // Standard French
  ],
  filterByLanguages: true, // Separate requests per region
  translatableEntities: ['node--article'],
  nonTranslatableEntities: ['file--file'],
}

Performance Considerations

Language configuration affects build performance:

// More languages = more API requests
enabledLanguages: ['en', 'fr', 'es', 'de', 'it'], // 5x API requests

// Filtering reduces response size but increases request count
filterByLanguages: true, // Smaller responses, more requests
filterByLanguages: false, // Larger responses, fewer requests

// Entity type configuration affects request patterns
translatableEntities: ['node--article'], // Only articles get language variants
nonTranslatableEntities: ['file--file'], // Files requested once

Language Migration and Updates

Webhook Language Handling

Webhook updates preserve language context:

// Webhook updates use entity's language code
const newNodeId = createNodeId(
  createNodeIdWithVersion({
    id: nodeToUpdate.id,
    type: nodeToUpdate.type,
    langcode: getOptions().languageConfig ? nodeToUpdate.langcode : 'und',
    // ... other params
  })
);

FastBuilds Language Support

FastBuilds work with multilingual sites:

// FastBuilds sync respects language configuration
// Changed entities are processed with their language context
// Relationships maintain language consistency

Types

interface LanguageConfig {
  defaultLanguage: string;
  enabledLanguages: (string | RenamedLangCode)[];
  renamedEnabledLanguages?: RenamedLangCode[]; // Internal processing
  filterByLanguages?: boolean;
  translatableEntities: string[];
  nonTranslatableEntities: string[];
}

interface RenamedLangCode {
  langCode: string;
  as: string;
}

interface MultilingualNode extends GatsbyNode {
  langcode: string;
  // Relationships can reference nodes in any language
  relationships: Record<string, string | string[]>;
}