I18nUtil.php
1 <?php
2 /**
3  * wCMF - wemove Content Management Framework
4  * Copyright (C) 2005-2020 wemove digital solutions GmbH
5  *
6  * Licensed under the terms of the MIT License.
7  *
8  * See the LICENSE file distributed with this work for
9  * additional information.
10  */
11 namespace wcmf\lib\util;
12 
16 
17 /**
18  * I18nUtil provides support i18n functionality.
19  *
20  * @author ingo herwig <ingo@wemove.com>
21  */
22 class I18nUtil {
23 
24  private static $result = [];
25  private static $baseDir = '';
26 
27  /**
28  * Get all messages from a directory recursively.
29  * @param $directory The directory to search in
30  * @param $exclude Array of directory names that are excluded from search
31  * @param $pattern The pattern the names of the files to search in must match
32  * @param $depth Internal use only
33  * @return An assoziative array with the filenames as keys and the values as
34  * array of strings.
35  * @see I18nUtil::getMessagesFromFile
36  */
37  public static function getMessages($directory, $exclude, $pattern, $depth=0) {
38 
39  if ($depth == 0) {
40  self::$baseDir = $directory;
41  }
42  if (substr($directory, -1) != '/') {
43  $directory .= '/';
44  }
45  if (is_dir($directory)) {
46  $d = dir($directory);
47  $d->rewind();
48  while(false !== ($file = $d->read())) {
49  if($file != '.' && $file != '..' && !in_array($file, $exclude)) {
50  if (is_dir($directory.$file)) {
51  self::getMessages($directory.$file, $exclude, $pattern, ++$depth);
52  }
53  elseif (preg_match($pattern, $file)) {
54  $messages = self::getMessagesFromFile($directory.$file);
55  if (sizeof($messages) > 0) {
56  $key = str_replace(self::$baseDir, '', $directory.$file);
57  self::$result[$key] = $messages;
58  }
59  }
60  }
61  }
62  $d->close();
63  }
64  else {
65  throw new IllegalArgumentException("The directory '".$directory."' does not exist.");
66  }
67  return self::$result;
68  }
69 
70  /**
71  * Get all messages from a file. Searches for parameters of the Message::getText
72  * method and usage of the smarty 'translate' function.
73  * @param $file The file to search in
74  * @return An array of strings.
75  * @note This method searches for occurrences of '->getText('Text to translate')',
76  * 'Dict.translate("Text to translate")' or {translate:"Text to translate"} where
77  * 'Text to translate' is supposed to be the message to translate. So it might not
78  * find the usage of the getText() method with concatenated strings
79  * (like $message->getText($login." says hello")). For replacements
80  * use method signatures, that support parameters.
81  */
82  public static function getMessagesFromFile($file) {
83  $result = [];
84  if (file_exists($file) && realpath($file) != __FILE__) {
85  $fh = fopen($file, "r");
86  $content = fread($fh, filesize ($file));
87  fclose($fh);
88  $messagePatterns = [
89  '->getText\(([\'"])(.*?)\\1', // usage in PHP code, e.g. $message->getText("Text to translate")
90  'Dict\.translate\(([\'"])(.*?)\\3', // usage in JS code, e.g. Dict.translate("Text to translate")
91  '\{translate:(.*?)[\|\}]', // usage in dojo template, e.g. {translate:Text to translate}, {translate:Text to translate|...}
92  '\{translate.*? text=([\'"])(.*?)\\6', // usage in Smarty template, e.g. {translate text="Text to translate"}
93  ];
94  preg_match_all('/'.join('|', $messagePatterns).'/i', $content, $matchesTmp);
95  $matches = [];
96  // filter out empty and duplicates
97  foreach(array_merge($matchesTmp[2], $matchesTmp[4], $matchesTmp[5], $matchesTmp[7]) as $match) {
98  if ($match != '' && !in_array($match, $matches)) {
99  $matches[] = $match;
100  }
101  }
102  if (sizeof($matches) > 0) {
103  $result = $matches;
104  }
105  }
106  return $result;
107  }
108 
109  /**
110  * Create a message file for use with the Message class. The file will
111  * be created in the directory defined in configutation key 'localeDir' in
112  * 'application' section.
113  * @param $language The language of the file (language code e.g. 'de')
114  * @param $messages An assoziative array with the messages as keys
115  * and assoziative array with keys 'translation' and 'files' (occurences of the message)
116  * @return Boolean whether successful or not.
117  */
118  public static function createPHPLanguageFile($language, $messages) {
119  $fileUtil = new FileUtil();
120 
121  // get locale directory
122  $config = ObjectFactory::getInstance('configuration');
123  $localeDir = $config->getDirectoryValue('localeDir', 'application');
124  $fileUtil->mkdirRec($localeDir);
125  $file = $localeDir.'messages_'.$language.'.php';
126 
127  // backup old file
128  if (file_exists($file)) {
129  rename($file, $file.".bak");
130  }
131  $fh = fopen($file, "w");
132 
133  // write header
134  $header = <<<EOT
135 <?php
136 \$messages_{$language} = [];
137 \$messages_{$language}[''] = '';
138 EOT;
139  fwrite($fh, $header."\n");
140 
141  // write messages
142  foreach($messages as $message => $attributes) {
143  $lines = '// file(s): '.$attributes['files']."\n";
144  $lines .= "\$messages_".$language."['".str_replace("'", "\'", $message)."'] = '".str_replace("'", "\'", $attributes['translation'])."';"."\n";
145  fwrite($fh, $lines);
146  }
147 
148  // write footer
149  $footer = <<<EOT
150 ?>
151 EOT;
152  fwrite($fh, $footer."\n");
153 
154  fclose($fh);
155  }
156 }
157 ?>
IllegalArgumentException signals an exception in method arguments.
static createPHPLanguageFile($language, $messages)
Create a message file for use with the Message class.
Definition: I18nUtil.php:118
I18nUtil provides support i18n functionality.
Definition: I18nUtil.php:22
static getMessagesFromFile($file)
Get all messages from a file.
Definition: I18nUtil.php:82
FileUtil provides basic support for file functionality like HTTP file upload.
Definition: FileUtil.php:22
static getInstance($name, $dynamicConfiguration=[])
Utility classes.
Definition: namespaces.php:97
static getMessages($directory, $exclude, $pattern, $depth=0)
Get all messages from a directory recursively.
Definition: I18nUtil.php:37
ObjectFactory implements the service locator pattern by wrapping a Factory instance and providing sta...