AttributeSlugLength.php
2 weeks ago
VisualAttributeTermAdmin.php
2 days ago
VisualAttributeTermMeta.php
2 months ago
AttributeSlugLength.php
74 lines
| 1 | <?php |
| 2 | /** |
| 3 | * Product attribute slug length utilities. |
| 4 | * |
| 5 | * @package WooCommerce\Classes |
| 6 | */ |
| 7 | |
| 8 | declare( strict_types = 1 ); |
| 9 | |
| 10 | namespace Automattic\WooCommerce\Internal\ProductAttributes; |
| 11 | |
| 12 | /** |
| 13 | * Utilities for communicating the product attribute slug length limit to users. |
| 14 | * |
| 15 | * @internal |
| 16 | * |
| 17 | * @since 11.1.0 |
| 18 | */ |
| 19 | class AttributeSlugLength { |
| 20 | |
| 21 | /** |
| 22 | * Estimate how many characters fit in a product attribute slug for a given locale. |
| 23 | * |
| 24 | * The slug limit is enforced in bytes (see wc_get_attribute_slug_max_byte_length()), |
| 25 | * but users think in characters. UTF-8 encodes a character in 1-4 bytes depending on |
| 26 | * its script, so the character budget depends on the language. This maps the locale to |
| 27 | * the typical byte width of its script and divides the byte budget by it, yielding a |
| 28 | * rough, user-friendly maximum. |
| 29 | * |
| 30 | * This is a heuristic: a locale predicts the script its users most likely type, |
| 31 | * not the actual slug they enter (a Greek-language store may still use Latin slugs), |
| 32 | * so callers should present the result as an approximation and keep the byte limit |
| 33 | * authoritative. |
| 34 | * |
| 35 | * @since 11.1.0 |
| 36 | * @param string $locale Locale to inspect, e.g. 'pt_BR'. Defaults to the current user's locale. |
| 37 | * @return int Approximate maximum number of characters, never less than 1. |
| 38 | */ |
| 39 | public static function get_character_estimate( string $locale = '' ): int { |
| 40 | if ( '' === $locale ) { |
| 41 | // Admin screens render in the user's profile language (get_user_locale()), |
| 42 | // which can differ from the site language; estimate for what the user |
| 43 | // actually reads and types. |
| 44 | $locale = get_user_locale(); |
| 45 | } |
| 46 | |
| 47 | // Reduce the locale to its language subtag, e.g. 'pt_BR' or 'zh-Hans' -> 'pt' / 'zh'. |
| 48 | $language = strtolower( (string) strtok( $locale, '_-' ) ); |
| 49 | |
| 50 | // Space-padded lists of language subtags grouped by the typical UTF-8 byte width of |
| 51 | // their script, covering the locale IDs WordPress core actually installs — including |
| 52 | // its three-letter IDs (kir, ckb, snd, sah, ...) — plus common ISO aliases (ky, be). |
| 53 | // Three bytes: CJK, Thai, Georgian, Ethiopic, Tibetan, and Brahmic (Indic) scripts. |
| 54 | // Two bytes: Cyrillic, Greek, Hebrew, Arabic-script, and Armenian. Everything else |
| 55 | // (Latin and unknown) is treated as single-byte. The padding makes each match whole-word. |
| 56 | // Latin-script languages with heavy diacritics (e.g. Vietnamese) are intentionally |
| 57 | // single-byte: slugs pass through wc_sanitize_taxonomy_name(), whose sanitize_title() |
| 58 | // call transliterates accented Latin letters to plain ASCII before the byte limit |
| 59 | // applies ('Tiếng Việt đậm nhạt' is stored as 'tieng-viet-dam-nhat'). |
| 60 | $three_byte = ' zh ja ko th ka hi bn ne ta te mr gu kn ml pa or si km lo my am as bo dzo '; |
| 61 | $two_byte = ' ru uk bg sr be bel mk kk ky kir tg tt mn sah el he ar ary azb ckb fa haz ps skr snd ug ur hy '; |
| 62 | |
| 63 | if ( false !== strpos( $three_byte, " {$language} " ) ) { |
| 64 | $byte_width = 3; |
| 65 | } elseif ( false !== strpos( $two_byte, " {$language} " ) ) { |
| 66 | $byte_width = 2; |
| 67 | } else { |
| 68 | $byte_width = 1; |
| 69 | } |
| 70 | |
| 71 | return max( 1, intdiv( wc_get_attribute_slug_max_byte_length(), $byte_width ) ); |
| 72 | } |
| 73 | } |
| 74 |