Merge pull request #4271 from owncloud/plural_translations
Plural translations
This commit is contained in:
commit
a2ac5e0163
|
@ -27,4 +27,4 @@ $app = OC_App::cleanAppId($app);
|
|||
|
||||
$l = OC_L10N::get( $app );
|
||||
|
||||
OC_JSON::success(array('data' => $l->getTranslations()));
|
||||
OC_JSON::success(array('data' => $l->getTranslations(), 'plural_form' => $l->getPluralFormString()));
|
||||
|
|
129
core/js/js.js
129
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
|
||||
|
@ -24,60 +24,121 @@ 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
|
||||
* @return string
|
||||
*/
|
||||
function t(app,text, vars){
|
||||
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){
|
||||
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] )){
|
||||
if (!( t.cache[app] )) {
|
||||
t.cache[app] = [];
|
||||
}
|
||||
}
|
||||
var _build = function (text, vars) {
|
||||
return text.replace(/{([^{}]*)}/g,
|
||||
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
|
||||
* @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, count){
|
||||
initL10N(app);
|
||||
var _build = function (text, vars, count) {
|
||||
return text.replace(/%n/g, count).replace(/{([^{}]*)}/g,
|
||||
function (a, b) {
|
||||
var r = vars[b];
|
||||
return typeof r === 'string' || typeof r === 'number' ? r : a;
|
||||
}
|
||||
);
|
||||
};
|
||||
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' || count !== undefined ) {
|
||||
return _build(translation, vars, count);
|
||||
} else {
|
||||
return translation;
|
||||
}
|
||||
}
|
||||
t.cache={};
|
||||
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 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);
|
||||
}
|
||||
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('"');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -773,7 +834,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){
|
||||
|
@ -792,7 +853,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]]={};
|
||||
|
|
54
l10n/l10n.pl
54
l10n/l10n.pl
|
@ -39,7 +39,7 @@ sub crawlFiles{
|
|||
foreach my $i ( @files ){
|
||||
next if substr( $i, 0, 1 ) eq '.';
|
||||
next if $i eq 'l10n';
|
||||
|
||||
|
||||
if( -d $dir.'/'.$i ){
|
||||
push( @found, crawlFiles( $dir.'/'.$i ));
|
||||
}
|
||||
|
@ -64,6 +64,16 @@ sub readIgnorelist{
|
|||
return %ignore;
|
||||
}
|
||||
|
||||
sub getPluralInfo {
|
||||
my( $info ) = @_;
|
||||
|
||||
# get string
|
||||
$info =~ s/.*Plural-Forms: (.+)\\n.*/$1/;
|
||||
$info =~ s/^(.*)\\n.*/$1/g;
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
my $task = shift( @ARGV );
|
||||
my $place = '..';
|
||||
|
||||
|
@ -100,11 +110,17 @@ if( $task eq 'read' ){
|
|||
|
||||
foreach my $file ( @totranslate ){
|
||||
next if $ignore{$file};
|
||||
my $keyword = ( $file =~ /\.js$/ ? 't:2' : 't');
|
||||
my $keywords = '';
|
||||
if( $file =~ /\.js$/ ){
|
||||
$keywords = '--keyword=t:2 --keyword=n:2,3';
|
||||
}
|
||||
else{
|
||||
$keywords = '--keyword=t --keyword=n:1,2';
|
||||
}
|
||||
my $language = ( $file =~ /\.js$/ ? 'Python' : 'PHP');
|
||||
my $joinexisting = ( -e $output ? '--join-existing' : '');
|
||||
print " Reading $file\n";
|
||||
`xgettext --output="$output" $joinexisting --keyword=$keyword --language=$language "$file" --from-code=UTF-8 --package-version="5.0.0" --package-name="ownCloud Core" --msgid-bugs-address="translations\@owncloud.org"`;
|
||||
`xgettext --output="$output" $joinexisting $keywords --language=$language "$file" --from-code=UTF-8 --package-version="5.0.0" --package-name="ownCloud Core" --msgid-bugs-address="translations\@owncloud.org"`;
|
||||
}
|
||||
chdir( $whereami );
|
||||
}
|
||||
|
@ -118,7 +134,7 @@ elsif( $task eq 'write' ){
|
|||
print " Processing $app\n";
|
||||
foreach my $language ( @languages ){
|
||||
next if $language eq 'templates';
|
||||
|
||||
|
||||
my $input = "${whereami}/$language/$app.po";
|
||||
next unless -e $input;
|
||||
|
||||
|
@ -126,18 +142,38 @@ elsif( $task eq 'write' ){
|
|||
my $array = Locale::PO->load_file_asarray( $input );
|
||||
# Create array
|
||||
my @strings = ();
|
||||
my $plurals;
|
||||
|
||||
foreach my $string ( @{$array} ){
|
||||
next if $string->msgid() eq '""';
|
||||
next if $string->msgstr() eq '""';
|
||||
push( @strings, $string->msgid()." => ".$string->msgstr());
|
||||
if( $string->msgid() eq '""' ){
|
||||
# Translator information
|
||||
$plurals = getPluralInfo( $string->msgstr());
|
||||
}
|
||||
elsif( defined( $string->msgstr_n() )){
|
||||
# plural translations
|
||||
my @variants = ();
|
||||
my $identifier = $string->msgid()."::".$string->msgid_plural();
|
||||
$identifier =~ s/"/_/g;
|
||||
|
||||
foreach my $variant ( sort { $a <=> $b} keys( %{$string->msgstr_n()} )){
|
||||
push( @variants, $string->msgstr_n()->{$variant} );
|
||||
}
|
||||
|
||||
push( @strings, "\"$identifier\" => array(".join(@variants, ",").")");
|
||||
}
|
||||
else{
|
||||
# singular translations
|
||||
next if $string->msgstr() eq '""';
|
||||
push( @strings, $string->msgid()." => ".$string->msgstr());
|
||||
}
|
||||
}
|
||||
next if $#strings == -1; # Skip empty files
|
||||
|
||||
# Write PHP file
|
||||
open( OUT, ">$language.php" );
|
||||
print OUT "<?php \$TRANSLATIONS = array(\n";
|
||||
print OUT "<?php\n\$TRANSLATIONS = array(\n";
|
||||
print OUT join( ",\n", @strings );
|
||||
print OUT "\n);\n";
|
||||
print OUT "\n);\n\$PLURAL_FORMS = \"$plurals\";\n";
|
||||
close( OUT );
|
||||
}
|
||||
chdir( $whereami );
|
||||
|
|
168
lib/l10n.php
168
lib/l10n.php
|
@ -2,8 +2,10 @@
|
|||
/**
|
||||
* ownCloud
|
||||
*
|
||||
* @author Frank Karlitschek
|
||||
* @author Jakob Sack
|
||||
* @copyright 2012 Frank Karlitschek frank@owncloud.org
|
||||
* @copyright 2013 Jakob Sack
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
|
@ -23,7 +25,7 @@
|
|||
/**
|
||||
* This class is for i18n and l10n
|
||||
*/
|
||||
class OC_L10N{
|
||||
class OC_L10N {
|
||||
/**
|
||||
* cached instances
|
||||
*/
|
||||
|
@ -54,6 +56,16 @@ class OC_L10N{
|
|||
*/
|
||||
private $translations = array();
|
||||
|
||||
/**
|
||||
* Plural forms (string)
|
||||
*/
|
||||
private $plural_form_string = 'nplurals=2; plural=(n != 1);';
|
||||
|
||||
/**
|
||||
* Plural forms (function)
|
||||
*/
|
||||
private $plural_form_function = null;
|
||||
|
||||
/**
|
||||
* Localization
|
||||
*/
|
||||
|
@ -66,6 +78,8 @@ class OC_L10N{
|
|||
|
||||
/**
|
||||
* get an L10N instance
|
||||
* @param $app string
|
||||
* @param $lang string|null
|
||||
* @return OC_L10N
|
||||
*/
|
||||
public static function get($app, $lang=null) {
|
||||
|
@ -81,8 +95,8 @@ class OC_L10N{
|
|||
|
||||
/**
|
||||
* @brief The constructor
|
||||
* @param $app the app requesting l10n
|
||||
* @param $lang default: null Language
|
||||
* @param $app string app requesting l10n
|
||||
* @param $lang string default: null Language
|
||||
* @returns OC_L10N-Object
|
||||
*
|
||||
* If language is not set, the constructor tries to find the right
|
||||
|
@ -93,6 +107,17 @@ class OC_L10N{
|
|||
$this->lang = $lang;
|
||||
}
|
||||
|
||||
public function load($transFile) {
|
||||
$this->app = true;
|
||||
include $transFile;
|
||||
if(isset($TRANSLATIONS) && is_array($TRANSLATIONS)) {
|
||||
$this->translations = $TRANSLATIONS;
|
||||
}
|
||||
if(isset($PLURAL_FORMS)) {
|
||||
$this->plural_form_string = $PLURAL_FORMS;
|
||||
}
|
||||
}
|
||||
|
||||
protected function init() {
|
||||
if ($this->app === true) {
|
||||
return;
|
||||
|
@ -138,6 +163,9 @@ class OC_L10N{
|
|||
}
|
||||
}
|
||||
}
|
||||
if(isset($PLURAL_FORMS)) {
|
||||
$this->plural_form_string = $PLURAL_FORMS;
|
||||
}
|
||||
}
|
||||
|
||||
if(file_exists(OC::$SERVERROOT.'/core/l10n/l10n-'.$lang.'.php')) {
|
||||
|
@ -153,6 +181,65 @@ class OC_L10N{
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a function that The constructor
|
||||
*
|
||||
* If language is not set, the constructor tries to find the right
|
||||
* language.
|
||||
*
|
||||
* Parts of the code is copied from Habari:
|
||||
* https://github.com/habari/system/blob/master/classes/locale.php
|
||||
* @param $string string
|
||||
* @return string
|
||||
*/
|
||||
protected function createPluralFormFunction($string){
|
||||
if(preg_match( '/^\s*nplurals\s*=\s*(\d+)\s*;\s*plural=(.*)$/u', $string, $matches)) {
|
||||
// sanitize
|
||||
$nplurals = preg_replace( '/[^0-9]/', '', $matches[1] );
|
||||
$plural = preg_replace( '#[^n0-9:\(\)\?\|\&=!<>+*/\%-]#', '', $matches[2] );
|
||||
|
||||
$body = str_replace(
|
||||
array( 'plural', 'n', '$n$plurals', ),
|
||||
array( '$plural', '$n', '$nplurals', ),
|
||||
'nplurals='. $nplurals . '; plural=' . $plural
|
||||
);
|
||||
|
||||
// add parents
|
||||
// important since PHP's ternary evaluates from left to right
|
||||
$body .= ';';
|
||||
$res = '';
|
||||
$p = 0;
|
||||
for($i = 0; $i < strlen($body); $i++) {
|
||||
$ch = $body[$i];
|
||||
switch ( $ch ) {
|
||||
case '?':
|
||||
$res .= ' ? (';
|
||||
$p++;
|
||||
break;
|
||||
case ':':
|
||||
$res .= ') : (';
|
||||
break;
|
||||
case ';':
|
||||
$res .= str_repeat( ')', $p ) . ';';
|
||||
$p = 0;
|
||||
break;
|
||||
default:
|
||||
$res .= $ch;
|
||||
}
|
||||
}
|
||||
|
||||
$body = $res . 'return ($plural>=$nplurals?$nplurals-1:$plural);';
|
||||
return create_function('$n', $body);
|
||||
}
|
||||
else {
|
||||
// default: one plural form for all cases but n==1 (english)
|
||||
return create_function(
|
||||
'$n',
|
||||
'$nplurals=2;$plural=($n==1?0:1);return ($plural>=$nplurals?$nplurals-1:$plural);'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Translating
|
||||
* @param $text String The text we need a translation for
|
||||
|
@ -166,6 +253,37 @@ class OC_L10N{
|
|||
return new OC_L10N_String($this, $text, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Translating
|
||||
* @param $text_singular String the string to translate for exactly one object
|
||||
* @param $text_plural String the string to translate for n objects
|
||||
* @param $count Integer Number of objects
|
||||
* @param array $parameters default:array() Parameters for sprintf
|
||||
* @return \OC_L10N_String Translation or the same text
|
||||
*
|
||||
* Returns the translation. If no translation is found, $text will be
|
||||
* returned. %n will be replaced with the number of objects.
|
||||
*
|
||||
* The correct plural is determined by the plural_forms-function
|
||||
* provided by the po file.
|
||||
*
|
||||
*/
|
||||
public function n($text_singular, $text_plural, $count, $parameters = array()) {
|
||||
$this->init();
|
||||
$identifier = "_${text_singular}__${text_plural}_";
|
||||
if( array_key_exists($identifier, $this->translations)) {
|
||||
return new OC_L10N_String( $this, $identifier, $parameters, $count );
|
||||
}
|
||||
else{
|
||||
if($count === 1) {
|
||||
return new OC_L10N_String($this, $text_singular, $parameters, $count);
|
||||
}
|
||||
else{
|
||||
return new OC_L10N_String($this, $text_plural, $parameters, $count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Translating
|
||||
* @param $textArray The text array we need a translation for
|
||||
|
@ -200,6 +318,42 @@ class OC_L10N{
|
|||
return $this->translations;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief getPluralFormString
|
||||
* @returns string containing the gettext "Plural-Forms"-string
|
||||
*
|
||||
* Returns a string like "nplurals=2; plural=(n != 1);"
|
||||
*/
|
||||
public function getPluralFormString() {
|
||||
$this->init();
|
||||
return $this->plural_form_string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief getPluralFormFunction
|
||||
* @returns string the plural form function
|
||||
*
|
||||
* returned function accepts the argument $n
|
||||
*/
|
||||
public function getPluralFormFunction() {
|
||||
$this->init();
|
||||
if(is_null($this->plural_form_function)) {
|
||||
$this->plural_form_function = $this->createPluralFormFunction($this->plural_form_string);
|
||||
}
|
||||
return $this->plural_form_function;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
|
@ -230,8 +384,12 @@ class OC_L10N{
|
|||
case 'date':
|
||||
case 'datetime':
|
||||
case 'time':
|
||||
if($data instanceof DateTime) return $data->format($this->localizations[$type]);
|
||||
elseif(is_string($data)) $data = strtotime($data);
|
||||
if($data instanceof DateTime) {
|
||||
return $data->format($this->localizations[$type]);
|
||||
}
|
||||
elseif(is_string($data)) {
|
||||
$data = strtotime($data);
|
||||
}
|
||||
$locales = array(self::findLanguage());
|
||||
if (strlen($locales[0]) == 2) {
|
||||
$locales[] = $locales[0].'_'.strtoupper($locales[0]);
|
||||
|
|
|
@ -7,19 +7,50 @@
|
|||
*/
|
||||
|
||||
class OC_L10N_String{
|
||||
/**
|
||||
* @var OC_L10N
|
||||
*/
|
||||
protected $l10n;
|
||||
public function __construct($l10n, $text, $parameters) {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $text;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $parameters;
|
||||
|
||||
/**
|
||||
* @var integer
|
||||
*/
|
||||
protected $count;
|
||||
|
||||
public function __construct($l10n, $text, $parameters, $count = 1) {
|
||||
$this->l10n = $l10n;
|
||||
$this->text = $text;
|
||||
$this->parameters = $parameters;
|
||||
|
||||
$this->count = $count;
|
||||
}
|
||||
|
||||
public function __toString() {
|
||||
$translations = $this->l10n->getTranslations();
|
||||
|
||||
$text = $this->text;
|
||||
if(array_key_exists($this->text, $translations)) {
|
||||
return vsprintf($translations[$this->text], $this->parameters);
|
||||
if(is_array($translations[$this->text])) {
|
||||
$fn = $this->l10n->getPluralFormFunction();
|
||||
$id = $fn($this->count);
|
||||
$text = $translations[$this->text][$id];
|
||||
}
|
||||
else{
|
||||
$text = $translations[$this->text];
|
||||
}
|
||||
}
|
||||
return vsprintf($this->text, $this->parameters);
|
||||
|
||||
// Replace %n first (won't interfere with vsprintf)
|
||||
$text = str_replace('%n', $this->count, $text);
|
||||
return vsprintf($text, $this->parameters);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"_%n window__%n windows_" => array("%n okno", "%n okna", "%n oken")
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;";
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"_%n file__%n files_" => array("%n Datei", "%n Dateien")
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=2; plural=(n != 1);";
|
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
$TRANSLATIONS = array(
|
||||
"_%n file__%n files_" => array("%n файл", "%n файла", "%n файлов")
|
||||
);
|
||||
$PLURAL_FORMS = "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);";
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
/**
|
||||
* Copyright (c) 2013 Thomas Müller <thomas.mueller@tmit.eu>
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later.
|
||||
* See the COPYING-README file.
|
||||
*/
|
||||
|
||||
class Test_L10n extends PHPUnit_Framework_TestCase {
|
||||
|
||||
public function testGermanPluralTranslations() {
|
||||
$l = new OC_L10N('test');
|
||||
$transFile = OC::$SERVERROOT.'/tests/data/l10n/de.php';
|
||||
|
||||
$l->load($transFile);
|
||||
$this->assertEquals('1 Datei', (string)$l->n('%n file', '%n files', 1));
|
||||
$this->assertEquals('2 Dateien', (string)$l->n('%n file', '%n files', 2));
|
||||
}
|
||||
|
||||
public function testRussianPluralTranslations() {
|
||||
$l = new OC_L10N('test');
|
||||
$transFile = OC::$SERVERROOT.'/tests/data/l10n/ru.php';
|
||||
|
||||
$l->load($transFile);
|
||||
$this->assertEquals('1 файл', (string)$l->n('%n file', '%n files', 1));
|
||||
$this->assertEquals('2 файла', (string)$l->n('%n file', '%n files', 2));
|
||||
$this->assertEquals('6 файлов', (string)$l->n('%n file', '%n files', 6));
|
||||
$this->assertEquals('21 файл', (string)$l->n('%n file', '%n files', 21));
|
||||
$this->assertEquals('22 файла', (string)$l->n('%n file', '%n files', 22));
|
||||
$this->assertEquals('26 файлов', (string)$l->n('%n file', '%n files', 26));
|
||||
|
||||
/*
|
||||
1 file 1 файл 1 папка
|
||||
2-4 files 2-4 файла 2-4 папки
|
||||
5-20 files 5-20 файлов 5-20 папок
|
||||
21 files 21 файл 21 папка
|
||||
22-24 files 22-24 файла 22-24 папки
|
||||
25-30 files 25-30 файлов 25-30 папок
|
||||
etc
|
||||
100 files 100 файлов, 100 папок
|
||||
1000 files 1000 файлов 1000 папок
|
||||
*/
|
||||
}
|
||||
|
||||
public function testCzechPluralTranslations() {
|
||||
$l = new OC_L10N('test');
|
||||
$transFile = OC::$SERVERROOT.'/tests/data/l10n/cs.php';
|
||||
|
||||
$l->load($transFile);
|
||||
$this->assertEquals('1 okno', (string)$l->n('%n window', '%n windows', 1));
|
||||
$this->assertEquals('2 okna', (string)$l->n('%n window', '%n windows', 2));
|
||||
$this->assertEquals('5 oken', (string)$l->n('%n window', '%n windows', 5));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue