diff --git a/.env.dist b/.env.dist index d6271d57..726635ba 100644 --- a/.env.dist +++ b/.env.dist @@ -3,6 +3,7 @@ APP_ENV= SHORTENED_URL_SCHEMA= SHORTENED_URL_HOSTNAME= SHORTCODE_CHARS= +DEFAULT_LOCALE= # Database DB_USER= diff --git a/composer.json b/composer.json index 0211ed05..b9be6c6d 100644 --- a/composer.json +++ b/composer.json @@ -21,10 +21,11 @@ "zendframework/zend-servicemanager": "^3.0", "zendframework/zend-paginator": "^2.6", "zendframework/zend-config": "^2.6", + "zendframework/zend-i18n": "^2.7", "mtymek/expressive-config-manager": "^0.4", + "acelaya/zsm-annotated-services": "^0.2.0", "doctrine/orm": "^2.5", "guzzlehttp/guzzle": "^6.2", - "acelaya/zsm-annotated-services": "^0.2.0", "symfony/console": "^3.0" }, "require-dev": { diff --git a/config/autoload/translator.global.php b/config/autoload/translator.global.php new file mode 100644 index 00000000..e3730927 --- /dev/null +++ b/config/autoload/translator.global.php @@ -0,0 +1,8 @@ + [ + 'locale' => getenv('DEFAULT_LOCALE') ?: 'en', + ], + +]; diff --git a/module/CLI/config/translator.config.php b/module/CLI/config/translator.config.php new file mode 100644 index 00000000..ae120db3 --- /dev/null +++ b/module/CLI/config/translator.config.php @@ -0,0 +1,14 @@ + [ + 'translation_file_patterns' => [ + [ + 'type' => 'gettext', + 'base_dir' => __DIR__ . '/../lang', + 'pattern' => '%s.mo', + ], + ], + ], + +]; diff --git a/module/CLI/lang/es.mo b/module/CLI/lang/es.mo new file mode 100644 index 00000000..08f58bd9 Binary files /dev/null and b/module/CLI/lang/es.mo differ diff --git a/module/CLI/lang/es.po b/module/CLI/lang/es.po new file mode 100644 index 00000000..896f2965 --- /dev/null +++ b/module/CLI/lang/es.po @@ -0,0 +1,40 @@ +msgid "" +msgstr "" +"Project-Id-Version: Shlink 1.0\n" +"POT-Creation-Date: 2016-07-21 15:05+0200\n" +"PO-Revision-Date: 2016-07-21 15:08+0200\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: es_ES\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 1.8.7.1\n" +"X-Poedit-Basepath: ..\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Poedit-SourceCharset: UTF-8\n" +"X-Poedit-KeywordsList: translate;translatePlural\n" +"X-Poedit-SearchPath-0: src\n" +"X-Poedit-SearchPath-1: config\n" + +msgid "Generates a shortcode for provided URL and returns the short URL" +msgstr "Genera un código corto para la URL proporcionada y devuelve la URL acortada" + +msgid "The long URL to parse" +msgstr "La URL larga a procesar" + +msgid "A long URL was not provided. Which URL do you want to shorten?:" +msgstr "No se ha proporcionado una URL larga. ¿Qué URL deseas acortar?" + +msgid "A URL was not provided!" +msgstr "¡No se ha proporcionado una URL!" + +msgid "Processed URL:" +msgstr "URL procesada:" + +msgid "Generated URL:" +msgstr "URL generada:" + +#, php-format +msgid "Provided URL \"%s\" is invalid. Try with a different one." +msgstr "La URL proporcionada \"%s\" e inválida. Prueba con una diferente." diff --git a/module/CLI/src/Command/GenerateShortcodeCommand.php b/module/CLI/src/Command/GenerateShortcodeCommand.php index 91cbd228..0a0af9eb 100644 --- a/module/CLI/src/Command/GenerateShortcodeCommand.php +++ b/module/CLI/src/Command/GenerateShortcodeCommand.php @@ -12,6 +12,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\Question; use Zend\Diactoros\Uri; +use Zend\I18n\Translator\TranslatorInterface; class GenerateShortcodeCommand extends Command { @@ -23,26 +24,37 @@ class GenerateShortcodeCommand extends Command * @var array */ private $domainConfig; + /** + * @var TranslatorInterface + */ + private $translator; /** * GenerateShortcodeCommand constructor. * @param UrlShortenerInterface|UrlShortener $urlShortener + * @param TranslatorInterface $translator * @param array $domainConfig * - * @Inject({UrlShortener::class, "config.url_shortener.domain"}) + * @Inject({UrlShortener::class, "translator", "config.url_shortener.domain"}) */ - public function __construct(UrlShortenerInterface $urlShortener, array $domainConfig) - { - parent::__construct(null); + public function __construct( + UrlShortenerInterface $urlShortener, + TranslatorInterface $translator, + array $domainConfig + ) { $this->urlShortener = $urlShortener; + $this->translator = $translator; $this->domainConfig = $domainConfig; + parent::__construct(null); } public function configure() { $this->setName('shortcode:generate') - ->setDescription('Generates a shortcode for provided URL and returns the short URL') - ->addArgument('longUrl', InputArgument::REQUIRED, 'The long URL to parse'); + ->setDescription( + $this->translator->translate('Generates a shortcode for provided URL and returns the short URL') + ) + ->addArgument('longUrl', InputArgument::REQUIRED, $this->translator->translate('The long URL to parse')); } public function interact(InputInterface $input, OutputInterface $output) @@ -54,9 +66,10 @@ class GenerateShortcodeCommand extends Command /** @var QuestionHelper $helper */ $helper = $this->getHelper('question'); - $question = new Question( - 'A long URL was not provided. Which URL do you want to shorten?: ' - ); + $question = new Question(sprintf( + '%s ', + $this->translator->translate('A long URL was not provided. Which URL do you want to shorten?:') + )); $longUrl = $helper->ask($input, $output, $question); if (! empty($longUrl)) { @@ -70,7 +83,7 @@ class GenerateShortcodeCommand extends Command try { if (! isset($longUrl)) { - $output->writeln('A URL was not provided!'); + $output->writeln(sprintf('%s', $this->translator->translate('A URL was not provided!'))); return; } @@ -80,13 +93,16 @@ class GenerateShortcodeCommand extends Command ->withHost($this->domainConfig['hostname']); $output->writeln([ - sprintf('Processed URL %s', $longUrl), - sprintf('Generated URL %s', $shortUrl), + sprintf('%s %s', $this->translator->translate('Processed URL:'), $longUrl), + sprintf('%s %s', $this->translator->translate('Generated URL:'), $shortUrl), ]); } catch (InvalidUrlException $e) { - $output->writeln( - sprintf('Provided URL "%s" is invalid. Try with a different one.', $longUrl) - ); + $output->writeln(sprintf( + '' . $this->translator->translate( + 'Provided URL "%s" is invalid. Try with a different one.' + ) . '', + $longUrl + )); } } } diff --git a/module/Common/config/services.config.php b/module/Common/config/services.config.php index 838b7896..1423b543 100644 --- a/module/Common/config/services.config.php +++ b/module/Common/config/services.config.php @@ -4,7 +4,10 @@ use Doctrine\Common\Cache\Cache; use Doctrine\ORM\EntityManager; use Shlinkio\Shlink\Common\Factory\CacheFactory; use Shlinkio\Shlink\Common\Factory\EntityManagerFactory; +use Shlinkio\Shlink\Common\Factory\TranslatorFactory; use Shlinkio\Shlink\Common\Service\IpLocationResolver; +use Shlinkio\Shlink\Common\Twig\Extension\TranslatorExtension; +use Zend\I18n\Translator\Translator; use Zend\ServiceManager\Factory\InvokableFactory; return [ @@ -15,10 +18,13 @@ return [ GuzzleHttp\Client::class => InvokableFactory::class, Cache::class => CacheFactory::class, IpLocationResolver::class => AnnotatedFactory::class, + Translator::class => TranslatorFactory::class, + TranslatorExtension::class => AnnotatedFactory::class, ], 'aliases' => [ 'em' => EntityManager::class, 'httpClient' => GuzzleHttp\Client::class, + 'translator' => Translator::class, AnnotatedFactory::CACHE_SERVICE => Cache::class, ], ], diff --git a/module/Common/config/templates.config.php b/module/Common/config/templates.config.php new file mode 100644 index 00000000..903c1e8c --- /dev/null +++ b/module/Common/config/templates.config.php @@ -0,0 +1,12 @@ + [ + 'extensions' => [ + TranslatorExtension::class, + ], + ], + +]; diff --git a/module/Common/src/Factory/TranslatorFactory.php b/module/Common/src/Factory/TranslatorFactory.php new file mode 100644 index 00000000..e41ba2fc --- /dev/null +++ b/module/Common/src/Factory/TranslatorFactory.php @@ -0,0 +1,30 @@ +get('config'); + return Translator::factory(isset($config['translator']) ? $config['translator'] : []); + } +} diff --git a/module/Common/src/Twig/Extension/TranslatorExtension.php b/module/Common/src/Twig/Extension/TranslatorExtension.php new file mode 100644 index 00000000..48ee3f11 --- /dev/null +++ b/module/Common/src/Twig/Extension/TranslatorExtension.php @@ -0,0 +1,75 @@ +translator = $translator; + } + + /** + * Returns the name of the extension. + * + * @return string The extension name + */ + public function getName() + { + return __CLASS__; + } + + public function getFunctions() + { + return [ + new \Twig_SimpleFunction('translate', [$this, 'translate']), + new \Twig_SimpleFunction('translate_plural', [$this, 'translatePlural']), + ]; + } + + /** + * Translate a message. + * + * @param string $message + * @param string $textDomain + * @param string $locale + * @return string + */ + public function translate($message, $textDomain = 'default', $locale = null) + { + return $this->translator->translate($message, $textDomain, $locale); + } + + /** + * Translate a plural message. + * + * @param string $singular + * @param string $plural + * @param int $number + * @param string $textDomain + * @param string|null $locale + * @return string + */ + public function translatePlural( + $singular, + $plural, + $number, + $textDomain = 'default', + $locale = null + ) { + $this->translator->translatePlural($singular, $plural, $number, $textDomain, $locale); + } +}