Problem/Motivation
Locale module has many functions let's review and deprecate:
- locale_get_plural
Steps to reproduce
N/A
Proposed resolution
Add method selectPluralForm to TranslationInterface.
Add the default implementation to TranslationManager with the fallback protected getPluralIndex.
Use a service provider in locale to swap in the Locale TranslationManager that can respond to the languages plural forms.
Remaining tasks
N/A
User interface changes
N/A
API changes
N/A
Data model changes
N/A
| Comment | File | Size | Author |
|---|
Issue fork drupal-2660338
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
alexpottNo that the major issue is fixed. I think this can be treated as a normal bug.
Comment #4
claudiu.cristea#2766857: Provide a PluralTranslatableMarkup::getPluralVariantIndex() factory method is related.
Comment #5
claudiu.cristeaHere's patch.
Comment #6
claudiu.cristeaSmall improvement.
Comment #9
claudiu.cristeaAdded the missed service in unit tests container.
Comment #10
kristen polThanks for the patch. I have reviewed it and don't see any obvious issues though there are some comments that should be changed slightly.
I had not heard "zero-based positive integer" used before. I googled it and it does appear to be used but it might be better to change to something like:
...implementation should return zero, a positive integer, or...
The "he" should be changed to be gender neutral. In other places "you" is used. Or, the sentence could be restructured something like:
The implementation should return zero, a positive integer, or, to not impact the results, nothing.
Typo:
local_get_plural => locale_get_plural
Typo:
Local => Locale
I'll test the patch shortly.
Comment #11
kristen polI've tested this as follows:
Comment #12
kristen polAssigning to myself to make the comment changes. I will try to finish this today.
Comment #13
kristen polStill plan on working on this but the day got away from me. Crossing fingers for tomorrow. If I don't finish by Friday EOD, then I'll take my name off.
Comment #15
kristen polI reworded some of the comments. Here's the patch and interdiff.
Comment #16
kristen polComment #17
claudiu.cristea@Kristen Pol, thank you for your work and review. Sorry for my poor English. I think the patch looks good. I'm not very sure yet about the solution: if invoking a hook is the way to go. Also I don't find it bad. Probably in 99.99% of the cases nobody will implement such a hook and we'll live with the only implementation which is
locale_plural_variant_index(). Normally we should offer also an "alter hook" but for me that sounds a little bit over-engineering.Nit:
Compute > Computes
Comment #21
alberto56 commentedThis might be related to #2273889: Don't use one language's plural index formula with another language's string in the case of untranslated strings using format_plural()., in the sense that computing the plural index requires more information than just the target language -- we also need to know the string itself: if no translation exists for a string, we should not be using the target language plural index, but rather -1, it seems. Perhaps the string itself could be passed to hook_plural_variant_index, so that the locale_plural_variant_index could then check if the string is, in fact, translated; if it is not then the plural variant index would always be -1.
Comment #22
alexpottI don't think a new hook is a way to do this. I think PluralTranslatableMarkup should be asking the TranslationManager for the plurals and then when locale is enabled it should be wrapping the TranslationManager service and enhancing the getPluralIndex method. A new hook adds an extension a new extension point that's not needed.
Comment #23
alexpottHere's #21 implemented but not yet working. This could be becasue of how code / services are loaded.
No interdiff because a different approach.
Comment #26
claudiu.cristeaWe can also deprecate
locale_get_plural()in the scope of this issue as in #23, the procedural function became only a wrapper of the service method call.Also this approach help us also to remove usages of
drupal_static()anddrupal_static_reset()fromlocale_get_plural()and this makes this part of the #1577902: [META] Remove all usages of drupal_static() & drupal_static_reset() effort.Comment #27
andypostReroll, looks tests do a lot of mocks for services so instead of strings translatable object returns
Comment #28
andypostDebugging test
\Drupal\Tests\Core\Datetime\DateTest::testFormatInterval()shows thatcountpassed wrong somehowComment #30
andypostShould fix some tests
Comment #32
andypostDecorated service should implement all public methods
Comment #34
andypostreroll
Comment #38
ridhimaabrol24 commentedReroll patch for 9.1.x.
Comment #39
ridhimaabrol24 commentedFixing the error in patch #38.
Comment #40
kristen polThanks for the patch. I tried testing it twice (two different installs) but keep getting an error after adding the language:
When the patch is updated, here are a few nitpicks that could be addressed:
Nitpick: Character wrapping (move some words up).
Nitpick: Comment should be a sentence with starting capital and ending period.
Nitpick: More than 80 chars.
Nitpick: Extra empty line.
Comment #41
ravi.shankar commentedComment #42
ravi.shankar commentedComment #43
adityasingh commentedComment #44
adityasingh commentedUpdated patch as per the changes suggested in #40, please review.
Comment #45
kristen polThanks for the update. #44 fixes the nitpicks noted in #40.
Comment #46
kristen polTagging for manual testing. I had issues but maybe someone else can try. If you want test steps, see #11.
Comment #47
tanubansal commentedWe have followed the steps given in #11 and after adding the patch mentioned #44 (https://www.drupal.org/pift-ci-job/1751390). While enabling singular/plural modules , its showing 'Site encountered error'. When we refresh the modules page then it should that the module is enable. Please refer the attached screenshots below.
Comment #48
tanubansal commentedComment #49
kristen polOk, since @tanubansal also had an issue, moving this back to needs work.
Comment #50
andypostTests failing because of
Comment #51
andypostAttempt to fix #50
Comment #52
quietone commentedComment #54
quietone commentedPatch fails to apply to 9.2.x setting to NW for that.
The Issue summary needs to have a proposed resolution, adding tag.
Comment #55
ravi.shankar commentedAdded reroll of patch #51 on Drupal 9.2.x.
Comment #56
ravi.shankar commentedFixed custom command fails.
Comment #57
mohit_aghera commentedComment #58
andypostNew method needs CR also it could help to deprecate locale code a bit
Comment #59
mohit_aghera commentedFixing test cases.
All the test cases failing in #56 are passing on local now.
InstallerExistingConfigTesttest is something that is passing without any change. So not sure if past failure was due to other reasons.Comment #61
kristen polPulling out the failure info:
Related code:
Comment #65
andypostComment #66
ravi.shankar commentedAdded reroll of patch #59 on Drupal 9.5.x.
Comment #67
andypostLets see what will fail now
Comment #69
smustgrave commentedThis issue is being reviewed by the kind folks in Slack, #needs-review-queue-initiative. We are working to keep the size of Needs Review queue [2700+ issues] to around 400 (1 month or less), following Review a patch or merge request as a guide.
For the IS update and change record
Did not test or review yet.
Comment #72
nicxvan commented#3577671: Modernize locale file handling
#3037031: Convert locale.compare.inc to a service
#3037156: Modernize locale history functions
Comment #73
nicxvan commentedI think we combine a few of the remaining functions in locale.module as part of the .module elimination initiative.
There are still 8 issues remaining even if we combine these few.
Comment #74
nicxvan commentedComment #75
nicxvan commentedShould have done the file audit first, locale_get_plural is complex enough, let's just do that one here.
Comment #76
nicxvan commentedComment #79
berdirRemoving postponed status, I think this is fairly conflict-free with other issues (maybe except services.yml, but I've moved the change up and that's easy to rebase) and can be worked on. Created an MR with that. At some point changes to TranslateEditForm snuck in, those seem unrelated and I ignored them.
Comment #80
berdirI think I want to explore adding this method to a new interface + service in core, that should be much easier to overwrite. I'm not found of decorators generally and this also comes with changes to a pretty fundamental interface.
Comment #81
berdirWorking on a new service. That requires updates to a bunch of unit tests, but seems to work well and feels much cleaner.
\Drupal\Core\StringTranslation\StringTranslationTrait::getNumberOfPlurals() is somewhat related to this. That also wraps a locale service. I only identified 3 calls to that. one in locale, one in config_translation and one in views. We could consider to just deprecate that, only the views call doesn't depend on locale anyway. Alternatively we could expand the same of the new interface and add it to that as well.
I'm even wondering if we could somehow reuse the existing \Drupal\locale\PluralFormula service implement the new interface instead of a new one that calls out to it. Would nee to alias and deprecate the current service. This is already complex enough I think.
FWIW, the static/memory cache here feels overkill. what exactly is this even caching? a php calculation?
Comment #82
berdirI think this is ready for review.
Comment #83
nicxvan commentedTook a quick look and had some minor questions, I'll have a clear look in a bit.
Comment #84
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #85
andypostThis is where formula caching been added so not sure it's a good idea to remove #1273968: remove eval from locale.module
Comment #86
berdirThat's not true, locale_get_plural() was already using drupal_static() before that, those lines weren't touched in that commit. and it had been using static caching even before drupal_static(), it had been using the static keyword since that function was added in a commit in 2004 by Dries before there were issues and issue numbers.
Raw PHP execution performance changed *a tiny bit* since 2004, it doesn't look like anyone every questioned whether static caching here is worth it or not. Might not even have been back in 2004.
I did a script that called the function 100k times, it barely registered with microtime() and it made no difference whether or not the static caching is there. I verified how often it's called on the frontpage of umami with disabled render caches: zero times, on the article add form, once.
Rebased and removed it.
Comment #87
nicxvan commentedOk I did a bunch of digging, had a couple of discussions in slack and read a bunch of references.
I think we should find a way to document this here in the comments for future people.
Some of this may be obvious to other people on this thread, but I want to type it out to help ensure I understand it properly.
Different languages have different formulas for plurals: https://docs.translatehouse.org/projects/localization-guide/en/latest/l1...
English for example:
nplurals=2; plural=(n != 1);There are two plural forms and the rule for plurals is if there is 1 say the singular, if there are more or less than 1 then use the plural.
E.g 1 horse, 2 horses, 50 horses, 0 horses, -10 horses.
Other languages have other rules: https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html
Polish:
nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);There is some documentation on d.o here: https://www.drupal.org/community/contributor-guide/reference-information...
My understanding is that the formula will be at the top of the .po files.
We then precalculate the plural formula in a compressed way shown here: https://www.drupal.org/project/drupal/issues/1273968#comment-7559379
A translation will look like this:
The 0 or 1 is the plural index.
I think we can fill out and link to this reference on
PluralFormula.And maybe on
LocalePluralIndexComment #88
nicxvan commentedRebased, haven't taken a pass at the docs yet other than looking through the process again.
It's green.
Comment #89
nicxvan commentedOk I added comments to the two interfaces where I think it makes sense. I took another look at the architecture, I think this makes sense.
The formula, formulae, formulas work should be in a followup I think since it includes interfaces, statics and methods, it's out of scope here.
If someone could review the comments I added I can take another pass at reading through these changes.
Comment #90
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #91
nicxvan commentedComment #92
nicxvan commentedTook another look at #81.
On the trait:
\Drupal\Core\StringTranslation\StringTranslationTrait::getNumberOfPlurals().I think that is fine as is to be honest. It's a helper trait, if we wanted to deprecate it or clean it up I think that's a follow up.
On
At first this was pretty appealing, but the truth is while the formula and index are related they are different.
Keeping the logic separate is cleaner I think.
Comment #93
nicxvan commentedHad another look at:
I was concerned this might get called tons for certain pages, but then I reread 85.
I think it's fine to drop.
Do we want to explicitly deprecate calling reset with these keys? Or just wait for the generic reset deprecation?
Edit: I can't find evidence of calls to reset this, lets wait for the generic reset deprecation.
Re 85
I'll try to verify those findings later.
I took a very close look through this I think it's in a good state, I created several suggestions to update to 11.5.
Still waiting on a review of my comment additions.
Comment #94
berdir> I think that is fine as is to be honest. It's a helper trait, if we wanted to deprecate it or clean it up I think that's a follow up.
The point is that it has exactly the same problem as the origin of this issue. A hardcoded dependency on locale in Drupal\Core. In the same trait. So the question is whether we want to apply the same solution to it and add it to that new service I created, which for BC would be convenient to not require future updates.
But I think I'd prefer deprecating that. Beside the 3 calls in core, there are exactly 2 contrib projects that call the trait, various others already call the locale service. And that can be done in a separate issue.
> At first this was pretty appealing, but the truth is while the formula and index are related they are different.
Are they really? the index is the result of the formula after executing it and locale_get_plural() is the primary usage of it. I think if I would design this from the scratch I would absolutely put it on the same service, the only reason for me to not do it is that it would make this quite a bit more complex, with more deprecations and changes. 12 references of the string "locale.plural.formula" in core, 30 in contrib.
Comment #95
nicxvan commentedThat's pretty convincing, but like you said there is already a service for it, so let's just deprecate it for removal. I'm not sure we need a follow up to deprecate a single method with a service replacement that already exists.
Yes, but I mean LocalePluralFormula->getIndex doesn't quite feel right. I'm not sure it's worth combining.
Comment #96
berdir> I'm not sure we need a follow up to deprecate a single method with a service replacement that already exists.
I'd prefer a separate issue, in case there's disagreement on the direction, and it will need DI updates in a few places, a CR and so on.
Updated the CR. FWIW, there is exactly one call to this function in contrib, in a Drush 8 drush.inc file, so really nothing, it's not something anyone uses directly. So on the documention thread on the MR, keep in mind that people generally don't need to know the internals on this. They just need to know how to use \Drupal\Core\StringTranslation\StringTranslationTrait::formatPlural().
Comment #97
berdirCreated #3606700: Deprecate StringTranslationTrait::getNumberOfPlurals
Comment #98
nicxvan commentedI don't have a strong opinion on this, we can do it in the issue you created.
Yes, but I struggled to get to what piece was important without the context, if you have a better place for it please let me know.
I think structurally this is ready, I'll see if I can get another opinion on the docs.
Comment #99
nicxvan commentedI think this is ready, I've been through this many times.
The only open question is my contribution which are the two interface comments explaining what a plural formula and index are.
The service provider switch is pretty clever.
Comment #100
alexpottAdded a couple of comments - can go back to rtbc once addressed.
Re the discussion on the docs; I'm not sure.
Comment #101
berdirAddressed one review point, replied to the other.
Comment #102
alexpottI'm just working an alternate idea...
Comment #104
alexpottI propose that we allow things to access the plural index service from the translation manager... see https://git.drupalcode.org/project/drupal/-/merge_requests/16293
In fact we could go one step further and not introduce the service and just override the TranslationManager in the locale module which one remove one layer of service indirection.
Comment #105
alexpottSo the new MR I posted basically implements #22. Personally I think that replacing the translation manager service is neater than replacing a new service like the other MR and not really any different with respect to service chicanery.
@berdir brought up the idea of trying completely replace the concept of getting a plural index from core and leaving this to something the locale module implements by making count publicly accessible on \Drupal\Core\StringTranslation\PluralTranslatableMarkup - I got 90% of the way there. The trick is to make \Drupal\Core\StringTranslation\TranslationManager::translateString() return the string based on the count rather than a string of all the plural forms + the singular form delimited by the
\Drupal\Component\Gettext\PoItem::DELIMITERbut unfortunately this is very tricky (maybe impossible) due to \Drupal\Core\StringTranslation\PluralTranslatableMarkup::createFromTranslatedString() :(Comment #106
alexpottOkay I worked out a way to deal with
PluralTranslatableMarkup::createFromTranslatedString()and I've also chosen to leave whatTranslationManager::translateString()returns alone because I think changing that could cause problems with translation UIs. Posted yet-another-mr to show how this could work - see MR 16306Comment #108
alexpottLooking at the 3 MRs, for me the best change is 16293 - I personally like that the locale module takes over the translation manager to add the functionality - it feels correct. Core no longer has weird calls to locale code and doesn't have to add another service for locale to override like it does in MR 15789. Also I prefer it to MR 16306 because it feels a smaller API change - both add methods to the translation manager and involve locale taking over the service BUT this MR goes further in delegating responsibility to the translation manager - which I like - but because of
PluralTranslatableMarkup::createFromTranslatedString()we have to introduce PreTranslatedPluralTranslatableMarkup which I don't like... but in writing this sentence I release I have a way around that now :).Comment #109
alexpottSo I've removed
PreTranslatedPluralTranslatableMarkupfrom MR 16306.Now I prefer both MR 16293 and MR 16306 to the original MR. I think they are basically equivalent and a matter of taste. Do we prefer
\Drupal\Core\StringTranslation\TranslationManager::selectPluralForm()(MR 16306) or\Drupal\Core\StringTranslation\TranslationManager::getPluralIndex()(MR 16293).I'm not sure. Pros from MR 16306 include PluralTranslatableMarkup having less special code compared with TranslatableMarkup. Pros for MR 16293 is we maintain the locale_get_plural API - but that could also be considered a con as the API is not used and an internal feature of translation. The new API added by MR 16306 to select the plural form from a translated string with PoItem::DELIMITERs feels like a more useful API. But that is just a hunch.
Comment #110
needs-review-queue-bot commentedThe Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".
This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.
Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.
Comment #113
berdirI like MR 16306, closed my MR and added a few minor comments on the MR. All test fails on that are random I think.
Comment #114
nicxvan commentedRebased and addressed the two comments from @berdir, this should be ready for review again!
Comment #115
daffie commentedWorking on this.
Comment #116
daffie commentedWhat I have added:
- I have added support for float values. There was no testing for it and AFIAK it used to work. Translating something like: “1.5 hours”
- Deprecation testing for locale_get_plural()
- Improved PluralTranslatableMarkup::getArguments() a little bit + testing
Disclamer: I have used AI for these changes.
Comment #117
berdirIt's not clear to me if that is restoring existing behavior or adding something new.
The whole point of this feature is to support other plural forms. The display of 1.6 only works correctly because we short-circuit 1 there with a == 1, so only an exact 1 or 1.0 is true and uses the singular form. But if you have a language that makes a distinction between 2 and 3, I have no idea what the correct result would be for 2.9, if that's even defined or not. we would calculate it for 2.
I tested what happens on HEAD, and 1.5 kind of works but gives me PHP deprecation messages. a string works too and uses the plural form
so if the argument is BC, then I think we'd also need to not fail with a type error on the abc string, which I think this would do right now. and is also tested now. Not sure.
Comment #118
alexpottI think the BC argument is a good one. I think we should file a follow-up issue to discuss how we should support or even if we should support floats here - but preserving the current behaviour feels sound. I think the changes here mean we can revert the (int) cast in core/lib/Drupal/Core/StringTranslation/ByteSizeMarkup.php and the related test changes - which also prove the BC behaviour.
Comment #119
alexpott@berdir pointed out with this change passing 'a meaningless string' to $count results in an error. I've checked is you don't have strict types on in the calling code you can pass a string that looks like a number ie '1' or '100' and boolean and the right thing happens. So I think this new behaviour is fine.
Comment #120
nicxvan commentedI reverted the int cast and fixed the one test, I think this is ready again.
Comment #121
berdirI think this looks good now. I worked on this issue as well, but a different MR that was rather different. Only some minor bits survived of my work, such as the removal of the static caching of the plural index calcuation, which is basic math and I have no idea why we had that.
Happy to RTBC this now, but the issue summary and CR definitely needs work, that's still from me for the version I did. There is no direct replacement now, the public APIs that people should use haven't changed, only mostly internal stuff. There's selectPluralForm now, but I don't think anything is supposed to be calling that directly. So I'd just write something along the along the lines of the internal function being deprecated and that nothing changes for how plural translations works.
Comment #122
berdirI also created #3620752: Refine and possibly deprecate whether or not plural translations should support float/non-integer values as a follow-up.
Comment #123
alexpottComment #124
nicxvan commentedComment #125
nicxvan commentedComment #126
berdirI think this is ready now.
I worked on a version of this as well, but this is now very different. I think only the removal of the static cache is left of my work. It's called a few times at most and only contains basic math.
There is a single call to this function in contrib and that is old drush 8 code
Comment #127
claudiu.cristeaRecently we hit this issue in our project and I'm not sure this refactoring is aware of: #3620921: Numeric views field passes the formatted value as the plural count, triggering a warning
Comment #128
berdir@claudiu.cristea: Yes, there's no longer a warning with this change, float is explicitly allowed and tested for BC, see the follow-up in #122 which is to discuss whether or not that makes sense and if it should be deprecated.
Comment #129
godotislateComments on the MR.
Also, are the
Needs issue summary updateandNeeds change recordtags current?Comment #130
nicxvan commentedThose tags are outdated, I removed them.
I addressed most of your feedback, one is still open.
Comment #131
nicxvan commentedI added
DependencySerializationTraitback, some views tests were failing without it.NumericFormatPluralTestTranslatedViewTestI addressed the remaining feedback, this should be ready!
Failures look random.
Comment #132
berdirOne minor thing.
Comment #133
berdirBack to RTBC. I'm not sure if the parameter order and it being required was deliberate. I think this makes more sense, but it doesn't make much difference, there's just one call to it and it has to provide a value anyway due to the options array thing.
The serialization trait is a bit weird, seems like a bug and it should possibly be applied higher up in the chain, that would be more efficient, but might result in changes that could be out of scope? I can dig into those tests if you'd prefer that.
Comment #134
godotislateI was going to look into it myself later just to see what is going on but as you say, making any changes could be out of scope. If you don't mind digging in, please do.
Comment #135
berdirThe error is triggered by \Drupal\views_ui\ViewUI::cacheSet, and it's the ViewUi object itself that has stringTranslation property set. Adding the trait to that fixes the failing tests, but there's a lot more being serialized there, the executable could possibly also get the trait.
From a BC perspective, since we alter a service that is extremely often injected into all kinds of things through StringTranslationTrait, I would suggest we keep the trait, because we otherwise make a currently serializable service non-serializable (it fails on the database service, probably through formula service an then state).
But we could open a separate issue to add the trait to ViewUi and ViewExecutable, that should slim down the size of those objects quite a bit. There might also be more we can do. It unsets a bunch of plugins, but not row and style plugins for example, which then again reference those.
Comment #136
godotislateThanks for looking into it.
Agreed about leaving the trait in the service here, and doing a follow up for views objects.
Comment #137
berdirI created #3621842: Optimize serialization of ViewUi and ViewsExecutable objects
Comment #139
godotislateCommitted 0c13239 and pushed to main. Thanks!
Conflicts in 11.x (see below), will need separate MR. Will hold off publishing CR until backport is in.
Comment #141
berdirYeah, backport was a bit rough, between mock/stub and the types, tets differ a lot in main and 11.x Only conflicted on unit tests though, I diffed the two commits and nothing stood out, if it passes phpcs/phpstan and tests then I guess it should be ok.
In most cases, I tried to keep the previous context and the mocks, one thing that I changed a bit was TranslationManagerTest::testFormatPlural, there I kept the types as in main.
Comment #142
berdir> and tests then I guess it should be ok.
580 test fails had me concerned for a second, but it was all a single unit test with 580 different variations, one that no longer exists in main.
Comment #143
oily commentededited: Read the issue. Seems current phase began at #26.
Re: #141 and #142 I read through code in MR!17050. It all seems consistent and logical; spotted no typos.
In #87 nicxvan refers to 'plural formulas'. The expression 'plural formula' seems less ambiguous and confusing than 'plural form'. There are a number of usages of 'plural form' in MR!17050 not to mention the main MR.
The only solution might be to coin a new word e.g. 'morph' so 'plural morph' that obviously has nothing to do with forms or formulas. Supply an explanation of the term in necessary places in core/ docs.
With that cavil I am changing the MR to RTBTC.
Comment #144
oily commentedComment #145
oily commentedLooking up an online thesaurus I found these alternative words for plural 'form': 'embodiment', 'manifestation' and 'incarnation'. 'morph' still seems best alternative, if anyone else thinks one would be useful.
Comment #146
nicxvan commentedI reviewed the backport MR, looks great! The main changes I saw were in line with 141 and 142 including the tests in modules that have been removed from 12 already.
For 143 and 145, I don't think we need to introduce new terminology. Plural forms and plural formulas are the standard and we have comments outlining what they mean with links to further documentation.
Comment #147
oily commented#146 +1
Comment #149
godotislateCommitted b3d8bfe and pushed to 11.x. Thanks! Published the CR.
Comment #151
grimreaperHi,
On 11.x: https://git.drupalcode.org/project/drupal/-/jobs/12091552
Comment #153
godotislateSorry, missed two new files in the original 11.x commit.
Comment #154
grimreaperThanks for the quick fix!