Download & Extend

Content types should declare a plural form of their name

Project:Drupal core
Version:8.x-dev
Component:node system
Category:feature request
Priority:normal
Assigned:Unassigned
Status:needs work
Issue tags:D8MI

Issue Summary

Some pages might want to show lists of books, or blog entries, etc. We have a name for each node, but a plural equivalent. These plurals ought to be declared in english in the module, and available for translation as usual. Or perhaps there is some other better way to do this.

Comments

#1

I agree. This is important for usability for my node-to-node associations module. Also, perhaps the
hook_node_name
function should take a second argument which specifies "singular" [default] or "plural".

Also, I guess flexinode would have to support this w/ an additional field on its node types config form?

#2

hook_node_name is ancient past :) however it is entirely possible to add a 'plural' key to hook_node_info.

#3

I agree with chx. The question is: Is one plural form enough for every language. Or do certain languages need more than one?

#4

This may not handle languages with plural form properly, but I propose the pattern below. Note the format_plural() use ... Comments welcome

<?php
function blog_node_info() {
  return array(
'blog' => array('name' => format_plural(%count, 'blog entry', 'blog entries'), 'base' => 'blog'));
}
?>

#5

I don't quite understand how this would work within a module- would this require changes to existing code? How about a something like this:

<?php
function blog_node_info($count=-1) {
  if (
$count < 0) {
    return array(
'blog' => array('name' => t('blog entry'), 'base' => 'blog'));
  }
  else {
    return array(
'blog' => array('name' => format_plural($count, 'blog entry', 'blog entries'), 'base' => 'blog'));
  }
}
?>

#6

format_plural already handles the switch that you are introducing. see its definition

#7

Title:Node modules should declarare a plural form of their name» Node modules should declare a plural form of their name

Ok, I'm staring at http://api.drupal.org/api/4.7/function/format_plural

Here are some uses of it in existing modules:

poll.module:
format_plural($node->votes, '1 vote', '%count votes')
comment.module:
format_plural($all, '1 comment', '%count comments')

Where do you envision this new feature of hook_node_info being used?

Maybe the code needs to be something like:

<?php
function blog_node_info() {
  return array(
'blog' => array(('name' => t('blog entry'), 'base' => 'blog', 'singular' => '1 blog entry', 'plural' => '%count blog entries'); 
}
?>

And then there could be an additional function in node.module that would return a translated string for an enumerated number of nodes of type. This could follow the pattern of node_get_types(), node_get_name($node), etc. that use the _node_names($op = '', $node = NULL). So, essentially, this would require an additional two $op values for _node_names.

<?php
function node_get_enumerated_names($count, $node){
  return
format_plural($count,_node_names('singular',$node),_node_names('plural',$node));
}
?>

and where we change the latter part of _node_names to be:

  switch ($op) {
    case 'base':
      return $node_names[$type]['base'];
    case 'list':
      return $node_list;
    case 'name':
      return $node_list[$type];
    case 'singular':
      return $node_names[$type]['singular'];
    case 'plural':
      return $node_names[$type]['plural'];
  }

(of course, putting in some code to take care of modules that don't define 'singular' or 'plural' might be a good idea too)

#8

Oops. My pseudocode was unclear. I added a param to the function. Hopefully this is clear:

<?php
function blog_node_info($count = 1) {
  return array(
'blog' => array('name' => format_plural($count, 'blog entry', 'blog entries'), 'base' => 'blog'));
}
?>

#9

Will your prototype work as a drop-in replacement for the current function? One does not always want an enumerated name. For example, the list of node types at /node/add. I think your code would give mean I'd see the option to create "1 book page" or "1 forum topic".

Also, the function _node_names() caches the results of calls to hook_node_info in a static array.

#10

The problem with format_plural is that it requires the %count parameter in order to work for multiple plural forms that some languages have. However, we'd don't want the count parameter in the final output.

An idea would be to do the following:

<?php
function blog_node_info($count = -1) {
  if (
$count < 0) {
    return array(
'blog' => array('name' => t('blog entry'), 'base' => 'blog'));
  }
  else {
    return array(
'blog' => array('name' => strtr(format_plural($count, 'blog entry', '%count blog entries'), $count, ''), 'base' => 'blog'));
  }
}
?>

This would remove the number from the output.

#11

Are there any modules now that directly use hook_node_info()? In node.module, this hook is used only to get the information into the _node_names() function and through that to the various "public" functions like node_get_name().

No where in the core modules (that I can find) is hook_node_info() invoked except in _node_names(). In contrast, node_get_name() is frequently used (e.g. taxonomy.module, tracker.module, etc).

The scheme I suggest in #7 essentially follows the logic currently used in node.module and extends it in a way that I think is more consistent with the current API and usage.

#12

Status:active» needs review

patch attached that exactly implements my suggestion above. Works fine with Drupal CVS, PHP 4.4.2, MySQL 4.1.19.

The function name "node_get_enumerated_names" seems a little too long/inobvious. Any other suggestions?

simple test code:

<h2>My site has the following content:</h2>

<?php
$types
= node_get_types();
foreach (
$types as $type => $name ){
 
$result= db_query("SELECT n.nid FROM {node} n WHERE n.type = '%s'",$type);
 
$count=db_num_rows($result);
  print
node_get_enumerated_names($count, $type)."<br />";
}
?>
AttachmentSizeStatusTest resultOperations
pl_node_names_patch_0.txt4.07 KBIgnored: Check issue status.NoneNone

#13

Or, as an option to avoid adding another "public" function to node.module, one could use the rest of my patch and rewrite node_get_name as:

<?php
function node_get_name($node, $count = -1) {
  if (
$count < 0) {
    return
_node_names('name', $node);
  }
  else {
    return
format_plural($count,_node_names('singular',$node),_node_names('plural',$node));
  }
}
?>

#14

I was already in need of this functionality before on a Hungarian site, and solved it with a hack, so I would prefer a nice solution myself too :) Looked at the patch in #12.

First I would prefer not adding another function, but modifying node_get_name() as showed in #13. Otherwise I have a hard time thinking of a better solution. The node_name() hook should be the place to specify this piece, but this information is cached, and plurals could end up in any number of strings depending on the language, so the $count parameter is needed to identify the right translation in the system (and so the number should be in the output, as the translated version is only valid for that exact number).

There is no general plural translation of a string, which could be used, or at least not one we can get through format_plural(). If you also need a generic plural version, stripping the number off is not a good solution, but another field should be introduced which provides the cacheable t('stories'), t('book pages'), t('forum topics') generic plural version, for wihich the translators need to come up with some translation.

Look at the Polish translation for example, which has three plural versions, with a quite complex formula: Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);

msgid "1 new comment"
msgid_plural "%count new comments"
msgstr[0] "1 nowa odpowiedź"
msgstr[1] "%count nowe odpowiedzi"
msgstr[2] "%count nowych odpowiedzi"

BTW the -1 special parameter is not used in Drupal, but NULL should be used for testing a missing parameter:

<?php
function node_get_name($node, $count = NULL) {
  if (!isset(
$count)) {
    return
_node_names('name', $node);
  }
  else {
    return
format_plural($count,_node_names('singular',$node),_node_names('plural',$node));
  }
}
?>

#15

Status:needs review» needs work

#16

@Goba - i see that you are not satisfied with the last patch here, but can you suggest an alternative? i could not work out a proposal from your post.

#17

@moshe - I took the only essential criticism/suggestion as replacing the -1 with NULL, which is easily done.

#18

I also posed a question, whether you need general plural versions t('stories'), t('book pages') and such without numbers. The current patch is only useable if you intend to have a specific number with the pluraled node name. Note that even if you have a generic plural version, you should not use it in sentences, like t('update these %nodenames', array('%nodenames', t('stories)), since different languages have different versions of the plural word depending on what sentence and position it gets into.

#19

@Goba - my use case for this patch was primalily for lists/tables of conent were a specific number would be indicated.

#20

@pwolanin: OK, I think after fixing the -1 to NULL issue I noted this seems to be a good solution for the problem. Maybe this should be coupled with a generic plural form specification too, where nodes can specify t('stories') and such. I mean another key to node_info (wrapped only for easy reading):

<?php
return array(
 
'story' => array('name' => t('story'), 'base' => 'story',
 
'plural-1' => '1 story', 'plural-count' => '%count stories', 'plural-generic' => t('stories'))
);
?>

#21

Status:needs work» needs review

Patch updated for latest HEAD, and using node_get_name() as the interface as per above, modified so $count=NULL is the default 2nd parameter.

sample code:

<?php
$types
= node_get_types();
foreach (
$types as $type => $name ){
 
$result= db_query("SELECT n.nid FROM {node} n WHERE n.type = '%s'",$type);
 
$count=db_num_rows($result);
  print
node_get_name($type,$count)."<br />";
}
?>
AttachmentSizeStatusTest resultOperations
pl_node_names_patch_21.txt5.46 KBIgnored: Check issue status.NoneNone

#22

The CCK in core patch will have a big effect on the nature of this patch, once it gets committed. Personally, I would definitely like to see this patch get in after the CCK patch has landed.

I think that we should be adding 'name_plural', as an element in the array returned by hook_node_info(), and as an extra field in the new 'node_type' DB table that will be introduced with the CCK patch. This will mean that modules will be able to access the singular and the plural name of a node type very easily, using code such as this:

<?php
$type
= node_get_types('type', $node);
$msg = t('You are looking at %count %type nodes right now.',
array(
'%count' => $count, '%type' => theme('placeholder',
format_plural($count, $type->name, $type->name_plural))));
?>

format_plural() should not be used in hook_node_info or in node_get_types(), IMO. Modules can make use of this function directly when they wish to actually prepare text for presentation, if need be. What they should be provided with is simply the raw singular and plural strings of the node type name.

Also note that with the CCK patch going in, translation of (singular or plural) node type names will not be an issue, as the names of all node types will be editable by the site admin.

#23

I haven't been following the CCK patch closely- this patch can certainly be postponed. I assume that module-defined node types will still be supported?

Also, part of my goal with the way I structured the patch above was to minimize the effect on the API.

#24

Jaza, your expectations on format_plural() usage are not right. Format_plural does return a string with a number in it, which is put in place where it is sufficient in the given language (maybe at the beginning, middle or end). This also means that format_plural() is used with a first param which contains '1 thing' and a second param which contains '%count things'. The node name is not directly reuseable here.

<?php
// ! Node_get_types accepts no parameters, and returns an array, not object
$type = node_get_types('type', $node);
// ! Count should be generated into the string by format_plural.
$msg = t('You are looking at %count %type nodes right now.',
array(
'%count' => $count, '%type' => theme('placeholder',
format_plural($count, $type->name, $type->name_plural))));
?>

Maybe you can provide a better usage example, which helps us understand your intentions?

#25

Ok, I'm a little puzzled now as to how to proceed now that the new content system is in core.

Seems like this would require 2 (or 3) additional columns in the node_type table?

Also, this function seems to need work:

http://api.drupal.org/api/HEAD/function/_node_types_build

Unless I'm wrong, a module-defined type will never have its machine-readable type changed, right? So a lot of this seems redundent and dating to before the story and page modules were removed as separate entities.

#26

Status:needs review» needs work

setting back to "needs work". I think both this patch, and some of the related node functions.

#27

@pwolanin:

Unless I'm wrong, a module-defined type will never have its machine-readable type changed, right?

The CCK patch made it so that module-defined types can't have their machine-readable type name changed by default. However, such types can still override the default behaviour, and can allow their machine-readable type name to be changed. The stuff in _node_types_build() remains in there to support that.

Anyway, this is off-topic - if you find bugs with the new node type system, please file them as separate issues. ;-)

#28

Ok, fundamentally I think after the CCK patch having plural verions defined requires extra node_type DB columns since any custom or user-modified type must be able to have the user define the plural forms as well. Is this correct?

#29

yes, i would think so since simple node types are purely defined in the database ... i haven't looked much into new node system though

#30

Version:x.y.z» 6.x-dev

@pwolanin - any chance you will get back to this?

@gabor - has the new language system changed anything relevant to this patch? i don't think so, but just checking.

#31

Nothing changed in core to make this either easier or harder.

#32

I'll take another look

#33

Version:6.x-dev» 7.x-dev
Priority:normal» critical

#34

bump. anyone?

#35

i think this needs some comment from Gabor - any user-defined types would require i18n for translation, right? Is a single plural form sufficient?

#36

Title:Node modules should declare a plural form of their name» Content types should declare a plural form of their name

Update title for the modern Drupal. Yes, I think we can assume that a number is going along with the plural name.

#37

Adding an older patch I wrote for a (mostly duplicate) issue at #300801: Collect the plural name of content types. Patch needs updating.

AttachmentSizeStatusTest resultOperations
content_type_plural.patch5.05 KBIgnored: Check issue status.NoneNone

#38

subscribe

#39

Version:7.x-dev» 8.x-dev
Priority:critical» normal

#40

Subscribe. Would be really nice for Views / SimpleViews, so you could build UIs that say something like "Show [published articles] tagged with [term1] sorted by [newest first]", where each bracket represents a drop-down. I guess, currently, our guidelines dictate that it would need to be "Show [published article content] tagged with [term1] sorted by [newest first]", which isn't quite as nice.

#41

To add another use case: I am needing this to build a Wordpress-type content overview dashboard block that displays "5 articles, 6 basic pages, 2 webforms, ...".

#42

Tagging this as an issue for the Snowman project for D8. The ability to cleanly generate things like listing pages, blocks, and other UI help for content types relies on having sensible pluralization.

#43

lala

#44

Unfortunately, depending on the language of the site, the "a plural" form would not be enough. Many languages define multiple plural forms depending on the number of items. You can look for some examples in the Polish Drupal translation let's say: http://localize.drupal.org/translate/languages/pl/translate?project=&sta...

You'll find pieces like "1 invitation sent" / "@count invitations sent" have different translations depending on the number of @count:

  • Wysłano 1 zaproszenie.
  • Wysłano @count zaproszenia.
  • Wysłano @count zaproszeń.

So for many languages, there is not one but multiple plural forms for a singular form and which one to use depends on the number of items. (When the number of items is available). We should only be able to get away with one plural vatiant input for this, if we never use it at places where the number of items is known, which will be very tempting I think... (such as "@count $nodes were deleted", where $nodes would be the plural version of the type).

You can find rules for how plurals are selected from multiple variants for different languages at http://translate.sourceforge.net/wiki/l10n/pluralforms. You'll see Irish has 5 different variants, Arabic has 6 (all include the singular form).

#45

So for many languages, there is not one but multiple plural forms for a singular form and which one to use depends on the number of items. (When the number of items is available). We should only be able to get away with one plural vatiant input for this, if we never use it at places where the number of items is known, which will be very tempting I think... (such as "@count $nodes were deleted", where $nodes would be the plural version of the type).

Just out of curiosity (and because I'm shameless in the particular use case I'm thinking of this for), would text like "Recent articles" be affected by the problems you describe? Or is it just in places where there is a discrete number of things being referred to?

#46

In other words, the number of input fields and the rules of which value to use should "ideally" be language dependent on the node type configuration then. If you have an Irish site, you'd have 4 plural fields (on top of the 1 singular) and the system would know the rules to use for them when the data is requested. The "language the site is in", "how many fields are needed" and "what rules to follow to pick the right one" are all data managed by locale module, and currently all configuration is assumed to be in the default language (language_default()). If your default language is not English, we can assume you have locale module enabled practically (you probably also use interface translation), in which case all this data is available to Drupal. However, this is user configuration and not to be stored in the interface localization database. Our discussion above in 2006 about using format_plural() dated back to when node types were defined by hooks, not by a UI, so you could wire in the English defaults to your code.

Now this issue is about providing a UI for something that potentially needs to be different based on the configuration language (site default language) being used. Date formats have a one-off special implementation for this in Drupal 7, but no other configuration component has similar support. I believe instead of coming up with yet another one-off solution here, it would like the best idea to keep this on hold until we have the Drupal 8 configuration management storage and retrieval system, which should support variants based on language or other factors natively, making one-off hacks unnecessary.

#47

@eaton: to my best knowledge it is problematic at places only where we know the number of things referred to. And I can easily see this can propel into uses in those areas after it lands :|

#48

@eaton: to my best knowledge it is problematic at places only where we know the number of things referred to. And I can easily see this can propel into uses in those areas after it lands :|

Sigh.

Yeah, I can definitely see that being a problem... Once the plural form exists, it'd probably be impossible to keep people from misusing it unknowingly. On the other hand, is it possible to construct reasonably correct grammar using the current system? The UX implications of always saying, "article content" instead of "articles" makes my heart heavy. Hrm.

#49

sub

#50

Suppose this should be related to CMI translation. For D8 we have improved plural storage but node-name is out of scope of interface translation

nobody click here