Skip to content
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

LPD-41528 Add batch GET method to Language Override APIs #786

Open
wants to merge 13 commits into
base: master
Choose a base branch
from

Conversation

rotty3000
Copy link

https://liferay.atlassian.net/browse/LPD-41528

Begin by enabling the feature flag:

feature.flag.LPD-27222=true

Next, somewhere, either in custom code or perhaps as an additional API in Liferay's libraries, define the following reusable function:

/*
 * Fetch the translation of the keys for the current language.
 * @param {Array<String>} keys The array of keys.
 * @returns {{[name:string]: string}} map of translations by key
 */
const fetchTranslations = async (keys) => {
    return await fetch(
        '/o/language/v1.0/messages/export?' + new URLSearchParams({
            languageId: Liferay.ThemeDisplay.getLanguageId()
        }), {
            body: JSON.stringify(keys),
            headers: {
                "Accept": "application/json",
                "Content-Type": "application/json"
            },
            method: 'POST'
        }
    ).then(
        r => r.json()
    ).then(
        r => r.items.reduce(
            (map, obj) => (map[obj.key] = obj.value, map), {}
        )
    );
};

This function, in addition to this PR, constitutes the reusable portion.

Next in custom code, a developer would collect the language keys used by their application in a JSON array:

// collect the keys somewhere in the app (maybe with tooling support)
const keys = [
    "800-by-600-pixels",
    "1024-by-768-pixels",
    "AUTHORIZATION_CODE",
    "AUTHORIZATION_CODE_PKCE",
    "AUTHORIZED_OAUTH2_SAP"
];

and finally, early in the initalization of their app, before any rendering occurs the following function (newly added by this PR) would be invoked:

Liferay.Language.put(await fetchTranslations(keys));

With that, all existing invocations of Liferay.Language.get('key') will simply work.

Use the following to test the api with curl:

curl http://localhost:8080/o/language/v1.0/messages/export?languageId=en_US \
  -s \
  --json '["800-by-600-pixels","1024-by-768-pixels","AUTHORIZATION_CODE","AUTHORIZATION_CODE_PKCE","AUTHORIZED_OAUTH2_SAP"]' | \
  jq 'reduce .items[] as $i ({}; .[$i.key] = $i.value)'

result should be:

{
  "800-by-600-pixels": "800 by 600 Pixels",
  "1024-by-768-pixels": "1024 by 768 Pixels",
  "AUTHORIZATION_CODE": "Authorization Code",
  "AUTHORIZATION_CODE_PKCE": "PKCE Extended Authorization Code",
  "AUTHORIZED_OAUTH2_SAP": "Service Access Policy for REST Requests Authorized by OAuth2"
}

@liferay-continuous-integration
Copy link
Collaborator

The following guidelines have been set by the owner of this repository:

  •     "Thank you for sending this PR to liferay-platform-experience. If you haven't already,take this opportunity to review our pull request guidelines. For additional help,please reach out via the appropriate channels."

@liferay-continuous-integration
Copy link
Collaborator

To conserve resources, the PR Tester does not automatically run for every pull.

If your code changes were already tested in another pull, reference that pull in this pull so the test results can be analyzed.

If your pull was never tested, comment "ci:test" to run the PR Tester for this pull.

@rotty3000
Copy link
Author

@izaera @dsanz @dnebing what do you think?

@thiago-buarqque
Copy link
Collaborator

The changes to our modules is fine. The other caching stuff I have no idea what's going on haha. I can look into that deeper on Monday

@izaera
Copy link

izaera commented Nov 11, 2024

The other caching stuff I have no idea what's going on haha. I can look into that deeper on Monday

@thiago-buarqque don't miss -> #786 (comment)

@rotty3000
Copy link
Author

After discussion with @izaera I will remove the javascript change and just leave the headless api for this PR. Then frontend infra Product Management can decide how to proceed with solutions to that aspect of the problem.

@rotty3000
Copy link
Author

@thiago-buarqque this change now only contains changes in portal-language-rest-* (and language keys)

@rotty3000 rotty3000 requested review from ethib137 and izaera November 12, 2024 15:45
Copy link
Collaborator

@thiago-buarqque thiago-buarqque left a comment

Choose a reason for hiding this comment

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

Hey @rotty3000, it's missing the implementation for testPostMessagesExportPage

return;
}

Map<Locale, String> map = ResourceBundleUtil.getLocalizationMap(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggestion: rename to localizationMap

@@ -213,6 +213,11 @@ public void testPutMessage() throws Exception {
Assert.assertTrue(false);
}

@Test
public void testPostMessagesExportPage() throws Exception {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Missing implementation for this

@izaera
Copy link

izaera commented Nov 13, 2024

After discussion with @izaera I will remove the javascript change and just leave the headless api for this PR. Then frontend infra Product Management can decide how to proceed with solutions to that aspect of the problem.

Not wanting to start another long discussion, but we decided to remove Liferay.Language.put for now because if you think at it, it doesn't make too much sense to couple a client extension to a vendor (Liferay) just to hold a map of translations 🤷

I mean, I get it could be used for legacy code, but I don't want to add a new public method to an old API to give the impression that we want people to keep using it in the future. I prefer to explore better options first. And when I say "I" it's me, not my product manager or team lead.

In any case we will discuss this in the team and see what comes next...

@izaera
Copy link

izaera commented Nov 13, 2024

to couple a client extension to a vendor (Liferay) just to hold a map of translations 🤷

Let me explain myself: why using Liferay.Language.get and Liferay.Language.put when you can simply do window.myTranslations[x] = 'y' and ${window.myTranslations[x]}? 🤔

Copy link

@izaera izaera left a comment

Choose a reason for hiding this comment

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

It's good for me since the JS code has been removed.

Regarding the headless API I'll leave the review up to Thiago 👍

@dnebing
Copy link

dnebing commented Nov 13, 2024

Why use Liferay.Language.get()?

For consistency. JS code that is using that will work if it is served out of Liferay (through the servlet filter) or from a CX with no significant change.

That's what we're hoping for with this, the platform taking care of the differences transparently, not requiring the developer to handle both scenarios manually.

@izaera
Copy link

izaera commented Nov 13, 2024

the platform taking care of the differences transparently

Yep, that would be the only reason and Ray and I discussed it yesterday but for that to happen we need more machinery because:

  1. With Liferay.Language.put you need to differentiate between out of Liferay or inside Liferay to know whether you need to invoke the headless API and invoke put or not.
  2. The LanguageFilter is preventing anything from being cached and there's no way to fix that so it would be better if people don't use it. Essentially it has the same problems of the minifier, which we already deprecated.

Said that, if the CXs provided a list of label keys to load (as we do internally for each JAR file with a language.json file that is created at build time) it could be almost totally transparent as you say (you would still need to issue a call to the server to load the labels).

Finally, take into account that whatever we do to make this work outside of Liferay will work in Liferay, which IMO is much better than using the LanguageFilter. What I mean is that if you (or the platform) request the labels through headless and put them in the Liferay.Language cache, you won't need the filter any more since it will work in all scenarios.

The same would happen now (even in the absence of proper infrastructure) if you decided to retrieve your labels from the server and store them inside any localization facility your framework of choice provides, and it would probably integrate better with your framework than Liferay.Language 😉

@izaera
Copy link

izaera commented Nov 13, 2024

So, for example, as I suggested @rotty3000 yesterday, when using React you can use things like this -> https://react.i18next.com/latest/i18nextprovider and this -> https://react.i18next.com/latest/i18next-instance and you get React-friendly translations.

Why using Liferay-friendly translations when you can integrate them and hide them behind React-friendly translations if all your app is written in React? To me it doesn't make sense to plague your code with invocations to platform vendor's API when you can make it agnostic 🤷

@izaera
Copy link

izaera commented Nov 13, 2024

I may be wrong, I haven't tried to create a full example with the links I've pasted, but it looks to me that loading a bunch of labels from a server and provide them to the framework you are using to render your UI is something most frameworks will support one way or another...

@rotty3000
Copy link
Author

@thiago-buarqque please take this PR and feel free to continue with it. I won't have time to continue to make changes to it. I was just trying to be helpful.

@ethib137
Copy link
Collaborator

@thiago-buarqque when you have some time, let's take advantage of the work Ray put in to add the Batch get method to language override. You can create a new PR that removes all of the JS stuff since that's outside of our team's scope.

@thiago-buarqque
Copy link
Collaborator

@rotty3000 @ethib137 Okay, I will work on this as soon as possible. There are some priorities to address right now.

@rotty3000
Copy link
Author

the JS parts are already removed!

@thiago-buarqque
Copy link
Collaborator

Guys, still no time to work on this, will do ASAP

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants