Simplify ThemeLocaleContextResolver (#6651)

#### What type of PR is this?

/kind improvement
/area theme
/milestone 2.20.x

#### What this PR does / why we need it:

This PR simplifies ThemeLocaleContextResolver by removing unused attributes. 

In another PR <https://github.com/halo-dev/halo/pull/6647>, fixed locale resolution for query parameter `language`. This PR fixes locale resolution for cookie `language` as well.

Please see the results below:

```bash
http https://www.halo.run/ Cookie:language=zh-CN -p h

HTTP/1.1 200 OK
Content-Language: und
```

```bash
http http://localhost:8090 Cookie:language=zh-CN -p h

HTTP/1.1 200 OK
Content-Language: zh-CN
```

#### Does this PR introduce a user-facing change?

```release-note
None
```
pull/6656/head^2
John Niang 2024-09-13 15:44:26 +08:00 committed by GitHub
parent 25eec1ec4f
commit 8ab8a440b6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 30 additions and 56 deletions

View File

@ -1,15 +1,15 @@
package run.halo.app.theme;
import java.util.Locale;
import java.util.Optional;
import java.util.TimeZone;
import java.util.function.Function;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.i18n.LocaleContext;
import org.springframework.context.i18n.SimpleTimeZoneAwareLocaleContext;
import org.springframework.http.HttpCookie;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
@ -22,71 +22,45 @@ import org.springframework.web.server.i18n.AcceptHeaderLocaleContextResolver;
@Slf4j
@Component(WebHttpHandlerBuilder.LOCALE_CONTEXT_RESOLVER_BEAN_NAME)
public class ThemeLocaleContextResolver extends AcceptHeaderLocaleContextResolver {
public static final String TIME_ZONE_REQUEST_ATTRIBUTE_NAME =
ThemeLocaleContextResolver.class.getName() + ".TIME_ZONE";
public static final String LOCALE_REQUEST_ATTRIBUTE_NAME =
ThemeLocaleContextResolver.class.getName() + ".LOCALE";
public static final String DEFAULT_PARAMETER_NAME = "language";
public static final String LANGUAGE_PARAMETER_NAME = "language";
public static final String LANGUAGE_COOKIE_NAME = LANGUAGE_PARAMETER_NAME;
public static final String TIME_ZONE_COOKIE_NAME = "time_zone";
private final Function<ServerWebExchange, TimeZone> defaultTimeZoneFunction =
exchange -> getDefaultTimeZone();
@Override
@NonNull
public LocaleContext resolveLocaleContext(@NonNull ServerWebExchange exchange) {
parseLocaleCookieIfNecessary(exchange);
var request = exchange.getRequest();
var locale = getLocaleFromQueryParameter(request)
.or(() -> getLocaleFromCookie(request))
.orElseGet(() -> super.resolveLocaleContext(exchange).getLocale());
Locale locale = getLocale(exchange);
var timeZone = getTimeZoneFromCookie(request)
.orElseGet(TimeZone::getDefault);
return new SimpleTimeZoneAwareLocaleContext(locale,
exchange.getAttribute(TIME_ZONE_REQUEST_ATTRIBUTE_NAME));
return new SimpleTimeZoneAwareLocaleContext(locale, timeZone);
}
@Nullable
private Locale getLocale(ServerWebExchange exchange) {
String language = exchange.getRequest().getQueryParams()
.getFirst(DEFAULT_PARAMETER_NAME);
Locale locale;
if (StringUtils.isNotBlank(language)) {
locale = Locale.forLanguageTag(language);
} else if (exchange.getAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME) != null) {
locale = exchange.getAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME);
} else {
locale = super.resolveLocaleContext(exchange).getLocale();
}
return locale;
private Optional<Locale> getLocaleFromCookie(ServerHttpRequest request) {
return Optional.ofNullable(request.getCookies().getFirst(LANGUAGE_COOKIE_NAME))
.map(HttpCookie::getValue)
.filter(StringUtils::isNotBlank)
.map(Locale::forLanguageTag);
}
private TimeZone getDefaultTimeZone() {
return TimeZone.getDefault();
private Optional<Locale> getLocaleFromQueryParameter(ServerHttpRequest request) {
return Optional.ofNullable(request.getQueryParams().getFirst(LANGUAGE_PARAMETER_NAME))
.filter(StringUtils::isNotBlank)
.map(Locale::forLanguageTag);
}
private void parseLocaleCookieIfNecessary(ServerWebExchange exchange) {
if (exchange.getAttribute(TIME_ZONE_REQUEST_ATTRIBUTE_NAME) == null) {
TimeZone timeZone = null;
HttpCookie cookie = exchange.getRequest()
.getCookies()
.getFirst(TIME_ZONE_COOKIE_NAME);
if (cookie != null) {
String value = cookie.getValue();
timeZone = TimeZone.getTimeZone(value);
}
exchange.getAttributes().put(TIME_ZONE_REQUEST_ATTRIBUTE_NAME,
(timeZone != null ? timeZone : this.defaultTimeZoneFunction.apply(exchange)));
}
if (exchange.getAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME) == null) {
HttpCookie cookie = exchange.getRequest()
.getCookies()
.getFirst(DEFAULT_PARAMETER_NAME);
if (cookie != null) {
String value = cookie.getValue();
exchange.getAttributes()
.put(LOCALE_REQUEST_ATTRIBUTE_NAME, new Locale(value));
}
}
private Optional<TimeZone> getTimeZoneFromCookie(ServerHttpRequest request) {
return Optional.ofNullable(request.getCookies().getFirst(TIME_ZONE_COOKIE_NAME))
.map(HttpCookie::getValue)
.filter(StringUtils::isNotBlank)
.map(TimeZone::getTimeZone);
}
}

View File

@ -12,7 +12,7 @@ import static java.util.Locale.KOREA;
import static java.util.Locale.UK;
import static java.util.Locale.US;
import static org.assertj.core.api.Assertions.assertThat;
import static run.halo.app.theme.ThemeLocaleContextResolver.DEFAULT_PARAMETER_NAME;
import static run.halo.app.theme.ThemeLocaleContextResolver.LANGUAGE_COOKIE_NAME;
import static run.halo.app.theme.ThemeLocaleContextResolver.TIME_ZONE_COOKIE_NAME;
import java.util.Arrays;
@ -187,7 +187,7 @@ class ThemeLocaleContextResolverTest {
return MockServerWebExchange.from(
MockServerHttpRequest.get("").acceptLanguageAsLocales(locales)
.cookie(new HttpCookie(TIME_ZONE_COOKIE_NAME, "America/Adak"))
.cookie(new HttpCookie(DEFAULT_PARAMETER_NAME, "en")));
.cookie(new HttpCookie(LANGUAGE_COOKIE_NAME, "en")));
}
private ServerWebExchange exchangeForParam(String language) {