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

Languages can only match exactly #66

Open
fenggwsx opened this issue Jan 21, 2025 · 0 comments
Open

Languages can only match exactly #66

fenggwsx opened this issue Jan 21, 2025 · 0 comments

Comments

@fenggwsx
Copy link

At present, gin-contrib/i18n can only match the language string in an exact level.

For example, when using en.json and zh.json with a default language of language.English, zh-CN will fallback to the default language because zh-CN and zh does not match exactly.

After reading the source codes, I find this problem is rooted in the logic of GetMessage function.

func (i *ginI18nImpl) GetMessage(ctx *gin.Context, param interface{}) (string, error) {
	lng := i.getLngHandler(ctx, i.defaultLanguage.String())
	localizer := i.getLocalizerByLng(lng)

	localizeConfig, err := i.getLocalizeConfig(param)
	if err != nil {
		return "", err
	}

	message, err := localizer.Localize(localizeConfig)
	if err != nil {
		return "", err
	}

	return message, nil
}

This function uses the getLocalizerByLng function to get a localizer from a map.

func (i *ginI18nImpl) getLocalizerByLng(lng string) *i18n.Localizer {
	localizer, hasValue := i.localizerByLng[lng]
	if hasValue {
		return localizer
	}

	return i.localizerByLng[i.defaultLanguage.String()]
}

To fix the problem is possible. Actually, the go-i18n package can automatically match the best language.

We can provide all the preferred languages in i18n.NewLocalizer, including the Accept-Language string, which can also be parsed correctly.

func NewLocalizer(bundle *Bundle, langs ...string) *Localizer {
	return &Localizer{
		bundle: bundle,
		tags:   parseTags(langs),
	}
}

The NewLocalizer function uses the parseTags function, where language.ParseAcceptLanguage is used.

func parseTags(langs []string) []language.Tag {
	tags := []language.Tag{}
	for _, lang := range langs {
		t, _, err := language.ParseAcceptLanguage(lang)
		if err != nil {
			continue
		}
		tags = append(tags, t...)
	}
	return tags
}

When Localizer.Localize is called, it will call the LocalizeWithTag function, in which Localizer.getMessageTemplate is called.

func (l *Localizer) getMessageTemplate(id string, defaultMessage *Message) (language.Tag, *MessageTemplate, error) {
	_, i, _ := l.bundle.matcher.Match(l.tags...)
	tag := l.bundle.tags[i]
	mt := l.bundle.getMessageTemplate(tag, id)
	if mt != nil {
		return tag, mt, nil
	}

	// ...
}

The first line uses Match to choose the best language.Tag in the supported languages.

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

No branches or pull requests

1 participant