Commit 9e9a982252a4aaa6a876e0c63a69416a12672bed

Authored by Brad Shuttleworth
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
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 &nbsp;<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')+' &nbsp;<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 &nbsp;#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 &nbsp;
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  
... ...