Completed
Push — master ( 2dc57f...5b6128 )
by Thomas
36:44 queued 22:51
created

L10N::getPluralFormFunction()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 0
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Joas Schilling <[email protected]>
4
 * @author Thomas Müller <[email protected]>
5
 *
6
 * @copyright Copyright (c) 2017, ownCloud GmbH
7
 * @license AGPL-3.0
8
 *
9
 * This code is free software: you can redistribute it and/or modify
10
 * it under the terms of the GNU Affero General Public License, version 3,
11
 * as published by the Free Software Foundation.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
 * GNU Affero General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License, version 3,
19
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
20
 *
21
 */
22
23
namespace OC\L10N;
24
25
use OCP\IL10N;
26
use OCP\L10N\IFactory;
27
use Punic\Calendar;
28
use Symfony\Component\Translation\PluralizationRules;
29
30
class L10N implements IL10N {
31
32
	/** @var IFactory */
33
	protected $factory;
34
35
	/** @var string App of this object */
36
	protected $app;
37
38
	/** @var string Language of this object */
39
	protected $lang;
40
41
	/** @var string[] */
42
	private $translations = [];
43
44
	/**
45
	 * @param IFactory $factory
46
	 * @param string $app
47
	 * @param string $lang
48
	 * @param array $files
49
	 */
50
	public function __construct(IFactory $factory, $app, $lang, array $files) {
51
		$this->factory = $factory;
52
		$this->app = $app;
53
		$this->lang = $lang;
54
55
		$this->translations = [];
56
		foreach ($files as $languageFile) {
57
			$this->load($languageFile);
58
		}
59
	}
60
61
	/**
62
	 * The code (en, de, ...) of the language that is used for this instance
63
	 *
64
	 * @return string language
65
	 */
66
	public function getLanguageCode() {
67
		return $this->lang;
68
	}
69
70
	/**
71
	 * Translating
72
	 * @param string $text The text we need a translation for
73
	 * @param array $parameters default:array() Parameters for sprintf
74
	 * @return string Translation or the same text
75
	 *
76
	 * Returns the translation. If no translation is found, $text will be
77
	 * returned.
78
	 */
79
	public function t($text, $parameters = []) {
80
		return (string) new L10NString($this, $text, $parameters);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return (string) new \OC\...s, $text, $parameters); (string) is incompatible with the return type declared by the interface OCP\IL10N::t of type OC\L10N\L10NString.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
81
	}
82
83
	/**
84
	 * Translating
85
	 * @param string $text_singular the string to translate for exactly one object
86
	 * @param string $text_plural the string to translate for n objects
87
	 * @param integer $count Number of objects
88
	 * @param array $parameters default:array() Parameters for sprintf
89
	 * @return string Translation or the same text
90
	 *
91
	 * Returns the translation. If no translation is found, $text will be
92
	 * returned. %n will be replaced with the number of objects.
93
	 *
94
	 * The correct plural is determined by the plural_forms-function
95
	 * provided by the po file.
96
	 *
97
	 */
98
	public function n($text_singular, $text_plural, $count, $parameters = []) {
99
		$identifier = "_${text_singular}_::_${text_plural}_";
100
		if (isset($this->translations[$identifier])) {
101
			return (string) new L10NString($this, $identifier, $parameters, $count);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return (string) new \OC\..., $parameters, $count); (string) is incompatible with the return type declared by the interface OCP\IL10N::n of type OC\L10N\L10NString.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
102
		} else {
103
			if ($count === 1) {
104
				return (string) new L10NString($this, $text_singular, $parameters, $count);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return (string) new \OC\..., $parameters, $count); (string) is incompatible with the return type declared by the interface OCP\IL10N::n of type OC\L10N\L10NString.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
105
			} else {
106
				return (string) new L10NString($this, $text_plural, $parameters, $count);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return (string) new \OC\..., $parameters, $count); (string) is incompatible with the return type declared by the interface OCP\IL10N::n of type OC\L10N\L10NString.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
107
			}
108
		}
109
	}
110
111
	/**
112
	 * Localization
113
	 * @param string $type Type of localization
114
	 * @param \DateTime|int|string $data parameters for this localization
115
	 * @param array $options
116
	 * @return string|int|false
117
	 *
118
	 * Returns the localized data.
119
	 *
120
	 * Implemented types:
121
	 *  - date
122
	 *    - Creates a date
123
	 *    - params: timestamp (int/string)
124
	 *  - datetime
125
	 *    - Creates date and time
126
	 *    - params: timestamp (int/string)
127
	 *  - time
128
	 *    - Creates a time
129
	 *    - params: timestamp (int/string)
130
	 *  - firstday: Returns the first day of the week (0 sunday - 6 saturday)
131
	 *  - jsdate: Returns the short JS date format
132
	 */
133
	public function l($type, $data = null, $options = []) {
134
		// Use the language of the instance
135
		$locale = $this->getLanguageCode();
136
		if ($locale === 'sr@latin') {
137
			$locale = 'sr_latn';
138
		}
139
140
		if ($type === 'firstday') {
141
			return (int) Calendar::getFirstWeekday($locale);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return (int) \Punic\Cale...tFirstWeekday($locale); (integer) is incompatible with the return type declared by the interface OCP\IL10N::l of type string|false.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
142
		}
143
		if ($type === 'jsdate') {
144
			return (string) Calendar::getDateFormat('short', $locale);
145
		}
146
147
		$value = new \DateTime();
148
		if ($data instanceof \DateTime) {
149
			$value = $data;
150
		} else if (is_string($data) && !is_numeric($data)) {
151
			$data = strtotime($data);
152
			$value->setTimestamp($data);
153
		} else if ($data !== null) {
154
			$value->setTimestamp($data);
155
		}
156
157
		$options = array_merge(['width' => 'long'], $options);
158
		$width = $options['width'];
159
		switch ($type) {
160
			case 'date':
161
				return (string) Calendar::formatDate($value, $width, $locale);
162
			case 'datetime':
163
				return (string) Calendar::formatDatetime($value, $width, $locale);
164
			case 'time':
165
				return (string) Calendar::formatTime($value, $width, $locale);
166
			default:
167
				return false;
168
		}
169
	}
170
171
	/**
172
	 * Returns an associative array with all translations
173
	 *
174
	 * Called by String
175
	 * @return array
176
	 */
177
	public function getTranslations() {
178
		return $this->translations;
179
	}
180
181
	/**
182
	 * @param $translationFile
183
	 * @return bool
184
	 */
185
	protected function load($translationFile) {
186
		$json = json_decode(file_get_contents($translationFile), true);
187
		if (!is_array($json)) {
188
			$jsonError = json_last_error();
189
			\OC::$server->getLogger()->warning("Failed to load $translationFile - json error code: $jsonError", ['app' => 'l10n']);
190
			return false;
191
		}
192
193
		$this->translations = array_merge($this->translations, $json['translations']);
194
		return true;
195
	}
196
197
	/**
198
	 * Computes the plural form
199
	 *
200
	 * @param int $number
201
	 * @return int
202
	 */
203
	public function computePlural($number) {
204
		return PluralizationRules::get($number, $this->lang);
205
	}
206
}
207