Problem/Motivation
Drupal 6 to 8 migrations currently don't include translations of nodes.
Translated nodes in D6 use a tnid property that associates them into translation sets. There's also i18ncontent and i18ncck that take care of the nodes and fields.
Proposed resolution
- Add translation data to the drupal6 migration fixture.
- Update the content entity destination to support translations.
- Make the node migration sources include only the default translation.
- Add auxiliary migrations to bring in the translations.
Related issues will be handled as follow-ups:
- Make the auxiliary migrations auto-derived, so they don't need a template.
- Migrate translated node revisions.
- Migrate other entity types: users, terms, etc.
- Migrate related data: menu items, taxonomy term relations, node access rules, path aliases, visitor stats, etc.
- Handle references to translated nodes, ie: "node/5" might be a translation, will links to that still work?
Comment | File | Size | Author |
---|---|---|---|
#238 | 2225775-i18n-node.interdiff.235-238.txt | 770 bytes | penyaskito |
#238 | 2225775-i18n-node-238.patch | 68.69 KB | penyaskito |
#235 | interdiff-225-235.txt | 5.14 KB | quietone |
#235 | 2225775-i18n-node-235.patch | 69.3 KB | quietone |
#232 | interdiff-2225775-225-232.txt | 8.32 KB | quietone |
Comments
Comment #1
Anonymous (not verified) CreditAttribution: Anonymous commentedTested this today and I observed this behavior:
Source: EN default language, FR language added
Destination: FR default language, EN was not enabled by default (had to add it back in).
delete from migrate_map_d6_node
One problem remains though: tnid is not mapped so the translations are not linked.
Comment #2
Anonymous (not verified) CreditAttribution: Anonymous commentedAfter talking to Gábor it sounds like the practice of having a separate node for each translation is over. Thus, the tnid field should not be mapped.
We will have to do something to detect when something is a translation of an existing entity and update the fields in that entity with the new "row" of data.
Comment #3
mikeryanComment #4
phenaproximaInitial attempt at a patch, affecting d6_node only.
Comment #5
Gábor Hojtsy@phenaproxima: sorry I don't have enough migrate experience to tell if the patch makes sense.
What needs to be done is basically merging nodes that have the same tnid under the nid which is the tnid. So if node 4, 5 both have the tnid 3, then node 4 and 5 are to be removed and their content are to be migrated to entity translations under node 3. That sounds "simple" in itself. Where it will get complex is to migrate path aliases, menu items, other entity references and so on and on to the new nid as well. Sites where they may be unsure if they migrated all the things they may want to set up redirects from the old nids to the new nids (their old tnid). Unfortunately Drupal core does not provide redirection functionality to be used. Anyway, the basics are to merge the nodes from multiple copies to the one indicated by tnid as a first step :)
Comment #6
Gábor HojtsyAh, there is also node access. That has language variance in D8 now which should be used.
Comment #7
Gábor HojtsyComment #8
Gábor HojtsyComment #10
Gábor HojtsyLooks like if the language_property would be defined in config schema, we would get better fails. Seems like fails are on that :)
Comment #11
phenaproximaAdded schema for the node destination.
Comment #12
phenaproximaI'm back on this. It's still a work in progress, but I think I have it working at a basic level. The wrinkle is that translations are migrated with node revisions, due to the relationship between originals and their translations in D6 and D7. I'd like to change this so that there is no separate migration for revisions -- this patch is a bit of a kludge -- but that's going to take some additional hacking which might as well be done in a follow-up issue. The test coverage also needs to be beefed up significantly. Right now I only have very, very bare-bones assertions.
I apologize for the size of the patch; I had to install the D6 translation modules, and that obviously added a bunch of (necessary) crap to our database fixture.
Comment #15
steinmb CreditAttribution: steinmb as a volunteer commentedBare with me, getting my feet wet with migrate in D8 (done migrate in D7 though). I might have gotten this all wrong.
Config
Comment #16
steinmb CreditAttribution: steinmb as a volunteer commentedOh, forget #15 bumped into a small issue. For now you need to have CCK enabled in D6 before running. I did run and created content type "Story" and mange to tag the right language to them.
Dump of run
Initialized Drupal 8.0.0-dev root directory at /Users/steinmb/sites/d8/drupal [notice]
Initialized Drupal site default at sites/default [notice]
Executing: mysql --defaults-extra-file=/private/tmp/drush_V47xG0 --database=d8 --host=localhost --port=3306 --silent < /private/tmp/drush_mCD7kM
Executing: mysql --defaults-extra-file=/private/tmp/drush_5Xw2Mj --database=d8 --host=localhost --port=3306 --silent < /private/tmp/drush_aAuXw9
Upgrading d6_date_formats
Upgrading d6_dblog_settings
Upgrading d6_file_settings
Upgrading d6_imagecache_presets
Migration failed with source plugin exception: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'd6migrate.imagecache_preset' doesn't exist: SELECT icp.* [error]
FROM
{imagecache_preset} icp; Array
(
)
Upgrading d6_search_page
Upgrading d6_search_settings
Upgrading d6_system_cron
Upgrading d6_system_date
Upgrading d6_system_file
Upgrading d6_system_image
Upgrading d6_system_image_gd
Upgrading d6_system_logging
Upgrading d6_system_maintenance
Upgrading d6_system_performance
Upgrading d6_system_rss
Upgrading d6_system_site
Upgrading d6_upload_field
Upgrading d6_user_mail
Upgrading d6_user_settings
Upgrading menu
Upgrading menu_settings
Upgrading taxonomy_settings
Upgrading text_settings
Upgrading d6_filter_format
Upgrading block_content_type
Upgrading block_content_body_field
Upgrading d6_custom_block
Upgrading d6_user_role
Upgrading d6_block
Upgrading d6_file
Upgrading d6_user_picture_file
Upgrading user_picture_field
Upgrading user_picture_field_instance
Upgrading user_picture_entity_display
Upgrading user_picture_entity_form_display
Upgrading d6_user
Upgrading d6_node_type
Upgrading d6_node_settings
Upgrading d6_field
Upgrading d6_field_instance
Upgrading d6_field_instance_widget_settings
Upgrading d6_view_modes
Upgrading d6_field_formatter_settings
Upgrading d6_node__page
Upgrading d6_node__story
Upgrading d6_comment_type
Upgrading d6_comment_field
Upgrading d6_comment_field_instance
Upgrading d6_comment_entity_display
Upgrading d6_comment_entity_form_display
Upgrading d6_comment
Upgrading d6_comment_entity_form_display_subject
Upgrading d6_node_revision__page
Upgrading d6_node_revision__story
Upgrading d6_node_setting_promote
Upgrading d6_node_setting_status
Upgrading d6_node_setting_sticky
Upgrading d6_taxonomy_vocabulary
Upgrading d6_taxonomy_term
Upgrading d6_vocabulary_field
Upgrading d6_vocabulary_field_instance
Upgrading d6_vocabulary_entity_display
Upgrading d6_vocabulary_entity_form_display
Upgrading d6_user_contact_settings
Upgrading d6_menu_links
Comment #17
steinmb CreditAttribution: steinmb as a volunteer commentedI have not found time to look at the data structures we created, but looking at the node UI I think we missed something when we exported/defined the content type:
Comment #18
neclimdulI've actually run into the checkbox thing before and even mentioned it in IRC but I failed in my job of creating an issue. Here it is #2572897: Promote and sticky options migrate to empty checkboxes
Comment #19
ultimikeRemoved rouge images from issue summary.
-mike
Comment #20
steinmb CreditAttribution: steinmb as a volunteer commentedTested this again with patch #3 from #2572897: Promote and sticky options migrate to empty checkboxes and the checkboxes now looked OK. YAY!
Comment #21
steinmb CreditAttribution: steinmb as a volunteer commentedDone some more monkeywork. Created two nodes (story, page) with a translation (D6). The content of the translated nodes never make it into drupal 8 fields from what I can tell. Only the node that tnid points to.
I also feel that we should pick up the content type translation settings from D6 and set them in D8. I would think that people would expect that to be done.
Comment #22
steinmb CreditAttribution: steinmb as a volunteer commentedLet me also include a raw dump on a node that should contain a translation:
Comment #23
steinmb CreditAttribution: steinmb as a volunteer commentedComment #24
Gábor Hojtsy@phenaproxima: you don't need any data in locales_* tables for node migration, that should cut down on the patch size definitely.
Comment #25
esclapes CreditAttribution: esclapes commentedThis is a patch with a drupal6 fixture based on a basic multilingual site and dumped with
db-tools.php
after #2568203: Remove migrate-db.sh in favor of core toolsThe configuration/content changes are:
Looking at the patch there are non-related changes in menu-links, which I did not edit. Is that normal?
I also did a bit of manual testing:
drush -y si --account-pass=admin && drush -y en migrate_upgrade migrate_plus language content_translation telephone locale config_translation
drush migrate-upgrade --legacy-db-url=mysql://root:root@localhost/d6_dump --legacy-root=http://d6.dev
No errors except for a
Missing filter plugin: filter_null
, but the migration ignored (as expected?) all multilingual settings and translationsShow language selector on create and edit pages
andEnable translation
were disabledComment #26
steinmb CreditAttribution: steinmb as a volunteer commentedComment #29
xjmDiscussed with @phenaproxima. Given the self-contained nature of Migrate, the fact that it is marked experimental, and the fact that having this available to test would be a huge win, I think this is worth considering as an rc target.
Comment #30
anavarreDon't want to bikeshed this issue but in #16 I've noticed the following, which I could reproduce with RC1:
It doesn't seem to me that we're addressing that issue here and I couldn't find any other existing issue referencing this failure. Have I overlooked something? If not, I'm happy to file a new issue to address just that.
Comment #31
quietone CreditAttribution: quietone commented@anavarre. That is in #2558927: d6_imagecache_presets reports failure for missing table.
Comment #32
alexpottUsing the new "rc target triage" tag - although I thought as migrate was experimental the RC target process should not apply.
Comment #33
phenaproximaA colossal new patch to test with! This implements basic translation migrations for Drupal 6 nodes, with tests -- the translations are migrated along with the node revisions.
The size of the patch is due to the addition of test data. I decided to leave the locale table in there as-is, because the point of Migrate's fixtures is to provide fully working databases that you can quickly spin up real sites to work on (so I'd rather not remove arbitrary pieces of the fixture, even if a particular patch doesn't need them).
Comment #35
phenaproximaFixed failing unit tests. Let's hope I don't have to re-roll that patch ever again.
Comment #36
steinmb CreditAttribution: steinmb as a volunteer commentedNice to see this issue moving again :) That is one scary patch! Trying to help out doing some monkey work. Is this patch supposed to also migrate the translation setting pr. content type?
If so, it is not getting set correctly:
Comment #37
steinmb CreditAttribution: steinmb as a volunteer commentedSorry but still not able to get to work:
Config
There seems to be something missing on the created nodes in D8. Non of the nodes created with migrate can I get the translation tab to show. Resaving the node does not help. Locally created nodes work OK.
Only the data from origin (tnid) get imported. This is a node that in D6 have a translation (two nodes). This is what I dug out of the db after migration. Was expecting to have two entries in node__body field.
Migration run:
Comment #38
phenaproximaI've spent several frustrating days trying to get this to work.
What has become painfully clear is that trying to implement i18n support in a single mega-patch is unworkable and unsustainable. There is a lot of foundational work that needs to be done before node translations -- or indeed, translations of anything -- can be migrated. So I'm wontfixing this issue, but will file follow-ups so that I can submit smaller patches to build up i18n support in logical, bite-sized chunks.
All related follow-ups will be tagged with i18n-migrate.
Comment #39
Gábor HojtsyFor reference, the issues mentioned by @phenaproxima would be at https://www.drupal.org/project/issues/search?issue_tags=i18n-migrate -- I understand it may not be practical to connect all of them back here, but it would be nice to mark this as related issue there, so people can find the broken out issues. I updated #2594263: Add translation data to Migrate Drupal's test fixtures with appropriate related issue and tags.
Comment #40
phenaproximaRe-opening, but postponing until the groundwork has been laid for migrating node translations, and only node translations.
Comment #41
xjmToday the D8 core committers agreed that patches that only change "Experimental" functionality (like Migrate) can be treated as "rc eligible" rather than rc targets. Reference: https://www.drupal.org/core/d8-allowed-changes#rc
Comment #42
Gábor Hojtsy@phenaproxima: now that #2594263: Add translation data to Migrate Drupal's test fixtures landed, should this be reopened?
Comment #43
Gábor HojtsyAlso #2596793: Migrate legacy languages to configurable language entites landed, so I think this should be good to unpostpone?
Comment #44
Gábor HojtsyRemoving from D8MI sprint due to inactivity.
Comment #45
quietone CreditAttribution: quietone commentedAdding parent.
Comment #46
quietone CreditAttribution: quietone commentedComment #47
quietone CreditAttribution: quietone commented@phenaproxima, will you expand on this comment you made in #38. Specifically, what groundwork are you referring to and in what order to do that work.
Thx.
Comment #48
quietone CreditAttribution: quietone as a volunteer commentedIn #38 phenaproxima referred to this patch as a mega-patch. The large size is because it contains a D6 test fixture with an additional language. The work on the fixture was moved to #2594263: Add translation data to Migrate Drupal's test fixtures. Since that has been committed it can be removed from this patch.
Also, this patch includes the migration of the default_language variable which is an issue in itself, albeit a small one, but it has it's own scope. It is now #2657978: Variable to config: language_default [D6 & D7].
So, that should reduce the size of this patch and narrow the scope to migrating nodes.
This patch removes drupal6.php, d6_default_language.yml and MigrateDefaultLanguageTest.php. It still needs to be rerolled.
Comment #49
quietone CreditAttribution: quietone as a volunteer commentedMoved the migration of the node translation settings to #2660028: Migrate node translation settings . This patch removes the files for that test and it still needs to be rerolled.
Comment #50
quietone CreditAttribution: quietone as a volunteer commentedTurns out the test fixture in #35 is needed. So it is back in but it made the reroll difficult.
Comment #51
quietone CreditAttribution: quietone as a volunteer commentedComment #55
quietone CreditAttribution: quietone as a volunteer commentedLooks like I uploaded the wrong patch.
Comment #56
quietone CreditAttribution: quietone as a volunteer commentedThis should be the right patch.
Comment #58
quietone CreditAttribution: quietone as a volunteer commentedThat's better.
Both EntityContentBaseTest and EntityRevisionTest fail because getEntityTypeId is no longer static.
I tried to fix the tests but get this error, "array_keys() expects parameter 1 to be array, null given".
Comment #59
Gábor HojtsyComment #60
vasi CreditAttribution: vasi at Evolving Web commentedI'd like to work on field-translated content from D7. I have code for a completely different approach here: https://github.com/vasi/migrate_field_translated . But I'd like to try the approach you're using here—so would it be possible to split out just the MigrateDestination work from this? I think a less mega-patch approach would work better, anyhow.
Comment #61
quietone CreditAttribution: quietone as a volunteer commented@vasi, I'm too new at this to give a definitive answer. However, in my opinion, since this issue is for D6 nodes, the D7 field-translated content should be a separated issue.
Hoping this patch will fix the errors on EntityContentBaseTest.
Comment #62
Gábor Hojtsy@vasi: is that independently testable, etc? Then it would be nice to cut down on this patch and get a step in IMHO.
Comment #63
quietone CreditAttribution: quietone as a volunteer commentedfor testbot
Comment #65
vasi CreditAttribution: vasi at Evolving Web commentedI think it should be possible to test just the destination, yes. Just create a destination, create a Row manually, ask the destination to import() the Row, see what happens.
I'm a little uncertain about the current design of the destination, though. We assign the same destination ID to two separate input rows—is that considered ok? This means they can't be rolled-back independently of one another; the 'items created' report from migrate_tools can be misleading; the result of an import can be order-dependent... Maybe we should make the IDs a tuple of (entity_id, langcode) instead?
Comment #66
Gábor Hojtsy@vasi: I think the same id makes the translation mapping to the same node possible? I am not well versed enough in migrate to know if this is just an interim mapping, but if its just internal, we should be able to make it more granular, sure!
Comment #67
steinmb CreditAttribution: steinmb as a volunteer commentedFor context, have look back at #37 and #38 where we originally gave up on this mega patch. Config was split out and is now in, but it is still big and hard to test.
Comment #68
quietone CreditAttribution: quietone as a volunteer commentedComment #69
quietone CreditAttribution: quietone as a volunteer commentedAdd parent issue.
Comment #70
quietone CreditAttribution: quietone as a volunteer commentedThis will fix the problem in the previous patch and expose a new one, in the Unit test, EntityRevisionTest. Hopefully, the testbot will report the same error.
What I get is this:
Staring at it and knowing the changes, I guessed that it had to do with storage. This test class prophesized storage but I'm not sure how the parent can make the entity when it doesn't have any storage. It's still not clear to me how the original code works. Anyway, I added storage back into the constructor and the test passed. Good. But other tests failed so not so good.
So, I restored the code to this patch. After some debugging I realized that creating the revision fails in getEntityTypeId. That was changed from static to protected in an earlier patch by phenaproxima. So, the next thing I'd like to do is make sure that the revision is created in the test. Not sure how to do that.
Comment #72
chx CreditAttribution: chx commentedWhile this could be made to pass easily, after all, it's just one test that fails, I completely fail to see what and why is going on here. I am sorry but this is a kitten killer and should be trimmed back if possible. What's the minimal version of this patch that would pass? Is there anything besides the changes in Node and NodeRevision necessary? All the entity destination factory and constructor method changes , I doubt they are relevant. Also, the change in Node / NodeRevision looks atrocious (sorry) just put the "// Do not include translations." into an addTranslationConditions method in Node, override in NodeRevision with a method with an empty body and be done with it. I wonder just those changes, updateEntity in EntityContentBase plus tests, how would it fare.
Also, a merge has failed in MigrateNodeTest .
Comment #73
chx CreditAttribution: chx commentedLet's see this.
Comment #74
chx CreditAttribution: chx commentedThat's not enough. I meant this :)
Comment #76
chx CreditAttribution: chx commentedAlrighty, let's see this one. I attached a do not test patch without the fixture changes for easier review. Edit:
git diff HEAD `git diff HEAD --name-only|grep -v fixtures` > 2225775_76-do-not-test.patch
Comment #78
Gábor HojtsyUnfortunately did not pass. Some review comments:
Would be good to explain why are translation revisions migrated while translated nodes themselves are not? That is basically because we merge nodes along their tnid, so not all nodes are to be created but that would be good to document on the Node class.
Why is the vid condition removed?
Comment #79
vasi CreditAttribution: vasi at Evolving Web commentedMinor bugfix.
Comment #80
vasi CreditAttribution: vasi at Evolving Web commentedComment #81
vasi CreditAttribution: vasi at Evolving Web commentedI think this is so we don't exclude current translations! Eg, suppose I have a translated node:
We turn this into one row from the d6_node source, corresponding to just the English translation (nid 1). Then we produce two d6_node_revision rows, one for the English translation (nid 1, vid 1), and one for the French one (nid 2, vid 2). If we excluded revisions with node.vid = node_revisions.vid, then we would never see the French translation.
However, there are still some issues here. For one thing, the EntityRevision destination is setting
$entity->isDefaultRevision(FALSE);
, which we probably don't want in the case of current revisions. Maybe it doesn't have any consequences though?The patch looks mostly good to me, but I'm a little worried by the result of our test migrations (from MigrateNodeRevisionTest). If I look at the initial D6 DB and the resulting D8 one, here's what I see:
Notice that the current revision in node_field_data is 12, even though revision 13 exists? And we have a fourth revision entry (vid 13 in english). I wonder what happens if we happen to get the node_revisions entries in a different order, do we still get ok results?
Comment #82
vasi CreditAttribution: vasi at Evolving Web commentedAnd now I've added a couple of assertions to test the problem.
What do you think the behavior should be for importing content translation, anyhow? It seems a bit suboptimal for each D8 revision to carry just one language—anybody who reverts to a previous revision will probably be surprised at losing translations. Maybe we can copy in previous translations into subsequent revisions.
Comment #84
Gábor HojtsyYeah ideally all revisions would have all languages and only the ones changed/added there would be different. I am not sure how complicated that is to implement.
Comment #85
quietone CreditAttribution: quietone as a volunteer commentedRight, thanks Gábor Hojtsy. Lets see if I understand.
Say there are two languages in D6. A given node N has 5 revisions for language A and 20 for language B. If I understand correctly, in D8 that node would have 20 revisions with all languages. But, since there isn't a one to one correspondence of revisions, what happens to the 5 revisions for language A?
Lets assume that the first and last revision for node N in both languages would go into the first and last revision in D8. What about the second revision for language A? Does it go with the second revision of language B or another revision? How would one know? What assumptions can be made?
Comment #86
vasi CreditAttribution: vasi at Evolving Web commentedThanks for the reply, quietone! I definitely appreciate the work you're putting in here. My assumptions were different in this case, though. I think if there's eg: 20 english revisions and 5 french ones, that should be 25 revisions overall. It corresponds better with the usual way people edit nodes: one language at a time. So my solution would look like this:
I think our test data needs some improvements for this, too. I'd like to see more revisions, more than two languages, and also fields in multiple languages. I'm not really sure what the process is for adding this, though.
Comment #87
vasi CreditAttribution: vasi at Evolving Web commentedI'm also a little concerned about what will happen with other translated migrations, that aren't D6. We'll want to make sure that any D6-specific strategy we come up with doesn't adversely effect those. The major ones are probably:
* D7 content-translation, which should be very similar to D6.
* D7/D8 field-translation. This has the problem that we'll have multiple source rows with the same nid/vid. I guess we could add a third migration for each bundle, with source IDs (vid, language) or something? Ick.
* Other sources that may not even have a concept of revisions, like manually-editing CSV, or other CMSes. So it would be best if we didn't depend on revisions existing in the source to import multiple languages.
I don't know if this is the best place to discuss all of that, maybe I'll use the META issue. But any thoughts would be appreciated.
Comment #88
quietone CreditAttribution: quietone as a volunteer commentedLike this?
What?
First, let me state that working with the test fixtures (dumps) is, hmm, tedious. There is Generating database fixtures for D8 Migrate tests, which needs updating. For now, I think a few more revisions would be helpful. But anything more would be noise and distracting. Small steps first.
Referring to the test results in #81, for D8 node_field_data. On D8 I see that the node_field_data table has an entry per node per language. So, there should be another one, node 9, vid 12, langcode fr.
Comment #89
vasi CreditAttribution: vasi at Evolving Web commentedHmm, more like this:
Does that kinda make sense? Each revision updates one translation, and keeps the others the same.
Comment #91
quietone CreditAttribution: quietone as a volunteer commented@vasi, thx for helping to realize my misunderstanding about version ids.
Just did a simple MigrateNodeRevision Test and the results in node_field_data and node_field_revision are what I expected. Looking good.
I'm inclined to get this passing tests and then get some feedback from others. I'd rather not change the test fixture at this point.
Comment #92
quietone CreditAttribution: quietone as a volunteer commentedA fix for one Unit test. I'm not fluent enough in unit testing to fix the other one. I'll try again later.
Comment #93
quietone CreditAttribution: quietone as a volunteer commentedComment #95
quietone CreditAttribution: quietone as a volunteer commentedComment #96
vasi CreditAttribution: vasi commentedI think I may have mentioned this in IRC, but I'm not inclined to "fix" the test for EntityRevision. I think it's sub-optimal to change the behavior of all revision destinations just for the one case of tnid-based content translation. The destination that I wrote also depends on order of import, which is also not great.
Instead, I think we should have a source and destination that use a key of tuple(vid, langcode). Then we just need to make our revision source for D6 produce potentially multiple rows per vid. That means we want a query something like this:
Yes, that's kinda long, but not the worst thing I've ever seen. Should be portable and efficient for any DB engine.
Comment #97
vasi CreditAttribution: vasi at Evolving Web commentedRe-rolled, fixed conflicts.
Comment #99
vasi CreditAttribution: vasi at Evolving Web commentedHere's an attempt at the strategy I suggested in #96. I also added some more test coverage, including partial imports (which would break with the previous approach).
Comment #101
vasi CreditAttribution: vasi at Evolving Web commentedFixed the tests, I hope.
Comment #102
vasi CreditAttribution: vasi at Evolving Web commentedI tested it out on an actual D6 site, and it went well. Except that the translation of the default revision wasn't being populated, because EntityRevision always calls
isDefaultRevision(FALSE)
. It works better if I change EntityRevision to check if it's the default revision or not.An alternative would be migrating translations in the node migration, and making node revisions always not the default. But then we'd need a two-column source/destination ID for Node, which would make the migration process hard to use—so I prefer just making EntityRevision check for defaults.
Comment #103
Gábor HojtsyThe strategy explained in #89 sounds good to me.
Comment #104
quietone CreditAttribution: quietone as a volunteer commented@vasi, this looks really good. Just a few comments/questions.
I'm all for tests but what is the use case here? Why do we need to test for partial node revision migrations?
The comments make perfect sense to me and are easy to read, but are ellipsis allowed in comments? And if they are, shouldn't there be a space before and after it?
Since the addition of translations has increased the complexity of both the Node and NodeRevision source plugins, particularly the latter, can the respective class doc block include some explanation of what it is doing?
Finally, the queries in Node.php and NodeRevision.php really need a more practiced eye to look at them.
Comment #105
vasi CreditAttribution: vasi at Evolving Web commentedHey, sorry for the delay, and thanks for the reviews. I realize I haven't given a very complete explanation of what this patch does now, and why. So here's a start.
Let's look at an example, suppose we have a node that started in English. Then it was translated into French, changed a little in English, and finally translated into German. Our D6 data would look like this:
In the old version of the patch, the source would generate four rows, one per revision:
This is simple, which is good. But then the EntityRevision destination had to do special processing to find the previous revision, and bring its translations along. This had a few downsides:
The migration becomes fragile—it breaks if revisions are migrated out of order, or if one revision is skipped. There are a bunch of ways this could happen:
drush migrate-import
, which then imports just some revisions.In any of these cases, when a revision row is skipped, all subsequent revisions would not be able to find it. They would be migrated without the content from that revision, so we could end up with nodes missing entire translations, or subtly broken data.
This is why I wanted to test "partial [..] revision migrations". I don't think we want recommend this use-case to users! But it's not hard for someone to end up there, intentionally or not, so we need to make sure it doesn't Break All The Things.
The new version of this patch tries to get rid of these issues. Instead of our source generating one row per revision, we now generate multiple rows. Each row corresponds to one translation that existed at the time of that revision. So in our example, we'd generate this:
As you can see, this is a bit more complex. The unique ID is no longer just 'vid', but a tuple of ('vid', 'language'). But now we avoid the problems from before:
I hope this makes more sense now. I admit my code could use some more explanation too, so I'll go over it again and try to add that, especially for the DB queries.
Thanks @quietone for catching the comment formatting issue, I'll give that a shot too.
Comment #107
mikeryanComment #108
mikeryanComment #109
BerdirThis will need a complicated reroll will all the changes that happened, e.g. migrations to plugins and kernel test conversions.
That said, If you're like me and don't care about all the revisions stuff but just want to import the latest revision, all you need from the patch is this part: https://gist.github.com/Berdir/9ac6aa8c7bc4f2fbc287ac6a3512c17d.
And then set up the nid/tnid mapping like this: https://gist.github.com/mikeryan776/2bd2bbf6c17bd09abcb74422e280288f (thanks @mikeryan!). Note that field_whatever is nid, A is tnid and B is nid. Also, you very likely want to remove vid from the mappings and let it generate a new one, otherwise translations might get messed up.
That worked quite nicely for me. One thing I noticed is that content_translation_source won't be imported like that, but I think it won't be set either with the full patch? I've seen problems caused by a missing source language in the field synchronizer code.
Comment #110
quietone CreditAttribution: quietone as a volunteer commentedFirst go at a reroll.
Comment #112
vasi CreditAttribution: vasi at Evolving Web commentedBerdir, if you have any nodes that are translated you'll also need to turn track_changes on. Otherwise migrate will just skip the rows for the second language.
Comment #113
vasi CreditAttribution: vasi at Evolving Web commentedI looked at the failing tests:
Also had to reroll because of conflicts, so I don't have an interdiff.
Comment #114
vasi CreditAttribution: vasi at Evolving Web commentedComment #120
xjmDiscussed with @alexpott, @weal, @benjifisher, and @mikeryan. #1952044: Migration path for legacy content translation module data is probably a duplicate of this issue. From that issue:
There is also a potential problem with links in e.g. the body field. If you have:
<a href="/node/5">Link!</a>
And node 5 was a translation of node 3 and now it's node 3. All your links like the above are now broken.
So we should create followups for all of those tasks.
Comment #121
quietone CreditAttribution: quietone as a volunteer commented@vasi, thanks for adding the comments, it really helps.
Regarding the points in #113.
This patch is expected to fail on MigrateUpgrade7Test.
Comment #123
quietone CreditAttribution: quietone as a volunteer commentedFailed as expected. I still don't see the solution, nor why this is only occurs in D7.
The error msg from migrate_message_d7_user table:
Invalid translation language () specified. (/opt/sites/d8/core/lib/Drupal/Core/Entity/ContentEntityBase.php:823)
Edit: Fix copy/paste error. The original error msg shown was wrong and has been replaced with the correct one. Thanks to mikeryan for questioning that msg on IRC.
Comment #124
vasi CreditAttribution: vasi at Evolving Web commentedI think the d7_user issue is just happening because we have a mapping ' langcode: language'.
I'm not sure if that mapping makes sense? I thought "language" in the D6/D7 users table was supposed to mean "the language this user prefers for communication", not "the default translation for this entity".
Comment #125
mikeryanAh, I see, d7_user.yml has:
So, it looks to me like preferred_langcode is the right mapping, but as you point out the D8 langcode here is for translation of the user entity, not for their language preference. D7 didn't have translation of user entities, right? So we should just remove that langcode mapping...
Comment #127
vasi CreditAttribution: vasi at Evolving Web commentedComment #129
vasi CreditAttribution: vasi at Evolving Web commentedTrying to fix MigrateUserTest. Until we have translated user migrations, we should assume the user's langcode is the site default. Their preferred langcodes could still be migrated.
Comment #130
mikeryanFirst step in testing against my client's db is rerolling for 8.1.x...
Comment #132
mikeryanA little naming change between 8.1.x and 8.2.x...
Comment #133
vasi CreditAttribution: vasi at Evolving Web commentedWe observed that this only works properly when migrating revision IDs (vids), keeping the same ones in D8 as D6. If new revisions are generated, then there's no way for different-language-versions of the revision to find the same revision ID.
We're going to need a way to query the id_map by partial source IDs.
Comment #134
vasi CreditAttribution: vasi at Evolving Web commentedComment #135
mikeryanPostponed on #2724941: Need to be able to lookup destination IDs by partial source IDs.
Comment #136
bwinett CreditAttribution: bwinett at Danaher commentedSummary of testing I just did (tl;dr - looks good to me!)
I:
In new 8.1.1 site:
At http://d8test/upgrade, Page informed me that the following are missing from the upgrade path.
Clicked on "Perform upgrade" button. Got message:
Completed 61 upgrade tasks successfully
Congratulations, you upgraded Drupal!
And it provided a link to the detailed log.
It created a single row in the node table, nid=1, vid=4, langcode=en
It created 4 nodes in the node_revisions table:
It created 8 rows in the node_revision_body table:
It created 3 rows in the node_field_data table:
It created 8 rows in the node_field_revision table:
Comment #137
esclapes CreditAttribution: esclapes as a volunteer commentedI followed the instructions from #109 as I don't care about revisions, and it works. However, I was wondering if the last line in that comment might be relevant:
I have used this code in addition to the patch linked in #109 to update it and seems to work for me:
Comment #138
vasi CreditAttribution: vasi at Evolving Web commentedHere's a first attempt at migrating nodes with the new destination-lookup. It doesn't yet include node revisions, just nodes. Probably some tests will fail.
Comment #140
vasi CreditAttribution: vasi at Evolving Web commentedAgain, just nodes, not revisions. Maybe we should just review it this way? We could do a follow-up issue for revisions, which are much more complicated. It would be great to get one example of a migrated translated entity in core, so we can work on all the other entities.
Some issues that need thinking about, and maybe some testing:
* Is anything here actually order-dependent? Is it ok if non-default translations are imported first?
* Are we ok with the way import/rollback aren't symmetrical? When we import a row, we either add an entity, or add a translation to an existing one...but when we rollback a row, we remove the whole entity. I don't think there's a better solution until this is closed: https://www.drupal.org/node/2443991
* Make sure that the 'migration' process is working right, now that we have two-column source IDs for nodes. Might already be a test that exercises this?
Comment #141
vasi CreditAttribution: vasi at Evolving Web commentedGrr, patch didn't attach.
Comment #143
vasi CreditAttribution: vasi at Evolving Web commentedI had the User migration default to the site's default language code. I think that's a reasonable solution to that problem.
For the term_node issue, I had to mess with the 'migration' process. I'm not sure I like the result:
But I guess that's what's needed now that node migrations have two source keys. It would be nice to be able to say something like this instead, maybe a future enhancement?
Comment #144
vasi CreditAttribution: vasi at Evolving Web commentedAlso, I tested out rows where the default language isn't the first. We end up creating a node with the wrong default language, no good. Not sure what the right solution is here.
Comment #145
esclapes CreditAttribution: esclapes commentedVasi, I think you can also have a
tnid == 0
, at least that is the case in some rows in my node_export csv. I guesstnid
gets populated when there is at least one translation, but not sure.Comment #147
esclapes CreditAttribution: esclapes as a volunteer commentedReading again your question, I would say that D6 default language has no direct relation with the source node. You could have source nodes in any of the enabled languages. Source nodes do have
tnid == nid
set.So far I did not have any problem with that in D8. My imported entities get created in order and can have a different source language, even if it is not the site's default. In each case
x-default
is assigned for the first entity:This might be a problem in D7, where field translation was possible, though.
Comment #148
mikeryanSome initial review - @vasi, can we get some time tomorrow to walk through this in #drupal-migrate?
I'm not sure I see where source_language_keys could be multiple (i.e., why is this not source_language_key)?
Since the purpose of this function is to generate modified destination IDs, I'd rather see them returned rather than modified as a side-effect.
On the source side, nid alone should always be unique, no? Why add language to the source ID?
If I'm not mistaken, this is assuming the maximum vid is the active revision for a given language? Shouldn't it be the vid matching n.vid?
Comment #149
vasi CreditAttribution: vasi at Evolving Web commentedI'll change that back to singular. Just erring on the side of generality.
Ok, will do.
Yeah, that's true for D6 content translation. I was trying to make things the same for content-translation and entity-translation, so that all the related migrations don't have to change depending on that.
<
Yes. Maybe I should rename this function. It doesn't find the maximum node_revisions.vid, it finds the maximum node.vid in the current translation set. This is important so that we don't try to import multiple translations of the same node, that each claim that the current revision is something different, that really confuses Drupal.
Comment #150
mikeryanWell, after hurting my head trying to deal with the whole patch here, I've implemented a custom solution for my current client which is quite simple and (based on *very* minimal testing) seems to work. Keep in mind that in my case we don't care about revision history, and also that we are not preserving nids and vids.
First thing is, defining separate migrations for the primary/default translation, and for other translations, which addresses the need to get the default translation right when the node is originally created. To accommodate this, I added a 'translation' configuration property in my source plugins (derived from d6_node) - when the value is 'primary' I filter the query on
n.tnid=0 OR n.tnid=n.nid
, when 'secondary' the filter isn.tnid>0 AND n.tnid <> n.nid
.So, for my node_bio migration, the only change I make is to add that configuration value:
I copied that node_bio migration to make a node_bio_translation migration - apart from changing the id and label, these are the only differences:
Finally, I implemented an entity:node destination plugin to override updateEntity with the same bit the existing patches do here for adding/getting the translation:
So, would this approach work in the general case? How will the revision migrations deal with this?
Comment #151
vasi CreditAttribution: vasi at Evolving Web commentedI think we should handle revisions in a follow-up, and get just nodes themselves working in this issue.
I think this approach will work ok, but it will require each and every entity to have two migrations, with the exact same process steps. For now we can just have the deriver do double duty. In a follow-up we can find a way to make it easier on users writing their own migrations.
Comment #152
vasi CreditAttribution: vasi at Evolving Web commentedHere's a first try at the new approach.
Comment #153
vasi CreditAttribution: vasi at Evolving Web commentedComment #155
vasi CreditAttribution: vasi at Evolving Web commentedFixed some tests, I think.
Also added some new tests:
* Ensure that non-Drupalish content (without nids) can be imported with translations.
* Ensure that rolling back translations works.
One issue I've thought of: What happens to node references that refer to non-default translations? You can't use a 'plugin: migration' against the node migration, since the translations won't be there, so we'll need to refer to the node_translation migration instead....ick.
Comment #157
vasi CreditAttribution: vasi at Evolving Web commentedI changed 'tnid' in the source output so it is consistent and always means "the current translation set", even if there's just one node in it. This lets us use it in the process for 'nid'. Tests needed updating.
Comment #159
vasi CreditAttribution: vasi at Evolving Web commentedComment #160
mikeryanSome comments based on a quick review, but I still need to dig a bit deeper (and test manually).
Is the user module stuff really in scope? The node translations aren't dependent on that, are they?
Anything else we can break out so make the patch more manageable/reviewable? Like, maybe the destination-side support for translations (tested with non-Drupal data) could be a separate issue...
I'm curious why this is added?
EntityConfigBase::updateEntity() should also return the entity.
We've stuck with the migration_templates directory for core modules already using it, but I think new test modules should use the favored 'migrations' directory.
I'd rather spell it out - default_language. Although, is it more accurate to call is 'default_translation'?
Dupe line.
I would make this
@todo: Remove when https://www.drupal.org/node/2560795 is fixed.
Perhaps we should install de? I'm not sure this is proving much, how would a node acquire a translation for a language that isn't even installed?
Rather than have a .yml which is a near-identical copy of d6_node.yml, could we have the deriver create it?
Comment #161
vasi CreditAttribution: vasi at Evolving Web commentedIt turns out a bunch of tests break in the presence of languages, or nodes with languages. So this is needed to keep tests green. We could try splitting it out if you'd like.
There are a bunch of different subclasses that override this method. I made returning the entity optional so that I don't have to change all of them. Is that ok? Would you rather I change all of them? Or just change the base class?
This is part of an test of non-Drupalish data being imported, since that was a problem with a previous version of the patch—thanks for finding that! I intentionally chose a name different from Drupal's here, to make sure we weren't relying on it being the same.
Yeah, it's perhaps a bit unlikely that we'd assign a random language. Maybe I'll take it out.
And the same for node_revisions. Maybe let's do that as a follow-up?
Everything else you mentioned sounds correct, I'll update the patch.
Comment #162
vasi CreditAttribution: vasi at Evolving Web commentedComment #163
mikeryanI've run this with a real D6 site on 8.1.x (latest patch applies to 8.1.x cleanly) and translations were properly migrated. I think everything in the code review that needs to be addressed has been, so to me this is RTBC. I'd like to get more eyes on it, though, in particular someone with in-depth understanding of the D8 translation system (e.g., Gabor).
Comment #164
vasi CreditAttribution: vasi at Evolving Web commentedComment #165
penyaskitoGábor asked me to review this one. Assigning it, as I think it's complex enough for needing more time to actually test it.
This is a first code review pass, but first of all, I'm impressed how good this looks and it's simpler than expected (as simple as this could be).
Nitpick: we need to add @return to the phpdoc.
If I'm re-migrating a translation, and I have already one, I'm deleting it. It's that really ok?
What happens when there is no multilingual site? Is tnid there?
Ok, this answered my question, but it's tricky. Let's add a comment in the migration for clarification?
Yep. This. Let's add a comment in the migration for clarification.
Typo. Query.
Comment #166
vasi CreditAttribution: vasi at Evolving Web commentedThanks for the review, @penyaskito. Most of those I can fix up. I'm not sure I understand this though:
This is in rollback(), so it only happens when you rollback a translation that you previously imported. What's the behaviour you're expecting?
Comment #167
penyaskitoI'm thinking about incremental migrations. If I already succeeded running a migration, I will have a node with a translation. If that node runs again, and something happens that ends up with a rollback, I'm deleting the translation, not only the one I just imported but the existing one.
It doesn't look like critical to me, but maybe we can think of better options here. In any case that could be part of a follow-up.
Comment #168
mikeryanMigrate's rollback is a distinct operation from import - it only happens explicitly (drush migrate-rollback), it's not something that gets called during import when there's a failure.
Comment #169
vasi CreditAttribution: vasi at Evolving Web commented@mikeryan already addressed that rollback only happens explicitly. But I should also add that we detect existing translations, in which case we don't delete on rollback. See EntityContentBase::updateEntity() :
Comment #170
penyaskito@mikeryan, @vasi: Thanks, clear now :)
Comment #171
penyaskitoOK, I have tested this with a site. I set it Story content type as translatable in D6, and created two stories: one in English and one in Neutral language. I've translated the English one to Spanish.
I run the migrations on the Drupal 8 site using the experimental UI, and the node in Neutral was assigned the "Language not specified" language. The English node and its translation was assigned the right language, and both translations were in the same node as expected. So in terms of migration, it works perfectly.
The only thing I somehow missed is that the source translation is not migrated. I added another translation manually in the D8 site and got it filled:
I think that we can assume that the source translation is the original tnid, but in any case I wouldn't block this on that, we can create a follow-up.
I would RTBC this one, but the points in #165 are quick to fix, so better if can do them before committing.
Amazing job everyone :)
Comment #172
Gábor HojtsyFixing title. The node translation feature is not specific to i18n module.
Comment #173
penyaskitoGábor asked for clarification on what I meant here on IRC. I was referring to the "source language" column in that table, the original source of the translation. I still think it's ok to do in a follow-up.
Comment #174
mikeryan@penyaskito: So, what do we need to get this to RTBC? I feel I've been a little too closely involved with this (suggesting the approach of a separate translation migration), and I'm also not particularly translation-fluent, to do it. Do you feel confident enough in the last patch to set to RTBC?
Comment #175
vasi CreditAttribution: vasi at Evolving Web commented@mikeryan: I'll fix the minor issues @penyaskito identifier tonight. Then hopefully it can go RTBC! Sorry for the delay.
Comment #176
Gábor HojtsyYeah the source translation would/should be as indicated by the tnid yes, Drupal core translation in 6/7 does not have another way to identify if you translated from a different source. It is fine to fix in a followup or here as appropriate.
Comment #177
vasi CreditAttribution: vasi at Evolving Web commentedOk, this should handle the issues @penyaskito identified above.
Source translation looks more complicated, it'll take an extra join on the node table to figure that out. So let's leave it for a follow-up.
Comment #178
penyaskito@mikeryan and I tested the patch at #162, and the new one only includes comments fixes, so it's good to go.
All the concerning issues have been fixed.
Created #2746293: Migrate content_translation_source when migrating node translations as a follow-up. We need to check if the follow-ups at #120 have been created.
For me this is RTBC. Thanks everyone :D
Comment #179
vasi CreditAttribution: vasi at Evolving Web commentedI created some follow ups:
I also updated the META issue #2208401: [META] Remaining multilingual migration paths with all the follow-ups.
I'd also like to look into how to adapt the solution we have to non-D6 migrations, just to make sure we don't end up making those impossibly hard.
Comment #180
Gábor Hojtsy@vasi: yeah the D7 node translation schema / data structure is the same as D6 I think, so the D7 to D8 should be the same except of course dedicated test coverage :) Thanks for opening those followups.
Comment #181
mikeryan#2607524: [meta] Migrations from Drupal 8 to Drupal 8 and Drupal 8 to Drupal 9
Comment #182
vasi CreditAttribution: vasi at Evolving Web commented@Gábor Hojtsy: As you know, many (most?) D7 sites use D8 style field-translation with the entity_translation module. And of course we'll have to support D8-to-D8 migration too at some point! So we'll have to figure out a way to support that.
Comment #183
penyaskitoAll follow-ups have been created, so removing tag.
Comment #185
vasi CreditAttribution: vasi at Evolving Web commentedRe-rolled after #2598038: Invalid passwords after D7 to D8 migration. Fixed some minor conflicts in d7\MigrateUserTest.php.
Comment #186
penyaskitoReviewed the conflicts parts, still looks good to me if green.
Comment #187
steinmb CreditAttribution: steinmb as a volunteer commented+1 from me. BTW, did we create a followup issue on supporting entity translation (entity_translation)? Do not see it listed as one of the child isssues.
Comment #188
Gábor Hojtsy@steinmb: yeah I only found #929402: Add support for migrate module which is a destination handler for entity_translation D7. I think that issue still needs to be opened. Not sure it logically/technically should be a children of this one since the two translation methods are different and entity_translation was not in core either. It should definitely be a related issue.
Comment #189
alexpottIs this exception tested?
assertNull and assertFalse should have an assertion message
No need for a comma before the or.
Might be worth saying "An SQL expression..."
If we're going to break everything up like this - no need to call the variable
$subquery
. I'm not convinced of having both maxVidQuery() and translationQuery(). Do we envisage needing this break up of logic?Should be static:: for late static binding.
The comma here is not needed.
Comment should break on 80 chars - also the second sentence is not clear what is meant.
Rather than asking a question in the comments I think it is clearer just to say which each statement is.
This assertions need messages.
Why is an issue titled "Migrate Drupal 6 core node translation to Drupal 8" changing Drupal 7 migrations? Ah I see there is some discussion of this already (for example #125). In one of the comments @mikeryan suggested splitting this out as a blocker for this. I think that is a good idea given the complexity of this issue. Obviously it's a blocker for this issue and things might take a little bit longer but it means reviews are more likely to catch mistakes because this is complex stuff.
Could just inject the language.default service for a less heavy dependency that's what you're getting with the first call on the languageManager
Comment #190
vasi CreditAttribution: vasi at Evolving Web commentedOk, here's an update. What's changed:
Comment #191
vasi CreditAttribution: vasi at Evolving Web commentedAdded a test for D6NodeDeriver.
Comment #192
vasi CreditAttribution: vasi at Evolving Web commentedAdded a follow-up for the user language code issue: #2751223: D6 & D7 users are migrated into D8 with incorrect langcode
Comment #193
penyaskitoAll the comments from #189 have been addressed. The user migrations changes are gone from this patch with the new strategy described in #180.1. The follow-up has been created.
So IMHO this is good to go.
Comment #194
catchThe follow-ups all look good, left some comments on a couple of them, thanks for opening.
Why does this have to be null/entityinterface vs. just returning the $entity all the time?
Looks ready to me too otherwise.
Comment #195
vasi CreditAttribution: vasi at Evolving Web commentedI just didn't want to change BC. There are destinations that extend EntityContentBase all over core, definitely in my custom code, and probably in other peoples' code too. If it's this easy to keep them working, I think that's a plus.
Comment #197
Gábor HojtsyLooks like some legit fails in migrate :/
Comment #198
vasi CreditAttribution: vasi at Evolving Web commentedOk, I investigated the failures. They're coming from #2225271: Migrate content type language settings from Drupal 6 & 7. I think there's two things going on:
Comment #199
vasi CreditAttribution: vasi at Evolving Web commentedI think this fixes it. Let me know if you like/dislike the approach.
Do we want a new issue for this problem?
Comment #201
vasi CreditAttribution: vasi at Evolving Web commentedForgot to commit a file :O
Comment #202
Marc Angles CreditAttribution: Marc Angles commentedWorking on a D6 > D8 migration since several days.
I've worked with drupal stable until I wanted to try this patch.
On drupal-8.2.x-dev and all the dev modules (migrate_tools, migrate_upgrade, migrate_plus) at first glance it is working well, translations are mapped and language switcher works.
However the images (image fields) appears to be migrated into the english translation.
Great job @vasi. Thanks.
Comment #203
vasi CreditAttribution: vasi at Evolving Web commented@Marc Angles: Can you clarify what happened?
* Did the translated nodes have images in D6?
* Did the image files for these translations not get applied to the other translations in D8?
* Were there other fields in translated content? Did they migrate ok?
Comment #204
vasi CreditAttribution: vasi at Evolving Web commented@Marc Angles: Can you clarify what happened?
* Did the translated nodes have images in D6?
* Did the image files for these translations not get applied to the other translations in D8?
* Were there other fields in translated content? Did they migrate ok?
Comment #205
Marc Angles CreditAttribution: Marc Angles commented@vasi,
* My setup is fr/en, the drupal 6 source has 'French' as the default language
* yes, drupal nodes have images in D6. Using image field. And using the "synchronize translation" feature (if it may be relevant...). So, in drupal 6 the images can be edited both on each translation but they are synchronized (when one image change in the field, it changes for both nodes).
* Now in drupal 8, I get the images imported in the images fields of English nodes but not in the french ones
* There where other fields and also aliases. The fields are ok in the english version but except the titles none are populated on the the french translation.
* On the other hand, aliases are applying only on the french nodes... (there is no url aliases on english nodes)
Comment #206
vasi CreditAttribution: vasi at Evolving Web commentedOk, the "synchronize translations" feature is interesting. I didn't remember about that at all. I think the right solution to that is to change the content translation settings in D8 so that those fields are marked as untranslatable
Are the other fields you have also "synchronized"? Or are they normal translated fields, that somehow weren't imported into the french translations? I think we are testing that case, but maybe something is going wrong.
Comment #207
penyaskitoI would say we should create a different issue for the image problem, as this may be a special case that happens with other field types too (thinking at least on entity references).
For the aliases, we should do the same and investigate if it's related to #2689459: If you don't want to translate your URL alias, the original URL alias won't work with your translations. The path field is so special I'm not surprised you run into this, but not sure if we should stop this because of that one neither.
Comment #208
Marc Angles CreditAttribution: Marc Angles commented@vasi, yes, almost all the fields I'm working on are "synchronized" in drupal 6
Other field that cause some headaches are taxonomy terms, I try to report the problems here: https://www.drupal.org/node/2653984
Comment #209
Berdirsynchronized fields is a feature of the i18n module(s). Since the title specifically says Drupal 7 core node translation, maybe supporting that should be a follow-up issue? I have a feeling that's not going to be trivial.
Comment #210
Gábor HojtsyYeah I agree synched fields is/was an i18n module feature, and this core migration is complicated enough already to try to include more :) Should be possible in a followup.
Comment #211
vasi CreditAttribution: vasi at Evolving Web commentedAdded a follow-up for synchronized fields: #2754493: D6 synchronized field settings aren't migrated properly
Comment #212
Marc Angles CreditAttribution: Marc Angles commentedI doubt the "synchronization" feature have anything to do with the problems we have when running the upgrade.
I modified the source DB so there is no more synchronization and the problems are still there.
* All the 'en' nodes are correctly migrated (except their url aliases)
* The 'fr' nodes are having their url aliases but are missing their bodies and images
* for the terms, there might be a fix here https://www.drupal.org/node/2653984#comment-11333199
Comment #213
steinmb CreditAttribution: steinmb as a volunteer commented@Marc Angles did you see any errors/warnings during the migration? If so, could you post them?
Comment #214
penyaskitoRerolling (automerge worked). No functional changes so hope I'm still eligible to RTBC.
This is unused. Removed this and some other minor complaints from phpcs. Interdiff attached.
Comment #215
penyaskito@Marc Angles I tried this again, and it worked for me. I have article nodes, with title and body fields filled.
My neutral node was migrated to a Language neutral node, as I would expect.
My english node was migrated to a English node as I would expect.
My spanish node, being a translation of the English one, was migrated as a translation of the english one.
Didn't really try images, as I'm sure we will need to work on that and @vasi already created a follow-up, which Berdir and Gábor agreed to.
So unless @Marc Angles or someone else can explain how to reproduce the issue of not having bodies migrated, I would love to RTBC and move forward.
Comment #216
penyaskitoTagging for the sprint.
Comment #217
Marc Angles CreditAttribution: Marc Angles commented@penyaskito to me it seems related to the content_translation_* columns not being in the fields tables at the right time. I did not save the logs but I remember having to run something like drupal update:entities to get those columns added. However, the upgrade was not complete after that and I had some other things to do.
This patch seems to be a huge improvement in any case.
Comment #219
penyaskito@Marc: the way translations work in core doesn't require content translation to be installed actually for doing translations through the API, so those columns are not even mandatory if you want to manage your translations without content translation module. We have a follow-up for that one: #2746293: Migrate content_translation_source when migrating node translations.
Comment #220
Gábor HojtsySeems like the patch application fails are not a biggie, but I have issues rerolling it on my local setup, so sorry but cannot help right now. The fails are in MigrateNodeTest.php and d6_node_translation.yml
Comment #221
Marc Angles CreditAttribution: Marc Angles commentedOk, I restarted my upgrade process from scratch and everything looks correct now, in terms of translations.
Comment #222
quietone CreditAttribution: quietone as a volunteer commentedReroll. Result in an error in MigrateNodeTest on the test that a link field with an internal link is migrated.
$this->assertSame('internal:/node/10', $node->field_test_link->uri);
Comment #224
vprocessor CreditAttribution: vprocessor at Skilld commentedComment #225
vprocessor CreditAttribution: vprocessor at Skilld commentedrerolled
Comment #227
vprocessor CreditAttribution: vprocessor at Skilld commentedComment #228
Gábor Hojtsy@vprocessor: planning to work on the fails?
Comment #229
Gábor HojtsyThe fails sound very relevant:
Comment #230
quietone CreditAttribution: quietone as a volunteer commentedThis looks like it is because of a problem with the dump file. Nid 9 revision 11 is a content type planet and nid 9 revision 12 is a content type story. There is a previous issue about this type of problem, #2686651: Same nid in two content types in d6_dump. But that is all I can do on this now. I should be able to look more thoroughly into that this evening (6 hours from now).
Comment #231
mpp CreditAttribution: mpp at AmeXio commentedAny chance we could have some documentation on how this is supposed to work?
Is this all that is needed?
I want to migrate translations in different rows to the same node so it should work with this patch (once it's fixed) or am I missing something?
Source:
for id=id1 lookupDestinationId returns
So it seems that the English version is missing?
Note that I am using a different source plugin (migrate_source_csv) but as it also uses the Sql id_map that should work, or is something else needed to support migration of translations?
Comment #232
quietone CreditAttribution: quietone as a volunteer commentedI hope it is OK that I'm uploading a patch while this is assigned to someone else. I'm doing so because it is tagged migrate critical. Please let me know if I should have waited.
Comment #234
Gábor Hojtsy@quietone: well, @vprocessor went inactive on this, so I think its fine that you took it over, thanks!
Comment #235
quietone CreditAttribution: quietone as a volunteer commentedThe previous patch was made with a test version of the test fixture. So ignore that one. (I wish I had a quiet place to work). Anyway, this new patch passes tests locally. The interdiff is against the patch in #225.
Comment #236
quietone CreditAttribution: quietone as a volunteer commented@Gábor Hojtsy, thanks!
Comment #237
Gábor HojtsyWhy did you remove the node access dataset? That looks totally unrelated. The rest of the changes look logical based on the explanation in #230.
Comment #238
penyaskitoThanks quietone for working on this!
Attended #237 by applying the related chunk of the interdiff as a reverse patch, let's see if the bot is happy now.
Comment #239
Gábor HojtsyLooks good now, yay :)
Comment #240
quietone CreditAttribution: quietone as a volunteer commented@Gábor Hojtsy,
Oversight on my part. (We have a baby visiting and I'm not getting as much sleep as usual.) Thanks for spotting it.
Comment #241
chx CreditAttribution: chx commentedtwo and half years later or not: YAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY someone did it! Thanks so much for your hard work.
Comment #242
Gábor HojtsyWhile this issue is a monumental achievement (especially once it lands #hinthint), there are many more (admittedly mostly smaller) issues to make multilingual migrations semi-complete: https://docs.google.com/spreadsheets/d/16SwQsp7nF1UKrZQCNdPYML_wi53ZjM1e...
Comment #243
alexpottThis looks an excellent start and all the followups are in place so I've committed and pushed 1fa26afd9618278aa98334eb15514a2e18cbefd6 to 8.2.x and 169c290 to 8.1.x. Thanks!
It'd be great if someone could answer @mpp's question in #231
Comment #245
mikeryan/me returns from an unblocking spree...
Thanks to everyone who put in such hard work on this!
Comment #246
Gábor HojtsyThis is amazing, thanks everyone :) #highfives
Comment #247
kriboogh CreditAttribution: kriboogh at Calibrate commented@mpp: we did it like this (from a JSON file):
You need two migration configs.yml files, one for the sources and one for the translations.
edit: your source plugin must return only the "source" data for the my_sources.yml file and the "translated" data for the my_translations.yml file. So if you use a custom source plugin make sure you filter the source data before using if by overriding the protected function initializeIterator() {}.
migrate_plus.migrations.my_sources.yml:
migrate_plus.migrations.my_translations.yml:
JSON source data:
Comment #248
mpp CreditAttribution: mpp at AmeXio commentedHi @kriboogh, thanks for the follow up. Are you using track_changes? See https://www.drupal.org/node/2749989, I've seen some bizarre effects with track_changes after this patch got in.
Another way of "filtering" the proper sources is by using a specific PREPARE_ROW:
Comment #249
kriboogh CreditAttribution: kriboogh at Calibrate commentedno not using track_changes at the moment. Yes prepare row is also a good alternative, although I wanted the counts (number of rows to import, processed, ignored) to be correct when you show the migration status, so that's why I did it in the initialise iterator.
@mpp A bit of topic perhaps, but any reason why you used a subscribe event in stead of just overriding the prepareRow function in the extended source? Or didn't you use in a source class?
Comment #250
Gábor HojtsySo #2669964: Migrate Drupal 7 core node translations to Drupal 8 would be the next step and should be straightforward hopefully because its the same logic, probably some "new" tests and done(?) :)
Comment #251
webchickThis seems like a pretty big deal. :)
Comment #254
mpp CreditAttribution: mpp at AmeXio commentedThe patch no longer applies to 8.1.8.
Comment #255
Gábor Hojtsy@mpp: well, it was committed on 8.2.x and is not supposed to be maintained for 8.1.x as it will not get committed there.
Comment #256
mpp CreditAttribution: mpp at AmeXio commentedWell I must have missed this: " I've committed and pushed to 8.2.x and 169c290 to 8.1.x."
So it is in 8.1.8? which would explain the patch failing :-)
Comment #257
Gábor HojtsyIndeed, the commit does not seem to have appeared as a comment here, but the files are there. Eg. http://cgit.drupalcode.org/drupal/tree/core/modules/node/migration_templ... Also https://www.drupal.org/project/drupal/releases/8.1.8 lists this issue as well being fixed.
Comment #258
m.c.t CreditAttribution: m.c.t commentedIs there a way to get a full working example ?
I am struggling to implement this solutions as when I imported my translation, I get the error:
Migration test_fr did not meet the requirements. Missing migrations test_en. requirements: test_en.
But the dependency is there on my translated config file:
migration_dependencies:
required:
- test_en
Also I am migrating sources from mySQL, source is extending SqlBase, not sure if it makes a difference
Comment #259
quietone CreditAttribution: quietone as a volunteer commented@m.c.t, Welcome!
You'll get a better response if you ask for support in a new issue. This is closed and will have less folks looking at it. Just create a new issue using category 'Support request'. If you use IRC you can also ask in #drupal-migrate on Freenode.
Cheers
Comment #261
Gábor HojtsyRemoving from sprint, thanks all again!
Comment #262
pbattino CreditAttribution: pbattino commentedEven if this is closed: I keep ending here if I google the error that m.c.t and that I also got.
Since I managed to solve it for me, I post my solution:
Migration test_fr did not meet the requirements. Missing migrations test_en. requirements: test_en.
I had to change the way the requirement is stated. As the example in#247 but with "migration." prepended to the name of the migration.
Instead of
I had to write