Skip to content

[WIP] refactor: change lang selector logic #493

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

dcoa
Copy link
Contributor

@dcoa dcoa commented Jan 13, 2025

Description and motivation

This PR refactors the lang selector logic recognizing its significance for multi-language instances.
The Open edX platform previously featured a configurable language selector in both the header and footer. However, after transitioning to microfrontends, this feature is only partially implemented in the footer. It requires passing a list of supported languages and a change function, necessitating additional modifications even when using the footer slot.

This PR change the dropdown and add the user preference update endpoint.

Warning

This depends on openedx/frontend-platform#786

Proposal

Convert this component in a slot so could be installed in the header as well and give them the operators the option to use the language selector in the header or footer.

How to test

  1. Override the Footer component in a MFE or use the example application to test the current implementation.
  2. You need the messages for the selected language if you want to visualize the change.
  3. You can see the change in the language cookie.
2025-01-13.21-07-20.mov

@openedx-webhooks openedx-webhooks added the open-source-contribution PR author is not from Axim or 2U label Jan 13, 2025
@openedx-webhooks
Copy link

openedx-webhooks commented Jan 13, 2025

Thanks for the pull request, @dcoa!

This repository is currently maintained by @openedx/committers-frontend.

Once you've gone through the following steps feel free to tag them in a comment and let them know that your changes are ready for engineering review.

🔘 Get product approval

If you haven't already, check this list to see if your contribution needs to go through the product review process.

  • If it does, you'll need to submit a product proposal for your contribution, and have it reviewed by the Product Working Group.
    • This process (including the steps you'll need to take) is documented here.
  • If it doesn't, simply proceed with the next step.
🔘 Provide context

To help your reviewers and other members of the community understand the purpose and larger context of your changes, feel free to add as much of the following information to the PR description as you can:

  • Dependencies

    This PR must be merged before / after / at the same time as ...

  • Blockers

    This PR is waiting for OEP-1234 to be accepted.

  • Timeline information

    This PR must be merged by XX date because ...

  • Partner information

    This is for a course on edx.org.

  • Supporting documentation
  • Relevant Open edX discussion forum threads
🔘 Get a green build

If one or more checks are failing, continue working on your changes until this is no longer the case and your build turns green.

🔘 Update the status of your PR

Your PR is currently marked as a draft. After completing the steps above, update its status by clicking "Ready for Review", or removing "WIP" from the title, as appropriate.


Where can I find more information?

If you'd like to get more details on all aspects of the review process for open source pull requests (OSPRs), check out the following resources:

When can I expect my changes to be merged?

Our goal is to get community contributions seen and reviewed as efficiently as possible.

However, the amount of time that it takes to review and merge a PR can vary significantly based on factors such as:

  • The size and impact of the changes that it introduces
  • The need for product review
  • Maintenance status of the parent repository

💡 As a result it may take up to several weeks or months to complete a review and merge your PR.

@dcoa dcoa changed the title Dcoa/lang selector refactor: change lang selector logic Jan 13, 2025
Copy link

codecov bot commented Jan 13, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 94.25%. Comparing base (bc79936) to head (7ec5478).
Report is 41 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #493      +/-   ##
==========================================
+ Coverage   91.22%   94.25%   +3.02%     
==========================================
  Files           5        6       +1     
  Lines          57       87      +30     
  Branches       19       23       +4     
==========================================
+ Hits           52       82      +30     
  Misses          5        5              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@dcoa dcoa force-pushed the dcoa/lang-selector branch 8 times, most recently from 0ae49f6 to 3845c7f Compare January 13, 2025 09:37
@dcoa dcoa marked this pull request as ready for review January 13, 2025 09:40
@dcoa dcoa requested a review from arbrandes January 13, 2025 10:16
@dcoa dcoa force-pushed the dcoa/lang-selector branch 2 times, most recently from bd327ad to 7ec5478 Compare January 27, 2025 21:19
@dcoa
Copy link
Contributor Author

dcoa commented Jan 27, 2025

Hi, @brian-smith-tcril I has wondering if you can have a look to this proposal or if should I tag someone from product before the technical review?

@brian-smith-tcril
Copy link
Contributor

Sorry for the extended delay in response!

I think this is a change we do want. I also know that there is a similar feature implemented in frontend-base at the moment. Ideally the implementation of this feature will align with what is needed by the feature in frontend-base. I think @arbrandes has a better sense of what the frontend-base implementation is at the moment, and what we'll want it to be by the time we are ready to start using frontend-base.

Assuming this PR and the implementation in frontend-base play well together I'd be more than happy to review it!

@sarina
Copy link
Contributor

sarina commented Jan 28, 2025

should I tag someone from product before the technical review

I think there's a question of whether or not we want to be adding a new flag. If we don't mind a new flag this PR is good to go from a product perspective, but if we want to make this the default experience for any site that has multiple languages, you'd want to make a product ticket.

@dcoa
Copy link
Contributor Author

dcoa commented Jan 31, 2025

@arbrandes I think your opinion here is valuable, understanding you have a better panorama of the current state of the frontend new architecture.

What do you think about this proposal and the alignment with frontend-base also the introduction of new config variables?

@mphilbrick211
Copy link

@arbrandes I think your opinion here is valuable, understanding you have a better panorama of the current state of the frontend new architecture.

What do you think about this proposal and the alignment with frontend-base also the introduction of new config variables?

Friendly ping on this, @arbrandes

@dcoa
Copy link
Contributor Author

dcoa commented Mar 31, 2025

@arbrandes any opinion in this topic?

@Ang-m4
Copy link

Ang-m4 commented Apr 1, 2025

Hi @dcoa,
I hope you're doing well!
I came across this PR while working with the NELC team, as we were looking for a simple and practical implementation of a language selector. We really appreciate your proposal and are excited about the possibility of using it. We're also looking forward to seeing it merged upstream.
Additionally, we're currently working on a header implementation that follows the same logic. I’d appreciate it if you could take a look at it soon.

I’ll be leaving some comments on your code for further discussion, and i really would like to @arbrandes to take a look at this as he has a better understanding of the entire project.

Thank you for your hard work and contributions!

Comment on lines 60 to 63
{config.ENABLE_FOOTER_LANG_SELECTOR && (
<div className="mb-2">
<LanguageSelector
options={config.SITE_SUPPORTED_LANGUAGES}
username={authenticatedUser?.username}
langCookieName={config.LANGUAGE_PREFERENCE_COOKIE_NAME}
/>
</div>
Copy link

@Ang-m4 Ang-m4 Apr 1, 2025

Choose a reason for hiding this comment

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

I think it might be cleaner to handle some rendering logic validation inside the component, along with fetching the options, username, and langCookieName there.

};
const getLocaleName = (locale) => {
const langName = new Intl.DisplayNames([locale], { type: 'language', languageDisplay: 'standard' }).of(locale);
return langName.replace(/^\w/, (c) => c.toUpperCase());
Copy link

Choose a reason for hiding this comment

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

Suggested change
return langName.replace(/^\w/, (c) => c.toUpperCase());
return langName.charAt(0).toUpperCase() + langName.slice(1);

I see that this line capitalizes the string. A more straightforward implementation without regular expressions might be better for this task. I'll leave it up to you.

});
});

it('should disp,ay the language icon and modify the label according to the screen size', () => {
Copy link

Choose a reason for hiding this comment

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

Suggested change
it('should disp,ay the language icon and modify the label according to the screen size', () => {
it('should display the language icon and modify the label according to the screen size', () => {

Copy link

Choose a reason for hiding this comment

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

I suggest adding docstrings to this file methods to improve readability.

Copy link

Choose a reason for hiding this comment

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

I suggest adding docstrings to this file methods to improve readability.

Copy link

Choose a reason for hiding this comment

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

I would like you to take a look at this PR, you might find it interesting as it proposes a new frontend-platform module to handle the language change logic based on your changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi @arbrandes , I would like to take this conversation back to the table, there is this proposal of centralize the logic for update the language in frontend-platofrm openedx/frontend-platform#786 I think is a good idea, have the core logic agnostic to a component, specially if we want to extended the functionality to the header as well (as we used to have in comprehensive theming). I look forward to hearing your opinion.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, this PR should be refactored so that it contains only the display logic, leaving the API calls and state management to frontend-platform, via openedx/frontend-platform#786.

@Ang-m4
Copy link

Ang-m4 commented Apr 7, 2025

Hi @dcoa,

I've tested the final version of the component using frontend-app-learning and it looks great visually! However, I noticed an issue: when a new language is selected from the dropdown, it only updates the cookie in LMS, which prevents the application from loading and applying the correct translations. This happens because the getLocale() method (also used by handleRtl()) relies on the LANGUAGE_PREFERENCE cookie to retrieve its information. I recommend moving the cookie assignment outside of the conditional statement.

Please see the attached video demonstrating the behavior:

translations-not-working.mp4

After the change, everything seems to work fine:

translations-working.mp4

However, please note that while the translations do update, they are only applied partially. Many sections of the platform are still not configured to receive the publish() event or handle translations dynamically.

Given this, the most robust solution might be to force a full page reload when updating the language, ensuring that all parts of the application reflect the new language settings.

What do you think?

Comment on lines 14 to 20
try {
if (username) {
await patchPreferences(username, { prefLang: selectedLlocale });
await postSetLang(selectedLlocale);
} else {
getCookies().set(langCookieName, selectedLlocale);
}
Copy link

Choose a reason for hiding this comment

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

Suggested change
try {
if (username) {
await patchPreferences(username, { prefLang: selectedLlocale });
await postSetLang(selectedLlocale);
} else {
getCookies().set(langCookieName, selectedLlocale);
}
try {
getCookies().set(langCookieName, selectedLlocale);
if (username) {
await patchPreferences(username, { prefLang: selectedLlocale });
await postSetLang(selectedLlocale);
}

Copy link
Contributor Author

@dcoa dcoa Apr 23, 2025

Choose a reason for hiding this comment

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

I thing the real problem is there are 2 cookies one is being updated the second one not, I will check if I can replicate the behavior and understand why that is happening. In any case, your suggest is good.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The suggested change creates a new cookie instead of changing the default one, because of that is not the best solution for the described problem.

I could identify that the described problem is only present in learning (that make sense for the iframe - django based does not change at runtime as react does).

Copy link
Contributor

@arbrandes arbrandes left a comment

Choose a reason for hiding this comment

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

This is a good direction, but I'd like to see this refactored to take into account openedx/frontend-platform#786. As a matter of fact, both PRs should be developed in tandem, so that all the state management and API calls are handled by frontend-platform, and the footer need only concern itself with the presentation.

options={supportedLanguages}
onSubmit={onLanguageSelected}
/>
{config.ENABLE_FOOTER_LANG_SELECTOR && (
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we need an env var for this. We can wrap the selector in a plugin slot instead, and if an operator doesn't want it, they can use the slot to remove it.

config: {
ENABLE_FOOTER_LANG_SELECTOR: true,
LANGUAGE_PREFERENCE_COOKIE_NAME,
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be implemented as part of openedx/frontend-platform#786. This PR should only be concerned with the UI elements.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, this PR should be refactored so that it contains only the display logic, leaving the API calls and state management to frontend-platform, via openedx/frontend-platform#786.

@openedx-webhooks openedx-webhooks added the core contributor PR author is a Core Contributor (who may or may not have write access to this repo). label Jun 5, 2025
@dcoa dcoa changed the title refactor: change lang selector logic [WIP] refactor: change lang selector logic Jun 13, 2025
@dcoa dcoa force-pushed the dcoa/lang-selector branch from 7ec5478 to c2d3ccc Compare June 13, 2025 06:32
@dcoa
Copy link
Contributor Author

dcoa commented Jun 13, 2025

I will pass this to draft and reopen it once the refactor is done

@dcoa dcoa marked this pull request as draft June 13, 2025 06:37
@dcoa dcoa force-pushed the dcoa/lang-selector branch from 871b384 to 73064f8 Compare June 18, 2025 05:39
fix: update test and linter

docs: add slot readme example

test: update snapshoots

vv
@dcoa dcoa force-pushed the dcoa/lang-selector branch from 73064f8 to 7997ef4 Compare June 18, 2025 05:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core contributor PR author is a Core Contributor (who may or may not have write access to this repo). open-source-contribution PR author is not from Axim or 2U
Projects
Status: Waiting on Author
Development

Successfully merging this pull request may close these issues.

7 participants