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

[JENKINS-57456] User language prefer setting support #8

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ This plugin allows you to:

* override the system default locale to the language of your choice
* ignore browser's language preference completely
* allow users set their own language preferences

This feature is sometimes convenient for multi-lingual environment.

Expand All @@ -30,6 +31,9 @@ you're using have been translated into the specified language).
To additionally force this language on all users, overriding their browser language,
you can check the "Ignore browser preference and force this language to all users" option.

If you want to have a different language setting for your user, please configure a custom locale in your profile settings page.
This feature needs to be firstly enabled by the Jenkins instance admins in global settings.
Copy link
Member

Choose a reason for hiding this comment

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

why?

Copy link
Member

Choose a reason for hiding this comment

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

Admins may want to enforce the locale on the instance. E.g. it would be my approach


### Changelog

* See [GitHub releases](https://github.com/jenkinsci/locale-plugin/releases) for new releases
Expand Down
12 changes: 10 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

<name>Locale plugin</name>
<url>https://github.com/jenkinsci/locale-plugin</url>

<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
Expand Down Expand Up @@ -57,7 +57,15 @@
<developerConnection>scm:git:ssh://[email protected]/jenkinsci/locale-plugin.git</developerConnection>
<url>https://github.com/jenkinsci/locale-plugin</url>
<tag>HEAD</tag>
</scm>
</scm>

<dependencies>
<dependency>
<groupId>org.jenkins-ci</groupId>
<artifactId>symbol-annotation</artifactId>
<version>1.1</version>
</dependency>
</dependencies>

</project>

Expand Down
38 changes: 36 additions & 2 deletions src/main/java/hudson/plugins/locale/LocaleFilter.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package hudson.plugins.locale;

import hudson.model.User;
import hudson.plugins.locale.user.UserLocaleProperty;
import jenkins.model.Jenkins;

import javax.annotation.CheckForNull;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
Expand All @@ -10,6 +13,7 @@
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Locale;

Expand All @@ -29,21 +33,51 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
throws IOException, ServletException {
if (request instanceof HttpServletRequest) {
PluginImpl plugin = (PluginImpl) Jenkins.getActiveInstance().getPlugin("locale");
if (plugin != null && plugin.isIgnoreAcceptLanguage()) {
final Locale locale;
Locale currentUserLocale = getCurrentUserLocale();

if (plugin == null) {
LinuxSuRen marked this conversation as resolved.
Show resolved Hide resolved
chain.doFilter(request, response);
return;
} else if (plugin.isAllowUserPreferences() && currentUserLocale != null) {
locale = currentUserLocale;
} else if (plugin.isIgnoreAcceptLanguage()) {
locale = Locale.getDefault();
} else {
locale = null;
}

if(locale != null) {
request = new HttpServletRequestWrapper((HttpServletRequest) request) {
@Override
public Locale getLocale() {
// Force locale to configured default, ignore request' Accept-Language header
return Locale.getDefault();
return locale;
}
};
((HttpServletResponse)response).addHeader("X-Jenkins-Language", locale.toString());
}
}

chain.doFilter(request, response);
}

@Override
public void destroy() {
// nop
}

@CheckForNull
private Locale getCurrentUserLocale() {
User user = User.current();
if(user != null) {
UserLocaleProperty userLocaleProperty = user.getProperty(UserLocaleProperty.class);
if(userLocaleProperty == null) {
return null;
}
return userLocaleProperty.getLocale();
}
return null;
}

}
10 changes: 10 additions & 0 deletions src/main/java/hudson/plugins/locale/PluginImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public class PluginImpl extends Plugin {

private String systemLocale;
private boolean ignoreAcceptLanguage;
private boolean allowUserPreferences;

/**
* The value of {@link Locale#getDefault()} before we replace it.
Expand Down Expand Up @@ -66,13 +67,18 @@ public void configure(StaplerRequest req, JSONObject jsonObject)
throws IOException, ServletException, FormException {
setSystemLocale(jsonObject.getString("systemLocale"));
ignoreAcceptLanguage = jsonObject.getBoolean("ignoreAcceptLanguage");
allowUserPreferences = jsonObject.getBoolean("allowUserPreferences");
save();
}

public boolean isIgnoreAcceptLanguage() {
return ignoreAcceptLanguage;
}

public boolean isAllowUserPreferences() {
return allowUserPreferences;
}

public String getSystemLocale() {
return systemLocale;
}
Expand All @@ -94,6 +100,10 @@ public void setIgnoreAcceptLanguage(boolean ignoreAcceptLanguage) {
this.ignoreAcceptLanguage = ignoreAcceptLanguage;
}

public void setAllowUserPreferences(boolean allowUserPreferences) {
this.allowUserPreferences = allowUserPreferences;
}

/**
* Parses a string like "ja_JP" into a {@link Locale} object.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package hudson.plugins.locale.user;

import hudson.Extension;
import hudson.model.User;
import hudson.model.UserProperty;
import hudson.model.UserPropertyDescriptor;
import hudson.plugins.locale.Messages;
import hudson.plugins.locale.PluginImpl;
import net.sf.json.JSONObject;
import org.jenkinsci.Symbol;
import org.jvnet.localizer.LocaleProvider;
import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.StaplerRequest;

import java.util.Locale;

public class UserLocaleProperty extends UserProperty {
private String localeCode;

private Locale locale; // for the cache purpose

public UserLocaleProperty(String localeCode) {
this.localeCode = localeCode;
}

public Locale getLocale() {
return locale;
}

public String getLocaleCode() {
return localeCode;
}

@DataBoundSetter
public void setLocaleCode(String localeCode) {
try {
locale = PluginImpl.parse(localeCode);
} catch (IllegalArgumentException e) {
// ignore this exception
}
this.localeCode = localeCode;
}

@Extension
LinuxSuRen marked this conversation as resolved.
Show resolved Hide resolved
@Symbol("userLocale")
public static final class DescriptorImpl extends UserPropertyDescriptor {
public String getDisplayName() {
return Messages.locale();
}

public UserProperty newInstance(User user) {
return new UserLocaleProperty(LocaleProvider.getLocale().toString());
}

@Override
public UserProperty newInstance(StaplerRequest req, JSONObject formData) throws FormException {
return new UserLocaleProperty(formData.optString("locale"));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
locale=Locale
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,9 @@
<f:checkbox name="ignoreAcceptLanguage" checked="${it.ignoreAcceptLanguage}" />
<label class="attach-previous">${%description}</label>
</f:nested>
<f:nested>
<f:checkbox name="allowUserPreferences" checked="${it.allowUserPreferences}" />
<label class="attach-previous">${%userPreferDescription}</label>
</f:nested>
</f:section>
</j:jelly>
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
description=Ignore browser preference and force this language to all users
description=Ignore browser preference and force this language to all users
userPreferDescription=Allow all users have their own language setting
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form">
<f:entry title="${%Language}">
<f:textbox field="localeCode" />
</f:entry>
</j:jelly>
51 changes: 51 additions & 0 deletions src/test/java/hudson/plugins/locale/UserLocaleTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package hudson.plugins.locale;

import hudson.model.Item;
import hudson.model.User;
import hudson.plugins.locale.user.UserLocaleProperty;
import jenkins.model.Jenkins;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.MockAuthorizationStrategy;

import static org.junit.Assert.assertEquals;

public class UserLocaleTest {

@Rule
public JenkinsRule j = new JenkinsRule();

@Test
public void differentUsers() throws Exception {
j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
MockAuthorizationStrategy authorizationStrategy = new MockAuthorizationStrategy();
authorizationStrategy.grant(Jenkins.READ).onRoot().toEveryone();
authorizationStrategy.grant(Item.READ).everywhere().to("bob");
authorizationStrategy.grant(Item.READ).everywhere().to("alice");
j.jenkins.setAuthorizationStrategy(authorizationStrategy);

PluginImpl plugin = (PluginImpl) j.jenkins.getPlugin("locale");
plugin.setAllowUserPreferences(true);

// test for zh_CN user
User userBob = User.get("bob", true, null);
UserLocaleProperty userLocaleProperty = userBob.getProperty(UserLocaleProperty.class);
userLocaleProperty.setLocaleCode("zh_CN");

JenkinsRule.WebClient wc = j.createWebClient().login("bob");
String language = wc.goTo("", "text/html")
.getWebResponse().getResponseHeaderValue("X-Jenkins-Language");
assertEquals("zh_CN", language);

// test for en user
User userAlice = User.get("alice", true, null);
userLocaleProperty = userAlice.getProperty(UserLocaleProperty.class);
userLocaleProperty.setLocaleCode("en");

wc = j.createWebClient().login("alice");
language = wc.goTo("", "text/html")
.getWebResponse().getResponseHeaderValue("X-Jenkins-Language");
assertEquals("en", language);
}
}