Problem/Motivation
Language negotiation setting variables should be migrated separately from #2166875: Migrate D6 languages.
Proposed resolution
Involved variable: language_negotiation
Possible values in D6:
- LANGUAGE_NEGOTIATION_NONE => t('None.'),
- LANGUAGE_NEGOTIATION_PATH_DEFAULT => t('Path prefix only.'),
- LANGUAGE_NEGOTIATION_PATH => t('Path prefix with language fallback.'),
- LANGUAGE_NEGOTIATION_DOMAIN => t('Domain name only.')),
This needs to be translated into the language.types yaml
Additionally we need to handle the relevant values in the {language} table: prefix and domain that used to be a language property and now are in the language.negotiation config entity (check yaml file).
In order to do that, we need to add values to the source and add a test to make sure that they get migrated.
Original report by Ryan Weal
Language negotiation settings (D6?/D7 locale -> locale). This will bring the priority given to different methods of detecting the user's language. Note: there can be multiple instances of this in D7 as user interface, content translation, and entity translation may define different methods.
More details about what options should be migrated can be found on the docs page and in the D7 API documentation.
Comment | File | Size | Author |
---|---|---|---|
#101 | interdiff-98-101.txt | 9.17 KB | maxocub |
#101 | 2225293-101.patch | 29.93 KB | maxocub |
#98 | 2225293-98.patch | 30.05 KB | Gábor Hojtsy |
#94 | interdiff-92-94.txt | 1.21 KB | maxocub |
#94 | 2225293-94.patch | 29.18 KB | maxocub |
Comments
Comment #1
rvilarworking on this
Comment #2
pcambraComment #3
rvilarThis solution depends on #2222169: Add skip_row option to StaticMap to skip some rows without value.
Comment #4
rvilarThis is a patch with the migration, the tests and dumps for language_negotitation variable migration.
Comment #5
Anonymous (not verified) CreditAttribution: Anonymous commentedComment #6
Anonymous (not verified) CreditAttribution: Anonymous commentedComment #7
Anonymous (not verified) CreditAttribution: Anonymous commentedComment #8
Anonymous (not verified) CreditAttribution: Anonymous commentedThis looks good but needs some work. I ran *many* tests...
Scenario 1:
D6 default lang EN
D8 default lang FR:
If D6 negotiation is set to "none" it will be "URL" and "Selected language" (the default settings in D8).
If D6 negotiation is set to "Path prefix with language fallback" I get "URL", "User", "Browser", and "Selected Language" in D8.
English was NOT installed by the migration process (as noted on #2166875: Migrate D6 languages).
Scenario 2:
D6 default lang EN
D8 default lang EN:
If D6 negotiation is set to "Path prefix with language fallback" it will be "URL" and "Selected language" (the default settings in D8). Was expecting this to have "User", "Browser" and "Selected Language" as above.
French was installed by the migration process (as noted on #2166875: Migrate D6 languages).
Other observations:
Re-running the migration does not update (I'm sure this is expected behavior as rollbacks do not exist yet either). There was no DB table migrate_map_d6_language_negotiation to flush so I had to create a new instance after changing the D6 value.
I did not see language_negotiation in core/modules/migrate_drupal/migrate.config.yml which contains a list of all the migrations.
Path prefixes did not come through. The D8 default language gets no path prefix (whether EN or FR), and the second language installed gets the default value.
Comment #9
phenaproximaComment #10
phenaproximaBlocked by #2594263: Add translation data to Migrate Drupal's test fixtures.
Comment #11
svendecabooterUnblocked
Comment #12
penyaskitoWIP.
Started from scratch, as #4 is 2 years old now...
d6_language_negotiation_settings
contains the required migration. I'm not contemplatinglanguage_types
migration, which is needed for language negotiation to work, but #2130307: Variable to config: language.negotiation [d7] didn't neither and we will need an issue for doing that both for d6 and d7.Tests fails because of schema issues, I've forgot about migrate for one year and need to catch up how sources schemas work when defining constants. Will find someone on IRC later.
Comment #13
penyaskitoAdded tags.
Comment #15
penyaskito@benjy figured out that I was defining my variable in schema in the wrong place.
I'm wondering how we could add more coverage now that we have concrete dumps for each version, so how can we check behavior having different source values?
Comment #16
penyaskitoLooks like
\Drupal\Tests\comment\Unit\Migrate\d6\CommentVariablePerCommentTypeTest
is a good example to follow for adding coverage for the different options of the mapping.Comment #17
Gábor HojtsyComment #18
penyaskitoIncreased testing coverage. Now I'm happy with this, please review.
Comment #19
benjy CreditAttribution: benjy at PreviousNext commented0 isn't actually mapped?
Comment #20
penyaskitoNone its equivalent as no having value at all, so we just ignore it. Added tests assert on that.
Comment #21
benjy CreditAttribution: benjy at PreviousNext commentedLooks good.
Comment #22
penyaskitoOh, I forgot about language prefixes.
Comment #23
Gábor Hojtsy@penyaskito asked for signoff on this. I think the patch is a good start but it does not migrate path prefixes and/or domains and neither it migrates which methods it would enable for negotiation AFAIS (it does not touch/set up language.types). So definitely needs work for those.
Comment #24
penyaskito@Gábor, yes, I pinged you before noticing it. We have the same problem in D7 so I created #2625148: [PP-1] Migrate language prefixes and domains to language.negotiation [d7]
Comment #25
Gábor Hojtsy@penyaskito: still planning to work on this one?
Comment #26
penyaskitoYes, we've been discussing last week and looks like the easiest solution is a custom process plugin.
I will get to this ASAP.
Comment #27
chx CreditAttribution: chx commentedComment #28
chx CreditAttribution: chx commentedComment #29
quietone CreditAttribution: quietone commentedThe prefixes and domains appear to be independent of the language negotiation variable migration, which this patch does. If that is correct, the prefixes and domains are easier done in their own migration. They exist in a separate table and will, at least, need a custom source plugin. This is different that penyaskito suggestion in #26.
Please explain. What are the methods and where are they setup?
Language types appear to be handled in #2225271: Migrate content type language settings from Drupal 6 & 7. Is that sufficient or are there more language.type settings that need to be migrated?
Comment #30
quietone CreditAttribution: quietone as a volunteer commentedComment #32
mikeryanNeeds reroll - minimally, the schema stuff needs to be removed from this patch.
Should we, as quietone suggests in #29, go ahead with this patch and handle prefixes and domains in a follow-up?
Comment #33
Sonal.Sangale CreditAttribution: Sonal.Sangale at Blisstering Solutions commentedComment #34
Sonal.Sangale CreditAttribution: Sonal.Sangale at Blisstering Solutions commentedRerolled the patch.
Comment #36
steinmb CreditAttribution: steinmb as a volunteer commentedI'm pretty sure this should now be against 8.2.x-dev?
Comment #37
Sonal.Sangale CreditAttribution: Sonal.Sangale at Blisstering Solutions commentedShould we try to reroll against 8.2.x-dev?
Comment #38
vasi CreditAttribution: vasi at Evolving Web commentedWith no passing patch, this is Needs Work.
Over 80 chars per line. Also, you have the same description for every function.
Comment #39
ashishdalviI will work on rerolling patch with 8.2.x version.
Comment #40
Gábor Hojtsy@Ashish.Dalvi: still working on it?
Comment #41
Gábor HojtsyPatch still applied to 8.x-2.x, so not sure why the concern that it does not. Anyway, rolled a fresh copy. Let's see what does testbot have to say. Also unassigning.
Comment #42
Gábor HojtsyComment #44
quietone CreditAttribution: quietone as a volunteer commentedMoved the MigrateLanguageNegotiationSettingsTest to Drupal\Tests\language\Kernel\Migrate\d6. Moved the test with language negotiation value of '1' to be the first test because that is the value of the language negotiation variable in the test fixture. This passed locally for 8.1.x and 8.2.x.
TODO: the issues raised in #38. Sorry, it is too late to do even that little bit more right now.
Comment #45
quietone CreditAttribution: quietone as a volunteer commentedI was really tired last night, the patch in #44 is numbered #45.
Comment #46
quietone CreditAttribution: quietone as a volunteer commentedAdjusted the comments to be within the 80 char limit.
Comment #47
Gábor HojtsyThanks! The issue summary mentions migrating the domains and paths out of the language objects, which would end up in the same language.negotiation config file. A sample file with 4 languages:
This patch does not migrate the paths and domains yet, it just migrates the setting itself as to whether to look at the path or domain.
The other thing misisng here is the creation of the language.types.yml file, which actually lists each negotiation method enabled and their priorities. That would be different for the different D6 language options as well and complete this migration.
Comment #48
Gábor HojtsyBTW quietone said above that language types were migrated in #2225271: Migrate content type language settings from Drupal 6 & 7, but that deals with language setting for content types, not negotiation settings for language types. language.types.yml looks like this by default in core:
This lists which language types are available, which ones are configurable and then negotiation configuration for each with their priorities. That would need to be migrated here, given that differences between the D6 LANGUAGE_NEGOTIATION_PATH_DEFAULT and LANGUAGE_NEGOTIATION_PATH would make the language-url-fallback item either appear or not appear in the negotiation settings.
Comment #50
Gábor HojtsySo selected fallback langcode is missing, but that seems to be as simple as adding these:
Because D6 does not make fallback configurable.
Comment #51
Gábor HojtsyComment #52
Sonal.Sangale CreditAttribution: Sonal.Sangale at Blisstering Solutions commentedComment #53
Gábor HojtsyI wanted to add that new key manually and then figured out that the case where the setting was 0 also known as LANGUAGE_NEGOTIATION_NONE in Drupal 6, we should still migrate some default settings and not null them out like the setting expects/verifies. We should still migrate the default settings, because this config file does not have any effect on how the actual migration works if the migration options THERE are disabled. In fact LANGUAGE_NEGOTIATION_NONE should result in the site default fallback setting and only that one enabled.
Comment #54
Gábor HojtsySorry did not want to step on your toes @Sonal.Sangale, if you are at DrupalCon now, you can come over to the general sprint room and discuss? :)
Comment #56
Sonal.Sangale CreditAttribution: Sonal.Sangale at Blisstering Solutions commentedHi Gábor Hojtsy,
I am glad that you asked to meet and discuss but I am not in DrupalCon now. :)
Comment #57
maxocub CreditAttribution: maxocub commentedHi @Sonal.Sangale, are you still working on this?
I was working on this at DrupalCon Dublin, but I forgot to assign it to myself.
After discussing this problem with @Gábor Hojtsy and @phenaproxima in Dublin, we found that migrating the prefixes and domains is a bit tricky, and we may have come up with a solution. I have a WIP patch that I may be uploading soon, but I don't want to step on your work.
Comment #58
maxocub CreditAttribution: maxocub commentedHere's a WIP for migrating language prefixes and domains, based on a discussion with @Gábor Hojtsy and @phenaproxima in Dublin.
@phenaproxima: I'd love to have your input on the Array_map process plugin. Is that what you had in mind?
Comment #60
maxocub CreditAttribution: maxocub commentedComment #61
Gábor HojtsyLooks fine for now to me (with my limited know-how of migrate). Also as per our discussion, it does need default handling for an empty domain too.
Comment #62
Gábor HojtsyUnassign from @Sonal.Sangale to reflect reality. Note that your contributions would still be valuable. Sorry if we stepped on your toes at DrupalCon :/
Comment #63
maxocub CreditAttribution: maxocub commentedHere's a new patch with the handling of an empty domain.
Also, I added a way to remove the protocol from the domain, since D6 expected it and D8 don't.
I also added tests for prefixes and domains.
About the possible empty domain, I had to assume that it was only the default language that was left empty, otherwise the migration will end up with duplicate domains. Should I check if the empty domain is for the default language? And leave empty non default empty domains?
Comment #64
Gábor HojtsyI think multiple same domains are better than even a single empty domain, given that we are generating links and redirects based on these settings. At least the computed domain points to somewhere as opposed to an empty domain.
Comment #65
maxocub CreditAttribution: maxocub commentedHere's the migration for the language.types configuration, and some tests.
What's missing now is the review for the new Array_map process plugin (@phenaproxima ;)). When the review is done we'll need to write some tests and documentation for it.
I'm not sure about the mapping I've made, but I think it's OK based on the D6 language negotiation help text. Here it is to help reviewers:
Comment #66
maxocub CreditAttribution: maxocub commentedHmm, I think a better way to write the tests could be to combine them in four cases, the four possible cases of D6 language negotiation. What do you think?
Comment #67
quietone CreditAttribution: quietone as a volunteer commentedTook a very brief look at this stood out.
Why not use the variableGet method in DrupalSqlBase?
The name array_map for a process plugin is confusing. The corresponding Php function does a very different thing. What other use case are there for this function? Just wondering. Anyway, array_map can wait until a maintainer reviews.
Comment #68
maxocub CreditAttribution: maxocub commented@quietone: I wasn't aware of variableGet() in DrupalSqlBase, thanks!
About Array_map, the idea and the name came from a brief discussion with @phenaproxima at DrupalCon Dublin. I was going to make a specific plugin for prefixes & domains, but he suggested to make a generic one so it could be used elsewhere. I'm waiting for his review, it's only a minimal prototype to show him what is needed here.
Then, if we go this way, we'll need tests and documentation for this new plugin.
Comment #69
phenaproximaFor brevity, let's make this
if (!empty($this->configuration['negotiation']))
.Should be named ArrayMap.
It is being assumed here that $old_value is an array, or can be used as an array. Can we cast $value to array so that it will always be traversable?
I've never seen this before, why is it needed?
Comment #70
mitrpaka CreditAttribution: mitrpaka as a volunteer commentedPatch updated.
Comment #72
mitrpaka CreditAttribution: mitrpaka as a volunteer commentedComment #73
phenaproximaThis is really close to ready, but I'd like to see two things:
1) A unit test of ArrayMap; and
2) Extensive documentation in ArrayMap's doc comment about the purpose of the plugin, plus usage examples.
It might need a change record as well. @alexpott, what do you think?
Comment #74
phenaproximaOne more thing I'd like to see -- can we add an array_key_exists() sanity check to make certain that both the key and value in $old_value actually exist, and throw an exception if not? I ask because if the key doesn't exist, the output array could potentially cause weird, hard-to-debug behavior further down the chain.
Comment #75
maxocub CreditAttribution: maxocub commentedThanks @phenaproxima for the review and @mitrpaka for the corrections.
@phenaproxima, about #69/4, I based this plugin on the Iterator plugin which contains this multiple() method, if it's not needed here I guess it's not needed there either.
I'm working on a unit test and documentation for the ArrayMap plugin.
Comment #76
maxocub CreditAttribution: maxocub commentedHere's the unit test.
Documentation's next.
Comment #77
phenaproximaOf the code, I have only minor nitpicks at this point :) I'd still like to see documentation and usage examples though, per #73.2. Excellent work, @maxocub et. al.
I might be wrong about this, but I believe that we are not supposed to add periods at the end of exception messages in core...
Let's switch to []. The core standard is to prefer [] over array(), and not to mix both in the same file.
Let's rename this testTransform().
Comment #78
maxocub CreditAttribution: maxocub commented@phenaproxima: Sure, I'm now working on the documentation and usage examples, but it's the first time I'll be doing that so I'm doing some reading on that subject first.
One thing I'm wondering though is why the other migrate process plugins have a link to the online handbook instead of documentation in their docblocks?
Comment #79
phenaproximaBecause that is how it used to be done :) There is an issue underway to get all the plugin documentation moved into the docblocks instead: #2776179: [meta] Add process plugin documentation to the codebase. Rather than reroll that issue when ArrayMap is committed, I figure it's better to just document ArrayMap inline right now.
Comment #80
maxocub CreditAttribution: maxocub commentedHere's a first version of the documentation and example usage. English is not my native language, so there may be better ways to formulate this. Also, there's a lot of usage of the words 'key' and 'value', so I hope it's at least a bit clear.
Comment #81
phenaproximaI think I would phrase it this way:
The array_map plugin builds a single associative array by extracting keys and values from each array in the input value, which is expected to be an array of arrays. The keys of the returned array will are determined by the 'key' configuration option, and the values are determined by the 'value' option.
This should just be {@inheritdoc}, since transform() comes from the process plugin interface.
Also, I hate to do this...but I have realized that calling this plugin ArrayMap (and array_map as the plugin ID) is kind of a misnomer. Can we rename it to something else? I'm thinking ArrayBuild/array_build, but I'm open to other ideas if they will be clearer.
Comment #82
maxocub CreditAttribution: maxocub commentedThat's a much more clear way to phrase it, thanks @phenaproxima!
I don't have any other idea for the name of this plugin, so let's use ArrayBuild/array_build, which is better that ArrayMap/array_map.
Comment #83
phenaproximaGlorious.
Comment #84
quietone CreditAttribution: quietone as a volunteer commented@maxocub, thanks! Pleased to see the name change to ArrayBuild. And love the docs too.
Comment #85
maxocub CreditAttribution: maxocub commentedHmm, I just realized that I didn't add a unit test for the LanguageDomains process plugin, I guess I should, right?
Also, since I started to think about migrating prefixes and domains from D7 (#2625148: [PP-1] Migrate language prefixes and domains to language.negotiation [d7]), I realized that this plugin only works for D6, and should be able to do both, I think. Should I try to correct that here or do we wait till this gets in and I adapt it latter?
Comment #86
phenaproximaBetter to get it done now. If we missed a unit test for LanguageDomains, let's add one now as well.
Comment #87
Gábor HojtsyAgreed with @phenaproxima :)
Comment #88
Gábor HojtsyComment #89
maxocub CreditAttribution: maxocub commentedHere's a new patch where I make the language prefix and domains migration work for D6 & D7 and add a unit test for the plugin, as requested in #86.
I also corrected the d7_language_negotiation_settings which didn't worked for sites using domain negotiation.
Comment #91
maxocub CreditAttribution: maxocub commentedI forgot to update the D7 language negotiation settings test.
Comment #92
maxocub CreditAttribution: maxocub commentedComment #93
Gábor HojtsyLooks fantastic, resolves the concerns raised since the last RTBC and nicely integrates Drupal 7 migration with corresponding tests :)
This is the extent core supports, so I think this looks good. We can update when/if an entity_translation module migration is built.
This is so beautiful :)
Woot, nice to see this tested :)
Comment #94
maxocub CreditAttribution: maxocub commentedSome self nitpicking :)
Comment #96
maxocub CreditAttribution: maxocub commentedRandom test fail, re-tested and back to RTBC.
Comment #97
alexpottNow that the other patch has landed this needs a reroll.
Comment #98
Gábor HojtsyThe only conflicts to resolve were in core/modules/language/tests/src/Kernel/Migrate/d7/MigrateLanguageNegotiationSettingsTest.php due to the new test method added in #2353709: Variables to config: language.types [d7].
Comment #99
Gábor HojtsyComment #100
alexpottAll this code is not indented correctly.
Method is missing a comment with an @covers
Needs a full stop.
See #2822837: Replace @expectedException @expectedExceptionMessage with $this->setExpectedException - we do this differently now.
Comment #101
maxocub CreditAttribution: maxocub commentedHere you go!
Comment #102
Gábor HojtsyLooks good to me, pending passing tests :)
Comment #103
alexpottComment #104
alexpottCommitted and pushed 1380ab9 to 8.3.x and aa8ed51 to 8.2.x. Thanks!
Comment #107
Gábor HojtsyAmazing, thanks all especially @maxocub :)
Comment #108
Gábor HojtsyComment #110
maxocub CreditAttribution: maxocub commentedComment #111
maxocub CreditAttribution: maxocub as a volunteer and commented