diff --git a/README.md b/README.md
index 32da999..321ec5a 100644
--- a/README.md
+++ b/README.md
@@ -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.
@@ -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.
+
### Changelog
* See [GitHub releases](https://github.com/jenkinsci/locale-plugin/releases) for new releases
diff --git a/pom.xml b/pom.xml
index 96c0e17..c743d66 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
Locale plugin
https://github.com/jenkinsci/locale-plugin
-
+
org.jenkins-ci.plugins
plugin
@@ -57,7 +57,15 @@
scm:git:ssh://git@github.com/jenkinsci/locale-plugin.git
https://github.com/jenkinsci/locale-plugin
HEAD
-
+
+
+
+
+ org.jenkins-ci
+ symbol-annotation
+ 1.1
+
+
diff --git a/src/main/java/hudson/plugins/locale/LocaleFilter.java b/src/main/java/hudson/plugins/locale/LocaleFilter.java
index b3e1bee..e62d4d7 100644
--- a/src/main/java/hudson/plugins/locale/LocaleFilter.java
+++ b/src/main/java/hudson/plugins/locale/LocaleFilter.java
@@ -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;
@@ -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;
@@ -29,16 +33,32 @@ 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) {
+ 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);
}
@@ -46,4 +66,18 @@ public Locale getLocale() {
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;
+ }
+
}
diff --git a/src/main/java/hudson/plugins/locale/PluginImpl.java b/src/main/java/hudson/plugins/locale/PluginImpl.java
index e6dc8e0..01143ed 100644
--- a/src/main/java/hudson/plugins/locale/PluginImpl.java
+++ b/src/main/java/hudson/plugins/locale/PluginImpl.java
@@ -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.
@@ -66,6 +67,7 @@ public void configure(StaplerRequest req, JSONObject jsonObject)
throws IOException, ServletException, FormException {
setSystemLocale(jsonObject.getString("systemLocale"));
ignoreAcceptLanguage = jsonObject.getBoolean("ignoreAcceptLanguage");
+ allowUserPreferences = jsonObject.getBoolean("allowUserPreferences");
save();
}
@@ -73,6 +75,10 @@ public boolean isIgnoreAcceptLanguage() {
return ignoreAcceptLanguage;
}
+ public boolean isAllowUserPreferences() {
+ return allowUserPreferences;
+ }
+
public String getSystemLocale() {
return systemLocale;
}
@@ -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.
*
diff --git a/src/main/java/hudson/plugins/locale/user/UserLocaleProperty.java b/src/main/java/hudson/plugins/locale/user/UserLocaleProperty.java
new file mode 100644
index 0000000..537cdd3
--- /dev/null
+++ b/src/main/java/hudson/plugins/locale/user/UserLocaleProperty.java
@@ -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
+ @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"));
+ }
+ }
+}
diff --git a/src/main/resources/hudson/plugins/locale/Messages.properties b/src/main/resources/hudson/plugins/locale/Messages.properties
new file mode 100644
index 0000000..7d0d1a8
--- /dev/null
+++ b/src/main/resources/hudson/plugins/locale/Messages.properties
@@ -0,0 +1 @@
+locale=Locale
diff --git a/src/main/resources/hudson/plugins/locale/PluginImpl/config.jelly b/src/main/resources/hudson/plugins/locale/PluginImpl/config.jelly
index a13c91d..e28b479 100644
--- a/src/main/resources/hudson/plugins/locale/PluginImpl/config.jelly
+++ b/src/main/resources/hudson/plugins/locale/PluginImpl/config.jelly
@@ -8,5 +8,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/hudson/plugins/locale/PluginImpl/config.properties b/src/main/resources/hudson/plugins/locale/PluginImpl/config.properties
index 4d12625..9393b90 100644
--- a/src/main/resources/hudson/plugins/locale/PluginImpl/config.properties
+++ b/src/main/resources/hudson/plugins/locale/PluginImpl/config.properties
@@ -1 +1,2 @@
-description=Ignore browser preference and force this language to all users
\ No newline at end of file
+description=Ignore browser preference and force this language to all users
+userPreferDescription=Allow all users have their own language setting
\ No newline at end of file
diff --git a/src/main/resources/hudson/plugins/locale/user/UserLocaleProperty/config.jelly b/src/main/resources/hudson/plugins/locale/user/UserLocaleProperty/config.jelly
new file mode 100644
index 0000000..7c57c96
--- /dev/null
+++ b/src/main/resources/hudson/plugins/locale/user/UserLocaleProperty/config.jelly
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/src/test/java/hudson/plugins/locale/UserLocaleTest.java b/src/test/java/hudson/plugins/locale/UserLocaleTest.java
new file mode 100644
index 0000000..8573a95
--- /dev/null
+++ b/src/test/java/hudson/plugins/locale/UserLocaleTest.java
@@ -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);
+ }
+}