first import
This commit is contained in:
313
sites/all/modules/i18n/i18n_string/i18n_string.admin.inc
Normal file
313
sites/all/modules/i18n/i18n_string/i18n_string.admin.inc
Normal file
@@ -0,0 +1,313 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Helper functions for string administration.
|
||||
*/
|
||||
|
||||
// Load locale library
|
||||
include_once DRUPAL_ROOT . '/includes/locale.inc';
|
||||
|
||||
/**
|
||||
* Form callback. Refresh textgroups.
|
||||
*/
|
||||
function i18n_string_admin_refresh_form() {
|
||||
// Select textgroup/s. Just the ones that have a 'refresh callback'
|
||||
$groups = array();
|
||||
foreach (i18n_string_group_info() as $name => $info) {
|
||||
$groups[$name] = $info['title'];
|
||||
}
|
||||
$form['groups'] = array(
|
||||
'#type' => 'checkboxes',
|
||||
'#title' => t('Select text groups'),
|
||||
'#options' => $groups,
|
||||
'#description' => t('If a text group is no showing up here it means this feature is not implemented for it.'),
|
||||
);
|
||||
$form['delete'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Clean up left over strings.'),
|
||||
'#default_value' => TRUE,
|
||||
);
|
||||
$form['refresh'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Refresh strings'),
|
||||
'#suffix' => '<p>' . t('This will create all the missing strings for the selected text groups.') . '</p>',
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form submission.
|
||||
*/
|
||||
function i18n_string_admin_refresh_form_submit($form, &$form_state) {
|
||||
$op = isset($form_state['values']['op']) ? $form_state['values']['op'] : '';
|
||||
$groups = array_filter($form_state['values']['groups']);
|
||||
$group_names = module_invoke_all('locale', 'groups');
|
||||
if ($op == t('Refresh strings') && $groups) {
|
||||
$batch = i18n_string_refresh_batch($groups, $form_state['values']['delete']);
|
||||
batch_set($batch);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Refresh all user defined strings for a given text group.
|
||||
*
|
||||
* @param $group
|
||||
* Text group to refresh
|
||||
* @param $delete
|
||||
* Optional, delete existing (but not refresed, strings and translations)
|
||||
* @return Boolean
|
||||
* True if the strings have been refreshed successfully. False otherwise.
|
||||
*/
|
||||
function i18n_string_refresh_group($group, $delete = FALSE) {
|
||||
$result = FALSE;
|
||||
|
||||
// Compile all strings for this group
|
||||
if ($strings = i18n_string_group_string_list($group)) {
|
||||
i18n_string_refresh_string_list($strings);
|
||||
$result = TRUE;
|
||||
}
|
||||
// Invoke refresh hook
|
||||
$result = $result || module_invoke_all('i18n_string_refresh', $group);
|
||||
|
||||
// Now delete all source strings that were not refreshed (they don't have a row in i18n_string)
|
||||
if ($result && $delete) {
|
||||
i18n_string_refresh_cleanup($group);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up left over strings for text group
|
||||
*/
|
||||
function i18n_string_refresh_cleanup($group) {
|
||||
$lids = db_select('locales_source', 's')
|
||||
->fields('s', array('lid'))
|
||||
->condition('textgroup', $group)
|
||||
->condition('version', 0)
|
||||
->execute()
|
||||
->fetchCol();
|
||||
if ($lids) {
|
||||
drupal_set_message(t('Performing cleanup for text group %textgroup, deleting @count left over strings.', array('%textgroup' => $group, '@count' => count($lids))));
|
||||
db_delete('locales_target')->condition('lid', $lids)->execute();
|
||||
db_delete('locales_source')->condition('lid', $lids)->execute();
|
||||
db_delete('i18n_string')->condition('lid', $lids)->execute();
|
||||
return count($lids);
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare group for refreshing, reset version, count strings
|
||||
*/
|
||||
function i18n_string_refresh_reset($group) {
|
||||
// Mark data on locales_source setting version = 0
|
||||
db_update('locales_source')
|
||||
->fields(array('version' => 0))
|
||||
->condition('textgroup', $group)
|
||||
->execute();
|
||||
return (int)db_query("SELECT COUNT(*) FROM {locales_source} WHERE textgroup = :textgroup", array(':textgroup' => $group))->fetchField();
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh string list
|
||||
*/
|
||||
function i18n_string_refresh_string_list($strings) {
|
||||
$count = 0;
|
||||
foreach ($strings as $textgroup => $group_strings) {
|
||||
foreach ($group_strings as $type => $type_strings) {
|
||||
foreach ($type_strings as $id => $object_strings) {
|
||||
foreach ($object_strings as $key => $string) {
|
||||
if (is_array($string)) {
|
||||
$format = isset($string['format']) ? $string['format'] : NULL;
|
||||
$string = $string['string'];
|
||||
}
|
||||
else {
|
||||
$format = NULL;
|
||||
}
|
||||
i18n_string_update(array($textgroup, $type, $id, $key), $string, array('format' => $format));
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create batch for refreshing strings
|
||||
*
|
||||
* @param $groups
|
||||
* Array of text groups to refresh
|
||||
* @param $delete
|
||||
* Optional, delete existing (but not refresed, strings and translations)
|
||||
*/
|
||||
function i18n_string_refresh_batch($groups, $delete = FALSE) {
|
||||
$operations = array();
|
||||
foreach ($groups as $group) {
|
||||
$operations[] = array('_i18n_string_batch_refresh_prepare', array($group));
|
||||
// First try to find string list
|
||||
$operations[] = array('_i18n_string_batch_refresh_list', array($group));
|
||||
// Then invoke refresh callback
|
||||
$operations[] = array('_i18n_string_batch_refresh_callback', array($group));
|
||||
if ($delete) {
|
||||
$operations[] = array('_i18n_string_batch_refresh_cleanup', array($group));
|
||||
}
|
||||
// Output group summary
|
||||
$operations[] = array('_i18n_string_batch_refresh_summary', array($group));
|
||||
}
|
||||
$batch = array(
|
||||
'operations' => $operations,
|
||||
'title' => t('Refreshing user defined strings'),
|
||||
'init_message' => t('Starting string refresh'),
|
||||
'error_message' => t('Error refreshing user defined strings'),
|
||||
'file' => drupal_get_path('module', 'i18n_string') . '/i18n_string.admin.inc',
|
||||
);
|
||||
return $batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh strings for enabled modules
|
||||
*/
|
||||
function i18n_string_refresh_enabled_modules($modules) {
|
||||
// Check if any of the modules has strings to update
|
||||
$count = 0;
|
||||
foreach ($modules as $module) {
|
||||
if ($strings = i18n_string_module_string_list($module)) {
|
||||
$count += i18n_string_refresh_string_list($strings);
|
||||
|
||||
}
|
||||
// Call module refresh if exists
|
||||
module_invoke($module, 'i18n_string_refresh', 'all');
|
||||
}
|
||||
if ($count) {
|
||||
drupal_set_message(format_plural($count, 'Refreshed one string for enabled modules.', 'Refreshed @count strings for the enabled modules.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge uninstalled modules.
|
||||
*/
|
||||
function i18n_string_refresh_uninstalled_modules($modules) {
|
||||
foreach ($modules as $module) {
|
||||
// If the module defines any textgroup, purge all strings.
|
||||
module_load_include('i18n.inc', $module);
|
||||
if ($string_info = module_invoke($module, 'i18n_string_info')) {
|
||||
foreach ($string_info as $group => $group_info) {
|
||||
i18n_string_refresh_reset($group);
|
||||
i18n_string_refresh_cleanup($group);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare group for refreshing
|
||||
*/
|
||||
function _i18n_string_batch_refresh_prepare($group, &$context) {
|
||||
$context['results'][$group] = array(
|
||||
'count' => i18n_string_refresh_reset($group),
|
||||
'result' => FALSE,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch operation: Refresh string list for group
|
||||
*/
|
||||
function _i18n_string_batch_refresh_list($group, &$context) {
|
||||
$count = 0;
|
||||
if ($strings = i18n_string_group_string_list($group)) {
|
||||
$count = i18n_string_refresh_string_list($strings);
|
||||
$context['results'][$group]['result'] = TRUE;
|
||||
}
|
||||
$context['results'][$group]['refresh'] = $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch operation: Invoke i18n_string_refresh
|
||||
*/
|
||||
function _i18n_string_batch_refresh_callback($group, &$context) {
|
||||
$result = module_invoke_all('i18n_string_refresh', $group);
|
||||
$count = $result ? array_sum($result) : 0;
|
||||
$context['results'][$group]['refresh'] += $count;
|
||||
if ($count) {
|
||||
$context['results'][$group]['result'] = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch callback, delete old strings
|
||||
*/
|
||||
function _i18n_string_batch_refresh_cleanup($group, &$context) {
|
||||
if (!empty($context['results'][$group]['result'])) {
|
||||
$context['results'][$group]['deleted'] = i18n_string_refresh_cleanup($group);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch operations: Print refresh summary for group
|
||||
*/
|
||||
function _i18n_string_batch_refresh_summary($group, &$context) {
|
||||
if ($context['results'][$group]['result']) {
|
||||
drupal_set_message(t("Successfully refreshed @count strings for %group", array('@count' => $context['results'][$group]['refresh'], '%group' => i18n_string_group_info($group, 'title'))));
|
||||
if (!empty($context['results'][$group]['deleted'])) {
|
||||
drupal_set_message(t('Deleted @count left over strings.', array('@count' => $context['results'][$group]['deleted'])));
|
||||
}
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t("Cannot refresh strings for %group.", array('%group' => i18n_string_group_info($group, 'title'))), 'warning');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all strings for a text group
|
||||
*/
|
||||
function i18n_string_group_string_list($group) {
|
||||
// Add strings provided by all modules on hook_string_list().
|
||||
// Note that i18n_string module itself will also collect all strings for this group's objects
|
||||
$strings = module_invoke_all('i18n_string_list', $group);
|
||||
// Invoke hook_i18n_string_list_TEXTGROUP_alter()
|
||||
drupal_alter('i18n_string_list_' . $group, $strings);
|
||||
return $strings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all strings from a module.
|
||||
*/
|
||||
function i18n_string_module_string_list($module) {
|
||||
$strings = array();
|
||||
// Try loading i18n.inc for the module and some library functions.
|
||||
module_load_include('i18n.inc', $module);
|
||||
module_load_include('i18n.inc', 'i18n_string');
|
||||
// If the module defines any textgroup, get all strings for this group
|
||||
if ($groups = module_invoke($module, 'i18n_string_info')) {
|
||||
foreach (array_keys($groups) as $group) {
|
||||
$strings = i18n_string_array_merge($strings, i18n_string_group_string_list($group));
|
||||
}
|
||||
}
|
||||
else {
|
||||
$groups = array();
|
||||
}
|
||||
// The module may implement i18n_string_list()
|
||||
if ($string_list = module_invoke($module, 'i18n_string_list', 'all')) {
|
||||
foreach ($string_list as $group => $group_strings) {
|
||||
if (!in_array($group, $groups)) {
|
||||
$strings[$group] = $group_strings;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the module defines any object that has strings in another textgroup
|
||||
if ($object_types = module_invoke($module, 'i18n_object_info')) {
|
||||
foreach ($object_types as $type => $type_info) {
|
||||
if (($group = i18n_string_object_info($type, 'textgroup')) && !in_array($group, $groups)) {
|
||||
if ($group_strings = i18n_string_object_type_string_list($type)) {
|
||||
$strings = i18n_string_array_merge($strings, $group_strings);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $strings;
|
||||
}
|
123
sites/all/modules/i18n/i18n_string/i18n_string.api.php
Normal file
123
sites/all/modules/i18n/i18n_string/i18n_string.api.php
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* API documentation file for String translation module.
|
||||
*
|
||||
* Basically we are collecting translatable strings for each text group. There are two ways a
|
||||
* module can produce this list of strings. It should be one or the other, not both.
|
||||
*
|
||||
* 1. Provide a list of objects that are translatable for that text group either defining a
|
||||
* 'list callback' for that object type or implementing hook_i18n_string_objects($type) for
|
||||
* that object type.
|
||||
*
|
||||
* 2. Provide a full list of strings for that text group by implementing
|
||||
* hook_i18n_string_list()
|
||||
*
|
||||
* Then we have hook_i18n_string_list_TEXTGROUP_alter() for other modules to alter either the
|
||||
* list of strings for a single object or the full list of strings at the end.
|
||||
*/
|
||||
|
||||
/**
|
||||
* List text groups for string translation.
|
||||
*
|
||||
* This information will be automatically produced later for hook_locale()
|
||||
*/
|
||||
function hook_i18n_string_info() {
|
||||
$groups['menu'] = array(
|
||||
'title' => t('Menu'),
|
||||
'description' => t('Translatable menu items: title and description.'),
|
||||
'format' => FALSE, // This group doesn't have strings with format
|
||||
'list' => TRUE, // This group can list all strings
|
||||
);
|
||||
return $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide list of translatable strings for text group.
|
||||
|
||||
* A module can provide either a list of translatable strings using hook_i18n_string_list() or
|
||||
* it can provide a list of objects using hook_i18n_string_objects() from which the string
|
||||
* list will be produced automatically. But not both.
|
||||
*
|
||||
* @param $group
|
||||
* Text group name.
|
||||
*/
|
||||
function hook_i18n_string_list($group) {
|
||||
if ($group == 'mygroup') {
|
||||
$strings['mygroup']['type1']['key1']['name'] = 'Name of object type1/key1';
|
||||
$strings['mygroup']['type1']['key1']['description'] = 'Description of object type1/key1';
|
||||
return $strings;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter string list for objects of text group.
|
||||
*
|
||||
* To build a list of translatable strings for a text group, we'll follow these steps:
|
||||
* 1. Invoke hook_i18n_string_list($textgroup), that will get us an array of strings
|
||||
* 2. Get the object types for that textgroup, collectin it from i18n object information.
|
||||
* @see i18n_string_group_object_types()
|
||||
* 3. For each object type, collect the full list of objects invoking hook_i18n_string_objects($type)
|
||||
* @see i18n_string_object_type_string_list()
|
||||
* If an object defines a 'list callback' function that one will be called to get the list of strings.
|
||||
* 4. For each object, collect the properties for that specific object.
|
||||
* $properties = i18n_object($type, $object)->get_properties();
|
||||
* 5. Run this hook to alter the strings for that specific object. In this case we'll pass the
|
||||
* $type and $object parameters.
|
||||
* 6. Merge all strings from all objects in an array indexed by textgroup, type, id, name
|
||||
* 7. Run this hook once again to alter *all* strings for this textgroup. In this case we
|
||||
* don't have a $type and $object parameters.
|
||||
*
|
||||
* Thus this hook is really invoked once per object and once per textgroup on top of that.
|
||||
*
|
||||
* @see i18n_string_group_string_list()
|
||||
* @see i18n_string_object_type_string_list()
|
||||
* @see i18n_menu_i18n_string_list_menu_alter()
|
||||
*
|
||||
* @param $strings
|
||||
* Associative array with current string list indexed by textgroup, type, id, name
|
||||
* @param $type
|
||||
* Object type ad defined on i18n_object_info()
|
||||
* @param $object
|
||||
* Object defined on i18n_object_info()
|
||||
*
|
||||
* These last parameters are optional. If type and object are not present
|
||||
* we are altering the full list of strings for the text group that happens once at the end.
|
||||
*/
|
||||
function hook_i18n_string_list_TEXTGROUP_alter(&$strings, $type = NULL, $object = NULL) {
|
||||
if ($type == 'menu_link' && $object) {
|
||||
if (isset($object['options']['attributes']['title'])) {
|
||||
$strings['menu']['item'][$object['mlid']]['title']['string'] = $object['link_title'];
|
||||
$strings['menu']['item'][$object['mlid']]['description']['string'] = $object['options']['attributes']['title'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List objects to collect translatable strings.
|
||||
*
|
||||
* A module can provide either a list of translatable strings using hook_i18n_string_list() or
|
||||
* it can provide a list of objects using hook_i18n_string_objects() from which the string
|
||||
* list will be produced automatically. But not both.
|
||||
*
|
||||
* @see i18n_object_info()
|
||||
* @see i18n_menu_i18n_string_objects()
|
||||
* @see i18n_string_i18n_string_list()
|
||||
*
|
||||
* @param $type string
|
||||
* Object type
|
||||
* @return $objects array
|
||||
* Associative array of objects indexed by object id
|
||||
*/
|
||||
function hook_i18n_string_objects($type) {
|
||||
if ($type == 'menu_link') {
|
||||
// All menu items that have no language and are customized.
|
||||
return db_select('menu_links', 'm')
|
||||
->fields('m')
|
||||
->condition('language', LANGUAGE_NONE)
|
||||
->condition('customized', 1)
|
||||
->execute()
|
||||
->fetchAllAssoc('mlid', PDO::FETCH_ASSOC);
|
||||
}
|
||||
}
|
105
sites/all/modules/i18n/i18n_string/i18n_string.i18n.inc
Normal file
105
sites/all/modules/i18n/i18n_string/i18n_string.i18n.inc
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Implementation of i18n hooks
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_i18n_string_objects().
|
||||
*
|
||||
* Automate object list for object types that have a 'table' property
|
||||
*/
|
||||
function i18n_string_i18n_string_objects($type) {
|
||||
if ($function = i18n_object_info($type, 'list callback')) {
|
||||
return call_user_func($function);
|
||||
}
|
||||
elseif ($table = i18n_string_object_info($type, 'table')) {
|
||||
$query = db_select($table, 's')->fields('s');
|
||||
return $query->execute()->fetchAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_i18n_string_list().
|
||||
*
|
||||
* Collect all strings from objects of this group.
|
||||
*/
|
||||
function i18n_string_i18n_string_list($group) {
|
||||
$strings = array();
|
||||
// It may be for one group or all groups
|
||||
$groups = $group == 'all' ? array_keys(i18n_string_group_info()) : array($group);
|
||||
foreach ($groups as $group) {
|
||||
// Compile strings for object types for this group
|
||||
foreach (i18n_string_group_object_types($group) as $type) {
|
||||
$type_strings = i18n_string_object_type_string_list($type);
|
||||
if ($type_strings && !empty($type_strings[$group])) {
|
||||
$strings[$group] = isset($strings[$group]) ? i18n_string_array_merge($strings[$group], $type_strings[$group]) : $type_strings[$group];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $strings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get object types for text group
|
||||
*/
|
||||
function i18n_string_group_object_types($group) {
|
||||
$types = array();
|
||||
foreach (i18n_object_info() as $type => $type_info) {
|
||||
if (!empty($type_info['string translation']) && $type_info['string translation']['textgroup'] == $group) {
|
||||
$types[] = $type;
|
||||
}
|
||||
}
|
||||
return $types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get object string list that are in this text group.
|
||||
*
|
||||
* @param $type
|
||||
* Object type
|
||||
*/
|
||||
function i18n_string_object_type_string_list($type) {
|
||||
$strings = array();
|
||||
if ($objects = module_invoke_all('i18n_string_objects', $type)) {
|
||||
foreach ($objects as $object) {
|
||||
if ($object_strings = i18n_object($type, $object)->get_properties()) {
|
||||
$strings = i18n_string_array_merge($strings, $object_strings);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $strings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges multiple arrays, recursively, and returns the merged array.
|
||||
*
|
||||
* This function is not equivalent to PHP's array_merge_recursive(),
|
||||
* as this version leaves integer keys intact.
|
||||
*
|
||||
* @see drupal_array_merge_deep(), @see array_merge_recursive()
|
||||
*
|
||||
* @param ...
|
||||
* Arrays to merge.
|
||||
* @return
|
||||
* The merged array.
|
||||
*/
|
||||
function i18n_string_array_merge() {
|
||||
$arrays = func_get_args();
|
||||
$result = array();
|
||||
|
||||
foreach ($arrays as $array) {
|
||||
foreach ($array as $key => $value) {
|
||||
// Recurse when both values are arrays.
|
||||
if (isset($result[$key]) && is_array($result[$key]) && is_array($value)) {
|
||||
$result[$key] = i18n_string_array_merge($result[$key], $value);
|
||||
}
|
||||
// Otherwise, use the latter value, overriding any previous value.
|
||||
else {
|
||||
$result[$key] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
1282
sites/all/modules/i18n/i18n_string/i18n_string.inc
Normal file
1282
sites/all/modules/i18n/i18n_string/i18n_string.inc
Normal file
File diff suppressed because it is too large
Load Diff
18
sites/all/modules/i18n/i18n_string/i18n_string.info
Normal file
18
sites/all/modules/i18n/i18n_string/i18n_string.info
Normal file
@@ -0,0 +1,18 @@
|
||||
name = String translation
|
||||
description = Provides support for translation of user defined strings.
|
||||
dependencies[] = locale
|
||||
dependencies[] = i18n
|
||||
package = Multilingual - Internationalization
|
||||
core = 7.x
|
||||
|
||||
files[] = i18n_string.admin.inc
|
||||
files[] = i18n_string.inc
|
||||
files[] = i18n_string.test
|
||||
configure = admin/config/regional/i18n/strings
|
||||
|
||||
; Information added by drupal.org packaging script on 2013-01-13
|
||||
version = "7.x-1.8"
|
||||
core = "7.x"
|
||||
project = "i18n"
|
||||
datestamp = "1358075001"
|
||||
|
260
sites/all/modules/i18n/i18n_string/i18n_string.install
Normal file
260
sites/all/modules/i18n/i18n_string/i18n_string.install
Normal file
@@ -0,0 +1,260 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Installation file for i18n_string module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_enable().
|
||||
*/
|
||||
function i18n_string_enable() {
|
||||
// Refresh locales for enabled modules
|
||||
$modules = module_implements('i18n_string_refresh');
|
||||
i18n_string_modules_enabled($modules);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_install().
|
||||
*/
|
||||
function i18n_string_install() {
|
||||
// Add a field to track whether a translation needs updating.
|
||||
module_load_install('i18n');
|
||||
i18n_install_create_fields('locales_target', array('i18n_status'));
|
||||
// Set module weight for it to run after core modules.
|
||||
db_query("UPDATE {system} SET weight = 10 WHERE name = 'i18n_string' AND type = 'module'");
|
||||
// If updating from D6, module changed name
|
||||
if (variable_get('i18n_drupal6_update')) {
|
||||
i18n_string_update_7000();
|
||||
i18n_string_update_7001();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_uninstall().
|
||||
*/
|
||||
function i18n_string_uninstall() {
|
||||
// Drop custom field.
|
||||
db_drop_field('locales_target', 'i18n_status');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_schema().
|
||||
*/
|
||||
function i18n_string_schema() {
|
||||
$schema['i18n_string'] = array(
|
||||
'description' => 'Metadata for source strings.',
|
||||
'fields' => array(
|
||||
'lid' => array(
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'description' => 'Source string ID. References {locales_source}.lid.',
|
||||
),
|
||||
'textgroup' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 50,
|
||||
'not null' => TRUE,
|
||||
'default' => 'default',
|
||||
'description' => 'A module defined group of translations, see hook_locale().',
|
||||
),
|
||||
'context' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => 'Full string ID for quick search: type:objectid:property.',
|
||||
),
|
||||
'objectid' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => 'Object ID.',
|
||||
),
|
||||
'type' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => 'Object type for this string.',
|
||||
),
|
||||
'property' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => TRUE,
|
||||
'default' => '',
|
||||
'description' => 'Object property for this string.',
|
||||
),
|
||||
'objectindex' => array(
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'description' => 'Integer value of Object ID.',
|
||||
),
|
||||
'format' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 255,
|
||||
'not null' => FALSE,
|
||||
'description' => 'The {filter_format}.format of the string.',
|
||||
),
|
||||
|
||||
),
|
||||
'primary key' => array('lid'),
|
||||
'indexes' => array(
|
||||
'group_context' => array('textgroup', 'context'),
|
||||
),
|
||||
);
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_schema_alter().
|
||||
*/
|
||||
function i18n_string_schema_alter(&$schema) {
|
||||
// Add field for tracking whether translations need updating.
|
||||
$schema['locales_target']['fields']['i18n_status'] = array(
|
||||
'description' => 'A boolean indicating whether this translation needs to be updated.',
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to upate strings
|
||||
*/
|
||||
function i18n_string_install_update_string($string) {
|
||||
$string->context = $string->type . ':' . $string->objectid . ':' . $string->property;
|
||||
$string->location = $string->textgroup . ':' . $string->context;
|
||||
$string->objectindex = (int)$string->objectid;
|
||||
drupal_write_record('i18n_string', $string, 'lid');
|
||||
drupal_write_record('locales_source', $string, 'lid');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update context for strings.
|
||||
*
|
||||
* As some string locations depend on configurable values, the field needs sometimes to be updated
|
||||
* without losing existing translations. I.e:
|
||||
* - profile fields indexed by field name.
|
||||
* - content types indexted by low level content type name.
|
||||
*
|
||||
* Example:
|
||||
* 'profile:field:oldfield:*' -> 'profile:field:newfield:*'
|
||||
*/
|
||||
function i18n_string_install_update_context($oldname, $newname) {
|
||||
// Get context replacing '*' with empty string.
|
||||
$oldcontext = explode(':', $oldname);
|
||||
$newcontext = explode(':', $newname);
|
||||
/*
|
||||
i18n_string_context(str_replace('*', '', $oldname));
|
||||
$newcontext = i18n_string_context(str_replace('*', '', $newname));
|
||||
*/
|
||||
// Get location with placeholders.
|
||||
foreach (array('textgroup', 'type', 'objectid', 'property') as $index => $field) {
|
||||
if ($oldcontext[$index] != $newcontext[$index]) {
|
||||
$replace[$field] = $newcontext[$index];
|
||||
}
|
||||
}
|
||||
|
||||
// Query and replace if there are any fields. It is possible that under some circumstances fields are the same
|
||||
if (!empty($replace)) {
|
||||
$textgroup = array_shift($oldcontext);
|
||||
$context = str_replace('*', '%', implode(':', $oldcontext));
|
||||
$count = 0;
|
||||
$query = db_select('i18n_string', 's')
|
||||
->fields('s')
|
||||
->condition('s.textgroup', $textgroup)
|
||||
->condition('s.context', $context, 'LIKE');
|
||||
|
||||
foreach ($query->execute()->fetchAll() as $source) {
|
||||
foreach ($replace as $field => $value) {
|
||||
$source->$field = $value;
|
||||
}
|
||||
// Recalculate location, context, objectindex
|
||||
$source->context = $source->type . ':' . $source->objectid . ':' . $source->property;
|
||||
$source->location = $source->textgroup . ':' . $source->context;
|
||||
$source->objectindex = (int)$source->objectid;
|
||||
// Update source string.
|
||||
$update = array(
|
||||
'textgroup' => $source->textgroup,
|
||||
'context' => $source->context,
|
||||
);
|
||||
db_update('locales_source')
|
||||
->fields($update + array('location' => $source->location))
|
||||
->condition('lid', $source->lid)
|
||||
->execute();
|
||||
|
||||
// Update object data.
|
||||
db_update('i18n_string')
|
||||
->fields($update + array(
|
||||
'type' => $source->type,
|
||||
'objectid' => $source->objectid,
|
||||
'property' => $source->property,
|
||||
'objectindex' => $source->objectindex,
|
||||
))
|
||||
->condition('lid', $source->lid)
|
||||
->execute();
|
||||
$count++;
|
||||
}
|
||||
drupal_set_message(t('Updated @count string names from %oldname to %newname.', array('@count' => $count, '%oldname' => $oldname, '%newname' => $newname)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate fields from old locale table (textgroup, location) and drop indexes from locales_source
|
||||
*/
|
||||
function i18n_string_update_7000() {
|
||||
// @todo Update from d6
|
||||
variable_del('i18nstrings_allowed_textgroups');
|
||||
// If we've got old table from D6, move data to new one
|
||||
if (db_table_exists('i18n_strings')) {
|
||||
// First of all clean up strings that don't have a locale source, see http://drupal.org/node/1186692
|
||||
db_query("DELETE FROM {i18n_strings} WHERE lid NOT IN (SELECT lid FROM {locales_source})");
|
||||
db_query("INSERT INTO {i18n_string}(lid, objectid, type, property, objectindex, format) SELECT lid, objectid, type, property, objectindex, format FROM {i18n_strings}");
|
||||
// Update and populate textgroup field
|
||||
db_query("UPDATE {i18n_string} s SET s.textgroup = (SELECT l.textgroup FROM {locales_source} l WHERE l.lid = s.lid)");
|
||||
// Populate context field. We could use CONCAT_WS but I guess this is more standard.
|
||||
db_query("UPDATE {i18n_string} SET context = CONCAT(type, ':', objectid, ':', property)");
|
||||
db_query("UPDATE {locales_source} s INNER JOIN {i18n_string} i ON s.lid = i.lid SET s.context = i.context");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop obsoleted i18n_strings table if exists
|
||||
*/
|
||||
function i18n_string_update_7001() {
|
||||
if (db_table_exists('i18n_strings')) {
|
||||
db_drop_table('i18n_strings');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes for update script
|
||||
*/
|
||||
// Added fields: context, textgroup
|
||||
//
|
||||
// Drop all indexes from locales_source
|
||||
// Update format field
|
||||
// Update string names: profile, cck => field
|
||||
// Update string names:
|
||||
|
||||
/**
|
||||
* Old strings to update. All these will be handled by i18n_field module
|
||||
*
|
||||
* 'cck:field:'. $content_type .'-'. $field_name .':widget_label'
|
||||
* --> 'field:$field_name:$bundle:label' (though not used atm)
|
||||
* 'cck:field:'. $content_type .'-'. $field_name .':widget_description'
|
||||
* --> 'field:$field_name:$bundle:description'
|
||||
* 'cck:fieldgroup:'. $content_type .'-'. $group_name .':display_description'
|
||||
* 'cck:fieldgroup:'. $content_type .'-'. $group_name .':form_description', $group['settings']['form']['description']);
|
||||
*
|
||||
* Profile:
|
||||
* profile:field:$field_name:title|explanation|options
|
||||
* "profile:category", $field->category
|
||||
*
|
||||
* Node type
|
||||
* nodetype:type:[type]:[property] -> node:type:[type]:[property]
|
||||
* Property names: title -> title_label
|
||||
*/
|
940
sites/all/modules/i18n/i18n_string/i18n_string.module
Normal file
940
sites/all/modules/i18n/i18n_string/i18n_string.module
Normal file
@@ -0,0 +1,940 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Internationalization (i18n) package - translatable strings.
|
||||
*
|
||||
* Object oriented string translation using locale and textgroups. As opposed to core locale strings,
|
||||
* all strings handled by this module will have a unique id (name), composed by several parts
|
||||
*
|
||||
* A string name or string id will have the form 'textgroup:type:objectid:property'. Examples:
|
||||
*
|
||||
* - 'profile:field:profile_name:title', will be the title for the profile field 'profile_name'
|
||||
* - 'taxonomy:term:tid:name', will be the name for the taxonomy term tid
|
||||
* - 'views:view_name:display_id:footer', footer text
|
||||
*
|
||||
* Notes:
|
||||
* - The object id must be an integer. This is intended for quick indexing of some properties
|
||||
*
|
||||
* Some concepts
|
||||
* - Textgroup. Group the string belongs to, defined by locale hook.
|
||||
* - Location. Unique id of the string for this textgroup.
|
||||
* - Name. Unique absolute id of the string: textgroup + location.
|
||||
* - Context. Object with textgroup, type, objectid, property.
|
||||
*
|
||||
* Default language
|
||||
* - Default language may be English or not. It will be the language set as default.
|
||||
* Source strings will be stored in default language.
|
||||
* - In the traditional i18n use case you shouldn't change the default language once defined.
|
||||
*
|
||||
* Default language changes
|
||||
* - You might result in the need to change the default language at a later point.
|
||||
* - Enabling translation of default language will curcumvent previous limitations.
|
||||
* - Check i18n_string_translate_langcode() for more details.
|
||||
*
|
||||
* The API other modules to translate/update/remove user defined strings consists of
|
||||
*
|
||||
* @see i18n_string($name, $string, $langcode)
|
||||
* @see i18n_string_update($name, $string, $format)
|
||||
* @see i18n_string_remove($name, $string)
|
||||
*
|
||||
* @author Jose A. Reyero, 2007
|
||||
*/
|
||||
|
||||
/**
|
||||
* Translated string is current.
|
||||
*/
|
||||
define('I18N_STRING_STATUS_CURRENT', 0);
|
||||
|
||||
/**
|
||||
* Translated string needs updating as the source has been edited.
|
||||
*/
|
||||
define('I18N_STRING_STATUS_UPDATE', 1);
|
||||
|
||||
/**
|
||||
* Source string is obsoleted, cannot be found anymore. To be deleted.
|
||||
*/
|
||||
define('I18N_STRING_STATUS_DELETE', 2);
|
||||
|
||||
/**
|
||||
* Special string formats/filters: Run through filter_xss
|
||||
*/
|
||||
define('I18N_STRING_FILTER_XSS', 'FILTER_XSS');
|
||||
|
||||
/**
|
||||
* Special string formats/filters: Run through filter_xss_admin
|
||||
*/
|
||||
define('I18N_STRING_FILTER_XSS_ADMIN', 'FILTER_XSS_ADMIN');
|
||||
|
||||
/**
|
||||
* Implements hook_help().
|
||||
*/
|
||||
function i18n_string_help($path, $arg) {
|
||||
switch ($path) {
|
||||
case 'admin/help#i18n_string':
|
||||
$output = '<p>' . t('This module adds support for other modules to translate user defined strings. Depending on which modules you have enabled that use this feature you may see different text groups to translate.') . '<p>';
|
||||
$output .= '<p>' . t('This works differently to Drupal standard localization system: The strings will be translated from the <a href="@configure-strings">source language</a>, which defaults to the site default language (it may not be English), so changing the default language may cause all these translations to be broken.', array('@configure-strings' => url('admin/config/regional/i18n/strings'))) . '</p>';
|
||||
$output .= '<ul>';
|
||||
$output .= '<li>' . t('To search and translate strings, use the <a href="@translate-interface">translation interface</a> pages.', array('@translate-interface' => url('admin/config/regional/translate'))) . '</li>';
|
||||
$output .= '<li>' . t('If you are missing strings to translate, use the <a href="@refresh-strings">refresh strings</a> page.', array('@refresh-strings' => url('admin/build/translate/refresh'))) . '</li>';
|
||||
$output .= '</ul>';
|
||||
$output .= '<p>' . t('Read more on the <em>Internationalization handbook</em>: <a href="http://drupal.org/node/313293">Translating user defined strings</a>.') . '</p>';
|
||||
return $output;
|
||||
|
||||
case 'admin/config/regional/translate/i18n_string':
|
||||
$output = '<p>' . t('On this page you can refresh and update values for user defined strings.') . '</p>';
|
||||
$output .= '<ul>';
|
||||
$output .= '<li>' . t('Use the refresh option when you are missing strings to translate for a given text group. All the strings will be re-created keeping existing translations.') . '</li>';
|
||||
$output .= '<li>' . t('Use the update option when some of the strings had been previously translated with the localization system, but the translations are not showing up for the configurable strings.') . '</li>';
|
||||
$output .= '</ul>';
|
||||
$output .= '<p>' . t('To search and translate strings, use the <a href="@translate-interface">translation interface</a> pages.', array('@translate-interface' => url('admin/config/regional/translate'))) . '</p>';
|
||||
$output .= '<p>' . t('<strong>Important:</strong> To configure which text formats are safe for translation, visit the <a href="@configure-strings">configure strings</a> page before refreshing your strings.', array('@configure-strings' => url('admin/config/regional/i18n/strings'))) . '</p>';
|
||||
return $output;
|
||||
|
||||
case 'admin/config/regional/language':
|
||||
$output = '<p>' . t('<strong>Warning</strong>: Changing the default language may have unwanted effects on string translations. Check also the <a href="@configure-strings">source language</a> for translations and read more about <a href="@i18n_string-help">String translation</a>', array('@configure-strings' => url('admin/config/regional/i18n/strings'), '@i18n_string-help' => url('admin/help/i18n_string'))) . '</p>';
|
||||
return $output;
|
||||
case 'admin/config/regional/i18n/strings':
|
||||
$output = '<p>' . t('When translating user defined strings that have a text format associated, translators will be able to edit the text before it is filtered which may be a security risk for some filters. An obvious example is when using the PHP filter but other filters may also be dangerous.') . '</p>';
|
||||
$output .= '<p>' . t('As a general rule <strong>do not allow any filtered text to be translated unless the translators already have access to that text format</strong>. However if you are doing all your translations through this site\'s translation UI or the Localization client, and never importing translations for other textgroups than <i>default</i>, filter access will be checked for translators on every translation page.') . '</p>';
|
||||
$output .= '<p>' . t('<strong>Important:</strong> After disallowing some text format, use the <a href="@refresh-strings">refresh strings</a> page so forbidden strings are deleted and not allowed anymore for translators.', array('@refresh-strings' => url('admin/config/regional/translate/i18n_string'))) . '</p>';
|
||||
return $output;
|
||||
case 'admin/config/filters':
|
||||
return '<p>' . t('After updating your text formats do not forget to review the list of formats allowed for string translations on the <a href="@configure-strings">configure translatable strings</a> page.', array('@configure-strings' => url('admin/config/regional/i18n/strings'))) . '</p>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*/
|
||||
function i18n_string_menu() {
|
||||
$items['admin/config/regional/translate/i18n_string'] = array(
|
||||
'title' => 'Strings',
|
||||
'description' => 'Refresh user defined strings.',
|
||||
'weight' => 20,
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('i18n_string_admin_refresh_form'),
|
||||
'file' => 'i18n_string.admin.inc',
|
||||
'access arguments' => array('translate interface'),
|
||||
);
|
||||
$items['admin/config/regional/i18n/strings'] = array(
|
||||
'title' => 'Strings',
|
||||
'description' => 'Options for user defined strings.',
|
||||
'weight' => 20,
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('variable_edit_form', array('i18n_string_allowed_formats', 'i18n_string_source_language')),
|
||||
'access arguments' => array('administer site configuration'),
|
||||
);
|
||||
// AJAX callback path for strings.
|
||||
$items['i18n_string/save'] = array(
|
||||
'title' => 'Save string',
|
||||
'page callback' => 'i18n_string_l10n_client_save_string',
|
||||
'access arguments' => array('use on-page translation'),
|
||||
'file' => 'i18n_string.pages.inc',
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_menu_alter().
|
||||
*
|
||||
* Take over the locale translation page.
|
||||
*/
|
||||
function i18n_string_menu_alter(&$items) {
|
||||
$items['admin/config/regional/translate/edit/%'] = array(
|
||||
'title' => 'Edit string',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('i18n_string_locale_translate_edit_form', 5),
|
||||
'access arguments' => array('translate interface'),
|
||||
'file' => 'i18n_string.pages.inc',
|
||||
'file path' => drupal_get_path('module', 'i18n_string'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_hook_info().
|
||||
*/
|
||||
function i18n_string_hook_info() {
|
||||
$hooks['i18n_string_info'] =
|
||||
$hooks['i18n_string_list'] =
|
||||
$hooks['i18n_string_refresh'] =
|
||||
$hooks['i18n_string_objects'] = array(
|
||||
'group' => 'i18n',
|
||||
);
|
||||
return $hooks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_locale().
|
||||
*
|
||||
* Provide the information from i18n_string groups to locale module
|
||||
*/
|
||||
function i18n_string_locale($op = 'groups') {
|
||||
if ($op == 'groups') {
|
||||
$groups = array();
|
||||
foreach (i18n_string_group_info() as $name => $info) {
|
||||
$groups[$name] = $info['title'];
|
||||
}
|
||||
return $groups;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_permission().
|
||||
*/
|
||||
function i18n_string_permission() {
|
||||
return array(
|
||||
'translate user-defined strings' => array(
|
||||
'title' => t('Translate user-defined strings'),
|
||||
'description' => t('Translate user-defined strings that are created as part of content or configuration.'),
|
||||
'restrict access' => TRUE,
|
||||
),
|
||||
'translate admin strings' => array(
|
||||
'title' => t('Translate admin strings'),
|
||||
'description' => t('Translate administrative strings with a very permissive XSS/HTML filter that allows all HTML tags.'),
|
||||
'restrict access' => TRUE,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_modules_enabled().
|
||||
*/
|
||||
function i18n_string_modules_enabled($modules) {
|
||||
module_load_include('admin.inc', 'i18n_string');
|
||||
i18n_string_refresh_enabled_modules($modules);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_modules_uninstalled().
|
||||
*/
|
||||
function i18n_string_modules_uninstalled($modules) {
|
||||
module_load_include('admin.inc', 'i18n_string');
|
||||
i18n_string_refresh_uninstalled_modules($modules);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_form_FORM_ID_alter()
|
||||
*/
|
||||
function i18n_string_form_l10n_client_form_alter(&$form, &$form_state) {
|
||||
$form['#action'] = url('i18n_string/save');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_form_FORM_ID_alter()
|
||||
*/
|
||||
function i18n_string_form_locale_translate_export_po_form_alter(&$form, $form_state) {
|
||||
$names = locale_language_list('name', TRUE);
|
||||
if (i18n_string_source_language() != 'en' && array_key_exists('en', $names)) {
|
||||
$form['langcode']['#options']['en'] = $names['en'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_form_FORM_ID_alter()
|
||||
*/
|
||||
function i18n_string_form_locale_translate_import_form_alter(&$form, $form_state) {
|
||||
if (i18n_string_source_language() != 'en') {
|
||||
$names = locale_language_list('name', TRUE);
|
||||
if (array_key_exists('en', $names)) {
|
||||
$form['import']['langcode']['#options'][t('Already added languages')]['en'] = $names['en'];
|
||||
}
|
||||
else {
|
||||
$form['import']['langcode']['#options'][t('Languages not yet added')]['en'] = t('English');
|
||||
}
|
||||
}
|
||||
$form['#submit'][] = 'i18n_string_locale_translate_import_form_submit';
|
||||
}
|
||||
|
||||
/**
|
||||
* Update string data after import form submit
|
||||
*/
|
||||
function i18n_string_locale_translate_import_form_submit($form, &$form_state) {
|
||||
if (!drupal_get_messages('error', FALSE) && i18n_string_group_info($form_state['values']['group'])) {
|
||||
i18n_string_textgroup($form_state['values']['group'])->update_check();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if translation is required for this language code.
|
||||
*
|
||||
* Translation is required when default language is different from the given
|
||||
* language, or when default language translation is explicitly enabled.
|
||||
*
|
||||
* No UI is provided to enable translation of default language. On the other
|
||||
* hand, you can enable/disable translation for a specific language by adding
|
||||
* the following to your settings.php
|
||||
*
|
||||
* @param $langcode
|
||||
* Optional language code to check. It will default to current request language.
|
||||
* @code
|
||||
* // Enable translation of specific language. Language code is 'xx'
|
||||
* $conf['i18n_string_translate_langcode_xx'] = TRUE;
|
||||
* // Disable translation of specific language. Language code is 'yy'
|
||||
* $conf['i18n_string_translate_langcode_yy'] = FALSE;
|
||||
* @endcode
|
||||
*/
|
||||
function i18n_string_translate_langcode($langcode = NULL) {
|
||||
$translate = &drupal_static(__FUNCTION__);
|
||||
$langcode = isset($langcode) ? $langcode : i18n_langcode();
|
||||
if (!isset($translate[$langcode])) {
|
||||
$translate[$langcode] = variable_get('i18n_string_translate_langcode_' . $langcode, i18n_string_source_language() != $langcode);
|
||||
}
|
||||
return $translate[$langcode];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create string class from string name
|
||||
*/
|
||||
function i18n_string_build($name, $string = NULL) {
|
||||
list ($group, $context) = i18n_string_context($name);
|
||||
return i18n_string_textgroup($group)->build_string($context, $string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update / create translation source for user defined strings.
|
||||
*
|
||||
* @param $name
|
||||
* Array or string concatenated with ':' that contains textgroup and string context
|
||||
* @param $string
|
||||
* Source string in default language. Default language may or may not be English.
|
||||
* Array of key => string to update multiple strings at once
|
||||
* @param $options
|
||||
* Array with additional options:
|
||||
* - 'format', String format if the string has text format
|
||||
* - 'messages', Whether to print out status messages
|
||||
*/
|
||||
function i18n_string_update($name, $string, $options = array()) {
|
||||
if (is_array($string)) {
|
||||
return i18n_string_multiple('update', $name, $string, $options);
|
||||
}
|
||||
else {
|
||||
list($textgroup, $context) = i18n_string_context($name);
|
||||
return i18n_string_textgroup($textgroup)->context_update($context, $string, $options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update context for strings.
|
||||
*
|
||||
* As some string locations depend on configurable values, the field needs sometimes to be updated
|
||||
* without losing existing translations. I.e:
|
||||
* - profile fields indexed by field name.
|
||||
* - content types indexted by low level content type name.
|
||||
*
|
||||
* Example:
|
||||
* 'profile:field:oldfield:*' -> 'profile:field:newfield:*'
|
||||
*/
|
||||
function i18n_string_update_context($oldname, $newname) {
|
||||
module_load_install('i18n_string');
|
||||
return i18n_string_install_update_context($oldname, $newname);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get textgroup handler
|
||||
*/
|
||||
function i18n_string_textgroup($textgroup) {
|
||||
$groups = &drupal_static(__FUNCTION__);
|
||||
if (!isset($groups[$textgroup])) {
|
||||
$class = i18n_string_group_info($textgroup, 'class', 'i18n_string_textgroup_default');
|
||||
$groups[$textgroup] = new $class($textgroup);
|
||||
}
|
||||
return $groups[$textgroup];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a string format is allowed for translation.
|
||||
*/
|
||||
function i18n_string_allowed_format($format_id = NULL) {
|
||||
if (!$format_id || $format_id === I18N_STRING_FILTER_XSS || $format_id === I18N_STRING_FILTER_XSS_ADMIN) {
|
||||
return TRUE;
|
||||
}
|
||||
else {
|
||||
// Check the format still exists an it is in the allowed formats list.
|
||||
return filter_format_load($format_id) && in_array($format_id, variable_get('i18n_string_allowed_formats', array(filter_fallback_format())), TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert string name into textgroup and string context
|
||||
*
|
||||
* @param $name
|
||||
* Array or string concatenated with ':' that contains textgroup and string context
|
||||
* @param $replace
|
||||
* Parameter to replace the placeholder ('*') if we are dealing with multiple strings
|
||||
* Or parameter to append to context if there's no placeholder
|
||||
*
|
||||
* @return array
|
||||
* The first element will be the text group name
|
||||
* The second one will be an array with string name elements, without textgroup
|
||||
*/
|
||||
function i18n_string_context($name, $replace = NULL) {
|
||||
$parts = is_array($name) ? $name : explode(':', $name);
|
||||
if ($replace) {
|
||||
$key = array_search('*', $parts);
|
||||
if ($key !== FALSE) {
|
||||
$parts[$key] = $replace;
|
||||
}
|
||||
elseif (count($parts) < 4) {
|
||||
array_push($parts, $replace);
|
||||
}
|
||||
}
|
||||
$textgroup = array_shift($parts);
|
||||
$context = $parts;
|
||||
return array($textgroup, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark form element as localizable
|
||||
*/
|
||||
function i18n_string_element_mark(&$element) {
|
||||
$description = '<strong>' . t('This string will be localizable. You can translate it using the <a href="@translate-interface">translate interface</a> pages.', array('@translate-interface' => url('admin/config/regional/translate/translate'))) . '</strong>';
|
||||
if (empty($element['#description'])) {
|
||||
$element['#description'] = $description;
|
||||
}
|
||||
else {
|
||||
$element['#description'] .= ' ' . $description;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get source string object.
|
||||
*
|
||||
* This returns the i18nstring object only when it has a source.
|
||||
*
|
||||
* @return i18n_string_object
|
||||
*/
|
||||
function i18n_string_get_source($name) {
|
||||
return i18n_string_build($name)->get_source();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get full string object.
|
||||
*
|
||||
* Builds string and loads the source if available.
|
||||
*
|
||||
* @return i18n_string_object
|
||||
*/
|
||||
function i18n_string_get_string($name, $default = NULL) {
|
||||
$i18nstring = i18n_string_build($name, $default);
|
||||
$i18nstring->get_source();
|
||||
return $i18nstring;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get full string object by lid.
|
||||
*/
|
||||
function i18n_string_get_by_lid($lid) {
|
||||
$strings = i18n_string_load_multiple(array('lid' => $lid));
|
||||
return reset($strings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load multiple strings, including string source
|
||||
*
|
||||
* @param $conditions
|
||||
* Array of conditions for i18n_string table.
|
||||
*
|
||||
* @return $strings
|
||||
* List of i18n string objects
|
||||
*/
|
||||
function i18n_string_load_multiple($conditions) {
|
||||
// The primary table here will be i18n_string, though we add source too.
|
||||
$query = db_select('i18n_string', 'i')
|
||||
->fields('i');
|
||||
$query->leftJoin('locales_source', 's', 'i.lid = s.lid');
|
||||
$query->fields('s', array('source', 'version', 'location'));
|
||||
// Add text group condition and add conditions to the query
|
||||
foreach ($conditions as $field => $value) {
|
||||
$alias = in_array($field, array('source', 'version', 'location')) ? 's' : 'i';
|
||||
$query->condition($alias . '.' . $field, $value);
|
||||
}
|
||||
// this patch is a workaround for core file bug in file
|
||||
// include/database/prefetch.inc (see: http://drupal.org/node/1567216)
|
||||
// return $query->execute()->fetchAll(PDO::FETCH_CLASS, 'i18n_string_object');
|
||||
$stmt = $query->execute();
|
||||
$stmt->setFetchMode(PDO::FETCH_CLASS, 'i18n_string_object');
|
||||
return $stmt->fetchAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get textgroup info, from hook_locale('info')
|
||||
*
|
||||
* @param $group
|
||||
* Text group name.
|
||||
* @param $default
|
||||
* Default value to return for a property if not set.
|
||||
*/
|
||||
function i18n_string_group_info($group = NULL, $property = NULL, $default = NULL) {
|
||||
$info = &drupal_static(__FUNCTION__ , NULL);
|
||||
|
||||
if (!isset($info)) {
|
||||
$info = module_invoke_all('i18n_string_info');
|
||||
drupal_alter('i18n_string_info', $info);
|
||||
}
|
||||
|
||||
if ($group && $property) {
|
||||
return isset($info[$group][$property]) ? $info[$group][$property] : $default;
|
||||
}
|
||||
elseif ($group) {
|
||||
return isset($info[$group]) ? $info[$group] : array();
|
||||
}
|
||||
else {
|
||||
return $info;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Translate / update multiple strings
|
||||
*
|
||||
* @param $strings
|
||||
* Array of name => string pairs
|
||||
*/
|
||||
function i18n_string_multiple($operation, $name, $strings, $options = array()) {
|
||||
$result = array();
|
||||
// Strings may be an array of properties, we need to shift it
|
||||
if ($operation == 'remove') {
|
||||
$strings = array_flip($strings);
|
||||
}
|
||||
foreach ($strings as $key => $string) {
|
||||
list($textgroup, $context) = i18n_string_context($name, $key);
|
||||
array_unshift($context, $textgroup);
|
||||
$result[$key] = call_user_func('i18n_string_' . $operation, $context, $string, $options);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup i18napi
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get translation for user defined string.
|
||||
*
|
||||
* This function is intended to return translations for plain strings that have NO text format
|
||||
*
|
||||
* @param $name
|
||||
* Array or string concatenated with ':' that contains textgroup and string context
|
||||
* @param $string
|
||||
* String in default language or array of strings to be translated
|
||||
* @param $options
|
||||
* An associative array of additional options, with the following keys:
|
||||
* - 'langcode' (defaults to the current language) The language code to translate to a language other than what is used to display the page.
|
||||
* - 'filter' Filtering callback to apply to the translated string only
|
||||
* - 'format' Input format to apply to the translated string only
|
||||
* - 'callback' Callback to apply to the result (both to translated or untranslated string
|
||||
* - 'sanitize' Whether to filter the translation applying the text format if any, default is TRUE
|
||||
* - 'sanitize default' Whether to filter the default value if no translation found, default is FALSE
|
||||
*/
|
||||
function i18n_string_translate($name, $string, $options = array()) {
|
||||
if (is_array($string)) {
|
||||
return i18n_string_translate_list($name, $string, $options);
|
||||
}
|
||||
else {
|
||||
$options['langcode'] = $langcode = isset($options['langcode']) ? $options['langcode'] : i18n_langcode();
|
||||
if (i18n_string_translate_langcode($langcode)) {
|
||||
list($textgroup, $context) = i18n_string_context($name);
|
||||
$translation = i18n_string_textgroup($textgroup)->context_translate($context, $string, $options);
|
||||
// Add for l10n client if available, we pass translation object that contains the format
|
||||
i18n_string_l10n_client_add($translation, $langcode);
|
||||
return $translation->format_translation($langcode, $options);
|
||||
}
|
||||
else {
|
||||
// If we don't want to translate to this language, format and return
|
||||
$options['sanitize'] = !empty($options['sanitize default']);
|
||||
return i18n_string_format($string, $options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check user access to translate a specific string.
|
||||
*
|
||||
* If the string has a format the user is not allowed to edit, it will return FALSE
|
||||
*
|
||||
* @param $string_format;
|
||||
* String object or $format_id
|
||||
*/
|
||||
function i18n_string_translate_access($string_format, $account = NULL) {
|
||||
$format_id = is_object($string_format) ? i18n_object_field($string_format, 'format') : $string_format;
|
||||
return user_access('translate interface', $account) &&
|
||||
(empty($format_id) || i18n_string_allowed_format($format_id) && ($format = filter_format_load($format_id)) && filter_access($format, $account));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether there is any problem for the user to translate a specific string.
|
||||
*
|
||||
* Here we assume the user has 'translate interface' access that should have
|
||||
* been checked for the page. Possible reasons a user cannot translate a string:
|
||||
*
|
||||
* @param $i18nstring
|
||||
* String object.
|
||||
* @param $account
|
||||
* Optional user account, defaults to current user.
|
||||
*
|
||||
* @return
|
||||
* None or empty string if the user has access to translate the string.
|
||||
* Message if the user cannot translate that string.
|
||||
*/
|
||||
function i18n_string_translate_check_string($i18nstring, $account = NULL) {
|
||||
if (!user_access('translate interface', $account) || !user_access('translate user-defined strings', $account)) {
|
||||
return t('This is a user-defined string. You are not allowed to translate these strings.');
|
||||
}
|
||||
elseif (!empty($i18nstring->format)) {
|
||||
if (!i18n_string_allowed_format($i18nstring->format)) {
|
||||
$format = filter_format_load($i18nstring->format);
|
||||
return t('This string uses the %name text format. Strings with this format are not allowed for translation.', array('%name' => $format->name));
|
||||
}
|
||||
elseif ($format = filter_format_load($i18nstring->format)) {
|
||||
// It is a text format, check user access to that text format.
|
||||
if (!filter_access($format, $account)) {
|
||||
return t('This string uses the %name text format. You are not allowed to translate or edit texts with this format.', array('%name' => $format->name));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// This is one of our special formats, I18N_STRING_FILTER_*
|
||||
if ($i18nstring->format == I18N_STRING_FILTER_XSS_ADMIN && !user_access('translate admin strings', $account)) {
|
||||
return t('The source string is an administrative string. You are not allowed to translate these strings.');
|
||||
}
|
||||
}
|
||||
}
|
||||
// No error message, it should be OK to translate.
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the resulting translation or the default string applying callbacks
|
||||
*
|
||||
* @param $string
|
||||
* Text string.
|
||||
* @param $options
|
||||
* Array of options for string formatting:
|
||||
* - 'format', text format to apply to the string, defaults to none.
|
||||
* - 'sanitize', whether to apply the text format, defaults to TRUE.
|
||||
* - 'cache', text format parameter.
|
||||
* - 'langcode', text format parameter, defaults to current page language.
|
||||
* - 'allowed_tags', allowed HTML tags when format is I18N_STRING_FILTER_XSS
|
||||
*/
|
||||
function i18n_string_format($string, $options = array()) {
|
||||
$options += array('langcode' => i18n_langcode(), 'format' => FALSE, 'sanitize' => TRUE, 'cache' => FALSE);
|
||||
// Apply format and callback
|
||||
if ($string) {
|
||||
if ($options['sanitize']) {
|
||||
if ($options['format']) {
|
||||
// Handle special format values (xss, xss_admin)
|
||||
switch ($options['format']) {
|
||||
case I18N_STRING_FILTER_XSS:
|
||||
$string = !empty($options['allowed_tags']) ? filter_xss($string, $options['allowed_tags']) : filter_xss($string);
|
||||
break;
|
||||
case I18N_STRING_FILTER_XSS_ADMIN:
|
||||
$string = filter_xss_admin($string);
|
||||
break;
|
||||
default:
|
||||
$string = check_markup($string, $options['format'], $options['langcode'], $options['cache']);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$string = check_plain($string);
|
||||
}
|
||||
}
|
||||
if (isset($options['callback'])) {
|
||||
$string = call_user_func($options['callback'], $string);
|
||||
}
|
||||
}
|
||||
// Finally, apply prefix and suffix
|
||||
$options += array('prefix' => '', 'suffix' => '');
|
||||
return $options['prefix'] . $string . $options['suffix'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filtered translation.
|
||||
*
|
||||
* This function is intended to return translations for strings that have a text format
|
||||
*
|
||||
* @param $name
|
||||
* Array or string concatenated with ':' that contains textgroup and string context
|
||||
* @param $default
|
||||
* Default string to return if not found, already filtered
|
||||
* @param $options
|
||||
* Array with additional options.
|
||||
*/
|
||||
function i18n_string_text($name, $default, $options = array()) {
|
||||
$options += array('format' => filter_fallback_format(), 'sanitize' => TRUE);
|
||||
return i18n_string_translate($name, $default, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translation for plain string. In case it finds a translation it applies check_plain() to it
|
||||
*
|
||||
* @param $name
|
||||
* Array or string concatenated with ':' that contains textgroup and string context
|
||||
* @param $default
|
||||
* Default string to return if not found
|
||||
* @param $options
|
||||
* Array with additional options
|
||||
*/
|
||||
function i18n_string_plain($name, $default, $options = array()) {
|
||||
$options += array('filter' => 'check_plain');
|
||||
return i18n_string_translate($name, $default, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get source language code for translations
|
||||
*/
|
||||
function i18n_string_source_language() {
|
||||
return variable_get('i18n_string_source_language', language_default('language'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Translation for list of options
|
||||
*
|
||||
* @param $options
|
||||
* Array with additional options, some changes
|
||||
* - 'index' => field that will be mapped to the array key (defaults to 'property')
|
||||
*/
|
||||
function i18n_string_translate_list($name, $strings, $options = array()) {
|
||||
$options['langcode'] = $langcode = isset($options['langcode']) ? $options['langcode'] : i18n_langcode();
|
||||
// If language is default, just return
|
||||
if (i18n_string_translate_langcode($langcode)) {
|
||||
// Get textgroup context, preserve placeholder
|
||||
list($textgroup, $context) = i18n_string_context($name, '*');
|
||||
$translations = i18n_string_textgroup($textgroup)->multiple_translate($context, $strings, $options);
|
||||
// Add for l10n client if available, we pass translation object that contains the format
|
||||
foreach ($translations as $index => $translation) {
|
||||
i18n_string_l10n_client_add($translation, $langcode);
|
||||
$strings[$index] = $translation->format_translation($langcode, $options);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Format and return
|
||||
foreach ($strings as $key => $string) {
|
||||
$strings[$key] = i18n_string_format($string, $options);
|
||||
}
|
||||
}
|
||||
return $strings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove source and translations for user defined string.
|
||||
*
|
||||
* Though for most strings the 'name' or 'string id' uniquely identifies that string,
|
||||
* there are some exceptions (like profile categories) for which we need to use the
|
||||
* source string itself as a search key.
|
||||
*
|
||||
* @param $name
|
||||
* String name
|
||||
* @param $string
|
||||
* Optional source string (string in default language).
|
||||
* Array of string properties to remove
|
||||
*/
|
||||
function i18n_string_remove($name, $string = NULL, $options = array()) {
|
||||
if (is_array($string)) {
|
||||
return i18n_string_multiple('remove', $name, $string, $options);
|
||||
}
|
||||
else {
|
||||
list($textgroup, $context) = i18n_string_context($name);
|
||||
return i18n_string_textgroup($textgroup)->context_remove($context, $string, $options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @} End of "ingroup i18napi".
|
||||
*/
|
||||
|
||||
/*** l10n client related functions ***/
|
||||
|
||||
/**
|
||||
* Add string to l10n strings if enabled and allowed for this string
|
||||
*
|
||||
* @param $context
|
||||
* String object
|
||||
*/
|
||||
function i18n_string_l10n_client_add($string, $langcode) {
|
||||
// If current language add to l10n client list for later on page translation.
|
||||
// If langcode translation was disabled we are not supossed to reach here.
|
||||
if (($langcode == i18n_langcode()) && function_exists('l10_client_add_string_to_page') && user_access('translate interface')) {
|
||||
if (!$string->check_translate_access()) {
|
||||
$translation = $string->get_translation($langcode);
|
||||
$source = !empty($string->source) ? $string->source : $string->string;
|
||||
l10_client_add_string_to_page($source, $translation ? $translation : TRUE, $string->textgroup, $string->context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get information about object string translation
|
||||
*/
|
||||
function i18n_string_object_info($type = NULL, $property = NULL) {
|
||||
if ($type) {
|
||||
if (($info = i18n_object_info($type, 'string translation'))) {
|
||||
if ($property) {
|
||||
return isset($info[$property]) ? $info[$property] : NULL;
|
||||
}
|
||||
else {
|
||||
return $info;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$list = array();
|
||||
foreach (i18n_object_info() as $type => $info) {
|
||||
if (!empty($info['string translation'])) {
|
||||
$list[$type] = $info;
|
||||
}
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_i18n_object_info_alter().
|
||||
*
|
||||
* Set a different default object wrapper for objects that have string translation.
|
||||
*/
|
||||
function i18n_string_i18n_object_info_alter(&$object_info) {
|
||||
foreach ($object_info as $type => &$info) {
|
||||
if (!empty($info['string translation']) && (empty($info['class']) || $info['class'] == 'i18n_object_wrapper')) {
|
||||
$info['class'] = 'i18n_string_object_wrapper';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate object properties
|
||||
*
|
||||
* We clone the object previously so we don't risk translated properties being saved
|
||||
*
|
||||
* @param $type
|
||||
* Object type
|
||||
* @param $object
|
||||
* Object or array
|
||||
*/
|
||||
function i18n_string_object_translate($type, $object, $options = array()) {
|
||||
$langcode = isset($options['langcode']) ? $options['langcode'] : i18n_langcode();
|
||||
if (i18n_string_translate_langcode($langcode)) {
|
||||
// Object properties will be returned without filtering as in the original one.
|
||||
$options += array('sanitize' => FALSE);
|
||||
return i18n_object($type, $object)->translate($langcode, $options);
|
||||
}
|
||||
else {
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove object strings, because object is deleted
|
||||
*
|
||||
* @param $type
|
||||
* Object type
|
||||
* @param $object
|
||||
* Object or array
|
||||
*/
|
||||
function i18n_string_object_remove($type, $object, $options = array()) {
|
||||
return i18n_object($type, $object)->strings_remove($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update object properties.
|
||||
*
|
||||
* @param $type
|
||||
* Object type
|
||||
* @param $object
|
||||
* Object or array
|
||||
*/
|
||||
function i18n_string_object_update($type, $object, $options = array()) {
|
||||
return i18n_object($type, $object)->strings_update($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic translation page for i18n_strings objects.
|
||||
*/
|
||||
function i18n_string_object_translate_page($object_type, $object_value, $language = NULL) {
|
||||
module_load_include('inc', 'i18n_string', 'i18n_string.pages');
|
||||
return i18n_string_translate_page_object($object_type, $object_value, $language);
|
||||
}
|
||||
|
||||
/**
|
||||
* Preload all strings for this textroup/context.
|
||||
*
|
||||
* This is a performance optimization to load all needed strings with a single query.
|
||||
*
|
||||
* Examples of valid string name to search are:
|
||||
* - 'taxonomy:term:*:title'
|
||||
* This will find all titles for taxonomy terms
|
||||
* - array('taxonomy', 'term', array(1,2), '*')
|
||||
* This will find all properties for taxonomy terms 1 and 2
|
||||
*
|
||||
* @param $name
|
||||
* Specially crafted string name, it may take '*' and array parameters for each element.
|
||||
* @param $langcode
|
||||
* Language code to search translations. Defaults to current language.
|
||||
*
|
||||
* @return array()
|
||||
* String objects indexed by context.
|
||||
*/
|
||||
function i18n_string_translation_search($name, $langcode = NULL) {
|
||||
$langcode = isset($langcode) ? $langcode : i18n_langcode();
|
||||
list ($textgroup, $context) = i18n_string_context($name);
|
||||
return i18n_string_textgroup($textgroup)->multiple_translation_search($context, $langcode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update / create translation for a certain source.
|
||||
*
|
||||
* @param $name
|
||||
* Array or string concatenated with ':' that contains textgroup and string context
|
||||
* @param $translation
|
||||
* Translation string for this language code
|
||||
* @param $langcode
|
||||
* The language code to translate to a language other than what is used to display the page.
|
||||
* @param $source_string
|
||||
* Optional source string, just in case it needs to be created.
|
||||
*
|
||||
* @return mixed
|
||||
* Source string object if update was successful.
|
||||
* Null if source string not found.
|
||||
* FALSE if use doesn't have permission to edit this translation.
|
||||
*/
|
||||
function i18n_string_translation_update($name, $translation, $langcode, $source_string = NULL) {
|
||||
if (is_array($translation)) {
|
||||
return i18n_string_multiple('translation_update', $name, $translation, $langcode);
|
||||
}
|
||||
elseif ($source = i18n_string_get_source($name)) {
|
||||
if ($langcode == i18n_string_source_language()) {
|
||||
// It's the default language so we should update the string source as well.
|
||||
i18n_string_update($name, $translation);
|
||||
}
|
||||
else {
|
||||
list ($textgroup, $context) = i18n_string_context($name);
|
||||
i18n_string_textgroup($textgroup)->update_translation($context, $langcode, $translation);
|
||||
}
|
||||
return $source;
|
||||
}
|
||||
elseif ($source_string) {
|
||||
// We don't have a source in the database, so we need to create it, but only if we've got the source too.
|
||||
// Note this string won't have any format.
|
||||
i18n_string_update($name, $source_string);
|
||||
return i18n_string_translation_update($name, $translation, $langcode);
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Count operation results by result value
|
||||
*/
|
||||
function _i18n_string_result_count($list) {
|
||||
$result = array();
|
||||
foreach ($list as $value) {
|
||||
$key = (string)$value;
|
||||
$result[$key] = isset($result[$key]) ? $result[$key] +1 : 1;
|
||||
}
|
||||
return $result;
|
||||
}
|
429
sites/all/modules/i18n/i18n_string/i18n_string.pages.inc
Normal file
429
sites/all/modules/i18n/i18n_string/i18n_string.pages.inc
Normal file
@@ -0,0 +1,429 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Internationalization (i18n) package - translatable strings reusable admin UI.
|
||||
*
|
||||
* @author Jose A. Reyero, 2007
|
||||
*/
|
||||
|
||||
// Load locale libraries
|
||||
include_once DRUPAL_ROOT . '/includes/locale.inc';
|
||||
include_once drupal_get_path('module', 'locale') . '/locale.admin.inc';
|
||||
|
||||
/**
|
||||
* Generate translate page from object
|
||||
*/
|
||||
function i18n_string_translate_page_object($object_type, $object_value, $language = NULL) {
|
||||
// For backwards compatibility, ensure parameter is a language object
|
||||
$language = i18n_language_object($language);
|
||||
$langcode = $language ? $language->language : NULL;
|
||||
// Get base keys for all these strings. Object key may be multiple like for blocks (module, delta)
|
||||
$object = i18n_object($object_type, $object_value);
|
||||
$strings = $object->get_strings(array('empty' => TRUE));
|
||||
|
||||
if (empty($langcode)) {
|
||||
drupal_set_title(t('Translate !name', array('!name' => i18n_object_info($object_type, 'title'))));
|
||||
return i18n_string_translate_page_overview($object, $strings);
|
||||
}
|
||||
else {
|
||||
drupal_set_title(t('Translate to !language', array('!language' => i18n_language_name($langcode))));
|
||||
return drupal_get_form('i18n_string_translate_page_form', $strings, $langcode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a core translation module like overview page for this object.
|
||||
*/
|
||||
function i18n_string_translate_page_overview($object, $strings) {
|
||||
$build['i18n_overview'] = drupal_get_form('i18n_string_translate_page_overview_form', $object, $strings);
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a core translation module like overview page for this object.
|
||||
*/
|
||||
function i18n_string_translate_page_overview_form($form, &$form_state, $object, $strings) {
|
||||
//include_once DRUPAL_ROOT . '/includes/language.inc';
|
||||
// Set the default item key, assume it's the first.
|
||||
$item_title = reset($strings);
|
||||
$header = array(
|
||||
'language' => t('Language'),
|
||||
'title' => t('Title'),
|
||||
'status' => t('Status'),
|
||||
'operations' => t('Operations')
|
||||
);
|
||||
$source_language = variable_get_value('i18n_string_source_language');
|
||||
$rows = array();
|
||||
|
||||
foreach (language_list() as $langcode => $language) {
|
||||
if ($langcode == $source_language) {
|
||||
$items = array(
|
||||
'language' => check_plain($language->name) . ' ' . t('(source)'),
|
||||
'title' => check_plain($item_title->get_string()),
|
||||
'status' => t('original'),
|
||||
'operations' => l(t('edit'), $object->get_edit_path()),
|
||||
);
|
||||
}
|
||||
else {
|
||||
// Try to figure out if this item has any of its properties translated.
|
||||
$translated = FALSE;
|
||||
foreach ($strings as $i18nstring) {
|
||||
if ($i18nstring->get_translation($langcode)) {
|
||||
$translated = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Translate the item that was requested to be displayed as title.
|
||||
$items = array(
|
||||
'language' => check_plain($language->name),
|
||||
'title' => $item_title->format_translation($langcode, array('sanitize default' => TRUE)),
|
||||
'status' => $translated ? t('translated') : t('not translated'),
|
||||
'operations' => l(t('translate'), $object->get_translate_path($langcode), array('query' => drupal_get_destination())),
|
||||
);
|
||||
}
|
||||
foreach ($items as $key => $markup) {
|
||||
$rows[$langcode][$key] = $markup;
|
||||
//$form['#rows'][$langcode][$key]['#markup'] = $markup;
|
||||
}
|
||||
}
|
||||
// Build a form so it can be altered later, with all this information.
|
||||
$form['object'] = array('#type' => 'value', '#value' => $object);
|
||||
$form['source_language'] = array('#type' => 'value', '#value' => $source_language);
|
||||
$form['languages'] = array(
|
||||
'#header' => $header,
|
||||
'#rows' => $rows,
|
||||
'#theme' => 'table',
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form builder callback for in-place string translation.
|
||||
*
|
||||
* @param $strings
|
||||
* Array of strings indexed by string name (may be indexed by group key too if $groups is present)
|
||||
* @param $langcode
|
||||
* Language code to translate to.
|
||||
* @param $groups
|
||||
* Optional groups to provide some string grouping. Array with group key and title pairs.
|
||||
*/
|
||||
function i18n_string_translate_page_form($form, &$form_state, $strings, $langcode, $groups = NULL) {
|
||||
$form = i18n_string_translate_page_form_base($form, $langcode);
|
||||
if ($groups) {
|
||||
// I we've got groups, string list is grouped by group key.
|
||||
$form['string_groups'] = array('#type' => 'value', '#value' => $strings);
|
||||
foreach ($groups as $key => $title) {
|
||||
$form['display'] = array(
|
||||
'#type' => 'vertical_tabs',
|
||||
);
|
||||
$form['strings'][$key] = array(
|
||||
'#group' => 'display',
|
||||
'#title' => $title,
|
||||
'#type' => 'fieldset',
|
||||
) + i18n_string_translate_page_form_strings($strings[$key], $langcode);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// We add a single group with key 'all', but no tabs.
|
||||
$form['string_groups'] = array('#type' => 'value', '#value' => array('all' => $strings));
|
||||
$form['strings']['all'] = i18n_string_translate_page_form_strings($strings, $langcode);
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create base form for string translation
|
||||
*/
|
||||
function i18n_string_translate_page_form_base($form, $langcode, $redirect = NULL) {
|
||||
$form['langcode'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $langcode,
|
||||
);
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Save translation'),
|
||||
'#weight' => 10,
|
||||
);
|
||||
if ($redirect) {
|
||||
$form['#redirect'] = array(
|
||||
$redirect,
|
||||
);
|
||||
}
|
||||
// Add explicit validate and submit hooks so this can be used from inside any form.
|
||||
$form['#submit'] = array('i18n_string_translate_page_form_submit');
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create field elements for strings
|
||||
*/
|
||||
function i18n_string_translate_page_form_strings($strings, $langcode) {
|
||||
$formats = filter_formats();
|
||||
foreach ($strings as $item) {
|
||||
// We may have a source or not. Load it, our string may get the format from it.
|
||||
$source = $item->get_source();
|
||||
$format_id = $source ? $source->format : $item->format;
|
||||
$description = '';
|
||||
// Check permissions to translate this string, depends on format, etc..
|
||||
if ($message = $item->check_translate_access()) {
|
||||
// We'll display a disabled element with the reason it cannot be translated.
|
||||
$disabled = TRUE;
|
||||
$description = $message;
|
||||
}
|
||||
else {
|
||||
$disabled = FALSE;
|
||||
$description = '';
|
||||
// If we don't have a source and it can be translated, we create it.
|
||||
if (!$source) {
|
||||
// Enable messages just as a reminder these strings are not being updated properly.
|
||||
$status = $item->update(array('messages' => TRUE));
|
||||
if ($status === FALSE || $status === SAVED_DELETED) {
|
||||
// We don't have a source string so nothing to translate here
|
||||
$disabled = TRUE;
|
||||
}
|
||||
else {
|
||||
$source = $item->get_source();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$default_value = $item->format_translation($langcode, array('langcode' => $langcode, 'sanitize' => FALSE, 'debug' => FALSE));
|
||||
$form[$item->get_name()] = array(
|
||||
'#title' => $item->get_title(),
|
||||
'#type' => 'textarea',
|
||||
'#default_value' => $default_value,
|
||||
'#disabled' => $disabled,
|
||||
'#description' => $description . _i18n_string_translate_format_help($format_id),
|
||||
//'#i18n_string_format' => $source ? $source->format : 0,
|
||||
// If disabled, provide smaller textarea (that can be expanded anyway).
|
||||
'#rows' => $disabled ? 1 : min(ceil(str_word_count($default_value) / 12), 10),
|
||||
// Change the parent for disabled strings so we don't get empty values later
|
||||
'#parents' => array($disabled ? 'disabled_strings': 'strings', $item->get_name()),
|
||||
);
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form submission callback for in-place string translation.
|
||||
*/
|
||||
function i18n_string_translate_page_form_submit($form, &$form_state) {
|
||||
$count = $success = 0;
|
||||
foreach ($form_state['values']['strings'] as $name => $value) {
|
||||
$count++;
|
||||
list($textgroup, $context) = i18n_string_context(explode(':', $name));
|
||||
$result = i18n_string_textgroup($textgroup)->update_translation($context, $form_state['values']['langcode'], $value);
|
||||
$success += ($result ? 1 : 0);
|
||||
}
|
||||
if ($success) {
|
||||
drupal_set_message(format_plural($success, 'A translation was saved successfully.', '@count translations were saved successfully.'));
|
||||
}
|
||||
if ($error = $count - $success) {
|
||||
drupal_set_message(format_plural($error, 'A translation could not be saved.', '@count translations could not be saved.'), 'warning');
|
||||
}
|
||||
if (isset($form['#redirect'])) {
|
||||
$form_state['redirect'] = $form['#redirect'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu callback. Saves a string translation coming as POST data.
|
||||
*/
|
||||
function i18n_string_l10n_client_save_string() {
|
||||
global $user, $language;
|
||||
|
||||
if (user_access('use on-page translation')) {
|
||||
$textgroup = !empty($_POST['textgroup']) ? $_POST['textgroup'] : 'default';
|
||||
// Other textgroups will be handled by l10n_client module
|
||||
if (!i18n_string_group_info($textgroup)) {
|
||||
return l10n_client_save_string();
|
||||
}
|
||||
elseif (isset($_POST['source']) && isset($_POST['target']) && !empty($_POST['context']) && !empty($_POST['form_token']) && drupal_valid_token($_POST['form_token'], 'l10n_client_form')) {
|
||||
$name = $textgroup . ':' . $_POST['context'];
|
||||
if ($i18nstring = i18n_string_get_source($name)) {
|
||||
// Since this is not a real form, we double check access permissions here too.
|
||||
if ($error = $i18nstring->check_translate_access()) {
|
||||
$message = theme('l10n_client_message', array('message' => t('Not saved due to: !reason', array('!reason' => $error)), 'level' => WATCHDOG_WARNING));
|
||||
}
|
||||
else {
|
||||
$result = i18n_string_translation_update($name, $_POST['target'], $language->language, $_POST['source']);
|
||||
if ($result) {
|
||||
$message = theme('l10n_client_message', array('message' => t('Translation saved locally for user defined string.'), 'level' => WATCHDOG_INFO));
|
||||
}
|
||||
elseif ($result === FALSE) {
|
||||
$message = theme('l10n_client_message', array('message' => t('Not saved due to insufficient permissions.')));
|
||||
}
|
||||
else {
|
||||
$message = theme('l10n_client_message', array('message' => t('Not saved due to unknown reason.')));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$message = theme('l10n_client_message', array('message' => t('Not saved due to source string missing.')));
|
||||
}
|
||||
}
|
||||
else {
|
||||
$message = theme('l10n_client_message', array('message' => t('Not saved due to missing form values.')));
|
||||
}
|
||||
drupal_json_output($message);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* User interface for string editing.
|
||||
*/
|
||||
function i18n_string_locale_translate_edit_form($form, &$form_state, $lid) {
|
||||
// Fetch source string, if possible.
|
||||
$source = db_query('SELECT source, context, textgroup, location FROM {locales_source} WHERE lid = :lid', array(':lid' => $lid))->fetchObject();
|
||||
if (!$source) {
|
||||
drupal_set_message(t('String not found.'), 'error');
|
||||
drupal_goto('admin/config/regional/translate/translate');
|
||||
}
|
||||
|
||||
// Add original text to the top and some values for form altering.
|
||||
$form['original'] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => t('Original text'),
|
||||
'#markup' => check_plain(wordwrap($source->source, 0)),
|
||||
);
|
||||
if (!empty($source->context)) {
|
||||
$form['context'] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => t('Context'),
|
||||
'#markup' => check_plain($source->context),
|
||||
);
|
||||
}
|
||||
$form['lid'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $lid
|
||||
);
|
||||
$form['textgroup'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $source->textgroup,
|
||||
);
|
||||
$form['location'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => $source->location
|
||||
);
|
||||
|
||||
// Include default form controls with empty values for all languages.
|
||||
// This ensures that the languages are always in the same order in forms.
|
||||
$languages = language_list();
|
||||
|
||||
// We don't need the default language value, that value is in $source.
|
||||
$omit = $source->textgroup == 'default' ? 'en' : i18n_string_source_language();
|
||||
unset($languages[($omit)]);
|
||||
$form['translations'] = array('#tree' => TRUE);
|
||||
// Approximate the number of rows to use in the default textarea.
|
||||
$rows = min(ceil(str_word_count($source->source) / 12), 10);
|
||||
foreach ($languages as $langcode => $language) {
|
||||
$form['translations'][$langcode] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => t($language->name),
|
||||
'#rows' => $rows,
|
||||
'#default_value' => '',
|
||||
);
|
||||
}
|
||||
|
||||
// Fetch translations and fill in default values in the form.
|
||||
$result = db_query("SELECT DISTINCT translation, language FROM {locales_target} WHERE lid = :lid AND language <> :omit", array(':lid' => $lid, ':omit' => $omit));
|
||||
foreach ($result as $translation) {
|
||||
$form['translations'][$translation->language]['#default_value'] = $translation->translation;
|
||||
}
|
||||
|
||||
$form['actions'] = array('#type' => 'actions');
|
||||
$form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save translations'));
|
||||
|
||||
// Restrict filter permissions and handle validation and submission for i18n strings.
|
||||
if (i18n_string_group_info($source->textgroup)) {
|
||||
if ($i18nstring = i18n_string_get_by_lid($form['lid']['#value'])) {
|
||||
$form['i18n_string'] = array('#type' => 'value', '#value' => $i18nstring);
|
||||
if ($message = $i18nstring->check_translate_access()) {
|
||||
drupal_set_message($message);
|
||||
$disabled = TRUE;
|
||||
}
|
||||
// Add format help anyway, though the form may be disabled.
|
||||
$form['translations']['format_help']['#markup'] = _i18n_string_translate_format_help($i18nstring->format);
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('Source string not found.'), 'warning');
|
||||
$disabled = TRUE;
|
||||
}
|
||||
if (!empty($disabled)) {
|
||||
// Disable all form elements
|
||||
$form['submit']['#disabled'] = TRUE;
|
||||
foreach (element_children($form['translations']) as $langcode) {
|
||||
$form['translations'][$langcode]['#disabled'] = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process string editing form validations.
|
||||
*
|
||||
* If it is an allowed format, skip default validation, the text will be filtered later
|
||||
*/
|
||||
function i18n_string_locale_translate_edit_form_validate($form, &$form_state) {
|
||||
if (empty($form_state['values']['i18n_string'])) {
|
||||
// If not i18n string use regular locale validation.
|
||||
$copy_state = $form_state;
|
||||
locale_translate_edit_form_validate($form, $copy_state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process string editing form submissions.
|
||||
*
|
||||
* Mark translations as current.
|
||||
*/
|
||||
function i18n_string_locale_translate_edit_form_submit($form, &$form_state) {
|
||||
// Invoke locale submission.
|
||||
locale_translate_edit_form_submit($form, $form_state);
|
||||
$lid = $form_state['values']['lid'];
|
||||
foreach ($form_state['values']['translations'] as $key => $value) {
|
||||
if (!empty($value)) {
|
||||
// An update has been made, so we assume the translation is now current.
|
||||
db_update('locales_target')
|
||||
->fields(array('i18n_status' => I18N_STRING_STATUS_CURRENT))
|
||||
->condition('lid', $lid)
|
||||
->condition('language', $key)
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Help for text format.
|
||||
*/
|
||||
function _i18n_string_translate_format_help($format_id) {
|
||||
$output = '';
|
||||
if ($format = filter_format_load($format_id)) {
|
||||
$title = t('Text format: @name', array('@name' => $format->name));
|
||||
$tips = theme('filter_tips', array('tips' => _filter_tips($format_id, FALSE)));
|
||||
}
|
||||
elseif ($format_id == I18N_STRING_FILTER_XSS) {
|
||||
$title = t('Standard XSS filter.');
|
||||
$allowed_html = '<a> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd>';
|
||||
$tips[] = t('Allowed HTML tags: @tags', array('@tags' => $allowed_html));
|
||||
}
|
||||
elseif ($format_id == I18N_STRING_FILTER_XSS_ADMIN) {
|
||||
$title = t('Administration XSS filter.');
|
||||
$tips[] = t('It will allow most HTML tags but not scripts nor styles.');
|
||||
}
|
||||
elseif ($format_id) {
|
||||
$title = t('Unknown filter: @name', array('@name' => $format_id));
|
||||
}
|
||||
|
||||
if (!empty($title)) {
|
||||
$output .= '<h5>' . $title . '</h5>';
|
||||
}
|
||||
if (!empty($tips)) {
|
||||
$output .= is_array($tips) ? theme('item_list', array('items' => $tips)) : $tips;
|
||||
}
|
||||
return $output;
|
||||
}
|
92
sites/all/modules/i18n/i18n_string/i18n_string.test
Normal file
92
sites/all/modules/i18n/i18n_string/i18n_string.test
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Test case for multilingual string
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class for testing i18n_string and modules using these features
|
||||
*
|
||||
* Tests basic API functions
|
||||
*/
|
||||
|
||||
|
||||
class i18nStringTestCase extends Drupali18nTestCase {
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'String translation API',
|
||||
'group' => 'Internationalization',
|
||||
'description' => 'User defined strings translation functions'
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
// We can use any of the modules that define a text group, to use it for testing
|
||||
parent::setUp('i18n_string', 'i18n_menu');
|
||||
parent::setUpLanguages();
|
||||
$this->translator = $this->drupalCreateUser(array('translate interface', 'translate user-defined strings'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test base i18n_string API
|
||||
*/
|
||||
function testStringsAPI() {
|
||||
// Create a bunch of strings for all languages
|
||||
$textgroup = 'menu';
|
||||
$strings = $this->stringCreateArray(2);
|
||||
$translations = array();
|
||||
// Save source strings and store translations
|
||||
foreach ($strings as $key => $string) {
|
||||
$name = "$textgroup:item:$key:title";
|
||||
i18n_string_update($name, $string);
|
||||
$translations[$key] = $this->createStringTranslation($textgroup, $string);
|
||||
}
|
||||
// Reset cache for text group
|
||||
i18n_string_textgroup($textgroup)->cache_reset();
|
||||
// Check translations using the API
|
||||
foreach ($this->getOtherLanguages() as $language) {
|
||||
foreach ($strings as $key => $value) {
|
||||
$name = "$textgroup:item:$key:title";
|
||||
$translation = i18n_string_translate($name, 'NOT FOUND', array('langcode' => $language->language));
|
||||
$this->assertEqual($translation, $translations[$key][$language->language], "The right $language->name ($language->language) translation has been retrieved for $name, $translation");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create strings for all languages
|
||||
*/
|
||||
public static function stringCreateAll($number = 10, $length = 100) {
|
||||
foreach (language_list() as $lang => $language) {
|
||||
$strings[$lang] = self::stringCreateArray($number, $length);
|
||||
}
|
||||
return $strings;
|
||||
}
|
||||
/**
|
||||
* Create a bunch of random strings to test the API
|
||||
*/
|
||||
public static function stringCreateArray($number = 10, $length = 100) {
|
||||
for ($i=1 ; $i <= $number ; $i++) {
|
||||
$strings[$i] = self::randomName($length);
|
||||
}
|
||||
return $strings;
|
||||
}
|
||||
/**
|
||||
* Create and store one translation into the db
|
||||
*/
|
||||
public static function stringCreateTranslation($name, $lang, $length = 20) {
|
||||
$translation = $this->randomName($length);
|
||||
if (self::stringSaveTranslation($name, $lang, $translation)) {
|
||||
return $translation;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Translate one string into the db
|
||||
*/
|
||||
public static function stringSaveTranslation($name, $lang, $translation) {
|
||||
list($textgroup, $context) = i18n_string_context($name);
|
||||
return i18n_string_textgroup($textgroup)->update_translation($context, $lang, $translation);
|
||||
}
|
||||
}
|
57
sites/all/modules/i18n/i18n_string/i18n_string.variable.inc
Normal file
57
sites/all/modules/i18n/i18n_string/i18n_string.variable.inc
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Variable information
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_variable_info().
|
||||
*/
|
||||
function i18n_string_variable_info($options = array()) {
|
||||
$variables['i18n_string_translate_langcode_[language]'] = array(
|
||||
'type' => 'multiple_language',
|
||||
'title' => t('Enable translation for language'),
|
||||
'multiple values' => array('type' => 'boolean'),
|
||||
'group' => 'i18n',
|
||||
);
|
||||
$variables['i18n_string_allowed_formats'] = array(
|
||||
'title' => t('Translatable text formats'),
|
||||
'options callback' => 'i18n_string_variable_format_list',
|
||||
'type' => 'options',
|
||||
'default callback' => 'i18n_string_variable_format_default',
|
||||
'access' => 'administer filters',
|
||||
'description' => t('The translation system only translates strings with the selected text formats. All other strings will be ignored and removed from the list of translatable strings.'),
|
||||
);
|
||||
$variables['i18n_string_source_language'] = array(
|
||||
'title' => t('Source language'),
|
||||
'type' => 'language',
|
||||
'default callback' => 'i18n_string_source_language',
|
||||
'description' => t('Language that will be used as the source language for string translations. The default is the site default language.'),
|
||||
);
|
||||
$variables['i18n_string_debug'] = array(
|
||||
'type' => 'enable',
|
||||
'title' => t('Debug string translation', array(), $options),
|
||||
'default' => 0,
|
||||
'group' => 'debug',
|
||||
);
|
||||
return $variables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options callback, format list
|
||||
*/
|
||||
function i18n_string_variable_format_list() {
|
||||
$list = array();
|
||||
// As the user has administer filters permissions we get a full list here
|
||||
foreach (filter_formats() as $fid => $format) {
|
||||
$list[$fid] = $format->name;
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allowed formats default value
|
||||
*/
|
||||
function i18n_string_variable_format_default() {
|
||||
return array(filter_fallback_format());
|
||||
}
|
Reference in New Issue
Block a user