diff --git a/translationtool/.gitignore b/translationtool/.gitignore new file mode 100644 index 0000000..8f483a6 --- /dev/null +++ b/translationtool/.gitignore @@ -0,0 +1,3 @@ +vendor +composer.phar +.vscode diff --git a/translationtool/Makefile b/translationtool/Makefile new file mode 100644 index 0000000..d48b225 --- /dev/null +++ b/translationtool/Makefile @@ -0,0 +1,16 @@ +.PHONY: translationtool.phar + +translationtool.phar: install-composer-deps + php -d phar.readonly=off vendor/bin/phar-composer build src + chmod +x translationtool.phar + +install-composer-deps: composer.phar + php composer.phar install + php composer.phar install -d src + +composer.phar: + curl -sS https://getcomposer.org/installer | php + +clean: + rm -f translationtool.phar composer.lock src/composer.lock + rm -rf vendor src/vendor \ No newline at end of file diff --git a/translationtool/README.md b/translationtool/README.md new file mode 100644 index 0000000..596a867 --- /dev/null +++ b/translationtool/README.md @@ -0,0 +1,16 @@ +# Nextcloud translation tool + +This tool is used to extract translatable texts from the source code and to create translation files that can be used by Nextcloud. + +## Generating PO files + +To extract the texts from the source code and create a pot file simply go to the folder of your app and run +`php /path/to/translationhelper.phar create-pot-files`. Now the script will create a folder called *translationfiles* +and put the generated pot file in there. One pot file will be created for each app. + +You'll find the pot files in *translationfiles/templates/$app.pot* + +## Generating Nextcloud files + +Once you have the translated po files under *translationfiles/$lang/$app.po* you can create the js and json files used by Nextcloud. +To do so run `php /path/to/translationhelper.phar convert-po-files`. The files are then put in the *l10n* folder of the apps. diff --git a/translationtool/composer.json b/translationtool/composer.json new file mode 100644 index 0000000..085ada2 --- /dev/null +++ b/translationtool/composer.json @@ -0,0 +1,13 @@ +{ + "name": "nextcloud/translationtool", + "description": "Needed for the translation tool", + "license": "MIT", + "config": { + "vendor-dir": "vendor", + "optimize-autoloader": true, + "classmap-authoritative": true + }, + "require": { + "clue/phar-composer": "^1.0" + } +} diff --git a/translationtool/composer.lock b/translationtool/composer.lock new file mode 100644 index 0000000..262c68e --- /dev/null +++ b/translationtool/composer.lock @@ -0,0 +1,953 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "content-hash": "0637cd208635bbacd438aa8ffe1dd928", + "packages": [ + { + "name": "clue/phar-composer", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/clue/phar-composer.git", + "reference": "3ea2cd961c45290b2578c6bf971ae028bfcd6377" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/clue/phar-composer/zipball/3ea2cd961c45290b2578c6bf971ae028bfcd6377", + "reference": "3ea2cd961c45290b2578c6bf971ae028bfcd6377", + "shasum": "" + }, + "require": { + "herrera-io/box": "~1.5", + "knplabs/packagist-api": "~1.0", + "symfony/console": "~2.1", + "symfony/finder": "~2.1", + "symfony/process": "~2.1" + }, + "bin": [ + "bin/phar-composer" + ], + "type": "library", + "extra": { + "phar": { + "bundler": "composer" + } + }, + "autoload": { + "psr-0": { + "Clue": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@lueck.tv" + } + ], + "description": "Simple phar creation for your projects managed via composer", + "homepage": "https://github.com/clue/phar-composer", + "keywords": [ + "build process", + "bundle dependencies", + "executable phar" + ], + "time": "2015-11-15T18:36:37+00:00" + }, + { + "name": "doctrine/inflector", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "e11d84c6e018beedd929cff5220969a3c6d1d462" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/e11d84c6e018beedd929cff5220969a3c6d1d462", + "reference": "e11d84c6e018beedd929cff5220969a3c6d1d462", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Common String Manipulations with regard to casing and singular/plural rules.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "inflection", + "pluralize", + "singularize", + "string" + ], + "time": "2017-07-22T12:18:28+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "6.3.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/f4db5a78a5ea468d4831de7f0bf9d9415e348699", + "reference": "f4db5a78a5ea468d4831de7f0bf9d9415e348699", + "shasum": "" + }, + "require": { + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.4", + "php": ">=5.5" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "^4.0 || ^5.0", + "psr/log": "^1.0" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.2-dev" + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "time": "2017-06-22T18:50:49+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "v1.3.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646", + "shasum": "" + }, + "require": { + "php": ">=5.5.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "time": "2016-12-20T10:07:11+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "1.4.2", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "psr/http-message": "~1.0" + }, + "provide": { + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + }, + "files": [ + "src/functions_include.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Schultze", + "homepage": "https://github.com/Tobion" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "request", + "response", + "stream", + "uri", + "url" + ], + "time": "2017-03-20T17:10:46+00:00" + }, + { + "name": "herrera-io/box", + "version": "1.6.1", + "source": { + "type": "git", + "url": "https://github.com/box-project/box2-lib.git", + "reference": "b55dceb5c65cc831e94ec0786b0b9b15f1103e8e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/box-project/box2-lib/zipball/b55dceb5c65cc831e94ec0786b0b9b15f1103e8e", + "reference": "b55dceb5c65cc831e94ec0786b0b9b15f1103e8e", + "shasum": "" + }, + "require": { + "ext-phar": "*", + "phine/path": "~1.0", + "php": ">=5.3.3", + "tedivm/jshrink": "~1.0" + }, + "require-dev": { + "herrera-io/annotations": "~1.0", + "herrera-io/phpunit-test-case": "1.*", + "mikey179/vfsstream": "1.1.0", + "phpseclib/phpseclib": "~0.3", + "phpunit/phpunit": "3.7.*" + }, + "suggest": { + "herrera-io/annotations": "For compacting annotated docblocks.", + "phpseclib/phpseclib": "For verifying OpenSSL signed phars without the phar extension." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-0": { + "Herrera\\Box": "src/lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kevin Herrera", + "email": "kevin@herrera.io", + "homepage": "http://kevin.herrera.io" + } + ], + "description": "A library for simplifying the PHAR build process.", + "homepage": "https://github.com/box-project/box2-lib", + "keywords": [ + "phar" + ], + "time": "2014-12-03T23:26:45+00:00" + }, + { + "name": "knplabs/packagist-api", + "version": "v1.5.0", + "source": { + "type": "git", + "url": "https://github.com/KnpLabs/packagist-api.git", + "reference": "44bdf781fa2ee0259bfff984b26d2b8666b0e89b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/KnpLabs/packagist-api/zipball/44bdf781fa2ee0259bfff984b26d2b8666b0e89b", + "reference": "44bdf781fa2ee0259bfff984b26d2b8666b0e89b", + "shasum": "" + }, + "require": { + "doctrine/inflector": "~1.0", + "guzzlehttp/guzzle": "~6.0", + "php": ">=5.5" + }, + "require-dev": { + "phpspec/phpspec": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-0": { + "Packagist\\Api\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "KnpLabs Team", + "homepage": "http://knplabs.com" + } + ], + "description": "Packagist API client.", + "homepage": "http://knplabs.com", + "keywords": [ + "api", + "composer", + "packagist" + ], + "time": "2017-05-31T17:28:36+00:00" + }, + { + "name": "phine/exception", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/kherge-abandoned/lib-exception.git", + "reference": "150c6b6090b2ebc53c60e87cb20c7f1287b7b68a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kherge-abandoned/lib-exception/zipball/150c6b6090b2ebc53c60e87cb20c7f1287b7b68a", + "reference": "150c6b6090b2ebc53c60e87cb20c7f1287b7b68a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "league/phpunit-coverage-listener": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-0": { + "Phine\\Exception": "src/lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kevin Herrera", + "email": "kevin@herrera.io", + "homepage": "http://kevin.herrera.io" + } + ], + "description": "A PHP library for improving the use of exceptions.", + "homepage": "https://github.com/phine/lib-exception", + "keywords": [ + "exception" + ], + "abandoned": true, + "time": "2013-08-27T17:43:25+00:00" + }, + { + "name": "phine/path", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/box-project/box2-path.git", + "reference": "cbe1a5eb6cf22958394db2469af9b773508abddd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/box-project/box2-path/zipball/cbe1a5eb6cf22958394db2469af9b773508abddd", + "reference": "cbe1a5eb6cf22958394db2469af9b773508abddd", + "shasum": "" + }, + "require": { + "phine/exception": "~1.0", + "php": ">=5.3.3" + }, + "require-dev": { + "league/phpunit-coverage-listener": "~1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "psr-0": { + "Phine\\Path": "src/lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Kevin Herrera", + "email": "kevin@herrera.io", + "homepage": "http://kevin.herrera.io" + } + ], + "description": "A PHP library for improving the use of file system paths.", + "homepage": "https://github.com/phine/lib-path", + "keywords": [ + "file", + "path", + "system" + ], + "abandoned": true, + "time": "2013-10-15T22:58:04+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "psr/log", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2016-10-10T12:19:37+00:00" + }, + { + "name": "symfony/console", + "version": "v2.8.26", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "32a3c6b3398de5db8ed381f4ef92970c59c2fcdd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/32a3c6b3398de5db8ed381f4ef92970c59c2fcdd", + "reference": "32a3c6b3398de5db8ed381f4ef92970c59c2fcdd", + "shasum": "" + }, + "require": { + "php": ">=5.3.9", + "symfony/debug": "^2.7.2|~3.0.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/event-dispatcher": "~2.1|~3.0.0", + "symfony/process": "~2.1|~3.0.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "https://symfony.com", + "time": "2017-07-29T21:26:04+00:00" + }, + { + "name": "symfony/debug", + "version": "v3.0.9", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug.git", + "reference": "697c527acd9ea1b2d3efac34d9806bf255278b0a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/debug/zipball/697c527acd9ea1b2d3efac34d9806bf255278b0a", + "reference": "697c527acd9ea1b2d3efac34d9806bf255278b0a", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "psr/log": "~1.0" + }, + "conflict": { + "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + }, + "require-dev": { + "symfony/class-loader": "~2.8|~3.0", + "symfony/http-kernel": "~2.8|~3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Debug\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Debug Component", + "homepage": "https://symfony.com", + "time": "2016-07-30T07:22:48+00:00" + }, + { + "name": "symfony/finder", + "version": "v2.8.26", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "4f4e84811004e065a3bb5ceeb1d9aa592630f9ad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/4f4e84811004e065a3bb5ceeb1d9aa592630f9ad", + "reference": "4f4e84811004e065a3bb5ceeb1d9aa592630f9ad", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Finder Component", + "homepage": "https://symfony.com", + "time": "2017-06-01T20:52:29+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.5.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "7c8fae0ac1d216eb54349e6a8baa57d515fe8803" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7c8fae0ac1d216eb54349e6a8baa57d515fe8803", + "reference": "7c8fae0ac1d216eb54349e6a8baa57d515fe8803", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "time": "2017-06-14T15:44:48+00:00" + }, + { + "name": "symfony/process", + "version": "v2.8.26", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "57e52a0a6a80ea0aec4fc1b785a7920a95cb88a8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/57e52a0a6a80ea0aec4fc1b785a7920a95cb88a8", + "reference": "57e52a0a6a80ea0aec4fc1b785a7920a95cb88a8", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Process Component", + "homepage": "https://symfony.com", + "time": "2017-07-03T08:04:30+00:00" + }, + { + "name": "tedivm/jshrink", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/tedious/JShrink.git", + "reference": "667e99774d230525d4d3dc2a50da7ba6b1d56bad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tedious/JShrink/zipball/667e99774d230525d4d3dc2a50da7ba6b1d56bad", + "reference": "667e99774d230525d4d3dc2a50da7ba6b1d56bad", + "shasum": "" + }, + "require": { + "php": "^5.6|^7.0" + }, + "require-dev": { + "fabpot/php-cs-fixer": "0.4.0", + "phpunit/phpunit": "4.0.*", + "satooshi/php-coveralls": "^0.7.0" + }, + "type": "library", + "autoload": { + "psr-0": { + "JShrink": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Robert Hafner", + "email": "tedivm@tedivm.com" + } + ], + "description": "Javascript Minifier built in PHP", + "homepage": "http://github.com/tedious/JShrink", + "keywords": [ + "javascript", + "minifier" + ], + "time": "2017-05-30T02:59:46+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/translationtool/src/composer.json b/translationtool/src/composer.json new file mode 100644 index 0000000..2a1b909 --- /dev/null +++ b/translationtool/src/composer.json @@ -0,0 +1,16 @@ +{ + "name": "nextcloud/translationtool", + "description": "Needed for the translation tool", + "license": "MIT", + "config": { + "vendor-dir": "vendor", + "optimize-autoloader": true, + "classmap-authoritative": true + }, + "bin": [ + "translationtool.php" + ], + "require": { + "gettext/gettext": "^4.4" + } +} diff --git a/translationtool/src/composer.lock b/translationtool/src/composer.lock new file mode 100644 index 0000000..2b5b740 --- /dev/null +++ b/translationtool/src/composer.lock @@ -0,0 +1,141 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "content-hash": "6f0a9cef57b70b63567362110dac36f4", + "packages": [ + { + "name": "gettext/gettext", + "version": "v4.4.3", + "source": { + "type": "git", + "url": "https://github.com/oscarotero/Gettext.git", + "reference": "4f57f004635cc6311a20815ebfdc0757cb337113" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/oscarotero/Gettext/zipball/4f57f004635cc6311a20815ebfdc0757cb337113", + "reference": "4f57f004635cc6311a20815ebfdc0757cb337113", + "shasum": "" + }, + "require": { + "gettext/languages": "^2.3", + "php": ">=5.4.0" + }, + "require-dev": { + "illuminate/view": "*", + "phpunit/phpunit": "^4.8|^5.7", + "squizlabs/php_codesniffer": "^3.0", + "symfony/yaml": "~2", + "twig/extensions": "*", + "twig/twig": "^1.31|^2.0" + }, + "suggest": { + "illuminate/view": "Is necessary if you want to use the Blade extractor", + "symfony/yaml": "Is necessary if you want to use the Yaml extractor/generator", + "twig/extensions": "Is necessary if you want to use the Twig extractor", + "twig/twig": "Is necessary if you want to use the Twig extractor" + }, + "type": "library", + "autoload": { + "psr-4": { + "Gettext\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Oscar Otero", + "email": "oom@oscarotero.com", + "homepage": "http://oscarotero.com", + "role": "Developer" + } + ], + "description": "PHP gettext manager", + "homepage": "https://github.com/oscarotero/Gettext", + "keywords": [ + "JS", + "gettext", + "i18n", + "mo", + "po", + "translation" + ], + "time": "2017-08-09T16:59:46+00:00" + }, + { + "name": "gettext/languages", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/mlocati/cldr-to-gettext-plural-rules.git", + "reference": "49c39e51569963cc917a924b489e7025bfb9d8c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mlocati/cldr-to-gettext-plural-rules/zipball/49c39e51569963cc917a924b489e7025bfb9d8c7", + "reference": "49c39e51569963cc917a924b489e7025bfb9d8c7", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "require-dev": { + "phpunit/phpunit": "^4" + }, + "bin": [ + "bin/export-plural-rules", + "bin/export-plural-rules.php" + ], + "type": "library", + "autoload": { + "psr-4": { + "Gettext\\Languages\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michele Locati", + "email": "mlocati@gmail.com", + "role": "Developer" + } + ], + "description": "gettext languages with plural rules", + "homepage": "https://github.com/mlocati/cldr-to-gettext-plural-rules", + "keywords": [ + "cldr", + "i18n", + "internationalization", + "l10n", + "language", + "languages", + "localization", + "php", + "plural", + "plural rules", + "plurals", + "translate", + "translations", + "unicode" + ], + "time": "2017-03-23T17:02:28+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [] +} diff --git a/translationtool/src/translationtool.php b/translationtool/src/translationtool.php new file mode 100644 index 0000000..9b90172 --- /dev/null +++ b/translationtool/src/translationtool.php @@ -0,0 +1,374 @@ + + * + * @author Jakob Sack + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ +require __DIR__ . '/vendor/autoload.php'; + +class TranslatableApp { + private $appPath; + private $name; + private $translatableFiles; + private $dummyFileName; + private $ignoreFiles; + private $translationsPath; + + public function __construct($appPath, $translationsPath) { + $this->appPath = $appPath; + $this->translationsPath = $translationsPath; + + $this->translatableFiles = []; + $this->ignoreFiles = []; + $this->dummyFileName = $this->appPath . '/specialAppInfoFakeDummyForL10nScript.php'; + + $this->setAppName(); + } + + public function createPotFile() { + $pathToPotFile = $this->translationsPath . '/templates/' . $this->name . '.pot'; + + // Gather required data + $this->readIgnoreList(); + $this->createFakeFileForAppInfo(); + $this->findTranslatableFiles(); + + // Let gettext create the pot file + $additionalArguments = ' --add-comments=TRANSLATORS --from-code=UTF-8 --package-version="8.0.0" --package-name="ownCloud Core" --msgid-bugs-address="translations\@owncloud.org"'; + foreach ($this->translatableFiles as $entry) { + $output = '--output=' . escapeshellarg($pathToPotFile); + + $keywords = ''; + if (substr($entry, -3) === '.js') { + $keywords = '--keyword=t:2 --keyword=n:2,3'; + } else { + $keywords = '--keyword=t --keyword=n:1,2'; + } + + $language = '--language='; + if (substr($entry, -3) === '.js') { + $language .= 'Javascript'; + } else { + $language .= 'PHP'; + } + + $joinexisting = ''; + if (file_exists($pathToPotFile)) { + $joinexisting = '--join-existing'; + } + + exec('xgettext ' . $output . ' ' . $joinexisting . ' ' . $keywords . ' ' . $language . ' ' . escapeshellarg($entry) . ' ' . $additionalArguments); + } + + // Don't forget to remove the temporary file + $this->deleteFakeFileForAppInfo(); + } + + public function createNextcloudFiles() { + foreach ($this->findLanguages() as $language) { + $poFile = $this->translationsPath . '/' . $language . '/' . $this->name . '.po'; + $translations = Gettext\Translations::fromPoFile($poFile); + + $strings = []; + $plurals = $translations->getHeader('Plural-Forms'); + + foreach ($translations as $translation) { + if (!$translation->hasTranslation()) { + // Skip if we have no translation (for the base form) + continue; + } + + if ($translation->hasPlural()) { + $identifier = $this->escape('_' . $translation->getOriginal() . '_::_' . $translation->getPlural() . '_'); + + $variants = [$this->escape($translation->getTranslation())]; + foreach ($translation->getPluralTranslations() as $plural) { + if ($plural === '') { + // We skip the complete string if not all plural forms exist + continue 2; + } + $variants[] = $this->escape($plural); + } + + $strings[] = $identifier . ' : [' . join(',', $variants) . ']'; + } else { + $strings[] = $this->escape($translation->getOriginal()) . ' : ' . $this->escape($translation->getTranslation()); + } + } + + // Nothing translated :-( skip this file + if (count($strings) === 0) { + continue; + } + + $this->writeJsFile($language, $plurals, $strings); + $this->writeJsonFile($language, $plurals, $strings); + } + } + + private function writeJsFile($language, $plurals, $strings) { + $outfile = fopen($this->appPath . '/l10n/' . $language . '.js', 'w'); + fwrite($outfile, 'OC.L10N.register(' . PHP_EOL); + fwrite($outfile, ' "' . $this->name . '",' . PHP_EOL); + fwrite($outfile, ' {' . PHP_EOL); + fwrite($outfile, ' '); + fwrite($outfile, join(',' . PHP_EOL . ' ', $strings)); + fwrite($outfile, PHP_EOL . '},' . PHP_EOL); + fwrite($outfile, $this->escape($plurals) . ');' . PHP_EOL); + fclose($outfile); + } + + private function writeJsonFile($language, $plurals, $strings){ + $outfile = fopen($this->appPath . '/l10n/' . $language . '.json', 'w'); + fwrite($outfile, '{ "translations": {' . PHP_EOL); + fwrite($outfile, ' '); + fwrite($outfile, join(',' . PHP_EOL . ' ', $strings)); + fwrite($outfile, PHP_EOL . '},"pluralForm" :' . $this->escape($plurals) . PHP_EOL . '}'); + fclose($outfile); + } + + private function escape($string) { + return Gettext\Generators\Po::convertString($string); + } + + private function findTranslatableFiles($path='') { + $realPath = $path === '' ? $this->appPath : $this->appPath . '/' . $path; + + $directoryectoryContent = scandir($realPath); + foreach ($directoryectoryContent as $entry) { + if ($entry[0] === '.') { + continue; + } + + $newPath = $path === '' ? $entry : $path . '/' . $entry; + $newRealPath = $this->appPath . '/' . $newPath; + + if (in_array($newPath, $this->ignoreFiles)) { + continue; + } + if (is_dir($newRealPath) && $entry != 'l10n') { + $this->findTranslatableFiles($newPath); + } + if (is_file($newRealPath)) { + if (substr($entry, -4) === '.php' || (substr($entry, -3) === '.js' && substr($entry, -7) !== '.min.js')) { + $this->translatableFiles[] = $newRealPath; + } + } + } + } + + private function readIgnoreList() { + $ignoreFile = $this->appPath . '/l10n/ignorelist'; + if (!is_file($ignoreFile)) { + return []; + } + + return file($ignoreFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + } + + private function findLanguages() { + $languages = []; + $directoryectoryContent = scandir($this->translationsPath); + foreach ($directoryectoryContent as $entry) { + if ($entry[0] === '.' || $entry === 'templates' || !is_dir($this->translationsPath . '/' . $entry)) { + continue; + } + + if (is_file($this->translationsPath . '/' . $entry . '/' . $this->name . '.po')) { + $languages[] = $entry; + } + } + + return $languages; + } + + private function createFakeFileForAppInfo() { + $entryName = $this->appPath . '/appinfo/info.xml'; + + if (!file_exists($entryName)) { + return false; + } + + $strings = []; + $xml = simplexml_load_file($entryName); + + if ($xml->name) { + $strings[] = $xml->name->__toString(); + } + + if ($xml->navigations) { + foreach ($xml->navigations as $navigation) { + $name = $navigation->navigation->name->__toString(); + if (!in_array($name, $strings)) { + $strings[] = $name; + } + } + } + + $content = 't(' . $this->escape($string) . ');' . PHP_EOL; + } + + file_put_contents($this->dummyFileName, $content); + } + + private function deleteFakeFileForAppInfo() { + if (is_file($this->dummyFileName)){ + unlink($this->dummyFileName); + } + } + + private function setAppName() { + $xmlFile = $this->appPath . '/appinfo/info.xml'; + + $this->name = basename($this->appPath); + + if (!file_exists($xmlFile)) { + return; + } + + $xml = simplexml_load_file($xmlFile); + + if ($xml->name) { + $this->name = $xml->id->__toString(); + } + } +} + +class TranslationTool { + private $translationPath; + private $appPaths; + + public function __construct(){ + $this->translationPath = getcwd() . '/translationfiles'; + $this->appPaths = []; + + if (!is_dir($this->translationPath)) { + mkdir($this->translationPath); + } + } + + public function checkEnvironment() { + // Check if the version of xgettext is at least 0.18.3 + $output = []; + exec('xgettext --version', $output); + + // we assume the first line looks like this 'xgettext (GNU gettext-tools) 0.19.3' + $version = trim(substr($output[0], 29)); + + if (version_compare($version, '0.18.3', '<')) { + echo 'Minimum expected version of xgettext is 0.18.3. Detected: ' . $version . '".' . PHP_EOL; + return false; + } + + $this->findApps(getcwd()); + if (count($this->appPaths) === 0) { + echo 'Could not find translatable apps.' . PHP_EOL; + return false; + } + + return true; + } + + public function createPotFiles() { + // Recreate folder for the templates + $this->rrmdir($this->translationPath . '/templates'); + mkdir($this->translationPath . '/templates'); + + // iterate over all apps + foreach ($this->appPaths as $appPath) { + $app = new TranslatableApp($appPath, $this->translationPath); + $app->createPotFile(); + } + } + + public function convertPoFiles() { + foreach ($this->appPaths as $appPath) { + $app = new TranslatableApp($appPath, $this->translationPath); + $app->createNextcloudFiles(); + } + } + + private function findApps($path){ + $directoryectoryContent = scandir($path); + foreach ($directoryectoryContent as $entry) { + if ($entry[0] === '.') { + continue; + } + + $newPath = $path . '/' . $entry; + if (!is_dir($newPath)) { + continue; + } + + if ($entry === 'l10n') { + $this->appPaths[] = $path; + } else { + $this->findApps($newPath); + } + } + } + + + private function rrmdir($path) { + if (!is_dir($path)) { + return; + } + + $directory = opendir($path); + while (false !== ($entry = readdir($directory))) { + if (($entry !== '.') && ($entry !== '..')) { + $fullPath = $path . '/' . $entry; + + if (is_dir($fullPath)) { + $this->rrmdir($fullPath); + } else { + unlink($fullPath); + } + } + } + closedir($directory); + + rmdir($path); + } +} + +// read the command line arguments +if(count($argv) < 2) { + echo 'Missing arguments' . PHP_EOL; + echo 'call "' . $argv[0] . ' $task [$appName]' . PHP_EOL; + echo '$task: create-pot-files || convert-po-files' . PHP_EOL; + return false; +} +$task = $argv[1]; + +$tool = new TranslationTool(); +if (!$tool->checkEnvironment()) { + return false; +} + +if ($task === 'create-pot-files') { + $tool->createPotFiles(); +} elseif ($task === 'convert-po-files') { + $tool->convertPoFiles(); +} else { + echo 'Unknown task: "' . $task . '".' . PHP_EOL; + return false; +} diff --git a/translationtool/translationtool.phar b/translationtool/translationtool.phar new file mode 100755 index 0000000..46aa8fe Binary files /dev/null and b/translationtool/translationtool.phar differ