forked from actframework/actframework
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLocaleResolver.java
More file actions
190 lines (172 loc) · 5.71 KB
/
LocaleResolver.java
File metadata and controls
190 lines (172 loc) · 5.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
package act.i18n;
/*-
* #%L
* ACT Framework
* %%
* Copyright (C) 2014 - 2017 ActFramework
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import act.apidoc.Description;
import act.app.ActionContext;
import act.conf.AppConfig;
import act.controller.Controller;
import org.joda.time.DateTime;
import org.osgl.http.H;
import org.osgl.mvc.annotation.PostAction;
import org.osgl.util.S;
import java.util.Locale;
import javax.inject.Inject;
/**
* Responsible for setting up client Locale for the context
* <p>
* The client locale info is resolved in the following sequence:
* 1. check the request parameter by configured name
* 2. check the session variable
* 3. check the cookie value
* 4. check the `Accept-Language` header
* 5. use the server locale
*/
public class LocaleResolver {
private static final String KEY = "__locale__";
private static final int COOKIE_TTL = 60 * 60 * 24 * 7;
private ActionContext context;
private AppConfig config;
private boolean enabled;
private Locale locale;
private boolean reset;
private boolean resolvedFromParam;
@Description("Set locale to the session. The parameter name is configured with default value act_locale, it must be put as a query parameter instead of form field")
@PostAction("i18n/locale")
public static void updateLocale(H.Request request) {
// there is no logic needed as locale has been processed built-in logic already
String s = request.header(H.Header.Names.REFERER);
if (S.notBlank(s)) {
throw Controller.Util.redirect(s);
}
}
@Inject
public LocaleResolver(ActionContext context) {
AppConfig config = context.config();
this.enabled = config.i18nEnabled();
if (!this.enabled) {
return;
}
this.context = context;
this.config = config;
}
public void resolve() {
if (!enabled) {
return;
}
Locale locale = resolveFromParam();
if (!reset && null == locale) {
locale = resolveFromSessionOrCookie();
}
if (null == locale) {
locale = resolveFromHeader();
}
if (null == locale) {
locale = resolveFromServer();
}
context.locale(locale);
this.locale = locale;
}
public void dissolve() {
if (!shouldWriteLocaleCookie()) {
return;
}
String cookieName = config.localeCookieName();
Locale locale = context.locale();
if (null == locale) {
locale = this.locale;
}
String localeStr = locale.toString();
H.Session session = context.session();
if (null != session) {
if (reset) {
session.remove(KEY);
} else {
session.put(KEY, localeStr);
}
}
H.Cookie cookie = new H.Cookie(cookieName, localeStr);
cookie.domain(config.cookieDomain());
cookie.path("/");
// in case we have resolved locale from cookie and we shouldn't write cookie anymore, we need to clear it
cookie.maxAge(reset ? -1 : COOKIE_TTL);
if (reset) {
cookie.expires(DateTime.now().minusDays(1).toDate());
}
context.resp().addCookie(cookie);
}
private boolean shouldWriteLocaleCookie() {
/*
* 1. i18n must be enabled
* 2. anyone of the following condition is true
* 2.1 resolved from param
* 2.2 the current locale does not match the locale resolved originally (meaning programmatically updated locale)
* 2.3 reset is true (meaning session and cookie should be cleared)
*/
return enabled && (reset || resolvedFromParam || locale != context.locale());
}
private Locale resolveFromSessionOrCookie() {
Locale locale = null;
H.Session session = context.session();
if (null != session) {
locale = parseStr(session.get(KEY));
}
if (null == locale) {
H.Cookie cookie = context.cookie(config.localeCookieName());
locale = null == cookie ? null : parseStr(cookie.value());
}
return locale;
}
private Locale resolveFromParam() {
String s = context.paramValwithoutBodyParsing(config.localeParamName());
Locale locale = parseStr(s);
if (null != locale) {
resolvedFromParam = true;
}
return locale;
}
private Locale resolveFromHeader() {
return context.req().locale();
}
private Locale resolveFromServer() {
return config.locale();
}
private Locale parseStr(String val) {
if (null == val) {
return null;
}
if ("default".equals(val)) {
reset = true;
return null;
}
String[] sa = val.trim().split("[-_]");
int len = sa.length;
switch (len) {
case 3:
return new Locale(sa[0], sa[1], sa[2]);
case 2:
return new Locale(sa[0], sa[1]);
default:
return new Locale(sa[0]);
}
}
public static void main(String[] args) {
System.out.println(Locale.US.toLanguageTag());
}
}