Completed
Push — master ( 90c0cc...b980fc )
by Toni
02:22
created

MultilingualContext::languageDetection()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 19
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 19
rs 8.8571
cc 6
eloc 13
nc 6
nop 0
1
<?php
2
3
namespace kolev\MultilingualExtension\Context;
4
5
use Behat\Behat\Context\Context;
6
use Symfony\Component\Yaml\Yaml;
7
use Drupal\DrupalExtension\Context\DrupalContext;
8
use Behat\MinkExtension;
9
use Behat\Behat\Context\TranslatableContext;
10
use Behat\Mink\Element\Element;
11
use Behat\Gherkin\Node\TableNode;
12
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
13
use Behat\MinkExtension\Context\RawMinkContext;
14
15
/**
16
 * This is the file for Multilingual context for Drupal. The context is working based on specifications
17
 * in the profile. The user needs to provide the language of the site and the translation file.
18
 *
19
 * The user is free to provide either full "english" or shortened "en" prefix for new languages
20
 * but all translations should follow common pattern. For example if the site's language
21
 * is marked as "en" you should define your translations with "en".
22
 *
23
 * It is important to note that the English language is used as a base.
24
 *
25
 * This is very early version of the context so it probably has some bugs/issues and points to be improved.
26
 *
27
 * @author Toni Kolev <[email protected]>
28
 * @skype k-o-l-e-v
29
 * @github https://github.com/byKolev
30
 */
31
32
class MultilingualContext extends RawMultilingualContext {
33
34
    /** Multilanguage implementation */
35
36
    // Declaring translations variable to store all translations.
37
    public $translations = array();
38
39
    // Declaring languages_iso_codes variable to store all languages ISO codes from json file.
40
    public $languages_iso_codes = array();
41
42
43
    // Parse the YAML translations to PHP array variable.
44
    public function parseTranslationFile() {
45
        $base_path = $this->getMinkParameter('files_path');
46
        $base_path = $base_path."/";
47
        $file_path = $base_path.$this->multilingual_parameters['translations'];
48
        $yaml = file_get_contents($file_path);
49
        $yaml_parse_array_check = Yaml::parse($yaml);
50
        if(is_array($yaml_parse_array_check)) {
51
            $this->translations = $yaml_parse_array_check;
52
        }
53
    }
54
55
    // Checks whether the translations file variable is set in the Behat profile and parses it to array.
56
    public function initializeMultilanguage() {
57
        if(isset($this->multilingual_parameters['translations'])) {
58
            $this->parseTranslationFile();
59
        }
60
        $this->parseLanguageCodes();
61
    }
62
63
    //This function parses the languages_iso_codes.json file to an array.
64
    public function parseLanguageCodes() {
65
        $languages_iso_codes_string = file_get_contents("vendor/kolev/multilingual-extension/src/Resources/languages_iso_codes.json");
66
        $this->languages_iso_codes = json_decode($languages_iso_codes_string, true);
0 ignored issues
show
Documentation Bug introduced by
It seems like json_decode($languages_iso_codes_string, true) of type * is incompatible with the declared type array of property $languages_iso_codes.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
67
    }
68
69
    /*
70
     * This function detects site's language based on URL. If no URL language is detected
71
     * the default_language is used.
72
     */
73
74
    public function languageDetection() {
75
        $current_url = $this->getSession()->getCurrentUrl();
76
        $base_url = $this->getMinkParameter('base_url');
77
        // Checks whether the last symbol in the base_url is /, if not it adds it
78
        if (substr($base_url, -1) != "/") {
79
            $base_url = $base_url."/";
80
        }
81
        $base_url_length = strlen($base_url);
82
        //Get the 2 symbols in current URL after the base_url when Clean URLs is enabled
83
        $clean_url_language_code = substr($current_url,$base_url_length,2);
84
        $not_clean_url_language_code = substr($current_url,$base_url_length+3,2);
85
        if(in_array($clean_url_language_code,$this->languages_iso_codes) && substr($current_url,$base_url_length+2,1) == "/") {
86
            return $clean_url_language_code;
87
        }
88
        else if (in_array($not_clean_url_language_code,$this->languages_iso_codes) && substr($current_url,$base_url_length+5,1) == "/"){
89
            return $not_clean_url_language_code;
90
        }
91
        else return $this->multilingual_parameters['default_language'];
92
    }
93
94
    /**
95
     * This function localizes the targeted string. It tries to find a definition of the provided text (in English)
96
     * in the translations file that is provided within the profile parameters. If it fails to find translation
97
     * for the requested language it falls back to English. If the string is not defined at all in the translations
98
     * file there will be an exception thrown.
99
     */
100
101
    public function localizeTarget($target) {
102
        $translations = $this->multilingual_parameters['translations'];
103
        if(isset($this->translations[$target][$this->multilingual_parameters['default_language']])){
104
            $target = $this->translations[$target][$this->languageDetection()];
105
            return $target;
106
        }
107
        elseif (isset($this->translations[$target])) {
108
            return $target;
109
        }
110
        else throw new \Exception ("The text '$target'' is not defined in '$translations' translation file.");
111
    }
112
113
    /**
114
     * This function localizes the field based on Drupal standards. default_language variable is used as a base.
115
     */
116
117
    public function localizeField($field) {
118
        $re = "/(?:[-])(".$this->multilingual_parameters['default_language'].")(?:[-])/";
119
        $language = "-".$this->languageDetection()."-";
120
        $field = preg_replace($re, $language,$field);
121
        return $field;
122
    }
123
124
125
    /**
126
     * Initialize the multilingual context before the scenario.
127
     * @BeforeScenario
128
     * @Given /^I initialize multilingual context/
129
     */
130
    public function iInitializeMultilingualContext() {
131
        $this->initializeMultilanguage();
132
    }
133
134
    /**
135
     *
136
     * @Given /^I follow localized "(?P<link>(?:[^"]|\\")*)"/
137
     */
138
    public function iFollowLocalized($target) {
139
140
        $pos = strpos($target, '-en-');
141
142
        if ($pos === false) {
143
            $target = $this->localizeTarget($target);
144
        } else {
145
            $target = $this->localizeField($target);
146
        }
147
        
148
        $this->getSession()->getPage()->clickLink($target);
149
    }
150
151
    /**
152
     *
153
     * @Given /^I follow second localized "(?P<link>(?:[^"]|\\")*)"/
154
     */
155
    public function iFollowLocalizedSecond($target) {
156
        $target = $this->localizeTarget($target);
157
        $this->getSession()->getPage()->clickLink($target);
158
    }
159
160
    /**
161
     * Click on some text.
162
     *
163
     * @When /^I click on the localized text "([^"]*)"$/
164
     */
165
166
    public function iClickOnTheLocalizedText($target) {
167
        $target = $this->localizeTarget($target);
168
        $this->iClickOnTheText($target);
169
    }
170
171
    /**
172
     * Checks, that page contains specified text in input
173
     *
174
     * @Then /^(?:|I )should see localized value "(?P<text>(?:[^"]|\\")*)" in input "([^"]*)"$/
175
     */
176
177
    public function iShouldSeeLocalizedValueInInput($value, $input) {
178
        $value = $this->localizeTarget($value);
179
        $this->assertValueInInput($value, $input);
180
    }
181
182
    /**
183
     * Checks, that page contains specified text
184
     *
185
     * @Then /^(?:|I )should see localized "(?P<text>(?:[^"]|\\")*)"$/
186
     */
187
188
    public function iShouldSeeLocalized($target) {
189
        $target = $this->localizeTarget($target);
190
        $this->assertSession()->pageTextContains($target);
191
    }
192
193
    /**
194
     * Checks, that page doesn't contain specified text
195
     *
196
     * @Then /^(?:|I )should not see localized "(?P<text>(?:[^"]|\\")*)"$/
197
     */
198
    public function iShouldNotSeeLocalized($target)
199
    {
200
        $target = $this->localizeTarget($target);
201
        $this->assertSession()->pageTextNotContains($target);
202
    }
203
204
    /**
205
     * Waiting for text to appear on a page with certain execution time
206
     *
207
     * @When /^I wait for localized text "([^"]*)" to appear with max time "([^"]+)"(?: seconds)?$/
208
     */
209
    public function iWaitForLocalizedTextToAppearWithMaxTime($target, $maxExecutionTime){
210
        $target = $this->localizeTarget($target);
211
        $this->iWaitForTextToAppearWithMaxTime($target, $maxExecutionTime);
212
    }
213
214
    /**
215
     * Fills in form field with specified id|name|label|value
216
     * Example: When I fill in "username" with: "bwayne"
217
     * Example: And I fill in "bwayne" for "username"
218
     *
219
     * @When /^(?:|I )fill in localized "(?P<field>(?:[^"]|\\")*)" with "(?P<value>(?:[^"]|\\")*)"$/
220
     * @When /^(?:|I )fill in localized "(?P<field>(?:[^"]|\\")*)" with:$/
221
     * @When /^(?:|I )fill in localized "(?P<value>(?:[^"]|\\")*)" for "(?P<field>(?:[^"]|\\")*)"$/
222
     */
223
    public function fillLocalizedField($field, $value)
224
    {
225
        $field = $this->localizeField($field);
226
        $this->getSession()->getPage()->fillField($field, $value);
227
    }
228
229
    /**
230
     * @Given I click localized :link in the :rowText row
231
     * @Then I (should )see the localized :link in the :rowText row
232
     */
233
    public function assertLocalizedClickInTableRow($link, $rowText){
234
        $link = $this->localizeTarget($link);
235
        $page = $this->getSession()->getPage();
236
        if ($link_element = $this->getTableRow($page, $rowText)->findLink($link)) {
237
            // Click the link and return.
238
            $link_element->click();
239
            return;
240
        }
241
        throw new \Exception(sprintf('Found a row containing "%s", but no "%s" link on the page %s', $rowText, $link, $this->getSession()->getCurrentUrl()));
242
    }
243
244
    public function getTableRow(Element $element, $search) {
245
        $rows = $element->findAll('css', 'tr');
246
        if (empty($rows)) {
247
            throw new \Exception(sprintf('No rows found on the page %s', $this->getSession()->getCurrentUrl()));
248
        }
249
        foreach ($rows as $row) {
250
            if (strpos($row->getText(), $search) !== FALSE) {
251
                return $row;
252
            }
253
        }
254
        throw new \Exception(sprintf('Failed to find a row containing "%s" on the page %s', $search, $this->getSession()->getCurrentUrl()));
255
    }
256
257
    /**
258
     * Click on text in specified region
259
     *
260
     * @When /^I click on the localized text "([^"]*)" in the "(?P<region>[^"]*)"(?:| region)$/
261
     */
262
    public function iClickOnTheLocalizedTextInRegion($text, $region){
263
        $text = $this->localizeTarget($text);
264
        $this->iClickOnTheTextInRegion($text, $region);
265
    }
266
267
    /**
268
     * Choose certain option from given selector
269
     *
270
     * @When I select localized :option from chosen :selector
271
     */
272
    public function lselectLocalizedOptionWithJavascript($selector, $option) {
273
        $localizedOption = $this->localizeTarget($option);
274
        $this->selectOptionWithJavascript($selector, $localizedOption);
275
    }
276
277
    /**
278
     * @When I select the localized radio button :label with the id :id
279
     * @When I select the localized radio button :label
280
     *
281
     */
282
    public function assertSelectLocalizedRadioById($label, $id = '') {
283
        $label = $this->localizeTarget($label);
284
        $this->assertSelectRadioById($label, $id);
285
    }
286
}
287