I thought I had this down, but alas it seems I don't.

Problem:
I have built a custom entity and have Entity Translation working fine on all parts except for ADDING a new translation after I have created the original language entity under "Translate UI" (../admin/structure/custom_entity/manage/%custom_entity/translate). When clicking ADD, (URL: ../admin/structure/custom_entity/manage/%custom_entity/edit/add/ja/en), I'm redirected to page not found.

I've tested inserting the translated entity manually via phpmyadmin and view, edit and delete links via "Translate UI" work fine and redirects to the correct forms and pages. Just not ADD.

It seems that the alias is not created with the redirect to the entity form with the EntityTranslationHandler form alters..

This is my hook_entity_info() function.... What am I missing?

function ecm_school_system_entity_info() {
  
  $info = array();

  $info['schools'] = array(
    'label' => t('School'),
    'base table' => 'schools',
    'controller class' => 'SchoolsEntityController',
    'entity class' => 'SchoolsEntity',
    'access arguments' => array('manage ecm school system'),
    'access callback' => 'schools_access_callback',
    'uri callback' => 'entity_class_uri',
    'label callback' => 'entity_class_label',
    'admin ui' => array(
       'path' => 'admin/structure/school-system/schools',
       'controller class' => 'SchoolsEntityUIController',
       'file' => 'includes/schools.admin.inc',
    ),
    'fieldable' => TRUE, 
    'entity keys' => array(
       'id' => 'id',
       'language' => 'language',      
    ),		
    'bundles' => array(
       'schools' => array(
          'label' => t('School'),
          'admin' => array(
          'path' => 'admin/structure/school-system/schools',
        ),
      ),
    ),
      // Add translation support.
      'translation' => array(
        'locale' => TRUE,
        'entity_translation' => array(
          'class' => 'EntityTranslationDefaultHandler',
		  'base path' => 'admin/structure/school-system/schools/manage/%schools',
		  'view path' => 'schools/%schools',
		  'edit form' => 'schools',
		  'path wildcard' => '%schools',	
          'default settings' => array(
            'default_language' => LANGUAGE_NONE,
            'hide_language_selector' => FALSE,
          ),
        ),
      ),	
	
      'view modes' => array(
        'full' => array(
        'label' => t('Full'),
        'custom settings' => false,
       ),
      'list' => array(
        'label' => t('List'),
        'custom settings' => false,
       ),     
    ),
    'views controller class' => 'EntityDefaultViewsController', 
    'module' => 'ecm_school_system',
  );

  return $info;
}

Any help/advice will be much appreciated.

Comments

nickolas.wilson’s picture

Assigned: nickolas.wilson » Unassigned
nickolas.wilson’s picture

I have solved the problem.

I had set an extra level in my path for menu usage, as shown below;

admin/structure/custom_entity/extra_level/manage/%custom_entity

However, it seems that having that caused problems with rendering entity translation's '/add/%entity_translation_language/%entity_translation_language' for adding new translations. ...

Not sure of how to fix this so I can add an extra menu level. But for now my current solution will do.

Marking as Bug Report and needing review.

nickolas.wilson’s picture

Category: Support request » Bug report
Status: Active » Needs work
nickolas.wilson’s picture

Priority: Normal » Minor
wizonesolutions’s picture

Version: 7.x-1.0-beta4 » 7.x-1.x-dev
Priority: Minor » Normal
Status: Needs work » Active

@nickolas.wilson: What workaround worked for you?

wizonesolutions’s picture

In my case, it looks like it's because the translate link exceeded MENU_MAX_PARTS (!)

I guess I Just have to alter it!

bucefal91’s picture

I have the same issue. Trying to introduce entity translation integration into units module #2203451: Compatible with entity translation.

Units are custom entities defined through Entity API module and their base URL is admin/structure/units-measure/%measure/units-unit/manage/%unit. Entity translations adds its own menu paths on top of it and the longest one is admin/structure/units-measure/%measure/units-unit/manage/%unit/edit/add/%entity_translation_language/%entity_translation_language, which is beyond the 9 allowed parts.

I'll update this issue when I was able to come up with a solution. As far as I can see right now, we have 2 outcomes: either to change the base URL to something shorter or to provide some kind of bridge between the 9 parts limitation and the entity translation functionality.

wizonesolutions’s picture

@bucefal91: The solution is a bit hairy. I'll try to post it if I can get around to it, but pseudocode:

- Make your module's weight higher than entity_translation
- Implement hook_module_implements_alter() and make your menu_alter run last (ET also does this: that's why you have to change module weight)
- Implement hook_menu_alter() — copy the path ET created to a shorter one. Be sure to update the page arguments and access arguments in your copy to be correct (decrement positional arguments whose position has actually changed, which won't be all of them).
- Implement hook_url_outbound_alter(). Transform occurrences of the old path to the new path. Read the hook documentation in system.api.php to see how to do this with preg_match(). This fixes the links ET outputs to the add form. I haven't found it necessary to implement the hook_url_inbound_alter().

That should fix it! You'll have to clear cache 2 or 3 times for some reason, but everything should work after that without further changes.

bucefal91’s picture

hello!

Thank you for your reply. By the time you posted it, I have already advanced more than half way in another direction. I was able to get it done too, though it was different from your approach. For those who might read this in future, here's the patch (code) of how I did it https://www.drupal.org/files/issues/2203451-entity-translation-4.patch and soon you should be able to see it in the source code of Units module.

My angle of attack was the following. I faced 3 different problems:

  • Max menu parts of 9 are exceeded. In my case the longest path was admin/structure/units-measure/%measure_argument/units-unit/manage/%unit_argument/edit/add/%entity_translation_language/%entity_translation_language.
  • Then, as far as I was able understand how entity translation works, it wouldn't account for the case, when the base path includes a bundle argument. In my case the base path was admin/structure/units-measure/%measure_argument/units-unit/manage/%unit_argument and apparently it included the bundle argument. In my case there are 2 entities: measures and units. Measures are bundles of units and I am trying to translate units.
  • Entity Translation inserts entity id into the base path, whereas Entity API admin UI is entirely built off machine names, if those are available.

Max menu parts of 9

For the max menu parts of 9 pieces, I got lazy and just moved my units admin path from admin/structure/units-measure/%measure_argument/units-unit/manage/%unit_argument to units-ui/%measure_argument/manage/%unit_argument. I simply removed some garbage from the beginning of the path and in the middle, so with all the entity translation suffix it would fit into those 9 allowed chunks.

I have added units-ui/* path as admin one through hook_admin_paths() so the admin theme is used and overall it is more continuous when user goes from Measures overview to managing units of that measure.

Also, I had to fix the menu breadcrumb. Since I have destroyed nesting in menu, the standard menu breadcrumb mechanisms no longer worked. Originally, when I was editing a unit, I had this breadcrumb: Home > Admin > Structure > Measures > Units measurements of [current measure]. I implemented hook_menu_breadcrumb_alter() and was altering all breadcrumbs on menu paths that begin with my units-ui/* prefix. I was just adding Measures item into the breadcrumb at the appropriate position. So the new breadcrumb became Home » Measures » Unit measurements of [current measure], which is acceptable for the sake of my goal.

Entity translation does not account for base paths with %load_arguments

At least as far as I can see. That was another big trouble for me, since my base path included the bundle argument. After quite some digging the best I could come up with was to introduce my own translation handler class: UnitsEntityTranslationHandler (yeah, inheriting in OOP is a way to fix issues! :) ). And in its constructor I made very simple hack: before I invoke parent's constructor I simply alter entity info and substitute the %measure_argument menu path to its real value. I was taking the real value from current URL, i.e. arg() function.

To make it at least a bit prettier and declarative, in my hook_entity_info() I added 1 extra property at $entity_info['units_unit']['translate']['entity_translation']['bundle argument']. This property held the number of menu part that holds bundle argument. So in fact my constructor code was reading that property from entity info and swapping that part of all translation paths with its real value, reading it from current path.

Side note: I was disappointed to find lots of EntityTranslationDefaultHandler methods and properties with "private" access modificator. If it had been "protected" things would have been much easier for me as I could overwrite much more stuff in my custom translation handler.

EntityTranslationDefaultHandler uses entity IDs and not machine names when compiling paths

This one is quite easy. Entity translation blindly assumes your paths will use numeric entity IDs, which is fine (almost all core Drupal entities do so), but Entity API that is widely used for introducing new custom entity types, tries to use machine name of an entity if one is declared for that entity type. There is clear mismatch between the 2. I was able to overcome it simply by further extending my custom entity translation handler UnitsEntityTranslationHandler. All I did was to overwrite the getEntityId() method (thanks god it was "protected" and not "private"). And instead of returning entity ID I returned entity machine name.

I tried to write very clear and in a step by step fashion, because I assume I am not the only one who faces these issues when trying to integrate a custom entity built off Entity API with entity translation. Although, the 2 modules should probably make an extra effort to collaborate between themselves so their integration becomes less pain.