Translating or internationalizing an Ubercart store: Common problems & solutions

Although Drupal 6 handles node translation with the i18n module very well, Ubercart seems to have a bit of difficulty with it. I believe that most of the problems are due to the nature of translated nodes, which are actually completely different nodes that are glued together with some metadata. This fact, for example, is the reason Ubercart will a product translation as a new product separate from the original.

As I tried to setup a multi-lingual store (English/French) store with Ubercart, I encountered many problems that seemed to be all over Google, but had no resolution posted or the solutions to the problems were fragmented across different sites and support threads. So after a lot of searching, reading PHP backtraces and hacking the Ubercart core modules, I was finally able to have a good Ubercart catalog set up in two languages! I've compiled a list of problems and their solutions below if you are also having problems. Feel free to use any part or all of the code samples on your site.

Note: The code in this tutorial has been confirmed to work with Ubercart 2.2. It should also work with future versions, but may require some minor tweaks.

Problem: "add to cart" and other form buttons need to be translated

Ubercart handles form button texts like "add to cart" via multi-lingual variables. Multi-lingual variables differ from strings that use Drupal's t() function in that they will not appear in the site's Translate Interface utility. Instead, multi-lingual store a value for each of the site's languages and load the appropriate string depending on which language the user is currently browsing in.

In the case of "add to cart", this simply means that one must browse to Administer > Store Administration > Configuration > Product Settings and click on the Edit button. Switch the site language to the desired language and enter new values in the "Add to cart button text" configuration box. Once the values have been saved, you will be able to switch to a different language and enter new values for that language.

Problem: Ubercart does not synchronize product data across translated nodes (product information needs to be updated for each translation)

As I mentioned in the introduction, this is due to the fact that each translation is in fact a node to itself. Since Drupal assigns each node with content type "product" the standard Ubercart attribute set, each product node must be updated individually. Fortunately, there is a quick and easy was to solve this by creating a custom module:

  1. Enable the i18nsync ("Synchronize Translations") module in Administer > Site building > Modules
  2. Create a custom module which will hook into i18nsync:
    1. Create the folder sites/all/modules/custommod
    2. Paste the following into sites/all/modules/custommod/custommod.info:
      name = Custom module
      description = A custom module which helps with the translation of an Ubercart store
      core = 6.x
    3. Paste into sites/all/modules/custommod/custommod.module:
      <?php
      /**
        * Implementation of hook_i18nsync_fields_alter().
        */
      function custommod_i18nsync_fields_alter($fields, $type) {
        if(
      in_array($type, uc_product_types())) {
         
      $fields['uc_products']['#title'] = 'Products';
         
      // These values were found by doing a print_r($node) in node-product.tpl.php
         
      $fields['uc_products']['#options'] = array (
           
      'model' => 'SKU',
           
      'list_price' => 'List Price',
           
      'cost' => 'Cost',
           
      'sell_price' => 'Sell Price',
           
      'weight' => 'Weight',
           
      'weight_units' => 'Weight Units',
           
      'dim_length' => 'Length',
           
      'dim_width' => 'Width',
           
      'dim_height' => 'Height',
           
      'length_units' => 'Length Units',
           
      'pkg_qty' => 'Quantity',
           
      'default_qty' => 'Default quantity to add to cart'
         
      );
        }
      }
      ?>

    (Thanks to these two commenters for posting code updates)

  3. Go to Administer > Site building > Modules and enable "Custom module"
  4. Go to Administer > Content management > Content types and edit the "Product" content type
    1. Under Workflow Settings > Synchronize translations, select all fields you would like to synchronize. However, do not select the Taxonomy terms option (see below for why)
    2. Repeat this step for any other product classes/content types whose product data you want synchronized

That's all! If you edit a node in one language, you should see the updated product data in all other languages as well. The only caveat is that product attributes and product options will still need to be added and updated on each translation.

Thanks to user gupa on Ubercart support forums for posting this fix (see reference 1)

Problem: Taxonomy terms are untranslated in Catalog block

This one had me puzzled for a long time. At first, I had enabled localized terms for the Catalog vocabulary. After I created some terms, I translated them using the Translate Interface tool as usual, but this did not work. Editing a product would show the localized term in the Catalog list, however viewing the product always resulted in the untranslated term being displayed on the Catalog block. The solution is to navigate to Administer > Content management > Taxonomy and edit the Catalog vocabulary, choosing Per language terms. Use the following procedure to define taxonomy term translations:

  1. Browse to Administer > Content management > Taxonomy
  2. Add a new term with its translations:
    1. Add a new term to the Catalog vocabulary in the default language of your store and choose that language from the drop-down menu
    2. Repeat the above step, but enter the desired translated texts for the term (including a translated term name)
    3. Repeat the above step, but enter the desired translated texts for the term (including a translated term name)
  3. Click on the Translation tab of the taxonomy interface
  4. Click Create new translation and pair up the original term with its translations
  5. Repeat the step above for each term that you created earlier.

This is why you do not want to synchronize taxonomy terms, with this setup each term is translated the same way nodes are - separate terms per node, linked together with some metadata. Synchronizing taxonomy terms would result in your products appearing in the right categories but in the wrong languages!

Problem: Adding items to the cart in one language, then switching to another language does not localize the cart contents

This is an unusual situation, but it's a very annoying problem; adding an item to the cart, switching languages and then click on that same item in the cart will open the product in first language, not the one the customer is browsing your website in. To solve this, hook_cart_item() will be used to override the default cart rendering with our own version which will replace node with translated nodes. Open the custom module file, sites/all/modules/custommod/custommod.module, which was created earlier and add before the closing ?> tag:

<?php
/**
  * Implementation of hook_add_to_cart().
  */
function custommod_add_to_cart($nid, $qty, $data) {
 
/* Due to Drupal's use of multiple nodes for product translations, the same
   * product in a different language is treated as a different product entirely.
   * This is problematic as the same product in different languages can be added
   * to the cart simultaneously. This function works around that problem by
   * always using the tnid/original node. As a result, the cart must be
   * localized as it is displayed.
   */
 
$node = node_load($nid);
 
// Determine if this node is the source node or a translated one
  // Remember: tnid is 0 if there are no translations
 
$is_source = ($node->nid == $node->tnid || $node->tnid == 0) ? 1 : 0;
  if (
$is_source) {
   
// If it is the source, then all is well…
   
$result[] =  array('success' => TRUE);
  } else {
   
/* If we are not the source node, then fail to add this product silently and
     * call uc_cart_add_item() to add the source node's product instead. It will
     * be localized later - see custommod_cart_item()
     */
   
uc_cart_add_item($node->tnid, $qty, $data);
   
$result[] = array('success' => FALSE, 'silent' => TRUE);
  }
 
// Remember: We need an array in an array here
 
return $result;
}

/**
  * Implementation of hook_cart_item().
  */
function custommod_cart_item($op, &$item) {
 
/* hook_cart_display() isn't really a hook, it's mostly for internal use.
   * However, we do need to access later. Setting $item->module forces
   * a module_invoke() call in uc_cart.module to call custommod_cart_display()
   * instead of the default uc_product_cart_display(). We will call
   * uc_product_cart_display() inside our function to ensure things work as
   * usual in future versions.
   */
 
$item->module = "custommod";
 
/* Note that although it is possible to use check for case 'load' in $op and
   * then override the $item->nid and $item->title values, this will cause bugs
   * when attempting to add or remove products in different languages. To
   * resolve these bugs, we are forcing the use of custommod_cart_display() and
   * rewriting the code for the title, img, and anchors to localize the cart.
   */
}
/**
  * Implementation of hook_cart_display().
  */
function custommod_cart_display($item) {
 
/* Call uc_product_cart_display() to get things setup as usual and to ensure
   * this hack still works even if uc_product_cart_display changes at some point
   * in the future.
   */
 
$display_item = uc_product_cart_display($item);
 
// Get the translations, if any.
 
$node = node_load($item->nid);
  global
$language;
 
$translations = translation_node_get_translations($node->tnid);
  if (
$translations[$language->language]) {
   
// Reminder: NEVER override the nid. That is what causes the bugs!
   
$tnode = node_load($translations[$language->language]->nid);
   
$display_item["title"]["#value"] = node_access('view', $tnode) ? l($tnode->title, 'node/'. $tnode->nid) : check_plain($tnode->title);
   
$display_item["image"]["#value"] = uc_product_get_picture($tnode->nid, 'cart');
  }
  return
$display_item;
}
?>

After reloading the Custom module at Administer > Site building > Modules, the cart should behave properly when switching languages. As well, adding a product to the cart in one language, switching languages, then adding it again should not result in two different products being added to the cart. Instead, the quantity of the product will increase by 1.

Credit for this solution goes to user Docc at Ubercart forums, who posted the code sample (see reference 3)

Problem: Ubercart does not localize products during checkout

This one was a bit trickier to solve, since there's no real elegant way to trick ubercart into localizing the products while using the standard checkout pane. As a result, we will have to disable the stock checkout pane and use the replacement provided by the code below instead (the replacement pane is called "Your order").

<?php
/**
  * Implementation of hook_checkout_pane().
  */
function custommod_checkout_pane() {
 
/* Replacement for standard cart contents pane. Although hook_cart_item() can
   * be used to localize the checkout pane, then we get into trouble while
   * trying to localize the cart display (see the comments above). The best way
   * that I can think of to work around this is to disable the stock cart
   * contents pane and enable this one instead.
   */
 
$panes[] = array(
   
'id' => 'custommod_cart',
   
'callback' => 'custommod_checkout_pane_custommod_cart',
   
'title' => t('Your order'),
   
'desc' => t('Display the (localized) contents of a customer\'s shopping cart.'),
   
'weight' => 2,
   
'process' => TRUE,
   
'collapsible' => FALSE,
  );
  return
$panes;
}

/**
  * Callback for our implementation of hook_checkout_pane()
  */
function custommod_checkout_pane_custommod_cart($op, &$arg1, $arg2) {
 
/* The code below is copied from uc_checkout_pane_cart() and is slightly
   * modified to localize the cart contents before displaying it. If you are
   * using this, you need to keep an eye on uc_checkout_pane_cart() to make sure
   * that if there is an important change or bugfix, you make the same change
   * here.
   */
 
switch ($op) {
    case
'view':
     
$contents['cart_review_table'] = array(
       
'#value' => theme('cart_review_table'),
       
'#weight' => variable_get('uc_pane_cart_field_cart_weight', 2),
      );
      return array(
'contents' => $contents, 'next-button' => FALSE);
    case
'review':
     
$items = uc_cart_get_contents();
     
$output = '<table>';
     
$context = array(
       
'revision' => 'themed',
       
'type' => 'cart_item',
       
'subject' => array(),
      );
      global
$language;
      foreach (
$items as $item) {
       
$node = node_load($item->nid);
       
$translations = translation_node_get_translations($node->tnid);
        if (
$translations[$language->language]) {
         
$tnode = node_load($translations[$language->language]->nid);
        } else {
         
$tnode = $node;
        }
       
$desc = check_plain($tnode->title) . uc_product_get_description($item);
       
$price_info = array(
         
'price' => $item->price,
         
'qty' => $item->qty,
        );
       
$context['subject'] = array(
         
'cart' => $items,
         
'cart_item' => $item,
         
'node' => $tnode,
        );
       
$output .= '<tr valign="top"><td>'. $item->qty .'&times;</td><td width="100%">'. $desc
                 
.'</td><td nowrap="nowrap">'. uc_price($price_info, $context) .'</td></tr>';
      }
     
$output .= '</table>';
     
$review[] = $output;
      return
$review;
  }
  return
$result;
}
?>

Thanks to user totsubo at Ubercart forums for helping me test this part of the module!

See also

References:

  1. Information about localized taxonomy in thread Multiple language Ubercart website on the Ubercart support forums
  2. Lots of good information at a thread titled i18n issues i D6/UC2 for Multilingual sites on the Ubercart support forums
  3. Method for product synchronization was based on a small code sample by Docc at Drupal node #456358
Rating: 

Comments

Many thanks for this round-up, Stewart.

I have however encountered a problem, and have mentioned it on Ubercart.org (here): if a user puts item A in the shopping cart, then switches to a second language, he/she can add item A again, though this will appear as a second item in the cart (basically you'll see "1x A, 1x A" instead of "2x A".
Would you know how to fix this easily?

Hm, you're right - I hadn't noticed that... I think to solve this, an additional check in custommod_cart_item() needs to be run on the 'update' or 'add' events to ensure that the product's base node ID doesn't match any of the base node IDs for products already in the cart. I won't have the time to take a look at this until at least next weekend, but I'll be sure to update the blog post when the new code is ready. Thanks for the comment!

Hey dude!

Did you solve that?? I'm pretty much interested in building a multilingual ubercart shop and this is the first site where I found a real an clear solution for these reported problems.

Congratulations for your work! Keep going!

I just looked into it, but it looks like we're missing (or I can't find) a critical piece of the puzzle:
http://www.ubercart.org/forum/internationalization/13396/hook_or_functio...

Once we find a way to modify the cart as items are added to it (in other words, to switch $nid values for $tnid values) then I'll be able to post a correction to the custommod module. I'll keep you updated!

I'm currently using version 2.4 of Ubercart and I'm happy to report that I can't reproduce this problem. In other words, it seems to be fixed for good.

instead of just:

<?php
/**
* Implementation of hook_i18nsync_fields_alter().
*/
function custommod_i18nsync_fields_alter($fields, $type) {
$fields['uc_products']['#title'] = 'Products';
// These values were found by doing a print_r($node) in node-product.tpl.php
$fields['uc_products']['#options'] = array (
'model' => 'SKU',
'list_price' => 'List Price',
'cost' => 'Cost',
'sell_price' => 'Sell Price',
'weight' => 'Weight',
'weight_units' => 'Weight Units',
'length' => 'Length',
'width' => 'Width',
'height' => 'Height',
'length_units' => 'Length Units',
'pkg_qty' => 'Quantity',
'default_qty' => 'Default quantity to add to cart'
);
}
?>

use:

<?php
/**
* Implementation of hook_i18nsync_fields_alter().
*/
function uc_i18nsync_i18nsync_fields_alter($fields, $type) {
    if(
in_array($type, uc_product_types())) {
       
$fields['uc_products']['#title'] = 'Products';
       
// These values were found by doing a print_r($node) in node-product.tpl.php
       
$fields['uc_products']['#options'] = array (
       
'model' => 'SKU',
       
'list_price' => 'List Price',
       
'cost' => 'Cost',
       
'sell_price' => 'Sell Price',
       
'weight' => 'Weight',
       
'weight_units' => 'Weight Units',
       
'length' => 'Length',
       
'width' => 'Width',
       
'height' => 'Height',
       
'length_units' => 'Length Units',
       
'pkg_qty' => 'Quantity',
       
'default_qty' => 'Default quantity to add to cart'
       
);
    }
}
?>

in this way only on node of type product you will have the fileds added.

Thanks for this tip! I've updated the post above to include the node type check.

the above code gives me this error:

Parse error: syntax error, unexpected T_VARIABLE in /home/bserem/public_html/bankdemo/sites/all/modules/c_ubercart/c_ubercart.module on line 10

I am using the latest UC version (2.2)

anybody else had this problem?

The code works here - have you checked for a missing/added bracket or quote by accident? Line 10 seems to be
'model' => 'SKU',
which is fine...

My terms are correctly translated by following your method detailed in your post, but my vocab name is not which appears in catalog page and breadcrumb.

Is there any trick for this too ?

This one is tricky, since you need to fresh translations before using the 'Translate Interface' tool in the Build section. First, browse to /admin/build/translate/refresh, select all three checkboxes and then click "Refresh". You should now be able to search for & translate your vocabulary names!

Thanks for the trick, but it doesn't work...
Steps I did:

1) Enabled catalog module
2) Change name of the vocabulary name to "Our Shop"
3) set Vocabulary to "Per terms"
4) Create all my terms with translated associated terms and linked them under Translations
5) Refresh of everything(menu, content type, Taxonomy) under Translate Interface.
6) made the translation of my vocabulary name under Translate Interface Taxonomy.
7) Check what is displayed under my catalog page in language other than default...It's still "Our Shop"

http://test.hsh.co.il/fr/catalog

PS: I don't see the string "Our Shop" on fr/catalog with Localization Client.

I'm not sure what's causing this (as posted above could be this bug)...

On my sites I stopped using the stock Ubercart catalog module and designed a custom view with the Views module instead. This has been working out very well for me and it's much more flexible.

Maybe my problem with vocab names is related to this bug introduced with i18n module 6.x-1.2:

http://drupal.org/node/638556

I'm having the same problem. I hope you solve it, I don't have time to do the programming.

Hello,
Thanks for the great information, I was already getting desperate. But unfortunately I have the same problem like the above 2 posters. Switching language with the language switcher block on a catalog category takes me to the wrong link. I created a taxonomy from scratch, and the same behaviour again. In the db table the trid columns seem correct. Any idea how to solve this?

Best regards

Martin

Are you using the stock/prepackaged Ubercart catalog module? If so that may be the cause, I've switched to using a custom catalog view using the Views module and it's been working great for me so far. Not only does it allow for more flexibility, but I haven't had any problem regarding taxonomy & translations (yet, at least)!

Hi firewing1, thanks for the tip. Tried your recommendation, works great, except i couldn't find the grid style display (under the Arguments setting for the view), it was either List or Unformatted. Am i missing something, or is this the right place to make the change (just a note, this Style setting is not available in the original uc_products view)? Also, do the configuration in Ubercart catalog settings still apply to this cloned view? Thanks!

Hi kyk,

Under "Basic Settings", there's a "Style" option which gives you access to a grid layout among other styles. If you're using the original uc_products view, you'll need to clone it first - otherwise, as you mentioned you run into problems where some settings aren't available!

Unfortunately using a custom view also means that the Ubercart catalog settings will no longer have any effect on the product grid. Instead, you'll need to change the settings directly in the view editor.

Stewart

I followed the trick for the taxonomy terms by choosing traslation mode to per language terms, but now pathes displayed by the block "Language switcher" are wrong in every term's page.

See the link for french (or hebrew) on this english page(default language):

http://test.hsh.co.il/catalog/11

For french I have :
fr/catalog/11
instead of
fr/catalog/13 (the translated term)

Is there any trick ofr this too ? Or it's a current bug ?
Thanks for your help.

I solved the misleading catalog taxonomy term paths by adding this function to uc_catalog.module:

<?php
function uc_catalog_translation_link_alter(&$links, $path) {
  if (
preg_match("/^(catalog\/)([^\/]*)(.*)$/", $path, $matches)) {
    foreach (
$links as $langcode => $link) {
      if (
$str_tids = i18ntaxonomy_translation_tids($matches[2], $langcode)) {
       
$links[$langcode]['href'] = "catalog/$str_tids". $matches[3];
      }
    }
  }
}
?>

Since I did some alterations to the uc_catalog code previously, I didn't bother creating a separate module for this.
If you do, the function should be named custommod_translation_link_alter, where "custommod" is the name of your module.

This function is an implementation of hook_alter_translation_link() hook and is basically a cloned i18ntaxonomy_translation_link_alter() function from i18n/i18ntaxonomy/i18taxonomy.module with "taxonomy/term" replaced by "catalog".

I suppose the i18ntaxonomy module could do a better job in translating all the taxonomy links (that is, 'catalog' and all others in addition to 'taxonomy/term') and I'm not sure the preg_match stuff is the best approach to this either.
But it works and fixes our problem. So that's the bright side :)
Maybe somebody with a deeper understanding of all the i18n inner-workings should code a more elegant solution for translating taxonomy links. As I'm quite new to this, I'll leave filing bugs to others of you out there ;)

Thanks mate!!You fixed the issue for me..had your exact same problem with the terms path.

Your code did it;)

I just tried your solution and added your function uc_catalog_translation_link_alter() to the catalogue module but it unfortunately did not fix the issue for me.

When a user is a on a catalog category page and switches languages, the link the language switcher goes to is incorrect. For example in my case the language switcher points to http://localhost/ja/catalog/17 when it should link to http://localhost/ja/catalog/18

Too bad since I have been trying to fix this issue for months and was very hopeful when I saw your solution :(

hook_translation_link_alter is a valid hook so the code (or some very similar code) should be working normally with UC 2.3. I'll be looking into this soon and posting an update, I had accomplished this at one point but then used a different method for language switching on my live website and forgot about it.

Firewing1, looking forward to seeing your solution for the catalog issue! If/when you get a chance to look at it, I'd be mighty glad if you could ping me just to let me know to come and check out any blog updates :)

The code posted in the top-level comment is a good start, I'll put this on my todo list and hopefully I can post some sample code in the next week. Sorry for the wait - work has been busy lately so I've had less time to test.

I was wrong and Chionsas' code works like a charm!

I've not exactly sure why it didn't work for me initially but I think it had to do with pathauto (URL aliases) that were set up either by me, or more probably automatically created, that aliases the Catalog block's link to category/catalog/[Term name]. I removed all those aliases and the solution presented above now work.

I really have to thank you Chionsas since this has been a problem that has been bugging me since my first installation of Ubercart!

Finally - It works!
Thank You!

Just wanted to share this one: i18nsync 1.2 taxonomy synchronization is fixed (check http://drupal.org/node/626836 ), so you can synchronize the catalog now. Of course you have to make sure every term in the catalog is translated first, otherwise the sync will be broken.

First off, thanks Stewart for putting this page together. I was getting very frustrated with Drupal/UC to say the least and so glad I found your page.

I've followed the steps you outlined to get the Product catalog to translate but it's not working. When switch languages the product catalog contents disappears. Any ideas?

Also if a view is a better way to go would you mind sharing your solution? I'm very new to Drupal and not at all familiar with views. But I don't mind using one if it's better than the product catalog UI!

Thanks!

Hi Jc,

If you look at the /admin/settings/language/i18n page, what is your current content selection mode? Unless the mode enables content for users of all languages, the catalog products are being hidden because a translated node isn't available yet. As you add translations for a given language, the translated products should appear for users when they click catalog. If you want to show all nodes, translated or not, just select "All content. No language conditions apply." as your content selection current mode.

The Views module looks very complex to setup at first, but once you experiment a bit it's easy to get the hang of it. Just install the Views module and enable the appropriate modules in your Drupal installation. Now when you visit /admin/build/views you should see the default "uc_products" view - I usually clone this one and create uc_products_custom, and then disable uc_products. Then simply click on "edit" to start making changes to the catalog layout - for example, you could change the image for a Thickbox popup or change the positions of the item price and "add to cart" button.

Stewart

Thanks for the quick reply! You're a Genius!

I was taking a step-by-step approach and wanted to first get Catalog navigation to work before first moving on to translating product. I thought the catalog would default to English if the product was not translated. Now that I have translated the product the Catalog is showing up!

For the Views thing. Just to make sure I am understanding you correctly:

1- You are saying that we can replace the Catalog menu list with a View
2- Do we still need a Taxonomy in place to support the view?

So what are the advantages of using a View compared to the default product Catalog?

Do you mind pointing me to a site you have that is currently using this so I can get a feel for the end goal to help me while I try to set up a Catalog using Views? If I do figure it out I'm definitely writing up a support page for it! :)

PS I'm happy to take this discussion off line if you prefer

Hi Jc,

Glad to hear things are working a bit better now! You can go ahead and post the link to your site if you'd like, I'll take a look. You don't have to use taxonomy to get a Views-based catalog display working, but it's obviously much easier since you can use it to organize and categorize your catalog. The primary advantage to using Views instead of the Ubercart catalog module is that you have much, much more flexibility - you can choose sort criteria, arguments, add filters or even have users choose which filters they want enabled as they browse your View. As well, you have complete control over the output format, meaning that you don't have to follow the stock Ubercart layout. You can choose what product information is displayed, in what order, and with what picture (including a Thickbox popup).

The default ubercart catalog is actually using Views, it's just integrated and configured for you. To get a custom views setup, you just need to setup something that behaves similarly to the default/integrated one. After cloning the default uc_products view as I mentioned in my last post, disable uc_products (since it is being replaced in-place with the new uc_products_custom) and then click Next. You should now see the Views configuration interface.

In order to get your view taxonomy-enabled, you'll need to create an argument for your view - in this case, the argument will be the term ID but you can customize this to better suit your site if needed (for example, with term name instead of term ID). In my case, I clicked on the + button under Arguments and chose Taxonomy from the drop-down menu. From there, I selected only Term ID and clicked Add. Under Action to take if argument is not present choose Summary, sorted ascending and then click Update (3 times - leave the other settings at their default/blank values).

Next, two settings can be added quickly to mimic the behaviour of the Ubercart catalog view. Under Sort criteria, click the + button again and select the Node: Title checkbox that you'll find under the Node group. Similarly, add a new filter and choose i18n: Content negotiation from the i18n group (I again recommend clicking Add and then Update immediately again, leaving the default settings). This will prevent untranslated nodes form appearing in your final view once it's ready.

The last step is to save your View settings and to define a page for it to appear at. Click Save at the bottom of the interface to save the view settings, and then switch to the Page tab on the top left of the interface. You should now see a setting called Path - click on this and set a path for users to access the view at. If you disable the Ubercart catalog module, you could set this to catalog to make your view a drop-in replacement. Now save your view again and that's all! Check out your new view at http://your-site/catalog. If you want to change the page layout (for example change from grid to list view or vice-versa), simply edit the view again and change the Style setting under the Defaults tab.

I hope this was able to help you! I took me a while to figure out how it was all put together too, so I feel your pain. Let me know if these instructions work for you, if so I'll extend on them a bit and write part 2 of the Ubercart tutorial.

Stewart

Thanks for the mini tutorial on Views.

Just one note. I was not able to find a i18n group when trying to add a filter. I needed to enable another module called 'Views translation'. Also when you then try to add the filter Drupal give a scary looking message:

'This item is currently not exposed. If you expose it, users will be able to change the filter as they view it.'

I just clicked update but the message did worry me when I first saw it :)

Looking forward to a full Ubercart related Views tutorial! I'm sure the is much that can be done with it than what I've got so far, which is really just an exact copy of what Ubercart had with an added feature, sorting.

Hi Stewart,

I've finally started and am giving Views a twirl and seeing if I can get a Catalog to work. So far I have been able to get the products to list correctly if I go to /products or products/[Taxonomy term]

I still haven't figured out how to get the following to work though and was hoping you could help out:

1- I've disabled the default uc_products view but my UC installation still seems to work even if I disable my uc_products_custom view. I'm guessing UC has can still use a view even if I've disabled it?

2- I have a Catalog block that displays the various Taxonomy terms I have for my products. Each entry is a link that lists certain products in the catalog. I can't get this to work with my view since the links are formed as category/catalog/[Taxonomy term]. How can I get the Catalog block to create links that point to catalog/[Taxonomy term] instead of category/catalog/[Taxonomy term]?

3- Language switcher ... when I am on page catalog/stickers and I want to switch to Japanese, the language switcher block has a link to ja/catalog/stickers. This isn't correct, it should be ja/catalog/ステッカー Is this related to #2 above? I.e. for each category I have one English Taxonomy entry and one Japanese taxonomy entry, but in order to use Views and the language switcher I should only have one entry for both translation nodes?

Thanks again for all the great info on this page!

Views is great! Once you are accustomed to the UI, I find views can create pages that are much more dynamic than the stock modules. I'll answer by number:

1) I'm not sure what you mean on this one - even if you disable the stock Views page, things should continue to operate normally with the exception that the /catalog page should not return 404, unless your other Views is serving pages on that path.

2) For this you'll probably have to implement your own Views block. In your uc_products_custom view, select Block from the drop-down menu on the top left and then click "Add display". This will add a block that will inherit the settings of your view, but that you can also customize independently by clicking the "Override defaults" button on any of the settings (warning: if you don't, you'll end up changing the default settings ie for your catalog page too!)

As for the actual linking part, if adding the block this way doesn't solve the problem then you'll need to use rewriting and tokens. You'll see that in "Fields", you are able to rewrite the text label and href attribute of the links using tokens from any of the fields appearing prior to that link field. The trick with this one is to add fields but exclude them from the display, then use them later in the link rewrites. For example, on one of my sites I have the URLs working like this:
/catalog = list of all products
/catalog/[Taxonomy Term] = displays child taxonomy terms
/catalog/[Taxonomy Term]/[Taxonomy Term2] = displays all products nodes in [Taxonomy Term2] with parent [Taxonomy Term]

In the view that displays child taxonomy terms for a top-level term, I have to keep the catalog path and can't just link to the taxonomy term page. I do this by using a "taxonomy: term" field that is excluded, and a "link" field afterwards. When I output the link to the child taxonomy terms, I rewrite the output using the string "catalog/!1/[name_1]". !1 represents the argument passed, [Taxonomy Term]. [name_1] is the replacement for the child taxonomy term. So say I put in /catalog/top_level_term, top_level_term is the argument (it is get substituted by !1) and [name_1] will be substituted in each link to the child nodes for top_level_term.

3) This one is a REAL pain to fix... It is possible, but extremely difficult. You'll have to modify the uc_catalog_translation_link_alter() function provided by Chionsas to suit your URL layout and lookup the correct (translated) terms based on a given catalog URL. That isn't so difficult, but once you start playing with Views and fixing some SEO stuff (for example, making "-" replace all of the annoying "%20" that appear whenever you use a space) then getting the correct term name from the URL is difficult, and that prevents you from getting a term ID which in turn prevents you from getting the translated term IDs and names. That's not to mention that having two term with the same name will confuse the lookup code.

In my case, I ended up settling it by having it point users to the translated page unless the path started with /catalog, in which case I point users to the main catalog page of the other language regardless of where they were previously. This isn't a great thing from a usability perspective, but it was the cleanest considering my SEO optimizations.

The only caveat is that product attributes and product options will still need to be added and updated on each translation.

..this issue seems yet to be solved and options cannot be translated.. :|
please, any solution found meanwhile? thx

Unfortunately there's no easy, clean way to handle this... It needs a custom module that does (if I remember correctly) some database updates that can't be done via the regular Ubercart API for the synchronization to work properly. I may look into this in the future if I need to start using product attributes, but until I've given up on this problem. I'm hoping UC3 will make the situation a bit easier to handle, as I know that improving i18n is one of the Ubercart developers' targets for UC3.

Hello Stewart,

This is a great site! Extremely usefull.

Sorry if this appears to be off topic. Feel free to move it to a more appropriate place.

I have a UC question. In your post, you wrote I may look into this in the future if I need to start using product attributes... (http://www.firewing1.com/comment/reply/27/197#comment-197).

I'm trying to decide when i should use attributes and when it makes more sense to use CCK. I have a hard time finding answers. Can you help or point me in the right direction?

CASES #1
- product class: annual hockey registration
- the player's level is defined by his age
- If you're 12 then you're in level PW and the price is 295
- If you're 14 then you're in level B and the price is 315, and so on
* I've setup a product class with a Level attribute (options include different age groups)
* Users buy a Registration and select their Level according to their birthdate
* product is priced accordingly
? Is this the better way to go ?
? Could I have done it without Attributes ? (your post seems to suggest just that)
? if so why & how ?

CASES #2
- product class: Continuing education for real estate agents
- Courses are given in different locations or cities
- Courses are available in 2 languages
- the price is the same
- Admin decides which courses are given where & in what language
? Should location & language be attributes ?
? Is this the better way to go ?
? Could I do it without Attributes & if so why & how ?

Renaud

From what I have found, using CCK in products works better with i18n at the moment, but Attributes is a much cleaner solution due to its tight integration with Ubercart. Theoretically nothing makes CCK easier to internationalize than product attributes, but the code for CCK exists already and the code for product attributes doesn't.

For case #1, attributes is exactly what you need apart from the fact that it can't be internationalized... What I would recommend would be to create an attribute with the levels for each language on your site and then add the appropriate attribute for each language to each product. This will make your setup a bit complicated since changing one product will not affect the translated nodes/products, but it would be the easiest way to handle things for now.

For case #2, I would implement that using taxonomy:
Course (Vocabulary)
|-- Language 1
|-- Language 2
Then tag products accordingly. This will make it easy to create a Views that can filter out items. The location would be a bit more difficult to handle... Unless there's a high level of consistency (use taxonomy), I would use CCK and just enter the location manually since it can vary so much.

FWIW, implementing synchronization of product attributes and attribute translation is on my todo list except that it's a very big task so I haven't even had the time to get to it yet. Depending on how quickly I can get something setup with various code samples I've collected I may have a demo ready within a month, but it will probably a much more than that until I'm finished and have a production-ready module.

In other words, as of August 2010, when setting up a multilingual Ubercart store, try using taxonomy first in order to define product features (especially for a big store that sells lots of products in many different languages). If you can't avoid using Attributes (which are great outside of i18n), be prepared to create separate sets of attributes for each language your store supports. For example:

- Level (English attribute) has the following options: A, B and C
- Niveau (French attribute) has the following options: X, Y and Z.

Both become language specific attributes.

Does all this make sense?

Sub-question if I may. Asuming it does make sense, if I have to create separate sets of attributes for each language, should I then consider creating language specific product classes? Is there anything to be gained from this or not?

> Does all this make sense?
Yup, you nailed it.

> Should I then consider creating language specific product classes? Is there anything to be gained from this or not?
It may be worthwhile... Personally I found it easier to do things manually, but then again I was only dealing with 1 template (so 2 types, EN and FR).

About translation attributes and options, i18n module do this greate with string translations (see uc_attribute_translate in uc_attribute.module). But sync was a problem. I've found solution and discribed it here:
https://drupal.org/node/2238029

Help! I just want to

    install

the translation files at the moment, it seems i am not even doing

    that

properly because only 2% percent of ubercart is in french after i install the .po files, and 98% still in english.

I tried 2 methods: i downloaded "ubercart-all-fr-translations.tgz" from localize.drupal.org... it contained 15 ubercart module folders such as UC_cart UC_attribute UC_order etc... and copied all these folders over the existing ones, so each folder has a translated .po file.

it didnt work very well at all!

So i downloaded the complete 600KB all-in-one "ubercart-all-fr.po" from localize and impoted it into my drupal installation with admin/build/translate/import...

Both ways only worked 2%

here is the result, for example:
http://127.0.0.1/d6/admin/store/settings/orders

reads like this:

Order settings
Vue d'ensemble Éditer

Order settings:
Displaying 30 orders at a time on the admin overview
Order logging is enabled.
Addresses on order view pages are capitalized.
Customers are allowed to view order invoices from their accounts.
You are using the customer order invoice template.

Processus des commandes:
Les statuts de commande suivants ont été définis:
Canceled
In checkout
Post checkout
Payment received
Completed

Order panes:
Order panes on Voir screen:
Ship to is activé.
Facturer à is activé.
Customer info is activé.
Paiement is activé.
Products is activé.
Line items is activé.
Tracking numbers is activé.
Order comments is activé.
Commentaires de l'administrateur is activé.
Update order is activé.

etc etc.

my main navigation menu looks like this:
root
FreelinksMon
compteTranslate
stringsCréer un contenu
Administrer
Construction du site
Alias d'url
Blocs
Menus
Mini panels
Modules
Pages
Panels
Thèmes
Traduction de l'interface
Vues
Gestion du contenu
Configuration du site
Generate items
Gestion des utilisateurs
Store administration**********
Rapports
Aide
Aide Avancé
Example help
Se déconnecter

I will try all the advice on this site, but it seems something is very wrong with my starting point as only 2% of ubercart fr is installed, and no susimilair issue is mentioned on this page!

thankyou!

If you opted to upload the all the traslations/ folders on your server, have you disabled and re-enabled all the Ubercart-related modules? These translations are only imported when enabling the module. If you imported each .po, then all the strings should be there... 2% sounds a bit low, but have you imported any of the Drupal localizations? 2% would make sense if that represented only the Ubercart strings.

As for the untranslated parts, I can't help you there - it looks like those haven't been done upstream yet.

I never understood why I got involved with Ubercart in the first place. It's been a giant headache from day 1. Why can't they make these things EASY?

I've run into a problem similar to the one you describe for adding an item and then switching languages but for deletion.

Steps to reproduce bug:

1. user adds an item using language B
2. user switches to language A and views cart
3. user checks item for deletion and then updates cart
4- cart is updated but item is *not* removed from the cart

The only way to remove the item is to switch to language B and perform the deletion ...

Updated the module code, this should be fixed now :)

I love you. :)

This was my D6 solution to pre-populating the newly translated node with the original node's data - seems to be working.

function uc_product_translate_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
if (in_array($node->type, uc_product_types())) {
switch ($op) {
case 'insert':
$source_node = $node->translation_source;

db_query("
INSERT INTO {uc_product_adjustments}
(nid, combination, model)
SELECT %d, combination, model
FROM uc_product_adjustments
WHERE nid = %d",
$node->nid,
$source_node->nid
);

db_query("
INSERT INTO {uc_product_options}
(nid, oid, cost, price, weight, ordering)
SELECT %d, oid, cost, price, weight, ordering
FROM uc_product_options
WHERE nid = %d",
$node->nid,
$source_node->nid
);

db_query("
INSERT INTO uc_product_attributes
(nid, aid, label, ordering, default_option, required, display)
SELECT %d, aid, label, ordering, default_option, required, display
FROM uc_product_attributes
WHERE nid = %d",
$node->nid,
$source_node->nid
);

break;
default:
break;
}
}
}

Comments appreciated.