Skip to content
Browse files

ENHANCEMENT Backwards compatible $priority parameter for i18n::_t(): …

…Allow numeric arrays as parameters, as well as %s style replacements with a named parameter map (easier transition to new system with existing translation strings)
  • Loading branch information...
1 parent 2288d80 commit e949b6f2b0c01b6aa666eaaa0e972aea0ba478de @chillu chillu committed
Showing with 83 additions and 9 deletions.
  1. +26 −3 docs/en/changelogs/3.0.0.md
  2. +7 −2 docs/en/topics/i18n.md
  3. +30 −3 i18n/i18n.php
  4. +20 −1 tests/i18n/i18nTest.php
View
29 docs/en/changelogs/3.0.0.md
@@ -455,13 +455,36 @@ and was rarely used in practice - so we moved it to a "[homepagefordomain](https
### New syntax for translatable _t functions [i18n-t]###
-You can now call the _t() function in both templates and code with a namespace and string to translate, as well as a
-comment and injection array. Note that the proxity arguement to _t is no longer supported.
+You can now call the `_t()` function in both templates and code with a namespace and string to translate, as well as a comment and injection array.
The new syntax supports injecting variables into the translation. For example:
:::php
- _t('i18nTestModule.INJECTIONS2', "Hello {name} {greeting}", array("name"=>"Paul", "greeting"=>"good you are here"));
+ _t(
+ 'i18nTestModule.INJECTIONS2',
+ "Hello {name} {greeting}",
+ array("name"=>"Paul", "greeting"=>"good you are here")
+ );
+
+We've written the injection logic in a way that keeps backwards compatible with
+existing translations. This means that you can migrate from `sprintf()` to the new injection
+API incrementally. The following to "mixed usage" examples still work, although they
+don't get the advantage of flexible ordering in substitutions.
+
+ :::php
+ _t(
+ 'i18nTestModule.INJECTIONS2',
+ "Hello {name} {greeting}",
+ array("Paul", "good you are here")
+ );
+ _t(
+ 'i18nTestModule.INJECTIONS2',
+ "Hello %s, %s",
+ array("name"=>"Paul", "greeting"=>"good you are here")
+ );
+
+Of course, you can keep using `sprintf()` for variable substitution in your own code.
+
### Default translation source in YML instead of PHP $lang array, using Zend_Translate {#zend-translate}
View
9 docs/en/topics/i18n.md
@@ -180,9 +180,10 @@ Therefore, the following would be a valid use in templates:
Using SS templating variables in the translatable string (e.g. $Author, $Date..) is not currently supported.
-### Injection-support
+### Injection Support
-Variable injection in _t allows us to dynamically replace parts of a translated string, e.g. by a username or a page-title.
+Variable injection in `_t()` allows us to dynamically replace parts of a translated string, e.g. by a username or a page-title. The named parameters also allow flexible ordering of placeholders,
+which might vary depending on the used language.
:::php
// in PHP-file
@@ -196,6 +197,10 @@ Variable injection in _t allows us to dynamically replace parts of a translated
// in SS-template ($Name must be available in the current template-scope)
<%t MYPROJECT.INJECTIONS "Hello {name} {greeting}" name="$Name" greeting="good to see you" %>
+Note that you can still use `sprintf()` wrapped around a `_t()` call
+for your substitutions. In contrast to `sprintf()`, our API has a more translator friendly
+placeholder syntax, as well as more graceful fallback if not all placeholders are found
+(an outdated translation with less placeholders will throw a notice rather than a fatal error).
## Collecting text
View
33 i18n/i18n.php
@@ -1512,9 +1512,36 @@ static function _t($entity, $string = "", $context = "", $injection = "") {
}
// inject the variables from injectionArray (if present)
- if ($injectionArray && count($injectionArray) > 0) {
- foreach($injectionArray as $variable => $injection) {
- $returnValue = str_replace('{'.$variable.'}', $injection, $returnValue);
+ if($injectionArray) {
+ $regex = '/\{[\w\d]*\}/i';
+ if(!preg_match($regex, $returnValue)) {
+ // Legacy mode: If no injection placeholders are found,
+ // replace sprintf placeholders in fixed order.
+ $returnValue = vsprintf($returnValue, array_values($injectionArray));
+ } else if(!ArrayLib::is_associative($injectionArray)) {
+ // Legacy mode: If injection placeholders are found,
+ // but parameters are passed without names, replace them in fixed order.
+ $returnValue = preg_replace_callback(
+ $regex,
+ function($matches) use(&$injectionArray) {
+ return $injectionArray ? array_shift($injectionArray) : '';
+ },
+ $returnValue
+ );
+ } else {
+ // Standard placeholder replacement with named injections and variable order.
+ foreach($injectionArray as $variable => $injection) {
+ $placeholder = '{'.$variable.'}';
+ $returnValue = str_replace($placeholder, $injection, $returnValue, $count);
+ if(!$count) {
+ SS_Log::log(sprintf(
+ "Couldn't find placeholder '%s' in translation string '%s' (id: '%s')",
+ $placeholder,
+ $returnValue,
+ $entity
+ ), SS_Log::NOTICE);
+ }
+ }
}
}
View
21 tests/i18n/i18nTest.php
@@ -251,7 +251,8 @@ function testNewTMethodSignature() {
i18n::get_translator('core')->getAdapter()->addTranslation(array(
'i18nTestModule.NEWMETHODSIG' => 'TRANS New _t method signature test',
- 'i18nTestModule.INJECTIONS' => 'TRANS Hello {name} {greeting}. But it is late, {goodbye}'
+ 'i18nTestModule.INJECTIONS' => 'TRANS Hello {name} {greeting}. But it is late, {goodbye}',
+ 'i18nTestModule.INJECTIONSLEGACY' => 'TRANS Hello %s %s. But it is late, %s',
), 'en_US');
$entity = "i18nTestModule.INJECTIONS";
@@ -287,6 +288,24 @@ function testNewTMethodSignature() {
$translated, "Testing a translation with just entity and injection array"
);
+ $translated = i18n::_t(
+ 'i18nTestModule.INJECTIONSLEGACY', // has %s placeholders
+ array("name"=>"Cat", "greeting2"=>"meow", "goodbye"=>"meow")
+ );
+ $this->assertContains(
+ "TRANS Hello Cat meow. But it is late, meow",
+ $translated, "Testing sprintf placeholders with named injections"
+ );
+
+ $translated = i18n::_t(
+ 'i18nTestModule.INJECTIONS', // has {name} placeholders
+ array("Cat", "meow", "meow")
+ );
+ $this->assertContains(
+ "TRANS Hello Cat meow. But it is late, meow",
+ $translated, "Testing named injection placeholders with unnamed injections"
+ );
+
i18n::set_locale($oldLocale);
}

0 comments on commit e949b6f

Please sign in to comment.
Something went wrong with that request. Please try again.