Skip to content
wiki.fftac.org

Localevalidator

**Site relevance:** Antichrist.net

**Memory type:** plugin source memory

**Source path:** Antichrist.net/wp-content/plugins/uaix-locale-router/src/LocaleValidator.php

**Size:** 4 KB

Summary

namespace UAIXLocaleRouter;

Source Preview

This source file is short enough to preview directly on its source-memory page.

<?php

namespace UAIXLocaleRouter;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

final class LocaleValidator {
	/**
	 * Validate a BCP 47 style locale tag.
	 *
	 * @param string $tag Locale tag.
	 * @return bool
	 */
	public static function is_valid_locale_tag( $tag ) {
		$tag = trim( (string) $tag );

		return '' !== $tag
			&& strlen( $tag ) <= 64
			&& (bool) preg_match( '/^[A-Za-z]{2,8}(?:-[A-Za-z0-9]{2,8})*$/', $tag );
	}

	/**
	 * Canonicalize a locale tag.
	 *
	 * @param string $tag Locale tag.
	 * @return string
	 */
	public static function canonicalize_tag( $tag ) {
		$tag = str_replace( '_', '-', trim( (string) $tag ) );

		if ( '' === $tag ) {
			return '';
		}

		if ( strlen( $tag ) > 64 || ! preg_match( '/^[A-Za-z]{2,8}(?:-[A-Za-z0-9]{2,8})*$/', $tag ) ) {
			return '';
		}

		$parts = array_values( array_filter( explode( '-', $tag ), 'strlen' ) );

		if ( empty( $parts ) ) {
			return '';
		}

		$parts[0] = strtolower( $parts[0] );

		for ( $index = 1; $index < count( $parts ); $index++ ) {
			if ( 4 === strlen( $parts[ $index ] ) && ctype_alpha( $parts[ $index ] ) ) {
				$parts[ $index ] = ucfirst( strtolower( $parts[ $index ] ) );
			} elseif ( ( 2 === strlen( $parts[ $index ] ) && ctype_alpha( $parts[ $index ] ) ) || ( 3 === strlen( $parts[ $index ] ) && ctype_digit( $parts[ $index ] ) ) ) {
				$parts[ $index ] = strtoupper( $parts[ $index ] );
			} else {
				$parts[ $index ] = strtolower( $parts[ $index ] );
			}
		}

		return implode( '-', $parts );
	}

	/**
	 * Determine whether the locale is RTL.
	 *
	 * @param string $tag Locale tag.
	 * @return bool
	 */
	public static function is_rtl_locale( $tag ) {
		$language = strtolower( strtok( self::canonicalize_tag( $tag ), '-' ) );
		$rtl      = array( 'ar', 'arc', 'fa', 'he', 'ps', 'ur', 'ckb', 'ug', 'yi' );

		return in_array( $language, $rtl, true );
	}

	/**
	 * Normalize a supported locale record.
	 *
	 * @param array $record Locale record.
	 * @return array
	 */
	public static function normalize_supported_record( array $record ) {
		$tag = isset( $record['tag'] ) ? self::canonicalize_tag( $record['tag'] ) : '';

		return array(
			'tag'        => $tag,
			'urlTag'     => strtolower( str_replace( '_', '-', $tag ) ),
			'language'   => isset( $record['language'] ) ? (string) $record['language'] : $tag,
			'nativeName' => isset( $record['nativeName'] ) ? (string) $record['nativeName'] : $tag,
			'region'     => isset( $record['region'] ) ? (string) $record['region'] : self::extract_region( $tag ),
			'script'     => isset( $record['script'] ) ? (string) $record['script'] : self::extract_script( $tag ),
			'isRtl'      => isset( $record['isRtl'] ) ? (bool) $record['isRtl'] : self::is_rtl_locale( $tag ),
			'enabled'    => ! empty( $record['enabled'] ),
			'isDefault'  => ! empty( $record['isDefault'] ),
			'fallback'   => isset( $record['fallback'] ) ? self::canonicalize_tag( $record['fallback'] ) : $tag,
			'catalogHit' => isset( $record['catalogHit'] ) ? (bool) $record['catalogHit'] : false,
		);
	}

	/**
	 * Extract a region subtag.
	 *
	 * @param string $tag Locale tag.
	 * @return string
	 */
	public static function extract_region( $tag ) {
		$parts = explode( '-', self::canonicalize_tag( $tag ) );

		foreach ( $parts as $index => $part ) {
			if ( 0 === $index ) {
				continue;
			}

			if ( ( 2 === strlen( $part ) && ctype_alpha( $part ) ) || ( 3 === strlen( $part ) && ctype_digit( $part ) ) ) {
				return strtoupper( $part );
			}
		}

		return '';
	}

	/**
	 * Extract a script subtag.
	 *
	 * @param string $tag Locale tag.
	 * @return string
	 */
	public static function extract_script( $tag ) {
		$parts = explode( '-', self::canonicalize_tag( $tag ) );

		foreach ( $parts as $index => $part ) {
			if ( 0 === $index ) {
				continue;
			}

			if ( 4 === strlen( $part ) && ctype_alpha( $part ) ) {
				return ucfirst( strtolower( $part ) );
			}
		}

		return '';
	}
}