diff --git a/bin/jsi18n.py b/bin/jsi18n.py new file mode 100755 index 0000000..63c6571 --- /dev/null +++ b/bin/jsi18n.py @@ -0,0 +1,65 @@ +#!/usr/bin/python +# +# JS Gettext-style extractor. + +import re +import sys + +usage_str = ''' + Extracts _() items in JS. + + Usage: jsi18n.py [list of files] > output.smarty +''' + +baseline = ''' +/* + * Javascript (actual translations); + */ + +{literal} +var i18n = {}; + +function _(trans_string) { + var newstr = i18n[trans_string]; + if (!isUndefinedOrNull(newstr)) { return newstr; } + else { + return trans_string; + } +} +{/literal} + + +''' + +peritem = "i18n['%s'] = '{i18n}%s{/i18n}';\n" + +# this is not the best way to do this ... + +class JSExtractor: + def __init__(self, filename): + self.strings = [] + handle = file(filename, 'r') + self.content = handle.read() + handle.close() + + def process(self): + proc = re.compile('(_\(\'(.*?)\'\))') + self.strings = [i[1] for i in proc.findall(self.content)] + + def getStrings(self): + out = '' + for l in self.strings: + out += peritem%(l, l) + return out + +if __name__ == '__main__': + fake_po = baseline + + filelist = sys.stdin.readlines() + for filename in filelist: + processor = JSExtractor(filename[:-1]) + processor.process() + fake_po += "\n// strings for file: %s\n"%(filename[:-1]); + fake_po += processor.getStrings() + + print fake_po \ No newline at end of file diff --git a/browse.php b/browse.php index 3c42785..91c633b 100755 --- a/browse.php +++ b/browse.php @@ -261,7 +261,7 @@ class BrowseDispatcher extends KTStandardDispatcher { $aFields = DocumentField::getList('has_lookup = 1'); if (empty($aFields)) { - $this->errorRedirectToMain('No lookup fields available.'); + $this->errorRedirectToMain(_('No lookup fields available.')); exit(0); } diff --git a/docs/developer/i18n.txt b/docs/developer/i18n.txt index 6eebd4c..1279bd2 100644 --- a/docs/developer/i18n.txt +++ b/docs/developer/i18n.txt @@ -6,6 +6,9 @@ Testing - install gettext command line utilities - Run the following to extract translatable text from the templates: $ rm -f i18n/templates.c +- run custom python to generate i18n for js + $ find resources -name "*.js" | python ./bin/jsi18n.py > templates/ktcore/javascript_i18n.smarty + $ php bin/smarty_to_gettext.php . > i18n/templates.c - run xgettext to generate .po files eg. $ find . -type f -name "*.php" -o -name "*.inc" | xgettext --no-wrap -d knowledgeTree -L PHP -s -f - -o i18n/knowledgeTree.po diff --git a/presentation/i18nJavascript.php b/presentation/i18nJavascript.php new file mode 100644 index 0000000..7303731 --- /dev/null +++ b/presentation/i18nJavascript.php @@ -0,0 +1,28 @@ +loadTemplate("ktcore/javascript_i18n"); + + return $oTemplate->render(); + } +} + +$oD =& new JavascriptTranslationDispatcher(); +$oD->dispatch(); + +?> \ No newline at end of file diff --git a/resources/js/conditional_complex_edit.js b/resources/js/conditional_complex_edit.js index 71bc2ce..b45a3f8 100644 --- a/resources/js/conditional_complex_edit.js +++ b/resources/js/conditional_complex_edit.js @@ -80,7 +80,7 @@ function placeFinishButton() { } var column = getColumnForField(active_field); - var finish_button = INPUT({'type':'button', 'value':'Finish with this column\'s behaviours.','id':'global-stack-popper-button'}); + var finish_button = INPUT({'type':'button', 'value':_('Finish with this column\'s behaviours.'),'id':'global-stack-popper-button'}); simpleLog('DEBUG','placing stack-popper with function popFixedStack in field '+active_field); addEvent(finish_button, 'click', popFixedStack); simpleLog('DEBUG','added listener.'); @@ -155,7 +155,7 @@ function setFixedValueForField(field_id, value, label) { var column = getColumnForField(field_id); simpleLog('DEBUG','fixing value for field '+field_id+' to '+label+' ('+value+')'); addElementClass(column, 'fixed'); - setMessageForField(field_id,'fixed_message', 'Assuming this field has behaviour "'+label+'".'); + setMessageForField(field_id,'fixed_message', _('Assuming this field has behaviour "')+label+'".'); // now we need to check if this field _is_ fixed. var fixed_source = getElementsByTagAndClassName('input','fixed_value',column); diff --git a/resources/js/conditional_simple_edit.js b/resources/js/conditional_simple_edit.js index bc6435a..3aad86e 100644 --- a/resources/js/conditional_simple_edit.js +++ b/resources/js/conditional_simple_edit.js @@ -163,7 +163,7 @@ function storeRelationship(selected_lookup, child_lookups) { // inform the user that something has happened. // FIXME this isn't i18n friendly. - addInformationNote('Dependencies saved. (at ' + new Date() + ')'); + addInformationNote(_('Dependencies saved. (at ') + new Date() + ')'); deferred.addCallback(do_updateActiveLookups); deferred.addErrback(partial(do_handleAjaxError, 'storeRelationship')); @@ -223,7 +223,7 @@ function do_updateActiveLookups(label, req) { } } - addInformationNote('Dependencies for value "'+label+' loaded."(at ' + new Date() + ')'); + addInformationNote(_('Dependencies for value "')+label+('" loaded.(at ') + new Date() + ')'); } @@ -269,7 +269,7 @@ function editSimpleField(field_id) { setExclusiveEditing(field_id); updateActiveFields(); // trigger an update of the backend. // rest is asynchronous. - addInformationNote('Now editing field "'+getNameForField(field_id)+'".'); + addInformationNote(_('Now editing field "')+getNameForField(field_id)+'".'); } @@ -301,7 +301,7 @@ function finishSimpleField(field_id) { // called when a single-view dropdown is activated. function handleChangedSelection(field_id, select_input) { - addInformationNote('Loading Dependencies for value "'+scrapeText(select_input.options[select_input.selectedIndex])+'"(at ' + new Date() + ')'); + addInformationNote(_('Loading Dependencies for value "')+scrapeText(select_input.options[select_input.selectedIndex])+'"(at ' + new Date() + ')'); updateActiveLookups(select_input.value, scrapeText(select_input.options[select_input.selectedIndex])); // handles everything for us. } diff --git a/resources/js/conditional_usage.js b/resources/js/conditional_usage.js index 06522dd..fed9703 100644 --- a/resources/js/conditional_usage.js +++ b/resources/js/conditional_usage.js @@ -329,7 +329,7 @@ function reviseConditional(buttonsource) { var fieldset = breadcrumbFind(buttonsource, 'FIELDSET'); setElementClass(fieldset, 'conditional_metadata'); if (!checkStackForFieldset(fieldset)) { - var undo_button = INPUT({'type':'button','value':'undo'},null); + var undo_button = INPUT({'type':'button','value':_('Undo')},null); attachToElementEvent(undo_button,'click',partial(popStack, fieldset)); fieldset.appendChild(undo_button); // initialise the stack. @@ -352,7 +352,7 @@ function initialiseConditionalFieldsets() { // and insert the initial (master) field. for (var i=0; i
'+_('Criteria')+' '+_('Values')+'
'; // add the fieldset @@ -203,7 +203,7 @@ function addBooleanGroup(addbutton) { // get an id for the table. var table_id = getBooleanGroupId(tableObj); // add the grouping string - groupingString = '

Return items which match   of the criteria specified.

'; + groupingString = '

' + _('Return items which match')+'  '+_('of the criteria specified.')+'

'; t = DIV(null); t.innerHTML = groupingString; var paraObj = t.getElementsByTagName('P')[0]; diff --git a/templates/ktcore/boolean_search.smarty b/templates/ktcore/boolean_search.smarty index c3f81a1..4cd75a0 100644 --- a/templates/ktcore/boolean_search.smarty +++ b/templates/ktcore/boolean_search.smarty @@ -63,7 +63,7 @@ legend { border: 1px dotted #999;} {/if} {capture assign=options} - + {/capture}

{i18n arg_options=$options}Return items which match  #options# of the criteria groups specified.{/i18n}

diff --git a/templates/ktcore/javascript_i18n.smarty b/templates/ktcore/javascript_i18n.smarty new file mode 100644 index 0000000..cbb6f0b --- /dev/null +++ b/templates/ktcore/javascript_i18n.smarty @@ -0,0 +1,61 @@ + +/* + * Javascript (actual translations); + */ + +{literal} +var i18n = {}; + +function _(trans_string) { + var newstr = i18n[trans_string]; + if (!isUndefinedOrNull(newstr)) { return newstr; } + else { + return trans_string; + } +} +{/literal} + + + +// strings for file: resources/js/kt3calendar.js + +// strings for file: resources/js/conditional_complex_edit.js +i18n['Finish with this column\'s behaviours.'] = '{i18n}Finish with this column\'s behaviours.{/i18n}'; +i18n['Assuming this field has behaviour "'] = '{i18n}Assuming this field has behaviour "{/i18n}'; + +// strings for file: resources/js/conditional_simple_edit.js +i18n['Dependencies saved. (at '] = '{i18n}Dependencies saved. (at {/i18n}'; +i18n['Dependencies for value "'] = '{i18n}Dependencies for value "{/i18n}'; +i18n['Now editing field "'] = '{i18n}Now editing field "{/i18n}'; +i18n['Loading Dependencies for value "'] = '{i18n}Loading Dependencies for value "{/i18n}'; + +// strings for file: resources/js/translate.js + +// strings for file: resources/js/constructed_search.js +i18n['Remove'] = '{i18n}Remove{/i18n}'; +i18n['first select a type of query'] = '{i18n}first select a type of query{/i18n}'; +i18n['Add'] = '{i18n}Add{/i18n}'; +i18n['Criteria Group'] = '{i18n}Criteria Group{/i18n}'; +i18n['Criteria'] = '{i18n}Criteria{/i18n}'; +i18n['Values'] = '{i18n}Values{/i18n}'; +i18n['Return items which match'] = '{i18n}Return items which match{/i18n}'; +i18n['all'] = '{i18n}all{/i18n}'; +i18n['any'] = '{i18n}any{/i18n}'; +i18n['of the criteria specified.'] = '{i18n}of the criteria specified.{/i18n}'; + +// strings for file: resources/js/taillog.js + +// strings for file: resources/js/add_document.js + +// strings for file: resources/js/constructed_search_postprocess.js + +// strings for file: resources/js/toggleselect.js + +// strings for file: resources/js/kt-utility.js + +// strings for file: resources/js/help.js + +// strings for file: resources/js/conditional_usage.js +i18n['Undo'] = '{i18n}Undo{/i18n}'; +i18n['Undo'] = '{i18n}Undo{/i18n}'; + diff --git a/templates/ktstandard/action/document_links.smarty b/templates/ktstandard/action/document_links.smarty index 2a5cd6a..bf1937a 100644 --- a/templates/ktstandard/action/document_links.smarty +++ b/templates/ktstandard/action/document_links.smarty @@ -30,7 +30,7 @@ {if $write_permission} - Delete + {i18n}Delete{/i18n} {else}   {/if} @@ -66,7 +66,7 @@ {else} -There are no links to or from this document. +{i18n}There are no links to or from this document.{/i18n} {/if} @@ -77,8 +77,8 @@ {if $write_permission} -Add a new link +{i18n}Add a new link{/i18n} Add a new link. +href="{addQS}action=new&fDocumentId={$context->oDocument->getId()}&fFolderId={$context->oDocument->getFolderId()}{/addQS}">{i18n}Add a new link{/i18n}. {/if}