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

Base setup for i18n for server with go-i18n library #782

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

Kshitij-Katiyar
Copy link
Contributor

@Kshitij-Katiyar Kshitij-Katiyar commented May 28, 2024

Summary

It includes:

  1. Added the go-i18n library v2.
  2. Added sample translation and also en.json file

Fixes #783

Copy link
Contributor

@mickmister mickmister left a comment

Choose a reason for hiding this comment

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

LGTM, just a suggestion on wording

@@ -95,6 +96,8 @@ type Plugin struct {
poster poster.Poster
flowManager *FlowManager

b *i18n.Bundle
Copy link
Contributor

Choose a reason for hiding this comment

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

This names seems a bit cryptic to me. Maybe we can call it localization or i18n? @hanzei Thoughts on this?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, b isn't quite telling. 2./5 on bundle as i18n is already a library name.

@@ -609,14 +610,22 @@ func (p *Plugin) handleMe(_ *plugin.Context, _ *model.CommandArgs, _ []string, u
return text
}

func (p *Plugin) handleHelp(_ *plugin.Context, _ *model.CommandArgs, _ []string, _ *GitHubUserInfo) string {
func (p *Plugin) handleHelp(_ *plugin.Context, args *model.CommandArgs, _ []string, _ *GitHubUserInfo) string {
l := p.b.GetUserLocalizer(args.UserId)
message, err := renderTemplate("helpText", p.getConfiguration())
Copy link
Contributor

Choose a reason for hiding this comment

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

Curious how we can use the translations in the templates?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah @mickmister I was trying to find the same thing.

Copy link
Contributor

Choose a reason for hiding this comment

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

Can we expose functions to call from within the template?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this is something we should try and solve before merging the PR. Any question marks we have on how to do things like this should ideally be resolved before contributors go and work on the same sort of things

Copy link
Contributor

Choose a reason for hiding this comment

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

We can implement this method:

func (p *Plugin) localize(id, other string) string {
	return p.b.LocalizeWithConfig(l, &i18n.LocalizeConfig{
		DefaultMessage: &i18n.Message{
			ID:    id,
			Other: other,
		},
	})
}

Then change

to

func (p *Plugin) initTemplates() {

and add a block here

funcMap["commitAuthor"] = func(commit *github.HeadCommit) *github.CommitAuthor {
if showAuthorInCommitNotification {
return commit.GetAuthor()
}
return commit.GetCommitter()
}
masterTemplate = template.Must(template.New("master").Funcs(funcMap).Parse(""))

to

funcMap["i18n"] = p.localize

Then we should be able to use the i18n function in the templates

Copy link
Contributor Author

@Kshitij-Katiyar Kshitij-Katiyar Jun 24, 2024

Choose a reason for hiding this comment

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

Hey @mickmister Thanks for the approach above, I tried a bunch of things as stated above but faced several issues.
First of all, there is a huge lack of documentation and resources on the internet regarding Go's text/template and i was not able to find anything which connects the translation and template together. If you have some resources, please share those i would love to deep dive into those.

First of all, When using higher-order functions inside the template directly, it prints the function returned by the parent function instead of trying to run the child function returned with the arguments passed(similar code here dummy code). I also tried storing the child function in a variable and calling it with the arguments, but that didn't work either. (You can have a link here goPlayground)

Secondly, the approach of making the initTemplate a method of the Plugin also didn't work because, during the initialization of the template, the Plugin is null.

Copy link
Contributor

Choose a reason for hiding this comment

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

Secondly, the approach of making the initTemplate a method of the Plugin also didn't work because, during the initialization of the template, the Plugin is null.

@Kshitij-Katiyar We should be able to call initTemplate during OnActivate to make that work

I'm not sure about the template functions behavior

@mickmister
Copy link
Contributor

In order to include localization in templates, we'll need to have the code-operated parts (i.e. markdown link construction) of the message be parameterized into the translation string. We can pass the calculated sub-template calls as a dictionary argument to the localize function

With this in i18n/en.json

{
     "newPullRequestCollapsed": "{{.RepoName}} New pull request {{.PullRequestTitle}} was opened by {{.UserName}}.",
}
func localize(bundle *i18n.Bundle, lang string) func(id string, data map[string]interface{}) string {
    return func(id string, data map[string]interface{}) string {
        localizer := i18n.NewLocalizer(bundle, lang)
        return localizer.MustLocalize(&i18n.LocalizeConfig{
            MessageID:    id,
            TemplateData: data,
        })
    }
}

Then we can change

{{template "repo" .Event.GetRepo}} New pull request {{template "pullRequest" .Event.GetPullRequest}} was opened by {{template "user" .Event.GetSender}}.

to

{{ localize "newPullRequestCollapsed" dict "RepoName" (template "repo" .Event.GetRepo) "PullRequestTitle" (template "pullRequest" .Event.GetPullRequest) "UserName" (template "user" .Event.GetSender) }}

Or we could instead make local variables in the template like this for potentially better readability, but we'll need to implement an expose a templateToString function to return a string:

{{ $repo := templateToString "repo" .Event.GetRepo }}
{{ $pullRequest := templateToString "pullRequest" .Event.GetPullRequest }}
{{ $user := templateToString "user" .Event.GetSender }}
{{ localize "newPullRequestCollapsed" dict "RepoName" $repo "PullRequestTitle" $pullRequest "UserName" $user }}

@hanzei hanzei added the 2: Dev Review Requires review by a core committer label Jun 27, 2024
Copy link
Contributor

@hanzei hanzei left a comment

Choose a reason for hiding this comment

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

That is a great starting point!

How can community members contribute to translations? Do we plan to hook the repo up to https://translate.mattermost.com/?

@@ -95,6 +96,8 @@ type Plugin struct {
poster poster.Poster
flowManager *FlowManager

b *i18n.Bundle
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, b isn't quite telling. 2./5 on bundle as i18n is already a library name.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2: Dev Review Requires review by a core committer
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement server-side localization for the plugin
3 participants