Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API Replace i18n message localisation with symfony/translation #6558

Merged
merged 2 commits into from
Jan 26, 2017

Conversation

tractorcow
Copy link
Contributor

@tractorcow tractorcow commented Jan 24, 2017

Closes #6221

Requires:

This feature includes advanced pluralisation based on http://symfony.com/doc/current/components/translation/usage.html#component-translation-pluralization

An important upgrading note for this change is that any localisation calls to _t() without a default will now trigger a warning.

All existing Zend_Translate libraries and dependencies have been removed.

This does not replace Zend_Locale, however, which will be addressed later with #6194

There are some potential performance issues with this implementation: I will post benchmarking analysis later.

@tractorcow
Copy link
Contributor Author

I also have some preliminary feedback from @sminnee which I need to implement:

  • i18nTextCollector should collect strings, even if they do not have a default defined, to ensure they show up as editable within transifex.
  • usage of pluralised strings with i18n::_t (rather than i18n::pluralise) should be a warning.

@tractorcow
Copy link
Contributor Author

Phew, travis-ci isn't slower, as I had feared. :) Still about ~12 minutes per test run.

@@ -22,7 +22,9 @@
"league/flysystem": "~1.0.12",
"symfony/yaml": "~2.7",
"embed/embed": "^2.6",
"swiftmailer/swiftmailer": "~5.4"
"swiftmailer/swiftmailer": "~5.4",
"symfony/config": "^2.8|^3",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More like, in-don't-ation right?

In many cases, localisation strings which worked in 3.x will continue to work in 4.0, however certain patterns
have been deprecated and will be removed in 5.0. These include:

- _t calls with a $context parameter, which is ignored.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, this was a useful for translators, since text collector picks it up - we just stopped using it because transifex didn't support it at the time. Looks like support for comments has been added now: https://docs.transifex.com/formats/yaml. I originally considered this a regression when moving from the old getlocalization.com service over to transifex.

Context is fairly essential for good translation quality - for example, an identifier like CMSMain.HANDLE="handle" doesn't make it clear to a translator if it's used a verb or noun. The fact that we haven't been including comments is unlikely to generate a lot of noise with translators, but that's mainly because we don't talk to translators enough (rather than them not valuing the feature).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK - if there's a reason we're not using it that's no longer relevant, then maybe it's worth keeping.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for forking the discussion, I've commented a bit more on the original RFC: #6221 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added this back.

- _t calls with a $context parameter, which is ignored.
- _t calls with sprintf-style placeholders (`%s`). Replace with named placeholders instead.
- _t calls with non-associative injection arguments. Please use an associative array for all arguments.
- _t calls which do not include a default value.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The intention here was to avoid duplication - you can use the same _t() call multiple times in your code, without duplicating the default value and having them diverge over time. But relying on one "master" _t() call is just as prone to human error, since you might remove from the code later on, only leaving the _t() call without the default value. In this case, text collection might set the value to null.

I think it's a per-project decision though: Some translation workflows will rely on developers maintaining YAML/JSON files directly, rather than relying on text collection - so you shouldn't force them to duplicate their efforts by setting default values in _t() calls.

Copy link
Member

@sminnee sminnee Jan 24, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps warn_on_missing_default is global config option set to true by default? If it has been missed, it's much more likely that someone has just forgotten it as opposed to it being a special workflow.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for forking the discussion, I've commented a bit more on the original RFC: #6221 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done as @sminnee suggested. missing_default_warning added.

More information on what forms these plurals can take for various locales can be found on the
[CLDR documentation](http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html)

The ability to pluralise strings is provided through the `i18n::pluaralise` method, which is similar to the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling

#### <a name="overview-i18n-api"></a>i18n API Additions / Changes

* Upgrade of i18n to symfony/translation
* Localisation based on language-only (without any specific locale) is now supported
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wasn't that supported already? For example, we've got es.yml for generic Spanish, and es_MX.yml for Mexican Spanish.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what's changed is that you can do i18n::set_locale('es') now, where before you could have a set of es strings, but you'd still need to set i18n::set_locale('es_MX').

* Localisation based on language-only (without any specific locale) is now supported
* i18nEntityProvider::provideI18nEntities() Now is expected to return only a single array
map of key to default values.
* i18n keys for '.PLURAL_NAME' and '.SINGULAR_NAME' have been changed back to FQN class names
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"FQN" isn't a commonly used term - just say "include their namespace"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FQCN is probably what you mean, but I agree it's best to avoid these abreviations where possible

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll use <Namespaced\ClassName>.PLURALS

@@ -121,6 +121,21 @@ As well as properties, method calls can also be specified:
- [ pushHandler, [ %$DefaultHandler ] ]


## Using constants as variables

Any of the core constants can be used as a service argument by quoting with back ticks "`".
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome change, that would've come in handy a couple of times already!

SINGULARNAME: 'Permission Role Code'
SilverStripe\Security\RememberLoginHash:
PLURALNAME: 'Remember Login Hashs'
PLURALS:
one: 'A Remember Login Hash'
other: '{count} Remember Login Hashs'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hashs -> Hashes

@@ -155,7 +155,7 @@ public static function backtrace($returnVal = false, $ignoreAjax = false, $ignor
* @param int $argCharLimit
* @return string
*/
public static function full_func_name($item, $showArgs = false, $argCharLimit = 10000)
public static function full_func_name($item, $showArgs = false, $argCharLimit = 100)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does that have to do with i18n?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, this was just debugging changes I forgot to revert. :)

@@ -6,7 +6,7 @@
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\Debug;
use SilverStripe\Dev\BuildTask;
use SilverStripe\i18n\i18nTextCollector;
use SilverStripe\i18n\TextCollection\i18nTextCollector;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about moving text collection to its own module? As I've outlined in my comments around the _t() default value, I don't think text collection is the only translation workflow we should support - some teams will just manage their YAML/JSON separately. The reason I'm bringing this up is namespacing: If it's a separate module, we'd probably use SilverStripe\i18nTextCollection\i18nTextCollector instead of SilverStripe\i18n\TextCollection\i18nTextCollector (since the SilverStripe\i18n namespace should be core only)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, but in another change. :)

* Some arbitrary resource which expires when flush is invoked.
* Uses a canary file to mark future freshness requests as stale.
*
* @link https://media.giphy.com/media/fRRD3T37DeY6Y/giphy.gif for use case
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hah, nice easter egg

*/
protected static function canary()
{
return TEMP_FOLDER . '/catalog.i18n_canary';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The class name and PHPDoc ("Some arbitrary resource") implies this is a generic helper, yet the canary file name is hardcoded to catalog.i18n_canary. Shouldn't it take a mandatory identifier as a constructor arg?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It needs to be accessible to flush handler, which is a static method, otherwise I'd make it a constructor argument.

* Zend_Translate removed
* i18n::_t $context parameter deprecated
* i18n::_t Support for sprintf-style `%s` arguments deprecated
* i18n::_t Using non-associative injection with named parameters is now an error
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: Can you either wrap things like this in backticks or escape the markdown characters to prevent the formatting breaking?

API Implement enhanced pluralisation
Remove Zend_Translate and all Zend dependencies from i18n
Deprecated $context from i18n::_t()
Warn on missing default string for i18n::_t()
@tractorcow tractorcow force-pushed the pulls/4.0/i18n-symfony branch from 34d34b2 to 719a00d Compare January 25, 2017 04:09
@tractorcow
Copy link
Contributor Author

Updated based on feedback, as well as result of conversation over at #6221 (comment)

Rolled pluralisation functionality into the i18n::_t() method
Warnings on missing default can now be turned off
@tractorcow tractorcow force-pushed the pulls/4.0/i18n-symfony branch from 719a00d to de02a3f Compare January 25, 2017 05:12
@tractorcow
Copy link
Contributor Author

Note: CMS build can be merged ahead of framework build, so we can restart and see if these tests pass.

silverstripe/silverstripe-cms#1724

@tractorcow
Copy link
Contributor Author

silverstripe/silverstripe-cms#1724 is green

// inject the variables from injectionArray (if present)
$sprintfArgs = [];
if ($default && !preg_match('/\{[\w\d]*\}/i', $default) && preg_match('/%[s,d]/', $default)) {
Deprecation::notice('5.0', 'sprintf style localisation variables are deprecated');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also need to replace existing core uses: #6582.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants