1: <?php
2: //= api-features
3: //: - Translations
4:
5: namespace aliuly\common;
6:
7: /**
8: * Simple translation class in the style of **gettext**.
9: *
10: * You can actually use **gettext** tools to process these files.
11: * For example, to create/update a message catalogue use:
12: *
13: * `xgettext --no-wrap [-j] [-o file]`
14: *
15: * Where -j is used to join an existing catalague.
16: * -o file is the output file.
17: *
18: * Basic usage:
19: *
20: * * mc::load("messages.po|messages.ini");
21: * * mc::plugin_init($plugin,$plugin->getFile());
22: * * mc::_("string to translate\n")
23: * * mc::_("string to translate %1% %2%\n",$arg1,$arg2)
24: * * mc::n(mc::\_("singular form"),mc::\_("Plural form"),$count)
25: */
26: abstract class mc {
27: /** @var str[] $txt Message translations */
28: public static $txt = [];
29: /** Main translation function
30: *
31: * This translates strings. The naming of "_" is to make it compatible
32: * with gettext utilities. The string can contain "%1%", "%2%, etc...
33: * These are inserted from the following arguments. Use "%%" to insert
34: * a single "%".
35: *
36: * @param str[] $args - messages
37: * @return str translated string
38: */
39: public static function _(...$args) {
40: $fmt = array_shift($args);
41: if (isset(self::$txt[$fmt])) $fmt = self::$txt[$fmt];
42: if (count($args)) {
43: $vars = [ "%%" => "%" ];
44: $i = 1;
45: foreach ($args as $j) {
46: $vars["%$i%"] = $j;
47: ++$i;
48: }
49: $fmt = strtr($fmt,$vars);
50: }
51: return $fmt;
52: }
53: /**
54: * Plural and singular forms.
55: *
56: * @param str $a - Singular form
57: * @param str $b - Plural form
58: * @param int $c - the number to test to select between $a or $b
59: * @return str - Either plural or singular forms depending on the value of $c
60: */
61: public static function n($a,$b,$c) {
62: return $c == 1 ? $a : $b;
63: }
64: /**
65: * Load a message file for a PocketMine plugin. Only uses .ini files.
66: *
67: * @param Plugin $plugin - owning plugin
68: * @param str $path - output of $plugin->getFile()
69: * @return int|false - false on error or the number of messages loaded
70: */
71: public static function plugin_init($plugin,$path) {
72: if (file_exists($plugin->getDataFolder()."messages.ini")) {
73: return self::load($plugin->getDataFolder()."messages.ini");
74: }
75: $msgs = $path."resources/messages/".
76: $plugin->getServer()->getProperty("settings.language").
77: ".ini";
78: if (!file_exists($msgs)) return false;
79: return self::load($msgs);
80: }
81:
82: /**
83: * Load the specified message catalogue.
84: * Can read .ini or .po files.
85: * @param str $f - Filename to load
86: * @return int|false - returns the number of strings loaded or false on error
87: */
88: public static function load($f) {
89: $potxt = "\n".file_get_contents($f)."\n";
90: if (preg_match('/\nmsgid\s/',$potxt)) {
91: $potxt = preg_replace('/\\\\n"\n"/',"\\n",
92: preg_replace('/\s+""\s*\n\s*"/'," \"",
93: $potxt));
94: }
95: foreach (['/\nmsgid "(.+)"\nmsgstr "(.+)"\n/',
96: '/^\s*"(.+)"\s*=\s*"(.+)"\s*$/m'] as $re) {
97: $c = preg_match_all($re,$potxt,$mm);
98: if ($c) {
99: for ($i=0;$i<$c;++$i) {
100: if ($mm[2][$i] == "") continue;
101: eval('$a = "'.$mm[1][$i].'";');
102: eval('$b = "'.$mm[2][$i].'";');
103: self::$txt[$a] = $b;
104: }
105: return $c;
106: }
107: }
108: return false;
109: }
110: }
111: