Fixed:
[project/i18n.git] / i18n.inc
1 <?php
2 // $Id$
3
4 /**
5 * Internationalization (i18n) module
6 *
7 * These are the functions to be defined only when module is enabled.
8 * Otherwise they could mess up with the admin system
9 *
10 * @author Jose A. Reyero, 2004
11 *
12 */
13
14 /**
15 * Implementation of conf_url_rewrite
16 *
17 * This is a conditional definition, just in case it is defined somewhere else
18 */
19
20 if(!function_exists('custom_url_rewrite')) {
21 function custom_url_rewrite($type, $path, $original) {
22 return i18n_url_rewrite($type, $path, $original);
23 }
24 }
25
26 function i18n_url_rewrite($type, $path, $original){
27 if ($type == 'alias' && !i18n_get_lang_prefix($path) ){
28 return $path ? i18n_get_lang() . '/'. $path : i18n_get_lang();
29 } else {
30 return $path;
31 }
32 }
33
34 /**
35 * Implementation of hook_db_rewrite_sql()
36 */
37 function i18n_db_rewrite_sql($query, $primary_table, $primary_key){
38 // Some exceptions for query rewrites
39 if(strstr(request_uri(),'cron.php')) return;
40
41 $alias = $primary_table;
42
43 switch ($alias) {
44 case 'n':
45 $result = i18n_db_node_rewrite($query, $primary_table, $primary_key);
46 break;
47 case 't':
48 case 'v':
49 $result = i18n_db_taxonomy_rewrite($query, $primary_table, $primary_key);
50 break;
51 }
52
53 return $result;
54 }
55
56 function i18n_db_node_rewrite($query, $primary_table, $primary_key){
57 $alias = $primary_table;
58 // When loading specific nodes, language conditions shouldn't apply
59 // TO-DO: Refine this regexp
60 if (preg_match("/WHERE.*$alias.nid\s*=\s*(\d|%d)/", $query)) return;
61 //drupal_set_message($query);
62 $mode = i18n_selection_mode();
63 if($mode == 'off') return;
64
65 $result['join'] = "LEFT JOIN {i18n_node} i18n ON $alias.nid = i18n.nid";
66 $alias = 'i18n';
67
68 switch($mode){
69 case 'simple':
70 $result['where'] = "$alias.language ='".i18n_get_lang()."' OR $alias.language IS NULL" ;
71 break;
72 case 'mixed':
73 $result['where'] = "$alias.language ='".i18n_get_lang()."' OR $alias.language ='".i18n_default_language()."' OR $alias.language IS NULL" ;
74 break;
75 case 'strict':
76 $result['where'] = "$alias.language ='".i18n_get_lang()."'" ;
77 break;
78 case 'default':
79 $result['where'] = "$alias.language ='".i18n_default_language()."' OR $alias.language IS NULL" ;
80 break;
81 }
82
83 return $result;
84 }
85
86 function i18n_db_taxonomy_rewrite($query, $primary_table, $primary_key){
87 // When loading specific terms, vocabs, language conditions shouldn't apply
88 // TO-DO: Refine this regexp
89 if (preg_match("/WHERE.* $primary_table\.tid\s*(=\s*\d|IN)/", $query)) return;
90
91 // Decide language depending on what we are doing
92 $lang = i18n_get_lang(); // Default
93 switch(arg(0)) {
94 case 'node':
95 $edit = $_POST['edit'];
96 if( arg(1) == 'add'){
97 // Adding node
98 $lang = isset($edit['language']) ? $edit['language'] : i18n_get_lang();
99 } elseif( is_numeric(arg(1)) && arg(2) == 'edit') {
100 // Editing a node
101 if(is_array($edit)) {
102 $lang = isset($edit['language']) ? $edit['language'] : i18n_get_lang();
103 } else {
104 $lang = i18n_node_get_lang(arg(1), i18n_get_lang());
105 }
106 } else {
107 $lang = i18n_get_lang();
108 }
109 break;
110 case 'translation':
111 $edit = $_POST['edit'];
112 $lang = isset($edit['language']) ? $edit['language'] : arg(3);
113 break;
114 case 'admin':
115 if(arg(1) == 'taxonomy') {
116 // Taxonomy administration. Show all
117 $lang = NULL;
118 }
119 /*
120 case 'taxonomy':
121 if(arg(1) == 'term'){
122 $lang = NULL;
123 }
124 */
125 }
126
127 if($lang) {
128 $alias = $primary_table;
129 $result['where'] = "$alias.language ='$lang' OR $alias.language = ''";
130 return $result;
131 }
132 }
133
134 /**
135 * Implementation of hook_exit
136 */
137 function i18n_exit(){
138 _i18n_variable_exit();
139 }
140
141 /**
142 * Implementation of hook_form_alter
143 *
144 * This is the place to add language fields to all forms
145 * Alan: - changed to test in case translation_form_alter (or another module/mechanism) has already set language
146 * - translation module may reduce language selection options in case there already exist translations
147 */
148 function i18n_form_alter($form_id, &$form) {
149 //drupal_set_message("i18n_form_alter form_id=$form_id ");
150 switch($form_id){
151 case 'taxonomy_overview_vocabularies':
152 $vocabularies = taxonomy_get_vocabularies();
153 $languages = i18n_supported_languages();
154 foreach ($vocabularies as $vocabulary) {
155 if($vocabulary->language) $form[$vocabulary->vid]['type']['#value'] = $form[$vocabulary->vid]['type']['#value'].'&nbsp('.$languages[$vocabulary->language].')';
156 }
157 break;
158 case 'taxonomy_form_vocabulary': // Taxonomy vocabulary
159 if(isset($form['vid'])) {
160 $vocabulary = taxonomy_get_vocabulary($form['vid']['#value']);
161 }
162 $form['language'] = _i18n_language_select(isset($vocabulary) ? $vocabulary->language : i18n_get_lang(),t('This language will be set for all terms in this vocabulary'));
163 break;
164
165 case 'taxonomy_form_term': // Taxonomy term
166 if(isset($form['vid']) && is_numeric($form['vid'])) {
167 $vocabulary = taxonomy_get_vocabulary($form['vid']);
168 }
169 $form['language'] = _i18n_language_select(isset($vocabulary) ? $vocabulary->language : i18n_get_lang());
170 break;
171
172 default:
173 // Content type settings
174 if (isset($form['type']) && $form['type']['#value'] .'_node_settings' == $form_id) {
175 $form['workflow']['i18n_node_'. $form['type']['#value']] = array(
176 '#type' => 'radios',
177 '#title' => t('Multilingual support'),
178 '#default_value' => variable_get('i18n_node_'. $form['type']['#value'], 0),
179 '#options' => array(t('Disabled'), t('Enabled')),
180 '#description' => t('Enables language field and multilingual support for this content type.'),
181 );
182 }
183 // Node edit form
184 if (isset($form['type']) && $form['type']['#value'] .'_node_form' == $form_id){
185 // Language field
186 if(variable_get('i18n_node_'.$form['type']['#value'], 0) && !isset($form['i18n']['language'])) {
187 // Language field
188 $form['i18n'] = array('#type' => 'fieldset', '#title' => t('Language'), '#collapsible' => TRUE, '#collapsed' => FALSE, '#weight' => -4);
189 // Language will default to current only when creating a node
190 $language = isset($form['#node']->language) ? $form['#node']->language : (arg(1)=='add' ? i18n_get_lang() : '');
191 $form['i18n']['language'] = _i18n_language_select($language, t('If you change the Language, you must click on <i>Preview</i> to get the right Categories &amp; Terms for that language.'), -4);
192 }
193 // Correction for lang/node/nid aliases generated by path module
194 // if($form['#node']->path && $form['#node']->path == i18n_get_lang().'/node/'.$form['#node']->nid){
195 if($form['#node']->path) {
196 $alias=drupal_lookup_path('alias', 'node/'.$form['#node']->nid);
197 if($alias && $alias != 'node/'.$form['#node']->nid){
198 $form['#node']->path = $alias;
199 } else {
200 unset($form['#node']->path);
201 }
202 }
203 }
204
205 }
206 }
207
208 /**
209 * Implementation of hook_nodeapi
210 * Updated for new table i18n_node
211 */
212 function i18n_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
213 if (variable_get("i18n_node_$node->type", 0)) {
214 switch ($op) {
215 case 'load':
216 return db_fetch_array(db_query("SELECT trid, language FROM {i18n_node} WHERE nid=%d", $node->nid));
217 case 'insert':
218 case 'update':
219 db_query("DELETE FROM {i18n_node} WHERE nid=%d",$node->nid);
220 if($node->language){
221 db_query("INSERT INTO {i18n_node} (nid, trid, language) VALUES(%d, '%d', '%s')", $node->nid, $node->trid, $node->language);
222 }
223 break;
224 case 'delete':
225 db_query('DELETE FROM {i18n_node} WHERE nid=%d', $node->nid);
226 break;
227 }
228 }
229 }
230
231 /**
232 * Helper function to create language selector
233 */
234 function _i18n_language_select($value ='', $description ='', $weight = -20){
235 return array(
236 '#type' => 'select',
237 '#title' => t('Language'),
238 '#default_value' => $value,
239 '#options' => array_merge(array('' => ''), i18n_supported_languages()),
240 '#description' => $description,
241 '#weight' => $weight,
242 );
243 }
244
245 /**
246 * Implementation of hook_taxonomy
247 *
248 * $edit parameter may be an array or an object !!
249 */
250 function i18n_taxonomy($op, $type, $edit = NULL) {
251 $edit = (array)$edit;
252 switch ("$type/$op") {
253 case 'term/insert':
254 case 'term/update':
255 $language = isset($edit['language']) ? $edit['language'] : '';
256 db_query("UPDATE {term_data} SET language='%s' WHERE tid=%d", $language, $edit['tid']);
257 break;
258 case 'vocabulary/insert':
259 case 'vocabulary/update':
260 $language = isset($edit['language']) ? $edit['language'] : '';
261 db_query("UPDATE {vocabulary} SET language='%s' WHERE vid=%d", $language, $edit['vid']);
262 if ($language && $op == 'update') {
263 db_query("UPDATE {term_data} t SET t.language='%s' WHERE t.vid=%d", $edit['language'], $edit['vid']);
264 drupal_set_message(t('Reset language for all terms.'));
265 }
266 break;
267 }
268 }
269
270 /**
271 * More i18n API
272 */
273
274 /**
275 * This one expects to be called first from common.inc
276 */
277 function i18n_get_lang() {
278 static $i18n_language;
279 //see if the language is already set.
280 if ($i18n_language) {
281 return $i18n_language;
282 } else {
283 return $i18n_language = _i18n_get_lang();
284 }
285 }
286
287 // Note: do not call url() anymore, it will be called from l()
288 function i18n_url($url, $lang) {
289 // Strip prefix if default language
290 if ($url) {
291 return $lang.'/'.$url;
292 } else {
293 return $lang;
294 }
295 }
296
297 function i18n_node_get_lang($nid, $default = '') {
298 $lang = db_result(db_query('SELECT language FROM {i18n_node} WHERE nid=%d',$nid));
299 return $lang ? $lang : $default ;
300 }
301
302 /**
303 * Returns main language, two letter code
304 */
305 function i18n_get_main_lang($lang = NULL){
306 $lang = $lang ? $lang : i18n_get_lang();
307 return substr($lang, 2);
308 }
309
310
311 /**
312 * Language block
313 *
314 * This is a simple language switcher which knows nothing about translations
315 */
316 function i18n_block($op = 'list', $delta = 0) {
317 if ($op == 'list') {
318 $blocks[0]['info'] = t('Language switcher');
319 }
320 elseif($op == 'view') {
321 $blocks['subject'] = t('Languages');
322 $blocks['content'] = theme('item_list', i18n_get_links($_GET['q']));
323 }
324
325 return $blocks;
326 }
327
328 /**
329 * Function i18n_get_links
330 *
331 * Returns an array of urls for all languages, with or without names/flags
332 */
333 function i18n_get_links($path = '') {
334 foreach(i18n_supported_languages() as $lang => $name){
335 $links[$lang]= theme('i18n_link', $name, i18n_url($path, $lang), $lang);
336 }
337 return $links;
338 }
339
340
341 /**
342 * Multilingual variables
343 */
344 function i18n_variable_init(){
345 global $conf;
346 global $i18n_conf;
347 $lang = _i18n_get_lang();
348 if($i18n_variables = variable_get('i18n_variables', '')){
349 $i18n_conf = array();
350 $variables = _i18n_variable_init();
351 foreach($i18n_variables as $name){
352 $i18n_conf[$name] = isset($variables[$name]) ? $variables[$name] : (isset($conf[$name]) ? $conf[$name] : '');
353 }
354 $conf = array_merge($conf, $i18n_conf);
355 }
356 }
357
358 function _i18n_variable_init(){
359 $lang = _i18n_get_lang();
360 $variables = array();
361 if ($cached = cache_get('variables:'.$lang)) {
362 $variables = unserialize($cached->data);
363 }
364 else {
365 $result = db_query("SELECT * FROM {i18n_variable} WHERE language='%s'", $lang);
366 while ($variable = db_fetch_object($result)) {
367 $variables[$variable->name] = unserialize($variable->value);
368 }
369 cache_set('variables:'.$lang, serialize($variables));
370 }
371
372 return $variables;
373
374 }
375
376 function _i18n_variable_exit(){
377 global $i18n_conf;
378 global $conf;
379 $lang = _i18n_get_lang();
380 if($i18n_conf){
381 $variables = array_diff_assoc($i18n_conf, $conf);
382 if($variables){
383 foreach($variables as $name => $value){
384 $i18n_conf[$name] = $conf[$name];
385 db_query("DELETE FROM {i18n_variable} WHERE name='%s' AND language='%s'", $name, $lang );
386 db_query("INSERT INTO {i18n_variable} (language, name, value) VALUES('%s', '%s', '%s')", $lang, $name, serialize($conf[$name]));
387 }
388 cache_set('variables:'.$lang, serialize($i18n_conf));
389 }
390 }
391 }
392
393 /**
394 * @name Themeable functions
395 * @{
396 */
397
398 /**
399 * Produces a language link with the right flag
400 */
401 function theme_i18n_link($text, $target, $lang, $separator='&nbsp;'){
402 $output = '<span class="i18n-link">';
403 $attributes = ($lang == i18n_get_lang()) ? array('class' => 'active') : NULL;
404 $output .= l(theme('i18n_language_icon', $lang), $target, $attributes, NULL, NULL, FALSE, TRUE);
405 $output .= $separator;
406 $output .= l($text, $target, $attributes, NULL, NULL, FALSE, TRUE);
407 $output .= '</span>';
408 return $output;
409 }
410
411 function theme_i18n_language_icon($lang){
412 if ($path = variable_get('i18n_icon_path', drupal_get_path('module', 'i18n').'/flags/*.png')) {
413 $languages = i18n_supported_languages();
414 $src = base_path().str_replace('*', $lang, $path);
415 list($width, $height) = explode('x', variable_get('i18n_flags_size', '16x12'));
416 $attribs = array('class' => 'i18n-icon', 'width' => $width, 'height' => $height, 'alt' => $languages[$lang]);
417 return "<img src=\"$src\" ".drupal_attributes($attribs)." />";
418 }
419 }
420
421 /* @} */
422 ?>