2222namespace phpMyFAQ ;
2323
2424use phpMyFAQ \Language \LanguageCodes ;
25- use Symfony \ Component \ HttpFoundation \ Request ;
25+ use phpMyFAQ \ Language \ LanguageDetector ;
2626use Symfony \Component \HttpFoundation \Session \SessionInterface ;
2727
2828/**
@@ -38,9 +38,9 @@ class Language
3838 public static string $ language = '' ;
3939
4040 /**
41- * The accepted language of the user agent .
41+ * Detector helper .
4242 */
43- private string $ acceptLanguage = '' ;
43+ private LanguageDetector $ detector ;
4444
4545 /**
4646 * Constructor.
@@ -49,6 +49,7 @@ public function __construct(
4949 private readonly Configuration $ configuration ,
5050 private readonly SessionInterface $ session ,
5151 ) {
52+ $ this ->detector = new LanguageDetector ($ this ->configuration , $ this ->session );
5253 }
5354
5455 /**
@@ -63,20 +64,24 @@ public function isLanguageAvailable(int $identifier, string $table = 'faqdata'):
6364 {
6465 $ output = [];
6566
66- if ( $ identifier === 0 ) {
67- $ distinct = ' DISTINCT ' ;
68- $ where = '' ;
69- } else {
67+ // Avoid it else: default values for all records, override if identifier is set
68+ $ distinct = 'DISTINCT ' ;
69+ $ where = '' ;
70+ if ( $ identifier !== 0 ) {
7071 $ distinct = '' ;
7172 $ where = ' WHERE id = ' . $ identifier ;
7273 }
7374
74- $ query = sprintf ( ' SELECT %s lang FROM %s%s %s ' , $ distinct , Database:: getTablePrefix (), $ table , $ where );
75-
75+ // Correct spacing: " SELECT" then optional DISTINCT
76+ $ query = ' SELECT ' . $ distinct . ' lang FROM ' . Database:: getTablePrefix () . $ table . $ where ;
7677 $ result = $ this ->configuration ->getDb ()->query ($ query );
7778
7879 if ($ this ->configuration ->getDb ()->numRows ($ result ) > 0 ) {
79- while ($ row = $ this ->configuration ->getDb ()->fetchObject ($ result )) {
80+ while (true ) {
81+ $ row = $ this ->configuration ->getDb ()->fetchObject ($ result );
82+ if (!$ row ) {
83+ break ;
84+ }
8085 $ output [] = $ row ->lang ;
8186 }
8287 }
@@ -85,24 +90,37 @@ public function isLanguageAvailable(int $identifier, string $table = 'faqdata'):
8590 }
8691
8792 /**
88- * Sets the current language for phpMyFAQ user session.
89- *
90- * @param bool $configDetection Configuration detection
91- * @param string $configLanguage Language from configuration
93+ * Sets language using browser detection combined with config fallback.
9294 */
93- public function setLanguage ( bool $ configDetection , string $ configLanguage ): string
95+ public function setLanguageWithDetection ( string $ configLanguage ): string
9496 {
95- $ detectedLang = $ this ->detectLanguage ($ configDetection , $ configLanguage );
96- self ::$ language = $ this ->selectLanguage ($ detectedLang );
97- $ this ->session ->set ('lang ' , self ::$ language );
97+ $ detected = $ this ->detector ->detectAllWithBrowser ($ configLanguage );
98+ self ::$ language = $ this ->detector ->selectLanguage ($ detected );
99+ $ this ->session ->set (
100+ name: 'lang ' ,
101+ value: self ::$ language ,
102+ );
98103 return strtolower (self ::$ language );
99104 }
100105
101- public function setLanguageByAcceptLanguage (): string
106+ /**
107+ * Sets language only from the provided configuration string.
108+ */
109+ public function setLanguageFromConfiguration (string $ configLanguage ): string
102110 {
103- self ::getUserAgentLanguage ();
111+ $ detected = $ this ->detector ->detectAllFromConfig ($ configLanguage );
112+ self ::$ language = $ this ->detector ->selectLanguage ($ detected );
113+ $ this ->session ->set (
114+ name: 'lang ' ,
115+ value: self ::$ language ,
116+ );
117+ return strtolower (self ::$ language );
118+ }
104119
105- return self ::$ language = $ this ->acceptLanguage ;
120+ public function setLanguageByAcceptLanguage (): string
121+ {
122+ $ this ->detector ->detectAllWithBrowser (configLanguage: '' );
123+ return self ::$ language = $ this ->detector ->getAcceptLanguage ();
106124 }
107125
108126 /**
@@ -122,110 +140,4 @@ public function getLanguage(): string
122140 {
123141 return strtolower (self ::$ language );
124142 }
125-
126- /**
127- * Detects the language.
128- *
129- * @param bool $configDetection Configuration detection
130- * @param string $configLanguage Language from configuration
131- * @return string[]
132- */
133- private function detectLanguage (bool $ configDetection , string $ configLanguage ): array
134- {
135- $ detectedLang = [];
136- $ this ->getUserAgentLanguage ();
137-
138- $ detectedLang ['post ' ] = $ this ->getPostLanguage ();
139- $ detectedLang ['get ' ] = $ this ->getGetLanguage ();
140- $ detectedLang ['artget ' ] = $ this ->getArtGetLanguage ();
141- $ detectedLang ['session ' ] = $ this ->getSessionLanguage ();
142- $ detectedLang ['config ' ] = $ this ->getConfigLanguage ($ configLanguage );
143- $ detectedLang ['detection ' ] = $ this ->getDetectionLanguage ($ configDetection );
144-
145- return $ detectedLang ;
146- }
147-
148- private function getPostLanguage (): ?string
149- {
150- $ lang = Filter::filterInput (INPUT_POST , 'language ' , FILTER_SANITIZE_SPECIAL_CHARS );
151- return static ::isASupportedLanguage ($ lang ) ? $ lang : null ;
152- }
153-
154- private function getGetLanguage (): ?string
155- {
156- $ lang = Filter::filterInput (INPUT_GET , 'lang ' , FILTER_SANITIZE_SPECIAL_CHARS );
157- return static ::isASupportedLanguage ($ lang ) ? $ lang : null ;
158- }
159-
160- private function getArtGetLanguage (): ?string
161- {
162- $ lang = Filter::filterInput (INPUT_GET , 'artlang ' , FILTER_SANITIZE_SPECIAL_CHARS );
163- return static ::isASupportedLanguage ($ lang ) ? $ lang : null ;
164- }
165-
166- private function getSessionLanguage (): ?string
167- {
168- $ lang = $ this ->session ->get ('lang ' );
169- return static ::isASupportedLanguage ($ lang ) ? trim ((string ) $ lang ) : null ;
170- }
171-
172- private function getConfigLanguage (string $ configLanguage ): ?string
173- {
174- $ lang = str_replace (['language_ ' , '.php ' ], '' , $ configLanguage );
175- return static ::isASupportedLanguage ($ lang ) ? $ lang : null ;
176- }
177-
178- private function getDetectionLanguage (bool $ configDetection ): ?string
179- {
180- return $ configDetection && static ::isASupportedLanguage ($ this ->acceptLanguage )
181- ? strtolower ($ this ->acceptLanguage )
182- : null ;
183- }
184-
185- /**
186- * Selects the language.
187- *
188- * @param string[] $detectedLanguage Detected language
189- */
190- private function selectLanguage (array $ detectedLanguage ): string
191- {
192- $ priorityOrder = ['post ' , 'get ' , 'artget ' , 'session ' , 'detection ' , 'config ' ];
193-
194- foreach ($ priorityOrder as $ source ) {
195- if (!empty ($ detectedLanguage [$ source ])) {
196- return $ detectedLanguage [$ source ];
197- }
198- }
199-
200- return 'en ' ;
201- }
202-
203- /**
204- * Gets the accepted language from the user agent.
205- *
206- * HTTP_ACCEPT_LANGUAGE could be like the text below:
207- * it,pt_BR;q=0.8,en_US;q=0.5,en;q=0.3
208- */
209- private function getUserAgentLanguage (): void
210- {
211- $ languages = Request::createFromGlobals ()->getLanguages ();
212-
213- foreach ($ languages as $ language ) {
214- if (self ::isASupportedLanguage (strtoupper ($ language ))) {
215- $ this ->acceptLanguage = strtolower ($ language );
216- break ;
217- }
218- }
219-
220- // If the browser, e.g., sends "en_us", we want to get "en" only.
221- if ('' === $ this ->acceptLanguage ) {
222- foreach ($ languages as $ language ) {
223- $ language = substr ($ language , 0 , 2 );
224- if (self ::isASupportedLanguage (strtoupper ($ language ))) {
225- $ this ->acceptLanguage = strtolower ($ language );
226- break ;
227- }
228- }
229- }
230- }
231143}
0 commit comments