PluginProbe
Polylang / trunk
Polylang vtrunk
3.8.9 3.8.8 3.8.7 3.8.6 3.8.5 3.8.4 3.8.3 2.7 2.7.0.1 2.7.1 2.7.2 2.7.3 2.7.4 2.8 2.8.1 2.8.2 2.8.3 2.8.4 2.9 2.9.1 2.9.2 3.0 3.0.1 3.0.2 3.0.3 All 233 releases
polylang / src / frontend / accept-languages-collection.php

accept-languages-collection.php in Polylang trunk, at src/frontend/accept-languages-collection.php

144 lines 3.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package Polylang
4 */
5
6 /**
7 * Class PLL_Accept_Languages_Collection.
8 *
9 * Represents a collection of values parsed from an Accept-Language HTTP header.
10 *
11 * @since 3.0
12 */
13 class PLL_Accept_Languages_Collection {
14 /**
15 * @var PLL_Accept_Language[]
16 */
17 protected $accept_languages = array();
18
19 /**
20 * Parse Accept-Language HTTP header according to IETF BCP 47.
21 *
22 * @since 3.0
23 *
24 * @param string $http_header Value of the Accept-Language HTTP Header. Formatted as stated BCP 47 for language tags {@see https://tools.ietf.org/html/bcp47}.
25 * @return PLL_Accept_Languages_Collection
26 */
27 public static function from_accept_language_header( $http_header ) {
28 $lang_parse = array();
29 // Break up string into pieces ( languages and q factors ).
30 $language_pattern = implode( '', PLL_Accept_Language::SUBTAG_PATTERNS );
31 $quality_pattern = '\s*;\s*q\s*=\s*((?>1|0)(?>\.[0-9]+)?)';
32 $full_pattern = "/{$language_pattern}(?:{$quality_pattern})?/i";
33
34 preg_match_all(
35 $full_pattern,
36 $http_header,
37 $lang_parse,
38 PREG_SET_ORDER
39 );
40
41 return new PLL_Accept_Languages_Collection(
42 array_map(
43 array( PLL_Accept_Language::class, 'from_array' ),
44 $lang_parse
45 )
46 );
47 }
48
49 /**
50 * PLL_Accept_Languages_Collection constructor.
51 *
52 * @since 3.0
53 *
54 * @param PLL_Accept_Language[] $accept_languages Objects representing Accept-Language HTTP headers.
55 */
56 public function __construct( $accept_languages = array() ) {
57 $this->accept_languages = $accept_languages;
58 }
59
60 /**
61 * Bubble sort (need a stable sort for Android, so can't use a PHP sort function).
62 *
63 * @since 3.0
64 *
65 * @return void
66 */
67 public function bubble_sort() {
68 $k = $this->accept_languages;
69 $v = array_map(
70 function ( $accept_lang ) {
71 return $accept_lang->get_quality();
72 },
73 $this->accept_languages
74 );
75
76 if ( $n = count( $k ) ) {
77
78 if ( $n > 1 ) {
79 for ( $i = 2; $i <= $n; $i++ ) {
80 for ( $j = 0; $j <= $n - 2; $j++ ) {
81 if ( $v[ $j ] < $v[ $j + 1 ] ) {
82 // Swap values.
83 $temp = $v[ $j ];
84 $v[ $j ] = $v[ $j + 1 ];
85 $v[ $j + 1 ] = $temp;
86 // Swap keys.
87 $temp = $k[ $j ];
88 $k[ $j ] = $k[ $j + 1 ];
89 $k[ $j + 1 ] = $temp;
90 }
91 }
92 }
93 }
94 $this->accept_languages = array_filter(
95 $k,
96 function ( $accept_lang ) {
97 return $accept_lang->get_quality() > 0;
98 }
99 );
100 }
101 }
102
103 /**
104 * Looks through sorted list and use first one that matches our language list.
105 *
106 * @since 3.0
107 *
108 * @param PLL_Language[] $languages The language list.
109 * @return string|false A language slug if there's a match, false otherwise.
110 */
111 public function find_best_match( $languages = array() ) {
112 foreach ( $this->accept_languages as $accept_lang ) {
113 // First loop to match the exact locale.
114 foreach ( $languages as $language ) {
115 if ( 0 === strcasecmp( $accept_lang, $language->get_locale( 'display' ) ) ) {
116 return $language->slug;
117 }
118 }
119
120 // In order of priority.
121 $subsets = array();
122 if ( ! empty( $accept_lang->get_subtag( 'region' ) ) ) {
123 $subsets[] = $accept_lang->get_subtag( 'language' ) . '-' . $accept_lang->get_subtag( 'region' );
124 $subsets[] = $accept_lang->get_subtag( 'region' );
125 }
126 if ( ! empty( $accept_lang->get_subtag( 'variant' ) ) ) {
127 $subsets[] = $accept_lang->get_subtag( 'language' ) . '-' . $accept_lang->get_subtag( 'variant' );
128 }
129 $subsets[] = $accept_lang->get_subtag( 'language' );
130
131 // More loops to match the subsets.
132 foreach ( $languages as $language ) {
133 foreach ( $subsets as $subset ) {
134
135 if ( 0 === stripos( $subset, $language->slug ) || 0 === stripos( $language->get_locale( 'display' ), $subset ) ) {
136 return $language->slug;
137 }
138 }
139 }
140 }
141 return false;
142 }
143 }
144