Multilingual nodes in Drupal 6 raise challenges for voting. Say there are French, English, and Japanese versions of a given piece of content. Should votes on that content be separate, or should they be tallied for the translation set as a whole?

Both of these approaches might be desired.

The attached patch introduces the option of having all votes for multilingual content read from and assigned to the "source" translation--the original node from which translations were made. (For some background, see this section in the Drupal module developers handbook:

http://drupal.org/node/303984

particularly the subpage on working with multilingual content.

To avoid each voting module implementing its own selection for translation behaviour, it would be useful to have something built into Voting API--not to actually handle multilingual voting, but to provide options that voting modules can respect. So this patch relies on a small patch to Voting API in #306567: Handle multilingual content. The patch is here:

http://drupal.org/node/306567#comment-1007007

CommentFileSizeAuthor
#10 fivestar.patch1.13 KBmr.j
#12 fivestar.patch1.13 KBmr.j
#1 fivestar-translation.diff2.24 KBnedjo
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

nedjo’s picture

FileSize
2.24 KB

Patch.

nedjo’s picture

Status: Needs review » Active

Issue #306567: Handle multilingual content is under active discussion. Setting this patch back to active, since it makes sense to get some consensus on the general Voting API approach before implementing particular voting solutions.

nedjo’s picture

Assigned: Unassigned » nedjo
Status: Active » Needs review

The issue on Voting API is wending its way towards resolution. Reviews of this issue would help, so setting it back to code needs review.

nedjo’s picture

Major remaining issues are:

1. Handling of tnid changes. I've put this in a handbook page: http://drupal.org/node/304047#handling-by-tnid. At CivicActions we're sketching out a helper module to facilitate this and other common needs for working with multilingual content. The basic idea:

We provide a method that other modules can call or else a hook they can implement. Maybe the latter is better. Something like:


/**
 * Implementation of hook_nodeapi().
 *
 * Manages translation information for nodes.
 */
function translation_helpers_nodeapi(&$node, $op, $teaser, $page) {
  // Only act if we are dealing with a content type supporting translations.
  if (translation_supported_type($node->type) && $op == 'delete') {
    translation_helpers_remove_from_set($node);
  }
}

/**
 * Call hook_translation_source_change() to respond to a change in
source translation.
 *
 * Follows logic in translation_remove_from_set().
 */
function translation_helpers_remove_from_set($node) {
  if (isset($node->tnid)) {
    if (db_result(db_query('SELECT COUNT(*) FROM {node} WHERE tnid =
%d', $node->tnid)) <= 2) {
      // There would only be one node left in the set: remove the set altogether.
      module_invoke_all('translation_source_change', $node->tnid, 0);
    }
    elseif ($node->tnid == $node->nid) {
      $new_tnid = db_result(db_query('SELECT nid FROM {node} WHERE tnid = %d  ORDER BY translate ASC, nid ASC', $node->tnid));
      module_invoke_all('translation_source_change', $node->tnid,
$new_tnid);
    }
  }
}

Then modules could respond to this hook and make their updates--in this case, change the existing votes.


hook_translation_source_change($old_tnid, $new_tnid) {

}


2. Whether and how to handle changes between "use tnid" to "use nid".

Here it's seeming to me that, in general, we need multiple voting parameters. Whether voting applies to a translation set or to an individual translation depends on what we're voting on. If we have multiple fivestar parameters for a given node type, some of them might suitably be per translation ("rate the quality of this translation" or "how good are these song lyrics (in this language)?", while others will be suitably handled by translation set.

So we can't really use a blanket "use one or the other always" setting. Rather - like is being suggested with flag module and nodequeue - this would be a setting for individual voting parameters. This assumes, however, multiple parameters.

And it assumes you can't change once you've created a parameter. Or, at least, you can't change from "use tnid" "use nid", because you won't have the needed data.

eaton’s picture

Here it's seeming to me that, in general, we need multiple voting parameters. Whether voting applies to a translation set or to an individual translation depends on what we're voting on. If we have multiple fivestar parameters for a given node type, some of them might suitably be per translation ("rate the quality of this translation" or "how good are these song lyrics (in this language)?", while others will be suitably handled by translation set.

So we can't really use a blanket "use one or the other always" setting. Rather - like is being suggested with flag module and nodequeue - this would be a setting for individual voting parameters. This assumes, however, multiple parameters.

And it assumes you can't change once you've created a parameter. Or, at least, you can't change from "use tnid" "use nid", because you won't have the needed data.

I've put a solution in place for VotingAPI RC2. While it's not perfect, I think it will work well. if a vote's content type is 'node' it will be assumed that content_id means 'nid'. If the content type is 'translation_set', it's assumed that its content_id means 'tnid'. This, as noted above, requires modules to explicitly migrate existing votes to a new set of content_id/content_type combinations if a site is being converted to multilingual.

But -- and here's the biggie -- making translation_set votes and 'raw node' votes explicit allows us to combine those kinds of votes on one site without compromises. VotingAPI is also capable of automatically adding the translation_set relationship if content_translation module is enabled -- making it just as easy to put together views based on cross-language votes.

Admittedly, this puts the burden on modules that do the vote-casting: they're in the best position to know whether the vote being cast is on a node that's translation aware, if it should be "translation agnostic", etc.

Another possibility is to continue casting votes on 'node', but to always use the 'tnid' as the content_id; in that case, the 'Source node' relationship could be used to connect a given translated node to its source node, and a votingapi relationship could be added on the end of THAT relationship's related node.

catch’s picture

Subscribing to this so I can review later on.

nedjo’s picture

I'm working on a version of this patch using Eaton's new voting content type.

Proposed implementation:

* Admin UI to set default voting content type per 'tag' type (vote, etc.).
* Admin UI to override this default at the node type level, again per 'tag' type.

So there is a default for 'vote' and then the ability to refine this per node type.

nedjo’s picture

Status: Needs review » Needs work
nedjo’s picture

I opened #334138: Configurable voting axes. I'll work up a patch here that depends on a patch for that issue.

mr.j’s picture

Status: Postponed » Needs work
FileSize
1.13 KB

Here is a quick, dirty patch that works for me against 5.x branch of fivestar, for anyone else who might be looking for this. It forces all votes to be cast and read against the node with the lowest nid within a trid set ($node->tnid does not exist on 5.x). This makes the assumption that the lowest nid in the set will be the first node created and thus the "source" node.

There are a few caveats with this approach that I can see:
- if you delete the first node in the set then all your votes might be lost (untested)
- views don't return any values when viewing in a language that does not have votes cast to them (requires mods to votingapi as mentioned by Eaton above). We get around this by calling votingapi_get_voting_result() using the correct nid, then theme('fivestar_static' ...) directly inside a .tpl file that modifies the view output.

This patch has a bug - get the fixed one below in #12

nedjo’s picture

Status: Needs work » Postponed

Waiting on #317317: Rate on multiple axis with admin UI, which in turn is waiting on #335668: Add system for registering voting tags (axes).

When we have multiple voting axes fully implemented, we can enable multilingual support per voging axis (tag).

mr.j’s picture

FileSize
1.13 KB

Small fix to my patch at #10 above. It ensures the right node is selected when you have a translation set with only a single node in it. In that case trid = 0, and it was selecting the first node with trid = 0 which erroneously includes all nodes with a language set but no translations.

eaton’s picture

Status: Needs work » Postponed

Apologies for taking so long to respond to this -- I have been watching and have been thinking hard about it.

I'm in favor of modules providing metadata about the types, tags, and voing styles that they manage. I agree that it's difficult for modules to do crazy stuff without clobbering each other now, in part because they can't find out about each other.

I don't support the idea that votingapi itself should have a UI for adding and managing all of these things. The nature of the tags and content types system is such that modules can use them in very different ways, with very different meanings. If they can auto-discover each others' tags etc, why should VotingAPI be asked to provide a UI that works for every possible use of the tag/content_type set? I worry that it would be nothing more than a raw from end for database table editing...

halfabrain’s picture

Dear Nedjo, Eaton et al,

I tracked down this thread through google. Thank you for all the time you are putting into this. I am new to Drupal and unfortunately not technically savvy enough to amend this on my own. I have tried installing Nedjo's patches but received the error on fivestar - 'can't find file to patch on line 25'. I took the liberty of re-naming the file line to be the latest version of fivestar ( 1.13.2.67) but instead received the error:

Hunk #1 FAILED at 137
Hunk #2 FAILED at 945.
2 out of 2 hunks failed...

Please can you tell me if you have progressed with these patches since Dec 08 or if I am attempting to install them incorrectly?

Also, for what it's worth, I have been thinking about how I personally think fivestar would work best; it seems to me that for multi-lingual sites, the comments and the fivestar ratings do not need to be stored with each language node; but could be stored seperately. So for instance, a site running Spanish and English may have a restaurant that has been reviewed. The review is in English but with the option of being translated into Spanish. The fivestar ratings and all the comments are stored seperately to the language review nodes that are being translated but associated to both translations, so regardless of the translated review above it, the comments are always the same.

This should then get past the problem of having to aggregate ratings from seperate translated nodes, plus the difficulties associated with deleting comments.

However, I don't know if this makes sense - I hope so...! I also don't know if this is possible so please forgive my tecnical inabilites if what I've said is total nonsense!

Thanks again for all your work on this and I look forward to seeing where this ends up.
Best regards, Rob (aka halfabrain)

volocuga’s picture

mr.j : The patch you presented (#12) works good on a node,but when I try to display fivestar widget using Views (table view) its value doesnt change.

mr.j’s picture

Yes, re-read #10.

halfabrain’s picture

Dear all

Please can someone reply to my previous comment #14? Even if just to say that there is nothing they can do, or perhaps that they are working on it?
Thanks

H

volocuga’s picture

eaton: Do you have a similar solution for drupal 5 (about #5)?

Thanks!

Anonymous’s picture

@halfabrain: I don't know enough to help you out with your problem. I'd suggest that you try applying the patch manually. Your posts suggests that you tried automatic installation of the patch.

@nedjo: Thanks for the patch. Works fine for me!

Taxoman’s picture

Version: 6.x-1.x-dev » 7.x-2.x-dev
ericduran’s picture

Version: 7.x-2.x-dev » 6.x-2.x-dev

Moving back t 6.x There's already a path here that might work.

tnfno’s picture

The patch mentioned by ericduran in the header seems to be from a different version. The 6.x of votingapi no longer has this function in the votingapi.module, but I can find it in votingapi.admin.inc. Has anyone successfully applied it to a 6.x installation, I have tried to do it manually but with no success.

vasrush’s picture

Looking for a solution on 6, too

adelka’s picture

Maybe I am in bad thread, but is there any solution for drupal 7.x?

rockNroll00q’s picture

Is there a solution for 7.x?

estebant’s picture

Issue summary: View changes

I found the following solution for D7:

1.- Install the modules "Rules" and "Voting Rules"
https://www.drupal.org/project/rules
https://www.drupal.org/project/voting_rules

2.- Create a new rule with the event "User votes on a Node"

3.- Add action: "Execute custom PHP code"

4.- Copy this code, that will create/update the rows corresponding to the translation(s) of the node voted.

$resultNID = db_query("SELECT nid FROM {node} WHERE tnid=" . $node->tnid);
if($resultNID) {
    foreach ($resultNID as $recordNID) {
        if($recordNID->nid != $node->nid) {
            $resultVoteExists = db_query("SELECT entity_id FROM {votingapi_vote} WHERE entity_id=" . $recordNID->nid . " AND uid=" . $vote['uid'] . " LIMIT 1");
            if($resultVoteExists) {
                $exists = false;
                foreach ($resultVoteExists as $recordVoteExists) {
                    $exists = true;
                    break;
                }
                if($exists) {
                    db_update('votingapi_vote')->fields(array(
                      'value' => $vote['value'],
                      'timestamp' => time()
                    ))->condition('entity_id', $recordNID->nid, '=')->condition('uid', $vote['uid'], '=')->execute();
                } else {
                    db_insert('votingapi_vote')->fields(array(
                      'entity_type' => 'node',
                      'entity_id' => $recordNID->nid,
                      'value' => $vote['value'],
                      'value_type' => 'percent',
                      'tag' => 'vote',
                      'uid' => $vote['uid'],
                      'timestamp' => time(),
                      'vote_source' => '::1'
                    ))->execute();
                }
            }
        }
    }
}
Naomi79’s picture

Thank you Estebant, I confirm your solution works perfectly for D7. Quick and easy !

estebant’s picture

Good to know Naomi, thanks! :)

kbell_paris’s picture

Hi Estebant,
Thanks for posting a D7 solution. I'm trying to implement it but when I get to step 3, "add an action", I don't have the option "execute custom php code" showing. I've got a bunch of data setting options which look promising, then a bunch of other stuff. Could the naming the dropping list have changed? Just installed Rules and Voting Rules today.

thanks so much for any advice you might have.

estebant’s picture

The solution:
https://www.drupal.org/node/964494
=> Enable PHP filter module

whiteph’s picture

Status: Postponed » Closed (won't fix)

Sorry, Drupal 6 is end of life, and is no longer supported.