Closed (fixed)
Project:
Drupal core
Version:
8.1.x-dev
Component:
entity system
Priority:
Major
Category:
Bug report
Assigned:
Unassigned
Reporter:
Created:
25 Nov 2012 at 17:29 UTC
Updated:
15 Jul 2016 at 14:52 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #1
dawehnerIt will be helpful also in the generic views integration.
Comment #2
xjmWe should probably run this by the D8MI folks first?
Comment #3
xjmDiscussed in IRC and #1830822-43: Split the Views UI listing into two tables for enabled and disabled. I'm not actually sure this is a good idea because:
format_plural()instead.@tim.plunkett mentioned that Views handler types might have a special plural format as well; we might want to look into that to see if there's a better way.
So at least, this needs more discussion.
Comment #4
dawehnerSo what we might should do is the following:
with the known count. If the count is not known we might just apply 3 or something like that? Seems to be pretty difficult to give a context of unknown many.
Comment #5
xjmI'm not sure we should do it at all, TBH.
Comment #6
jibranplural_entity_labels.patch queued for re-testing.
Comment #8
bojanz commentedCrossreferencing the Entity API issue: #1664350: Revise the custom label keys.
Pasting what I said into this issue.
So, applied to D8 core today, it would look something like this:
Since we have format_plural in core, it makes sense to have labels that are usable there.
From inline entity form to actions ("Deleted $number_of_items $entity_type_in_plural' => "Deleted 10 nodes"), this makes sense in a lot of places.
Comment #9
bojanz commentedPerhaps a better title.
Comment #10
mstrelan commentedIs this a duplicate of #23298: Entity bundles should declare a plural form of their label? And should bundles also have pluralised labels?
Comment #11
amateescu commentedIt's not really a duplicate, #23298: Entity bundles should declare a plural form of their label deals with *bundle labels*, which are stored in config (and it's pretty much impossible to do with the current config system in D8), while this one deals with entity type labels, which are stored in an annotation, and it is doable in D8. Working on a revised proposal and a patch :)
Comment #12
klonosWill this suffice for languages like Russian for example that have multiple plural forms (noun quantity that ends in 1 / noun quantities that end in 2,3,4 / noun quantities that end in 5,6,7,8,9,0)?
Comment #13
gábor hojtsyWe should use format_plural() for every case.
Comment #14
amateescu commentedHere's how I think this should look like. It's only implemented on the node entity type as a PoC, but should be expanded to all types provided by core if we agree on the direction.
Comment #16
gábor hojtsyYes, if there is no count I agree we should not invoke format_plural(). The suggestion that "we should use t() for the single case and format_plural for the N > 1 case" was wrong though. If we do know the number of things, we should call format_plural() at all times.
Comment #17
panchoFix missing implementation of EntityBCDecorator::entityTypeLabel() in #14.
Comment #18
panchoI believe this is important for UI.
If we really can't avoid using "article content" instead of "articles" (#23298: Entity bundles should declare a plural form of their label), then we should at least avoid "taxonomy term items" and "file items".
What would we do with multiple plural forms though?
If we don't implement a variable number of forms, in these cases we could simply fall back to using " items". That could be left to the translators. It wouldn't be a good solution for all languages but at least for the majority.
Comment #20
amateescu commentedThat's the whole point of the code above (as opposed to Bojan's proposal), multiple plural forms are handled correctly :)
Last night in IRC he mentioned that we also need a 'generic' plural form for when we don't want to count things, so I added it in this new patch.
Also, thanks for the fix in #17!
Comment #22
amateescu commentedBah!
Comment #24
amateescu commentedComment #25
amateescu commentedComment #26
amateescu commentedAdded the new @PluralTranslation annotation to existing tests. I think we're ready for some reviews on the approach before adding plural translations for all entity types. Or, even better, this patch could go in as-is and open a followup for the remaining entity types.
Comment #27
bojanz commentedWhile it is great that we have count labels, we also need both singular and plural generic labels, that was the point of my proposal.
This patch adds the generic plural label, but not the generic singular label, so I can't do "Add new $type" in Inline Entity Form for instance.
Comment #28
pancho1. That's true, we'd also need a generic, or indefinite singular.
We might want to define some constants for the first parameter of entityTypeLabel(), instead of the cryptic boolean:
NUMERUS_SINGULAR => indefinite singular
NUMERUS_PLURAL => indefinite plural
NUMERUS_DEFINITE => definite singular or plural depending on the count given in the second argument.
IMHO, we can define these constants in system.module because they are valid beyond language/locale and beyond entity system.
2. In any case these concepts need to be extended even further to really cater for all possible forms.
Apart from the numerus, many languages have regular (and irregular) endings that flect with the case. Translators mostly find a way to work around that, but to solve this generically, we'd need all of those forms. But that's far beyond the scope of D8 now.
Comment #29
amateescu commentedYep, I see now that we need the singular label too. Unfortunately, I'll be away for at least a week so I won't be able to push this further.
Comment #30
pancho@amateescu:
Before you're going: How about the approach proposed in #28.1? Should I give it a try or does something else come in your mind?
Comment #31
amateescu commentedI think that's fine, yes :) Although NUMERUS sounds a bit criptic.. we might try to go with something like LABEL_*.
About how the patch should look like, I guess it needs to be a combination of #17 and @bojanz's #8 (I mean separating the count definition for the indefinite one). I started with the count approach only because I'm sure that people would've misused the singular and plural forms for counts..
Comment #32
pancho#31:
I liked numerus because it is the grammatical concept and would at a later point be nicely extendable by CASE_NOMINATIVE etc. But that might be a bit over-engineered for now, andprobably is too much for grammar experts.
So in entityTypeLabel(), we might use:
And the annotation would look like:
Don't know if we want to rename 'label' to 'label_generic', so it matches the constant in entityTypeLabel()?
Comment #33
xano#2037763: Set page title in EntityListController::listing() depends on this.
Comment #34
panchoAny thoughts on #32, before I roll it into a patch?
Comment #35
gábor hojtsyYeah I think #32 solves the concerns raised in #23298: Entity bundles should declare a plural form of their label as well properly. We do need generic and definite plurals as well if we want to have a complete solution. Not sure if this will be easy on the developer experience, but human language is not easy.
Comment #36
amateescu commentedOk then, let's go with that.
Comment #38
amateescu commentedSilly php 5.3 :)
Comment #40
amateescu commentedHow about this.
Comment #41
andypostexamples are wrong
Comment #42
amateescu commentedThanks for reviewing.
Comment #43
andypostMaybe better provide additional methods?
Lower-cased 'Singular' is confusing me with upper-cased default label
I think this names too long, suppose 'ENTITY_TYPE_' prefix could be skiped
Comment #44
joachim commentedThis is really long:
These values are just getting passed around in calls, they're never stored in the database. So is there a reason to use integers -- could we use a string like 'plural' instead? That would be easier to read than a namespaced constant.
Comment #45
amateescu commentedThe 'ENTITY_TYPE_' prefix cannot really be skipped because the constants are on EntityInterface and without the prefix they can be confusing about which label they refer to, entity or entity type..
Re #44:
I was a bit verbose there, it should only be:
Comment #46
andypostso 'ENTITY_' could be skipped
Comment #47
amateescu commentedWell, TYPE_LABEL_COUNT sounds even more confusing..
Comment #48
jibran42: entity_type_count_labels-1850080-42.patch queued for re-testing.
Comment #50
xanoRe-roll.
Comment #51
joachim commentedCould someone explain why we have to have these hideously long namespaced constants?
What would be the problem with using strings, like this:
Comment #52
xanoThat was already explained in #45.
Comment #54
xanoRe-roll because of the extension of AnnotationInterface.
Comment #55
joachim commented> The 'ENTITY_TYPE_' prefix cannot really be skipped because the constants are on EntityInterface and without the prefix they can be confusing about which label they refer to, entity or entity type..
That explains why the constants are so verbose.
It doesn't seem to say why we need constants at all.
Comment #57
xanoFixed the test failures, and added a PHPUnit test and context support for the @PluralTranslation annotation.
Comment #59
xanoMinor code comment fix.
Comment #61
xanoComment #62
tim.plunkettNot sure how this is passing, that returns \Drupal\Core\Entity\EntityTypeInterface now.
Wouldn't these be better on \Drupal\Core\Entity\EntityTypeInterface? I could be wrong (it would make the static:: calls harder), but it seems to be about entity types.
If the constants do move, this seems like a good method for \Drupal\Core\Entity\EntityTypeInterface
Comment #63
martin107 commented61: drupal_1850080_61.patch queued for re-testing.
Comment #65
martin107 commentedComment #66
icseh. commentedI'm here in Szeged, and I'm going to reroll this.
Comment #67
icseh. commentedAfter the reroll it was a simple automerge.
Comment #68
heddnComment #69
icseh. commentedComment #72
stefank commentedHere is a fresh reroll.
Comment #73
stefank commentedTriggering testbot.
Comment #75
gábor hojtsyReformulate as bug report as per the summary. Needs issue summary update for more detail, suggested resolution, etc. as well as beta evaluation if this is proposed before RC/release :)
@bojanz asked me to look at this. The implementation looks to make sense to me. I would not invoke format_plural() globally but inject / use the string translation service (eg. use the string translation trait). Also you would need a potx module issue to parse the new annotation properly as plural source strings but that is not blocking for core.
Comment #76
moshe weitzman commentedComment #77
amateescu commentedRerolled and fixed the usage of format_plural().
Comment #79
amateescu commentedFixed that.
Comment #81
amateescu commentedFixed the new test class.
Comment #82
jibrans/loafs/loaves? Unless I have been taught wrong.
Comment #83
amateescu commentedGood catch :)
I'm wondering if this 8.1.x material now..
Comment #84
gábor hojtsyRemoving from D8MI sprint due to lack of attention.
Comment #85
dawehnerYeah this is totally 8.1.x feature to be fair.
Comment #86
tstoecklerI like this patch a lot, nice work! One question I was thinking about is whether we should be doing any fallback for entity types that do not provide this. I.e. just fallback to the
labelannotation which everyone will have or something like that.Some more specific notes:
I think these should move to
EntityTypeInterfaceallowing them to be less verbose, i.e.EntityTypeInterface::LABEL_SINGULAR.A more general question: Why use constants instead of just having separate methods (which could then be on the entity type directly)? I.e. why not have
$entity->getEntityType->singularLabel()instead ofSeems unused.
If we're going to leave this, it should be called
getEntityTypeLabel().It is done this way all over core, but it is in fact better to use
@countin the singular version as well, for languages where the singular formula is more complex than@count === 1.All in all warrants a needs work I guess.
Comment #87
dawehnerThis mostly addresses some points of the review of @tstoeckler
In general it would be really nice to have this done.
Well, this is not necessarily a getter, it actually calculates something.
Comment #88
dawehnerComment #89
bojanz commentedThe new code feels misplaced: I would expect the EntityType to have getters for these labels, not the Entity.
I see tim.plunkett had the same comment in #62, but it wasn't addressed.
(tstoeckler in #86 also wanted the constants moved to EntityTypeInterface, which would match the above, not touching Entity at all)
Nitpicks of the current patch:
Should this singular and the Banana one be also updated to use @count? If I saw 1 in some places and @count in others I wouldn't be sure what the best practise is.
The constants weren't updated here.
Comment #90
bojanz commentedRerolling
Comment #91
bojanz commentedHere's what I had in mind.
Changes:
- Moved the constants to EntityTypeInterface
- Moved the method to EntityType (but didn't rename it for now)
- Cleaned up all references to the constants, usage of array() vs [], PluralTranslation
- Made @count used in all singular labels instead of hardcoding 1.
entityTypeLabels() needs a new name. Any suggestions? getPluralLabel() I guess?
We'll also need EntityType test coverage, and updated example code for entities all over the place..
Comment #92
dawehnerLet's skip the echo bit, IMHO its not needed
Here is a question, why do we not have 4 different methods, one for each type? This would make the naming much easier.
Comment #93
dawehnerNeeds work based upon #92
Comment #94
dawehnerComment #95
bojanz commentedI can live with the separate methods. Any second opinions?
We'll want to update this whole piece then, and most likely remove the constants completely:
Comment #96
tstoecklerI totally like the separate methods. I already suggested something along those lines (albeit a little bit shyly (wow, that's a cool word)) in #86.
Comment #97
dawehnerAgreed
Comment #98
tim.plunkettMissed a constant.
What's the plan for BC?
Comment #99
bojanz commentedPlan for BC:
Comment #100
tim.plunkettThis interface is not marked @internal. That means anyone implementing it without extending a base class will get a fatal error. This is a BC break.
Comment #101
bojanz commentedInitial discussion:
Yes, this is technically a BC break. Potentially impacting half a theoretical person.
Comment #102
dawehnerRight, EntityType is a value object, the base interface maybe was a bad decision in the first place.
Comment #103
dawehnerComment #104
dawehnerHere is the interdiff
Comment #105
tstoecklerActually I think having an interface is fine, the poblem is that we have not really declared in most places what we consider our API. Just because we have an interface doesn't mean we consider it part of the API.
As @tim.plunkett is eluding to in #100 we have marked some places in core that are explicitly not part of the API as
@internal, but that's not very widespread, and we have changed classes before where we have assumed people will not reasonably subclass them even though were not marked as @internal.So really suggesting anything either way, we've just but ourselves in a less than optimal situation... :-/
Comment #106
dawehnerAdded a really related discussion.
Comment #107
bojanz commentedUpdated the default labels to actually be usable.
Ready for RTBC from my side.
Btw, update from catch on the BC issue: https://www.drupal.org/node/2550249#comment-10870382
I am of course inclined to agree.
Comment #108
bojanz commentedAnd the interdiff.
Comment #109
dawehnerI really like how this looks like now
Comment #110
berdirIn #2507235: EntityType::getLowercaseLabel() breaks translation, it was pointed out that the proposed solution there would get really complicated in combination with this. Looking at the patch, it seems like we only use lowercase labels for this now as we expect it will only be used as part of sentences. Which is fine I think and means that we do *not* need special lowercase versions for this in the other issue.
I'll update there as well.
Comment #112
dawehnerAs it turns out, we are not allowed to pass translatable markup objects to
PluralTranslatableMarkupNote: I also changed the code to do less on every initialization.
Comment #113
martin107 commentedNothing but minor changes
1) For example Translation::__construct which also extends AnnonationBase restricts the input parameter to be "array".
2) Moved the comments so the first line is on is own. in a minor thing pointed out by phpcs
3) From https://www.drupal.org/coding-standards/docs#Plugin @Annonation should be at the end of the comment section.
Comment #114
dawehnerThank you @martin107
Those changes are looking great!
Comment #115
bojanz commented@dawehner
Can you provide an interdiff for #112?
martin107's #113 doesn't include your changes, we need to reapply them.
Comment #116
martin107 commentedAh crap patch clash I posted my changes 3 mins after dawehner's and did not check for updates
... my changes are also based on #107 therefore ignoring the changes from #112 .. I will sort this out tonight...my bad.
Comment #117
dawehnerOH yeah sorry
Comment #119
martin107 commented#116 is another comment clash it was written with outsight of #115
Who knew that giving my lucky charm to Wile E Coyote was going to turn out like this!
https://www.youtube.com/watch?v=i6e-KrNCe_E&list=PLL3uNn7f3npgkXGEU71mZS...
If I step outside tonight, I should look up as there might just be a grand piano about to fall on my head...
What follows is a merge of the last 2 changes with and interdiff from #107
Comment #120
martin107 commentedThis comment is sponsored by the acme corporation.
Comment #121
bojanz commentedOkay, we're definitely good to go.
Comment #122
jhodgdonUm.... Does this work with translation, really? I mean, is the POTX extractor getting these? I doubt it.
Comment #123
dawehner@jhodgdon Currently it doesn't this is for sure, but I don't see why it should not be able to parse that as well, much like it parses
@Translationat the moment.Comment #124
jhodgdonWell the problem is that it is not going to store it like a normal Plural translation string. This is not going to work.
Plural strings are stored in the translation database as something like this:
single_formWEIRD_DELIMITERplural_form
This will store single_form and plural_form as separate strings. So when someone calls formatPlural() or makes a PluralTranslatableMarkup or whatever, it will not get translated properly. The test that you have in here didn't detect this because it doesn't actually try to translate to a different language.
This patch needs some work.
Comment #125
dawehnerI mean @jhodgdon what else should we be able to do? This calls out to format_plural at the end of the day, which is kinda what we want, don't we?
Comment #126
jhodgdonReally, the entire premise of this issue is flawed. This whole thing will only work for some languages. English, sort of. Spanish, sort of. French, sort of. Russian, not at all.
So. Let me explain.
There is a reason that we translate entire phrases at once. For instance, we might translate:
1 content item has been updated. / @count content items have been updated.
Note: these are plural/singular forms -- but not only the noun "content item" changes, but also the verb. In other languages, also adjectives might need to be changed to agree with the noun, or even the entire sentence order might need to change between singular and plural, and in some languages there are more than 2 plural forms for verbs, and in some there is only one.
The proposal here is just to have the strings "content item" and "content items", as the singular and plural forms, translate into other languages. So this would be OK for French or Spanish, aside from the verbs and adjectives, but not at all OK for Russian, which besides having 4 plural forms (which are not going to be translated right because this is not a proper formatPlural), also have different forms for nouns based on whether they're subjects or objects of verbs or objects of prepositions.
The other problem is formatPlural(). You MUST call formatPlural by passing in the literal strings that are to be translated, because that is how they are picked up by the POTX generator. They are translated as a group on localize.drupal.org into different languages, so that the 2 source strings in English become 4 translations in Russian. This is not going to happen with the code in this patch. They are going to be stored as 2 strings and translated as 2 separate strings, and like I said, in Russian the loner strings like "content items" cannot even be translated without knowing that they're going to be subjects or objects or whatever.
So this whole idea is flawed. Whatever the purpose was, it will not work right for anything but English.
Comment #127
jhodgdonSee #2545730: Misuse of formatPlural() in Numeric field prefix/suffix for more discussion on how to misuse formatPlural() in a very similar way on another issue that still needs to be resolved. But let's not introduce another misuse here please.
Comment #128
dawehner@jhodgdon So let's drop support for format plural as part of the issue and just handle the rest of it?
Comment #129
jhodgdonWhat else is there? This patch adds methods getSingularLabel(), getPluralLabel(), and getCountLabel(). To me they are all suspect.
Comment #130
jhodgdonApparently Gabor signed off on this so I'm setting this back to RTBC. I still think the formatPlural stuff at a minimum is wrong. But whatever.
Comment #132
dawehnerI'm feeling bad how this went :(
Comment #133
bojanz commentedAs I said on IRC, I'm with with pinging Gabor and other experts again, getting a second opinion.
As a speaker of a Slavic language (Serbian) I confirmed that it's fine to have generic singular / plural labels, and then the various count-specific forms. The problems start when the labels are embedded into a sentence (which brings noun cases into play), but that's a problem with every label in Drupal, including the current singular-only entity type labels. We are not making this problem worse. In fact, we're making translations better, because I'd very much rather see $plural_translated_to_serbian than $singular_translated_to_serbian . 's', etc.'
Comment #134
gábor hojtsySo first things first the generic singular and generic plural should be fine regardless of language, I would expect translators know that concept and would translate accordingly when seeing a plural/singular without a @count :) Looking at the concrete singular/plural stuff again now.
Comment #135
gábor hojtsyAll right, looking at the definite plural/singular cases, I don't see the problem. Once potx is capable of extracting the three strings (singular/plural/context) from its annotation, the fact that formatPlural() is called on them with those original source strings should both match up the translations properly and apply the plural rules of the language currently in use for the request. Any caching or bubbling that data without consideration for language may be a problem, but otherwise it looks like it considers the interface language and uses proper source values to me. Please correct me if I am missing something.
On review found one doc problem and a bigger problem with how getCountLabel's fallback code and lack of consideration for string context is shaping up. So those need fixing (and additional tests for context support). Leaving at needs work for these.
format_plural() as a global function does not exist.
This would of course not be able to be pretranslated. This is fallback code. A slightly better way to fix this is to do the @label replacement after the format plural, so the string translated is static and is not dynamic.
Also to have an inline formatPlural() with the two hardcoded strings so potx finds it properly. This way the source strings will not be found.
(Also this fallback probably needs context, since '@count @label' will not be easy to understand for translators).
Also wrong that label_count's context is never passed into format plural, that should be. Otherwise what does it help? This apparently does not have test coverage either or it would have failed.
Comment #136
gábor hojtsyAdditionally @dawehner points out that the 2 snippet I posted is also incorrect because getLowercaseLabel is already a translation object, so replacing the translation into a string and then format plural translating the translation would double translate it. One more reason to do the replacement in formatPlural()'s args.
Comment #138
amateescu commentedIf I understood #135 correctly, something like this should do it?
Comment #140
dawehnerI'm glad we have this kind of test coverage
Comment #141
bojanz commentedGabor's feedback has been addressed. Third time's the charm?
Comment #143
alexpottShould this be
if (empty($this->label_count['singular']) || empty($this->label_count['plural'])) {- or should we check this below and throw an exception if the keys are present and it's not empty?Comment #144
dawehnerI think the annotation class should do some kind of validation ...
Comment #145
dawehnerThere we go.
Comment #146
martin107 commentedNothing major - Just describing what we throw in the annotations.
Comment #147
bojanz commentedDidn't we just ensure that label_count can be empty, but the individual keys can't? In which case this change is not needed?
Comment #148
bojanz commentedConfirmed #147 with dawehner. His exceptions in PluralTranslation ensure that the singular and plural keys are always set. The point of the check in getCountLabel() is to provide a default when the entire count label is missing. Made the change to reflect that.
Comment #149
dawehnerThank you @bojanz
Comment #150
tim.plunkettJust curious, any reason this doesn't use
@expectedException?Comment #151
bojanz commented@tim.plunkett
Probably no reason, though note that the PHPUnit maintainer no longer recommends using the annotation: https://thephp.cc/news/2016/02/questioning-phpunit-best-practices
Comment #152
alexpottGiven the additions to EntityTypeInterface I think we have to wait for #2661926: [policy no-patch] Document that interfaces without an @api tag can have API additions during a minor release to become fixed before committing this. Also if this is committed to 8.1.x during beta it should have CR and be mentioned in the release notes.
Comment #153
dawehnerHere is one: https://www.drupal.org/node/2689949
Comment #154
bojanz commented#2661926: [policy no-patch] Document that interfaces without an @api tag can have API additions during a minor release has landed, and we have a change record now (made some tweaks too).
Comment #155
alexpottSaving issue credit.
Comment #156
alexpottLast time I reviewed this patch I get stuck on the fact that EntityType::getLowerCaseLabel() is not going to work for languages like German... but that is not the fault of this issue - that's #2507235: EntityType::getLowercaseLabel() breaks translation
Comment #157
alexpottI think we need to improve the documentation because atm we now have 4 labels in the annotation and 4 methods and I'm confused about when to use
getSingularLabel()overlabel(). Working out howGets the human-readable name of the entity type.is differentGets the singular label of the the entity type.is not so simple.I'm sorry it has taken a while to review this patch I've looked at it many times over the past week and discussed with @catch and @xjm. The general feeling is that this patch in its present state can land during the 8.1.x beta but none of us are "yay" this look fantastic - #35 sums this up nicely
And given that we are adding quite a few new methods which are similar to an existing method I think we need to make it super obvious which method to use.
Comment #158
dawehnerI hope this improves the documentation a bit.
Comment #159
alexpottDiscussed with @xjm, @effulgentsia and @cottser. We decided that the docs changes need to be improved but we'd like this patch to be in the 8.1.0-rc1 release. So we should go back to the patch in #148 and commit that and file a docs followup.
Comment #163
effulgentsia commentedPushed #159 to 8.2.x and 8.1.x. The confusing sequence of #161 and #162 is due to me having initially cherry picked into 8.1.x without the -x option, so I reverted, and then repushed with that option. Sorry for that.
Needs work for the docs follow-up per #159.
Comment #164
effulgentsia commentedPrefixing title to clarify that the main patch here has landed.
Comment #165
effulgentsia commentedComment #166
alexpottCreated #2701005: Improve documentation of EntityTypeInterface label functions for the followup.
Comment #168
tstoecklerFollow-up: #2767025: Add entity type label for a collection of entities