Transposh WordPress Translation - Version 0.3.5

Version Description

Download this release

Release Info

Developer oferwald
Plugin Icon 128x128 Transposh WordPress Translation
Version 0.3.5
Comparing to
See all releases

Code changes from version 0.3.4 to 0.3.5

core/constants.php CHANGED
@@ -91,41 +91,7 @@ $rtl_languages = array("ar", "he", "fa", "yi");
91
  //Define the new capability that will be assigned to roles - translator
92
  define("TRANSLATOR", 'translator');
93
 
94
- //Option defining whether anonymous translation is allowed.
95
- define("ANONYMOUS_TRANSLATION", "transposh_allow_anonymous_translation");
96
-
97
- //Option defining the list of currentlly viewable languages
98
- define("VIEWABLE_LANGS", "transposh_viewable_languages");
99
-
100
- //Option defining the list of currentlly editable languages
101
- define("EDITABLE_LANGS", "transposh_editable_languages");
102
-
103
- //Option to enable/disable auto translation
104
- define("ENABLE_AUTO_TRANSLATE", "transposh_enable_autotranslate");
105
-
106
- //Option to enable/disable msn translation
107
- define("ENABLE_MSN_TRANSLATE", "transposh_enable_msntranslate");
108
-
109
- //Option to store the msn API key
110
- define("MSN_TRANSLATE_KEY", "transposh_msn_key");
111
-
112
- //Option to enable/disable rewrite of permalinks
113
- define("ENABLE_PERMALINKS_REWRITE", "transposh_enable_permalinks");
114
-
115
- //Option to enable/disable default language translation
116
- define("ENABLE_DEFAULT_TRANSLATE", "transposh_enable_default_translate");
117
-
118
- //Option to enable/disable footer scripts (2.8 and up)
119
- define("ENABLE_FOOTER_SCRIPTS", "transposh_enable_footer_scripts");
120
-
121
- //Use CSS sprites for flags if available
122
- define("ENABLE_CSS_FLAGS", "transposh_enable_css_flags");
123
-
124
- //Option defining the default language
125
- define("DEFAULT_LANG", "transposh_default_language");
126
-
127
- //Option defining transposh widget appearance
128
- define("WIDGET_TRANSPOSH", "transposh_widget");
129
 
130
  //Define segment id prefix, will be included in span tag. also used as class identifier
131
  define("SPAN_PREFIX", "tr_");
@@ -133,4 +99,7 @@ define("SPAN_PREFIX", "tr_");
133
  //The name of our admin page
134
  define('TRANSPOSH_ADMIN_PAGE_NAME', 'transposh');
135
 
 
 
 
136
  ?>
91
  //Define the new capability that will be assigned to roles - translator
92
  define("TRANSLATOR", 'translator');
93
 
94
+ define("TRANSPOSH_PLUGIN_VER",'0.3.5');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
 
96
  //Define segment id prefix, will be included in span tag. also used as class identifier
97
  define("SPAN_PREFIX", "tr_");
99
  //The name of our admin page
100
  define('TRANSPOSH_ADMIN_PAGE_NAME', 'transposh');
101
 
102
+ //0.3.5 - Storing all options in this config option
103
+ define("TRANSPOSH_OPTIONS", "transposh_options");
104
+
105
  ?>
core/globals.php CHANGED
@@ -25,22 +25,22 @@
25
  */
26
 
27
  //Home (root) url of the site/blog under which translation will take place.
28
- $home_url;
29
 
30
  //The url pointing to the base of the plugin. Used for generating urls to resources
31
- $tr_plugin_url;
32
 
33
  //The language to which the current page will be translated to.
34
- $lang;
35
 
36
  //Is the current user is in edit mode.
37
- $is_edit_mode = FALSE;
38
 
39
  //Indicates whether automatic translation (i.e. google) is enabled for this page
40
- $enable_auto_translate = FALSE;
41
 
42
  //Indicates whether to use parameters when rewriting url as oppposed to using permalinks format
43
  // http://wordpress?lang=he vs. http://wordpress/he/ when flag is set to TRUE
44
- $enable_permalinks_rewrite = FALSE;
45
 
46
  ?>
25
  */
26
 
27
  //Home (root) url of the site/blog under which translation will take place.
28
+ //$home_url;
29
 
30
  //The url pointing to the base of the plugin. Used for generating urls to resources
31
+ //$tr_plugin_url;
32
 
33
  //The language to which the current page will be translated to.
34
+ //$lang;
35
 
36
  //Is the current user is in edit mode.
37
+ //$is_edit_mode = FALSE;
38
 
39
  //Indicates whether automatic translation (i.e. google) is enabled for this page
40
+ //$enable_auto_translate = FALSE;
41
 
42
  //Indicates whether to use parameters when rewriting url as oppposed to using permalinks format
43
  // http://wordpress?lang=he vs. http://wordpress/he/ when flag is set to TRUE
44
+ //$enable_permalinks_rewrite = FALSE;
45
 
46
  ?>
core/jsonwrapper/JSON.php ADDED
@@ -0,0 +1,804 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Converts to and from JSON format.
4
+ *
5
+ * JSON (JavaScript Object Notation) is a lightweight data-interchange
6
+ * format. It is easy for humans to read and write. It is easy for machines
7
+ * to parse and generate. It is based on a subset of the JavaScript
8
+ * Programming Language, Standard ECMA-262 3rd Edition - December 1999.
9
+ * This feature can also be found in Python. JSON is a text format that is
10
+ * completely language independent but uses conventions that are familiar
11
+ * to programmers of the C-family of languages, including C, C++, C#, Java,
12
+ * JavaScript, Perl, TCL, and many others. These properties make JSON an
13
+ * ideal data-interchange language.
14
+ *
15
+ * This package provides a simple encoder and decoder for JSON notation. It
16
+ * is intended for use with client-side Javascript applications that make
17
+ * use of HTTPRequest to perform server communication functions - data can
18
+ * be encoded into JSON notation for use in a client-side javascript, or
19
+ * decoded from incoming Javascript requests. JSON format is native to
20
+ * Javascript, and can be directly eval()'ed with no further parsing
21
+ * overhead
22
+ *
23
+ * All strings should be in ASCII or UTF-8 format!
24
+ *
25
+ * LICENSE: Redistribution and use in source and binary forms, with or
26
+ * without modification, are permitted provided that the following
27
+ * conditions are met: Redistributions of source code must retain the
28
+ * above copyright notice, this list of conditions and the following
29
+ * disclaimer. Redistributions in binary form must reproduce the above
30
+ * copyright notice, this list of conditions and the following disclaimer
31
+ * in the documentation and/or other materials provided with the
32
+ * distribution.
33
+ *
34
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
35
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
36
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
37
+ * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
38
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
39
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
40
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
42
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
43
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
44
+ * DAMAGE.
45
+ *
46
+ * @category
47
+ * @package Services_JSON
48
+ * @author Michal Migurski <mike-json@teczno.com>
49
+ * @author Matt Knapp <mdknapp[at]gmail[dot]com>
50
+ * @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
51
+ * @copyright 2005 Michal Migurski
52
+ * @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $
53
+ * @license http://www.opensource.org/licenses/bsd-license.php
54
+ * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198
55
+ */
56
+
57
+ /**
58
+ * Marker constant for Services_JSON::decode(), used to flag stack state
59
+ */
60
+ define('SERVICES_JSON_SLICE', 1);
61
+
62
+ /**
63
+ * Marker constant for Services_JSON::decode(), used to flag stack state
64
+ */
65
+ define('SERVICES_JSON_IN_STR', 2);
66
+
67
+ /**
68
+ * Marker constant for Services_JSON::decode(), used to flag stack state
69
+ */
70
+ define('SERVICES_JSON_IN_ARR', 3);
71
+
72
+ /**
73
+ * Marker constant for Services_JSON::decode(), used to flag stack state
74
+ */
75
+ define('SERVICES_JSON_IN_OBJ', 4);
76
+
77
+ /**
78
+ * Marker constant for Services_JSON::decode(), used to flag stack state
79
+ */
80
+ define('SERVICES_JSON_IN_CMT', 5);
81
+
82
+ /**
83
+ * Behavior switch for Services_JSON::decode()
84
+ */
85
+ define('SERVICES_JSON_LOOSE_TYPE', 16);
86
+
87
+ /**
88
+ * Behavior switch for Services_JSON::decode()
89
+ */
90
+ define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
91
+
92
+ /**
93
+ * Converts to and from JSON format.
94
+ *
95
+ * Brief example of use:
96
+ *
97
+ * <code>
98
+ * // create a new instance of Services_JSON
99
+ * $json = new Services_JSON();
100
+ *
101
+ * // convert a complexe value to JSON notation, and send it to the browser
102
+ * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
103
+ * $output = $json->encode($value);
104
+ *
105
+ * print($output);
106
+ * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
107
+ *
108
+ * // accept incoming POST data, assumed to be in JSON notation
109
+ * $input = file_get_contents('php://input', 1000000);
110
+ * $value = $json->decode($input);
111
+ * </code>
112
+ */
113
+ class Services_JSON
114
+ {
115
+ /**
116
+ * constructs a new JSON instance
117
+ *
118
+ * @param int $use object behavior flags; combine with boolean-OR
119
+ *
120
+ * possible values:
121
+ * - SERVICES_JSON_LOOSE_TYPE: loose typing.
122
+ * "{...}" syntax creates associative arrays
123
+ * instead of objects in decode().
124
+ * - SERVICES_JSON_SUPPRESS_ERRORS: error suppression.
125
+ * Values which can't be encoded (e.g. resources)
126
+ * appear as NULL instead of throwing errors.
127
+ * By default, a deeply-nested resource will
128
+ * bubble up with an error, so all return values
129
+ * from encode() should be checked with isError()
130
+ */
131
+ function Services_JSON($use = 0)
132
+ {
133
+ $this->use = $use;
134
+ }
135
+
136
+ /**
137
+ * convert a string from one UTF-16 char to one UTF-8 char
138
+ *
139
+ * Normally should be handled by mb_convert_encoding, but
140
+ * provides a slower PHP-only method for installations
141
+ * that lack the multibye string extension.
142
+ *
143
+ * @param string $utf16 UTF-16 character
144
+ * @return string UTF-8 character
145
+ * @access private
146
+ */
147
+ function utf162utf8($utf16)
148
+ {
149
+ // oh please oh please oh please oh please oh please
150
+ if(function_exists('mb_convert_encoding')) {
151
+ return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
152
+ }
153
+
154
+ $bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
155
+
156
+ switch(true) {
157
+ case ((0x7F & $bytes) == $bytes):
158
+ // this case should never be reached, because we are in ASCII range
159
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
160
+ return chr(0x7F & $bytes);
161
+
162
+ case (0x07FF & $bytes) == $bytes:
163
+ // return a 2-byte UTF-8 character
164
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
165
+ return chr(0xC0 | (($bytes >> 6) & 0x1F))
166
+ . chr(0x80 | ($bytes & 0x3F));
167
+
168
+ case (0xFFFF & $bytes) == $bytes:
169
+ // return a 3-byte UTF-8 character
170
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
171
+ return chr(0xE0 | (($bytes >> 12) & 0x0F))
172
+ . chr(0x80 | (($bytes >> 6) & 0x3F))
173
+ . chr(0x80 | ($bytes & 0x3F));
174
+ }
175
+
176
+ // ignoring UTF-32 for now, sorry
177
+ return '';
178
+ }
179
+
180
+ /**
181
+ * convert a string from one UTF-8 char to one UTF-16 char
182
+ *
183
+ * Normally should be handled by mb_convert_encoding, but
184
+ * provides a slower PHP-only method for installations
185
+ * that lack the multibye string extension.
186
+ *
187
+ * @param string $utf8 UTF-8 character
188
+ * @return string UTF-16 character
189
+ * @access private
190
+ */
191
+ function utf82utf16($utf8)
192
+ {
193
+ // oh please oh please oh please oh please oh please
194
+ if(function_exists('mb_convert_encoding')) {
195
+ return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
196
+ }
197
+
198
+ switch(strlen($utf8)) {
199
+ case 1:
200
+ // this case should never be reached, because we are in ASCII range
201
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
202
+ return $utf8;
203
+
204
+ case 2:
205
+ // return a UTF-16 character from a 2-byte UTF-8 char
206
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
207
+ return chr(0x07 & (ord($utf8{0}) >> 2))
208
+ . chr((0xC0 & (ord($utf8{0}) << 6))
209
+ | (0x3F & ord($utf8{1})));
210
+
211
+ case 3:
212
+ // return a UTF-16 character from a 3-byte UTF-8 char
213
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
214
+ return chr((0xF0 & (ord($utf8{0}) << 4))
215
+ | (0x0F & (ord($utf8{1}) >> 2)))
216
+ . chr((0xC0 & (ord($utf8{1}) << 6))
217
+ | (0x7F & ord($utf8{2})));
218
+ }
219
+
220
+ // ignoring UTF-32 for now, sorry
221
+ return '';
222
+ }
223
+
224
+ /**
225
+ * encodes an arbitrary variable into JSON format
226
+ *
227
+ * @param mixed $var any number, boolean, string, array, or object to be encoded.
228
+ * see argument 1 to Services_JSON() above for array-parsing behavior.
229
+ * if var is a strng, note that encode() always expects it
230
+ * to be in ASCII or UTF-8 format!
231
+ *
232
+ * @return mixed JSON string representation of input var or an error if a problem occurs
233
+ * @access public
234
+ */
235
+ function encode($var)
236
+ {
237
+ switch (gettype($var)) {
238
+ case 'boolean':
239
+ return $var ? 'true' : 'false';
240
+
241
+ case 'NULL':
242
+ return 'null';
243
+
244
+ case 'integer':
245
+ return (int) $var;
246
+
247
+ case 'double':
248
+ case 'float':
249
+ return (float) $var;
250
+
251
+ case 'string':
252
+ // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
253
+ $ascii = '';
254
+ $strlen_var = strlen($var);
255
+
256
+ /*
257
+ * Iterate over every character in the string,
258
+ * escaping with a slash or encoding to UTF-8 where necessary
259
+ */
260
+ for ($c = 0; $c < $strlen_var; ++$c) {
261
+
262
+ $ord_var_c = ord($var{$c});
263
+
264
+ switch (true) {
265
+ case $ord_var_c == 0x08:
266
+ $ascii .= '\b';
267
+ break;
268
+ case $ord_var_c == 0x09:
269
+ $ascii .= '\t';
270
+ break;
271
+ case $ord_var_c == 0x0A:
272
+ $ascii .= '\n';
273
+ break;
274
+ case $ord_var_c == 0x0C:
275
+ $ascii .= '\f';
276
+ break;
277
+ case $ord_var_c == 0x0D:
278
+ $ascii .= '\r';
279
+ break;
280
+
281
+ case $ord_var_c == 0x22:
282
+ case $ord_var_c == 0x2F:
283
+ case $ord_var_c == 0x5C:
284
+ // double quote, slash, slosh
285
+ $ascii .= '\\'.$var{$c};
286
+ break;
287
+
288
+ case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
289
+ // characters U-00000000 - U-0000007F (same as ASCII)
290
+ $ascii .= $var{$c};
291
+ break;
292
+
293
+ case (($ord_var_c & 0xE0) == 0xC0):
294
+ // characters U-00000080 - U-000007FF, mask 110XXXXX
295
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
296
+ $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
297
+ $c += 1;
298
+ $utf16 = $this->utf82utf16($char);
299
+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
300
+ break;
301
+
302
+ case (($ord_var_c & 0xF0) == 0xE0):
303
+ // characters U-00000800 - U-0000FFFF, mask 1110XXXX
304
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
305
+ $char = pack('C*', $ord_var_c,
306
+ ord($var{$c + 1}),
307
+ ord($var{$c + 2}));
308
+ $c += 2;
309
+ $utf16 = $this->utf82utf16($char);
310
+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
311
+ break;
312
+
313
+ case (($ord_var_c & 0xF8) == 0xF0):
314
+ // characters U-00010000 - U-001FFFFF, mask 11110XXX
315
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
316
+ $char = pack('C*', $ord_var_c,
317
+ ord($var{$c + 1}),
318
+ ord($var{$c + 2}),
319
+ ord($var{$c + 3}));
320
+ $c += 3;
321
+ $utf16 = $this->utf82utf16($char);
322
+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
323
+ break;
324
+
325
+ case (($ord_var_c & 0xFC) == 0xF8):
326
+ // characters U-00200000 - U-03FFFFFF, mask 111110XX
327
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
328
+ $char = pack('C*', $ord_var_c,
329
+ ord($var{$c + 1}),
330
+ ord($var{$c + 2}),
331
+ ord($var{$c + 3}),
332
+ ord($var{$c + 4}));
333
+ $c += 4;
334
+ $utf16 = $this->utf82utf16($char);
335
+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
336
+ break;
337
+
338
+ case (($ord_var_c & 0xFE) == 0xFC):
339
+ // characters U-04000000 - U-7FFFFFFF, mask 1111110X
340
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
341
+ $char = pack('C*', $ord_var_c,
342
+ ord($var{$c + 1}),
343
+ ord($var{$c + 2}),
344
+ ord($var{$c + 3}),
345
+ ord($var{$c + 4}),
346
+ ord($var{$c + 5}));
347
+ $c += 5;
348
+ $utf16 = $this->utf82utf16($char);
349
+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
350
+ break;
351
+ }
352
+ }
353
+
354
+ return '"'.$ascii.'"';
355
+
356
+ case 'array':
357
+ /*
358
+ * As per JSON spec if any array key is not an integer
359
+ * we must treat the the whole array as an object. We
360
+ * also try to catch a sparsely populated associative
361
+ * array with numeric keys here because some JS engines
362
+ * will create an array with empty indexes up to
363
+ * max_index which can cause memory issues and because
364
+ * the keys, which may be relevant, will be remapped
365
+ * otherwise.
366
+ *
367
+ * As per the ECMA and JSON specification an object may
368
+ * have any string as a property. Unfortunately due to
369
+ * a hole in the ECMA specification if the key is a
370
+ * ECMA reserved word or starts with a digit the
371
+ * parameter is only accessible using ECMAScript's
372
+ * bracket notation.
373
+ */
374
+
375
+ // treat as a JSON object
376
+ if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
377
+ $properties = array_map(array($this, 'name_value'),
378
+ array_keys($var),
379
+ array_values($var));
380
+
381
+ foreach($properties as $property) {
382
+ if(Services_JSON::isError($property)) {
383
+ return $property;
384
+ }
385
+ }
386
+
387
+ return '{' . join(',', $properties) . '}';
388
+ }
389
+
390
+ // treat it like a regular array
391
+ $elements = array_map(array($this, 'encode'), $var);
392
+
393
+ foreach($elements as $element) {
394
+ if(Services_JSON::isError($element)) {
395
+ return $element;
396
+ }
397
+ }
398
+
399
+ return '[' . join(',', $elements) . ']';
400
+
401
+ case 'object':
402
+ $vars = get_object_vars($var);
403
+
404
+ $properties = array_map(array($this, 'name_value'),
405
+ array_keys($vars),
406
+ array_values($vars));
407
+
408
+ foreach($properties as $property) {
409
+ if(Services_JSON::isError($property)) {
410
+ return $property;
411
+ }
412
+ }
413
+
414
+ return '{' . join(',', $properties) . '}';
415
+
416
+ default:
417
+ return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
418
+ ? 'null'
419
+ : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
420
+ }
421
+ }
422
+
423
+ /**
424
+ * array-walking function for use in generating JSON-formatted name-value pairs
425
+ *
426
+ * @param string $name name of key to use
427
+ * @param mixed $value reference to an array element to be encoded
428
+ *
429
+ * @return string JSON-formatted name-value pair, like '"name":value'
430
+ * @access private
431
+ */
432
+ function name_value($name, $value)
433
+ {
434
+ $encoded_value = $this->encode($value);
435
+
436
+ if(Services_JSON::isError($encoded_value)) {
437
+ return $encoded_value;
438
+ }
439
+
440
+ return $this->encode(strval($name)) . ':' . $encoded_value;
441
+ }
442
+
443
+ /**
444
+ * reduce a string by removing leading and trailing comments and whitespace
445
+ *
446
+ * @param $str string string value to strip of comments and whitespace
447
+ *
448
+ * @return string string value stripped of comments and whitespace
449
+ * @access private
450
+ */
451
+ function reduce_string($str)
452
+ {
453
+ $str = preg_replace(array(
454
+
455
+ // eliminate single line comments in '// ...' form
456
+ '#^\s*//(.+)$#m',
457
+
458
+ // eliminate multi-line comments in '/* ... */' form, at start of string
459
+ '#^\s*/\*(.+)\*/#Us',
460
+
461
+ // eliminate multi-line comments in '/* ... */' form, at end of string
462
+ '#/\*(.+)\*/\s*$#Us'
463
+
464
+ ), '', $str);
465
+
466
+ // eliminate extraneous space
467
+ return trim($str);
468
+ }
469
+
470
+ /**
471
+ * decodes a JSON string into appropriate variable
472
+ *
473
+ * @param string $str JSON-formatted string
474
+ *
475
+ * @return mixed number, boolean, string, array, or object
476
+ * corresponding to given JSON input string.
477
+ * See argument 1 to Services_JSON() above for object-output behavior.
478
+ * Note that decode() always returns strings
479
+ * in ASCII or UTF-8 format!
480
+ * @access public
481
+ */
482
+ function decode($str)
483
+ {
484
+ $str = $this->reduce_string($str);
485
+
486
+ switch (strtolower($str)) {
487
+ case 'true':
488
+ return true;
489
+
490
+ case 'false':
491
+ return false;
492
+
493
+ case 'null':
494
+ return null;
495
+
496
+ default:
497
+ $m = array();
498
+
499
+ if (is_numeric($str)) {
500
+ // Lookie-loo, it's a number
501
+
502
+ // This would work on its own, but I'm trying to be
503
+ // good about returning integers where appropriate:
504
+ // return (float)$str;
505
+
506
+ // Return float or int, as appropriate
507
+ return ((float)$str == (integer)$str)
508
+ ? (integer)$str
509
+ : (float)$str;
510
+
511
+ } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
512
+ // STRINGS RETURNED IN UTF-8 FORMAT
513
+ $delim = substr($str, 0, 1);
514
+ $chrs = substr($str, 1, -1);
515
+ $utf8 = '';
516
+ $strlen_chrs = strlen($chrs);
517
+
518
+ for ($c = 0; $c < $strlen_chrs; ++$c) {
519
+
520
+ $substr_chrs_c_2 = substr($chrs, $c, 2);
521
+ $ord_chrs_c = ord($chrs{$c});
522
+
523
+ switch (true) {
524
+ case $substr_chrs_c_2 == '\b':
525
+ $utf8 .= chr(0x08);
526
+ ++$c;
527
+ break;
528
+ case $substr_chrs_c_2 == '\t':
529
+ $utf8 .= chr(0x09);
530
+ ++$c;
531
+ break;
532
+ case $substr_chrs_c_2 == '\n':
533
+ $utf8 .= chr(0x0A);
534
+ ++$c;
535
+ break;
536
+ case $substr_chrs_c_2 == '\f':
537
+ $utf8 .= chr(0x0C);
538
+ ++$c;
539
+ break;
540
+ case $substr_chrs_c_2 == '\r':
541
+ $utf8 .= chr(0x0D);
542
+ ++$c;
543
+ break;
544
+
545
+ case $substr_chrs_c_2 == '\\"':
546
+ case $substr_chrs_c_2 == '\\\'':
547
+ case $substr_chrs_c_2 == '\\\\':
548
+ case $substr_chrs_c_2 == '\\/':
549
+ if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
550
+ ($delim == "'" && $substr_chrs_c_2 != '\\"')) {
551
+ $utf8 .= $chrs{++$c};
552
+ }
553
+ break;
554
+
555
+ case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
556
+ // single, escaped unicode character
557
+ $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
558
+ . chr(hexdec(substr($chrs, ($c + 4), 2)));
559
+ $utf8 .= $this->utf162utf8($utf16);
560
+ $c += 5;
561
+ break;
562
+
563
+ case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
564
+ $utf8 .= $chrs{$c};
565
+ break;
566
+
567
+ case ($ord_chrs_c & 0xE0) == 0xC0:
568
+ // characters U-00000080 - U-000007FF, mask 110XXXXX
569
+ //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
570
+ $utf8 .= substr($chrs, $c, 2);
571
+ ++$c;
572
+ break;
573
+
574
+ case ($ord_chrs_c & 0xF0) == 0xE0:
575
+ // characters U-00000800 - U-0000FFFF, mask 1110XXXX
576
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
577
+ $utf8 .= substr($chrs, $c, 3);
578
+ $c += 2;
579
+ break;
580
+
581
+ case ($ord_chrs_c & 0xF8) == 0xF0:
582
+ // characters U-00010000 - U-001FFFFF, mask 11110XXX
583
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
584
+ $utf8 .= substr($chrs, $c, 4);
585
+ $c += 3;
586
+ break;
587
+
588
+ case ($ord_chrs_c & 0xFC) == 0xF8:
589
+ // characters U-00200000 - U-03FFFFFF, mask 111110XX
590
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
591
+ $utf8 .= substr($chrs, $c, 5);
592
+ $c += 4;
593
+ break;
594
+
595
+ case ($ord_chrs_c & 0xFE) == 0xFC:
596
+ // characters U-04000000 - U-7FFFFFFF, mask 1111110X
597
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
598
+ $utf8 .= substr($chrs, $c, 6);
599
+ $c += 5;
600
+ break;
601
+
602
+ }
603
+
604
+ }
605
+
606
+ return $utf8;
607
+
608
+ } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
609
+ // array, or object notation
610
+
611
+ if ($str{0} == '[') {
612
+ $stk = array(SERVICES_JSON_IN_ARR);
613
+ $arr = array();
614
+ } else {
615
+ if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
616
+ $stk = array(SERVICES_JSON_IN_OBJ);
617
+ $obj = array();
618
+ } else {
619
+ $stk = array(SERVICES_JSON_IN_OBJ);
620
+ $obj = new stdClass();
621
+ }
622
+ }
623
+
624
+ array_push($stk, array('what' => SERVICES_JSON_SLICE,
625
+ 'where' => 0,
626
+ 'delim' => false));
627
+
628
+ $chrs = substr($str, 1, -1);
629
+ $chrs = $this->reduce_string($chrs);
630
+
631
+ if ($chrs == '') {
632
+ if (reset($stk) == SERVICES_JSON_IN_ARR) {
633
+ return $arr;
634
+
635
+ } else {
636
+ return $obj;
637
+
638
+ }
639
+ }
640
+
641
+ //print("\nparsing {$chrs}\n");
642
+
643
+ $strlen_chrs = strlen($chrs);
644
+
645
+ for ($c = 0; $c <= $strlen_chrs; ++$c) {
646
+
647
+ $top = end($stk);
648
+ $substr_chrs_c_2 = substr($chrs, $c, 2);
649
+
650
+ if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
651
+ // found a comma that is not inside a string, array, etc.,
652
+ // OR we've reached the end of the character list
653
+ $slice = substr($chrs, $top['where'], ($c - $top['where']));
654
+ array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
655
+ //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
656
+
657
+ if (reset($stk) == SERVICES_JSON_IN_ARR) {
658
+ // we are in an array, so just push an element onto the stack
659
+ array_push($arr, $this->decode($slice));
660
+
661
+ } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
662
+ // we are in an object, so figure
663
+ // out the property name and set an
664
+ // element in an associative array,
665
+ // for now
666
+ $parts = array();
667
+
668
+ if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
669
+ // "name":value pair
670
+ $key = $this->decode($parts[1]);
671
+ $val = $this->decode($parts[2]);
672
+
673
+ if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
674
+ $obj[$key] = $val;
675
+ } else {
676
+ $obj->$key = $val;
677
+ }
678
+ } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
679
+ // name:value pair, where name is unquoted
680
+ $key = $parts[1];
681
+ $val = $this->decode($parts[2]);
682
+
683
+ if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
684
+ $obj[$key] = $val;
685
+ } else {
686
+ $obj->$key = $val;
687
+ }
688
+ }
689
+
690
+ }
691
+
692
+ } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
693
+ // found a quote, and we are not inside a string
694
+ array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
695
+ //print("Found start of string at {$c}\n");
696
+
697
+ } elseif (($chrs{$c} == $top['delim']) &&
698
+ ($top['what'] == SERVICES_JSON_IN_STR) &&
699
+ ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
700
+ // found a quote, we're in a string, and it's not escaped
701
+ // we know that it's not escaped becase there is _not_ an
702
+ // odd number of backslashes at the end of the string so far
703
+ array_pop($stk);
704
+ //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
705
+
706
+ } elseif (($chrs{$c} == '[') &&
707
+ in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
708
+ // found a left-bracket, and we are in an array, object, or slice
709
+ array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
710
+ //print("Found start of array at {$c}\n");
711
+
712
+ } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
713
+ // found a right-bracket, and we're in an array
714
+ array_pop($stk);
715
+ //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
716
+
717
+ } elseif (($chrs{$c} == '{') &&
718
+ in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
719
+ // found a left-brace, and we are in an array, object, or slice
720
+ array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
721
+ //print("Found start of object at {$c}\n");
722
+
723
+ } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
724
+ // found a right-brace, and we're in an object
725
+ array_pop($stk);
726
+ //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
727
+
728
+ } elseif (($substr_chrs_c_2 == '/*') &&
729
+ in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
730
+ // found a comment start, and we are in an array, object, or slice
731
+ array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
732
+ $c++;
733
+ //print("Found start of comment at {$c}\n");
734
+
735
+ } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
736
+ // found a comment end, and we're in one now
737
+ array_pop($stk);
738
+ $c++;
739
+
740
+ for ($i = $top['where']; $i <= $c; ++$i)
741
+ $chrs = substr_replace($chrs, ' ', $i, 1);
742
+
743
+ //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
744
+
745
+ }
746
+
747
+ }
748
+
749
+ if (reset($stk) == SERVICES_JSON_IN_ARR) {
750
+ return $arr;
751
+
752
+ } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
753
+ return $obj;
754
+
755
+ }
756
+
757
+ }
758
+ }
759
+ }
760
+
761
+ /**
762
+ * @todo Ultimately, this should just call PEAR::isError()
763
+ */
764
+ function isError($data, $code = null)
765
+ {
766
+ if (class_exists('pear')) {
767
+ return PEAR::isError($data, $code);
768
+ } elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
769
+ is_subclass_of($data, 'services_json_error'))) {
770
+ return true;
771
+ }
772
+
773
+ return false;
774
+ }
775
+ }
776
+
777
+ if (class_exists('PEAR_Error')) {
778
+
779
+ class Services_JSON_Error extends PEAR_Error
780
+ {
781
+ function Services_JSON_Error($message = 'unknown error', $code = null,
782
+ $mode = null, $options = null, $userinfo = null)
783
+ {
784
+ parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
785
+ }
786
+ }
787
+
788
+ } else {
789
+
790
+ /**
791
+ * @todo Ultimately, this class shall be descended from PEAR_Error
792
+ */
793
+ class Services_JSON_Error
794
+ {
795
+ function Services_JSON_Error($message = 'unknown error', $code = null,
796
+ $mode = null, $options = null, $userinfo = null)
797
+ {
798
+
799
+ }
800
+ }
801
+
802
+ }
803
+
804
+ ?>
core/jsonwrapper/jsonwrapper.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+ # In PHP 5.2 or higher we don't need to bring this in
3
+ if (!function_exists('json_encode')) {
4
+ require_once 'jsonwrapper_inner.php';
5
+ }
6
+ ?>
core/jsonwrapper/jsonwrapper_inner.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ require_once 'JSON.php';
4
+
5
+ function json_encode($arg)
6
+ {
7
+ global $services_json;
8
+ if (!isset($services_json)) {
9
+ $services_json = new Services_JSON();
10
+ }
11
+ return $services_json->encode($arg);
12
+ }
13
+
14
+ function json_decode($arg)
15
+ {
16
+ global $services_json;
17
+ if (!isset($services_json)) {
18
+ $services_json = new Services_JSON();
19
+ }
20
+ return $services_json->decode($arg);
21
+ }
22
+
23
+ ?>
core/parser.php CHANGED
@@ -26,7 +26,9 @@ class parser {
26
  public $url_rewrite_func = null;
27
  public $fetch_translate_func = null;
28
  private $segment_id = 0;
 
29
  private $currentnode;
 
30
  private $html; // the document
31
  public $dir_rtl;
32
  public $lang;
@@ -39,8 +41,8 @@ class parser {
39
 
40
  /**
41
  * Determine if the current position in buffer is a white space.
42
- * @param $char
43
- * @return bool true if current position marks a white space
44
  */
45
  function is_white_space($char) {
46
  if (!$char) return TRUE;
@@ -50,7 +52,7 @@ class parser {
50
  /**
51
  * Determine if the current position in page points to a character in the
52
  * range of a-z (case insensetive).
53
- * @return bool true if a-z
54
  */
55
  function is_a_to_z_character($char) {
56
  return (($char >= 'a' && $char <= 'z') || ($char >= 'A' && $char <= 'Z')) ? true : false;
@@ -58,7 +60,7 @@ class parser {
58
 
59
  /**
60
  * Determine if the current position is a digit.
61
- * @return bool true if a digit
62
  */
63
  function is_digit($char) {
64
  return (($char >= '0' && $char <= '9')) ? true : false;
@@ -66,8 +68,8 @@ class parser {
66
 
67
  /**
68
  * Determine if the current position is an html entity - such as &amp; or &#8220;.
69
- * @param $string string to evalute
70
- * @param $position where to check for entities
71
  * @return int length of entity
72
  */
73
  function is_html_entity($string, $position) {
@@ -84,8 +86,8 @@ class parser {
84
  * such as Jack`s apple.
85
  * `uncatagorized` will break on the later entity
86
  * Added " quotes to this claim, as it is used in some languages in a similar fashion
87
- * @param $entity - html entity to check
88
- * @return - true if not a breaker (apostrophy)
89
  */
90
  function is_entity_breaker($entity) {
91
  return !(stripos('&#8217;&apos;&quot;&#039;&#39;', $entity) !== FALSE);
@@ -174,8 +176,8 @@ class parser {
174
  /**
175
  * Determine if the current position in buffer is a sentence breaker, e.g. '.' or ',' .
176
  * Note html markups are not considered sentence breaker within the scope of this function.
177
- * @param $char charcter checked if breaker
178
- * @param $nextchar needed for checking if . or - breaks
179
  * @return int length of breaker if current position marks a break in sentence
180
  */
181
  function is_sentence_breaker($char, $nextchar, $nextnextchar) {
@@ -187,7 +189,7 @@ class parser {
187
 
188
  /**
189
  * Determines if the current position marks the begining of a number, e.g. 123 050-391212232
190
- * @return length of number.
191
  */
192
  function is_number($page, $position) {
193
  return strspn($page,'0123456789-+,.\\/',$position);
@@ -224,7 +226,7 @@ class parser {
224
  $start = $pos;
225
 
226
  while($pos < strlen($string)) {
227
- // Some HTML entities make us break, almost all but apostrophies
228
  if($len_of_entity = $this->is_html_entity($string,$pos)) {
229
  $entity = substr($string,$pos,$len_of_entity);
230
  if(($this->is_white_space($string[$pos+$len_of_entity]) || $this->is_entity_breaker($entity)) && !$this->is_entity_letter($entity)) {
@@ -263,7 +265,7 @@ class parser {
263
  /**
264
  * This recursive function works on the $html dom and adds phrase nodes to translate as needed
265
  * it currently also rewrites urls, and should consider if this is smart
266
- * @param <type> $node
267
  */
268
  function translate_tagging($node, $level = 0) {
269
  $this->currentnode = $node;
@@ -272,10 +274,10 @@ class parser {
272
 
273
  if (!($this->inselect && $level > $this->inselect))
274
  $this->inselect = false;
275
-
276
  if (isset($this->ignore_tags[$node->tag])) return;
277
  if ($node->tag == 'text') {
278
- // this prevents translation of a link that just surrounds its address
279
  if ($node->parent->tag == 'a' && $node->parent->href == $node->outertext) {
280
  return;
281
  }
@@ -324,8 +326,8 @@ class parser {
324
  * @return string
325
  */
326
  function create_edit_span ($original_text , $translated_text, $source, $for_hidden_element = false) {
327
- // Use base64 encoding to make that when the page is translated (i.e. update_translation) we
328
- // get back exactlly the same string without having the client decode/encode it in anyway.
329
  $span = '<span class ="'.SPAN_PREFIX.'" id="'.SPAN_PREFIX.$this->segment_id.'" token="' . base64_url_encode($original_text)."\" source=\"$source\"";
330
  // those are needed for on the fly image creation / hidden elements translations
331
  if ($this->is_edit_mode || $for_hidden_element) {
@@ -345,11 +347,11 @@ class parser {
345
 
346
  /**
347
  * Main function - actually translates a given HTML
348
- * @param string $string
349
  * @return string Translated content is here
350
  */
351
  function fix_html($string) {
352
- // create our dom
353
  $this->html = str_get_html($string);
354
  // mark translateable elements
355
  $this->translate_tagging($this->html->root);
@@ -378,13 +380,13 @@ class parser {
378
  if (($this->is_edit_mode || ($this->is_auto_translate && $translated_text == null))/* && $ep->inbody*/) {
379
  $span = $this->create_edit_span($ep->phrase, $translated_text, $source);
380
  $spanend = "</span>";
381
- if ($ep->inselect || !$ep->inbody) {
382
  $savedspan .= $this->create_edit_span($ep->phrase, $translated_text, $source,true).$spanend;
383
  $span = '';
384
  $spanend = '';
385
  }
386
  else
387
- if ($translated_text == null) $translated_text = $ep->phrase;
388
  } else {
389
  $span = '';
390
  $spanend = '';
@@ -428,9 +430,9 @@ class parser {
428
  if ($ep->tag == 'phrase') {
429
  list ($translated_text, $source) = call_user_func_array($this->fetch_translate_func,array($ep->phrase, $this->lang));
430
  if (($this->is_edit_mode || ($this->is_auto_translate && $translated_text == null)) && $ep->inbody) {
431
- // prevent duplicate translation (title = text)
432
  if (strpos($e->innertext,base64_url_encode($ep->phrase)) === false) {
433
- //no need to translate span the same hidden phrase more than once
434
  if (!in_array($ep->phrase, $hidden_phrases)) {
435
  $span .= $this->create_edit_span($ep->phrase, $translated_text, $source, true)."</span>";
436
  //
@@ -485,5 +487,25 @@ class parser {
485
  //return $this->html;
486
  return $this->html->outertext;
487
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
488
  }
489
  ?>
26
  public $url_rewrite_func = null;
27
  public $fetch_translate_func = null;
28
  private $segment_id = 0;
29
+ /** @var simple_html_dom_node contains the current node */
30
  private $currentnode;
31
+ /** @var simple_html_dom contains the document dom model */
32
  private $html; // the document
33
  public $dir_rtl;
34
  public $lang;
41
 
42
  /**
43
  * Determine if the current position in buffer is a white space.
44
+ * @param char $char
45
+ * @return boolean true if current position marks a white space
46
  */
47
  function is_white_space($char) {
48
  if (!$char) return TRUE;
52
  /**
53
  * Determine if the current position in page points to a character in the
54
  * range of a-z (case insensetive).
55
+ * @return boolean true if a-z
56
  */
57
  function is_a_to_z_character($char) {
58
  return (($char >= 'a' && $char <= 'z') || ($char >= 'A' && $char <= 'Z')) ? true : false;
60
 
61
  /**
62
  * Determine if the current position is a digit.
63
+ * @return boolean true if a digit
64
  */
65
  function is_digit($char) {
66
  return (($char >= '0' && $char <= '9')) ? true : false;
68
 
69
  /**
70
  * Determine if the current position is an html entity - such as &amp; or &#8220;.
71
+ * @param string $string string to evalute
72
+ * @param int $position where to check for entities
73
  * @return int length of entity
74
  */
75
  function is_html_entity($string, $position) {
86
  * such as Jack`s apple.
87
  * `uncatagorized` will break on the later entity
88
  * Added " quotes to this claim, as it is used in some languages in a similar fashion
89
+ * @param string $entity - html entity to check
90
+ * @return boolean true if not a breaker (apostrophy)
91
  */
92
  function is_entity_breaker($entity) {
93
  return !(stripos('&#8217;&apos;&quot;&#039;&#39;', $entity) !== FALSE);
176
  /**
177
  * Determine if the current position in buffer is a sentence breaker, e.g. '.' or ',' .
178
  * Note html markups are not considered sentence breaker within the scope of this function.
179
+ * @param char $char charcter checked if breaker
180
+ * @param char $nextchar needed for checking if . or - breaks
181
  * @return int length of breaker if current position marks a break in sentence
182
  */
183
  function is_sentence_breaker($char, $nextchar, $nextnextchar) {
189
 
190
  /**
191
  * Determines if the current position marks the begining of a number, e.g. 123 050-391212232
192
+ * @return int length of number.
193
  */
194
  function is_number($page, $position) {
195
  return strspn($page,'0123456789-+,.\\/',$position);
226
  $start = $pos;
227
 
228
  while($pos < strlen($string)) {
229
+ // Some HTML entities make us break, almost all but apostrophies
230
  if($len_of_entity = $this->is_html_entity($string,$pos)) {
231
  $entity = substr($string,$pos,$len_of_entity);
232
  if(($this->is_white_space($string[$pos+$len_of_entity]) || $this->is_entity_breaker($entity)) && !$this->is_entity_letter($entity)) {
265
  /**
266
  * This recursive function works on the $html dom and adds phrase nodes to translate as needed
267
  * it currently also rewrites urls, and should consider if this is smart
268
+ * @param simple_html_dom_node $node
269
  */
270
  function translate_tagging($node, $level = 0) {
271
  $this->currentnode = $node;
274
 
275
  if (!($this->inselect && $level > $this->inselect))
276
  $this->inselect = false;
277
+
278
  if (isset($this->ignore_tags[$node->tag])) return;
279
  if ($node->tag == 'text') {
280
+ // this prevents translation of a link that just surrounds its address
281
  if ($node->parent->tag == 'a' && $node->parent->href == $node->outertext) {
282
  return;
283
  }
326
  * @return string
327
  */
328
  function create_edit_span ($original_text , $translated_text, $source, $for_hidden_element = false) {
329
+ // Use base64 encoding to make that when the page is translated (i.e. update_translation) we
330
+ // get back exactlly the same string without having the client decode/encode it in anyway.
331
  $span = '<span class ="'.SPAN_PREFIX.'" id="'.SPAN_PREFIX.$this->segment_id.'" token="' . base64_url_encode($original_text)."\" source=\"$source\"";
332
  // those are needed for on the fly image creation / hidden elements translations
333
  if ($this->is_edit_mode || $for_hidden_element) {
347
 
348
  /**
349
  * Main function - actually translates a given HTML
350
+ * @param string $string containing HTML
351
  * @return string Translated content is here
352
  */
353
  function fix_html($string) {
354
+ // create our dom
355
  $this->html = str_get_html($string);
356
  // mark translateable elements
357
  $this->translate_tagging($this->html->root);
380
  if (($this->is_edit_mode || ($this->is_auto_translate && $translated_text == null))/* && $ep->inbody*/) {
381
  $span = $this->create_edit_span($ep->phrase, $translated_text, $source);
382
  $spanend = "</span>";
383
+ if ($ep->inselect || !$ep->inbody) {
384
  $savedspan .= $this->create_edit_span($ep->phrase, $translated_text, $source,true).$spanend;
385
  $span = '';
386
  $spanend = '';
387
  }
388
  else
389
+ if ($translated_text == null) $translated_text = $ep->phrase;
390
  } else {
391
  $span = '';
392
  $spanend = '';
430
  if ($ep->tag == 'phrase') {
431
  list ($translated_text, $source) = call_user_func_array($this->fetch_translate_func,array($ep->phrase, $this->lang));
432
  if (($this->is_edit_mode || ($this->is_auto_translate && $translated_text == null)) && $ep->inbody) {
433
+ // prevent duplicate translation (title = text)
434
  if (strpos($e->innertext,base64_url_encode($ep->phrase)) === false) {
435
+ //no need to translate span the same hidden phrase more than once
436
  if (!in_array($ep->phrase, $hidden_phrases)) {
437
  $span .= $this->create_edit_span($ep->phrase, $translated_text, $source, true)."</span>";
438
  //
487
  //return $this->html;
488
  return $this->html->outertext;
489
  }
490
+
491
+ /**
492
+ * This functions returns a list of phrases from a given HTML string
493
+ * @param string $string Html with phrases to extract
494
+ * @return array List of phrases (or an empty one)
495
+ * @since 0.3.5
496
+ */
497
+ function get_phrases_list($string) {
498
+ $result = array();
499
+ // create our dom
500
+ $this->html = str_get_html($string);
501
+ // mark translateable elements
502
+ $this->translate_tagging($this->html->root);
503
+ foreach ($this->html->nodes as $ep) {
504
+ if ($ep->tag == 'phrase') {
505
+ $result[$ep->phrase] = $ep->phrase;
506
+ }
507
+ }
508
+ return $result;
509
+ }
510
  }
511
  ?>
core/shd/simple_html_dom.php CHANGED
@@ -12,6 +12,8 @@ Licensed under The MIT License
12
  Redistributions of files must retain the above copyright notice.
13
  *******************************************************************************/
14
 
 
 
15
  define('HDOM_TYPE_ELEMENT', 1);
16
  define('HDOM_TYPE_COMMENT', 2);
17
  define('HDOM_TYPE_TEXT', 3);
@@ -527,6 +529,8 @@ class simple_html_dom {
527
  // prepare
528
  $this->prepare($str, $lowercase);
529
  // strip out comments
 
 
530
  $this->remove_noise("'<!--(.*?)-->'is");
531
  // strip out cdata
532
  $this->remove_noise("'<!\[CDATA\[(.*?)\]\]>'is", true);
@@ -927,6 +931,7 @@ class simple_html_dom {
927
  // remove noise from html content
928
  protected function remove_noise($pattern, $remove_tag=false) {
929
  $count = preg_match_all($pattern, $this->doc, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
 
930
 
931
  for ($i=$count-1; $i>-1; --$i) {
932
  $key = '___noise___'.sprintf('% 3d', count($this->noise)+100);
@@ -942,6 +947,7 @@ class simple_html_dom {
942
 
943
  // restore noise to html content
944
  function restore_noise($text) {
 
945
  while(($pos=strpos($text, '___noise___'))!==false) {
946
  $key = '___noise___'.$text[$pos+11].$text[$pos+12].$text[$pos+13];
947
  if (isset($this->noise[$key]))
@@ -972,4 +978,5 @@ class simple_html_dom {
972
  function getElementsByTagName($name, $idx=-1) {return $this->find($name, $idx);}
973
  function loadFile() {$args = func_get_args();$this->load(call_user_func_array('file_get_contents', $args), true);}
974
  }
 
975
  ?>
12
  Redistributions of files must retain the above copyright notice.
13
  *******************************************************************************/
14
 
15
+ // avoid duplicate loading on different files
16
+ if (!function_exists("file_get_html")) {
17
  define('HDOM_TYPE_ELEMENT', 1);
18
  define('HDOM_TYPE_COMMENT', 2);
19
  define('HDOM_TYPE_TEXT', 3);
529
  // prepare
530
  $this->prepare($str, $lowercase);
531
  // strip out comments
532
+ //
533
+ /* $this->remove_noise("'<?xml(.*?)?>'is", true);*/
534
  $this->remove_noise("'<!--(.*?)-->'is");
535
  // strip out cdata
536
  $this->remove_noise("'<!\[CDATA\[(.*?)\]\]>'is", true);
931
  // remove noise from html content
932
  protected function remove_noise($pattern, $remove_tag=false) {
933
  $count = preg_match_all($pattern, $this->doc, $matches, PREG_SET_ORDER|PREG_OFFSET_CAPTURE);
934
+ //
935
 
936
  for ($i=$count-1; $i>-1; --$i) {
937
  $key = '___noise___'.sprintf('% 3d', count($this->noise)+100);
947
 
948
  // restore noise to html content
949
  function restore_noise($text) {
950
+ //
951
  while(($pos=strpos($text, '___noise___'))!==false) {
952
  $key = '___noise___'.$text[$pos+11].$text[$pos+12].$text[$pos+13];
953
  if (isset($this->noise[$key]))
978
  function getElementsByTagName($name, $idx=-1) {return $this->find($name, $idx);}
979
  function loadFile() {$args = func_get_args();$this->load(call_user_func_array('file_get_contents', $args), true);}
980
  }
981
+ }
982
  ?>
core/utils.php CHANGED
@@ -29,8 +29,7 @@ require_once("constants.php");
29
  * Remove from url any language (or editing) params that were added for our use.
30
  * Return the scrubed url
31
  */
32
- function cleanup_url($url, $remove_host = false) {
33
- global $languages, $home_url;
34
 
35
  $parsedurl = @parse_url($url);
36
  //cleanup previous lang & edit parameter from url
@@ -62,7 +61,7 @@ function cleanup_url($url, $remove_host = false) {
62
  $secondslashpos = strpos($parsedurl['path'], "/",1);
63
  if (!$secondslashpos) $secondslashpos = strlen($parsedurl['path']);
64
  $prevlang = substr($parsedurl['path'],1,$secondslashpos-1);
65
- if (isset ($languages[$prevlang])) {
66
 
67
  $parsedurl['path'] = substr($parsedurl['path'],$secondslashpos);
68
  }
@@ -83,8 +82,8 @@ function cleanup_url($url, $remove_host = false) {
83
  * @param boolean $is_edit - should url indicate editing
84
  * @param boolean $use_params_only - only use paramaters and avoid permalinks
85
  */
86
- function rewrite_url_lang_param($url, $lang, $is_edit, $use_params_only=FALSE) {
87
- global $home_url, $enable_permalinks_rewrite, $languages;
88
 
89
 
90
  $newurl = str_replace('&#038;', '&', $url);
@@ -119,7 +118,7 @@ function rewrite_url_lang_param($url, $lang, $is_edit, $use_params_only=FALSE) {
119
  $secondslashpos = strpos($parsedurl['path'], "/",1);
120
  if (!$secondslashpos) $secondslashpos = strlen($parsedurl['path']);
121
  $prevlang = substr($parsedurl['path'],1,$secondslashpos-1);
122
- if (isset ($languages[$prevlang])) {
123
 
124
  $parsedurl['path'] = substr($parsedurl['path'],$secondslashpos);
125
  }
29
  * Remove from url any language (or editing) params that were added for our use.
30
  * Return the scrubed url
31
  */
32
+ function cleanup_url($url, $home_url, $remove_host = false) {
 
33
 
34
  $parsedurl = @parse_url($url);
35
  //cleanup previous lang & edit parameter from url
61
  $secondslashpos = strpos($parsedurl['path'], "/",1);
62
  if (!$secondslashpos) $secondslashpos = strlen($parsedurl['path']);
63
  $prevlang = substr($parsedurl['path'],1,$secondslashpos-1);
64
+ if (isset ($GLOBALS['languages'][$prevlang])) {
65
 
66
  $parsedurl['path'] = substr($parsedurl['path'],$secondslashpos);
67
  }
82
  * @param boolean $is_edit - should url indicate editing
83
  * @param boolean $use_params_only - only use paramaters and avoid permalinks
84
  */
85
+ // Should send a transposh interface to here TODO - enable permalinks rewrite
86
+ function rewrite_url_lang_param($url,$home_url, $enable_permalinks_rewrite, $lang, $is_edit, $use_params_only=FALSE) {
87
 
88
 
89
  $newurl = str_replace('&#038;', '&', $url);
118
  $secondslashpos = strpos($parsedurl['path'], "/",1);
119
  if (!$secondslashpos) $secondslashpos = strlen($parsedurl['path']);
120
  $prevlang = substr($parsedurl['path'],1,$secondslashpos-1);
121
+ if (isset ($GLOBALS['languages'][$prevlang])) {
122
 
123
  $parsedurl['path'] = substr($parsedurl['path'],$secondslashpos);
124
  }
js/transposhadmin.js ADDED
@@ -0,0 +1 @@
 
1
+ var timer;var items=0;var translations=[];var tokens=[];var langs=[];function ajax_translate_me(a,c,b){clearTimeout(timer);items++;tokens.push(a);translations.push(c);langs.push(b);timer=setTimeout(function(){var e={sr0:1,translation_posted:"2",items:items};for(var d=0;d<items;d++){if(tokens[d]!=tokens[d-1]){e["tk"+d]=tokens[d]}if(langs[d]!=langs[d-1]){e["ln"+d]=langs[d]}if(translations[d]!=translations[d-1]){e["tr"+d]=translations[d]}}jQuery.ajax({type:"POST",url:transposh_params.post_url,data:e,success:function(){},error:function(f){}});translations=[];tokens=[];langs=[]},200)}jQuery.noConflict();google.load("language","1");var transposh_params=new Array();var ext_langs="he|zh-tw|pt|fa|af|be|is|ga|mk|ms|sw|ws|cy|yi";jQuery("script[src*='transposhadmin.js']").each(function(a){var e=unescape(this.src.substring(this.src.indexOf("?")+1));var d=e.split("&");for(var c=0;c<d.length;c++){var g=d[c].indexOf("=");if(g>0){var b=d[c].substring(0,g);var f=d[c].substring(g+1);transposh_params[b]=f}}});jQuery(document).ready(function(){var c=0;var a="";var b=0;jQuery.getJSON(transposh_params.post_url+"?tr_phrases_post=y&post="+transposh_params.post,function(d){if(d==null){jQuery("#tr_loading").replaceWith("Nothing left to translate");return}jQuery("#tr_loading").replaceWith('Translating<br/>Phrase: <span id="p"></span><div id="progress_bar"/>Target lanaguage: <span id="l"></span><div id="progress_bar2"/><span id="r"></span>');jQuery("#progress_bar").progressbar({value:0});jQuery("#progress_bar2").progressbar({value:0});jQuery.each(d.p,function(e,f){jQuery("#progress_bar2").progressbar("value",b/f.l.length*100);jQuery.each(f.l,function(h,g){google.language.translate(e,"",g,function(i){if(!i.error){if(a!=e){a=e;b=0;c++}jQuery("#progress_bar").progressbar("value",c/d.length*100);b++;jQuery("#progress_bar2").progressbar("value",b/f.l.length*100);jQuery("#p").text(jQuery("<div>"+e+"</div>").text());jQuery("#l").text(g);jQuery("#r").text(jQuery("<div>"+i.translation+"</div>").text());ajax_translate_me(f.t,jQuery("<div>"+i.translation+"</div>").text(),g)}})})})})});
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: oferwald, amirperlman
3
  Donate link: http://transposh.org/donate/
4
  Tags: translation, widget, filter, bilingual, multilingual, transposh, language, crowdsourcing, context, wiki, RTL, Hebrew, Spanish, French, Russian, English, Arabic, Portuguese
5
  Requires at least: 2.7
6
- Tested up to: 2.8.5
7
- Stable tag: 0.3.4
8
 
9
  Transposh filter allows in context quick translation of websites, it allows you to crowd-source the translation to your users
10
 
@@ -91,12 +91,16 @@ functions so the transposh.js file is not being included, try to include it manu
91
 
92
  Just add the following line to your template:
93
 
94
- &lt;?php if(function_exists("transposh_widget")) { transposh_widget(array()); } ?&gt;
95
 
96
  = I have php speedy (http://aciddrop.com/php-speedy/) and the plugin does not work =
97
 
98
  Users of php speedy will have to deactivate it, add “transposh.js” in the ignore list, click on “Test configuration” then reactivate it.
99
 
 
 
 
 
100
  = I want my own css image with less flags =
101
 
102
  This is coming soon
@@ -115,6 +119,13 @@ change the .css from transparent background to your page background color. And l
115
  5. Widget style selection
116
 
117
  == Changelog ==
 
 
 
 
 
 
 
118
  = 2009/11/05 - 0.3.4 =
119
  * Fix for nextgen gallery issue
120
  * Force LTR for wordpress blogs originiating in RTL
@@ -135,7 +146,7 @@ change the .css from transparent background to your page background color. And l
135
  = 2009/07/21 - 0.2.9 =
136
  * Supress warning on parse_url (thanks [Mike](http://www.nostate.com/))
137
  * Fix the urls generated for the widget with subdir blogs (thanks [Peter](http://www.algarve-abc.de/ferienhaus-westalgarve))
138
- * Fix issue when object->tostring didn't work correctly (thanks [Anthony](http://gratiswork.com))
139
  = 2009/07/19 - 0.2.8 =
140
  * Don't touch XML RPC
141
  * Allow usage of CSS sprites when available
3
  Donate link: http://transposh.org/donate/
4
  Tags: translation, widget, filter, bilingual, multilingual, transposh, language, crowdsourcing, context, wiki, RTL, Hebrew, Spanish, French, Russian, English, Arabic, Portuguese
5
  Requires at least: 2.7
6
+ Tested up to: 2.8.6
7
+ Stable tag: 0.3.5
8
 
9
  Transposh filter allows in context quick translation of websites, it allows you to crowd-source the translation to your users
10
 
91
 
92
  Just add the following line to your template:
93
 
94
+ <code><?php if(function_exists("transposh_widget")) { transposh_widget(); }?></code>
95
 
96
  = I have php speedy (http://aciddrop.com/php-speedy/) and the plugin does not work =
97
 
98
  Users of php speedy will have to deactivate it, add “transposh.js” in the ignore list, click on “Test configuration” then reactivate it.
99
 
100
+ = I am getting weird errors =
101
+
102
+ Please make sure you are using PHP5 and up, PHP4 is not supported
103
+
104
  = I want my own css image with less flags =
105
 
106
  This is coming soon
119
  5. Widget style selection
120
 
121
  == Changelog ==
122
+ = 2009/11/26 - 0.3.5 =
123
+ * Enabled auto-translation to all editable languages on the admin side
124
+ * Alternate posting methods (thanks Andre)
125
+ * Fix documenation display regarding widgetless themes (thanks [Hosein-mec](http://linuxshare.org/))
126
+ * Make sure simple_html_dom is not loaded twice (if we can...)
127
+ * Large scale code refactoring
128
+ * Migrated css flags to the widget settings
129
  = 2009/11/05 - 0.3.4 =
130
  * Fix for nextgen gallery issue
131
  * Force LTR for wordpress blogs originiating in RTL
146
  = 2009/07/21 - 0.2.9 =
147
  * Supress warning on parse_url (thanks [Mike](http://www.nostate.com/))
148
  * Fix the urls generated for the widget with subdir blogs (thanks [Peter](http://www.algarve-abc.de/ferienhaus-westalgarve))
149
+ * Fix issue when object->tostring didn't work correctly (thanks [Anthony](http://gratiswork.com/))
150
  = 2009/07/19 - 0.2.8 =
151
  * Don't touch XML RPC
152
  * Allow usage of CSS sprites when available
transposh.php CHANGED
@@ -4,7 +4,7 @@
4
  Plugin URI: http://transposh.org/
5
  Description: Translation filter for WordPress, After enabling please set languages at the <a href="options-general.php?page=transposh">the options page</a> Want to help? visit our development site at <a href="http://trac.transposh.org/">trac.transposh.org</a>.
6
  Author: Team Transposh
7
- Version: 0.3.4
8
  Author URI: http://transposh.org/
9
  License: GPL (http://www.gnu.org/licenses/gpl.txt)
10
  */
@@ -26,481 +26,516 @@
26
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27
  */
28
 
 
 
 
 
 
 
 
29
  require_once("core/parser.php");
30
  require_once("transposh_db.php");
31
  require_once("transposh_widget.php");
32
  require_once("transposh_admin.php");
 
 
33
 
34
- //Error message displayed for the admin in case of failure
35
- $admin_msg;
36
-
37
- /*
38
- * Called when the buffer containing the original page is flushed. Triggers the
39
- * translation process.
40
  */
41
- function process_page(&$buffer) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
 
43
- global $wp_query, $rtl_languages, $enable_auto_translate;
44
-
45
- $start_time = microtime(TRUE);
46
-
47
- // Refrain from touching the administrative interface
48
- if(stripos($_SERVER['REQUEST_URI'],'/wp-login.php') !== FALSE ||
49
- stripos($_SERVER['REQUEST_URI'],'/wp-admin/') !== FALSE ||
50
- stripos($_SERVER['REQUEST_URI'],'/xmlrpc.php') !== FALSE) {
51
 
52
- return $buffer;
53
- }
54
 
55
- // This one fixed a bug transposh created with other pages (xml generator for other plugins - such as the nextgen gallery)
56
- // TODO: need to further investigate
57
- if($GLOBALS['lang'] == "")
58
- return $buffer;
59
-
60
- // Don't translate the default language unless specifically allowed to...
61
- $default_lang = get_default_lang();
62
- if($GLOBALS['lang'] == $default_lang && !get_option(ENABLE_DEFAULT_TRANSLATE)) {
63
-
64
- return $buffer;
 
 
 
65
  }
66
 
67
- //translate the entire page
68
- $parse = new parser();
69
- $parse->fetch_translate_func = 'fetch_translation';
70
- $parse->url_rewrite_func = 'rewrite_url';
71
- $parse->dir_rtl = (in_array ($GLOBALS['lang'], $rtl_languages));
72
- $parse->lang = $GLOBALS['lang'];
73
- $parse->is_edit_mode = $GLOBALS['is_edit_mode'];
74
- $parse->is_auto_translate = $enable_auto_translate;
75
- if(stripos($_SERVER['REQUEST_URI'],'/feed/') !== FALSE) {
76
-
77
- $parse->is_auto_translate = false;
78
- $parse->is_edit_mode = false;
79
- $parse->feed_fix = true;
80
- }
81
- $buffer = $parse->fix_html($buffer);
 
82
 
83
- $end_time = microtime(TRUE);
84
-
 
 
 
 
 
 
 
85
 
86
- return $buffer;
87
- }
88
 
89
- /*
90
- * Init global variables later used throughout this process.
91
- * Note that at the time that this function is called the wp_query is not initialized,
92
- * which means that query parameters are not accessiable.
93
- */
94
- function init_global_vars() {
95
- global $home_url, $tr_plugin_url, $enable_permalinks_rewrite, $wp_rewrite;
96
-
97
- if (!$GLOBALS['home_url'])
98
- $GLOBALS['home_url'] = get_option('home');
99
- // Handle windows ('C:\wordpress')
100
- $local_dir = preg_replace("/\\\\/", "/", dirname(__FILE__));
101
- // Get last directory name
102
- $local_dir = preg_replace("/.*\//", "", $local_dir);
103
- $tr_plugin_url= WP_PLUGIN_URL .'/'. $local_dir;
104
- // TODO - test on more platforms - this failed in 2.7.1 so I am reverting for now...
105
- //$tr_plugin_url= plugins_url('', __FILE__);
106
-
107
- //
108
-
109
- if (is_object($wp_rewrite))
110
- if($wp_rewrite->using_permalinks() && get_option(ENABLE_PERMALINKS_REWRITE)) {
111
- $enable_permalinks_rewrite = TRUE;
112
  }
113
- }
114
 
115
- /*
116
- * Gets the default language setting, i.e. the source language which
117
- * should not be translated.
118
- * Return the default language setting
119
- */
120
- function get_default_lang() {
121
- global $languages;
122
 
123
- $default = get_option(DEFAULT_LANG);
124
- if(!$languages[$default]) {
125
- $default = "en";
126
  }
127
 
128
- return $default;
129
- }
130
-
131
- /*
132
- * Setup a buffer that will contain the contents of the html page.
133
- * Once processing is completed the buffer will go into the translation process.
134
- */
135
- function on_init() {
136
-
137
- init_global_vars();
138
 
139
- if (isset($_POST['translation_posted'])) {
140
- update_translation();
141
- }
142
- elseif (isset($_GET['tr_token_hist'])) {
143
- get_translation_history($_GET['tr_token_hist'], $_GET['lang']);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  }
145
- else {
146
- //set the callback for translating the page when it's done
147
- ob_start("process_page");
 
 
 
148
  }
149
- }
150
 
151
- /*
152
- * Page generation completed - flush buffer.
153
- */
154
- function on_shutdown() {
155
- ob_flush();
156
- }
 
157
 
158
- /*
159
- * Update the url rewrite rules to include language identifier
160
- */
161
- function update_rewrite_rules($rules) {
162
-
163
 
164
- if(!get_option(ENABLE_PERMALINKS_REWRITE)) {
165
-
166
- return $rules;
167
- }
168
 
169
- $newRules = array();
170
- $lang_prefix="([a-z]{2,2}(\-[a-z]{2,2})?)/";
171
 
172
- $lang_parameter= "&" . LANG_PARAM . '=$matches[1]';
 
 
173
 
174
- //catch the root url
175
- $newRules[$lang_prefix."?$"] = "index.php?lang=\$matches[1]";
176
-
177
 
178
- foreach ($rules as $key=>$value) {
179
- $original_key = $key;
180
- $original_value = $value;
181
 
182
- $key = $lang_prefix . $key;
 
 
 
 
183
 
184
- //Shift existing matches[i] two step forward as we pushed new elements
185
- //in the beginning of the expression
186
- for($i = 6; $i > 0; $i--) {
187
- $value = str_replace('['. $i .']', '['. ($i + 2) .']', $value);
188
- }
189
 
190
- $value .= $lang_parameter;
191
 
192
-
193
 
 
 
194
 
195
- $newRules[$key] = $value;
196
- $newRules[$original_key] = $original_value;
197
 
198
 
 
199
  }
200
 
201
-
202
- return $newRules;
203
- }
204
-
205
- /*
206
- * Let WordPress know which parameters are of interest to us.
207
- */
208
- function parameter_queryvars($vars) {
209
-
210
- $vars[] = LANG_PARAM;
211
- $vars[] = EDIT_PARAM;
212
-
213
- return $vars;
214
- }
215
 
216
- /**
217
- * Grabs and set the global language and edit params, they should be here
218
- * @param <type> $wp - here we get the WP class
219
- */
220
- function on_parse_request($wp) {
221
-
222
-
223
- $GLOBALS['lang'] = $wp->query_vars[LANG_PARAM];
224
- if (!$GLOBALS['lang']) $GLOBALS['lang'] = get_default_lang();
225
-
226
- if (isset($wp->query_vars[EDIT_PARAM]) && $wp->query_vars[EDIT_PARAM] && is_editing_permitted()) {
227
- $GLOBALS['is_edit_mode'] = true;
228
- } else {
229
- $GLOBALS['is_edit_mode'] = false;
 
 
 
 
 
 
 
230
  }
231
- // We are removing our query vars since they are no longer needed and also make issues when a user select a static page as his home
232
- unset ($wp->query_vars[LANG_PARAM]);
233
- unset ($wp->query_vars[EDIT_PARAM]);
234
-
235
- }
236
 
237
- /*
238
- * Determine if the current user is allowed to translate.
239
- * Return TRUE if allowed to translate otherwise FALSE
240
- */
241
- function is_translator() {
242
- if(is_user_logged_in()) {
243
- if(current_user_can(TRANSLATOR)) {
 
244
  return TRUE;
245
  }
 
 
 
 
246
  }
247
 
248
- if(get_option(ANONYMOUS_TRANSLATION)) {
249
- //if anonymous translation is allowed - let anyone enjoy it
250
- return TRUE;
251
- }
 
252
 
253
- return FALSE;
254
- }
 
 
255
 
256
- /*
257
- * Plugin activated.
258
- */
259
- function plugin_activate() {
260
- global $wp_rewrite;
261
-
262
 
263
- setup_db();
 
 
 
 
264
 
265
- add_filter('rewrite_rules_array', 'update_rewrite_rules');
266
- $wp_rewrite->flush_rules();
 
267
 
268
-
269
-
270
-
271
- //activate_plugin($plugin);
272
- }
273
 
274
- /*
275
- * Plugin deactivated.
276
- */
277
- function plugin_deactivate() {
278
- global $wp_rewrite;
279
-
280
 
281
- remove_filter('rewrite_rules_array', 'update_rewrite_rules');
282
- $wp_rewrite->flush_rules();
283
 
284
-
285
- }
286
 
287
- /*
288
- * Callback from admin_notices - display error message to the admin.
289
- */
290
- function plugin_install_error() {
291
- global $admin_msg;
292
-
293
 
294
- echo '<div class="updated"><p>';
295
- echo 'Error has occured in the installation process of the translation plugin: <br>';
296
 
297
- echo $admin_msg;
 
 
 
 
 
 
 
298
 
299
- if (function_exists('deactivate_plugins') ) {
300
- deactivate_plugins(get_plugin_name(), "translate.php");
301
- echo '<br> This plugin has been automatically deactivated.';
302
- }
303
 
304
- echo '</p></div>';
305
- }
 
306
 
307
- /*
308
- * Callback when all plugins have been loaded. Serves as the location
309
- * to check that the plugin loaded successfully else trigger notification
310
- * to the admin and deactivate plugin.
311
- */
312
- function plugin_loaded() {
313
- global $admin_msg;
314
-
315
 
316
- $db_version = get_option(TRANSPOSH_DB_VERSION);
 
317
 
318
- if ($db_version != DB_VERSION) {
319
- setup_db();
320
- //$admin_msg = "Translation database version ($db_version) is not comptabile with this plugin (". DB_VERSION . ") <br>";
321
 
322
-
323
- //Some error occured - notify admin and deactivate plugin
324
- //add_action('admin_notices', 'plugin_install_error');
 
325
  }
326
 
327
- if ($db_version != DB_VERSION) {
328
- $admin_msg = "Failed to locate the translation table <em> " . TRANSLATIONS_TABLE . "</em> in local database. <br>";
329
-
 
 
 
 
 
 
 
 
 
 
 
330
 
331
- //Some error occured - notify admin and deactivate plugin
332
- add_action('admin_notices', 'plugin_install_error');
333
  }
334
- }
335
 
336
- /*
337
- * Gets the plugin name to be used in activation/decativation hooks.
338
- * Keep only the file name and its containing directory. Don't use the full
339
- * path as it will break when using symbollic links.
340
- */
341
- function get_plugin_name() {
342
- $file = __FILE__;
343
- $file = str_replace('\\','/',$file); // sanitize for Win32 installs
344
- $file = preg_replace('|/+|','/', $file); // remove any duplicate slash
345
-
346
- //keep only the file name and its parent directory
347
- $file = preg_replace('/.*\/([^\/]+\/[^\/]+)$/', '$1', $file);
348
-
349
- return $file;
350
- }
351
-
352
- /*
353
- * Add custom css, i.e. transposh.css
354
- */
355
- function add_transposh_css() {
356
- global $tr_plugin_url;
357
-
358
- if(!is_editing_permitted() && !is_auto_translate_permitted()) {
359
- //translation not allowed - no need for the transposh.css
360
- return;
361
  }
362
- //include the transposh.css
363
- wp_enqueue_style("transposh","$tr_plugin_url/css/transposh.css",array(),'0.3.4');
364
- wp_enqueue_style("jquery","http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/themes/ui-lightness/jquery-ui.css",array(),'1.0');
365
-
366
- }
367
 
368
- /*
369
- * Insert references to the javascript files used in the transalted
370
- * version of the page.
371
- */
372
- function add_transposh_js() {
373
- global $tr_plugin_url, $wp_query, $home_url, $enable_auto_translate, $wp_version;
 
 
374
 
375
- $enable_auto_translate = is_auto_translate_permitted();
376
- if(!is_editing_permitted() && !$enable_auto_translate) {
377
- //translation not allowed - no need for any js.
378
- return;
379
- }
380
 
381
- if (!$GLOBALS['is_edit_mode'] && !$enable_auto_translate) {
382
- //Not in any translation mode - no need for any js.
383
- return;
384
- }
385
 
386
- $options = get_option(WIDGET_TRANSPOSH);
 
 
387
 
388
- $edit_mode = "";
389
- if($GLOBALS['is_edit_mode']) {
390
- $edit_mode = "&".EDIT_PARAM."=y";
 
 
 
 
 
 
 
 
 
 
391
  }
392
 
393
- if($GLOBALS['is_edit_mode'] || $options['progressbar']) {
394
- wp_enqueue_script("jqueryui","http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js",array("jquery"),'1.7.2',get_option(ENABLE_FOOTER_SCRIPTS));
395
- }
396
 
397
- if($GLOBALS['is_edit_mode'] || $enable_auto_translate) {
398
- $post_url = $home_url;// . '/index.php'; pay attention here - might be damaging
399
- wp_deregister_script('jquery');
400
- wp_enqueue_script("jquery","http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js",array(),'1.3.2');
401
- // jQuery pushing below might cause issues
402
- //wp_enqueue_script("jquery","http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js",array(),'1.3.2', get_option(ENABLE_FOOTER_SCRIPTS));
403
- wp_enqueue_script("google","http://www.google.com/jsapi",array(),'1',get_option(ENABLE_FOOTER_SCRIPTS));
404
- // Make sure msn translate is not needlessly loaded when we are only auto translating
405
- if (get_option(ENABLE_MSN_TRANSLATE) && $GLOBALS['is_edit_mode']) {
406
- wp_enqueue_script("mstranslate","http://api.microsofttranslator.com/V1/Ajax.svc/Embed?appId=".get_option(MSN_TRANSLATE_KEY),array(),'1',get_option(ENABLE_FOOTER_SCRIPTS));
407
- }
408
- wp_enqueue_script("transposh","$tr_plugin_url/js/transposh.js?post_url=$post_url{$edit_mode}&lang={$GLOBALS['lang']}&prefix=".SPAN_PREFIX,array("jquery"),'0.3.4',get_option(ENABLE_FOOTER_SCRIPTS));
409
- }
410
- }
411
 
 
 
412
 
413
- /**
414
- * Determine if the currently selected language (taken from the query parameters) is in the admin's list
415
- * of editable languages and the current user is allowed to translate.
416
- *
417
- * @return TRUE if translation allowed otherwise FALSE
418
- */
419
- function is_editing_permitted() {
420
- global $wp_query;
421
- // editing is permitted for translators only
422
- if(!is_translator()) return FALSE;
423
- // and only on the non-default lang (unless strictly specified)
424
- if (!get_option(ENABLE_DEFAULT_TRANSLATE) && $GLOBALS['lang'] == get_default_lang()) return false;
425
-
426
- return is_editable_lang($GLOBALS['lang']);
427
- }
428
 
429
- /**
430
- * Determine if the given language in on the list of editable languages
431
- * @return TRUE if editable othewise FALSE
432
- */
433
- function is_editable_lang($language) {
434
- $editable_langs = get_option(EDITABLE_LANGS);
435
- return (strpos($editable_langs, $language) === FALSE) ? FALSE : TRUE;
436
- }
437
 
 
 
438
 
439
- /**
440
- * Determine if the currently selected language (taken from the query parameters) is in the admin's list
441
- * of editable languages and that automatic translation has been enabled.
442
- * Note that any user can auto translate. i.e. ignore permissions.
443
- *
444
- * @return TRUE if automatic translation allowed otherwise FALSE
445
- */
446
- function is_auto_translate_permitted() {
447
- global $wp_query;
448
-
449
 
450
- if(!get_option(ENABLE_AUTO_TRANSLATE, 1)) return FALSE;
 
 
 
451
 
452
- return is_editable_lang($GLOBALS['lang']);
453
- }
454
- /**
455
- * Callback from parser allowing to overide the global setting of url rewriting using permalinks.
456
- * Some urls should be modified only by adding parameters and should be identified by this
457
- * function.
458
- * @param $href
459
- * @return TRUE if parameters should be used instead of rewriting as a permalink
460
- */
461
- function rewrite_url($href) {
462
- global $enable_permalinks_rewrite, $home_url;
463
- $use_params = FALSE;
464
-
465
 
466
- // Ignore urls not from this site
467
- if(stripos($href, $home_url) === FALSE) {
468
  return $href;
469
  }
470
 
471
- // don't fix links pointing to real files as it will cause that the
472
- // web server will not be able to locate them
473
- if(stripos($href, '/wp-admin') !== FALSE ||
474
- stripos($href, WP_CONTENT_URL) !== FALSE ||
475
- stripos($href, '/wp-login') !== FALSE ||
476
- stripos($href, '/.php') !== FALSE) {
477
- return $href;
 
478
  }
479
- $use_params = !$enable_permalinks_rewrite;
480
 
481
- $href = rewrite_url_lang_param($href, $GLOBALS['lang'], $GLOBALS['is_edit_mode'], $use_params);
482
-
483
- return $href;
484
  }
 
485
 
486
- function plugin_action_links( $links ) {
487
-
488
- return array_merge( array('<a href="' . admin_url('options-general.php?page='.TRANSPOSH_ADMIN_PAGE_NAME) . '">Settings</a>'), $links );
489
- }
490
-
491
- //Register callbacks
492
- add_filter('query_vars', 'parameter_queryvars' );
493
- add_action('parse_request', 'on_parse_request');
494
-
495
- add_filter('plugin_action_links_' .preg_replace( '|^' . preg_quote(WP_PLUGIN_DIR, '|') . '/|', '', __FILE__ ), 'plugin_action_links');
496
- add_action('wp_print_styles', 'add_transposh_css');
497
- add_action('wp_print_scripts', 'add_transposh_js');
498
- add_action('init', 'on_init');
499
- add_action('shutdown', 'on_shutdown');
500
-
501
- add_action( 'plugins_loaded', 'plugin_loaded');
502
- register_activation_hook(__FILE__, 'plugin_activate');
503
- register_deactivation_hook(__FILE__,'plugin_deactivate');
504
-
505
- add_filter('rewrite_rules_array', 'update_rewrite_rules');
506
  ?>
4
  Plugin URI: http://transposh.org/
5
  Description: Translation filter for WordPress, After enabling please set languages at the <a href="options-general.php?page=transposh">the options page</a> Want to help? visit our development site at <a href="http://trac.transposh.org/">trac.transposh.org</a>.
6
  Author: Team Transposh
7
+ Version: 0.3.5
8
  Author URI: http://transposh.org/
9
  License: GPL (http://www.gnu.org/licenses/gpl.txt)
10
  */
26
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27
  */
28
 
29
+ //avoid direct calls to this file where wp core files not present
30
+ if (!function_exists ('add_action')) {
31
+ header('Status: 403 Forbidden');
32
+ header('HTTP/1.1 403 Forbidden');
33
+ exit();
34
+ }
35
+
36
  require_once("core/parser.php");
37
  require_once("transposh_db.php");
38
  require_once("transposh_widget.php");
39
  require_once("transposh_admin.php");
40
+ require_once("transposh_options.php");
41
+ require_once("transposh_postpublish.php");
42
 
43
+ /**
44
+ * This class represents the complete plugin
 
 
 
 
45
  */
46
+ class transposh_plugin {
47
+ // List of contained objects
48
+ /** @var transposh_plugin_options An options object*/
49
+ public $options;
50
+ /** @var transposh_plugin_admin Admin page*/
51
+ private $admin;
52
+ /** @var transposh_plugin_widget Widget control*/
53
+ public $widget;
54
+ /** @var transposh_database The database class*/
55
+ public $database;
56
+ /** @var transposh_postpublish Happens after editing*/
57
+ public $postpublish;
58
+
59
+ // list of properties
60
+ /** @var string The site url*/
61
+ public $home_url;
62
+ /** @var string Where the javascript should post to*/
63
+ public $post_url;
64
+ /** @var string The url to the plugin directory*/
65
+ public $transposh_plugin_url;
66
+ /** @var boolean Enable rewriting of URLs*/
67
+ public $enable_permalinks_rewrite;
68
+ /** @var string The language to translate the page to*/
69
+ public $target_language;
70
+ /** @var boolean Are we currently editing the page?*/
71
+ public $edit_mode;
72
+ /** @var string Error message displayed for the admin in case of failure*/
73
+ private $admin_msg;
74
+
75
+ /**
76
+ * class constructor
77
+ */
78
+ function transposh_plugin() {
79
+ // create and initialize sub-objects
80
+ $this->options = new transposh_plugin_options();
81
+ $this->database = new transposh_database($this);
82
+ $this->admin = new transposh_plugin_admin($this);
83
+ $this->widget = new transposh_plugin_widget($this);
84
+ $this->postpublish = new transposh_postpublish($this);
85
+
86
+ // "global" vars
87
+ $this->home_url = get_option('home');
88
+ $this->post_url = $this->home_url;
89
+ if ($this->options->get_alternate_post() == 1) $this->post_url .= "/";
90
+ if ($this->options->get_alternate_post() == 2) $this->post_url .= "/index.php";
91
+
92
+ // Handle windows ('C:\wordpress')
93
+ $local_dir = preg_replace("/\\\\/", "/", dirname(__FILE__));
94
+ // Get last directory name
95
+ $local_dir = preg_replace("/.*\//", "", $local_dir);
96
+ $this->transposh_plugin_url = WP_PLUGIN_URL .'/'. $local_dir;
97
+ // TODO - test on more platforms - this failed in 2.7.1 so I am reverting for now...
98
+ //$tr_plugin_url= plugins_url('', __FILE__);
99
 
 
 
 
 
 
 
 
 
100
 
 
 
101
 
102
+ //Register some functions into wordpress
103
+ // includes transposh dir and php
104
+ add_filter('plugin_action_links_' .preg_replace( '|^' . preg_quote(WP_PLUGIN_DIR, '|') . '/|', '', __FILE__ ), array(&$this,'plugin_action_links'));
105
+ add_filter('query_vars', array(&$this,'parameter_queryvars' ));
106
+ add_filter('rewrite_rules_array', array(&$this,'update_rewrite_rules'));
107
+ add_action('init', array(&$this,'on_init'),0); // really high priority
108
+ add_action('parse_request', array(&$this,'on_parse_request'));
109
+ add_action('plugins_loaded', array(&$this,'plugin_loaded'));
110
+ add_action('shutdown', array(&$this,'on_shutdown'));
111
+ add_action('wp_print_styles', array(&$this,'add_transposh_css'));
112
+ add_action('wp_print_scripts', array(&$this,'add_transposh_js'));
113
+ register_activation_hook(__FILE__, array(&$this,'plugin_activate'));
114
+ register_deactivation_hook(__FILE__,array(&$this,'plugin_deactivate'));
115
  }
116
 
117
+ /**
118
+ * Called when the buffer containing the original page is flushed. Triggers the translation process.
119
+ * @param string $buffer Original page
120
+ * @return string Modified page buffer
121
+ */
122
+ function process_page(&$buffer) {
123
+
124
+ $start_time = microtime(TRUE);
125
+
126
+ // Refrain from touching the administrative interface and important pages
127
+ if(stripos($_SERVER['REQUEST_URI'],'/wp-login.php') !== FALSE ||
128
+ stripos($_SERVER['REQUEST_URI'],'/wp-admin/') !== FALSE ||
129
+ stripos($_SERVER['REQUEST_URI'],'/xmlrpc.php') !== FALSE) {
130
+
131
+ return $buffer;
132
+ }
133
 
134
+ // This one fixed a bug transposh created with other pages (xml generator for other plugins - such as the nextgen gallery)
135
+ // TODO: need to further investigate (will it be needed?)
136
+ if($this->target_language == "")
137
+ return $buffer;
138
+ // Don't translate the default language unless specifically allowed to...
139
+ if($this->options->is_default_language($this->target_language) && !$this->options->get_enable_default_translate()) {
140
+
141
+ return $buffer;
142
+ }
143
 
144
+
 
145
 
146
+ //translate the entire page
147
+ $parse = new parser();
148
+ $parse->fetch_translate_func = array(&$this->database,'fetch_translation');
149
+ $parse->url_rewrite_func = array(&$this, 'rewrite_url');
150
+ $parse->dir_rtl = (in_array ($this->target_language, $GLOBALS['rtl_languages']));
151
+ $parse->lang = $this->target_language;
152
+ $parse->is_edit_mode = $this->edit_mode;
153
+ $parse->is_auto_translate = $this->is_auto_translate_permitted();
154
+ // TODO - check this!
155
+ if(stripos($_SERVER['REQUEST_URI'],'/feed/') !== FALSE) {
156
+
157
+ $parse->is_auto_translate = false;
158
+ $parse->is_edit_mode = false;
159
+ $parse->feed_fix = true;
 
 
 
 
 
 
 
 
 
160
  }
161
+ $buffer = $parse->fix_html($buffer);
162
 
163
+ $end_time = microtime(TRUE);
164
+
 
 
 
 
 
165
 
166
+ return $buffer;
 
 
167
  }
168
 
169
+ /**
170
+ * Setup a buffer that will contain the contents of the html page.
171
+ * Once processing is completed the buffer will go into the translation process.
172
+ */
173
+ function on_init() {
174
+
 
 
 
 
175
 
176
+ // the wp_rewrite is not available earlier so we can only set the enable_permalinks here
177
+ if (is_object($GLOBALS['wp_rewrite']))
178
+ if($GLOBALS['wp_rewrite']->using_permalinks() && $this->options->get_enable_permalinks()) {
179
+
180
+ $this->enable_permalinks_rewrite = TRUE;
181
+ }
182
+
183
+ if (isset($_POST['translation_posted'])) {
184
+ if ($_POST['translation_posted'] == 2) {
185
+ $this->database->update_translation_new();
186
+ }
187
+ else {
188
+ $this->database->update_translation();
189
+ }
190
+ exit;
191
+ }
192
+ elseif (isset($_GET['tr_token_hist'])) {
193
+ $this->database->get_translation_history($_GET['tr_token_hist'], $_GET['lang']);
194
+ exit;
195
+ }
196
+ elseif (isset($_GET['tr_phrases_post'])) {
197
+ $this->postpublish->get_post_phrases($_GET['post']);
198
+ exit;
199
+ }
200
+ else {
201
+ //set the callback for translating the page when it's done
202
+ ob_start(array(&$this,"process_page"));
203
+ }
204
  }
205
+
206
+ /**
207
+ * Page generation completed - flush buffer.
208
+ */
209
+ function on_shutdown() {
210
+ ob_flush();
211
  }
 
212
 
213
+ /**
214
+ * Update the url rewrite rules to include language identifier
215
+ * @param array $rules Old rewrite rules
216
+ * @return array New rewrite rules
217
+ */
218
+ function update_rewrite_rules($rules) {
219
+
220
 
221
+ if(!$this->options->get_enable_permalinks()) {
222
+
223
+ return $rules;
224
+ }
 
225
 
226
+ $newRules = array();
227
+ $lang_prefix="([a-z]{2,2}(\-[a-z]{2,2})?)/";
 
 
228
 
229
+ $lang_parameter= "&" . LANG_PARAM . '=$matches[1]';
 
230
 
231
+ //catch the root url
232
+ $newRules[$lang_prefix."?$"] = "index.php?lang=\$matches[1]";
233
+
234
 
235
+ foreach ($rules as $key=>$value) {
236
+ $original_key = $key;
237
+ $original_value = $value;
238
 
239
+ $key = $lang_prefix . $key;
 
 
240
 
241
+ //Shift existing matches[i] two step forward as we pushed new elements
242
+ //in the beginning of the expression
243
+ for($i = 6; $i > 0; $i--) {
244
+ $value = str_replace('['. $i .']', '['. ($i + 2) .']', $value);
245
+ }
246
 
247
+ $value .= $lang_parameter;
 
 
 
 
248
 
249
+
250
 
 
251
 
252
+ $newRules[$key] = $value;
253
+ $newRules[$original_key] = $original_value;
254
 
255
+
256
+ }
257
 
258
 
259
+ return $newRules;
260
  }
261
 
262
+ /**
263
+ * Let WordPress know which parameters are of interest to us.
264
+ * @param array $vars Original queried variables
265
+ * @return array Modified array
266
+ */
267
+ function parameter_queryvars($vars) {
268
+
269
+ $vars[] = LANG_PARAM;
270
+ $vars[] = EDIT_PARAM;
271
+
272
+ return $vars;
273
+ }
 
 
274
 
275
+ /**
276
+ * Grabs and set the global language and edit params, they should be here
277
+ * @param WP $wp - here we get the WP class
278
+ */
279
+ function on_parse_request($wp) {
280
+
281
+
282
+ $this->target_language = $wp->query_vars[LANG_PARAM];
283
+ if (!$this->target_language)
284
+ $this->target_language = $this->options->get_default_language();
285
+
286
+ if (isset($wp->query_vars[EDIT_PARAM]) && $wp->query_vars[EDIT_PARAM] && $this->is_editing_permitted()) {
287
+ $this->edit_mode = true;
288
+ }
289
+ else {
290
+ $this->edit_mode = false;
291
+ }
292
+ // We are removing our query vars since they are no longer needed and also make issues when a user select a static page as his home
293
+ unset ($wp->query_vars[LANG_PARAM]);
294
+ unset ($wp->query_vars[EDIT_PARAM]);
295
+
296
  }
 
 
 
 
 
297
 
298
+ // TODO ? move to options?
299
+ /**
300
+ * Determine if the current user is allowed to translate.
301
+ * @return boolean Is allowed to translate?
302
+ */
303
+ function is_translator() {
304
+ //if anonymous translation is allowed - let anyone enjoy it
305
+ if($this->options->get_anonymous_translation()) {
306
  return TRUE;
307
  }
308
+ if(is_user_logged_in() && current_user_can(TRANSLATOR)) {
309
+ return TRUE;
310
+ }
311
+ return FALSE;
312
  }
313
 
314
+ /**
315
+ * Plugin activation
316
+ */
317
+ function plugin_activate() {
318
+
319
 
320
+ $this->database->setup_db();
321
+ // is it needed? the filter is already there? // TODO
322
+ add_filter('rewrite_rules_array', array(&$this,'update_rewrite_rules'));
323
+ $GLOBALS['wp_rewrite']->flush_rules();
324
 
325
+
326
+
327
+
328
+ //activate_plugin($plugin);
329
+ }
 
330
 
331
+ /**
332
+ * Plugin deactivation
333
+ */
334
+ function plugin_deactivate() {
335
+
336
 
337
+ // is it needed? the filter is already there? // TODO
338
+ add_filter('rewrite_rules_array', array(&$this,'update_rewrite_rules'));
339
+ $GLOBALS['wp_rewrite']->flush_rules();
340
 
341
+
342
+ }
 
 
 
343
 
344
+ /**
345
+ * Callback from admin_notices - display error message to the admin.
346
+ */
347
+ function plugin_install_error() {
348
+
 
349
 
350
+ echo '<div class="updated"><p>';
351
+ echo 'Error has occured in the installation process of the translation plugin: <br>';
352
 
353
+ echo $this->admin_msg;
 
354
 
355
+ if (function_exists('deactivate_plugins') ) {
356
+ // FIXME :wtf?
357
+ deactivate_plugins(get_plugin_name(), "translate.php");
358
+ echo '<br> This plugin has been automatically deactivated.';
359
+ }
 
360
 
361
+ echo '</p></div>';
362
+ }
363
 
364
+ /**
365
+ * Callback when all plugins have been loaded. Serves as the location
366
+ * to check that the plugin loaded successfully else trigger notification
367
+ * to the admin and deactivate plugin.
368
+ * TODO - needs revisiting!
369
+ */
370
+ function plugin_loaded() {
371
+
372
 
373
+ //TODO: fix this...
374
+ $db_version = get_option(TRANSPOSH_DB_VERSION);
 
 
375
 
376
+ if ($db_version != DB_VERSION) {
377
+ $this->database->setup_db();
378
+ //$this->admin_msg = "Translation database version ($db_version) is not comptabile with this plugin (". DB_VERSION . ") <br>";
379
 
380
+
381
+ //Some error occured - notify admin and deactivate plugin
382
+ //add_action('admin_notices', 'plugin_install_error');
383
+ }
 
 
 
 
384
 
385
+ //TODO: fix this too...
386
+ $db_version = get_option(TRANSPOSH_DB_VERSION);
387
 
388
+ if ($db_version != DB_VERSION) {
389
+ $this->admin_msg = "Failed to locate the translation table <em> " . TRANSLATIONS_TABLE . "</em> in local database. <br>";
 
390
 
391
+
392
+ //Some error occured - notify admin and deactivate plugin
393
+ add_action('admin_notices', array(&$this,'plugin_install_error'));
394
+ }
395
  }
396
 
397
+ /**
398
+ * Gets the plugin name to be used in activation/decativation hooks.
399
+ * Keep only the file name and its containing directory. Don't use the full
400
+ * path as it will break when using symbollic links.
401
+ * TODO - check!!!
402
+ * @return string
403
+ */
404
+ function get_plugin_name() {
405
+ $file = __FILE__;
406
+ $file = str_replace('\\','/',$file); // sanitize for Win32 installs
407
+ $file = preg_replace('|/+|','/', $file); // remove any duplicate slash
408
+
409
+ //keep only the file name and its parent directory
410
+ $file = preg_replace('/.*\/([^\/]+\/[^\/]+)$/', '$1', $file);
411
 
412
+ return $file;
 
413
  }
 
414
 
415
+ /**
416
+ * Add custom css, i.e. transposh.css
417
+ */
418
+ function add_transposh_css() {
419
+ if(!$this->is_editing_permitted() && !$this->is_auto_translate_permitted()) {
420
+ //translation not allowed - no need for the transposh.css
421
+ return;
422
+ }
423
+ //include the transposh.css
424
+ wp_enqueue_style("transposh","{$this->transposh_plugin_url}/css/transposh.css",array(),TRANSPOSH_PLUGIN_VER);
425
+ wp_enqueue_style("jquery","http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/ui-lightness/jquery-ui.css",array(),'1.0');
426
+
 
 
 
 
 
 
 
 
 
 
 
 
 
427
  }
 
 
 
 
 
428
 
429
+ /**
430
+ * Insert references to the javascript files used in the translated version of the page.
431
+ */
432
+ function add_transposh_js() {
433
+ //translation not allowed - no need for any js.
434
+ if(!$this->is_editing_permitted() && !$this->is_auto_translate_permitted()) {
435
+ return;
436
+ }
437
 
438
+ //not in any translation mode - no need for any js.
439
+ if (!$this->edit_mode && !$this->is_auto_translate_permitted()) {
440
+ return;
441
+ }
 
442
 
443
+ $edit_param = "";
444
+ if($this->edit_mode) {
445
+ $edit_param = "&".EDIT_PARAM."=y";
446
+ }
447
 
448
+ if($this->edit_mode || $this->options->get_widget_progressbar()) {
449
+ wp_enqueue_script("jqueryui","http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js",array("jquery"),'1.7.2',$this->options->get_enable_footer_scripts());
450
+ }
451
 
452
+ if($this->edit_mode || $this->is_auto_translate_permitted()) {
453
+ //TODO - fix (onetime var)
454
+ wp_deregister_script('jquery');
455
+ wp_enqueue_script("jquery","http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js",array(),'1.3.2');
456
+ // jQuery pushing below might cause issues
457
+ //wp_enqueue_script("jquery","http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js",array(),'1.3.2', $this->options->get_enable_footer_scripts());
458
+ wp_enqueue_script("google","http://www.google.com/jsapi",array(),'1',$this->options->get_enable_footer_scripts());
459
+ // Make sure msn translate is not needlessly loaded when we are only auto translating
460
+ if ($this->options->get_enable_msn_translate() && $this->edit_mode) {
461
+ wp_enqueue_script("mstranslate","http://api.microsofttranslator.com/V1/Ajax.svc/Embed?appId=".$this->options->get_msn_key(),array(),'1',$this->options->get_enable_footer_scripts());
462
+ }
463
+ wp_enqueue_script("transposh","{$this->transposh_plugin_url}/js/transposh.js?post_url={$this->post_url}{$edit_param}&lang={$this->target_language}&prefix=".SPAN_PREFIX,array("jquery"),TRANSPOSH_PLUGIN_VER,$this->options->get_enable_footer_scripts());
464
+ }
465
  }
466
 
 
 
 
467
 
468
+ /**
469
+ * Determine if the currently selected language (taken from the query parameters) is in the admin's list
470
+ * of editable languages and the current user is allowed to translate.
471
+ * @return boolean Is translation allowed?
472
+ */
473
+ // TODO????
474
+ function is_editing_permitted() {
475
+ // editing is permitted for translators only
476
+ if(!$this->is_translator()) return FALSE;
477
+ // and only on the non-default lang (unless strictly specified)
478
+ if (!$this->options->get_enable_default_translate() && $this->options->is_default_language($this->target_language)) return false;
 
 
 
479
 
480
+ return $this->options->is_editable_language($this->target_language);
481
+ }
482
 
483
+ /**
484
+ * Determine if the currently selected language (taken from the query parameters) is in the admin's list
485
+ * of editable languages and that automatic translation has been enabled.
486
+ * Note that any user can auto translate. i.e. ignore permissions.
487
+ * @return boolean Is automatic translation allowed?
488
+ */
489
+ function is_auto_translate_permitted() {
490
+
 
 
 
 
 
 
 
491
 
492
+ if(!$this->options->get_enable_auto_translate()) return FALSE;
 
 
 
 
 
 
 
493
 
494
+ return $this->options->is_editable_language($this->target_language);
495
+ }
496
 
497
+ /**
498
+ * Callback from parser allowing to overide the global setting of url rewriting using permalinks.
499
+ * Some urls should be modified only by adding parameters and should be identified by this
500
+ * function.
501
+ * @param $href Original href
502
+ * @return boolean Modified href
503
+ */
504
+ function rewrite_url($href) {
505
+ $use_params = FALSE;
506
+
507
 
508
+ // Ignore urls not from this site
509
+ if(stripos($href, $this->home_url) === FALSE) {
510
+ return $href;
511
+ }
512
 
513
+ // don't fix links pointing to real files as it will cause that the
514
+ // web server will not be able to locate them
515
+ if(stripos($href, '/wp-admin') !== FALSE ||
516
+ stripos($href, WP_CONTENT_URL) !== FALSE ||
517
+ stripos($href, '/wp-login') !== FALSE ||
518
+ stripos($href, '/.php') !== FALSE) {
519
+ return $href;
520
+ }
521
+ $use_params = !$this->enable_permalinks_rewrite;
 
 
 
 
522
 
523
+ $href = rewrite_url_lang_param($href,$this->home_url,$this->enable_permalinks_rewrite, $this->target_language, $this->edit_mode, $use_params);
524
+
525
  return $href;
526
  }
527
 
528
+ /**
529
+ * This function adds the word setting in the plugin list page
530
+ * @param array $links Links that appear next to the plugin
531
+ * @return array Now with settings
532
+ */
533
+ function plugin_action_links( $links ) {
534
+
535
+ return array_merge( array('<a href="' . admin_url('options-general.php?page='.TRANSPOSH_ADMIN_PAGE_NAME) . '">Settings</a>'), $links );
536
  }
 
537
 
 
 
 
538
  }
539
+ $my_transposh_plugin = new transposh_plugin();
540
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
541
  ?>
transposh_admin.php CHANGED
@@ -26,271 +26,95 @@
26
  define ("TR_NONCE","transposh_nonce");
27
 
28
 
29
- /*
30
- * Insert supported languages section in admin page
31
- */
32
- function insert_supported_langs() {
33
- global $languages, $tr_plugin_url;
34
-
35
- echo
36
- '<script type="text/javascript">'.
37
- 'function chbx_change(lang)'.
38
- '{'.
39
- 'jQuery("#"+lang+"_edit").attr("checked",jQuery("#"+lang+"_view").attr("checked"))'.
40
- '}'.
41
- 'jQuery(document).ready(function() {'.
42
- 'jQuery("#tr_anon").click(function() {'.
43
- 'if (jQuery("#tr_anon").attr("checked")) {'.
44
- 'jQuery(".tr_editable").css("display","none");'.
45
- '} else {'.
46
- 'jQuery(".tr_editable").css("display","");'.
47
- '}'.
48
- '});'.
49
- '});'.
50
- '</script>';
51
- echo '<table class="'.NO_TRANSLATE_CLASS.'" style="width: 100%"><tr>';
52
-
53
- // we will hide the translatable column if anonymous can translate anyway
54
- if (can_translate('anonymous')) $extrastyle = ' style ="display:none"';
55
-
56
- $columns = 2;
57
- for($hdr=0; $hdr < $columns; $hdr++) {
58
- $extrapad = ($hdr != $columns - 1) ? ";padding-right: 40px" : '';
59
- echo '<th style="text-align:left; width:'.(100/$columns).'%">Language</th>'.
60
- '<th title="Is this language user selectable?">Viewable</th>'.
61
- '<th title="Is this language visible for translators?"'.$extrastyle.' class="tr_editable">Translatable</th>'.
62
- '<th>Default</th>'.
63
- '<th style="text-align:left;width: 80px'.$extrapad.'" title="Can we auto-translate this language?">Auto?</th>';
64
- }
65
- echo '</tr>';
66
-
67
- $i=0;
68
- foreach($languages as $code => $lang) {
69
- list ($language,$flag,$autot) = explode (",",$lang);
70
- if(!($i % $columns)) echo '<tr'.(!($i/2 % $columns) ? ' class="alternate"':'').'>';
71
- $i++;
72
-
73
- echo "<td>".display_flag("$tr_plugin_url/img/flags", $flag, $language,get_option(ENABLE_CSS_FLAGS))."&nbsp;$language</td>";
74
- echo '<td align="center"><input type="checkbox" id="' . $code .'_view" name="' .
75
- $code . '_view" onchange="chbx_change(\'' . $code . '\')" ' . is_viewable($code) . '/></td>';
76
- echo '<td class="tr_editable"'.$extrastyle.' align="center"><input type="checkbox" id="' . $code . '_edit" name="' .
77
- $code . '_edit" ' . is_editable($code). '/></td>';
78
- echo "<td align=\"center\"><input type=\"radio\" name=\"default_lang\" value=\"$code\" " .
79
- is_default_lang($code). "/></td>";
80
- // TODO: Add icons?
81
- echo "<td>".($autot ? "Y" : "N")."</td>";
82
-
83
- if(!($i % $columns)) echo '</tr>';
84
- }
85
- // add a missing </tr> if needed
86
- if($i % $columns) echo '</tr>';
87
- echo '</table>';
88
- }
89
-
90
- /*
91
- * Determine if the given language code is currentlly editable
92
- * Return 'checked' if true otherwise ""
93
- */
94
- function is_editable($code) {
95
- $langs = get_option(EDITABLE_LANGS);
96
- return (strpos($langs, $code) !== FALSE) ? 'checked="checked"' : '';
97
- }
98
-
99
- /*
100
- * Determine if the given language code is currentlly viewable
101
- * Return 'checked' if true otherwise ""
102
- */
103
- function is_viewable($code) {
104
- $langs = get_option(VIEWABLE_LANGS);
105
- return (strpos($langs, $code) !== FALSE) ? 'checked="checked"' : '';
106
- }
107
-
108
- /*
109
- * Determine if the given language code is currentlly the default language
110
- * Return 'checked' if true otherwise ""
111
- */
112
- function is_default_lang($code) {
113
- global $languages;
114
- $default = get_option(DEFAULT_LANG);
115
- if(!$languages[$default]) $default = "en";
116
- return ($default == $code) ? 'checked="checked"' : '';
117
- }
118
-
119
- /*
120
- * Insert permissions section in the admin page
121
- */
122
- function insert_permissions() {
123
- global $wp_roles;
124
- //display known roles and their permission to translate
125
- foreach($wp_roles->get_names() as $role_name => $something) {
126
- echo '<input type="checkbox" value="1" name="'.$role_name.'" '.can_translate($role_name).
127
- '/> '.ucfirst($role_name).'&nbsp;&nbsp;&nbsp;';
128
  }
129
- //Add our own custom role
130
- echo '<input id="tr_anon" type="checkbox" value="1" name="anonymous" '. can_translate('anonymous') . '/> Anonymous';
131
- }
132
-
133
- /*
134
- * Insert the option to enable/disable rewrite of perlmalinks.
135
- * When disabled only parameters will be used to identify the current language.
136
- */
137
- function insert_permalink_rewrite_option() {
138
- $checked = (get_option(ENABLE_PERMALINKS_REWRITE)) ? 'checked="checked"' :'';
139
- echo '<input type="checkbox" value="1" name="enable_permalinks" '. $checked . '/> '.
140
- 'Rewrite URLs to be search engine friendly, '.
141
- 'e.g. (http://wordpress.org/<strong>en</strong>). '.
142
- 'Requires that permalinks will be enabled.';
143
- }
144
-
145
- /*
146
- * Insert the option to enable/disable pushing of scripts to footer.
147
- */
148
- function insert_script_footer_option() {
149
- $checked = (get_option(ENABLE_FOOTER_SCRIPTS)) ? 'checked="checked"' :'';
150
- echo '<input type="checkbox" value="1" name="enable_footer_scripts" '. $checked . '/> '.
151
- 'Push transposh scripts to footer of page instead of header, makes pages load faster. '.
152
- 'Requires that your theme should have proper footer support.';
153
- }
154
-
155
- /*
156
- * Insert the option to enable/disable css flags.
157
- */
158
- function insert_css_flags_option() {
159
- $checked = (get_option(ENABLE_CSS_FLAGS)) ? 'checked="checked"' :'';
160
- echo '<input type="checkbox" value="1" name="enable_css_flags" '. $checked . '/> '.
161
- 'Use a single sprite with all flags, makes pages load faster. Currently not suitable if you made changes to the flags.';
162
- }
163
-
164
- /*
165
- * Insert the option to enable/disable automatic translation.
166
- * Enabled by default.
167
- */
168
- function insert_auto_translate_option() {
169
- $checked = (get_option(ENABLE_AUTO_TRANSLATE,1)) ? 'checked="checked"' : '';
170
- echo '<input type="checkbox" value="1" name="enable_autotranslate" '.$checked.'/> '.
171
- 'Allow automatic translation of pages (currently using Google Translate)';
172
- }
173
-
174
- /*
175
- * Insert the option to enable/disable msn translations.
176
- * Disabled by default because an API key is needed.
177
- */
178
- function insert_msn_translate_option() {
179
- $checked = (get_option(ENABLE_MSN_TRANSLATE)) ? 'checked="checked"' : '';
180
- echo '<input type="checkbox" value="1" name="enable_msntranslate" '.$checked.'/> '.
181
- 'Allow MSN (Bing) translator hinting (get key from <a href="http://www.microsofttranslator.com/Dev/Ajax/Default.aspx">here</a>)<br/>'.
182
- 'Key: <input type="text" size="35" class="regular-text" value="'.get_option(MSN_TRANSLATE_KEY).'" id="transposh_msn_key" name="transposh_msn_key"/>';
183
- }
184
 
185
- /*
186
- * Insert the option to enable/disable default language translation.
187
- * Disabled by default.
188
- */
189
- function insert_default_translate_option() {
190
- $checked = (get_option(ENABLE_DEFAULT_TRANSLATE,0)) ? 'checked="checked"' : '';
191
- echo '<input type="checkbox" value="1" name="enable_defaulttranslate" '.$checked.'/> '.
192
- 'Allow translation of default language - useful for sites with more than one major language';
193
- }
194
- //
195
  /*
196
  * Indicates whether the given role can translate.
197
  * Return either "checked" or ""
198
  */
199
- function can_translate($role_name) {
200
- global $wp_roles;
201
- if($role_name != 'anonymous') {
202
- $role = $wp_roles->get_role($role_name);
203
- if(isset($role) && $role->has_cap(TRANSLATOR))
204
- return 'checked="checked"';
205
-
 
206
  }
207
- else
208
- return (get_option(ANONYMOUS_TRANSLATION,1)) ? 'checked="checked"' : '';
209
- }
210
  //
211
  /*
212
  * Handle newly posted admin options.
213
  */
214
- function update_admin_options() {
215
-
216
- global $wp_roles, $languages;
217
- $viewable_langs = array();
218
- $editable_langs = array();
219
-
220
- //update roles and capabilities
221
- foreach($wp_roles->get_names() as $role_name => $something) {
222
- $role = $wp_roles->get_role($role_name);
223
- if($_POST[$role_name] == "1")
224
- $role->add_cap(TRANSLATOR);
225
- else
226
- $role->remove_cap(TRANSLATOR);
227
- }
228
 
229
- //Anonymous needs to be handled differently as it does not have a role
230
- update_option(ANONYMOUS_TRANSLATION, ($_POST['anonymous']) ? 1 : 0);
231
 
232
- //Update the list of supported/editable languages
233
- foreach($languages as $code => $lang) {
234
- if($_POST[$code . '_view']) {
235
- $viewable_langs[$code] = $code;
236
- // force that every viewable lang is editable
237
- $editable_langs[$code] = $code;
238
- }
239
 
240
- if($_POST[$code . '_edit']) {
241
- $editable_langs[$code] = $code;
 
242
  }
243
- }
244
 
245
- update_option(VIEWABLE_LANGS, implode(',', $viewable_langs));
246
- update_option(EDITABLE_LANGS, implode(',', $editable_langs));
247
- update_option(DEFAULT_LANG, $_POST['default_lang']);
248
 
249
- if(get_option(ENABLE_PERMALINKS_REWRITE) != $_POST['enable_permalinks']) {
250
- global $wp_rewrite;
251
- update_option(ENABLE_PERMALINKS_REWRITE, $_POST['enable_permalinks']);
 
 
 
252
 
253
- //rewrite rules
254
- add_filter('rewrite_rules_array', 'update_rewrite_rules');
255
- $wp_rewrite->flush_rules();
 
 
 
 
 
256
  }
257
 
258
- if(get_option(ENABLE_FOOTER_SCRIPTS) != $_POST['enable_footer_scripts'])
259
- update_option(ENABLE_FOOTER_SCRIPTS, $_POST['enable_footer_scripts']);
260
-
261
- if(get_option(ENABLE_CSS_FLAGS) != $_POST['enable_css_flags'])
262
- update_option(ENABLE_CSS_FLAGS, $_POST['enable_css_flags']);
263
-
264
- if(get_option(ENABLE_AUTO_TRANSLATE,1) != $_POST['enable_autotranslate'])
265
- update_option(ENABLE_AUTO_TRANSLATE, $_POST['enable_autotranslate']);
266
-
267
- if(get_option(ENABLE_DEFAULT_TRANSLATE) != $_POST['enable_defaulttranslate'])
268
- update_option(ENABLE_DEFAULT_TRANSLATE, $_POST['enable_defaulttranslate']);
269
-
270
- if(get_option(ENABLE_MSN_TRANSLATE) != $_POST['enable_msntranslate'])
271
- update_option(ENABLE_MSN_TRANSLATE, $_POST['enable_msntranslate']);
272
-
273
- if(get_option(MSN_TRANSLATE_KEY) != $_POST['transposh_msn_key'])
274
- update_option(MSN_TRANSLATE_KEY, $_POST['transposh_msn_key']);
275
-
276
- }
277
-
278
- //class that reperesent the complete plugin
279
- class transposh_plugin {
280
-
281
- //constructor of class, PHP4 compatible construction for backward compatibility
282
- function transposh_plugin() {
283
- if (get_option(ENABLE_CSS_FLAGS))
284
- wp_enqueue_style("transposh-flags",plugins_url('', __FILE__)."/css/transposh_flags.css",array(),'0.3.4');
285
- //add filter for WordPress 2.8 changed backend box system !
286
- add_filter('screen_layout_columns', array(&$this, 'on_screen_layout_columns'), 10, 2);
287
- //add some help
288
- add_filter('contextual_help_list', array(&$this, 'on_contextual_help'),100,2);
289
- //register callback for admin menu setup
290
- add_action('admin_menu', array(&$this, 'on_admin_menu'));
291
- //register the callback been used if options of page been submitted and needs to be processed
292
- add_action('admin_post_save_transposh', array(&$this, 'on_save_changes'));
293
- }
294
 
295
  //for WordPress 2.8 we have to tell, that we support 2 columns !
296
  function on_screen_layout_columns($columns, $screen) {
@@ -312,9 +136,9 @@ class transposh_plugin {
312
 
313
  //extend the admin menu
314
  function on_admin_menu() {
315
- //add our own option page, you can also add it to different sections or use your own one
316
- // TODO (Will I? hardcoded path)
317
- // $this->pagehook = add_menu_page('Transposh control center', "Transposh", 'manage_options', TRANSPOSH_ADMIN_PAGE_NAME, array(&$this, 'on_show_page'),WP_PLUGIN_URL .'/transposh/img/tplogo.png');
318
  $this->pagehook = add_options_page('Transposh control center', "Transposh", 'manage_options', TRANSPOSH_ADMIN_PAGE_NAME, array(&$this, 'on_show_page'));
319
  //register callback gets call prior your own page gets rendered
320
  add_action('load-'.$this->pagehook, array(&$this, 'on_load_page'));
@@ -322,7 +146,7 @@ class transposh_plugin {
322
 
323
  //will be executed if wordpress core detects this page has to be rendered
324
  function on_load_page() {
325
- //ensure, that the needed javascripts been loaded to allow drag/drop, expand/collapse and hide/show of boxes
326
  wp_enqueue_script('common');
327
  wp_enqueue_script('wp-lists');
328
  wp_enqueue_script('postbox');
@@ -339,8 +163,8 @@ class transposh_plugin {
339
 
340
  //executed to show the plugins complete admin page
341
  function on_show_page() {
342
- //we need the global screen column value to beable to have a sidebar in WordPress 2.8
343
- global $screen_layout_columns;
344
  //add a 3rd content box now for demonstration purpose, boxes added at start of page rendering can't be switched on/off,
345
  //may be needed to ensure that a special box is always available
346
  add_meta_box('transposh-contentbox-community', 'Transposh community features (upcoming)', array(&$this, 'on_contentbox_community_content'), $this->pagehook, 'normal', 'core');
@@ -348,17 +172,23 @@ class transposh_plugin {
348
  //$data = array('My Data 1', 'My Data 2', 'Available Data 1');
349
  ?>
350
  <div id="transposh-general" class="wrap">
351
- <?php screen_icon('options-general'); ?>
 
352
  <h2>Transposh</h2>
353
  <form action="admin-post.php" method="post">
354
- <?php wp_nonce_field(TR_NONCE); ?>
355
- <?php wp_nonce_field('closedpostboxes', 'closedpostboxesnonce', false ); ?>
356
- <?php wp_nonce_field('meta-box-order', 'meta-box-order-nonce', false ); ?>
 
 
 
357
  <input type="hidden" name="action" value="save_transposh" />
358
 
359
- <div id="poststuff" class="metabox-holder<?php echo 2 == $screen_layout_columns ? ' has-right-sidebar' : ''; ?>">
 
360
  <div id="side-info-column" class="inner-sidebar">
361
- <?php do_meta_boxes($this->pagehook, 'side', ""); ?>
 
362
  </div>
363
  <div id="post-body" class="has-sidebar">
364
  <div id="post-body-content" class="has-sidebar-content">
@@ -381,25 +211,26 @@ class transposh_plugin {
381
  // close postboxes that should be closed
382
  $('.if-js-closed').removeClass('if-js-closed').addClass('closed');
383
  // postboxes setup
384
- postboxes.add_postbox_toggles('<?php echo $this->pagehook; ?>');
385
- });
386
- //]]>
 
387
  </script>
388
 
389
- <?php
390
  }
391
 
392
  //executed if the post arrives initiated by pressing the submit button of form
393
  function on_save_changes() {
394
- //user permission check
395
  if ( !current_user_can('manage_options') )
396
  wp_die( __('Problems?') );
397
  //cross check the given referer
398
  check_admin_referer(TR_NONCE);
399
 
400
  //process here your on $_POST validation and / or option saving
401
- update_admin_options();
402
- transposh_widget_post();
403
 
404
  //lets redirect the post request into get request (you may add additional params at the url, if you need to show save results
405
  wp_redirect($_POST['_wp_http_referer']);
@@ -417,8 +248,9 @@ class transposh_plugin {
417
  //Donate with PayPal
418
  echo '</ul>';
419
  }
 
420
  function on_sidebox_widget_content($data) {
421
- transposh_widget_control();
422
  }
423
 
424
  function on_sidebox_news_content($data) {
@@ -437,7 +269,7 @@ class transposh_plugin {
437
  '<li><a href="%1$s" title="%2$s">%3$s</a></li>',
438
  //esc_url( $item['link'] ),
439
  //esc_attr( strip_tags( $item['description'] ) ),
440
- // Switched to 2.7 compatability functions
441
  clean_url( $item['link'] ),
442
  attribute_escape( strip_tags( $item['description'] ) ),
443
  htmlentities( $item['title'],ENT_COMPAT,'UTF-8' )
@@ -445,7 +277,8 @@ class transposh_plugin {
445
  }
446
 
447
  echo '</ul>';
448
- } else {
 
449
  _e( 'An error has occurred, which probably means the feed is down. Try again later.' );
450
  }
451
  }
@@ -453,51 +286,177 @@ class transposh_plugin {
453
  wp_rss2('http://feeds2.feedburner.com/transposh', 5);
454
  echo '</div>';
455
  }
 
456
  function on_sidebox_stats_content($data) {
457
- db_stats();
458
  }
459
 
460
  function on_contentbox_languages_content($data) {
461
- insert_supported_langs();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
462
  }
463
 
464
  function on_contentbox_translation_content($data) {
 
 
 
465
  echo '<h4>Who can translate ?</h4>';
466
- insert_permissions();
 
 
 
 
 
 
467
 
 
 
 
 
468
  echo '<h4>Enable automatic translation</h4>';
469
- insert_auto_translate_option();
470
-
 
 
 
 
 
 
 
 
 
 
 
 
 
471
  echo '<h4>Support for Bing (MSN) translation hinting (experimental)</h4>';
472
- insert_msn_translate_option();
473
-
 
 
 
 
 
 
474
  echo '<h4>Enable default language translation</h4>';
475
- insert_default_translate_option();
 
476
 
477
  }
 
478
  function on_contentbox_generic_content($data) {
479
- global $wp_version;//, $languages;
 
 
 
480
  echo '<h4>Rewrite URLs</h4>';
481
- insert_permalink_rewrite_option();
482
-
483
- if (floatval($wp_version) >= 2.8) {
 
 
 
 
 
 
 
484
  echo '<h4>Add scripts to footer</h4>';
485
- insert_script_footer_option();
 
 
486
  }
487
 
488
- echo '<h4>Use css flags (experimental)</h4>';
489
- insert_css_flags_option();
 
 
 
 
 
 
 
 
 
 
 
490
  /*foreach($languages as $code => $lang) {
491
  list ($language,$flag,$autot) = explode (",",$lang);
492
  $flags .= $flag.',';
493
  }
 
494
  echo '<a href="http://transposh.org/services/index.php?flags='.$flags.'">Gen sprites</a>';*/
495
-
496
  }
 
497
  function on_contentbox_community_content($data) {
498
  echo "<p>This space is reserved for the coming community features of Transposh that will help you find translators to help with your site.</p>";
499
  }
500
  }
501
 
502
- $my_transposh_plugin = new transposh_plugin();
503
  ?>
26
  define ("TR_NONCE","transposh_nonce");
27
 
28
 
29
+ //class that reperesent the complete plugin
30
+ class transposh_plugin_admin {
31
+ /** @var transposh_plugin $transposh father class */
32
+ private $transposh;
33
+ //constructor of class, PHP4 compatible construction for backward compatibility
34
+ function transposh_plugin_admin(&$transposh) {
35
+ $this->transposh = &$transposh;
36
+ // FIX (probably always happens?)
37
+ if ($this->transposh->options->get_widget_css_flags())
38
+ wp_enqueue_style("transposh-flags",plugins_url('', __FILE__)."/css/transposh_flags.css",array(),TRANSPOSH_PLUGIN_VER);
39
+ //add filter for WordPress 2.8 changed backend box system !
40
+ add_filter('screen_layout_columns', array(&$this, 'on_screen_layout_columns'), 10, 2);
41
+ //add some help
42
+ add_filter('contextual_help_list', array(&$this, 'on_contextual_help'),100,2);
43
+ //register callback for admin menu setup
44
+ add_action('admin_menu', array(&$this, 'on_admin_menu'));
45
+ //register the callback been used if options of page been submitted and needs to be processed
46
+ add_action('admin_post_save_transposh', array(&$this, 'on_save_changes'));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
 
 
 
 
 
 
 
 
 
 
49
  /*
50
  * Indicates whether the given role can translate.
51
  * Return either "checked" or ""
52
  */
53
+ function can_translate($role_name) {
54
+ if($role_name != 'anonymous') {
55
+ $role = $GLOBALS['wp_roles']->get_role($role_name);
56
+ if(isset($role) && $role->has_cap(TRANSLATOR))
57
+ return 'checked="checked"';
58
+ }
59
+ else
60
+ return ($this->transposh->options->get_anonymous_translation()) ? 'checked="checked"' : '';
61
  }
 
 
 
62
  //
63
  /*
64
  * Handle newly posted admin options.
65
  */
66
+ function update_admin_options() {
67
+
68
+
69
+ $viewable_langs = array();
70
+ $editable_langs = array();
71
+
72
+ //update roles and capabilities
73
+ foreach($GLOBALS['wp_roles']->get_names() as $role_name => $something) {
74
+ $role = $GLOBALS['wp_roles']->get_role($role_name);
75
+ if($_POST[$role_name] == "1")
76
+ $role->add_cap(TRANSLATOR);
77
+ else
78
+ $role->remove_cap(TRANSLATOR);
79
+ }
80
 
81
+ //Anonymous needs to be handled differently as it does not have a role
82
+ $this->transposh->options->set_anonymous_translation($_POST['anonymous']);
83
 
84
+ //Update the list of supported/editable languages
85
+ foreach($GLOBALS['languages'] as $code => $lang) {
86
+ if($_POST[$code . '_view']) {
87
+ $viewable_langs[$code] = $code;
88
+ // force that every viewable lang is editable
89
+ $editable_langs[$code] = $code;
90
+ }
91
 
92
+ if($_POST[$code . '_edit']) {
93
+ $editable_langs[$code] = $code;
94
+ }
95
  }
 
96
 
97
+ $this->transposh->options->set_viewable_langs(implode(',', $viewable_langs));
98
+ $this->transposh->options->set_editable_langs(implode(',', $editable_langs));
99
+ $this->transposh->options->set_default_language($_POST['default_lang']);
100
 
101
+ if($this->transposh->options->get_enable_permalinks() != $_POST[ENABLE_PERMALINKS]) {
102
+ $this->transposh->options->set_enable_permalinks($_POST[ENABLE_PERMALINKS]);
103
+ //rewrite rules - refresh.? //TODO ---???
104
+ add_filter('rewrite_rules_array', 'update_rewrite_rules');
105
+ $GLOBALS['wp_rewrite']->flush_rules();
106
+ }
107
 
108
+ $this->transposh->options->set_enable_footer_scripts($_POST[ENABLE_FOOTER_SCRIPTS]);
109
+ $this->transposh->options->set_alternate_post($_POST[ALTERNATE_POST]);
110
+ $this->transposh->options->set_enable_auto_translate($_POST[ENABLE_AUTO_TRANSLATE]);
111
+ $this->transposh->options->set_enable_auto_post_translate($_POST[ENABLE_AUTO_POST_TRANSLATE]);
112
+ $this->transposh->options->set_enable_default_translate($_POST[ENABLE_DEFAULT_TRANSLATE]);
113
+ $this->transposh->options->set_enable_msn_translate($_POST[ENABLE_MSN_TRANSLATE]);
114
+ $this->transposh->options->set_msn_key($_POST[MSN_TRANSLATE_KEY]);
115
+ $this->transposh->options->update_options();
116
  }
117
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
 
119
  //for WordPress 2.8 we have to tell, that we support 2 columns !
120
  function on_screen_layout_columns($columns, $screen) {
136
 
137
  //extend the admin menu
138
  function on_admin_menu() {
139
+ //add our own option page, you can also add it to different sections or use your own one
140
+ // TODO (Will I? hardcoded path)
141
+ // $this->pagehook = add_menu_page('Transposh control center', "Transposh", 'manage_options', TRANSPOSH_ADMIN_PAGE_NAME, array(&$this, 'on_show_page'),WP_PLUGIN_URL .'/transposh/img/tplogo.png');
142
  $this->pagehook = add_options_page('Transposh control center', "Transposh", 'manage_options', TRANSPOSH_ADMIN_PAGE_NAME, array(&$this, 'on_show_page'));
143
  //register callback gets call prior your own page gets rendered
144
  add_action('load-'.$this->pagehook, array(&$this, 'on_load_page'));
146
 
147
  //will be executed if wordpress core detects this page has to be rendered
148
  function on_load_page() {
149
+ //ensure, that the needed javascripts been loaded to allow drag/drop, expand/collapse and hide/show of boxes
150
  wp_enqueue_script('common');
151
  wp_enqueue_script('wp-lists');
152
  wp_enqueue_script('postbox');
163
 
164
  //executed to show the plugins complete admin page
165
  function on_show_page() {
166
+ //we need the global screen column value to beable to have a sidebar in WordPress 2.8
167
+ //global $screen_layout_columns;
168
  //add a 3rd content box now for demonstration purpose, boxes added at start of page rendering can't be switched on/off,
169
  //may be needed to ensure that a special box is always available
170
  add_meta_box('transposh-contentbox-community', 'Transposh community features (upcoming)', array(&$this, 'on_contentbox_community_content'), $this->pagehook, 'normal', 'core');
172
  //$data = array('My Data 1', 'My Data 2', 'Available Data 1');
173
  ?>
174
  <div id="transposh-general" class="wrap">
175
+ <?php screen_icon('options-general');
176
+ ?>
177
  <h2>Transposh</h2>
178
  <form action="admin-post.php" method="post">
179
+ <?php wp_nonce_field(TR_NONCE);
180
+ ?>
181
+ <?php wp_nonce_field('closedpostboxes', 'closedpostboxesnonce', false );
182
+ ?>
183
+ <?php wp_nonce_field('meta-box-order', 'meta-box-order-nonce', false );
184
+ ?>
185
  <input type="hidden" name="action" value="save_transposh" />
186
 
187
+ <div id="poststuff" class="metabox-holder<?php echo 2 == $GLOBALS['screen_layout_columns'] ? ' has-right-sidebar' : '';
188
+ ?>">
189
  <div id="side-info-column" class="inner-sidebar">
190
+ <?php do_meta_boxes($this->pagehook, 'side', "");
191
+ ?>
192
  </div>
193
  <div id="post-body" class="has-sidebar">
194
  <div id="post-body-content" class="has-sidebar-content">
211
  // close postboxes that should be closed
212
  $('.if-js-closed').removeClass('if-js-closed').addClass('closed');
213
  // postboxes setup
214
+ postboxes.add_postbox_toggles('<?php echo $this->pagehook;
215
+ ?>');
216
+ });
217
+ //]]>
218
  </script>
219
 
220
+ <?php
221
  }
222
 
223
  //executed if the post arrives initiated by pressing the submit button of form
224
  function on_save_changes() {
225
+ //user permission check
226
  if ( !current_user_can('manage_options') )
227
  wp_die( __('Problems?') );
228
  //cross check the given referer
229
  check_admin_referer(TR_NONCE);
230
 
231
  //process here your on $_POST validation and / or option saving
232
+ $this->transposh->widget->transposh_widget_post(FALSE);
233
+ $this->update_admin_options();
234
 
235
  //lets redirect the post request into get request (you may add additional params at the url, if you need to show save results
236
  wp_redirect($_POST['_wp_http_referer']);
248
  //Donate with PayPal
249
  echo '</ul>';
250
  }
251
+
252
  function on_sidebox_widget_content($data) {
253
+ $this->transposh->widget->transposh_widget_control();
254
  }
255
 
256
  function on_sidebox_news_content($data) {
269
  '<li><a href="%1$s" title="%2$s">%3$s</a></li>',
270
  //esc_url( $item['link'] ),
271
  //esc_attr( strip_tags( $item['description'] ) ),
272
+ // TODO - check Switched to 2.7 compatability functions
273
  clean_url( $item['link'] ),
274
  attribute_escape( strip_tags( $item['description'] ) ),
275
  htmlentities( $item['title'],ENT_COMPAT,'UTF-8' )
277
  }
278
 
279
  echo '</ul>';
280
+ }
281
+ else {
282
  _e( 'An error has occurred, which probably means the feed is down. Try again later.' );
283
  }
284
  }
286
  wp_rss2('http://feeds2.feedburner.com/transposh', 5);
287
  echo '</div>';
288
  }
289
+
290
  function on_sidebox_stats_content($data) {
291
+ $this->transposh->database->db_stats();
292
  }
293
 
294
  function on_contentbox_languages_content($data) {
295
+ /*
296
+ * Insert supported languages section in admin page
297
+ */
298
+ // was function insert_supported_langs() {
299
+
300
+ echo
301
+ '<script type="text/javascript">'.
302
+ 'function chbx_change(lang)'.
303
+ '{'.
304
+ 'jQuery("#"+lang+"_edit").attr("checked",jQuery("#"+lang+"_view").attr("checked"))'.
305
+ '}'.
306
+ 'jQuery(document).ready(function() {'.
307
+ 'jQuery("#tr_anon").click(function() {'.
308
+ 'if (jQuery("#tr_anon").attr("checked")) {'.
309
+ 'jQuery(".tr_editable").css("display","none");'.
310
+ '} else {'.
311
+ 'jQuery(".tr_editable").css("display","");'.
312
+ '}'.
313
+ '});'.
314
+ '});'.
315
+ '</script>';
316
+ echo '<table class="'.NO_TRANSLATE_CLASS.'" style="width: 100%"><tr>';
317
+
318
+ // we will hide the translatable column if anonymous can translate anyway
319
+ if ($this->can_translate('anonymous')) $extrastyle = ' style ="display:none"';
320
+
321
+ $columns = 2;
322
+ for($hdr=0; $hdr < $columns; $hdr++) {
323
+ $extrapad = ($hdr != $columns - 1) ? ";padding-right: 40px" : '';
324
+ echo '<th style="text-align:left; width:'.(100/$columns).'%">Language</th>'.
325
+ '<th title="Is this language user selectable?">Viewable</th>'.
326
+ '<th title="Is this language visible for translators?"'.$extrastyle.' class="tr_editable">Translatable</th>'.
327
+ '<th>Default</th>'.
328
+ '<th style="text-align:left;width: 80px'.$extrapad.'" title="Can we auto-translate this language?">Auto?</th>';
329
+ }
330
+ echo '</tr>';
331
+
332
+ $i=0;
333
+ foreach($GLOBALS['languages'] as $code => $lang) {
334
+ list ($language,$flag,$autot) = explode (",",$lang);
335
+ if(!($i % $columns)) echo '<tr'.(!($i/2 % $columns) ? ' class="alternate"':'').'>';
336
+ $i++;
337
+
338
+ echo "<td>".display_flag("{$this->transposh->transposh_plugin_url}/img/flags", $flag, $language,$this->transposh->options->get_widget_css_flags())."&nbsp;$language</td>";
339
+ echo '<td align="center"><input type="checkbox" id="' . $code .'_view" name="' .
340
+ $code . '_view" onchange="chbx_change(\'' . $code . '\')" ' . $this->checked($this->transposh->options->is_viewable_language($code)) . '/></td>';
341
+ echo '<td class="tr_editable"'.$extrastyle.' align="center"><input type="checkbox" id="' . $code . '_edit" name="' .
342
+ $code . '_edit" ' . $this->checked($this->transposh->options->is_editable_language($code)). '/></td>';
343
+ echo "<td align=\"center\"><input type=\"radio\" name=\"default_lang\" value=\"$code\" " .
344
+ $this->checked($this->transposh->options->is_default_language($code)). "/></td>";
345
+ // TODO: Add icons?
346
+ echo "<td>".($autot ? "Y" : "N")."</td>";
347
+
348
+ if(!($i % $columns)) echo '</tr>';
349
+ }
350
+ // add a missing </tr> if needed
351
+ if($i % $columns) echo '</tr>';
352
+ echo '</table>';
353
+
354
+
355
+ }
356
+
357
+ /**
358
+ * uses a boolean expression to make checkboxes check
359
+ * @param boolean $eval
360
+ * @return string used for checkboxes
361
+ */
362
+ private function checked($eval) {
363
+ return $eval ? 'checked="checked"' : '';
364
  }
365
 
366
  function on_contentbox_translation_content($data) {
367
+ /*
368
+ * Insert permissions section in the admin page
369
+ */
370
  echo '<h4>Who can translate ?</h4>';
371
+ //display known roles and their permission to translate
372
+ foreach($GLOBALS['wp_roles']->get_names() as $role_name => $something) {
373
+ echo '<input type="checkbox" value="1" name="'.$role_name.'" '.$this->can_translate($role_name).
374
+ '/> '.ucfirst($role_name).'&nbsp;&nbsp;&nbsp;';
375
+ }
376
+ //Add our own custom role
377
+ echo '<input id="tr_anon" type="checkbox" value="1" name="anonymous" '. $this->can_translate('anonymous') . '/> Anonymous';
378
 
379
+ /*
380
+ * Insert the option to enable/disable automatic translation.
381
+ * Enabled by default.
382
+ */
383
  echo '<h4>Enable automatic translation</h4>';
384
+ echo '<input type="checkbox" value="1" name="'.ENABLE_AUTO_TRANSLATE.'" '.$this->checked($this->transposh->options->get_enable_auto_translate()).'/> '.
385
+ 'Allow automatic translation of pages (currently using Google Translate)';
386
+
387
+ /**
388
+ * Insert the option to enable/disable automatic translation upon publishing.
389
+ * Disabled by default.
390
+ * @since 0.3.5 */
391
+ echo '<h4>New - Enable automatic translation after posting</h4>';
392
+ echo '<input type="checkbox" value="1" name="'.ENABLE_AUTO_POST_TRANSLATE.'" '.$this->checked($this->transposh->options->get_enable_auto_post_translate()).'/> '.
393
+ 'Do automatic translation immediately after a post has been published';
394
+
395
+ /*
396
+ * Insert the option to enable/disable msn translations.
397
+ * Disabled by default because an API key is needed.
398
+ */
399
  echo '<h4>Support for Bing (MSN) translation hinting (experimental)</h4>';
400
+ echo '<input type="checkbox" value="1" name="'.ENABLE_MSN_TRANSLATE.'" '.$this->checked($this->transposh->options->get_enable_msn_translate()).'/> '.
401
+ 'Allow MSN (Bing) translator hinting (get key from <a href="http://www.microsofttranslator.com/Dev/Ajax/Default.aspx">here</a>)<br/>'.
402
+ 'Key: <input type="text" size="35" class="regular-text" value="'.$this->transposh->options->get_msn_key().'" id="'.MSN_TRANSLATE_KEY.'" name="'.MSN_TRANSLATE_KEY.'"/>';
403
+
404
+ /*
405
+ * Insert the option to enable/disable default language translation.
406
+ * Disabled by default.
407
+ */
408
  echo '<h4>Enable default language translation</h4>';
409
+ echo '<input type="checkbox" value="1" name="'.ENABLE_DEFAULT_TRANSLATE.'" '.$this->checked ($this->transposh->options->get_enable_default_translate()).'/> '.
410
+ 'Allow translation of default language - useful for sites with more than one major language';
411
 
412
  }
413
+
414
  function on_contentbox_generic_content($data) {
415
+ /*
416
+ * Insert the option to enable/disable rewrite of perlmalinks.
417
+ * When disabled only parameters will be used to identify the current language.
418
+ */
419
  echo '<h4>Rewrite URLs</h4>';
420
+ echo '<input type="checkbox" value="1" name="'.ENABLE_PERMALINKS.'" '. $this->checked($this->transposh->options->get_enable_permalinks()) . '/> '.
421
+ 'Rewrite URLs to be search engine friendly, '.
422
+ 'e.g. (http://wordpress.org/<strong>en</strong>). '.
423
+ 'Requires that permalinks will be enabled.';
424
+
425
+ /*
426
+ * Insert the option to enable/disable pushing of scripts to footer.
427
+ * Works on wordpress 2.8 and up
428
+ */
429
+ if (floatval($GLOBALS['wp_version']) >= 2.8) {
430
  echo '<h4>Add scripts to footer</h4>';
431
+ echo '<input type="checkbox" value="1" name="'.ENABLE_FOOTER_SCRIPTS.'" '. $this->checked($this->transposh->options->get_enable_footer_scripts()) . '/> '.
432
+ 'Push transposh scripts to footer of page instead of header, makes pages load faster. '.
433
+ 'Requires that your theme should have proper footer support.';
434
  }
435
 
436
+ /**
437
+ * Allow some alternate posting methods support
438
+ * @since 0.3.5 */
439
+ echo '<h4>Try alternate posting methods</h4>';
440
+
441
+ echo '<select name="'.ALTERNATE_POST.'" id="'.ALTERNATE_POST.'">';
442
+ echo '<option value="0" '.(($this->transposh->options->get_alternate_post() == 0) ? 'selected=""':'').'>Normal</option>';
443
+ echo '<option value="1" '.(($this->transposh->options->get_alternate_post() == 1) ? 'selected=""':'').'>Added &quot;/&quot;</option>';
444
+ echo '<option value="2" '.(($this->transposh->options->get_alternate_post() == 2) ? 'selected=""':'').'>Added &quot;/index.php&quot;</option>';
445
+ echo '</select> ';
446
+ echo 'Change this option only if changes fail to get saved on the database';
447
+
448
+ /* WIP echo '<h4>Show original language first</h4>';*/
449
  /*foreach($languages as $code => $lang) {
450
  list ($language,$flag,$autot) = explode (",",$lang);
451
  $flags .= $flag.',';
452
  }
453
+ * WIP2
454
  echo '<a href="http://transposh.org/services/index.php?flags='.$flags.'">Gen sprites</a>';*/
 
455
  }
456
+
457
  function on_contentbox_community_content($data) {
458
  echo "<p>This space is reserved for the coming community features of Transposh that will help you find translators to help with your site.</p>";
459
  }
460
  }
461
 
 
462
  ?>
transposh_db.php CHANGED
@@ -41,291 +41,421 @@ define("DB_VERSION", "1.03");
41
  //Constant used as key in options database
42
  define("TRANSPOSH_DB_VERSION", "transposh_db_version");
43
 
44
- /*
45
- * Fetch translation from db or cache.
46
- * Returns An array that contains the translated string and it source.
47
- * Will return NULL if no translation is available.
48
- */
49
- function fetch_translation($original, $lang) {
50
- global $wpdb;
51
- $translated = NULL;
52
-
 
 
 
 
 
 
 
 
 
53
 
54
- //The original is saved in db in its escaped form
55
- $original = $wpdb->escape(html_entity_decode($original, ENT_NOQUOTES, 'UTF-8'));
56
 
57
- if(ENABLE_APC && function_exists('apc_fetch')) {
58
- $cached = apc_fetch($original .'___'. $lang, $rc);
59
- if($rc === TRUE) {
60
-
61
- return $cached;
 
62
  }
63
- }
64
 
65
- $table_name = $wpdb->prefix . TRANSLATIONS_TABLE;
66
- $query = "SELECT * FROM $table_name WHERE original = '$original' and lang = '$lang' ";
67
- $row = $wpdb->get_row($query);
68
 
69
- if($row !== FALSE) {
70
- $translated_text = stripslashes($row->translated);
71
- $translated = array($translated_text, $row->source);
72
 
73
-
74
- }
75
-
76
- if(ENABLE_APC && function_exists('apc_store')) {
77
- //If we don't have translation still we want to have it in cache
78
- $cache_entry = $translated;
79
- if($cache_entry == NULL) {
80
- $cache_entry = "";
81
  }
82
 
83
- //update cache
84
- $rc = apc_store($original .'___'. $lang, $cache_entry, 3600);
85
- if($rc === TRUE) {
86
-
 
 
 
 
 
 
 
 
87
  }
88
- }
89
 
90
-
91
- return $translated;
92
- }
93
 
94
  /*
95
  * A new translation has been posted, update the translation database.
96
  * This has changed since we now accept multiple translations at once
97
  */
98
- function update_translation() {
99
- global $wpdb;
100
-
101
- $ref=getenv('HTTP_REFERER');
102
- $items = $_POST['items'];
103
- $lang = $_POST['lang'];
104
- $source = $_POST['source'];
105
- // check params
106
-
107
- if(!isset($items) || !isset($lang)) {
108
 
109
- return;
110
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
 
112
- //Check permissions, first the lanugage must be on the edit list. Then either the user
113
- //is a translator or automatic translation if it is enabled.
114
- if(!(is_editable_lang($lang) &&
115
- (is_translator() || ($source == 1 && get_option(ENABLE_AUTO_TRANSLATE, 1))))) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
 
117
- header("HTTP/1.0 401 Unauthorized translation");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  exit;
119
  }
120
 
121
- //add our own custom header - so we will know that we got here
122
- header("Transposh: ver-0.3.4 db_version-". DB_VERSION);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
 
124
- // transaction log stuff
125
- global $user_ID;
126
- get_currentuserinfo();
 
 
 
 
 
 
 
 
 
127
 
128
- // log either the user ID or his IP
129
- if ('' == $user_ID) {
130
- $loguser = $_SERVER['REMOTE_ADDR'];
131
- }
132
- else {
133
- $loguser = $user_ID;
134
- }
135
- // end tl
136
 
137
- // We are now passing all posted items
138
- for ($i=0;$i<$items;$i++) {
139
- $original = base64_url_decode($_POST["tk$i"]);
140
- $translation = $_POST["tr$i"];
141
- //Decode & remove already escaped character to avoid double escaping
142
- $translation = $wpdb->escape(htmlspecialchars(stripslashes(urldecode($translation))));
143
 
144
- //The original content is encoded as base64 before it is sent (i.e. token), after we
145
- //decode it should just the same after it was parsed.
146
- $original = $wpdb->escape(html_entity_decode($original, ENT_NOQUOTES, 'UTF-8'));
147
 
148
- //Here we check we are not redoing stuff
149
- list($translated_text, $old_source) = fetch_translation($original, $lang);
150
- if ($translated_text) {
151
- if ($source == 1) {
152
-
153
- return;
 
 
 
 
 
 
 
 
 
 
154
  }
155
- if ($translation == $wpdb->escape(htmlspecialchars(stripslashes(urldecode($translated_text)))) && $old_source == $source) {
156
-
157
- return;
 
 
 
 
 
 
 
158
  }
159
- }
160
- // Setting the values string for the database (notice how concatanation is handled)
161
- $values .= "('" . $original . "','" . $translation . "','" . $lang . "','" . $source . "')".(($items != $i+1) ?', ':'');
162
- // Setting the transaction log records
163
- $logvalues .= "('" . $original . "','" . $translation . "','" . $lang . "','".$loguser."','".$source."')".(($items != $i+1) ?', ':'');
164
 
165
- // If we have caching - we remove previous entry from cache
166
- if(ENABLE_APC && function_exists('apc_store')) {
167
- apc_delete($original .'___'. $lang);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
  }
169
- }
170
 
171
- // perform insertion to the database, with one query :)
172
- $update = "REPLACE INTO ".$wpdb->prefix . TRANSLATIONS_TABLE." (original, translated, lang, source)
173
  VALUES $values";
174
-
175
 
176
- $result = $wpdb->query($update);
177
 
178
- if($result !== FALSE) {
179
- // update the transaction log too
180
- $log = "INSERT INTO ".$wpdb->prefix.TRANSLATIONS_LOG." (original, translated, lang, translated_by, source) ".
181
- "VALUES $logvalues";
182
- $result = $wpdb->query($log);
183
 
184
-
185
- }
186
- else {
187
-
188
-
189
- header("HTTP/1.0 404 Failed to update language database ".mysql_error());
 
 
 
190
  }
191
- // this is a termination for the ajax sequence
192
- exit;
193
- }
194
 
195
  /*
196
  * Get translation history for some translation.
197
  */
198
- function get_translation_history($token, $lang) {
199
- global $wpdb;
200
 
201
- $ref=getenv('HTTP_REFERER');
202
- $original = base64_url_decode($token);
203
-
204
 
205
- // check params
206
-
207
- if(!isset($original) || !isset($lang)) {
 
 
 
208
 
209
- return;
210
- }
211
-
212
 
213
- //Check permissions, first the lanugage must be on the edit list. Then either the user
214
- //is a translator or automatic translation if it is enabled.
215
- if(!(is_editable_lang($lang) && is_translator())) {
 
 
 
 
216
 
217
- header("HTTP/1.0 401 Unauthorized history");
218
- exit;
219
- }
220
-
221
-
222
- $table_name = $wpdb->prefix . TRANSLATIONS_LOG;
223
-
224
-
225
- //The original content is encoded as base64 before it is sent (i.e. token), after we
226
- //decode it should just the same after it was parsed.
227
- $original = $wpdb->escape(html_entity_decode($original, ENT_NOQUOTES, 'UTF-8'));
228
-
229
- //add our own custom header - so we will know that we got here
230
- header("Transposh: ver-0.3.4 db_version-". DB_VERSION);
231
-
232
- $query = "SELECT translated, translated_by, timestamp, source, user_login ".
233
- "FROM $table_name ".
234
- "LEFT JOIN {$wpdb->prefix}users ON translated_by = {$wpdb->prefix}users.id ".
235
- "WHERE original='$original' AND lang='$lang' ".
236
- "ORDER BY timestamp DESC";
237
-
238
-
239
- $rows = $wpdb->get_results($query);
240
- // trying
241
-
242
- if($rows !== FALSE) {
243
- echo '<table>' .
244
- '<thead>'.
245
- '<tr>'.
246
- '<th>Translated</th><th/><th>By</th><th>At</th>'.
247
- '</tr>'.
248
- '</thead>'.
249
- '<tbody>';
250
- foreach ($rows as $row) {
251
- if (is_null($row->user_login)) $row->user_login = $row->translated_by;
252
- echo "<tr><td>{$row->translated}</td><td source=\"{$row->source}\"/><td user_id=\"{$row->translated_by}\">{$row->user_login}</td><td>{$row->timestamp}</td></tr>";
253
  }
254
- echo '</tbody></table>';
255
- }
256
 
257
- exit;
258
- }
259
 
260
  /*
261
  * Setup the translation database.
262
  */
263
- function setup_db() {
264
-
265
- global $wpdb;
266
- require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
267
 
268
- $installed_ver = get_option(TRANSPOSH_DB_VERSION);
269
 
270
- if( $installed_ver != DB_VERSION ) {
271
- $table_name = $wpdb->prefix . TRANSLATIONS_TABLE;
272
 
273
-
274
- $sql = "CREATE TABLE $table_name (original VARCHAR(255) NOT NULL,".
275
- "lang CHAR(5) NOT NULL,".
276
- "translated VARCHAR(255),".
277
- "source TINYINT NOT NULL,".
278
- "PRIMARY KEY (original, lang)) DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci";
279
 
280
- dbDelta($sql);
281
 
 
282
 
283
- $table_name = $wpdb->prefix . TRANSLATIONS_LOG;
 
 
 
 
 
 
 
 
 
 
 
284
 
285
 
286
- $sql = "CREATE TABLE $table_name (original VARCHAR(255) NOT NULL,".
287
- "lang CHAR(5) NOT NULL,".
288
- "translated VARCHAR(255),".
289
- "translated_by VARCHAR(15),".
290
- "source TINYINT NOT NULL,".
291
- "timestamp TIMESTAMP,".
292
- "PRIMARY KEY (original, lang, timestamp)) DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci";
293
-
294
- dbDelta($sql);
295
- update_option(TRANSPOSH_DB_VERSION, DB_VERSION);
296
  }
297
 
298
-
299
- }
300
-
301
- function db_stats () {
302
- global $wpdb;
303
- echo "<h4>Database stats</h4>";
304
- $table_name = $wpdb->prefix . TRANSLATIONS_TABLE;
305
- $log_table_name = $wpdb->prefix . TRANSLATIONS_LOG;
306
- $query = "SELECT count(*) as count FROM `$table_name`";
307
- $rows = $wpdb->get_results($query);
308
- foreach ($rows as $row) {
309
- if ($row->count)
310
- echo "<p>Total of <strong style=\"color:red\">{$row->count}</strong> translated phrases.</p>";
311
- }
312
 
313
- $query = "SELECT count(*) as count,lang FROM `$table_name` WHERE source='0' GROUP BY `lang` ORDER BY `count` DESC LIMIT 3";
314
- $rows = $wpdb->get_results($query);
315
- foreach ($rows as $row) {
316
- if ($row->count)
317
- echo "<p><strong>{$row->lang}</strong> has <strong style=\"color:red\">{$row->count}</strong> human translated phrases.</p>";
318
- }
319
 
320
- echo "<h4>Recent activity</h4>";
321
- $query = "SELECT * FROM `$log_table_name` WHERE source='0' ORDER BY `timestamp` DESC LIMIT 3";
322
- $rows = $wpdb->get_results($query);
323
- foreach ($rows as $row) {
324
- $td = mysql2date(get_option('date_format').' '.get_option('time_format'), $row->timestamp);
325
- //the_date();
326
- echo "<p>On <strong>{$td}</strong><br/>user <strong>{$row->translated_by}</strong> translated<br/>".
327
- "\"<strong>{$row->original}</strong>\"<br/>to ".
328
- "<strong style=\"color:red\">{$row->lang}</strong><br/>\"<strong>{$row->translated}</strong>\"</p>";
 
329
  }
330
  }
331
  ?>
41
  //Constant used as key in options database
42
  define("TRANSPOSH_DB_VERSION", "transposh_db_version");
43
 
44
+ class transposh_database {
45
+ /** @property transposh_plugin $transposh father class */
46
+ private $transposh;
47
+ //constructor of class, PHP4 compatible construction for backward compatibility
48
+ function transposh_database(&$transposh) {
49
+ $this->transposh = &$transposh;
50
+ }
51
+ /**
52
+ * Fetch translation from db or cache.
53
+ * Returns An array that contains the translated string and it source.
54
+ * Will return NULL if no translation is available.
55
+ * @param string $original
56
+ * @param string $lang
57
+ * @return array list(translation,source)
58
+ */
59
+ function fetch_translation($original, $lang) {
60
+ $translated = NULL;
61
+
62
 
63
+ //The original is saved in db in its escaped form
64
+ $original = $GLOBALS['wpdb']->escape(html_entity_decode($original, ENT_NOQUOTES, 'UTF-8'));
65
 
66
+ if(ENABLE_APC && function_exists('apc_fetch')) {
67
+ $cached = apc_fetch($original .'___'. $lang, $rc);
68
+ if($rc === TRUE) {
69
+
70
+ return $cached;
71
+ }
72
  }
 
73
 
74
+ $table_name = $GLOBALS['wpdb']->prefix . TRANSLATIONS_TABLE;
75
+ $query = "SELECT * FROM $table_name WHERE original = '$original' and lang = '$lang' ";
76
+ $row = $GLOBALS['wpdb']->get_row($query);
77
 
78
+ if($row !== FALSE) {
79
+ $translated_text = stripslashes($row->translated);
80
+ $translated = array($translated_text, $row->source);
81
 
82
+
 
 
 
 
 
 
 
83
  }
84
 
85
+ if(ENABLE_APC && function_exists('apc_store')) {
86
+ //If we don't have translation still we want to have it in cache
87
+ $cache_entry = $translated;
88
+ if($cache_entry == NULL) {
89
+ $cache_entry = "";
90
+ }
91
+
92
+ //update cache
93
+ $rc = apc_store($original .'___'. $lang, $cache_entry, 3600);
94
+ if($rc === TRUE) {
95
+
96
+ }
97
  }
 
98
 
99
+
100
+ return $translated;
101
+ }
102
 
103
  /*
104
  * A new translation has been posted, update the translation database.
105
  * This has changed since we now accept multiple translations at once
106
  */
107
+ function update_translation() {
108
+
109
+ $ref=getenv('HTTP_REFERER');
110
+ $items = $_POST['items'];
111
+ $lang = $_POST['lang'];
112
+ $source = $_POST['source'];
113
+ // check params
 
 
 
114
 
115
+ if(!isset($items) || !isset($lang)) {
116
+
117
+ return;
118
+ }
119
+
120
+ //Check permissions, first the lanugage must be on the edit list. Then either the user
121
+ //is a translator or automatic translation if it is enabled.
122
+ if(!($this->transposh->options->is_editable_language($lang) &&
123
+ ($this->transposh->is_translator() || ($source == 1 && $this->transposh->options->get_enable_auto_translate())))) {
124
+
125
+ header("HTTP/1.0 401 Unauthorized translation");
126
+ exit;
127
+ }
128
+
129
+ //add our own custom header - so we will know that we got here
130
+ header("Transposh: v-".TRANSPOSH_PLUGIN_VER." db_version-". DB_VERSION);
131
 
132
+ // transaction log stuff
133
+ global $user_ID;
134
+ get_currentuserinfo();
135
+
136
+ // log either the user ID or his IP
137
+ if ('' == $user_ID) {
138
+ $loguser = $_SERVER['REMOTE_ADDR'];
139
+ }
140
+ else {
141
+ $loguser = $user_ID;
142
+ }
143
+ // end tl
144
+
145
+ // We are now passing all posted items
146
+ for ($i=0;$i<$items;$i++) {
147
+ $original = base64_url_decode($_POST["tk$i"]);
148
+ $translation = $_POST["tr$i"];
149
+ //Decode & remove already escaped character to avoid double escaping
150
+ $translation = $GLOBALS['wpdb']->escape(htmlspecialchars(stripslashes(urldecode($translation))));
151
+
152
+ //The original content is encoded as base64 before it is sent (i.e. token), after we
153
+ //decode it should just the same after it was parsed.
154
+ $original = $GLOBALS['wpdb']->escape(html_entity_decode($original, ENT_NOQUOTES, 'UTF-8'));
155
+
156
+ //Here we check we are not redoing stuff
157
+ list($translated_text, $old_source) = $this->fetch_translation($original, $lang);
158
+ if ($translated_text) {
159
+ if ($source == 1) {
160
+
161
+ return;
162
+ }
163
+ if ($translation == $GLOBALS['wpdb']->escape(htmlspecialchars(stripslashes(urldecode($translated_text)))) && $old_source == $source) {
164
+
165
+ return;
166
+ }
167
+ }
168
+ // Setting the values string for the database (notice how concatanation is handled)
169
+ $values .= "('" . $original . "','" . $translation . "','" . $lang . "','" . $source . "')".(($items != $i+1) ?', ':'');
170
+ // Setting the transaction log records
171
+ $logvalues .= "('" . $original . "','" . $translation . "','" . $lang . "','".$loguser."','".$source."')".(($items != $i+1) ?', ':'');
172
+
173
+ // If we have caching - we remove previous entry from cache
174
+ if(ENABLE_APC && function_exists('apc_store')) {
175
+ apc_delete($original .'___'. $lang);
176
+ }
177
+ }
178
+
179
+ // perform insertion to the database, with one query :)
180
+ $update = "REPLACE INTO ".$GLOBALS['wpdb']->prefix . TRANSLATIONS_TABLE." (original, translated, lang, source)
181
+ VALUES $values";
182
 
183
+
184
+ $result = $GLOBALS['wpdb']->query($update);
185
+
186
+ if($result !== FALSE) {
187
+ // update the transaction log too
188
+ $log = "INSERT INTO ".$GLOBALS['wpdb']->prefix.TRANSLATIONS_LOG." (original, translated, lang, translated_by, source) ".
189
+ "VALUES $logvalues";
190
+ $result = $GLOBALS['wpdb']->query($log);
191
+
192
+
193
+ }
194
+ else {
195
+
196
+
197
+ header("HTTP/1.0 404 Failed to update language database ".mysql_error());
198
+ }
199
+ // this is a termination for the ajax sequence
200
  exit;
201
  }
202
 
203
+ /**
204
+ * A new translation has been posted, update the translation database.
205
+ * This has changed since we now accept multiple translations at once
206
+ * This function accepts a new more "versatile" format
207
+ * @global <type> $user_ID - TODO
208
+ */
209
+ function update_translation_new() {
210
+
211
+ $ref=getenv('HTTP_REFERER');
212
+ $items = $_POST['items'];
213
+ $lang = $_POST['ln0'];
214
+ $source = $_POST['sr0'];
215
+ // check params
216
+
217
+ if(!isset($items) || !isset($lang)) {
218
+
219
+ return;
220
+ }
221
 
222
+ //Check permissions, first the lanugage must be on the edit list. Then either the user
223
+ //is a translator or automatic translation if it is enabled.
224
+ // we must check that all sent languages are editable
225
+ $all_editable = true;
226
+ for ($i=0;$i<$items;$i++) {
227
+ if (isset($_POST["ln$i"])) {
228
+ if (!$this->transposh->options->is_editable_language($_POST["ln$i"])) {
229
+ $all_editable = false;
230
+ break;
231
+ }
232
+ }
233
+ }
234
 
235
+ if(!($all_editable &&
236
+ ($this->transposh->is_translator() || ($source == 1 && $this->transposh->options->get_enable_auto_translate())))) {
237
+
238
+ header("HTTP/1.0 401 Unauthorized translation");
239
+ exit;
240
+ }
 
 
241
 
242
+ //add our own custom header - so we will know that we got here
243
+ header("Transposh: v-".TRANSPOSH_PLUGIN_VER." db_version-". DB_VERSION);
 
 
 
 
244
 
245
+ // transaction log stuff
246
+ global $user_ID;
247
+ get_currentuserinfo();
248
 
249
+ // log either the user ID or his IP
250
+ if ('' == $user_ID) {
251
+ $loguser = $_SERVER['REMOTE_ADDR'];
252
+ }
253
+ else {
254
+ $loguser = $user_ID;
255
+ }
256
+ // end tl
257
+
258
+ // We are now passing all posted items
259
+ for ($i=0;$i<$items;$i++) {
260
+ if (isset($_POST["tk$i"])) {
261
+ $original = base64_url_decode($_POST["tk$i"]);
262
+ //The original content is encoded as base64 before it is sent (i.e. token), after we
263
+ //decode it should just the same after it was parsed.
264
+ $original = $GLOBALS['wpdb']->escape(html_entity_decode($original, ENT_NOQUOTES, 'UTF-8'));
265
  }
266
+ if (isset($_POST["tr$i"])) {
267
+ $translation = $_POST["tr$i"];
268
+ //Decode & remove already escaped character to avoid double escaping
269
+ $translation = $GLOBALS['wpdb']->escape(htmlspecialchars(stripslashes(urldecode($translation))));
270
+ }
271
+ if (isset($_POST["ln$i"])) {
272
+ $lang = $_POST["ln$i"];
273
+ }
274
+ if (isset($_POST["sr$i"])) {
275
+ $source = $_POST["sr$i"];
276
  }
 
 
 
 
 
277
 
278
+
279
+ //Here we check we are not redoing stuff
280
+ list($translated_text, $old_source) = $this->fetch_translation($original, $lang);
281
+ if ($translated_text) {
282
+ if ($source == 1) {
283
+
284
+ continue;
285
+ //return; // too harsh, we just need to get to the next in for
286
+ }
287
+ if ($translation == $GLOBALS['wpdb']->escape(htmlspecialchars(stripslashes(urldecode($translated_text)))) && $old_source == $source) {
288
+
289
+ continue;
290
+ //return; // too harsh, we just need to get to the next in for
291
+ }
292
+ }
293
+ // Setting the values string for the database (notice how concatanation is handled)
294
+ $values .= "('" . $original . "','" . $translation . "','" . $lang . "','" . $source . "')".(($items != $i+1) ?', ':'');
295
+ // Setting the transaction log records
296
+ $logvalues .= "('" . $original . "','" . $translation . "','" . $lang . "','".$loguser."','".$source."')".(($items != $i+1) ?', ':'');
297
+
298
+ // If we have caching - we remove previous entry from cache
299
+ if(ENABLE_APC && function_exists('apc_store')) {
300
+ apc_delete($original .'___'. $lang);
301
+ }
302
  }
 
303
 
304
+ // perform insertion to the database, with one query :)
305
+ $update = "REPLACE INTO ".$GLOBALS['wpdb']->prefix . TRANSLATIONS_TABLE." (original, translated, lang, source)
306
  VALUES $values";
307
+
308
 
309
+ $result = $GLOBALS['wpdb']->query($update);
310
 
311
+ if($result !== FALSE) {
312
+ // update the transaction log too
313
+ $log = "INSERT INTO ".$GLOBALS['wpdb']->prefix.TRANSLATIONS_LOG." (original, translated, lang, translated_by, source) ".
314
+ "VALUES $logvalues";
315
+ $result = $GLOBALS['wpdb']->query($log);
316
 
317
+
318
+ }
319
+ else {
320
+
321
+
322
+ header("HTTP/1.0 404 Failed to update language database ".mysql_error());
323
+ }
324
+ // this is a termination for the ajax sequence
325
+ exit;
326
  }
 
 
 
327
 
328
  /*
329
  * Get translation history for some translation.
330
  */
331
+ function get_translation_history($token, $lang) {
 
332
 
333
+ $ref=getenv('HTTP_REFERER');
334
+ $original = base64_url_decode($token);
335
+
336
 
337
+ // check params
338
+
339
+ if(!isset($original) || !isset($lang)) {
340
+
341
+ return;
342
+ }
343
 
 
 
 
344
 
345
+ //Check permissions, first the lanugage must be on the edit list. Then either the user
346
+ //is a translator or automatic translation if it is enabled.
347
+ if(!($this->transposh->options->is_editable_language($lang) && $this->transposh->is_translator())) {
348
+
349
+ header("HTTP/1.0 401 Unauthorized history");
350
+ exit;
351
+ }
352
 
353
+
354
+ $table_name = $GLOBALS['wpdb']->prefix . TRANSLATIONS_LOG;
355
+
356
+
357
+ //The original content is encoded as base64 before it is sent (i.e. token), after we
358
+ //decode it should just the same after it was parsed.
359
+ $original = $GLOBALS['wpdb']->escape(html_entity_decode($original, ENT_NOQUOTES, 'UTF-8'));
360
+
361
+ //add our own custom header - so we will know that we got here
362
+ header("Transposh: v-".TRANSPOSH_PLUGIN_VER." db_version-". DB_VERSION);
363
+
364
+ $query = "SELECT translated, translated_by, timestamp, source, user_login ".
365
+ "FROM $table_name ".
366
+ "LEFT JOIN {$GLOBALS['wpdb']->prefix}users ON translated_by = {$GLOBALS['wpdb']->prefix}users.id ".
367
+ "WHERE original='$original' AND lang='$lang' ".
368
+ "ORDER BY timestamp DESC";
369
+
370
+
371
+ $rows = $GLOBALS['wpdb']->get_results($query);
372
+ // trying
373
+
374
+ if($rows !== FALSE) {
375
+ echo '<table>' .
376
+ '<thead>'.
377
+ '<tr>'.
378
+ '<th>Translated</th><th/><th>By</th><th>At</th>'.
379
+ '</tr>'.
380
+ '</thead>'.
381
+ '<tbody>';
382
+ foreach ($rows as $row) {
383
+ if (is_null($row->user_login)) $row->user_login = $row->translated_by;
384
+ echo "<tr><td>{$row->translated}</td><td source=\"{$row->source}\"/><td user_id=\"{$row->translated_by}\">{$row->user_login}</td><td>{$row->timestamp}</td></tr>";
385
+ }
386
+ echo '</tbody></table>';
 
 
387
  }
 
 
388
 
389
+ exit;
390
+ }
391
 
392
  /*
393
  * Setup the translation database.
394
  */
395
+ function setup_db() {
396
+
397
+ require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
 
398
 
399
+ $installed_ver = get_option(TRANSPOSH_DB_VERSION);
400
 
401
+ if( $installed_ver != DB_VERSION ) {
402
+ $table_name = $GLOBALS['wpdb']->prefix . TRANSLATIONS_TABLE;
403
 
404
+
405
+ $sql = "CREATE TABLE $table_name (original VARCHAR(255) NOT NULL,".
406
+ "lang CHAR(5) NOT NULL,".
407
+ "translated VARCHAR(255),".
408
+ "source TINYINT NOT NULL,".
409
+ "PRIMARY KEY (original, lang)) DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci";
410
 
411
+ dbDelta($sql);
412
 
413
+ $table_name = $GLOBALS['wpdb']->prefix . TRANSLATIONS_LOG;
414
 
415
+
416
+ $sql = "CREATE TABLE $table_name (original VARCHAR(255) NOT NULL,".
417
+ "lang CHAR(5) NOT NULL,".
418
+ "translated VARCHAR(255),".
419
+ "translated_by VARCHAR(15),".
420
+ "source TINYINT NOT NULL,".
421
+ "timestamp TIMESTAMP,".
422
+ "PRIMARY KEY (original, lang, timestamp)) DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci";
423
+
424
+ dbDelta($sql);
425
+ update_option(TRANSPOSH_DB_VERSION, DB_VERSION);
426
+ }
427
 
428
 
 
 
 
 
 
 
 
 
 
 
429
  }
430
 
431
+ function db_stats () {
432
+ echo "<h4>Database stats</h4>";
433
+ $table_name = $GLOBALS['wpdb']->prefix . TRANSLATIONS_TABLE;
434
+ $log_table_name = $GLOBALS['wpdb']->prefix . TRANSLATIONS_LOG;
435
+ $query = "SELECT count(*) as count FROM `$table_name`";
436
+ $rows = $GLOBALS['wpdb']->get_results($query);
437
+ foreach ($rows as $row) {
438
+ if ($row->count)
439
+ echo "<p>Total of <strong style=\"color:red\">{$row->count}</strong> translated phrases.</p>";
440
+ }
 
 
 
 
441
 
442
+ $query = "SELECT count(*) as count,lang FROM `$table_name` WHERE source='0' GROUP BY `lang` ORDER BY `count` DESC LIMIT 3";
443
+ $rows = $GLOBALS['wpdb']->get_results($query);
444
+ foreach ($rows as $row) {
445
+ if ($row->count)
446
+ echo "<p><strong>{$row->lang}</strong> has <strong style=\"color:red\">{$row->count}</strong> human translated phrases.</p>";
447
+ }
448
 
449
+ echo "<h4>Recent activity</h4>";
450
+ $query = "SELECT * FROM `$log_table_name` WHERE source='0' ORDER BY `timestamp` DESC LIMIT 3";
451
+ $rows = $GLOBALS['wpdb']->get_results($query);
452
+ foreach ($rows as $row) {
453
+ $td = mysql2date(get_option('date_format').' '.get_option('time_format'), $row->timestamp);
454
+ //the_date();
455
+ echo "<p>On <strong>{$td}</strong><br/>user <strong>{$row->translated_by}</strong> translated<br/>".
456
+ "\"<strong>{$row->original}</strong>\"<br/>to ".
457
+ "<strong style=\"color:red\">{$row->lang}</strong><br/>\"<strong>{$row->translated}</strong>\"</p>";
458
+ }
459
  }
460
  }
461
  ?>
transposh_options.php ADDED
@@ -0,0 +1,331 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* Copyright © 2009 Transposh Team (website : http://transposh.org)
3
+ *
4
+ * This program is free software; you can redistribute it and/or modify
5
+ * it under the terms of the GNU General Public License as published by
6
+ * the Free Software Foundation; either version 2 of the License, or
7
+ * (at your option) any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ * GNU General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+ */
18
+ // OLD Options - To be removed
19
+ //Option defining whether anonymous translation is allowed.
20
+ define("OLD_ANONYMOUS_TRANSLATION", "transposh_allow_anonymous_translation");
21
+ //Option defining the list of currentlly viewable languages
22
+ define("OLD_VIEWABLE_LANGS", "transposh_viewable_languages");
23
+ //Option defining the list of currentlly editable languages
24
+ define("OLD_EDITABLE_LANGS", "transposh_editable_languages");
25
+ //Option to enable/disable auto translation
26
+ define("OLD_ENABLE_AUTO_TRANSLATE", "transposh_enable_autotranslate");
27
+ //Option to enable/disable msn translation
28
+ define("OLD_ENABLE_MSN_TRANSLATE", "transposh_enable_msntranslate");
29
+ //Option to store the msn API key
30
+ define("OLD_MSN_TRANSLATE_KEY", "transposh_msn_key");
31
+ //Option to enable/disable rewrite of permalinks
32
+ define("OLD_ENABLE_PERMALINKS_REWRITE", "transposh_enable_permalinks");
33
+ //Option to enable/disable default language translation
34
+ define("OLD_ENABLE_DEFAULT_TRANSLATE", "transposh_enable_default_translate");
35
+ //Option to enable/disable footer scripts (2.8 and up)
36
+ define("OLD_ENABLE_FOOTER_SCRIPTS", "transposh_enable_footer_scripts");
37
+ //Use CSS sprites for flags if available
38
+ define("OLD_ENABLE_CSS_FLAGS", "transposh_enable_css_flags");
39
+ //Option defining the default language
40
+ define("OLD_DEFAULT_LANG", "transposh_default_language");
41
+ //Option defining transposh widget appearance
42
+ define("OLD_WIDGET_TRANSPOSH", "transposh_widget");
43
+
44
+ //defines are used to avoid typos
45
+ //Option defining whether anonymous translation is allowed.
46
+ define("ANONYMOUS_TRANSLATION", "allow_anonymous_translation");
47
+ //Option defining the list of currentlly viewable languages
48
+ define("VIEWABLE_LANGS", "viewable_languages");
49
+ //Option defining the list of currentlly editable languages
50
+ define("EDITABLE_LANGS", "editable_languages");
51
+ //Option to enable/disable auto translation
52
+ define("ENABLE_AUTO_TRANSLATE", "enable_autotranslate");
53
+ //Option to enable/disable auto translation
54
+ define("ENABLE_AUTO_POST_TRANSLATE", "enable_autoposttranslate");
55
+ //Option to enable/disable msn translation
56
+ define("ENABLE_MSN_TRANSLATE", "enable_msntranslate");
57
+ //Option to store the msn API key
58
+ define("MSN_TRANSLATE_KEY", "msn_key");
59
+ //Option to enable/disable default language translation
60
+ define("ENABLE_DEFAULT_TRANSLATE", "enable_default_translate");
61
+ //Option to enable/disable rewrite of permalinks
62
+ define("ENABLE_PERMALINKS", "enable_permalinks");
63
+ //Option to enable/disable footer scripts (2.8 and up)
64
+ define("ENABLE_FOOTER_SCRIPTS", "enable_footer_scripts");
65
+ //Option to enable/disable footer scripts (2.8 and up)
66
+ define("ALTERNATE_POST", "alternate_post_method");
67
+ //Option defining the default language
68
+ define("DEFAULT_LANG", "default_language");
69
+ //Option defining transposh widget appearance
70
+ define("WIDGET_STYLE", "widget_style");
71
+ //Option allowing progress bar display
72
+ define("WIDGET_PROGRESSBAR", "widget_progressbar");
73
+ //Use CSS sprites for flags if available
74
+ define("WIDGET_CSS_FLAGS", "widget_css_flags");
75
+
76
+
77
+ class transposh_plugin_options {
78
+ //constructor of class, PHP4 compatible construction for backward compatibility
79
+ /** @var array storing all our options */
80
+ private $options = array();
81
+ /** @var boolean set to true if any option was changed */
82
+ private $changed = false;
83
+
84
+ function transposh_plugin_options() {
85
+
86
+ // load them here
87
+ $this->options = get_option(TRANSPOSH_OPTIONS);
88
+ $this->migrate_old_config();
89
+
90
+ }
91
+
92
+ private function old2new($key) {
93
+ // the substr removes the redundant transposh_ prefix
94
+ $this->options[substr($key,10)] = get_option($key);
95
+ delete_option($key);
96
+ }
97
+ // TODO: remove this function in a few versions (fix css, db version..., css flag
98
+ private function migrate_old_config() {
99
+
100
+ if (get_option(OLD_ENABLE_AUTO_TRANSLATE,666) != 666 || get_option(OLD_WIDGET_TRANSPOSH,666) != 666) {
101
+
102
+ $this->old2new(OLD_ANONYMOUS_TRANSLATION);
103
+ $this->old2new(OLD_VIEWABLE_LANGS);
104
+ $this->old2new(OLD_EDITABLE_LANGS);
105
+ $this->old2new(OLD_ENABLE_AUTO_TRANSLATE);
106
+ $this->old2new(OLD_ENABLE_MSN_TRANSLATE);
107
+ $this->old2new(OLD_MSN_TRANSLATE_KEY);
108
+ $this->old2new(OLD_ENABLE_PERMALINKS_REWRITE);
109
+ $this->old2new(OLD_ENABLE_DEFAULT_TRANSLATE);
110
+ $this->old2new(OLD_ENABLE_FOOTER_SCRIPTS);
111
+ $this->old2new(OLD_ENABLE_CSS_FLAGS);
112
+ $this->old2new(OLD_DEFAULT_LANG);
113
+ $this->old2new(OLD_WIDGET_TRANSPOSH);
114
+
115
+ update_option(TRANSPOSH_OPTIONS, $this->options);
116
+ }
117
+ //some options were moved
118
+
119
+ if (isset($this->options['widget'])) {
120
+
121
+ $this->set_widget_style($this->options['widget']['style']);
122
+ $this->set_widget_progressbar($this->options['widget']['progressbar']);
123
+ unset($this->options['widget']);
124
+
125
+ }
126
+ if (is_array($this->options) && array_key_exists('enable_css_flags',$this->options)) {
127
+ $this->set_widget_css_flags($this->options['enable_css_flags']);
128
+ unset($this->options['enable_css_flags']);
129
+
130
+ }
131
+ }
132
+
133
+ function get_anonymous_translation() {
134
+ return $this->options[ANONYMOUS_TRANSLATION];
135
+ }
136
+
137
+ function get_viewable_langs() {
138
+ return $this->options[VIEWABLE_LANGS];
139
+ }
140
+
141
+ function get_editable_langs() {
142
+ return $this->options[EDITABLE_LANGS];
143
+ }
144
+
145
+ function get_widget_progressbar() {
146
+ return $this->options[WIDGET_PROGRESSBAR];
147
+ }
148
+
149
+ function get_widget_style() {
150
+ return $this->options[WIDGET_STYLE];
151
+ }
152
+
153
+ function get_widget_css_flags() {
154
+ return $this->options[WIDGET_CSS_FLAGS];
155
+ }
156
+
157
+ function get_enable_permalinks() {
158
+ return $this->options[ENABLE_PERMALINKS];
159
+ }
160
+
161
+ function get_enable_footer_scripts() {
162
+ return $this->options[ENABLE_FOOTER_SCRIPTS];
163
+ }
164
+
165
+ function get_alternate_post() {
166
+ return $this->options[ALTERNATE_POST];
167
+ }
168
+
169
+ function get_enable_msn_translate() {
170
+ return $this->options[ENABLE_MSN_TRANSLATE]; // FIX
171
+ }
172
+
173
+ function get_enable_default_translate() {
174
+ return $this->options[ENABLE_DEFAULT_TRANSLATE];
175
+ }
176
+
177
+ function get_enable_auto_translate() {
178
+ if (!isset($this->options[ENABLE_AUTO_TRANSLATE])) return 1; // default is true
179
+ return $this->options[ENABLE_AUTO_TRANSLATE];
180
+ }
181
+
182
+ function get_enable_auto_post_translate() {
183
+ return $this->options[ENABLE_AUTO_POST_TRANSLATE];
184
+ }
185
+
186
+ function get_msn_key() {
187
+ return $this->options[MSN_TRANSLATE_KEY];
188
+ }
189
+
190
+ /**
191
+ * Gets the default language setting, i.e. the source language which
192
+ * should not be translated.
193
+ * @return string Default language
194
+ */
195
+ function get_default_language() {
196
+ $default = $this->options[DEFAULT_LANG];
197
+ if(!$GLOBALS['languages'][$default]) {
198
+ $default = "en";
199
+ }
200
+ return $default;
201
+ }
202
+
203
+ /**
204
+ * Sets a value at the options array
205
+ * @param mixed $val
206
+ * @param pointer $option Points to the option in the options array
207
+ */
208
+ private function set_value($val, &$option) {
209
+ if ($val != $option) {
210
+ $option = $val;
211
+ $this->changed = true;
212
+ }
213
+ }
214
+
215
+ function set_anonymous_translation($val) {
216
+ $val = ($val) ? 1 : 0;
217
+ $this->set_value($val, $this->options[ANONYMOUS_TRANSLATION]);
218
+ }
219
+
220
+ function set_viewable_langs($val) {
221
+ $this->set_value($val, $this->options[VIEWABLE_LANGS]);
222
+ }
223
+
224
+ function set_editable_langs($val) {
225
+ $this->set_value($val, $this->options[EDITABLE_LANGS]);
226
+ }
227
+
228
+ function set_widget_progressbar($val) {
229
+ $val = ($val) ? 1 : 0;
230
+ $this->set_value($val, $this->options[WIDGET_PROGRESSBAR]);
231
+ }
232
+
233
+ function set_widget_style($val) {
234
+ $this->set_value($val, $this->options[WIDGET_STYLE]);
235
+ }
236
+
237
+ function set_widget_css_flags($val) { // FIX!
238
+ $val = ($val) ? 1 : 0;
239
+ $this->set_value($val, $this->options[WIDGET_CSS_FLAGS]);
240
+ }
241
+
242
+ function set_enable_permalinks($val) {
243
+ $val = ($val) ? 1 : 0;
244
+ $this->set_value($val, $this->options[ENABLE_PERMALINKS]);
245
+ }
246
+
247
+ function set_alternate_post($val) {
248
+ $this->set_value($val,$this->options[ALTERNATE_POST]);
249
+ }
250
+
251
+ function set_enable_footer_scripts($val) {
252
+ $val = ($val) ? 1 : 0;
253
+ $this->set_value($val, $this->options[ENABLE_FOOTER_SCRIPTS]);
254
+ }
255
+
256
+ function set_enable_msn_translate($val) {
257
+ $val = ($val) ? 1 : 0;
258
+ $this->set_value($val, $this->options[ENABLE_MSN_TRANSLATE]); // FIX
259
+ }
260
+
261
+ function set_enable_default_translate($val) {
262
+ $val = ($val) ? 1 : 0;
263
+ $this->set_value($val, $this->options[ENABLE_DEFAULT_TRANSLATE]);
264
+ }
265
+
266
+ function set_enable_auto_translate($val) {
267
+ $val = ($val) ? 1 : 0;
268
+ $this->set_value($val, $this->options[ENABLE_AUTO_TRANSLATE]);
269
+ }
270
+
271
+ function set_enable_auto_post_translate($val) {
272
+ $val = ($val) ? 1 : 0;
273
+ $this->set_value($val, $this->options[ENABLE_AUTO_POST_TRANSLATE]);
274
+ }
275
+
276
+ function set_msn_key($val) {
277
+ $this->set_value($val, $this->options[MSN_TRANSLATE_KEY]);
278
+ }
279
+
280
+ /**
281
+ * Sets the default language setting, i.e. the source language which
282
+ * should not be translated.
283
+ * @param string $val Language set as default
284
+ */
285
+ function set_default_language($val) {
286
+ if(!$GLOBALS['languages'][$val]) {
287
+ $val = "en";
288
+ }
289
+ $this->set_value($val, $this->options[DEFAULT_LANG]);
290
+ }
291
+
292
+ /**
293
+ * Updates options at the wordpress options table if there was a change
294
+ */
295
+ function update_options() {
296
+ if ($this->changed) {
297
+ update_option(TRANSPOSH_OPTIONS, $this->options);
298
+ }
299
+ else {
300
+
301
+ }
302
+ $this->changed = false;
303
+ }
304
+
305
+ /**
306
+ * Determine if the given language code is the default language
307
+ * @param string $language
308
+ * @return boolean Is this the default language?
309
+ */
310
+ function is_default_language($language) {
311
+ return ($this->get_default_language() == $language);
312
+ }
313
+
314
+ /**
315
+ * Determine if the given language in on the list of editable languages
316
+ * @return boolean Is this language editable?
317
+ */
318
+ function is_editable_language($language) {
319
+ return (strpos($this->get_editable_langs(), $language) !== false);
320
+ }
321
+
322
+ /**
323
+ * Determine if the given language in on the list of viewable languages
324
+ * @return boolean Is this language viewable?
325
+ */
326
+ function is_viewable_language($language) {
327
+ return (strpos($this->get_viewable_langs(), $language) !== false);
328
+ }
329
+
330
+ }
331
+ ?>
transposh_postpublish.php ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* Copyright © 2009 Transposh Team (website : http://transposh.org)
3
+ *
4
+ * This program is free software; you can redistribute it and/or modify
5
+ * it under the terms of the GNU General Public License as published by
6
+ * the Free Software Foundation; either version 2 of the License, or
7
+ * (at your option) any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ * GNU General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+ *
18
+ */
19
+
20
+ /*
21
+ * Provides the side widget in the page/edit pages which will do translations
22
+ */
23
+
24
+
25
+ require_once("core/jsonwrapper/jsonwrapper.php");
26
+
27
+ /**
28
+ * class that makes changed to the edit page and post page, adding our change to the side ba
29
+ */
30
+ class transposh_postpublish {
31
+ /** @var transposh_plugin Container class */
32
+ private $transposh;
33
+ /** @var boolean Did we just edited/saved? */
34
+ private $just_published = false;
35
+ /**
36
+ *
37
+ * Construct our class
38
+ * @param transposh_plugin $transposh
39
+ */
40
+ function transposh_postpublish(&$transposh) {
41
+ $this->transposh = &$transposh;
42
+ // we'll only do something if so configured to do
43
+ if ($this->transposh->options->get_enable_auto_post_translate()) {
44
+ add_action('edit_post',array(&$this, 'on_edit'));
45
+ // add_action('publish_post',array(&$this, 'on_publish'));
46
+ add_action('admin_menu', array(&$this, 'on_admin_menu'));
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Admin menu created action, where we create our metaboxes
52
+ */
53
+ function on_admin_menu() {
54
+ //add our metabox to the post and pubish pages
55
+
56
+ add_meta_box( 'transposh_postpublish','Transposh', array(&$this, "transposh_postpublish_box"), 'post', 'side', 'core');
57
+ add_meta_box( 'transposh_postpublish','Transposh', array(&$this, "transposh_postpublish_box"), 'page', 'side', 'core');
58
+ if ($_GET['justedited']) {
59
+ wp_enqueue_script("google","http://www.google.com/jsapi",array(),'1',true);
60
+ wp_enqueue_script("transposh","{$this->transposh->transposh_plugin_url}/js/transposhadmin.js?post_url={$this->transposh->post_url}&post={$_GET['post']}",array("jquery"),TRANSPOSH_PLUGIN_VER,true);
61
+ wp_enqueue_style("jquery","http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/ui-lightness/jquery-ui.css",array(),'1.0');
62
+ wp_enqueue_script("jqueryui","http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js",array("jquery"),'1.7.2',true);
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Loop through all the post phrases and return them in json formatted script
68
+ * @param int $postID
69
+ */
70
+ function get_post_phrases($postID) {
71
+ // Some security, to avoid others from seeing private posts
72
+ if (!current_user_can('edit_post',$postID))
73
+ return;
74
+ $post = get_post($postID);
75
+ // Display filters
76
+ $title = apply_filters('the_title', $post->post_title);
77
+ $content = apply_filters('the_content', $post->post_content);
78
+ // TODO - grab phrases from rss excerpt
79
+ //$output = get_the_excerpt();
80
+ // echo apply_filters('the_excerpt_rss', $output);
81
+
82
+ $parser = new parser();
83
+ $phrases = $parser->get_phrases_list($content);
84
+ $phrases2 = $parser->get_phrases_list($title);
85
+
86
+ // Merge the two arrays for traversing
87
+ $phrases = array_merge($phrases, $phrases2);
88
+
89
+ foreach ($phrases as $key) {
90
+ foreach (explode(',',$this->transposh->options->get_editable_langs()) as $lang) {
91
+ // if this isn't the default language or we specifically allow default language translation, we will seek this out...
92
+ // as we don't normally want to auto-translate the default language
93
+ if (!$this->transposh->options->is_default_language($lang) || $this->transposh->options->get_enable_default_translate()) {
94
+ list($translation,$source) = $this->transposh->database->fetch_translation($key, $lang);
95
+ if (!$translation) {
96
+ // p stands for phrases, l stands for languages, t is token
97
+ if (!is_array($json['p'][$key]['l'])) {
98
+ $json['p'][$key]['l'] = array();
99
+ }
100
+ array_push($json['p'][$key]['l'],$lang);
101
+ }
102
+ }
103
+ }
104
+ // only if a languages list was created we'll need to translate this
105
+ if (is_array($json['p'][$key]['l'])) {
106
+ $json['p'][$key]['t'] = base64_url_encode($key);
107
+ $json['length']++;
108
+ }
109
+ }
110
+
111
+ // the header helps with debugging
112
+ header("Content-type: text/javascript");
113
+ echo json_encode($json);
114
+ }
115
+
116
+ /**
117
+ * This is the box that appears on the side
118
+ */
119
+ function transposh_postpublish_box() {
120
+ // the nonce will help double translation if time has passed
121
+ if ($_GET['justedited'] && wp_verify_nonce($_GET['justedited'])) $this->just_published = true;
122
+
123
+ if ($this->just_published) {
124
+ echo '<div id="tr_loading">Publication happened - loading phrases list...</div>';
125
+ }
126
+ else {
127
+ echo 'Waiting for publication';
128
+ }
129
+ }
130
+
131
+ /**
132
+ * When this happens, the boxes are not created and a redirect happens, we currently use this to inform the next stage we are involved
133
+ * @param int $postID
134
+ */
135
+ function on_edit($postID) {
136
+ add_filter('wp_redirect',array(&$this, 'inform_published'));
137
+ }
138
+
139
+ /**
140
+ * We add the justedited param here
141
+ * @param string $url Original URL
142
+ * @return string redirected URL
143
+ */
144
+ function inform_published($url) {
145
+ return add_query_arg('justedited',wp_create_nonce(),$url);
146
+ }
147
+ }
148
+ ?>
transposh_widget.php CHANGED
@@ -25,209 +25,236 @@ require_once("core/constants.php");
25
  require_once("core/utils.php");
26
  require_once("transposh.php");
27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  /*
29
  * Intercept init calls to see if it was posted by the widget.
30
- *
31
  */
32
- function init_transposh() {
33
- if (isset ($_POST['transposh_widget_posted'])) {
34
-
35
- init_global_vars();
36
-
37
- $ref=getenv('HTTP_REFERER');
38
- $lang = $_POST[LANG_PARAM];
39
-
40
 
41
- //remove existing language settings.
42
- $ref = cleanup_url($ref);
43
-
44
 
45
- if($lang != "none") {
46
- $ref = rewrite_url_lang_param($ref, $lang, $_POST[EDIT_PARAM]);
47
 
48
 
49
- //ref is generated with html entities encoded, needs to be
50
- //decoded when used in the http header (i.e. 302 redirect)
51
- //$ref = html_entity_decode($ref, ENT_NOQUOTES);
52
- }
53
 
54
-
 
 
 
 
 
55
 
56
- wp_redirect($ref);
57
- exit;
 
58
  }
59
- }
60
 
61
  /*
62
  * Register the widget.
63
  */
64
- function transposh_widget_init() {
65
-
66
- if (!function_exists('register_sidebar_widget')) {
67
- return;
68
- }
69
 
70
- // Register widget
71
- register_sidebar_widget(array('Transposh', 'widgets'), 'transposh_widget');
72
 
73
- // Register widget control
74
- register_widget_control("Transposh",'transposh_widget_control');
75
 
76
- //regigster callback for widget's css
77
- add_action('wp_print_styles', 'add_transposh_widget_css');
78
- }
79
 
80
  /*
81
  * Add custom css, i.e. transposh.css
82
  */
83
- function add_transposh_widget_css() {
84
  //include the transposh_widget.css
85
  // TODO: user generated version
86
- $options = get_option(WIDGET_TRANSPOSH);
87
- if ($options['style'] == 1 || $options['style'] == 2) {
88
- wp_enqueue_style("transposh_widget","{$GLOBALS['tr_plugin_url']}/css/transposh_widget.css",array(),'0.3.4');
89
- if (get_option(ENABLE_CSS_FLAGS)) {
90
- wp_enqueue_style("transposh_flags", "{$GLOBALS['tr_plugin_url']}/css/transposh_flags.css",array(),'0.3.4');
91
- if (file_exists("{$GLOBALS['tr_plugin_url']}/css/transposh_flags_u.css"))
92
- wp_enqueue_style("transposh_flags", "{$GLOBALS['tr_plugin_url']}/css/transposh_flags_u.css",array(),'0.3.4');
93
  }
 
94
  }
95
-
96
- }
97
 
98
- /*
99
- * The actual widget implementation.
100
- */
101
- function transposh_widget($args) {
102
-
103
- global $languages, $wp_query, $tr_plugin_url;
104
- extract($args);
105
-
106
- $page_url = $_SERVER["REQUEST_URI"];
107
-
108
-
109
- $options = get_option(WIDGET_TRANSPOSH);
110
- $viewable_langs = get_option(VIEWABLE_LANGS);
111
- $editable_langs = get_option(EDITABLE_LANGS);
112
- $is_translator = is_translator();
113
-
114
- $is_showing_languages = FALSE;
115
- //TODO: improve this shortening
116
- $plugpath = parse_url($tr_plugin_url, PHP_URL_PATH);
117
-
118
- echo $before_widget . $before_title . __("Translation") . $after_title;
119
-
120
- //remove any language identifier
121
- $clean_page_url = cleanup_url($page_url, true);
122
-
123
-
124
- switch ($options['style']) {
125
- case 1: // flags
126
- case 2: // language list
127
- //keep the flags in the same direction regardless of the overall page direction
128
- echo "<div class=\"" . NO_TRANSLATE_CLASS . " transposh_flags\" >";
129
-
130
- foreach($languages as $code => $lang2) {
131
- list($language,$flag) = explode (",",$lang2);
132
-
133
- //Only show languages which are viewable or (editable and the user is a translator)
134
- if(strpos($viewable_langs, $code) !== FALSE || is_editable_lang($code) || (get_option(DEFAULT_LANG) == $code)) {
135
-
136
- $page_url = rewrite_url_lang_param($clean_page_url, $code, $GLOBALS['is_edit_mode']);
137
- if (get_option(DEFAULT_LANG) == $code) {
138
- $page_url = $clean_page_url;
139
- }
140
 
141
-
142
- echo "<a href=\"" . $page_url . '"'.(($GLOBALS['lang'] == $code) ? ' class="tr_active"' :'').'>'.
143
- display_flag("$plugpath/img/flags", $flag, $language,get_option(ENABLE_CSS_FLAGS)).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  "</a>";
145
- if ($options['style'] != 1) {
146
  echo "$language<br/>";
 
 
147
  }
148
- $is_showing_languages = TRUE;
149
  }
150
- }
151
- echo "</div>";
152
-
153
- // this is the form for the edit...
154
- echo "<form action=\"$clean_page_url\" method=\"post\">";
155
- echo "<input type=\"hidden\" name=\"lang\" id=\"lang\" value=\"{$GLOBALS['lang']}\"/>";
156
- break;
157
- default: // language selection
158
-
159
- echo "<form action=\"$clean_page_url\" method=\"post\">";
160
- echo "<span class=\"" .NO_TRANSLATE_CLASS . "\" >";
161
- echo "<select name=\"lang\" id=\"lang\" onchange=\"Javascript:this.form.submit();\">";
162
- echo "<option value=\"none\">[Language]</option>";
163
-
164
- foreach($languages as $code => $lang2) {
165
- list($language,$flag) = explode (",",$lang2);
166
-
167
- //Only show languages which are viewable or (editable and the user is a translator)
168
- if(strpos($viewable_langs, $code) !== FALSE || is_editable_lang($code) || (get_option(DEFAULT_LANG) == $code)) {
169
- $is_selected = ($GLOBALS['lang'] == $code ? "selected=\"selected\"" : "" );
170
- echo "<option value=\"$code\" $is_selected>" . $language . "</option>";
171
- $is_showing_languages = TRUE;
172
  }
 
 
 
 
 
 
 
 
 
 
 
173
  }
174
- echo "</select><br/>";
175
- echo "</span>"; // the no_translate for the language list
176
- }
177
 
178
- //at least one language showing - add the edit box if applicable
179
- if($is_showing_languages) {
180
- //Add the edit checkbox only for translators on languages marked as editable
181
- if(is_editing_permitted()) {
182
- echo "<input type=\"checkbox\" name=\"" . EDIT_PARAM . "\" value=\"1\" " .
183
- ($GLOBALS['is_edit_mode'] ? "checked=\"checked\"" : "") .
184
- " onclick=\"this.form.submit();\"/>&nbsp;Edit Translation";
185
  }
186
 
187
- echo "<input type=\"hidden\" name=\"transposh_widget_posted\" value=\"1\"/>";
188
- }
189
- else {
190
- //no languages configured - error message
191
- echo '<p>No languages available for display. Check the Transposh settings (Admin).</p>';
192
  }
193
 
194
- echo "</form>";
195
- //echo "<button onClick=\"do_auto_translate();\">translate all</button>";
196
- echo "<div id=\"".SPAN_PREFIX."credit\">by <a href=\"http://transposh.org\"><img class=\"".NO_TRANSLATE_CLASS."\" height=\"16\" width=\"16\" src=\"$plugpath/img/tplogo.png\" style=\"padding:1px;border:0px\" title=\"Transposh\" alt=\"Transposh\"/></a></div>";
197
- echo $after_widget;
198
- }
199
-
200
- function transposh_widget_post() {
201
- $options = $newoptions = get_option(WIDGET_TRANSPOSH);
202
- $newoptions['style'] = $_POST['transposh-style'];
203
- $newoptions['progressbar'] = ($_POST['transposh-progress']) ? 1 : 0;
204
-
205
- if ($options != $newoptions) update_option(WIDGET_TRANSPOSH, $newoptions);
206
-
207
- }
208
 
209
  /*
210
  * This is the widget control, allowing the selection of presentation type.
211
  */
212
- function transposh_widget_control() {
213
- if (isset($_POST['transposh-submit'])) transposh_widget_post();
214
- $options = get_option(WIDGET_TRANSPOSH);
215
-
216
- echo '<p><label for="transposh-style">Style:<br />'.
217
- '<select id="transposh-style" name="transposh-style">'.
218
- '<option value="0"' . ($options['style'] == 0 ? ' selected="selected"' : '').'>Language selection</option>'.
219
- '<option value="1"' . ($options['style'] == 1 ? ' selected="selected"' : '').'>Flags</option>'.
220
- '<option value="2"' . ($options['style'] == 2 ? ' selected="selected"' : '').'>Language list</option>'.
221
- '</select>'.
222
- '</label></p>'.
223
- '<p><label for="transposh-progress">Effects:<br/>'.
224
- '<input type="checkbox" id="transposh-progress" name="transposh-progress"'.($options['progressbar'] ? ' checked="checked"' : '').'/>'.
225
- '&nbsp;Show progress bar</label></p>'.
226
- '<input type="hidden" name="transposh-submit" id="transposh-submit" value="1"/>';
 
 
 
 
227
  }
228
 
229
- //Register callback for WordPress events
230
- add_action('init', 'init_transposh',0);
231
- add_action('widgets_init', 'transposh_widget_init');
232
-
 
 
 
233
  ?>
25
  require_once("core/utils.php");
26
  require_once("transposh.php");
27
 
28
+
29
+ //class that reperesent the complete plugin
30
+ class transposh_plugin_widget {
31
+ /** @property transposh_plugin $transposh father class */
32
+ private $transposh;
33
+
34
+ //constructor of class, PHP4 compatible construction for backward compatibility
35
+ function transposh_plugin_widget(&$transposh) {
36
+ //Register callback for WordPress events
37
+ $this->transposh = &$transposh;
38
+ add_action('init', array(&$this,'init_transposh'),1);
39
+ add_action('widgets_init', array(&$this,'transposh_widget_init'));
40
+ }
41
+
42
  /*
43
  * Intercept init calls to see if it was posted by the widget.
 
44
  */
45
+ function init_transposh() {
46
+ if (isset ($_POST['transposh_widget_posted'])) {
47
+
48
+ // FIX! yes, this is needed (not with peiorty!
49
+ //transposh_plugin::init_global_vars();
50
+ //$this->transposh->init_global_vars();
 
 
51
 
52
+ $ref=getenv('HTTP_REFERER');
53
+ $lang = $_POST[LANG_PARAM];
54
+
55
 
56
+ //remove existing language settings.
57
+ $ref = cleanup_url($ref,$this->transposh->home_url);
58
 
59
 
60
+ if($lang != "none") {
61
+ $ref = rewrite_url_lang_param($ref,$this->transposh->home_url,$this->transposh->enable_permalinks_rewrite, $lang, $_POST[EDIT_PARAM]);
62
+
 
63
 
64
+ //ref is generated with html entities encoded, needs to be
65
+ //decoded when used in the http header (i.e. 302 redirect)
66
+ //$ref = html_entity_decode($ref, ENT_NOQUOTES);
67
+ }
68
+
69
+
70
 
71
+ wp_redirect($ref);
72
+ exit;
73
+ }
74
  }
 
75
 
76
  /*
77
  * Register the widget.
78
  */
79
+ function transposh_widget_init() {
80
+
81
+ if (!function_exists('register_sidebar_widget')) {
82
+ return;
83
+ }
84
 
85
+ // Register widget
86
+ register_sidebar_widget(array('Transposh', 'widgets'), array(&$this,'transposh_widget'));
87
 
88
+ // Register widget control
89
+ register_widget_control("Transposh", array(&$this,'transposh_widget_control'));
90
 
91
+ //regigster callback for widget's css
92
+ add_action('wp_print_styles', array(&$this,'add_transposh_widget_css'));
93
+ }
94
 
95
  /*
96
  * Add custom css, i.e. transposh.css
97
  */
98
+ function add_transposh_widget_css() {
99
  //include the transposh_widget.css
100
  // TODO: user generated version
101
+ if ($this->transposh->options->get_widget_style() == 1 || $this->transposh->options->get_widget_style() == 2) {
102
+ wp_enqueue_style("transposh_widget","{$this->transposh->transposh_plugin_url}/css/transposh_widget.css",array(),TRANSPOSH_PLUGIN_VER);
103
+ if ($this->transposh->options->get_widget_css_flags()) {
104
+ wp_enqueue_style("transposh_flags", "{$this->transposh->transposh_plugin_url}/css/transposh_flags.css",array(),TRANSPOSH_PLUGIN_VER);
105
+ if (file_exists("{$this->transposh->transposh_plugin_url}/css/transposh_flags_u.css"))
106
+ wp_enqueue_style("transposh_flags", "{$this->transposh->transposh_plugin_url}/css/transposh_flags_u.css",array(),TRANSPOSH_PLUGIN_VER);
107
+ }
108
  }
109
+
110
  }
 
 
111
 
112
+ /**
113
+ * Creates the widget html
114
+ * @param array $args Contains such as $before_widget, $after_widget, $before_title, $after_title, etc
115
+ */
116
+ function transposh_widget($args) {
117
+
118
+ extract($args);
119
+
120
+
121
+ $page_url = $_SERVER["REQUEST_URI"];
122
+
123
+
124
+ //$options = get_option(WIDGET_TRANSPOSH);
125
+ $viewable_langs = $this->transposh->options->get_viewable_langs();
126
+ $editable_langs = $this->transposh->options->get_editable_langs();
127
+
128
+
129
+ $is_translator = $this->transposh->is_translator();
130
+
131
+ $is_showing_languages = FALSE;
132
+ //TODO: improve this shortening
133
+ $plugpath = parse_url($this->transposh->transposh_plugin_url, PHP_URL_PATH);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
 
135
+ echo $before_widget . $before_title . __("Translation") . $after_title;
136
+
137
+ //remove any language identifier
138
+ $clean_page_url = cleanup_url($page_url,$this->transposh->home_url, true);
139
+
140
+
141
+ switch ($this->transposh->options->get_widget_style()) {
142
+ case 1: // flags
143
+ case 2: // language list
144
+ //keep the flags in the same direction regardless of the overall page direction
145
+ echo "<div class=\"" . NO_TRANSLATE_CLASS . " transposh_flags\" >";
146
+
147
+ foreach($GLOBALS['languages'] as $code => $lang2) {
148
+ list($language,$flag) = explode (",",$lang2);
149
+
150
+ //Only show languages which are viewable or (editable and the user is a translator)
151
+ if(strpos($viewable_langs, $code) !== FALSE || $this->transposh->options->is_editable_language($code) || ($this->transposh->options->get_default_language() == $code)) {
152
+
153
+ $page_url = rewrite_url_lang_param($clean_page_url,$this->transposh->home_url,$this->transposh->enable_permalinks_rewrite, $code, $this->transposh->edit_mode);
154
+ if ($this->transposh->options->get_default_language() == $code) {
155
+ $page_url = $clean_page_url;
156
+ }
157
+
158
+
159
+ echo "<a href=\"" . $page_url . '"'.(($this->transposh->target_language == $code) ? ' class="tr_active"' :'').'>'.
160
+ display_flag("$plugpath/img/flags", $flag, $language,$this->transposh->options->get_widget_css_flags()).
161
  "</a>";
162
+ if ($this->transposh->options->get_widget_style() != 1) {
163
  echo "$language<br/>";
164
+ }
165
+ $is_showing_languages = TRUE;
166
  }
 
167
  }
168
+ echo "</div>";
169
+
170
+ // this is the form for the edit...
171
+ echo "<form action=\"$clean_page_url\" method=\"post\">";
172
+ echo "<input type=\"hidden\" name=\"lang\" id=\"lang\" value=\"{$this->transposh->target_language}\"/>";
173
+ break;
174
+ default: // language selection
175
+
176
+ echo "<form action=\"$clean_page_url\" method=\"post\">";
177
+ echo "<span class=\"" .NO_TRANSLATE_CLASS . "\" >";
178
+ echo "<select name=\"lang\" id=\"lang\" onchange=\"Javascript:this.form.submit();\">";
179
+ echo "<option value=\"none\">[Language]</option>";
180
+
181
+ foreach($GLOBALS['languages'] as $code => $lang2) {
182
+ list($language,$flag) = explode (",",$lang2);
183
+
184
+ //Only show languages which are viewable or (editable and the user is a translator)
185
+ if(strpos($viewable_langs, $code) !== FALSE || $this->transposh->options->is_editable_language($code) || ($this->transposh->options->get_default_language() == $code)) {
186
+ $is_selected = ($this->transposh->target_language == $code ? "selected=\"selected\"" : "" );
187
+ echo "<option value=\"$code\" $is_selected>" . $language . "</option>";
188
+ $is_showing_languages = TRUE;
189
+ }
190
  }
191
+ echo "</select><br/>";
192
+ echo "</span>"; // the no_translate for the language list
193
+ }
194
+
195
+ //at least one language showing - add the edit box if applicable
196
+ if($is_showing_languages) {
197
+ //Add the edit checkbox only for translators on languages marked as editable
198
+ if($this->transposh->is_editing_permitted()) {
199
+ echo "<input type=\"checkbox\" name=\"" . EDIT_PARAM . "\" value=\"1\" " .
200
+ ($this->transposh->edit_mode ? "checked=\"checked\"" : "") .
201
+ " onclick=\"this.form.submit();\"/>&nbsp;Edit Translation";
202
  }
 
 
 
203
 
204
+ echo "<input type=\"hidden\" name=\"transposh_widget_posted\" value=\"1\"/>";
205
+ }
206
+ else {
207
+ //no languages configured - error message
208
+ echo '<p>No languages available for display. Check the Transposh settings (Admin).</p>';
 
 
209
  }
210
 
211
+ echo "</form>";
212
+ //echo "<button onClick=\"do_auto_translate();\">translate all</button>";
213
+ echo "<div id=\"".SPAN_PREFIX."credit\">by <a href=\"http://transposh.org\"><img class=\"".NO_TRANSLATE_CLASS."\" height=\"16\" width=\"16\" src=\"$plugpath/img/tplogo.png\" style=\"padding:1px;border:0px\" title=\"Transposh\" alt=\"Transposh\"/></a></div>";
214
+ echo $after_widget;
 
215
  }
216
 
217
+ function transposh_widget_post($save = true) {
218
+
219
+
220
+ $this->transposh->options->set_widget_style($_POST[WIDGET_STYLE]);
221
+ $this->transposh->options->set_widget_progressbar($_POST[WIDGET_PROGRESSBAR]);
222
+ $this->transposh->options->set_widget_css_flags($_POST[WIDGET_CSS_FLAGS]);
223
+ if ($save)
224
+ $this->transposh->options->update_options();
225
+ // Avoid coming here twice...
226
+ unset($_POST['transposh-submit']);
227
+ }
 
 
 
228
 
229
  /*
230
  * This is the widget control, allowing the selection of presentation type.
231
  */
232
+ function transposh_widget_control() {
233
+ if (isset($_POST['transposh-submit'])) $this->transposh_widget_post();
234
+ //$options = get_option(WIDGET_TRANSPOSH);
235
+
236
+ echo '<p><label for="'.WIDGET_STYLE.'">Style:<br />'.
237
+ '<select id="transposh-style" name="'.WIDGET_STYLE.'">'.
238
+ '<option value="0"' . ($this->transposh->options->get_widget_style() == 0 ? ' selected="selected"' : '').'>Language selection</option>'.
239
+ '<option value="1"' . ($this->transposh->options->get_widget_style() == 1 ? ' selected="selected"' : '').'>Flags</option>'.
240
+ '<option value="2"' . ($this->transposh->options->get_widget_style() == 2 ? ' selected="selected"' : '').'>Language list</option>'.
241
+ '</select>'.
242
+ '</label></p>'.
243
+ '<p><label for="transposh-progress">Effects:</label><br/>'.
244
+ '<input type="checkbox" id="'.WIDGET_PROGRESSBAR.'" name="'.WIDGET_PROGRESSBAR.'"'.($this->transposh->options->get_widget_progressbar() ? ' checked="checked"' : '').'/>'.
245
+ '<span style="border-bottom: 1px dotted #333; cursor: help; margin-left: 4px" title="Show progress bar when a client triggers automatic translation">Show progress bar</span><br/>'.
246
+ '<input type="checkbox" id="'.WIDGET_CSS_FLAGS.'" name="'.WIDGET_CSS_FLAGS.'"'.($this->transposh->options->get_widget_css_flags() ? ' checked="checked"' : '').'/>'.
247
+ '<span style="border-bottom: 1px dotted #333; cursor: help; margin-left: 4px" title="Use a single sprite with all flags, makes pages load faster. Currently not suitable if you made changes to the flags.">Use CSS flags</span>'.
248
+ '</p>'.
249
+ '<input type="hidden" name="transposh-submit" id="transposh-submit" value="1"/>';
250
+ }
251
  }
252
 
253
+ /**
254
+ * Function provided for old widget include code compatability
255
+ * @param array $args Not needed
256
+ */
257
+ function transposh_widget($args = array()) {
258
+ $my_transposh_plugin->widget->transposh_widget($args);
259
+ }
260
  ?>