Skip to content
wiki.fftac.org

Dictionaryrepository - Source Excerpt 01

Back to Dictionaryrepository

Summary

This source excerpt preserves a bounded section of Antichrist.net/wp-content/plugins/uaix-locale-router/src/DictionaryRepository.php so readers can inspect the evidence without opening the full source file.

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

<?php

namespace UAIXLocaleRouter;

use UAIXLocaleRouter\Support\Json;


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

final class DictionaryRepository {
	/**
	 * Per-request dictionary cache keyed by locale and content hash.
	 *
	 * @var array
	 */
	private static $dictionary_cache = array();

	/**
	 * Per-request file hash cache keyed by file path, mtime, and size.
	 *
	 * @var array
	 */
	private static $file_hash_cache = array();

	/**
	 * Register translation filters.
	 *
	 * @return void
	 */
	public static function register() {
		add_filter( 'the_content', array( __CLASS__, 'render_content_tokens' ), 9 );
		add_filter( 'nav_menu_item_title', array( __CLASS__, 'translate_nav_menu_item_title' ), 20, 4 );
	}

	/**
	 * Translate a key in the active locale.
	 *
	 * @param string $key Dictionary key.
	 * @param string $fallback Fallback text.
	 * @return string
	 */
	public static function translate( $key, $fallback = '' ) {
		$key        = trim( (string) $key );
		$active_tag = LocaleRepository::wp_locale_to_tag( determine_locale() );

		if ( '' === $active_tag ) {
			$active_tag = LocaleRepository::get_default_locale();
		}

		$dictionary = self::load_locale_dictionary( $active_tag );

		if ( isset( $dictionary['strings'][ $key ] ) && is_string( $dictionary['strings'][ $key ] ) && '' !== $dictionary['strings'][ $key ] ) {
			return $dictionary['strings'][ $key ];
		}

		$fallback_tag = self::resolve_fallback_locale( $active_tag, $dictionary );

		if ( $fallback_tag && $fallback_tag !== $active_tag ) {
			$fallback_dictionary = self::load_locale_dictionary( $fallback_tag );

			if ( isset( $fallback_dictionary['strings'][ $key ] ) && is_string( $fallback_dictionary['strings'][ $key ] ) && '' !== $fallback_dictionary['strings'][ $key ] ) {
				return $fallback_dictionary['strings'][ $key ];
			}
		}

		$template = self::load_template_dictionary();

		if ( isset( $template['strings'][ $key ] ) && is_string( $template['strings'][ $key ] ) && '' !== $template['strings'][ $key ] ) {
			return $template['strings'][ $key ];
		}

		return (string) $fallback;
	}

	/**
	 * Translate and interpolate a key.
	 *
	 * @param string $key Dictionary key.
	 * @param array  $replacements Placeholder replacements.
	 * @param string $fallback Fallback text.
	 * @return string
	 */
	public static function translate_format( $key, array $replacements = array(), $fallback = '' ) {
		$value = self::translate( $key, $fallback );

		foreach ( $replacements as $name => $replacement ) {
			$value = str_replace( '{' . $name . '}', (string) $replacement, $value );
		}

		return $value;
	}

	/**
	 * Load a locale dictionary.
	 *
	 * @param string $locale_tag Locale tag.
	 * @return array
	 */
	public static function load_locale_dictionary( $locale_tag ) {
		$locale_tag = LocaleValidator::canonicalize_tag( $locale_tag );
		$manifest   = self::dictionary_manifest();
		$file_paths = self::dictionary_candidate_paths( $locale_tag );
		$file_hash  = self::dictionary_cache_hash( $file_paths, isset( $manifest[ $locale_tag ]['fileHash'] ) ? (string) $manifest[ $locale_tag ]['fileHash'] : 'missing' );
		$cache_key  = 'uaixlr_dict_' . md5( $locale_tag . ':' . $file_hash );
		$cached     = wp_cache_get( $cache_key, 'uaixlr' );

		if ( isset( self::$dictionary_cache[ $cache_key ] ) ) {
			return self::$dictionary_cache[ $cache_key ];
		}

		if ( is_array( $cached ) ) {
			self::$dictionary_cache[ $cache_key ] = $cached;

			return $cached;
		}

		$dictionary = self::empty_dictionary( $locale_tag );
		$file_path  = '';

		foreach ( $file_paths as $candidate_path ) {
			$candidate = self::read_runtime_dictionary( $candidate_path, $locale_tag );

			if ( empty( $candidate['strings'] ) ) {
				continue;
			}

			$dictionary = self::merge_runtime_dictionaries( $dictionary, $candidate );
			$file_path  = $candidate_path;
		}

		$dictionary = apply_filters( 'uaixlr_locale_dictionary', $dictionary, $locale_tag, $file_path );
		if ( ! is_array( $dictionary ) || ! isset( $dictionary['strings'] ) || ! is_array( $dictionary['strings'] ) ) {
			$dictionary = self::empty_dictionary( $locale_tag );
		}

		wp_cache_set( $cache_key, $dictionary, 'uaixlr' );
		self::$dictionary_cache[ $cache_key ] = $dictionary;

		return $dictionary;
	}

	/**
	 * Load the template dictionary.
	 *
	 * @return array
	 */
	public static function load_template_dictionary() {
		return TranslationCatalog::build_runtime_dictionary();
	}

	/**
	 * Replace content tokens in post content.
	 *
	 * @param string $content Rendered content.
	 * @return string
	 */
	public static function render_content_tokens( $content ) {
		if ( ! is_string( $content ) || '' === $content || false === strpos( $content, '{{' ) ) {
			return $content;
		}

		return preg_replace_callback(
			'/\{\{\s*([a-zA-Z0-9._-]+)\s*\}\}/',
			static function ( $matches ) {
				$key = isset( $matches[1] ) ? (string) $matches[1] : '';

				return esc_html( self::translate( $key, $key ) );
			},
			$content
		);
	}

	/**
	 * Translate saved WordPress menu titles when their URL maps to a known navigation key.
	 *
	 * @param string $title Menu item title.
	 * @param object $menu_item Menu item object.
	 * @param object $args Menu args.
	 * @param int    $depth Menu depth.
	 * @return string
	 */
	public static function translate_nav_menu_item_title( $title, $menu_item = null, $args = null, $depth = 0 ) {
		unset( $args, $depth );

		if ( is_admin() ) {
			return $title;
		}

		$fallback = trim( wp_strip_all_tags( (string) $title ) );

		if ( '' === $fallback ) {
			return $title;
		}

		$key = self::navigation_dictionary_key_for_menu_item( $menu_item, $fallback );

		if ( '' === $key ) {
			return $title;
		}

		return self::translate( $key, $fallback );
	}

	/**
	 * Resolve a menu item URL/title to a dictionary key.
	 *
	 * @param object $menu_item Menu item object.
	 * @param string $fallback Existing title.
	 * @return string
	 */
	private static function navigation_dictionary_key_for_menu_item( $menu_item, $fallback ) {
		$path = '';

		if ( is_object( $menu_item ) ) {
			if ( isset( $menu_item->type, $menu_item->object, $menu_item->object_id ) && 'post_type' === $menu_item->type && 'page' === $menu_item->object ) {
				$page = get_post( (int) $menu_item->object_id );

				if ( $page instanceof \WP_Post ) {
					$path = get_page_uri( $page );
				}
			}

			if ( '' === $path && isset( $menu_item->url ) ) {
				$path = self::navigation_path_from_url( (string) $menu_item->url );
			}
		}

		$key = self::navigation_dictionary_key_for_path( $path );

		if ( '' !== $key ) {
			return $key;
		}

		return self::navigation_dictionary_key_for_title( $fallback );
	}

	/**
	 * Normalize a menu URL to a site path.
	 *
	 * @param string $url Menu URL.
	 * @return string
	 */
	private static function navigation_path_from_url( $url ) {
		$parts = wp_parse_url( trim( (string) $url ) );

		if ( ! is_array( $parts ) ) {
			return '';
		}

		$home_host = strtolower( (string) wp_parse_url( home_url( '/' ), PHP_URL_HOST ) );
		$url_host  = strtolower( (string) ( isset( $parts['host'] ) ? $parts['host'] : $home_host ) );

		if ( '' !== $home_host && '' !== $url_host && $home_host !== $url_host ) {
			return '';
		}

		$path = isset( $parts['path'] ) ? (string) $parts['path'] : '/';
		$path = '/' . trim( str_replace( '\\', '/', $path ), '/' );
		$path = preg_replace( '#/+#', '/', $path );

		$home_path = wp_parse_url( (string) get_option( 'home' ), PHP_URL_PATH );
		$home_path = is_string( $home_path ) ? '/' . trim( $home_path, '/' ) : '/';
		$home_path = '/' === $home_path ? '/' : untrailingslashit( $home_path );

		if ( '/' !== $home_path ) {
			if ( $path === $home_path ) {
				$path = '/';
			} elseif ( 0 === strpos( $path, $home_path . '/' ) ) {
				$path = substr( $path, strlen( $home_path ) );
			}
		}

		$segments = array_values( array_filter( explode( '/', trim( $path, '/' ) ), 'strlen' ) );

		if ( ! empty( $segments ) && LocaleRepository::is_enabled_url_tag( $segments[0] ) ) {
			array_shift( $segments );
		}

		return empty( $segments ) ? '' : implode( '/', $segments );
	}