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