Commit 9e9a982252a4aaa6a876e0c63a69416a12672bed
1 parent
43e73634
core JS i18n, addition of other i18n fixes.
git-svn-id: https://kt-dms.svn.sourceforge.net/svnroot/kt-dms/trunk@5114 c91229c3-7414-0410-bfa2-8a42b809f60b
Showing
11 changed files
with
176 additions
and
19 deletions
bin/jsi18n.py
0 โ 100755
| 1 | +#!/usr/bin/python | |
| 2 | +# | |
| 3 | +# JS Gettext-style extractor. | |
| 4 | + | |
| 5 | +import re | |
| 6 | +import sys | |
| 7 | + | |
| 8 | +usage_str = ''' | |
| 9 | + Extracts _() items in JS. | |
| 10 | + | |
| 11 | + Usage: jsi18n.py [list of files] > output.smarty | |
| 12 | +''' | |
| 13 | + | |
| 14 | +baseline = ''' | |
| 15 | +/* | |
| 16 | + * Javascript (actual translations); | |
| 17 | + */ | |
| 18 | + | |
| 19 | +{literal} | |
| 20 | +var i18n = {}; | |
| 21 | + | |
| 22 | +function _(trans_string) { | |
| 23 | + var newstr = i18n[trans_string]; | |
| 24 | + if (!isUndefinedOrNull(newstr)) { return newstr; } | |
| 25 | + else { | |
| 26 | + return trans_string; | |
| 27 | + } | |
| 28 | +} | |
| 29 | +{/literal} | |
| 30 | + | |
| 31 | + | |
| 32 | +''' | |
| 33 | + | |
| 34 | +peritem = "i18n['%s'] = '{i18n}%s{/i18n}';\n" | |
| 35 | + | |
| 36 | +# this is not the best way to do this ... | |
| 37 | + | |
| 38 | +class JSExtractor: | |
| 39 | + def __init__(self, filename): | |
| 40 | + self.strings = [] | |
| 41 | + handle = file(filename, 'r') | |
| 42 | + self.content = handle.read() | |
| 43 | + handle.close() | |
| 44 | + | |
| 45 | + def process(self): | |
| 46 | + proc = re.compile('(_\(\'(.*?)\'\))') | |
| 47 | + self.strings = [i[1] for i in proc.findall(self.content)] | |
| 48 | + | |
| 49 | + def getStrings(self): | |
| 50 | + out = '' | |
| 51 | + for l in self.strings: | |
| 52 | + out += peritem%(l, l) | |
| 53 | + return out | |
| 54 | + | |
| 55 | +if __name__ == '__main__': | |
| 56 | + fake_po = baseline | |
| 57 | + | |
| 58 | + filelist = sys.stdin.readlines() | |
| 59 | + for filename in filelist: | |
| 60 | + processor = JSExtractor(filename[:-1]) | |
| 61 | + processor.process() | |
| 62 | + fake_po += "\n// strings for file: %s\n"%(filename[:-1]); | |
| 63 | + fake_po += processor.getStrings() | |
| 64 | + | |
| 65 | + print fake_po | |
| 0 | 66 | \ No newline at end of file | ... | ... |
browse.php
| ... | ... | @@ -261,7 +261,7 @@ class BrowseDispatcher extends KTStandardDispatcher { |
| 261 | 261 | $aFields = DocumentField::getList('has_lookup = 1'); |
| 262 | 262 | |
| 263 | 263 | if (empty($aFields)) { |
| 264 | - $this->errorRedirectToMain('No lookup fields available.'); | |
| 264 | + $this->errorRedirectToMain(_('No lookup fields available.')); | |
| 265 | 265 | exit(0); |
| 266 | 266 | } |
| 267 | 267 | ... | ... |
docs/developer/i18n.txt
| ... | ... | @@ -6,6 +6,9 @@ Testing |
| 6 | 6 | - install gettext command line utilities |
| 7 | 7 | - Run the following to extract translatable text from the templates: |
| 8 | 8 | $ rm -f i18n/templates.c |
| 9 | +- run custom python to generate i18n for js | |
| 10 | + $ find resources -name "*.js" | python ./bin/jsi18n.py > templates/ktcore/javascript_i18n.smarty | |
| 11 | + | |
| 9 | 12 | $ php bin/smarty_to_gettext.php . > i18n/templates.c |
| 10 | 13 | - run xgettext to generate .po files eg. |
| 11 | 14 | $ find . -type f -name "*.php" -o -name "*.inc" | xgettext --no-wrap -d knowledgeTree -L PHP -s -f - -o i18n/knowledgeTree.po | ... | ... |
presentation/i18nJavascript.php
0 โ 100644
| 1 | +<?php | |
| 2 | + | |
| 3 | +require_once('../config/dmsDefaults.php'); | |
| 4 | +require_once(KT_LIB_DIR . '/dispatcher.inc.php'); | |
| 5 | +require_once(KT_LIB_DIR . '/templating/templating.inc.php'); | |
| 6 | + | |
| 7 | +class JavascriptTranslationDispatcher extends KTDispatcher { | |
| 8 | + | |
| 9 | + function check() { | |
| 10 | + if (!parent::check()) { return false; } | |
| 11 | + | |
| 12 | + return true; | |
| 13 | + } | |
| 14 | + | |
| 15 | + function do_main() { | |
| 16 | + header('Content-Type: application/javascript; charset=UTF-8'); | |
| 17 | + | |
| 18 | + $oTemplating =& KTTemplating::getSingleton(); | |
| 19 | + $oTemplate = $oTemplating->loadTemplate("ktcore/javascript_i18n"); | |
| 20 | + | |
| 21 | + return $oTemplate->render(); | |
| 22 | + } | |
| 23 | +} | |
| 24 | + | |
| 25 | +$oD =& new JavascriptTranslationDispatcher(); | |
| 26 | +$oD->dispatch(); | |
| 27 | + | |
| 28 | +?> | |
| 0 | 29 | \ No newline at end of file | ... | ... |
resources/js/conditional_complex_edit.js
| ... | ... | @@ -80,7 +80,7 @@ function placeFinishButton() { |
| 80 | 80 | } |
| 81 | 81 | var column = getColumnForField(active_field); |
| 82 | 82 | |
| 83 | - var finish_button = INPUT({'type':'button', 'value':'Finish with this column\'s behaviours.','id':'global-stack-popper-button'}); | |
| 83 | + var finish_button = INPUT({'type':'button', 'value':_('Finish with this column\'s behaviours.'),'id':'global-stack-popper-button'}); | |
| 84 | 84 | simpleLog('DEBUG','placing stack-popper with function popFixedStack in field '+active_field); |
| 85 | 85 | addEvent(finish_button, 'click', popFixedStack); |
| 86 | 86 | simpleLog('DEBUG','added listener.'); |
| ... | ... | @@ -155,7 +155,7 @@ function setFixedValueForField(field_id, value, label) { |
| 155 | 155 | var column = getColumnForField(field_id); |
| 156 | 156 | simpleLog('DEBUG','fixing value for field '+field_id+' to '+label+' ('+value+')'); |
| 157 | 157 | addElementClass(column, 'fixed'); |
| 158 | - setMessageForField(field_id,'fixed_message', 'Assuming this field has behaviour "'+label+'".'); | |
| 158 | + setMessageForField(field_id,'fixed_message', _('Assuming this field has behaviour "')+label+'".'); | |
| 159 | 159 | |
| 160 | 160 | // now we need to check if this field _is_ fixed. |
| 161 | 161 | var fixed_source = getElementsByTagAndClassName('input','fixed_value',column); | ... | ... |
resources/js/conditional_simple_edit.js
| ... | ... | @@ -163,7 +163,7 @@ function storeRelationship(selected_lookup, child_lookups) { |
| 163 | 163 | |
| 164 | 164 | // inform the user that something has happened. |
| 165 | 165 | // FIXME this isn't i18n friendly. |
| 166 | - addInformationNote('Dependencies saved. (at ' + new Date() + ')'); | |
| 166 | + addInformationNote(_('Dependencies saved. (at ') + new Date() + ')'); | |
| 167 | 167 | |
| 168 | 168 | deferred.addCallback(do_updateActiveLookups); |
| 169 | 169 | deferred.addErrback(partial(do_handleAjaxError, 'storeRelationship')); |
| ... | ... | @@ -223,7 +223,7 @@ function do_updateActiveLookups(label, req) { |
| 223 | 223 | } |
| 224 | 224 | } |
| 225 | 225 | |
| 226 | - addInformationNote('Dependencies for value "'+label+' loaded."(at ' + new Date() + ')'); | |
| 226 | + addInformationNote(_('Dependencies for value "')+label+('" loaded.(at ') + new Date() + ')'); | |
| 227 | 227 | } |
| 228 | 228 | |
| 229 | 229 | |
| ... | ... | @@ -269,7 +269,7 @@ function editSimpleField(field_id) { |
| 269 | 269 | setExclusiveEditing(field_id); |
| 270 | 270 | updateActiveFields(); // trigger an update of the backend. |
| 271 | 271 | // rest is asynchronous. |
| 272 | - addInformationNote('Now editing field "'+getNameForField(field_id)+'".'); | |
| 272 | + addInformationNote(_('Now editing field "')+getNameForField(field_id)+'".'); | |
| 273 | 273 | } |
| 274 | 274 | |
| 275 | 275 | |
| ... | ... | @@ -301,7 +301,7 @@ function finishSimpleField(field_id) { |
| 301 | 301 | |
| 302 | 302 | // called when a single-view dropdown is activated. |
| 303 | 303 | function handleChangedSelection(field_id, select_input) { |
| 304 | - addInformationNote('Loading Dependencies for value "'+scrapeText(select_input.options[select_input.selectedIndex])+'"(at ' + new Date() + ')'); | |
| 304 | + addInformationNote(_('Loading Dependencies for value "')+scrapeText(select_input.options[select_input.selectedIndex])+'"(at ' + new Date() + ')'); | |
| 305 | 305 | updateActiveLookups(select_input.value, scrapeText(select_input.options[select_input.selectedIndex])); // handles everything for us. |
| 306 | 306 | } |
| 307 | 307 | ... | ... |
resources/js/conditional_usage.js
| ... | ... | @@ -329,7 +329,7 @@ function reviseConditional(buttonsource) { |
| 329 | 329 | var fieldset = breadcrumbFind(buttonsource, 'FIELDSET'); |
| 330 | 330 | setElementClass(fieldset, 'conditional_metadata'); |
| 331 | 331 | if (!checkStackForFieldset(fieldset)) { |
| 332 | - var undo_button = INPUT({'type':'button','value':'undo'},null); | |
| 332 | + var undo_button = INPUT({'type':'button','value':_('Undo')},null); | |
| 333 | 333 | attachToElementEvent(undo_button,'click',partial(popStack, fieldset)); |
| 334 | 334 | fieldset.appendChild(undo_button); |
| 335 | 335 | // initialise the stack. |
| ... | ... | @@ -352,7 +352,7 @@ function initialiseConditionalFieldsets() { |
| 352 | 352 | // and insert the initial (master) field. |
| 353 | 353 | for (var i=0; i<fieldsets.length; i++) { |
| 354 | 354 | if (!checkStackForFieldset(fieldsets[i])) { |
| 355 | - var undo_button = INPUT({'type':'button','value':'undo'},null); | |
| 355 | + var undo_button = INPUT({'type':'button','value':_('Undo')},null); | |
| 356 | 356 | attachToElementEvent(undo_button,'click',partial(popStack, fieldsets[i])); |
| 357 | 357 | fieldsets[i].appendChild(undo_button); |
| 358 | 358 | // initialise the stack. | ... | ... |
resources/js/constructed_search.js
| ... | ... | @@ -86,7 +86,7 @@ function addNewCriteria(add_button) { |
| 86 | 86 | var newCriteriaText = scrapeText(select.options[select.selectedIndex])+' '; // FIXME insert the "input" here. |
| 87 | 87 | replaceChildNodes(select.parentNode, newCriteriaText, INPUT({'type':'hidden', 'name':'boolean_search[subgroup]['+tableId+'][values]['+critId+'][type]','value':select.value})); // works thanks to DOM co-ercion. |
| 88 | 88 | createAdditionalCriteriaOption(parent_table); |
| 89 | - var removeButton = INPUT({'type':'button', 'value':'Remove'}); | |
| 89 | + var removeButton = INPUT({'type':'button', 'value':_('Remove')}); | |
| 90 | 90 | attachToElementEvent(removeButton, 'click', partial(removeCriteria, removeButton)); |
| 91 | 91 | add_button.parentNode.replaceChild(removeButton, add_button); |
| 92 | 92 | |
| ... | ... | @@ -159,8 +159,8 @@ function createAdditionalCriteriaOption(parent_table) { |
| 159 | 159 | // clone, and append. |
| 160 | 160 | var clonedObject = master_div.getElementsByTagName('select')[0].cloneNode(true); |
| 161 | 161 | var select_entry = TD(null, clonedObject); |
| 162 | - var notification_entry = TD(null, createDOM('P',{'class':'helpText'},'first select a type of query')); | |
| 163 | - var add_button = INPUT({'type':'button', 'value':'Add'}); | |
| 162 | + var notification_entry = TD(null, createDOM('P',{'class':'helpText'},_('first select a type of query'))); | |
| 163 | + var add_button = INPUT({'type':'button', 'value':_('Add')}); | |
| 164 | 164 | attachToElementEvent(add_button, 'click', partial(addNewCriteria, add_button)); |
| 165 | 165 | var add_entry = TD(null, add_button); |
| 166 | 166 | tbody.appendChild(TR(null, select_entry, notification_entry, add_entry)); |
| ... | ... | @@ -191,7 +191,7 @@ function addBooleanGroup(addbutton) { |
| 191 | 191 | simpleLog('DEBUG','adding boolean group to '+bodyObj); |
| 192 | 192 | |
| 193 | 193 | // i hate me. i also want sane multiline |
| 194 | - sourceString = ' <fieldset> <legend>Criteria Group</legend> <table class="advanced-search-form"> <tbody> <tr> <th>Criteria</th> <th>Values</th> </tr></tbody></table> </fieldset>'; | |
| 194 | + sourceString = ' <fieldset> <legend>' + _('Criteria Group') + '</legend> <table class="advanced-search-form"> <tbody> <tr> <th>'+_('Criteria')+'</th> <th>'+_('Values')+'</th> </tr></tbody></table> </fieldset>'; | |
| 195 | 195 | |
| 196 | 196 | |
| 197 | 197 | // add the fieldset |
| ... | ... | @@ -203,7 +203,7 @@ function addBooleanGroup(addbutton) { |
| 203 | 203 | // get an id for the table. |
| 204 | 204 | var table_id = getBooleanGroupId(tableObj); |
| 205 | 205 | // add the grouping string |
| 206 | - groupingString = '<p class="helpText">Return items which match <select name="boolean_search['+table_id+'][join]"><option value="AND">all</option><option value="OR">any</option></select> of the criteria specified.</p>'; | |
| 206 | + groupingString = '<p class="helpText">' + _('Return items which match')+' <select name="boolean_search['+table_id+'][join]"><option value="AND">'+_('all')+'</option><option value="OR">'+_('any')+'</option></select>'+_('of the criteria specified.')+'</p>'; | |
| 207 | 207 | t = DIV(null); |
| 208 | 208 | t.innerHTML = groupingString; |
| 209 | 209 | var paraObj = t.getElementsByTagName('P')[0]; | ... | ... |
templates/ktcore/boolean_search.smarty
| ... | ... | @@ -63,7 +63,7 @@ legend { border: 1px dotted #999;} |
| 63 | 63 | {/if} |
| 64 | 64 | |
| 65 | 65 | {capture assign=options} |
| 66 | -<select name="boolean_search[join]"><option value="AND">all</option><option value="OR">any</option></select> | |
| 66 | +<select name="boolean_search[join]"><option value="AND">{i18n}all{/i18n}</option><option value="OR">{i18n}any{/i18n}</option></select> | |
| 67 | 67 | {/capture} |
| 68 | 68 | |
| 69 | 69 | <p class="helpText">{i18n arg_options=$options}Return items which match #options# of the <strong>criteria groups</strong> specified.{/i18n}</p> | ... | ... |
templates/ktcore/javascript_i18n.smarty
0 โ 100644
| 1 | + | |
| 2 | +/* | |
| 3 | + * Javascript (actual translations); | |
| 4 | + */ | |
| 5 | + | |
| 6 | +{literal} | |
| 7 | +var i18n = {}; | |
| 8 | + | |
| 9 | +function _(trans_string) { | |
| 10 | + var newstr = i18n[trans_string]; | |
| 11 | + if (!isUndefinedOrNull(newstr)) { return newstr; } | |
| 12 | + else { | |
| 13 | + return trans_string; | |
| 14 | + } | |
| 15 | +} | |
| 16 | +{/literal} | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | +// strings for file: resources/js/kt3calendar.js | |
| 21 | + | |
| 22 | +// strings for file: resources/js/conditional_complex_edit.js | |
| 23 | +i18n['Finish with this column\'s behaviours.'] = '{i18n}Finish with this column\'s behaviours.{/i18n}'; | |
| 24 | +i18n['Assuming this field has behaviour "'] = '{i18n}Assuming this field has behaviour "{/i18n}'; | |
| 25 | + | |
| 26 | +// strings for file: resources/js/conditional_simple_edit.js | |
| 27 | +i18n['Dependencies saved. (at '] = '{i18n}Dependencies saved. (at {/i18n}'; | |
| 28 | +i18n['Dependencies for value "'] = '{i18n}Dependencies for value "{/i18n}'; | |
| 29 | +i18n['Now editing field "'] = '{i18n}Now editing field "{/i18n}'; | |
| 30 | +i18n['Loading Dependencies for value "'] = '{i18n}Loading Dependencies for value "{/i18n}'; | |
| 31 | + | |
| 32 | +// strings for file: resources/js/translate.js | |
| 33 | + | |
| 34 | +// strings for file: resources/js/constructed_search.js | |
| 35 | +i18n['Remove'] = '{i18n}Remove{/i18n}'; | |
| 36 | +i18n['first select a type of query'] = '{i18n}first select a type of query{/i18n}'; | |
| 37 | +i18n['Add'] = '{i18n}Add{/i18n}'; | |
| 38 | +i18n['Criteria Group'] = '{i18n}Criteria Group{/i18n}'; | |
| 39 | +i18n['Criteria'] = '{i18n}Criteria{/i18n}'; | |
| 40 | +i18n['Values'] = '{i18n}Values{/i18n}'; | |
| 41 | +i18n['Return items which match'] = '{i18n}Return items which match{/i18n}'; | |
| 42 | +i18n['all'] = '{i18n}all{/i18n}'; | |
| 43 | +i18n['any'] = '{i18n}any{/i18n}'; | |
| 44 | +i18n['of the criteria specified.'] = '{i18n}of the criteria specified.{/i18n}'; | |
| 45 | + | |
| 46 | +// strings for file: resources/js/taillog.js | |
| 47 | + | |
| 48 | +// strings for file: resources/js/add_document.js | |
| 49 | + | |
| 50 | +// strings for file: resources/js/constructed_search_postprocess.js | |
| 51 | + | |
| 52 | +// strings for file: resources/js/toggleselect.js | |
| 53 | + | |
| 54 | +// strings for file: resources/js/kt-utility.js | |
| 55 | + | |
| 56 | +// strings for file: resources/js/help.js | |
| 57 | + | |
| 58 | +// strings for file: resources/js/conditional_usage.js | |
| 59 | +i18n['Undo'] = '{i18n}Undo{/i18n}'; | |
| 60 | +i18n['Undo'] = '{i18n}Undo{/i18n}'; | |
| 61 | + | ... | ... |
templates/ktstandard/action/document_links.smarty
| ... | ... | @@ -30,7 +30,7 @@ |
| 30 | 30 | <tr> |
| 31 | 31 | <td> |
| 32 | 32 | {if $write_permission} |
| 33 | - <a href="{addQS}action=delete&fDocumentId={$context->oDocument->getId()}&fDocumentLinkId={$link->getId()}{/addQS}" class="ktAction ktDelete">Delete</a> | |
| 33 | + <a href="{addQS}action=delete&fDocumentId={$context->oDocument->getId()}&fDocumentLinkId={$link->getId()}{/addQS}" class="ktAction ktDelete">{i18n}Delete{/i18n}</a> | |
| 34 | 34 | {else} |
| 35 | 35 | |
| 36 | 36 | {/if} |
| ... | ... | @@ -66,7 +66,7 @@ |
| 66 | 66 | |
| 67 | 67 | |
| 68 | 68 | {else} |
| 69 | -<tr><td colspan="4" align="center">There are no links to or from this document.</td></tr> | |
| 69 | +<tr><td colspan="4" align="center">{i18n}There are no links to or from this document.{/i18n}</td></tr> | |
| 70 | 70 | {/if} |
| 71 | 71 | |
| 72 | 72 | |
| ... | ... | @@ -77,8 +77,8 @@ |
| 77 | 77 | |
| 78 | 78 | |
| 79 | 79 | {if $write_permission} |
| 80 | -<a class="ktAction ktAdd ktInline" href="{addQS}action=new&fDocumentId={$context->oDocument->getId()}{/addQS}">Add a new link</a> | |
| 80 | +<a class="ktAction ktAdd ktInline" href="{addQS}action=new&fDocumentId={$context->oDocument->getId()}{/addQS}">{i18n}Add a new link{/i18n}</a> | |
| 81 | 81 | <a |
| 82 | -href="{addQS}action=new&fDocumentId={$context->oDocument->getId()}&fFolderId={$context->oDocument->getFolderId()}{/addQS}">Add a new link</a>. | |
| 82 | +href="{addQS}action=new&fDocumentId={$context->oDocument->getId()}&fFolderId={$context->oDocument->getFolderId()}{/addQS}">{i18n}Add a new link{/i18n}</a>. | |
| 83 | 83 | {/if} |
| 84 | 84 | ... | ... |