Comprehensive language and translation support for multilingual Drupal sites with configurable language handling, entity filtering, and translation management.
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'
],
},
},
}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")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:
defaultLanguagedefaultLanguage{langcode}.{id} or {typePrefix}.{langcode}.{id}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
]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/articleThe plugin handles:
filterByLanguages: trueOptional 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 requestsThe 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 languagesNon-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;
}# 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
}
}
}
}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
})
);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
],
}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'],
}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 onceWebhook 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 work with multilingual sites:
// FastBuilds sync respects language configuration
// Changed entities are processed with their language context
// Relationships maintain language consistencyinterface 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[]>;
}