Passed
Push — developer ( 1642b5...0c16b7 )
by Mariusz
234:43 queued 199:39
created

Language::jstranslate()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.8333
c 0
b 0
f 0
cc 3
nc 3
nop 3
1
<?php
2
/**
3
 * Language controller class.
4
 *
5
 * @copyright YetiForce Sp. z o.o.
6
 * @license   YetiForce Public License 3.0 (licenses/LicenseEN.txt or yetiforce.com)
7
 * @author    Mariusz Krzaczkowski <[email protected]>
8
 */
9
10
namespace App;
11
12
class Language
0 ignored issues
show
Coding Style introduced by
Language does not seem to conform to the naming convention (Utils?$).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
13
{
14
	/**
15
	 * Language files format.
16
	 */
17
	const FORMAT = 'json';
18
19
	/**
20
	 * Contains module language translations.
21
	 *
22
	 * @var array
23
	 */
24
	protected static $languageContainer = [];
25
26
	/** @var string Current language. */
27
	private static $language = '';
28
29
	/**
30
	 * Functions that gets translated string.
31
	 *
32
	 * @param string $key             - string which need to be translated
33
	 * @param string $module          - module scope in which the translation need to be check
34
	 * @param string $currentLanguage
35
	 *
36
	 * @return string - translated string
37
	 */
38
	public static function translate(string $key, string $module = 'Basic', string $currentLanguage = ''): string
39
	{
40
		if (empty($currentLanguage)) {
41
			$currentLanguage = static::getLanguage();
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $currentLanguage. This often makes code more readable.
Loading history...
42
		}
43
		//decoding for Start Date & Time and End Date & Time
44
		if (!\is_array($key)) {
45
			$key = html_entity_decode($key);
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $key. This often makes code more readable.
Loading history...
46
		}
47
		$translatedString = static::getLanguageTranslatedString($currentLanguage, $key, $module);
0 ignored issues
show
Bug introduced by
It seems like $key can also be of type array; however, App\Language::getLanguageTranslatedString() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
48
		// label not found in users language pack, then check in the default language pack(config.inc.php)
49
		if (null === $translatedString) {
50
			$defaultLanguage = Config::get('language');
51
			if (!empty($defaultLanguage) && 0 !== strcasecmp($defaultLanguage, $currentLanguage)) {
52
				$translatedString = static::getLanguageTranslatedString($defaultLanguage, $key, $module);
0 ignored issues
show
Bug introduced by
It seems like $key can also be of type array; however, App\Language::getLanguageTranslatedString() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
53
			}
54
		}
55
56
		// If translation is not found then return label
57
		if (null === $translatedString) {
58
			$translatedString = $key;
59
		}
60
		return $translatedString;
61
	}
62
63
	/**
64
	 * Functions that gets translated string by $args.
65
	 *
66
	 * @param string $key        - string which need to be translated
67
	 * @param string $moduleName - module scope in which the translation need to be check
68
	 *
69
	 * @return string - translated string
70
	 */
71
	public static function translateArgs(string $key, string $moduleName = 'Basic'): string
72
	{
73
		$formattedString = static::translate($key, $moduleName);
74
		$args = \array_slice(\func_get_args(), 2);
75
		if (\is_array($args) && !empty($args)) {
76
			$formattedString = \call_user_func_array('vsprintf', [$formattedString, $args]);
77
		}
78
		return $formattedString;
79
	}
80
81
	/**
82
	 * Function that returns current language.
83
	 *
84
	 * @return string
85
	 */
86
	public static function getLanguage(): string
87
	{
88
		if (static::$language) {
0 ignored issues
show
Bug introduced by
Since $language is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $language to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
89
			return static::$language;
0 ignored issues
show
Bug introduced by
Since $language is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $language to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
90
		}
91
		$userInstance = User::getUser();
92
		$language = '';
93
94
		if ($userInstance && $userInstance->has('language') && !empty($userInstance->get('language'))) {
95
			$language = $userInstance->get('language');
96
		} elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
97
			$allLanguages = static::getAllLanguages();
98
			foreach (explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']) as $code) {
99
				if (isset($allLanguages[$code])) {
100
					$language = $code;
101
				}
102
				break;
103
			}
104
		} else {
105
			$language = Config::get('language');
106
		}
107
108
		return static::$language = $language;
0 ignored issues
show
Bug introduced by
Since $language is declared private, accessing it with static will lead to errors in possible sub-classes; consider using self, or increasing the visibility of $language to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return static::$someVariable;
    }
}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass { }

YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class SomeClass
{
    private static $someVariable;

    public static function getSomeVariable()
    {
        return self::$someVariable; // self works fine with private.
    }
}
Loading history...
109
	}
110
111
	/**
112
	 * Function returns language specific translated string.
113
	 *
114
	 * @param string $language - en_us etc
115
	 * @param string $key      - label
116
	 * @param string $module   - module name
117
	 *
118
	 * @return string translated string or null if translation not found
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
119
	 */
120
	public static function getLanguageTranslatedString(string $language, string $key, string $module = 'Basic')
121
	{
122
		$moduleStrings = self::getModuleStringsFromFile($language, $module);
123
		if (!empty($moduleStrings['php'][$key])) {
124
			return stripslashes($moduleStrings['php'][$key]);
125
		}
126
127
		$commonStrings = self::getModuleStringsFromFile($language);
128
		if (!empty($commonStrings['php'][$key])) {
129
			return stripslashes($commonStrings['php'][$key]);
130
		}
131
		return null;
132
	}
133
134
	public static function getModuleStringsFromFile(string $language, string $module = 'Basic')
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
135
	{
136
		if (empty(self::$languageContainer[$language][$module])) {
137
			static::loadLanguageFile($language, $module);
138
		}
139
		if (isset(self::$languageContainer[$language][$module])) {
140
			return self::$languageContainer[$language][$module];
141
		}
142
		return [];
143
	}
144
145
	/**
146
	 * Load language file from JSON.
147
	 *
148
	 * @param string $language
149
	 * @param string $moduleName
150
	 *
151
	 * @return void
152
	 */
153
	public static function loadLanguageFile(string $language, string $moduleName = 'Basic')
154
	{
155
		if (!isset(static::$languageContainer[$language][$moduleName])) {
156
			static::$languageContainer[$language][$moduleName] = [];
157
			$file = \DIRECTORY_SEPARATOR . 'languages' . \DIRECTORY_SEPARATOR . $language . \DIRECTORY_SEPARATOR . $moduleName . '.' . static::FORMAT;
158
			$langFile = ROOT_DIRECTORY . $file;
159
			if (file_exists($langFile)) {
160
				static::$languageContainer[$language][$moduleName] = Json::decode(file_get_contents($langFile), true) ?? [];
161
				Cache::save('LanguageFiles', $language . $moduleName, static::$languageContainer[$language][$moduleName], Cache::LONG);
162
			}
163
		} elseif (Cache::has('LanguageFiles', $language . $moduleName)) {
164
			static::$languageContainer[$language][$moduleName] = Cache::get('LanguageFiles', $language . $moduleName);
165
		}
166
	}
167
168
	/**
169
	 * Functions that gets translated string for Client side.
170
	 *
171
	 * @param <String> $key      - string which need to be translated
0 ignored issues
show
Documentation introduced by
The doc-type <String> could not be parsed: Unknown type name "<" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
172
	 * @param <String> $module   - module scope in which the translation need to be check
0 ignored issues
show
Documentation introduced by
The doc-type <String> could not be parsed: Unknown type name "<" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
173
	 * @param mixed    $language
174
	 *
175
	 * @return <String> - translated string
0 ignored issues
show
Documentation introduced by
The doc-type <String> could not be parsed: Unknown type name "<" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
176
	 */
177
	public static function jstranslate($language, $key, $module = 'Basic')
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
178
	{
179
		$moduleStrings = self::getModuleStringsFromFile($language, $module);
180
		if (!empty($moduleStrings['js'][$key])) {
181
			return $moduleStrings['js'][$key];
182
		}
183
184
		$commonStrings = self::getModuleStringsFromFile($language);
185
		if (!empty($commonStrings['js'][$key])) {
186
			return $commonStrings['js'][$key];
187
		}
188
		return $key;
189
	}
190
191
	/**
192
	 * Function to returns all language information.
193
	 *
194
	 * @return array
195
	 */
196
	public static function getAllLanguages(): array
197
	{
198
		$languagess = [];
199
		foreach (new \DirectoryIterator(ROOT_DIRECTORY . \DIRECTORY_SEPARATOR . 'languages' . \DIRECTORY_SEPARATOR) as $level) {
200
			if ($level->isDir() && !$level->isDot()) {
201
				$languagess[$level->getFileName()] = self::getDisplayName($level->getFileName());
202
			}
203
		}
204
		return $languagess;
205
	}
206
207
	/**
208
	 * Function that returns current language short name.
209
	 *
210
	 * @return <String> -
0 ignored issues
show
Documentation introduced by
The doc-type <String> could not be parsed: Unknown type name "<" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
211
	 */
212
	public static function getShortLanguageName()
213
	{
214
		$language = self::getLanguage();
215
		return substr($language, 0, 2);
216
	}
217
218
	/**
219
	 * Function returns module strings.
220
	 *
221
	 * @param <String> $module - module Name
0 ignored issues
show
Documentation introduced by
The doc-type <String> could not be parsed: Unknown type name "<" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
222
	 * @param  <String> languageStrings or jsLanguageStrings
223
	 * @param mixed $type
224
	 *
225
	 * @return <Array>
0 ignored issues
show
Documentation introduced by
The doc-type <Array> could not be parsed: Unknown type name "<" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
226
	 */
227
	public static function export($module, $type = 'php')
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
228
	{
229
		$language = self::getLanguage();
230
		$exportLangString = [];
231
232
		$moduleStrings = self::getModuleStringsFromFile($language, $module);
233
		if (!empty($moduleStrings[$type])) {
234
			$exportLangString = $moduleStrings[$type];
235
		}
236
237
		$commonStrings = self::getModuleStringsFromFile($language);
238
		if (!empty($commonStrings[$type])) {
239
			$exportLangString += $commonStrings[$type];
240
		}
241
		return $exportLangString;
242
	}
243
244
	public static function translateModule($module)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
245
	{
246
		if (!self::$modules) {
247
			$userInstance = User::getUser();
248
			self::$modules = $userInstance->getModulesList();
249
		}
250
		return self::$modules[$module] ?? $module;
251
	}
252
253
	/**
254
	 * Get display language name.
255
	 *
256
	 * @param string $prefix
257
	 *
258
	 * @return string
259
	 */
260
	public static function getDisplayName(string $prefix): string
261
	{
262
		return Utils::mbUcfirst(locale_get_region($prefix) === strtoupper(locale_get_primary_language($prefix)) ? locale_get_display_language($prefix, $prefix) : locale_get_display_name($prefix, $prefix));
263
	}
264
}
265