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
CONSOLE-2425: Support localization of dynamic plugins #9196
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @jhadvig. We'll want to update the frontend code as well to use the new endpoint.
pkg/server/server.go
Outdated
@@ -55,6 +55,7 @@ const ( | |||
devfileEndpoint = "/api/devfile/" | |||
devfileSamplesEndpoint = "/api/devfile/samples/" | |||
pluginsEndpoint = "/api/plugins/" | |||
localesEndpoint = "api/locales/" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wouldn't put this under /api
because this request doesn't require auth. Any request under the /api
path will have the user's session cookie.
pkg/plugins/handlers.go
Outdated
|
||
// parseLangAndPluginName will parse the language and plugin locale file | ||
func parseLangAndPluginLocaleFile(urlPath string) (string, string, error) { | ||
langAndPluginLocaleFile := strings.SplitN(urlPath, "/", 2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wish we were using something like https://github.com/gorilla/mux to handle variables in the path, although that seems like overkill for one endpoint.
I'd suggest simply using query parameters lng
and ns
to avoid having to parse the path. We might eventually support multi-loading, and the query parameters would fit better with that (although that could be difficult if we need to proxy some requests).
https://github.com/i18next/i18next-http-backend#backend-options
pkg/plugins/handlers.go
Outdated
klog.Errorf(redirectTo) | ||
} | ||
|
||
resp, err := p.Client.Get(redirectTo) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this actually making an HTTP request for static files? Can we serve static files directly instead using http.ServeFile
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should
pkg/plugins/handlers.go
Outdated
// In case of the dynamic plugin the localization namespace should contain name of the plugin prefixed with 'plugin:' prefix | ||
// No file extension is needed since for the dynamic plugins we will fetch 'default.json' from the plugin pod. | ||
// eg. 'plugin:helm-plugin' | ||
pluginLocale := query.Get("ns") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't a locale. I'd stick to namespace
as the variable name.
pkg/plugins/handlers.go
Outdated
// In case of the dynamic plugin the localization namespace should contain name of the plugin prefixed with 'plugin:' prefix | ||
// No file extension is needed since for the dynamic plugins we will fetch 'default.json' from the plugin pod. | ||
// eg. 'plugin:helm-plugin' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you open a PR to update the dynamic plugin enhancement with this proposal? Then we can get agreement from stakeholders.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pkg/plugins/handlers.go
Outdated
} | ||
// in case of dynamic-plugin we need to trim the "plugin:" prefix. | ||
pluginName := strings.TrimPrefix(pluginLocale, "plugin:") | ||
http.Redirect(w, r, path.Join(r.Host, "api/plugins", pluginName, "locales", lang, "default.json"), http.StatusSeeOther) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should confirm that i18next-http-backend handles redirects. It might be better just to proxy the content here if it's not too hard.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, proxying makes more sense ... updated
@spadgett comments addressed. |
@spadgett updated the PR per updates in the enhancement |
/test e2e-gcp-console |
60fbab5
to
b38a92b
Compare
@spadgett I've addted locales to the dynamic-demo-plugin and updated the two Dockerfiles we have for it. |
frontend/dynamic-demo-plugin/locales/en/dynamic-demo-plugin.json
Outdated
Show resolved
Hide resolved
pkg/plugins/handlers.go
Outdated
// in case of dynamic-plugin we need to trim the "plugin__" prefix. | ||
pluginName := strings.TrimPrefix(namespace, "plugin__") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I personally wouldn't trim the prefix here. I'd make the the filename match the actual namespace used like plugin__kubevirt.json
since that's how i18next normally works.
Either way, we should make that more clear in the enhancement proposal with a specific example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the plus side, this would prevent e.g. plugin__kubevirt-plugin.json
file names 😃
Having i18n namespace match the file name sounds pretty straight-forward, sounds OK to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@spadgett I trim the plugin__
prefix to get the plugin service endpoint from the map of all the active plugins, where we are mapping the plugin name to its service endpoint. Based on the conversation I dont think ConsolePlugin resource name will contain the prefix, thats why Im trimming it to get the real name.
@@ -0,0 +1,3 @@ | |||
{ | |||
"Subject": "Subject" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this used anywhere in the demo plugin?
I would only add the JSON files if we're actually using it somewhere in the demo plugin to give a real example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no its not, in that case I can just put there and empty json
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can have a follow-up PR that illustrates localization usage in dynamic demo plugin.
- localizing strings in
console-extensions.json
- localizing strings in a plain function
- localizing strings in a React component
Once this PR is merged and the conventions are settled, I can write that PR.
@spadgett @vojtechszocs I've rebased the PR and addressed comments. Also remove the i18n changes in the dynamic plugin since we will address those as follow up PTAL |
Test failure looks like it might be related.
|
browser.log has a large amount of missing key errors: |
Looking deeper, I see the files are failing to load.
|
Hmm wondering if thats related to the PR since there are also other errors
|
@jhadvig Those are expected on initial console load since you're not logged in yet. |
/test e2e-gcp-console |
pkg/plugins/handlers.go
Outdated
} | ||
} | ||
|
||
func (p *PluginsHandler) HandlePlugins(w http.ResponseWriter, r *http.Request) { | ||
func (p *PluginsHandler) HandleLocales(w http.ResponseWriter, r *http.Request) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are resources, not locales.
func (p *PluginsHandler) HandleLocales(w http.ResponseWriter, r *http.Request) { | |
func (p *PluginsHandler) HandleI18nResources(w http.ResponseWriter, r *http.Request) { |
pkg/plugins/handlers.go
Outdated
// In case of console app or static plugins, the localization namespace should contain name of the json file that contains the localized strings, | ||
// since various console packages have different names for the localization file. | ||
// eg. namespace query for the local-storage-operator-plugin locales - '&ns=lso-plugin' | ||
// In case of the dynamic plugin the localization namespace should contain name of the plugin prefixed with 'plugin__' prefix. | ||
// No file extension is needed since for the dynamic plugins we will fetch file from the plugin pod, based on the namespace. | ||
// eg. 'plugin__helm' will fetch `/locales/{lang}/plugin__helm.json` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is the important bit, so I'd trim the comment to just this:
// In case of console app or static plugins, the localization namespace should contain name of the json file that contains the localized strings, | |
// since various console packages have different names for the localization file. | |
// eg. namespace query for the local-storage-operator-plugin locales - '&ns=lso-plugin' | |
// In case of the dynamic plugin the localization namespace should contain name of the plugin prefixed with 'plugin__' prefix. | |
// No file extension is needed since for the dynamic plugins we will fetch file from the plugin pod, based on the namespace. | |
// eg. 'plugin__helm' will fetch `/locales/{lang}/plugin__helm.json` | |
// In case of the dynamic plugins, the namespace should contain name of the plugin prefixed with 'plugin__' prefix. | |
// eg. 'plugin__helm' will fetch `locales/{lang}/plugin__helm.json` from the plugin service |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/lgtm
/hold for approvals
/assign @yapei @ahardin-rh @sferich888
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: jhadvig, spadgett The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
/label docs-approved |
/label px-approved |
tested the changes and it is working well |
/hold cancel |
Implementing additional endpoint for handling locales. The endpoint has following format:
api/locales/<language>/<plugin-locale-file>
eg.
api/locales/en/olm.json
When the request hits the endpoint:
loadPath
, which is set tostatic/locales/{{lng}}/{{ns}}.json
Hopefully I understood the desired logic correctly.
@spadgett shall I also update the i18n enhancement ?
PTAL