Browse Source

Merge pull request #5636 from cakephp/3.0-optional-i18n-cache

3.0 optional i18n cache
Mark Story 11 years ago
parent
commit
6a73a893a4
8 changed files with 407 additions and 231 deletions
  1. 4 2
      composer.json
  2. 7 1
      src/I18n/I18n.php
  3. 89 0
      src/I18n/README.md
  4. 53 15
      src/I18n/TranslatorRegistry.php
  5. 27 0
      src/I18n/composer.json
  6. 226 0
      src/I18n/functions.php
  7. 1 1
      src/Log/README.md
  8. 0 212
      src/basics.php

+ 4 - 2
composer.json

@@ -36,7 +36,8 @@
 		},
 		"files": [
 			"src/Core/functions.php",
-			"src/Collection/functions.php"
+			"src/Collection/functions.php",
+			"src/I18n/functions.php"
 		]
 	},
 	"autoload-dev": {
@@ -59,6 +60,7 @@
 		"cakephp/datasource": "self.version",
 		"cakephp/database": "self.version",
 		"cakephp/cache": "self.version",
-		"cakephp/log": "self.version"
+		"cakephp/log": "self.version",
+		"cakephp/i18n": "self.version"
 	}
 }

+ 7 - 1
src/I18n/I18n.php

@@ -17,6 +17,7 @@ namespace Cake\I18n;
 use Aura\Intl\FormatterLocator;
 use Aura\Intl\PackageLocator;
 use Aura\Intl\TranslatorFactory;
+use Cake\Cache\Cache;
 use Cake\I18n\Formatter\IcuFormatter;
 use Cake\I18n\Formatter\SprintfFormatter;
 use Locale;
@@ -54,7 +55,7 @@ class I18n
             return static::$_collection;
         }
 
-        return static::$_collection = new TranslatorRegistry(
+        static::$_collection = new TranslatorRegistry(
             new PackageLocator,
             new FormatterLocator([
                 'sprintf' => function () {
@@ -67,6 +68,11 @@ class I18n
             new TranslatorFactory,
             static::locale()
         );
+
+        if (class_exists('Cake\Cache\Cache')) {
+            static::$_collection->setCacher(Cache::engine('_cake_core_'));
+        }
+        return static::$_collection;
     }
 
     /**

+ 89 - 0
src/I18n/README.md

@@ -0,0 +1,89 @@
+# CakePHP Internationalization Library
+
+The I18n library provides a `I18n` service locator that can be used for setting
+the current locale, building translation bundles and translating messages.
+
+Additionally, it provides the `Time` and `Number` classes which can be used to
+ouput dates, currencies and any numbers in the right format for the specified locale.
+
+## Usage
+
+Internally, the `I18n` class uses [Aura.Intl](https://github.com/auraphp/Aura.Intl).
+Getting familiar with it, will help you understand how to build and manipulate translation bundles
+should you wish to create them manually instead of using the conventions this library uses.
+
+### Setting the Current Locale
+
+```php
+use Cake\I18n\I18n;
+
+I18n::locale('en_US');
+```
+
+### Translating a message
+
+```php
+echo __(
+    'Hi {0,string}, your balance on the {1,date} is {2,number,currency}',
+    ['Charles', '2014-01-13 11:12:00', 1354.37]
+);
+
+// Returns
+Hi Charles, your balance on the Jan 13, 2014, 11:12 AM is $ 1,354.37
+```
+
+### Creating your Own Translators
+
+```php
+use Cake\I18n\I18n;
+use Aura\Intl\Package;
+
+I18n::translator('animals', 'fr_FR', function () {
+    $package = new Package(
+        'default', // The formatting strategy (ICU)
+        'default', // The fallback domain
+    );
+    $package->setMessages([
+        'Dog' => 'Chien',
+        'Cat' => 'Chat',
+        'Bird' => 'Oiseau'
+        ...
+    ]);
+
+    return $package;
+});
+
+I18n::locale('fr_FR');
+__d('animals', 'Dog'); // Returns "Chien"
+```
+
+### Formatting Time
+
+```php
+$time = Time::now();
+echo $time; // shows '4/20/14, 10:10 PM' for the en-US locale
+```
+
+### Formattng Numbers
+
+```php
+echo Number::format(100100100);
+```
+
+```php
+echo Number::currency(123456.7890, 'EUR');
+// outputs €123,456.79
+```
+
+## Documentation
+
+Please make sure you check the [official I18n
+documentation](http://book.cakephp.org/3.0/en/core-libraries/internationalization-and-localization.html)
+
+The [documentation for the Time
+class](http://book.cakephp.org/3.0/en/core-libraries/time.html) contains
+instruction on how configure and output time strings for selected locales.
+
+The [documentation for the Number
+class](http://book.cakephp.org/3.0/en/core-libraries/number.html) shows how to
+use the `Number` class for displaying numbers in specific locales.

+ 53 - 15
src/I18n/TranslatorRegistry.php

@@ -15,7 +15,7 @@
 namespace Cake\I18n;
 
 use Aura\Intl\TranslatorLocator;
-use Cake\Cache\Cache;
+use Cake\Cache\CacheEngine;
 
 /**
  * Constructs and stores instances of translators that can be
@@ -43,6 +43,26 @@ class TranslatorRegistry extends TranslatorLocator
     protected $_defaultFormatter = 'default';
 
     /**
+     * A CacheEngine object that is used to remember translator across
+     * requests.
+     *
+     * @var \Cake\Cache\CacheEngine
+     */
+    protected $_cacher;
+
+    /**
+     * Sets the CacheEngine instance used to remember translators across
+     * requests.
+     *
+     * @param \Cake\Cache\CacheEngine $cacher The cacher instance.
+     * @return void
+     */
+    public function setCacher(CacheEngine $cacher)
+    {
+        $this->_cacher = $cacher;
+    }
+
+    /**
      * Gets a translator from the registry by package for a locale.
      *
      * @param string $name The translator package to retrieve.
@@ -62,25 +82,43 @@ class TranslatorRegistry extends TranslatorLocator
             $locale = $this->getLocale();
         }
 
-        if (!isset($this->registry[$name][$locale])) {
-            $key = "translations.$name.$locale";
-            $translator = Cache::remember($key, function () use ($name, $locale) {
-                try {
-                    return parent::get($name, $locale);
-                } catch (\Aura\Intl\Exception $e) {
-                }
+        if (isset($this->registry[$name][$locale])) {
+            return $this->registry[$name][$locale];
+        }
 
-                if (!isset($this->_loaders[$name])) {
-                    $this->registerLoader($name, $this->_partialLoader());
-                }
+        if (!$this->_cacher) {
+            return $this->registry[$name][$locale] = $this->_getTranslator($name, $locale);
+        }
 
-                return $this->_getFromLoader($name, $locale);
-            }, '_cake_core_');
+        $key = "translations.$name.$locale";
+        $translator = $this->_cacher->read($key);
+        if (!$translator) {
+            $translator = $this->_getTranslator($name, $locale);
+            $this->_cacher->write($key, $translator);
+        }
+
+        return $this->registry[$name][$locale] = $translator;
+    }
 
-            return $this->registry[$name][$locale] = $translator;
+    /**
+     * Gets a translator from the registry by package for a locale.
+     *
+     * @param string $name The translator package to retrieve.
+     * @param string|null $locale The locale to use; if empty, uses the default
+     * locale.
+     * @return \Aura\Intl\TranslatorInterface A translator object.
+     */
+    protected function _getTranslator($name, $locale)
+    {
+        try {
+            return parent::get($name, $locale);
+        } catch (\Aura\Intl\Exception $e) {
         }
 
-        return $this->registry[$name][$locale];
+        if (!isset($this->_loaders[$name])) {
+            $this->registerLoader($name, $this->_partialLoader());
+        }
+        return $this->_getFromLoader($name, $locale);
     }
 
     /**

+ 27 - 0
src/I18n/composer.json

@@ -0,0 +1,27 @@
+{
+    "name": "cakephp/i18n",
+    "description": "CakePHP Internationalization library with support for messages translation and dates and numbers localization",
+    "license": "MIT",
+    "authors": [
+        {
+        "name": "CakePHP Community",
+        "homepage": "http://cakephp.org"
+    }
+    ],
+    "autoload": {
+        "psr-4": {
+            "Cake\\I18n\\": "."
+        },
+        "files": ["functions.php"]
+    },
+    "require": {
+        "cakephp/core": "dev-master",
+        "ext-intl": "*",
+        "nesbot/Carbon": "~1.13",
+        "aura/intl": "1.1.*"
+    },
+    "suggest": {
+        "cakephp/cache": "Require this if you want automatic caching of translators"
+    },
+    "minimum-stability": "dev"
+}

+ 226 - 0
src/I18n/functions.php

@@ -0,0 +1,226 @@
+<?php
+/**
+ * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
+ * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The MIT License
+ * For full copyright and license information, please see the LICENSE.txt
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link          http://cakephp.org CakePHP(tm) Project
+ * @since         3.0.0
+ * @license       http://www.opensource.org/licenses/mit-license.php MIT License
+ */
+use Cake\I18n\I18n;
+
+if (!function_exists('__')) {
+    /**
+     * Returns a translated string if one is found; Otherwise, the submitted message.
+     *
+     * @param string $singular Text to translate
+     * @param mixed $args Array with arguments or multiple arguments in function
+     * @return mixed translated string
+     * @link http://book.cakephp.org/3.0/en/core-libraries/global-constants-and-functions.html#__
+     */
+    function __($singular, $args = null)
+    {
+        if (!$singular) {
+            return;
+        }
+
+        $arguments = func_num_args() === 2 ? (array)$args : array_slice(func_get_args(), 1);
+        return I18n::translator()->translate($singular, $arguments);
+    }
+
+}
+
+if (!function_exists('__n')) {
+    /**
+     * Returns correct plural form of message identified by $singular and $plural for count $count.
+     * Some languages have more than one form for plural messages dependent on the count.
+     *
+     * @param string $singular Singular text to translate
+     * @param string $plural Plural text
+     * @param int $count Count
+     * @param mixed $args Array with arguments or multiple arguments in function
+     * @return mixed plural form of translated string
+     * @link http://book.cakephp.org/3.0/en/core-libraries/global-constants-and-functions.html#__n
+     */
+    function __n($singular, $plural, $count, $args = null)
+    {
+        if (!$singular) {
+            return;
+        }
+
+        $arguments = func_num_args() === 4 ? (array)$args : array_slice(func_get_args(), 3);
+        return I18n::translator()->translate(
+            $plural,
+            ['_count' => $count, '_singular' => $singular] + $arguments
+        );
+    }
+
+}
+
+if (!function_exists('__d')) {
+    /**
+     * Allows you to override the current domain for a single message lookup.
+     *
+     * @param string $domain Domain
+     * @param string $msg String to translate
+     * @param mixed $args Array with arguments or multiple arguments in function
+     * @return string translated string
+     * @link http://book.cakephp.org/3.0/en/core-libraries/global-constants-and-functions.html#__d
+     */
+    function __d($domain, $msg, $args = null)
+    {
+        if (!$msg) {
+            return;
+        }
+        $arguments = func_num_args() === 3 ? (array)$args : array_slice(func_get_args(), 2);
+        return I18n::translator($domain)->translate($msg, $arguments);
+    }
+
+}
+
+if (!function_exists('__dn')) {
+    /**
+     * Allows you to override the current domain for a single plural message lookup.
+     * Returns correct plural form of message identified by $singular and $plural for count $count
+     * from domain $domain.
+     *
+     * @param string $domain Domain
+     * @param string $singular Singular string to translate
+     * @param string $plural Plural
+     * @param int $count Count
+     * @param mixed $args Array with arguments or multiple arguments in function
+     * @return string plural form of translated string
+     * @link http://book.cakephp.org/3.0/en/core-libraries/global-constants-and-functions.html#__dn
+     */
+    function __dn($domain, $singular, $plural, $count, $args = null)
+    {
+        if (!$singular) {
+            return;
+        }
+
+        $arguments = func_num_args() === 5 ? (array)$args : array_slice(func_get_args(), 4);
+        return I18n::translator($domain)->translate(
+            $plural,
+            ['_count' => $count, '_singular' => $singular] + $arguments
+        );
+    }
+
+}
+
+if (!function_exists('__x')) {
+    /**
+     * Returns a translated string if one is found; Otherwise, the submitted message.
+     * The context is a unique identifier for the translations string that makes it unique
+     * for in the same domain.
+     *
+     * @param string $context Context of the text
+     * @param string $singular Text to translate
+     * @param mixed $args Array with arguments or multiple arguments in function
+     * @return mixed translated string
+     * @link http://book.cakephp.org/3.0/en/core-libraries/global-constants-and-functions.html#__
+     */
+    function __x($context, $singular, $args = null)
+    {
+        if (!$singular) {
+            return;
+        }
+
+        $arguments = func_num_args() === 3 ? (array)$args : array_slice(func_get_args(), 2);
+        return I18n::translator()->translate($singular, ['_context' => $context] + $arguments);
+    }
+
+}
+
+if (!function_exists('__xn')) {
+    /**
+     * Returns correct plural form of message identified by $singular and $plural for count $count.
+     * Some languages have more than one form for plural messages dependent on the count.
+     * The context is a unique identifier for the translations string that makes it unique
+     * for in the same domain.
+     *
+     * @param string $context Context of the text
+     * @param string $singular Singular text to translate
+     * @param string $plural Plural text
+     * @param int $count Count
+     * @param mixed $args Array with arguments or multiple arguments in function
+     * @return mixed plural form of translated string
+     * @link http://book.cakephp.org/3.0/en/core-libraries/global-constants-and-functions.html#__xn
+     */
+    function __xn($context, $singular, $plural, $count, $args = null)
+    {
+        if (!$singular) {
+            return;
+        }
+
+        $arguments = func_num_args() === 5 ? (array)$args : array_slice(func_get_args(), 2);
+        return I18n::translator()->translate(
+            $singular,
+            ['_count' => $count, '_singular' => $singular, '_context' => $context] + $arguments
+        );
+    }
+
+}
+
+if (!function_exists('__dx')) {
+    /**
+     * Allows you to override the current domain for a single message lookup.
+     * The context is a unique identifier for the translations string that makes it unique
+     * for in the same domain.
+     *
+     * @param string $domain Domain
+     * @param string $context Context of the text
+     * @param string $msg String to translate
+     * @param mixed $args Array with arguments or multiple arguments in function
+     * @return string translated string
+     * @link http://book.cakephp.org/3.0/en/core-libraries/global-constants-and-functions.html#__dx
+     */
+    function __dx($domain, $context, $msg, $args = null)
+    {
+        if (!$msg) {
+            return;
+        }
+
+        $arguments = func_num_args() === 4 ? (array)$args : array_slice(func_get_args(), 2);
+        return I18n::translator($domain)->translate(
+            $msg,
+            ['_context' => $context] + $arguments
+        );
+    }
+
+}
+
+if (!function_exists('__dxn')) {
+    /**
+     * Returns correct plural form of message identified by $singular and $plural for count $count.
+     * Allows you to override the current domain for a single message lookup.
+     * The context is a unique identifier for the translations string that makes it unique
+     * for in the same domain.
+     *
+     * @param string $domain Domain
+     * @param string $context Context of the text
+     * @param string $singular Singular text to translate
+     * @param string $plural Plural text
+     * @param int $count Count
+     * @param mixed $args Array with arguments or multiple arguments in function
+     * @return mixed plural form of translated string
+     * @link http://book.cakephp.org/3.0/en/core-libraries/global-constants-and-functions.html#__dxn
+     */
+    function __dxn($domain, $context, $singular, $plural, $count, $args = null)
+    {
+        if (!$singular) {
+            return;
+        }
+
+        $arguments = func_num_args() === 6 ? (array)$args : array_slice(func_get_args(), 2);
+        return I18n::translator($domain)->translate(
+            $singular,
+            ['_count' => $count, '_singular' => $singular, '_context' => $context] + $arguments
+        );
+    }
+
+}

+ 1 - 1
src/Log/README.md

@@ -1,6 +1,6 @@
 # CakePHP Logging Library
 
-The Cache library provides a `Log` service locator for interfacing with
+The Log library provides a `Log` service locator for interfacing with
 multiple logging backends using a simple interface. With the `Log` class it is
 possible to send a single message to multiple logging backends at the same time
 or just a subset of them based on the log level or context.

+ 0 - 212
src/basics.php

@@ -14,7 +14,6 @@
  */
 use Cake\Core\Configure;
 use Cake\Error\Debugger;
-use Cake\I18n\I18n;
 
 /**
  * Basic defines for timing functions.
@@ -124,217 +123,6 @@ if (!function_exists('stackTrace')) {
 
 }
 
-if (!function_exists('__')) {
-    /**
-     * Returns a translated string if one is found; Otherwise, the submitted message.
-     *
-     * @param string $singular Text to translate
-     * @param mixed $args Array with arguments or multiple arguments in function
-     * @return mixed translated string
-     * @link http://book.cakephp.org/3.0/en/core-libraries/global-constants-and-functions.html#__
-     */
-    function __($singular, $args = null)
-    {
-        if (!$singular) {
-            return;
-        }
-
-        $arguments = func_num_args() === 2 ? (array)$args : array_slice(func_get_args(), 1);
-        return I18n::translator()->translate($singular, $arguments);
-    }
-
-}
-
-if (!function_exists('__n')) {
-    /**
-     * Returns correct plural form of message identified by $singular and $plural for count $count.
-     * Some languages have more than one form for plural messages dependent on the count.
-     *
-     * @param string $singular Singular text to translate
-     * @param string $plural Plural text
-     * @param int $count Count
-     * @param mixed $args Array with arguments or multiple arguments in function
-     * @return mixed plural form of translated string
-     * @link http://book.cakephp.org/3.0/en/core-libraries/global-constants-and-functions.html#__n
-     */
-    function __n($singular, $plural, $count, $args = null)
-    {
-        if (!$singular) {
-            return;
-        }
-
-        $arguments = func_num_args() === 4 ? (array)$args : array_slice(func_get_args(), 3);
-        return I18n::translator()->translate(
-            $plural,
-            ['_count' => $count, '_singular' => $singular] + $arguments
-        );
-    }
-
-}
-
-if (!function_exists('__d')) {
-    /**
-     * Allows you to override the current domain for a single message lookup.
-     *
-     * @param string $domain Domain
-     * @param string $msg String to translate
-     * @param mixed $args Array with arguments or multiple arguments in function
-     * @return string translated string
-     * @link http://book.cakephp.org/3.0/en/core-libraries/global-constants-and-functions.html#__d
-     */
-    function __d($domain, $msg, $args = null)
-    {
-        if (!$msg) {
-            return;
-        }
-        $arguments = func_num_args() === 3 ? (array)$args : array_slice(func_get_args(), 2);
-        return I18n::translator($domain)->translate($msg, $arguments);
-    }
-
-}
-
-if (!function_exists('__dn')) {
-    /**
-     * Allows you to override the current domain for a single plural message lookup.
-     * Returns correct plural form of message identified by $singular and $plural for count $count
-     * from domain $domain.
-     *
-     * @param string $domain Domain
-     * @param string $singular Singular string to translate
-     * @param string $plural Plural
-     * @param int $count Count
-     * @param mixed $args Array with arguments or multiple arguments in function
-     * @return string plural form of translated string
-     * @link http://book.cakephp.org/3.0/en/core-libraries/global-constants-and-functions.html#__dn
-     */
-    function __dn($domain, $singular, $plural, $count, $args = null)
-    {
-        if (!$singular) {
-            return;
-        }
-
-        $arguments = func_num_args() === 5 ? (array)$args : array_slice(func_get_args(), 4);
-        return I18n::translator($domain)->translate(
-            $plural,
-            ['_count' => $count, '_singular' => $singular] + $arguments
-        );
-    }
-
-}
-
-if (!function_exists('__x')) {
-    /**
-     * Returns a translated string if one is found; Otherwise, the submitted message.
-     * The context is a unique identifier for the translations string that makes it unique
-     * for in the same domain.
-     *
-     * @param string $context Context of the text
-     * @param string $singular Text to translate
-     * @param mixed $args Array with arguments or multiple arguments in function
-     * @return mixed translated string
-     * @link http://book.cakephp.org/3.0/en/core-libraries/global-constants-and-functions.html#__
-     */
-    function __x($context, $singular, $args = null)
-    {
-        if (!$singular) {
-            return;
-        }
-
-        $arguments = func_num_args() === 3 ? (array)$args : array_slice(func_get_args(), 2);
-        return I18n::translator()->translate($singular, ['_context' => $context] + $arguments);
-    }
-
-}
-
-if (!function_exists('__xn')) {
-    /**
-     * Returns correct plural form of message identified by $singular and $plural for count $count.
-     * Some languages have more than one form for plural messages dependent on the count.
-     * The context is a unique identifier for the translations string that makes it unique
-     * for in the same domain.
-     *
-     * @param string $context Context of the text
-     * @param string $singular Singular text to translate
-     * @param string $plural Plural text
-     * @param int $count Count
-     * @param mixed $args Array with arguments or multiple arguments in function
-     * @return mixed plural form of translated string
-     * @link http://book.cakephp.org/3.0/en/core-libraries/global-constants-and-functions.html#__xn
-     */
-    function __xn($context, $singular, $plural, $count, $args = null)
-    {
-        if (!$singular) {
-            return;
-        }
-
-        $arguments = func_num_args() === 5 ? (array)$args : array_slice(func_get_args(), 2);
-        return I18n::translator()->translate(
-            $singular,
-            ['_count' => $count, '_singular' => $singular, '_context' => $context] + $arguments
-        );
-    }
-
-}
-
-if (!function_exists('__dx')) {
-    /**
-     * Allows you to override the current domain for a single message lookup.
-     * The context is a unique identifier for the translations string that makes it unique
-     * for in the same domain.
-     *
-     * @param string $domain Domain
-     * @param string $context Context of the text
-     * @param string $msg String to translate
-     * @param mixed $args Array with arguments or multiple arguments in function
-     * @return string translated string
-     * @link http://book.cakephp.org/3.0/en/core-libraries/global-constants-and-functions.html#__dx
-     */
-    function __dx($domain, $context, $msg, $args = null)
-    {
-        if (!$msg) {
-            return;
-        }
-
-        $arguments = func_num_args() === 4 ? (array)$args : array_slice(func_get_args(), 2);
-        return I18n::translator($domain)->translate(
-            $msg,
-            ['_context' => $context] + $arguments
-        );
-    }
-
-}
-
-if (!function_exists('__dxn')) {
-    /**
-     * Returns correct plural form of message identified by $singular and $plural for count $count.
-     * Allows you to override the current domain for a single message lookup.
-     * The context is a unique identifier for the translations string that makes it unique
-     * for in the same domain.
-     *
-     * @param string $domain Domain
-     * @param string $context Context of the text
-     * @param string $singular Singular text to translate
-     * @param string $plural Plural text
-     * @param int $count Count
-     * @param mixed $args Array with arguments or multiple arguments in function
-     * @return mixed plural form of translated string
-     * @link http://book.cakephp.org/3.0/en/core-libraries/global-constants-and-functions.html#__dxn
-     */
-    function __dxn($domain, $context, $singular, $plural, $count, $args = null)
-    {
-        if (!$singular) {
-            return;
-        }
-
-        $arguments = func_num_args() === 6 ? (array)$args : array_slice(func_get_args(), 2);
-        return I18n::translator($domain)->translate(
-            $singular,
-            ['_count' => $count, '_singular' => $singular, '_context' => $context] + $arguments
-        );
-    }
-
-}
-
 if (!function_exists('json_last_error_msg')) {
     /**
      * Provides the fallback implementation of json_last_error_msg() available in PHP 5.5 and above.