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

Add checking for translators comments to the I18n sniff. #742

Merged
merged 2 commits into from
Jan 7, 2017

Conversation

jrfnl
Copy link
Member

@jrfnl jrfnl commented Dec 25, 2016

Implemented based on the following specs:

  • Only one error should be thrown per gettext call.
  • A translators comment is only required when (one of) the text string(s) contains placeholders.
  • It's ok for there to be a translators comment if the text string(s) does not contain placeholders.
  • The translators comment must be directly above the gettext call.
  • If the comment is not on the line directly above the gettext call, there should only be whitespace lines between the comment and the line containing the gettext call.
  • The translators comment must be in // or /* */ format, docblocks are not allowed.
  • A translators comment must start with translators:
  • The check defaults to throwing a warning. If the extra ruleset is enabled, the error level will change to error.

Fixes #423

I've added a sniff property $check_translator_comments to enable us to unit test the other checks within the I18n sniff without getting bogged down by errors thrown by the translators comment check.
This is a public property, but is only intended to be used in combination with the unit tests.
It could be used in custom rulesets too, but this shouldn't be needed as the translator comment checks can be excluded via their error codes.

Regarding the travis run failure:

The unit tests against PHPCS 2.7.0 are failing because the ruleset is erroneously taken into account when running the unit tests, which leads to PHPCS throwing an error instead of the expected warning.

This was fixed in PHPCS 2.7.1.
This only affects the unit tests however, not the functioning of the sniff itself.

Related: #733, #696 and squizlabs/PHP_CodeSniffer#1177

$comment_text = trim( $tokens[ $previous_comment ]['content'] );

// If it's multi-line /* */ comment, collect all the parts.
if ( '*/' === substr( $comment_text, -2 ) && '/*' !== substr( $comment_text, 0, 2 ) ) {
Copy link
Member

@GaryJones GaryJones Dec 26, 2016

Choose a reason for hiding this comment

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

Could this "collect all parts from a multi-line comment" be abstracted into a re-usable method in the base class?

Also, how does it handle something like:

/*
 * This is a multiline comment,
 * But it also has * at the start
 of some lines ;-)
*/

Copy link
Member Author

@jrfnl jrfnl Dec 26, 2016

Choose a reason for hiding this comment

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

Could this "collect all parts from a multi-line comment" be abstracted into a re-usable method in the base class?

It could, but I've not seen any other sniff within the WPCS which would need it. I suggest this can be done later if/when another sniff would need something similar.
Also - the snippet only handles multi-line /* */ type comments, no other type and (currently) does not care about how the lines are added together as for this sniff, only the start of the text is interesting, so if we would want it to be more generic, it will need some tweaking.

how does it handle something like <code snippet>

It handles that fine, just tested it to be sure + added an additional unit test to that effect.

printf(
/* translators: number of monkeys, location. */
__( 'There are %1$d monkeys in the %2$s', 'my-slug' ),
intval( $number ),
Copy link
Member

Choose a reason for hiding this comment

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

intval tends to be PHP 4 - (int) would be better.

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed

@GaryJones
Copy link
Member

Code generally looks good - great work.

Pinging @ramiy, as I think he does a lot with translator comments, and can offer feedback on any missed cases / false positives.

Implemented based on the following specs:
* Only one error should be thrown per gettext call.
* A translators comment is only required when (one of) the text string(s) contains placeholders.
* It's ok for there to be a translators comment if the text string(s) does not contain placeholders.
* The translators comment must be directly above the gettext call.
* If the comment is not on the *line* directly above the gettext call, there should only be whitespace lines between the comment and the line containing the gettext call.
* The translators comment must be in `//` or `/* */` format, docblocks are not allowed.
* A translators comment must start with `translators:`
* The check defaults to throwing a warning. If the `extra` ruleset is enabled, the error level will change to `error`.
@jrfnl jrfnl force-pushed the feature/issue-423-check-translator-comment branch from 73fd741 to ed0eb5d Compare December 29, 2016 18:28
@jrfnl
Copy link
Member Author

jrfnl commented Dec 29, 2016

Rebased after #733 to allow unit tests to pass.

@ramiy
Copy link

ramiy commented Dec 30, 2016

Looks good!!!

As for: The translators comment must be directly above the gettext call.

And the examples on the testing file:

printf(
	/* translators: number of monkeys, location. */
	__( 'There are %1$d monkeys in the %2$s', 'my-slug' ),
	(int) $number,
	esc_html( $string )
); // Ok.

/* translators: number of monkeys, location. */
printf(
	__( 'There are %1$d monkeys in the %2$s', 'my-slug' ),
	(int) $number,
	esc_html( $string )
); // Bad - comment not directly before line containing the gettext call.

Although I prefer to add comments above the gettext call, WordPress core has tons of translators comments above the printf() and sprintf() functions. We will need to create a new ticket to move all those comments. Pinging @SergeyBiryukov and @ocean90.

@jrfnl
Copy link
Member Author

jrfnl commented Dec 30, 2016

Hi @ramiy Thanks for looking this over!

As for: The translators comment must be directly above the gettext call.

I've set that quite strict as in my personal experience with PoEdit, the comments don't get picked up otherwise. Not sure how well GlotPress/makepot does in picking up those comments if they are not on the line directly above (I expect just as badly as PoEdit uses makepot underneath the hood).

If it's on one line, it should be fine, see the last unit test:

/* translators: number of monkeys, location. */
printf( __( 'There are %1$d monkeys in the %2$s', 'my-slug' ), intval( $number ), esc_html( $string ) ); // Ok - comment is directly before line containing the gettext call.

And if the gettext call is on the same line as the (s)printf(), but the parameters aren't, it should be fine as well:

/* translators: number of monkeys, location. */
printf( __(
	'There are %1$d monkeys in the %2$s', 'my-slug' ),
	intval( $number ),
	esc_html( $string )
); // Ok - comment is directly before line containing the gettext call.

@jrfnl
Copy link
Member Author

jrfnl commented Dec 30, 2016

I've just read through a number of trac tickets around this, starting from https://core.trac.wordpress.org/ticket/39116 and am left with one question: should translators: always be lowercase of should Translators: be allowed too ? (currently it's not)
IIRC PoEdit only accepts one or the other (it is a case-sensitive command line option you provide), not sure about other makepot tools.

@grappler
Copy link
Member

grappler commented Dec 30, 2016

as PoEdit uses makepot underneath the hood

I don't think so because PoEdit had to add this functionality.

Poedit did support the "TRANSLATORS:" tag mentioned in gettext's own manual, but not the lowercase variant.

I found this in one of my emails with the PoEdit Developer.

@ntwb
Copy link
Member

ntwb commented Dec 30, 2016

... am left with one question: should translators: always be lowercase

Edit: Yes No

Edit: Found it, it wasn't capitalisation I was thinking of, I'll post a follow up email for repo watchers

@ntwb
Copy link
Member

ntwb commented Dec 30, 2016

Via https://core.trac.wordpress.org/ticket/30603

Translator comments must be on a new line, and the line begin with either /* or //

@GaryJones
Copy link
Member

GaryJones commented Dec 30, 2016

Comments with lowercase t may trigger other warnings about starting a comment with a capital, unless we have exclusions for them in place - we currently have that check turned off in the Docs ruleset, because those exclusions don't exist at the sniff-level yet.

I'd love to allow just capitalised Translators, but clearly prior art (namely, anyone who's ever added in these comments), means the lowercase versions needs to be supported too.

@ocean90
Copy link
Member

ocean90 commented Dec 30, 2016

As for: The translators comment must be directly above the gettext call.

I've set that quite strict as in my personal experience with PoEdit, the comments don't get picked up otherwise. Not sure how well GlotPress/makepot does in picking up those comments if they are not on the line directly above (I expect just as badly as PoEdit uses makepot underneath the hood).

Just a general FYI: GlotPress doesn't generate POT files from source files, that's why we have makepot.

makepot doesn't care where a translator comment is. If there is a comment it stores it and adds the comment to the next gettext call, no matter how many lines there are between the comment and the actual gettext call.


We will need to create a new ticket to move all those comments.

There is no need for that, see also https://make.wordpress.org/core/handbook/contribute/code-refactoring/.

@jrfnl
Copy link
Member Author

jrfnl commented Dec 30, 2016

@grappler

I don't think so because PoEdit had to add this functionality.

It did for the automatic WP project setup which it now offers out of the box, but before that they already supported it as long as you configured it right:
Preferences -> Extractors -> PHP ->"Command to extra translations' - if you added "--add-comments=translators:" to this, it worked, even in (very) old versions of PoEdit.
That is the bit which I know only works in a case-sensitive way.

Oh and it also corrects me regarding what they use under the hood - not makepot, but xgettext.

@jrfnl
Copy link
Member Author

jrfnl commented Dec 30, 2016

Based on the feedback I've made the checking for the translators: part case-insensitive and added unit tests to that effect.
I've also added the additional case from #742 (comment) to the unit tests (second example).

makepot doesn't care where a translator comment is. If there is a comment it stores it and adds the comment to the next gettext call, no matter how many lines there are between the comment and the actual gettext call.

Based on this: should we loosen up the check for a translators comment on the line directly above the gettext call ?
I'd advocate against it for the following reasons:

  • We know that if it's on the line directly above it will get picked up correctly by different tools, this might not be consistently so for all tools if the comment has other code between it and the gettext call.
  • Similar to the late escaping philosophy, having the translators comment tightly coupled with the actual call makes it easier for other devs to see that there is one in place.

Last question as asked before in #423 (comment):

Oh and input on whether or not some form of whitelisting for a gettext call without translators comment is needed and what form it should take would be welcome too !

I can imagine we should have a whitelist comment as - if I remember correctly - if the same phrase is used several times, it only needs a translators comment once.

Opinions ?

@vslavik
Copy link

vslavik commented Dec 31, 2016

It did for the automatic WP project setup which it now offers out of the box, but before that they already supported it as long you configured it right:
Preferences -> Extractors -> PHP ->"Command to extra translations' - if you added "--add-comments=translators:" to this, it worked, even in (very) old versions of PoEdit.
That is the bit which I know only works in a case-sensitive way.

Oh and it also corrects me regarding what they use under the hood - not makepot, but xgettext.

Poedit developer here. That’s correct, and the limitations come from the de-facto standard GNU gettext tools, not Poedit itself: there can only be one such tag (further --add-comments override it, not amend) and it is case-sensitive. In Poedit 2, this will be user-configurable easily and on per-PO file basis to accommodate WP (and will default to “translators:” for it). I created an issue for this for public visibility into progress: vslavik/poedit#314

Based on this: should we loosen up the check for a translators comment on the line directly above the gettext call ?
I'd advocate against it for the following reasons:

Allow me to add another reason: compatibility with xgettext extraction.

@jrfnl
Copy link
Member Author

jrfnl commented Dec 31, 2016

@vslavik Thank you for your input & clarification! Very useful.

@jrfnl
Copy link
Member Author

jrfnl commented Jan 5, 2017

Anyone still wants to have a look at this ? If not, I propose we merge it tomorrow.

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

Successfully merging this pull request may close these issues.

Add a translator comment sniff
7 participants