Problem/Motivation
the decoupled router path in default language (/router/translate-path) can't resolve an alias in another language (i.e. with a language prefix at the beginning of the path argument).
Example:
Given
1) Site with default language of English and another language, German ('de').
2) The alias 'helloworld' is the alias of a node in German that doesn't have an english translation.
You can visit '/de/helloworld' directly in Drupal, but /router/translate-path?path=/de/helloworld doesn't work.
Strangely, if the alias is already resolved, it works.
/router/translate-path?path=/de/node/63 works.
I believe the first one should work too.
Proposed resolution
Detect language prefix and resolve aliases before resolving path.
The bug seems to be within the 'router.no_access_checks' service, which only uses the negotiated language to match the route.
But if we can resolve the path first, then it can find the node's route.
So do this:
$path = \Drupal::service('path.alias_manager')->getPathByAlias('/helloworld', 'de');
$router = \Drupal::service('router.no_access_checks');
$result = $router->match($path);rather than
$router = \Drupal::service('router.no_access_checks');
$result = $router->match('/de/helloworld');When '/de/node/63' is passed to \Drupal::service('router.no_access_checks') it works, even if the prefix is different than the negotiated language.
If we allow the path.alias_manager to check for alias, then we can get around this bug.
I know you can call the translated decoupled router:
/de/router/translate-path?path=/de/helloworld works.
But it seems inflexible to require the FE devs to call different routes based on the language for the decoupled router. It would be good for the base route to handle paths from any language when using language-url negotiation.
Remaining tasks
User interface changes
API changes
Data model changes
Release notes snippet
Issue fork decoupled_router-3111456
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
oknateComment #3
oknateComment #4
oknateComment #5
e0ipsoThanks for the detailed bug. This will be a nice fix for multilingual sites.
Comment #6
oknateHere's a patch for one proposed solution. It adds another subscriber that converts the alias to a path. Everything pretty much works after this, except the 'resolved' parameter is still off.
This code doesn't account for when the $entity->language() differs from the current resolved language:
Comment #7
oknateThis addresses the issue with the resolved parameter in the response not matching.
Comment #8
oknateComment #9
oknateComment #10
oknateComment #11
oknateComment #12
oknateComment #13
oknateComment #14
oknateComment #15
oknateAdding a fail patch to demonstrate the issue, and demonstrate the fix.
Comment #16
oknatepath.alias_manager is deprecated, so this needs reworking. Also, I think we could fold this functionality into RouterPathTranslatorSubscriber, since that will need a constructor update anyway.
Comment #17
oknateReworking the patch to add new functionality to RouterPathTranslatorSubscriber.
Comment #18
oknateThis fixes a bug we found where it was not translating the entity when langcode was a prefix in the path.
Comment #19
oknateAdding langcode to output, and fixing dependency issue (using
\Drupal::service('entity.repository')instead of injected service in one place).Comment #20
e0ipsoThanks for the patches! you rock!
I hope to review this soon.
Comment #21
oknateFixing a bug where it wasn't converting the path properly on the hompeage when passed to the path attribute:
/router/translate-path?path=/deComment #22
oknateFixing a bug where it was throwing an error if the site wasn't multilingual. We are running multiple sites and some aren't multilingual.
Comment #23
arshadkhan35 commentedRe-rolling #22 patch against 2.x branch.
Comment #24
arshadkhan35 commentedRe-rolling #23 against 2.0.1 as 2.x-dev have some code changes which case the patch to fail for 2.0.1.
Comment #25
bojan_dev commentedThe issue reported is also applicable for the redirects. With the patch from #23, the redirects are being queried with language prefix in "RedirectPathTranslatorSubscriber", while in the db they are stored as path (without language prefix), this results in 404's.
Comment #26
bojan_dev commented#25 was not considering language-specific redirects.
Comment #27
bojan_dev commentedComment #28
gsingh1 commentedUpdating patch from #22, the getTranslationFromContext was not returning the languages that exist for the node, instead returning entity with the default language. This patch is for version 8.x-1.11
Comment #30
gsingh1 commentedupdated patch #22 with following patch
Following is the diff between patch #22 and #28
Comment #31
gsingh1 commentedAdded patch for problem in getTranslationFromContext is that the call to getFallbackCandidates does not return the languages that exist for the node, making it display just the default language. Added patches #28 for 8.x-1.11 and 2.x.
Comment #32
bojan_dev commentedThe patch is not considering that language prefix can be different than language id, e.g: I have 'en' as lang code and 'en-gb' as language prefix, which made the redirects not work for English.
Comment #34
bojan_dev commentedLang code has been introduced in the response but not yet in the tests.
Comment #35
bojan_dev commentedComment #36
decipheredHi @bojan_dev,
I've done a brief test of this patch and it appears to be working as expected, and I can see the presence of updated automated tests. Can you specify what additional work you believe is still required?
Comment #37
decipheredremoved accidental tag
Comment #38
bojan_dev commentedHi @Deciphered,
Functional-wise, I believe it's working fine, I'm using this patch on a high traffic production website.
I think we are complete, it would be nice if we could have a test for the following change: interdiff_31-32.txt. It's not required, but again it would be nice to have test coverage for this inconsistency between lang code and lang prefix.
Comment #39
brianperryRan into a need for this fix today - patch applied cleanly and worked as expected.
Making a note of the need for additional tests on this one. If future me, or someone like future me could help out with that, would be great to get this one merged.
Comment #40
decipheredWhile testing I noticed that the entryPoint isn't correctly prefixed.
https://nginx.develop.demo-api-druxtjs-org.au2.amazee.io/router/translat...
Comment #42
decipheredI have opened a feature branch for this work and committed the latest patch with due credit.
I've added a fix for the issue I mentioned in #40.
The patch can be accessed from https://git.drupalcode.org/project/decoupled_router/-/merge_requests/5.diff, or via commit from the gitlab repo as required.
Comment #43
decipheredI agree that it's important to get full test coverage here if possible, I don't personally have the capacity or full understanding of the implications and usecases of using 'en-AU' or similar langcodes.
I do think that it's worth getting this merged in and making a followup story for the testing and inconsistencies with prefixes and langcodes, as in the meantime there will be greater access to multilingual support in decoupled builds.
Comment #44
decipheredIt's also worth noting, and maybe updating, that the pathPrefix and basePath don't have the langcode prefix. Thoughts?
Comment #45
bojan_dev commentedHi @Deciphered,
The commit you made looks fine: https://git.drupalcode.org/project/decoupled_router/-/merge_requests/5/d...
Unfortunately I'm pretty jammed with work currently, otherwise I could help out, but for now making a separate issue for the test coverage makes sense.
I agree with your comment about basePath/pathPrefix; it should include the langcode prefix as well.
Comment #46
shadcn commented@Deciphered Thanks for the patch. I'll test and report back.
Agreed with you both on the langcode missing.
From the screenshot above, is there a reason
individualandentryPointhave different langcode?Comment #47
deciphered@shadcn, the different langcodes was the bug I reported @ #40, that one has been fixed, but I've also added the prefix to basePath and pathPrefix now:
Comment #48
decipheredI have created the follow-up issue @ https://www.drupal.org/project/decoupled_router/issues/3280591
All that is needed now is for someone to mark this issue RTBC and I will get it merged in and released.
Comment #49
e0ipsoComment #50
gooddev commentedSorry for openening a new ticket, was not aware that they are related to each other. Made adjustments on this merge request here in this issue: https://www.drupal.org/project/decoupled_router/issues/3309874
Maybe somebody can feedback so it could eventually be proceed here.
Comment #51
vhin0210 commentedGot some errors loading translated webform. I tweaked patch 34 to check if entity object has getTranslation method.
Comment #53
decipheredCI is failing, and it appears to be due to Drupal being run in a subdirectory?
https://www.drupal.org/pift-ci-job/2498799
I'm unsure of the cause of this, but it will need to be accounted for.
Could you also provide a test for when the prefix doesn't match the the langcode?
Comment #55
rajeshreeputrahere is the updated patch for the new release 2.0.4
there an error in patch please refer #58
Comment #58
rajeshreeputrahere is the updated patch.
Comment #59
vhin0210 commentedAdding #51 again to the latest patch. can you please add that method exist call on your next patch file please?
if ($entity->hasTranslation($this->langcode) && method_exists($entity, 'getTranslation')) {This fixes the webform entity because webform doesn't have getTranslation
Thanks!
Comment #60
theruslanPatch #59 with decoupled_router 2.0.4 works fine for me.
Thank you!
Comment #61
yahyaalhamadThere is a problem with not being able to resolve the redirect and the current language, I expected that if you don't provide a language prefix, the current language will be used instead of only 'und'. This patch addresses the problem, but I think there will be slight problems if the prefix is also found in 'und' langcode. interdiff included.
Comment #62
e0ipsoI updated the test config so we can run tests on #61.
Looking forward to see an RTBC here.
Comment #63
abhisekmazumdarThe patch in #61 looks good apply in D10. But I did only see one issue with whitespaces warning throwing up. So created a new patch.
Also remove the Assigned to Unassigned so that people can find and review issue which are open to review.
Comment #64
robertom commentedThe patch in #3111456-63: Unable to resolve path on node in other language than default seems to work fine, but RedirectPathTranslatorSubscriber does not correctly take into account the language of the selected redirect.
Attached a modified version of the patch and the interdiff
Comment #66
decipheredIssue reported by Druxt user:
Patch attached cleans additional query string from resolver.
Comment #68
vhin0210 commentedAdded the patch from Unable to resolve path on path with fragments in patch #66
Comment #69
mglaman#63 was the last green run. With #64 to support RedirectPathTranslatorSubscriber the tests started to fail, in what looks like a valid failure. #66 looks like a valid addition to the patch, but tests still fail. #66 looks irrelevant because it adds another issue into this patch.
Can someone confirm is the test failure is positive not?
Comment #70
mglamanTrying to clean up files.
Comment #71
apmsooner commentedNot sure why test is failing but #66 works great for me.
Comment #72
vhin0210 commentedUpdated patch #68
So this patch has all the fixes from
RouterPathTranslatorSubscriber uses wrong param when resolving the url #2
Unable to resolve path on path with fragments #2
and #66
Comment #73
jeffschuler@vhin0210 is there a reason to add the patches from #3411402: RouterPathTranslatorSubscriber uses wrong param when resolving the url and #3397122: Unable to resolve path on path with fragments to this?
Mixing issues generally makes the individual issues a lot more challenging to test, fix, and get merged by the maintainer.
Comment #74
a.dmitriiev commentedUploading re-rolled #63, as it was the last one with not failing tests.
Comment #76
ankitv18 commentedRebased the MR!11 with 2.x-dev and pushed minor changes.
Now gitlab pipeline is executing so avoid creating anymore patches, lets try to fix the tests in the MR only.
Comment #77
naim belkaied commentedUpdated patch to retrieve the redirect URL corresponding to the language specified in the query parameter path.
eg : http://URL/fr/router/translate-path?path=/en/products/electronics/laptop...
response :
Comment #78
steve.elkins commentedUpdated patch to add support for external redirects borrowing similar changes from #3133681: No information for external redirects.
Before:
Path Examples
/router/translate-path?path=/external-redirect
/router/translate-path?path=/es/external-redirect
After:
Path Example: /router/translate-path?path=/external-redirect
Path Example: /router/translate-path?path=/es/external-redirect
Attached a modified version of the patch and the interdiff.
Comment #79
iamfredrik commentedPatch does not work correctly for me.
In my case the default language is Swedish.
I have a node with path /sv/aktiviteter
/router/translate-path?path=/en/aktiviteter
correctly returns the resolved path /en/activities
but it's unable to translate back and /sv/activities returns:
{"message":"Unable to resolve path \/sv\/activities.","details":"None of the available methods were able to find a match for this path."}
Comment #80
lbesenyei commentedPatch works in my case.
Comment #81
aaronbauman#78 does not apply on latest dev
Comment #87
aaronbaumanThis patch was quite a mess after the other upstream changes.
I've cleaned it up and opened a new MR !30, and attaching patch version of same.
I'm not going to bother with an interdiff.
Comment #88
vah67007@gmail.com commentedAdding a patch for 2.0.5
Comment #89
chandu7929 commentedNeed to re-rolls patch as per 5.0.6 latest release.
Comment #91
chandu7929 commentedCreated MR!36 with required changes to work with 5.0.6
Comment #93
serg.linkinHi @chandu7929 and thank you for the re-rolled patch.
The only important point is that the entity URL must be specified in the requested language if found, to avoid wrong content translation for multilingual websites.
Therefore, at least
jsonapi > individualneeds to be changed to use the found "en" langcode, just similar to the patches provided earlier in this thread. Please check the attached screenshot.Comment #94
chandu7929 commentedThanks @serg.linkin, I have included the changes for jsonapi, also adding latest patch here.
Comment #95
chandu7929 commentedComment #96
chandu7929 commentedComment #97
ahmad-alyasaki commentedFixes redirect failures when URLs contain encoded non-ASCII characters (e.g., Arabic: %D8%A7%D9%84%D8%B9%D8%B1%D8%A8%D9%8A%D8%A9).
The patch decodes URLs before matching redirects and aliases, ensuring proper handling whether the redirect source is stored in encoded or decoded form. Also adds multilingual support with language prefix detection and proper entity translation handling.
Comment #98
ahmad-alyasaki commentedFixes redirect failures with the prefix multi-language code
Comment #99
bojan_dev commentedin MR !35 the langcode property has been moved from entity object to the root of the response. Is there a reason for this? It breaks currently next-drupal, see: https://github.com/chapter-three/next-drupal/blob/main/packages/next-dru....
Comment #101
budalokko commentedI have created this MR that would fix the regression stated by @bojan_dev in the previous comment #99.
Please @chandu7929 check if this would make sense to be merged into the issue main MR !35 or there was a specific reason to move "langcode" key to a different place.
EDIT: I merged main branch as this
langcodehas been there for the entire history of this issue.Comment #102
jsmakk commentedThe MR !35 seems to return access denied for the node when following steps are taken.
The MR seems to check access to the entity before it gets the translation. Perhaps that is the cause. I think it was other way round in the old MR !11.
Comment #103
omar_emailat commentedI've been working with the patches from #3111456 and #10134399 and discovered an additional issue that affects multilingual sites.
Root Cause:
In the current patch, the entity translation is retrieved AFTER the access check. This means the access check runs on the default
language entity (which is unpublished), causing it to fail before we even get to the translated entity.
Additional fix in getPathFromAlias(): The method was returning the path WITH the language prefix (e.g., /ar/node/123), but the router expects paths WITHOUT the prefix.
Changed to return only the system path:
$system_path = $this->aliasManager->getPathByAlias($path_without_prefix, $langcode);
// Return the system path WITHOUT the language prefix.
// The router expects paths without language prefix - language is handled via $this->langcode property.
return $system_path;
I've attached a combined patch that includes:
- The language issues fix from #3111456-98
- The isHomePath fix from #10134399
- The translation unpublish fix described above
Tested on Drupal 10.x with decoupled_router 2.0.6.