/[drupal]/contributions/modules/i18n/i18nstrings/i18nstrings.module
ViewVC logotype

Contents of /contributions/modules/i18n/i18nstrings/i18nstrings.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.9 - (show annotations) (download) (as text)
Thu Feb 21 20:14:23 2008 UTC (21 months ago) by jareyero
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-5--3
Changes since 1.8: +52 -2 lines
File MIME type: text/x-php
- Added (Upgraded) i18ncontent, fully reworked, much cleaner now
- Improved i18nstrings, translation of strings without source, debug facility
- Replaced taxonomy term pages with localized version
1 <?php
2 // $Id: i18nstrings.module,v 1.8 2008/02/19 19:43:55 jareyero Exp $
3
4 /**
5 * @file
6 * Internationalization (i18n) package - translatable strings
7 *
8 * Object oriented string translation using locale and textgroups
9 *
10 * Some concepts
11 * - Textgroup. Group the string belongs to, defined by locale hook
12 * - Location. Unique id of the string for this textgroup
13 * - Name. Unique absolute id of the string: textgroup + location
14 * - Context. Object with textgroup, type, oid, property
15 * - Default language may be English or not. It will be the language set as default
16 * Source strings will be stored in default language
17 *
18 * @ TO DO: Handle default language changes.
19 *
20 * @author Jose A. Reyero, 2007
21 */
22
23 /**
24 * Translate configurable string
25 *
26 * @param $name
27 * Textgroup and location glued with ':'
28 * @param $string
29 * String in default language. Default language may or may not be English
30 * @param $langcode
31 * Optional language code if different from current request language
32 * @param $update
33 * Whether to update/create the string
34 */
35 function tt($name, $string, $langcode = NULL, $update = FALSE) {
36 global $language;
37 $langcode = $langcode ? $langcode : $language->language;
38
39 // If language is default, just return
40 if (language_default('language') == $langcode) {
41 if ($update) {
42 i18nstrings_update_string($name, $string);
43 }
44 return $string;
45 } else {
46 return i18nstrings_tt($name, $string, $langcode, $update);
47 }
48 }
49
50 /**
51 * Get configurable string,
52 *
53 * The difference with tt() is that it doesn't use a default string, it will be retrieved too.
54 * This is used for source texts that we don't have stored anywhere else.
55 *
56 * As the original language string will be stored in locales too so it should be only used when updating
57 */
58 function ts($name, $string = '', $langcode = NULL, $update = FALSE) {
59 global $language;
60
61 $langcode = $langcode ? $langcode : $language->language;
62 $translation = NULL;
63
64 if ($update) {
65 i18nstrings_update_string($name, $string);
66 }
67 // if language is default look in sources table
68 if (language_default('language') != $langcode) {
69 $translation = i18nstrings_get_string($name, $langcode);
70 }
71 if (!$translation) {
72 if ($source = i18nstrings_get_source($name)) {
73 $translation = $source->source;
74 } else {
75 $translation = '';
76 }
77 }
78 return $translation;
79 }
80
81 /**
82 * Debug util. Marks the translated strings
83 */
84 function ttd($name, $string, $langcode = NULL, $update = FALSE) {
85 return tt($name, $string, $langcode, $update).'[T:'.$string.']';
86 }
87
88 /**
89 * Translate configurable string
90 * @param $name
91 * Textgroup and location glued with ':'
92 */
93 function i18nstrings_tt($name, $string, $langcode, $update = FALSE, $create = TRUE) {
94 $context = i18nstrings_context($name, $string);
95
96 if ($update) {
97 i18nstrings_update_string($context, $string);
98 }
99
100 $translation = i18nstrings_get_string($context, $langcode);
101
102 if ($translation) {
103 return ($translation === TRUE) ? $string : $translation;
104 } elseif ($translation === FALSE && $create) {
105 i18nstrings_update_string($context, $string);
106 i18nstrings_cache($context, $string, $langcode, TRUE);
107 }
108 // Default case, just return untranslated string
109 return $string;
110 }
111
112 /**
113 * Translate object
114 */
115 function to($context, &$object, $properties = array(), $langcode = NULL, $update = FALSE) {
116 global $language;
117
118 $langcode = $langcode ? $langcode : $language->language;
119
120 // If language is default, just return
121 if (language_default('language') == $langcode && !$update) {
122 return $object;
123 } else {
124 i18nstrings_to($context, $object, $properties, $langcode, $update);
125 }
126 }
127
128 /**
129 * Translate object properties
130 */
131 function i18nstrings_to($context, &$object, $properties = array(), $langcode = NULL, $update = FALSE, $create = TRUE) {
132 $context = i18nstrings_context($context);
133 // @ TODO Object prefetch
134 foreach ($properties as $property) {
135 $context->property = $property;
136 if (!empty($object->$property)) {
137 $object->property = i18nstrings_tt($context, $object->$property, $langcode, $update, $create);
138 }
139 }
140 }
141
142 /**
143 * Update / create / remove string
144 *
145 * @param $context
146 * String context
147 * @pram $string
148 * New value of string for update/create. May be empty for removing.
149 */
150 function i18nstrings_update_string($context, $string) {
151 $context = i18nstrings_context($context);
152 if ($string) {
153 $status = i18nstrings_add_string($context, $string);
154 } else {
155 $status = i18nstrings_remove_string($context);
156 }
157 $params = array(
158 '%location' => i18nstrings_location($context),
159 '%textgroup' => $context->textgroup,
160 '%string' => $string,
161 );
162 switch ($status) {
163 case SAVED_UPDATED:
164 drupal_set_message(t('Updated string %location for textgroup %textgroup: %string', $params));
165 break;
166 case SAVED_NEW:
167 drupal_set_message(t('Created string %location for text group %textgroup: %string', $params));
168 break;
169 }
170 return $status;
171 }
172
173 /**
174 * Update string translation
175 */
176 function i18nstrings_update_translation($context, $langcode, $translation) {
177 if ($source = i18nstrings_get_source($context, $translation)) {
178 db_query("INSERT INTO {locales_target}(lid, language, translation) VALUES(%d, '%s', '%s')", $source->lid, $langcode, $translation);
179 }
180 }
181
182 /**
183 * Add string
184 *
185 * This function checks for already existing string without context for this textgroup
186 *
187 * @return
188 * Update status
189 */
190 function i18nstrings_add_string($name, $string) {
191 $context = i18nstrings_context($name);
192 $location = i18nstrings_location($context);
193
194 // Check if we have a source string
195 $source = i18nstrings_get_source($context, $string);
196
197 $status = -1;
198
199 if ($source) {
200 if ($source->source != $string || $source->location != $location) {
201 // String has changed or didnt have location
202 db_query("UPDATE {locales_source} SET source = '%s' WHERE lid = %d", $string, $source->lid);
203 $status = SAVED_UPDATED;
204 }
205 }
206 else {
207 db_query("INSERT INTO {locales_source} (location, source, textgroup, version) VALUES ('%s', '%s', '%s', '%s')", $location, $string, $context->textgroup, 0);
208 // Clear locale cache so this string can be added in a later request.
209 cache_clear_all('locale:'.$context->textgroup.':', 'cache', TRUE);
210 // Create string
211 $source->lid = db_last_insert_id('locales_source', 'lid');
212 $status = SAVED_NEW;
213 }
214 // Update metadata
215 db_query("DELETE FROM {i18n_strings} WHERE lid = %d", $source->lid);
216 db_query("INSERT INTO {i18n_strings} (lid, type, oid, property) VALUES(%d, '%s', %d, '%s')", $source->lid, $context->type, $context->oid, $context->property);
217
218 return $status;
219 }
220
221 /**
222 * Get source string provided a string context
223 *
224 * This will search first with the full context parameters and, if not found,
225 * it will search again only with textgroup and source string
226 *
227 * @param $context
228 * Context string or object
229 * @return
230 * Context object if it exists
231 */
232 function i18nstrings_get_source($context, $string = NULL) {
233 $context = i18nstrings_context($context);
234
235 // Check if we have the string for this location
236 list($where, $args) = i18nstrings_context_query($context);
237 if ($source = db_fetch_object(db_query("SELECT s.*, i.type, i.oid, i.property FROM {locales_source} s LEFT JOIN {i18n_strings} i ON s.lid = i.lid WHERE ". implode(' AND ', $where), $args))) {
238 $source->context = $context;
239 return $source;
240 }
241 // Search for the same string for this textgroup without object data
242 if ($string && $source = db_fetch_object(db_query("SELECT s.*, i.type, i.oid, i.property FROM {locales_source} s LEFT JOIN {i18n_strings} i ON s.lid = i.lid WHERE s.textgroup = '%s' AND s.source = '%s' AND i.lid IS NULL", $context->textgroup, $string))) {
243 $source->context = NULL;
244 return $source;
245 }
246 }
247
248 /**
249 * Get string for a language
250 *
251 * @param $context
252 * Context string or object
253 * @param $langcode
254 * Language code to retrieve string for
255 *
256 * @return
257 * - translation if found
258 * - TRUE if not found and cached
259 * - FALSE if not even cached
260 *
261 */
262 function i18nstrings_get_string($context, $langcode) {
263 $context = i18nstrings_context($context);
264 if ($translation = i18nstrings_cache($context, $langcode)) {
265 return $translation;
266 } else {
267 // Search translation and add it to the cache
268 list($where, $args) = i18nstrings_context_query($context);
269 $where[] = "t.language = '%s'";
270 $args[] = $langcode;
271 $text = db_fetch_object(db_query("SELECT s.*, t.translation FROM {locales_source} s INNER JOIN {locales_target} t ON s.lid = t.lid WHERE ". implode(' AND ', $where), $args));
272 if ($text && $text->translation) {
273 i18nstrings_cache($context, $langcode, NULL, $text->translation);
274 return $text->translation;
275 } else {
276 i18nstrings_cache($context, $langcode, NULL, TRUE);
277 return $text ? NULL : FALSE ;
278 }
279 }
280 }
281
282 /**
283 * Remove string for a given context
284 */
285 function i18nstrings_remove_string($context, $string = NULL) {
286 if ($source = i18nstrings_get_source($context, $string)) {
287 db_query("DELETE FROM {locales_target} WHERE lid = %d", $source->lid);
288 db_query("DELETE FROM {i18n_strings} WHERE lid = %d", $source->lid);
289 db_query("DELETE FROM {locales_source} WHERE lid = %d", $source->lid);
290 cache_clear_all('locale:'.$context->textgroup.':', 'cache', TRUE);
291 return SAVED_DELETED;
292 }
293 }
294
295 /**
296 * Update context for strings.
297 *
298 * As some string locations depend on configurable values, the field needs sometimes to be updated
299 * without losing existing translations. I.e:
300 * - profile fields indexed by field name
301 * - content types indexted by low level content type name
302 *
303 * Example
304 * 'profile:field:oldfield:*' -> 'profile:field:newfield:*'
305 */
306 function i18nstrings_update_context($oldname, $newname) {
307 // Get context replacing '*' with empty string
308 $oldcontext = i18nstrings_context(str_replace('*', '', $oldname));
309 $newcontext = i18nstrings_context(str_replace('*', '', $newname));
310 // Get location with placeholders
311 $location = i18nstrings_location(str_replace('*', '%', $oldname));
312 foreach (array('textgroup', 'type', 'oid', 'property') as $field) {
313 if ((!empty($oldcontext->$field) || !empty($newcontext->$field)) && $oldcontext->$field != $newcontext->$field) {
314 $replace[$field] = $newcontext->$field;
315 }
316 }
317 // Query and replace
318 $result = db_query("SELECT s.*, i.type, i.oid, i.property FROM {locales_source} s LEFT JOIN {i18n_strings} i ON s.lid = i.lid WHERE s.textgroup = '%s' AND s.location LIKE '%s'", $oldcontext->textgroup, $location);
319 while ($source = db_fetch_object($result)) {
320 // Make sure we have string and context
321 $context = i18nstrings_context($oldcontext->textgroup.':'.$source->location);
322 foreach ($replace as $field => $value) {
323 $context->$field = $value;
324 }
325 // Update source string
326 db_query("UPDATE {locales_source} SET textgroup = '%s', location = '%s' WHERE lid = %d", $context->textgroup, i18nstrings_location($context), $source->lid);
327 // Update object data
328 db_query("UPDATE {i18n_strings} SET type = '%s', oid = '%s', property = '%s' WHERE lid = %d", $context->type, $context->oid, $context->property, $source->lid);
329 }
330 drupal_set_message(t('Updating string names from %oldname to %newname', array('%oldname' => $oldname, '%newname' => $newname)));
331 }
332
333 /**
334 * Provides interface translation services.
335 *
336 * This function is called from tt() to translate a string if needed.
337 *
338 * @param $textgroup
339 *
340 * @param $string
341 * A string to look up translation for. If omitted, all the
342 * cached strings will be returned in all languages already
343 * used on the page.
344 * @param $langcode
345 * Language code to use for the lookup.
346 */
347 function i18nstrings_textgroup($textgroup, $string = NULL, $langcode = NULL) {
348 global $language;
349 static $locale_t;
350
351 // Return all cached strings if no string was specified
352 if (!isset($string)) {
353 return isset($locale_t[$textgroup]) ? $locale_t[$textgroup] : array();
354 }
355
356 $langcode = isset($langcode) ? $langcode : $language->language;
357
358 // Store database cached translations in a static var.
359 if (!isset($locale_t[$langcode])) {
360 $locale_t[$langcode] = array();
361 // Disabling the usage of string caching allows a module to watch for
362 // the exact list of strings used on a page. From a performance
363 // perspective that is a really bad idea, so we have no user
364 // interface for this. Be careful when turning this option off!
365 if (variable_get('locale_cache_strings', 1) == 1) {
366 if ($cache = cache_get('locale:'.$textgroup.':'.$langcode, 'cache')) {
367 $locale_t[$textgroup][$langcode] = $cache->data;
368 }
369 else {
370 // Refresh database stored cache of translations for given language.
371 // We only store short strings used in current version, to improve
372 // performance and consume less memory.
373 $result = db_query("SELECT s.source, t.translation, t.language FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid AND t.language = '%s' WHERE s.textgroup = '%s' AND s.version = '%s' AND LENGTH(s.source) < 75", $langcode, $textgroup, VERSION);
374 while ($data = db_fetch_object($result)) {
375 $locale_t[$textgroup][$langcode][$data->source] = (empty($data->translation) ? TRUE : $data->translation);
376 }
377 cache_set('locale:'.$textgroup.':'. $langcode, $locale_t[$textgroup][$langcode]);
378 }
379 }
380 }
381
382 // If we have the translation cached, skip checking the database
383 if (!isset($locale_t[$textgroup][$langcode][$string])) {
384
385 // We do not have this translation cached, so get it from the DB.
386 $translation = db_fetch_object(db_query("SELECT s.lid, t.translation, s.version FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid AND t.language = '%s' WHERE s.source = '%s' AND s.textgroup = '%s'", $langcode, $string, $textgroup));
387 if ($translation) {
388 // We have the source string at least.
389 // Cache translation string or TRUE if no translation exists.
390 $locale_t[$textgroup][$langcode][$string] = (empty($translation->translation) ? TRUE : $translation->translation);
391
392 if ($translation->version != VERSION) {
393 // This is the first use of this string under current Drupal version. Save version
394 // and clear cache, to include the string into caching next time. Saved version is
395 // also a string-history information for later pruning of the tables.
396 db_query("UPDATE {locales_source} SET version = '%s' WHERE lid = %d LIMIT 1", VERSION, $translation->lid);
397 cache_clear_all('locale:'.$textgroup.':', 'cache', TRUE);
398 }
399 }
400 else {
401 // We don't have the source string, cache this as untranslated.
402 db_query("INSERT INTO {locales_source} (location, source, textgroup, version) VALUES ('%s', '%s', 'default', '%s')", request_uri(), $string, VERSION);
403 $locale_t[$langcode][$string] = TRUE;
404 // Clear locale cache so this string can be added in a later request.
405 cache_clear_all('locale:'.$textgroup.':', 'cache', TRUE);
406 }
407 }
408
409 return ($locale_t[$textgroup][$langcode][$string] === TRUE ? $string : $locale_t[$textgroup][$langcode][$string]);
410 }
411
412 /**
413 * Convert context string in a context object
414 *
415 * I.e.
416 * 'taxonomy:term:1:name'
417 * will become a $context object where
418 * $context->textgroup = 'taxonomy';
419 * $context->type = 'term';
420 * $context->oid = 1;
421 * $context->property = 'name';
422 * Examples:
423 * 'taxonomy:title' -> (taxonomy, title, 0, 0)
424 * 'contenttypes:type:[type]:name'
425 * 'contenttypes:type:[type]:description'
426 * 'profile:category'
427 * 'profile:field:[fid]:title'
428 *
429 * @param $context
430 * Context string or object
431 * @return
432 * Context object with textgroup, type, oid, property and location names
433 */
434 function i18nstrings_context($context, $string = NULL) {
435 // Context may be already an object
436 if (is_object($context)) {
437 return $context;
438 } else {
439 // We add empty fields at the end before splitting
440 list($textgroup, $type, $oid, $property) = split(':', $context.':::');
441 $context = (object)array(
442 'textgroup' => $textgroup,
443 'type' => $type,
444 'oid' => $oid ? $oid : 0,
445 'property' => $property ? $property : 0,
446 );
447 $context->location = i18nstrings_location($context);
448 if (!$context->oid && !$context->property && $string) {
449 $context->source = $string;
450 }
451 return $context;
452 }
453 }
454
455 /**
456 * Get query conditions for this context
457 */
458 function i18nstrings_context_query($context, $alias = 's') {
459 $where = array("$alias.textgroup = '%s'", "$alias.location = '%s'");
460 $args = array($context->textgroup, $context->location);
461 if (!empty($context->source)) {
462 $where[] = "s.source = '%s'";
463 $args[] = $context->source;
464 }
465 return array($where, $args);
466 }
467
468 /**
469 * Get location string from context
470 *
471 * Returns the location for the locale table for a string context
472 */
473 function i18nstrings_location($context) {
474 if (is_string($context)){
475 $context = i18nstrings_context($context);
476 }
477 $location[] = $context->type;
478 if ($context->oid) {
479 $location[] = $context->oid;
480 if ($context->property) {
481 $location[] = $context->property;
482 }
483 }
484 return implode(':', $location);
485 }
486
487 /**
488 * Prefetch a number of object strings
489 */
490 function i18nstrings_prefetch($context, $langcode = NULL, $join = array(), $conditions = array()) {
491 global $language;
492
493 $langcode = $langcode ? $langcode : $language->language;
494 // Add language condition
495 $conditions['t.language'] = $langcode;
496 // Get context conditions
497 $context = (array)i18nstrings_context($context);
498 foreach ($context as $key => $value) {
499 if ($value) {
500 if ($key == 'textgroup') {
501 $conditions['s.textgroup'] = $value;
502 } else {
503 $conditions['i.'. $key] = $value;
504 }
505 }
506 }
507 // Prepare where clause
508 $where = $params = array();
509 foreach ($conditions as $key => $value) {
510 if (is_array($value)) {
511 $where[] = $key . ' IN ('.db_placeholders($value, is_int($value[0]) ? 'int' : 'string').')';
512 $params = array_merge($params, $value);
513 } else {
514 $where[] = $key . ' = ' . is_int($value) ? '%d' : "'%s'";
515 $params[] = $value;
516 }
517 }
518 $sql = "SELECT s.textgroup, s.source, i.type, i.oid, i.property, t.translation FROM {locales_source} s";
519 $sql .=" INNER JOIN {i18n_strings} i ON s.lid = i.lid INNER JOIN {locales_target} t ON s.lid = t.lid ";
520 $sql .= implode(' ', $join) . ' ' . implode (' AND ', $where);
521 $result = db_query($sql, $params);
522
523 // Fetch all rows and store in cache
524 while ($t = db_fetch_object($result)) {
525 i18nstrings_cache($t, $langcode, $t->source, $t->translation);
526 }
527
528 }
529
530 /**
531 * Retrieves and stores translations in page (static variable) cache.
532 */
533 function i18nstrings_cache($context, $langcode, $string = NULL, $translation = NULL) {
534 static $strings;
535
536 $context = i18nstrings_context($context);
537
538 if (!$context->oid && $string) {
539 // This is a type indexed by string
540 $context->oid = $string;
541 }
542 // At this point context must have at least textgroup and type
543 if ($translation) {
544 if ($context->property) {
545 $strings[$langcode][$context->textgroup][$context->type][$context->oid][$context->property] = $translation;
546 } elseif ($context->oid) {
547 $strings[$langcode][$context->textgroup][$context->type][$context->oid] = $translation;
548 } else {
549 $strings[$langcode][$context->textgroup][$context->type] = $translation;
550 }
551 } else {
552 // Search up the tree for the object or a default
553 $search = &$strings[$langcode];
554 $default = NULL;
555 $list = array('textgroup', 'type', 'oid', 'property');
556 while (($field = array_shift($list)) && !empty($context->$field)) {
557 if (isset($search[$context->$field])) {
558 $search = &$search[$context->$field];
559 if (isset($search['#default'])) {
560 $default = $search['#default'];
561 }
562 } else {
563 // We dont have cached this tree so we return the default
564 return $default;
565 }
566 }
567 // Returns the part of the array we got to
568 return $search;
569 }
570
571 }
572
573 /**
574 * Callback for menu title translation
575 */
576 function i18nstrings_title_callback($name, $string, $callback = NULL) {
577 $string = tt($name, $string);
578 if ($callback) {
579 $string = $callback($string);
580 }
581 return $string;
582 }
583
584 /**
585 * Implementation of hook_menu().
586 *
587 function i18nstrings_menu($may_cache) {
588 $items = array();
589 if ($may_cache) {
590 $items[] = array(
591 'path' => 'admin/settings/i18n/strings',
592 'type' => MENU_LOCAL_TASK,
593 'title' => t('Strings'),
594 'description' => t('Translatable strings.'),
595 'callback' => 'i18nstrings_admin',
596 'access' => user_access('administer site configuration'),
597 );
598 } else {
599
600 }
601
602 return $items;
603 }
604
605 /**
606 * Menu callback. Administration page
607 *
608 function i18nstrings_admin($op = NULL, $strid = NULL) {
609 switch($op) {
610 case 'edit':
611 return drupal_get_form('i18nstrings_admin_form', $strid);
612 default:
613 return i18nstrings_admin_overview();
614 }
615 }
616
617 /**
618 * List of strings
619 *
620 function i18nstrings_admin_overview() {
621 $output = '';
622 $header = array(t('String Id'), t('Default'), '');
623 $result = db_query("SELECT DISTINCT(strid) FROM {i18n_strings} ORDER BY strid", i18n_default_language());
624 $rows = array();
625 while($str = db_fetch_object($result)) {
626 $rows[] = array(
627 $str->strid,
628 tt($str->strid),
629 l(t('edit'), 'admin/settings/i18n/strings/edit/'.$str->strid)
630 );
631 }
632 $output .= theme('table', $header, $rows);
633 return $output;
634 }
635
636 /**
637 * Form callback: i18nstrings_admin_form
638 *
639 function i18nstrings_admin_form($strid) {
640 $strings = i18nstrings_load($strid);
641 $form['strid'] = array('#type' => 'value', '#value' => $strid);
642 $form['languages'] = array('#type' => 'fieldset', '#tree' => TRUE, '#title' => t('Translations'));
643
644 // Approximate the number of rows in a textfield with a maximum of 10.
645 $default = i18nstrings_get_string($strid, i18n_default_language());
646 $rows = min(ceil(str_word_count($default) / 12), 10);
647
648 foreach (i18n_supported_languages() as $language => $name) {
649 $form['languages'][$language] = array(
650 '#type' => 'textarea',
651 '#rows' => $rows,
652 '#title' => $name,
653 '#default_value' => i18nstrings_get_string($strid, $language)
654 );
655 }
656 $form['submit'] = array('#type' => 'submit', '#value' => t('Save'));
657 return $form;
658 }
659
660 /**
661 * Form submit callback
662 *
663 function i18nstrings_admin_form_submit($form_id, $form_values) {
664 $strid = $form_values['strid'];
665 foreach (i18n_supported_languages() as $language => $name) {
666 i18nstrings_save_string($strid, $language, $form_values['languages'][$language]);
667 }
668 drupal_set_message(t('The strings have been updated'));
669 return 'admin/settings/i18n/strings';
670 }
671
672 /**
673 * Load string translations
674 *
675 function i18nstrings_load($strid) {
676 $strings = array();
677 $result = db_query("SELECT * FROM {i18n_strings} WHERE strid = '%s'", $strid);
678 while ($str = db_fetch_object($result)) {
679 $strings[$str->locale] = $str->text;
680 }
681 }
682
683 /**
684 * Save string for a language
685 *
686 function i18nstrings_save_string($strid, $language, $value) {
687 drupal_set_message("DEBUG: i18n_strings_save: $strid($language)= $value");
688 db_query("DELETE FROM {i18n_strings} WHERE strid = '%s' AND locale = '%s'", $strid, $language);
689 db_query("INSERT INTO {i18n_strings}(strid, locale, text) VALUES('%s', '%s', '%s')", $strid, $language, $value);
690 }
691 /**/

  ViewVC Help
Powered by ViewVC 1.1.2