Skip to content

Apply the language URL parameter to the whole interface - #25248

Merged
tzi merged 11 commits into
6.x-devfrom
dev-14920
Sep 11, 2026
Merged

Apply the language URL parameter to the whole interface#25248
tzi merged 11 commits into
6.x-devfrom
dev-14920

Conversation

@tzi

@tzi tzi commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Description

Appending ?language=es to a reporting URL changed the segment and period selectors, but the widgets and the left reporting menu stayed in the user's own language, so the interface ended up half translated. Sharing a link, or switching language to check a translation, gave a mixed-language page.

The whole interface now follows the language the page asks for.

issue dev-14920

Step by step tests

  1. Set your user language to English, open any reporting page, and append &language=es to the URL.
    👁️ The left menu, the widget titles and the widget contents are all in Spanish, along with the selectors.
before after
Screenshot 2026-09-08 at 11 18 54 Screenshot 2026-09-08 at 11 18 10
  1. Navigate between reporting pages without touching the URL.
    👁️ Everything stays in Spanish. The parameter survives navigation.
  2. Add the Visitor Map and the Real-time Map to a dashboard, then reload with &language=es. Hover a country on the real-time map, and open a row evolution from the visitor map.
    👁️ The tooltips and the row evolution popover are in Spanish too.
before after
Screenshot 2026-09-08 at 12 28 48 Screenshot 2026-09-08 at 12 29 11
  1. With &language=es still in the URL, open a Page Overlay from the Behaviour > Pages report.
    👁️ The overlay opens in Spanish, sidebar included. (but Heatmap infobox will stay in english since it’s not translated)
before after
Screenshot 2026-09-09 at 11 40 53 Screenshot 2026-09-09 at 11 40 12
  1. With &language=es still in the URL, open the Pages report, click the export icon under the widget, pick CSV and download it.
    👁️ Two things to look at: the file name, the column headers are Spanish (ex: Visitas)
before after
Export _ Page URLs _ Tuesday, August 4, 2026.csv Exportar _ URLs de página _ Martes, 4 de agosto de 2026.csv
Screenshot 2026-09-09 at 14 25 14 Screenshot 2026-09-09 at 14 25 51
  1. With &language=es still in the URL, go to Administration > Personal > Settings, pick French as your language and save.
    👁️ Two things to look at: &language=es disappears from the URL bar as soon as the save succeeds, and any reporting page you open next is in French, the language you just saved. Before this change the parameter stayed in the URL and kept overriding the setting, so the next page was Spanish again and the save looked like it had been ignored.
  2. Give the anonymous user view access to a site (Administration > System > Users), log out, open that site's dashboard with &language=es, then pick French in the language selector of the top menu.
    👁️ Two things to look at: &language=es is gone from the URL, and the whole page including the widgets is in French. Before this change the redirect kept the parameter, so the page came back in Spanish and the selector looked broken. The selector only shows for anonymous users, which is why this step needs the logout.
  3. Remove &language=es and reload.
    👁️ The whole interface is back in English.
  4. Open a page with no language parameter at all.
    👁️ Unchanged from before: your own language, and no language in the requests the page makes.

Checklist

  • [✔] I have understood, reviewed, and tested all AI outputs before use
  • [✔] All AI instructions respect security, IP, and privacy rules

Appending ?language= changed the segment and period selectors but left the
widgets and the reporting menu in the user's stored language, so the interface
ended up half translated.

Those two regions are not part of the page render: the menu comes from
API.getReportPagesMetadata and each widget fetches its own content, both through
AjaxHelper. AjaxHelper carries idSite, period, date and segment over to those
requests but not language, so they were answered in the stored language while
the page around them used the requested one. The selectors looked right only
because they translate client-side from the strings the page already shipped.

language now travels with the other four. It is only sent when the page asks
for one, so the usual path is unchanged, and a request that sets its own
language still wins.
@tzi tzi added this to the 6.0.0 milestone Sep 8, 2026
@tzi tzi changed the title Carry the page language into the requests that build the page, DEV-14920 Carry the page language into the requests that build the page Sep 8, 2026
@tzi tzi changed the title Carry the page language into the requests that build the page Apply the language URL parameter to the whole interface, DEV-14920 Sep 8, 2026
@tzi tzi changed the title Apply the language URL parameter to the whole interface, DEV-14920 Apply the language URL parameter to the whole interface Sep 8, 2026
tzi added 2 commits September 8, 2026 11:30
…pendent, DEV-14920

The hash-beats-query-string contract and the postParams suppression were both unasserted, and originalHref was captured at collection time, which other tests in this file leave dirty. Also drops the spec comment that restated the one in the source.
…-14920

Both map widgets build their requests with a private $.ajax wrapper rather than
going through AjaxHelper, so the previous commit did not reach them. Their shell
is translated, but the realtime tooltips render a server-translated
referrerTypeName, and the row evolution opened from the visitor map fetches
server-rendered HTML.

getEnrichedRequest() now copies the language into the params baked into the page,
the way it already does for the segment, which covers the realtime report since
it spreads those params. The row evolution picks its params out one by one, so it
needs the language named explicitly.
@tzi
tzi requested a review from a team September 8, 2026 10:31

@chippison chippison left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything looks good.
This PR does what it says, except in Page Overlay
This will still open an untranslated page because it is javascript that builds the URL for this
Would be good to fix this as well just so this is complete

@tzi

tzi commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

Everything looks good. This PR does what it says, except in Page Overlay This will still open an untranslated page because it is javascript that builds the URL for this Would be good to fix this as well just so this is complete

Thanks @chippison, good catch! Page Overlay is fixed now. ✅

While checking I found two related gaps and fixed them as well:

  • CSV/TSV exports still came back in English, because core/Plugin/Controller.php read the language from the session rather than from the request.
  • Saving a different language in personal settings had no visible effect while the URL still pinned one.
    I also added tests for all three features.

@chippison chippison left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The revert in b0bbedbbd1 says the language selector "only reaches the installer and updater screens", but LanguagesManager\Menu::configureTopMenu also adds it to the normal reporting top menu for every anonymous user, so on an install with anonymous view access, someone on a ?language=es link who picks French gets redirected back to a referrer that still pins es, and the dropdown appears to do nothing. This PR makes that more visible rather than less: previously the AJAX-loaded widgets at least followed the newly chosen session language, and now they carry the URL one too, so nothing on the page changes. Could 02fe2bb5fb be restored? The code and its tests already look right to me.

Comment thread plugins/UsersManager/vue/src/PersonalSettings/PersonalSettings.vue
@tzi

tzi commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

You're right @chippison, and my reasoning for the revert was wrong: I traced the selector only through Template.topBar and missed LanguagesManager\Menu::configureTopMenu.

@chippison chippison left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good now 👍

@tzi
tzi merged commit a370601 into 6.x-dev Sep 11, 2026
332 of 334 checks passed
@tzi
tzi deleted the dev-14920 branch September 11, 2026 13:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants