arraypress/wp-language-utils

A lean WordPress library for language detection and locale handling

dev-main 2025-07-02 18:38 UTC

This package is auto-updated.

Last update: 2025-09-02 14:47:09 UTC


README

A lightweight WordPress library for detecting browser language preferences, handling WordPress locales, and managing RTL languages. Perfect for internationalization, user experience optimization, and content localization.

Features

  • 🎯 Clean API: WordPress-style snake_case methods with consistent interfaces
  • 🌐 Browser Detection: Parse Accept-Language headers with quality value support
  • 🔄 Locale Integration: Seamless WordPress locale to ISO 639-1 conversion
  • 📚 ISO Standards: Full ISO 639-1 and ISO 639-2 language code support
  • ↔️ RTL Support: Comprehensive RTL language detection (25+ languages)
  • 🎨 Quality Values: Parse language preferences with quality rankings
  • 🔧 WordPress Native: Integrates with get_locale() and WordPress i18n
  • 🛡️ Sanitized Input: All header parsing uses WordPress sanitization

Requirements

  • PHP 7.4 or later
  • WordPress 5.0 or later

Installation

composer require arraypress/wp-language-utils

Basic Usage

Browser Language Detection

// Get primary browser language
$language = Language::get();
// Returns: "en", "es", "fr", etc. or null if not found

// Get user language with WordPress fallback
$user_lang = Language::get_user_language();
// Returns: "en" (never null, defaults to English)

// Get full Accept-Language header
$header = Language::get_accept_language_header();
// Returns: "en-US,en;q=0.9,es;q=0.8,fr;q=0.7"

Language Preferences with Quality

// Get all accepted languages with quality values
$languages = Language::get_accepted_languages();
/*
Returns:
[
    'en' => 1.0,
    'es' => 0.8,
    'fr' => 0.7,
    'de' => 0.5
]
*/

// Use for content negotiation
foreach ( $languages as $lang => $quality ) {
	if ( $quality > 0.8 && has_translation( $lang ) ) {
		serve_content_in_language( $lang );
		break;
	}
}

WordPress Locale Integration

// Convert WordPress locale to ISO 639-1
$lang_code = Language::locale_to_iso639_1( 'es_ES' );
// Returns: "es"

// Convert ISO 639-1 to WordPress locale
$locale = Language::iso639_1_to_locale( 'es' );
// Returns: "es_ES" (first match)

// Check current WordPress locale
$current_lang = Language::locale_to_iso639_1( get_locale() );
// Returns: "en" for en_US, "fr" for fr_FR, etc.

RTL Language Detection

// Check if language is RTL
if ( Language::is_rtl( 'ar' ) ) {
	// Arabic is RTL
	add_theme_support( 'custom-logo' );
	wp_enqueue_style( 'rtl-styles', 'css/rtl.css' );
}

// Check user's language direction
$user_lang = Language::get_user_language();
if ( Language::is_rtl( $user_lang ) ) {
	// User prefers RTL language
	body_class( 'rtl-preferred' );
}

// RTL languages supported: ar, he, fa, ur, and 20+ more

ISO Language Code Conversion

// Convert between ISO 639-1 and ISO 639-2
$iso2 = Language::to_iso639_2( 'en' );
// Returns: "eng"

$iso1 = Language::to_iso639_1( 'eng' );
// Returns: "en"

// Validate language codes
if ( Language::is_valid_iso639_1( 'es' ) ) {
	// Valid 2-letter code
}

if ( Language::is_valid_iso639_2( 'spa' ) ) {
	// Valid 3-letter code
}

Comprehensive Language Info

// Get all language information at once
$info = Language::get_language_info();
/*
Returns:
[
    'code' => 'en',
    'iso639_2' => 'eng', 
    'locale' => 'en_US',
    'is_rtl' => false,
    'quality' => 1.0
]
*/

// For specific language
$spanish_info = Language::get_language_info( 'es' );

Common Use Cases

Smart Content Localization

function serve_localized_content() {
	$user_lang = Language::get_user_language();

	// Check if we have content in user's language
	$available_languages = [ 'en', 'es', 'fr', 'de' ];

	if ( in_array( $user_lang, $available_languages ) ) {
		switch_to_locale( Language::iso639_1_to_locale( $user_lang ) );
		load_theme_textdomain( 'theme', get_template_directory() . '/languages' );
	}

	// Handle RTL languages
	if ( Language::is_rtl( $user_lang ) ) {
		wp_enqueue_style( 'rtl-stylesheet', get_template_directory_uri() . '/rtl.css' );
	}
}

add_action( 'init', 'serve_localized_content' );

Language Negotiation for APIs

function negotiate_api_language() {
	$accepted  = Language::get_accepted_languages();
	$supported = [ 'en', 'es', 'fr', 'de', 'zh' ];

	// Find best match based on quality
	foreach ( $accepted as $lang => $quality ) {
		if ( in_array( $lang, $supported ) && $quality > 0.5 ) {
			return $lang;
		}
	}

	return 'en'; // Default fallback
}

// REST API endpoint
function my_api_endpoint( $request ) {
	$lang = negotiate_api_language();

	return [
		'message'  => get_localized_message( $lang ),
		'language' => $lang,
		'locale'   => Language::iso639_1_to_locale( $lang )
	];
}

Automatic RTL Theme Support

function setup_rtl_support() {
	$user_lang = Language::get_user_language();

	if ( Language::is_rtl( $user_lang ) ) {
		// Add RTL support
		add_theme_support( 'automatic-feed-links' );

		// Enqueue RTL styles
		add_action( 'wp_enqueue_scripts', function () {
			wp_enqueue_style( 'rtl-theme', get_template_directory_uri() . '/css/rtl.css' );
		} );

		// Add body class
		add_filter( 'body_class', function ( $classes ) {
			$classes[] = 'rtl-language';

			return $classes;
		} );
	}
}

add_action( 'after_setup_theme', 'setup_rtl_support' );

User Language Preference Detection

function detect_user_language_preference() {
	// Get browser language
	$browser_lang = Language::get();

	// Get WordPress locale language  
	$wp_lang = Language::locale_to_iso639_1( get_locale() );

	// Check if they match
	if ( $browser_lang && $browser_lang !== $wp_lang ) {
		// User's browser language differs from site language
		suggest_language_switch( $browser_lang );
	}
}

function suggest_language_switch( $suggested_lang ) {
	$locale = Language::iso639_1_to_locale( $suggested_lang );

	if ( $locale && is_locale_available( $locale ) ) {
		add_action( 'wp_footer', function () use ( $suggested_lang, $locale ) {
			echo '<div class="language-suggestion">';
			echo sprintf(
				__( 'Would you prefer to view this site in %s?', 'textdomain' ),
				get_language_name( $suggested_lang )
			);
			echo ' <a href="' . add_query_arg( 'lang', $locale ) . '">';
			echo __( 'Switch Language', 'textdomain' );
			echo '</a></div>';
		} );
	}
}

WooCommerce Currency by Language

function set_currency_by_language() {
	if ( ! class_exists( 'WooCommerce' ) ) {
		return;
	}

	$user_lang = Language::get_user_language();

	$currency_map = [
		'en' => 'USD',
		'es' => 'EUR',
		'fr' => 'EUR',
		'de' => 'EUR',
		'zh' => 'CNY',
		'ja' => 'JPY',
		'ko' => 'KRW'
	];

	if ( isset( $currency_map[ $user_lang ] ) ) {
		add_filter( 'woocommerce_currency', function () use ( $currency_map, $user_lang ) {
			return $currency_map[ $user_lang ];
		} );
	}
}

add_action( 'init', 'set_currency_by_language' );

Analytics Language Tracking

function track_visitor_language() {
	$info = Language::get_language_info();

	// Track language preferences
	$analytics_data = [
		'primary_language'  => $info['code'],
		'is_rtl'            => $info['is_rtl'],
		'browser_languages' => Language::get_accepted_languages(),
		'wp_locale'         => get_locale(),
		'timestamp'         => current_time( 'mysql' )
	];

	// Send to analytics or store in database
	update_option( 'language_analytics', $analytics_data );
}

add_action( 'wp_head', 'track_visitor_language' );

Content Direction Helper

function get_content_direction( $lang_code = null ) {
	$lang = $lang_code ?: Language::get_user_language();

	return Language::is_rtl( $lang ) ? 'rtl' : 'ltr';
}

// Use in templates
function enqueue_directional_styles() {
	$direction = get_content_direction();
	wp_enqueue_style(
		"theme-{$direction}",
		get_template_directory_uri() . "/css/{$direction}.css"
	);
}

add_action( 'wp_enqueue_scripts', 'enqueue_directional_styles' );

Supported Languages

RTL Languages (25+ supported)

  • Arabic (ar) - Including Egyptian, Moroccan variants
  • Hebrew (he)
  • Persian/Farsi (fa)
  • Urdu (ur)
  • Kurdish (ku, ckb, sdh)
  • Pashto (ps)
  • Sindhi (sd)
  • Uyghur (ug)
  • Yiddish (yi)
  • Divehi (dv)
  • And 15+ more regional RTL languages

WordPress Locale Support

  • 50+ locale mappings including regional variants
  • Major languages: en_US, es_ES, fr_FR, de_DE, zh_CN, ja, ko_KR
  • Regional variants: en_GB, es_MX, fr_CA, de_AT, zh_TW
  • Automatic extraction from unmapped locales

ISO Standard Support

  • ISO 639-1: 2-letter language codes (184 languages)
  • ISO 639-2: 3-letter language codes with full conversion
  • Quality values: RFC 2616 compliant Accept-Language parsing

Method Reference

Core Methods

  • get() - Get primary browser language from Accept-Language header
  • get_user_language() - Get user language with WordPress fallback
  • get_accept_language_header( string $default ) - Get raw Accept-Language header
  • get_accepted_languages() - Get all languages with quality values
  • get_language_info( ?string $code ) - Get comprehensive language information

Validation & Conversion

  • is_valid_iso639_1( string $code ) - Check if valid ISO 639-1 code
  • is_valid_iso639_2( string $code ) - Check if valid ISO 639-2 code
  • to_iso639_2( string $code ) - Convert ISO 639-1 to ISO 639-2
  • to_iso639_1( string $code ) - Convert ISO 639-2 to ISO 639-1

WordPress Integration

  • locale_to_iso639_1( string $locale ) - Convert WordPress locale to ISO 639-1
  • iso639_1_to_locale( string $code ) - Convert ISO 639-1 to WordPress locale

RTL Support

  • is_rtl( string $code ) - Check if language is Right-to-Left

WordPress Integration

  • Sanitized Input: All header parsing uses sanitize_text_field() and wp_unslash()
  • WordPress Fallback: Automatic fallback to get_locale() when browser detection fails
  • Theme Integration: Perfect for RTL theme support and content direction
  • Plugin Compatible: Works with WPML, Polylang, and other i18n plugins

Performance

  • Lightweight: Minimal overhead with efficient array lookups
  • Cached Results: Internal caching for repeated calls
  • Standards Compliant: RFC 2616 Accept-Language header parsing
  • Memory Efficient: Static arrays with optimized language mappings

Requirements

  • PHP 7.4+
  • WordPress 5.0+

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the GPL-2.0-or-later License.

Support