From 4e214883d64acf4dc9cc3191780086d0a9dac60f Mon Sep 17 00:00:00 2001 From: Jakob Sack Date: Sun, 7 Jul 2013 20:26:09 +0200 Subject: Partly integrate plural translations into js --- core/js/js.js | 55 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 19 deletions(-) (limited to 'core/js/js.js') diff --git a/core/js/js.js b/core/js/js.js index 3904787c4e5..15cf1d286fa 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -1,6 +1,6 @@ /** * Disable console output unless DEBUG mode is enabled. - * Add + * Add * define('DEBUG', true); * To the end of config/config.php to enable debug mode. * The undefined checks fix the broken ie8 console @@ -28,9 +28,11 @@ if (oc_debug !== true || typeof console === "undefined" || typeof console.log == * translate a string * @param app the id of the app for which to translate the string * @param text the string to translate + * @param vars (optional) FIXME + * @param count (optional) number to replace %n with * @return string */ -function t(app,text, vars){ +function t(app, text, vars, count){ if( !( t.cache[app] )){ $.ajax(OC.filePath('core','ajax','translations.php'),{ async:false,//todo a proper sollution for this without sync ajax calls @@ -46,7 +48,8 @@ function t(app,text, vars){ t.cache[app] = []; } } - var _build = function (text, vars) { + var _build = function (text, vars, count) { + // FIXME: replace %n with content of count return text.replace(/{([^{}]*)}/g, function (a, b) { var r = vars[b]; @@ -54,30 +57,44 @@ function t(app,text, vars){ } ); }; + var translation = text; if( typeof( t.cache[app][text] ) !== 'undefined' ){ - if(typeof vars === 'object') { - return _build(t.cache[app][text], vars); - } else { - return t.cache[app][text]; - } + translation = t.cache[app][text]; } - else{ - if(typeof vars === 'object') { - return _build(text, vars); - } else { - return text; - } + + if(typeof vars === 'object' || typeof count !== 'undefined' ) { + return _build(translation, vars, count); + } else { + return translation; } } t.cache={}; -/* +/** + * translate a string + * @param app the id of the app for which to translate the string + * @param text_singular the string to translate for exactly one object + * @param text_plural the string to translate for n objects + * @param count number to determine whether to use singular or plural + * @param vars (optional) FIXME + * @return string + */ +function tp(app, text_singular, text_plural, count, vars){ + if(count==1){ + return t(app, text_singular, vars, count); + } + else{ + return t(app, text_plural, vars, count); + } +} + +/** * Sanitizes a HTML string -* @param string +* @param s string * @return Sanitized string */ function escapeHTML(s) { - return s.toString().split('&').join('&').split('<').join('<').split('"').join('"'); + return s.toString().split('&').join('&').split('<').join('<').split('"').join('"'); } /** @@ -741,7 +758,7 @@ OC.get=function(name) { var namespaces = name.split("."); var tail = namespaces.pop(); var context=window; - + for(var i = 0; i < namespaces.length; i++) { context = context[namespaces[i]]; if(!context){ @@ -760,7 +777,7 @@ OC.set=function(name, value) { var namespaces = name.split("."); var tail = namespaces.pop(); var context=window; - + for(var i = 0; i < namespaces.length; i++) { if(!context[namespaces[i]]){ context[namespaces[i]]={}; -- cgit v1.2.3 From bb0c5bff5fc493dd24c2c9cbbf27986fd5098de1 Mon Sep 17 00:00:00 2001 From: Jakob Sack Date: Tue, 16 Jul 2013 22:16:53 +0200 Subject: Add multiple plural forms to the php part --- core/js/js.js | 11 +++++------ lib/l10n.php | 34 ++++++++++++++++++++++++++++++---- lib/l10n/string.php | 9 ++++++++- 3 files changed, 43 insertions(+), 11 deletions(-) (limited to 'core/js/js.js') diff --git a/core/js/js.js b/core/js/js.js index 15cf1d286fa..37540bd15e7 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -33,7 +33,7 @@ if (oc_debug !== true || typeof console === "undefined" || typeof console.log == * @return string */ function t(app, text, vars, count){ - if( !( t.cache[app] )){ + if( !( t.cache[app] )) { $.ajax(OC.filePath('core','ajax','translations.php'),{ async:false,//todo a proper sollution for this without sync ajax calls data:{'app': app}, @@ -49,8 +49,7 @@ function t(app, text, vars, count){ } } var _build = function (text, vars, count) { - // FIXME: replace %n with content of count - return text.replace(/{([^{}]*)}/g, + return text.replace(/%n/g, count).replace(/{([^{}]*)}/g, function (a, b) { var r = vars[b]; return typeof r === 'string' || typeof r === 'number' ? r : a; @@ -62,7 +61,7 @@ function t(app, text, vars, count){ translation = t.cache[app][text]; } - if(typeof vars === 'object' || typeof count !== 'undefined' ) { + if(typeof vars === 'object' || count !== undefined ) { return _build(translation, vars, count); } else { return translation; @@ -79,8 +78,8 @@ t.cache={}; * @param vars (optional) FIXME * @return string */ -function tp(app, text_singular, text_plural, count, vars){ - if(count==1){ +function n(app, text_singular, text_plural, count, vars){ + if(count === 1) { return t(app, text_singular, vars, count); } else{ diff --git a/lib/l10n.php b/lib/l10n.php index 03528c22746..8348962cc10 100644 --- a/lib/l10n.php +++ b/lib/l10n.php @@ -176,13 +176,28 @@ class OC_L10N{ * * Returns the translation. If no translation is found, $text will be * returned. %n will be replaced with the number of objects. + * + * In case there is more than one plural form you can add a function + * "selectplural" in core/l10n/l10n-*.php + * + * Example: + * + * [...] + * 'selectplural' => function($i){return $i == 1 ? 0 : $i == 2 ? 1 : 2}, + * [...] */ - public function tp($text_singular, $text_plural, $count, $parameters = array()) { - if($count == 1){ - return new OC_L10N_String($this, $text_singular, $parameters, $count); + public function n($text_singular, $text_plural, $count, $parameters = array()) { + $identifier = "_${text_singular}__${text_plural}_"; + if(array_key_exists( $this->localizations, "selectplural") && array_key_exists($this->translations, $identifier)) { + return new OC_L10N_String( $this, $identifier, $parameters, $count ); } else{ - return new OC_L10N_String($this, $text_plural, $parameters, $count); + if($count === 1) { + return new OC_L10N_String($this, $text_singular, $parameters, $count); + } + else{ + return new OC_L10N_String($this, $text_plural, $parameters, $count); + } } } @@ -220,6 +235,17 @@ class OC_L10N{ return $this->translations; } + /** + * @brief get localizations + * @returns Fetch all localizations + * + * Returns an associative array with all localizations + */ + public function getLocalizations() { + $this->init(); + return $this->localizations; + } + /** * @brief Localization * @param $type Type of localization diff --git a/lib/l10n/string.php b/lib/l10n/string.php index 1bef7330945..3cda5eab506 100644 --- a/lib/l10n/string.php +++ b/lib/l10n/string.php @@ -18,10 +18,17 @@ class OC_L10N_String{ public function __toString() { $translations = $this->l10n->getTranslations(); + $localizations = $this->l10n->getLocalizations(); $text = $this->text; if(array_key_exists($this->text, $translations)) { - $text = $translations[$this->text]; + if(is_array($translations[$this->text])) { + $id = $localizations["selectplural"]( $count ); + $text = $translations[$this->text][$id] + } + else{ + $text = $translations[$this->text]; + } } // Replace %n first (won't interfere with vsprintf) $text = str_replace('%n', $this->count, $text); -- cgit v1.2.3 From d97e3c3571acb2ea88623384f4b17ced41dc0be9 Mon Sep 17 00:00:00 2001 From: Thomas Müller Date: Sat, 3 Aug 2013 23:31:49 +0200 Subject: adding proper evaluation of plural form - uses LGPL licensed code of jsgettext --- core/js/js.js | 79 ++++++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 17 deletions(-) (limited to 'core/js/js.js') diff --git a/core/js/js.js b/core/js/js.js index 37540bd15e7..b687c408bca 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -24,6 +24,55 @@ if (oc_debug !== true || typeof console === "undefined" || typeof console.log == } } +function initL10N(app) { + if (!( t.cache[app] )) { + $.ajax(OC.filePath('core', 'ajax', 'translations.php'), { + async: false,//todo a proper solution for this without sync ajax calls + data: {'app': app}, + type: 'POST', + success: function (jsondata) { + t.cache[app] = jsondata.data; + t.plural_form = jsondata.plural_form; + } + }); + + // Bad answer ... + if (!( t.cache[app] )) { + t.cache[app] = []; + } + } + if (typeof t.plural_function == 'undefined') { + t.plural_function = function (n) { + var p = (n != 1) ? 1 : 0; + return { 'nplural' : 2, 'plural' : p }; + }; + + /** + * code below has been taken from jsgettext - which is LGPL licensed + * https://developer.berlios.de/projects/jsgettext/ + * http://cvs.berlios.de/cgi-bin/viewcvs.cgi/jsgettext/jsgettext/lib/Gettext.js + */ + var pf_re = new RegExp('^(\\s*nplurals\\s*=\\s*[0-9]+\\s*;\\s*plural\\s*=\\s*(?:\\s|[-\\?\\|&=!<>+*/%:;a-zA-Z0-9_\(\)])+)', 'm'); + if (pf_re.test(t.plural_form)) { + //ex english: "Plural-Forms: nplurals=2; plural=(n != 1);\n" + //pf = "nplurals=2; plural=(n != 1);"; + //ex russian: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10< =4 && (n%100<10 or n%100>=20) ? 1 : 2) + //pf = "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)"; + var pf = t.plural_form; + if (! /;\s*$/.test(pf)) pf = pf.concat(';'); + /* We used to use eval, but it seems IE has issues with it. + * We now use "new Function", though it carries a slightly + * bigger performance hit. + var code = 'function (n) { var plural; var nplurals; '+pf+' return { "nplural" : nplurals, "plural" : (plural === true ? 1 : plural ? plural : 0) }; };'; + Gettext._locale_data[domain].head.plural_func = eval("("+code+")"); + */ + var code = 'var plural; var nplurals; '+pf+' return { "nplural" : nplurals, "plural" : (plural === true ? 1 : plural ? plural : 0) };'; + t.plural_function = new Function("n", code); + } else { + console.log("Syntax error in language file. Plural-Forms header is invalid ["+plural_forms+"]"); + } + } +} /** * translate a string * @param app the id of the app for which to translate the string @@ -33,21 +82,7 @@ if (oc_debug !== true || typeof console === "undefined" || typeof console.log == * @return string */ function t(app, text, vars, count){ - if( !( t.cache[app] )) { - $.ajax(OC.filePath('core','ajax','translations.php'),{ - async:false,//todo a proper sollution for this without sync ajax calls - data:{'app': app}, - type:'POST', - success:function(jsondata){ - t.cache[app] = jsondata.data; - } - }); - - // Bad answer ... - if( !( t.cache[app] )){ - t.cache[app] = []; - } - } + initL10N(app); var _build = function (text, vars, count) { return text.replace(/%n/g, count).replace(/{([^{}]*)}/g, function (a, b) { @@ -67,7 +102,7 @@ function t(app, text, vars, count){ return translation; } } -t.cache={}; +t.cache = {}; /** * translate a string @@ -78,7 +113,17 @@ t.cache={}; * @param vars (optional) FIXME * @return string */ -function n(app, text_singular, text_plural, count, vars){ +function n(app, text_singular, text_plural, count, vars) { + initL10N(app); + var identifier = '_' + text_singular + '__' + text_plural + '_'; + if( typeof( t.cache[app][identifier] ) !== 'undefined' ){ + var translation = t.cache[app][identifier]; + if ($.isArray(translation)) { + var plural = t.plural_function(count); + return t(app, translation[plural.plural], vars, count); + } + } + if(count === 1) { return t(app, text_singular, vars, count); } -- cgit v1.2.3 From 9549bd3e68aa32bb9fa1a9a54bda84fa5070966f Mon Sep 17 00:00:00 2001 From: kondou Date: Fri, 9 Aug 2013 20:37:18 +0200 Subject: Use plural translations --- apps/files/js/filelist.js | 5 +++-- apps/files/js/files.js | 14 +++----------- apps/files_trashbin/js/trash.js | 12 ++---------- core/js/js.js | 10 ++++------ lib/template/functions.php | 10 ++++------ 5 files changed, 16 insertions(+), 35 deletions(-) (limited to 'core/js/js.js') diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index b858e2580ee..e0c72295702 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -452,13 +452,14 @@ $(document).ready(function(){ var currentUploads = parseInt(uploadtext.attr('currentUploads')); currentUploads += 1; uploadtext.attr('currentUploads', currentUploads); + var translatedText = n('files', '%n file uploading', '%n files uploading', currentUploads); if(currentUploads === 1) { var img = OC.imagePath('core', 'loading.gif'); data.context.find('td.filename').attr('style','background-image:url('+img+')'); - uploadtext.text(t('files', '1 file uploading')); + uploadtext.text(translatedText); uploadtext.show(); } else { - uploadtext.text(currentUploads + ' ' + t('files', 'files uploading')); + uploadtext.text(translatedText); } } else { // add as stand-alone row to filelist diff --git a/apps/files/js/files.js b/apps/files/js/files.js index 3fad3fae7d3..53fc25f41b0 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -759,21 +759,13 @@ function procesSelection(){ $('#headerSize').text(humanFileSize(totalSize)); var selection=''; if(selectedFolders.length>0){ - if(selectedFolders.length==1){ - selection+=t('files','1 folder'); - }else{ - selection+=t('files','{count} folders',{count: selectedFolders.length}); - } + selection += n('files', '%n folder', '%n folders', selectedFolders.length); if(selectedFiles.length>0){ selection+=' & '; } } if(selectedFiles.length>0){ - if(selectedFiles.length==1){ - selection+=t('files','1 file'); - }else{ - selection+=t('files','{count} files',{count: selectedFiles.length}); - } + selection += n('files', '%n file', '%n files', selectedFiles.length); } $('#headerName>span.name').text(selection); $('#modified').text(''); @@ -852,4 +844,4 @@ function checkTrashStatus() { $("input[type=button][id=trash]").removeAttr("disabled"); } }); -} \ No newline at end of file +} diff --git a/apps/files_trashbin/js/trash.js b/apps/files_trashbin/js/trash.js index c3c958b07a7..b14a7240cbe 100644 --- a/apps/files_trashbin/js/trash.js +++ b/apps/files_trashbin/js/trash.js @@ -188,21 +188,13 @@ function processSelection(){ $('.selectedActions').show(); var selection=''; if(selectedFolders.length>0){ - if(selectedFolders.length === 1){ - selection+=t('files','1 folder'); - }else{ - selection+=t('files','{count} folders',{count: selectedFolders.length}); - } + selection += n('files', '%n folder', '%n folders', selectedFolders.length); if(selectedFiles.length>0){ selection+=' & '; } } if(selectedFiles.length>0){ - if(selectedFiles.length === 1){ - selection+=t('files','1 file'); - }else{ - selection+=t('files','{count} files',{count: selectedFiles.length}); - } + selection += n('files', '%n file', '%n files', selectedFiles.length); } $('#headerName>span.name').text(selection); $('#modified').text(''); diff --git a/core/js/js.js b/core/js/js.js index 1d1711383f7..0fc4bab80a7 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -812,15 +812,13 @@ function relative_modified_date(timestamp) { var diffdays = Math.round(diffhours/24); var diffmonths = Math.round(diffdays/31); if(timediff < 60) { return t('core','seconds ago'); } - else if(timediff < 120) { return t('core','1 minute ago'); } - else if(timediff < 3600) { return t('core','{minutes} minutes ago',{minutes: diffminutes}); } - else if(timediff < 7200) { return t('core','1 hour ago'); } - else if(timediff < 86400) { return t('core','{hours} hours ago',{hours: diffhours}); } + else if(timediff < 3600) { return n('core','%n minute ago', '%n minutes ago', diffminutes); } + else if(timediff < 86400) { return n('core', '%n hour ago', '%n hours ago', diffhours); } else if(timediff < 86400) { return t('core','today'); } else if(timediff < 172800) { return t('core','yesterday'); } - else if(timediff < 2678400) { return t('core','{days} days ago',{days: diffdays}); } + else if(timediff < 2678400) { return n('core', '%n day ago', '%n days ago', diffdays); } else if(timediff < 5184000) { return t('core','last month'); } - else if(timediff < 31556926) { return t('core','{months} months ago',{months: diffmonths}); } + else if(timediff < 31556926) { return n('core', '%n month ago', '%n months ago', diffmonths); } //else if(timediff < 31556926) { return t('core','months ago'); } else if(timediff < 63113852) { return t('core','last year'); } else { return t('core','years ago'); } diff --git a/lib/template/functions.php b/lib/template/functions.php index 2d43cae1c0c..717e197c1cb 100644 --- a/lib/template/functions.php +++ b/lib/template/functions.php @@ -78,15 +78,13 @@ function relative_modified_date($timestamp) { $diffmonths = round($diffdays/31); if($timediff < 60) { return $l->t('seconds ago'); } - else if($timediff < 120) { return $l->t('1 minute ago'); } - else if($timediff < 3600) { return $l->t('%d minutes ago', $diffminutes); } - else if($timediff < 7200) { return $l->t('1 hour ago'); } - else if($timediff < 86400) { return $l->t('%d hours ago', $diffhours); } + else if($timediff < 3600) { return $l->n('%n minute ago', '%n minutes ago', $diffminutes); } + else if($timediff < 86400) { return $l->n('%n hour ago', '%n hours ago', $diffhours); } else if((date('G')-$diffhours) > 0) { return $l->t('today'); } else if((date('G')-$diffhours) > -24) { return $l->t('yesterday'); } - else if($timediff < 2678400) { return $l->t('%d days ago', $diffdays); } + else if($timediff < 2678400) { return $l->n('%n day go', '%n days ago', $diffdays); } else if($timediff < 5184000) { return $l->t('last month'); } - else if((date('n')-$diffmonths) > 0) { return $l->t('%d months ago', $diffmonths); } + else if((date('n')-$diffmonths) > 0) { return $l->n('%n month ago', '%n months ago', $diffmonths); } else if($timediff < 63113852) { return $l->t('last year'); } else { return $l->t('years ago'); } } -- cgit v1.2.3 From 5660f99592b313e423c0b7d9682dacb1896ce102 Mon Sep 17 00:00:00 2001 From: Jörn Friedrich Dreyer Date: Tue, 13 Aug 2013 22:58:27 +0200 Subject: add PERMISSIONS_ALL summary --- core/js/js.js | 1 + 1 file changed, 1 insertion(+) (limited to 'core/js/js.js') diff --git a/core/js/js.js b/core/js/js.js index 1d1711383f7..64b5556987d 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -157,6 +157,7 @@ var OC={ PERMISSION_UPDATE:2, PERMISSION_DELETE:8, PERMISSION_SHARE:16, + PERMISSION_ALL:31, webroot:oc_webroot, appswebroots:(typeof oc_appswebroots !== 'undefined') ? oc_appswebroots:false, currentUser:(typeof oc_current_user!=='undefined')?oc_current_user:false, -- cgit v1.2.3