wp_normalize_path( WP_LANG_DIR ), 'custom' => wp_normalize_path( trailingslashit( $upload_dir['basedir'] ) . 'af-translate/core' ) ); } $base = ( 'theme' === $type ) ? wp_normalize_path( get_theme_root() . '/' . $slug ) : wp_normalize_path( WP_PLUGIN_DIR . '/' . $slug ); $lang_dir = wp_normalize_path( WP_LANG_DIR ); $sub_folder = ( 'plugin' === $type ) ? 'plugins' : 'themes'; return array( 'author' => $base . '/languages', 'system' => $lang_dir . '/' . $type . 's', 'custom' => wp_normalize_path( trailingslashit( $upload_dir['basedir'] ) . "af-translate/{$sub_folder}" ) ); } /** * Aggregates configuration files across disk architectures safely. * Implements smart prefix parsing loops to isolate distinct Core sub-projects. */ public static function get_component_summary( $slug, $type ) { if ( ! current_user_can( 'manage_options' ) ) { return array( 'text_domain' => sanitize_key( $slug ), 'pot_exists' => false, 'pot_file' => '', 'po_count' => 0, 'po_collection' => array() ); } $slug = sanitize_key( $slug ); $type = self::clean_component_type( $type ); $dirs = self::locate_translation_dirs( $slug, $type ); $pot_files = array(); $po_files = array(); foreach ( $dirs as $key => $dir ) { if ( is_dir( $dir ) && self::verify_path_containment( $dir ) ) { // 1. Scan and filter Template files (.pot) $found_pots = glob( trailingslashit( $dir ) . "*.pot" ); if ( ! empty( $found_pots ) && is_array( $found_pots ) ) { foreach ( $found_pots as $pot ) { $pot_name = basename( $pot ); if ( 'wordpress' === $type ) { if ( 'admin-network' === $slug && stripos( $pot_name, 'admin-network' ) === 0 ) { $pot_files[] = wp_normalize_path( $pot ); } elseif ( 'admin' === $slug && stripos( $pot_name, 'admin' ) === 0 && stripos( $pot_name, 'admin-network' ) !== 0 ) { $pot_files[] = wp_normalize_path( $pot ); } elseif ( 'continents-cities' === $slug && stripos( $pot_name, 'continents-cities' ) === 0 ) { $pot_files[] = wp_normalize_path( $pot ); } elseif ( ( 'default' === $slug || 'wordpress' === $slug || 'core' === $slug ) && stripos( $pot_name, 'admin' ) !== 0 && stripos( $pot_name, 'continents-cities' ) !== 0 ) { $pot_files[] = wp_normalize_path( $pot ); } } else { if ( 'system' !== $key || $pot_name === "{$slug}.pot" ) { $pot_files[] = wp_normalize_path( $pot ); } } } } // 2. Scan and filter Translation tables (.po) $found_pos = glob( trailingslashit( $dir ) . "*.po" ); if ( ! empty( $found_pos ) && is_array( $found_pos ) ) { foreach ( $found_pos as $po ) { $filename = basename( $po ); if ( 'wordpress' === $type ) { // Sub-project filtering logic for core language files if ( 'admin-network' === $slug ) { if ( stripos( $filename, 'admin-network-' ) === 0 ) { $po_files[] = wp_normalize_path( $po ); } } elseif ( 'admin' === $slug ) { if ( stripos( $filename, 'admin-' ) === 0 && stripos( $filename, 'admin-network-' ) !== 0 ) { $po_files[] = wp_normalize_path( $po ); } } elseif ( 'continents-cities' === $slug ) { if ( stripos( $filename, 'continents-cities-' ) === 0 ) { $po_files[] = wp_normalize_path( $po ); } } elseif ( 'default' === $slug || 'wordpress' === $slug || 'core' === $slug ) { // Default main layout files contain raw locale codes only (e.g. de_DE.po, hi_IN.po) if ( stripos( $filename, 'admin-' ) !== 0 && stripos( $filename, 'continents-cities-' ) !== 0 ) { $po_files[] = wp_normalize_path( $po ); } } } else { if ( 'author' === $key ) { $po_files[] = wp_normalize_path( $po ); } else { if ( stripos( $filename, "{$slug}-" ) === 0 ) { $po_files[] = wp_normalize_path( $po ); } } } } } } } $pot_files = array_unique( array_filter( $pot_files ) ); $po_files = array_unique( array_filter( $po_files ) ); $primary_pot = ''; if ( ! empty( $pot_files ) ) { $primary_pot = reset( $pot_files ); } return array( 'text_domain' => $slug, 'pot_exists' => ! empty( $primary_pot ) || ( 'wordpress' === $type ), // Force bypass core physical template gaps 'pot_file' => $primary_pot, 'po_count' => count( $po_files ), 'po_collection' => $po_files ); } /** * Reads, tokenizes, and aggregates real completion matrices using native WP Core POMO classes. */ public static function analyze_po_file( $file_path ) { $metrics = array( 'total' => 0, 'translated' => 0, 'percentage' => 0 ); if ( ! current_user_can( 'manage_options' ) || ! self::verify_path_containment( $file_path ) ) { return $metrics; } if ( ! is_readable( $file_path ) ) { return $metrics; } if ( ! class_exists( 'PO' ) ) { require_once ABSPATH . 'wp-includes/pomo/po.php'; } $po_parser = new PO(); if ( false === $po_parser->import_from_file( $file_path ) ) { return $metrics; } if ( ! empty( $po_parser->entries ) && is_array( $po_parser->entries ) ) { foreach ( $po_parser->entries as $entry ) { if ( '' === $entry->singular ) { continue; } $metrics['total']++; if ( ! empty( $entry->translations ) && is_array( $entry->translations ) ) { $is_valid_translation = false; foreach ( $entry->translations as $string_variant ) { if ( '' !== trim( (string) $string_variant ) ) { $is_valid_translation = true; break; } } if ( $is_valid_translation ) { $metrics['translated']++; } } } } if ( $metrics['total'] > 0 ) { $metrics['percentage'] = (int) round( ( $metrics['translated'] / $metrics['total'] ) * 100 ); } return $metrics; } }