Locale Lookup
Trying to find a best-match for a given locale. Otherwise, returning a fallback but never returning an unsupported locale.
This commit is contained in:
parent
18eaa92eff
commit
d2fb59a992
|
@ -10,11 +10,13 @@ import org.springframework.web.servlet.LocaleResolver;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||||
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
|
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
|
||||||
|
|
||||||
|
import de.mstock.monolith.web.i18n.AcceptHeaderLookupLocaleResolver;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
public class I18nConfig extends WebMvcConfigurerAdapter {
|
public class I18nConfig extends WebMvcConfigurerAdapter {
|
||||||
|
|
||||||
private static final List<Locale> SUPPORTED_LOCALES =
|
private static final List<Locale> SUPPORTED_LOCALES =
|
||||||
Arrays.asList(new Locale("de_DE"), new Locale("en_US"));
|
Arrays.asList(new Locale("en", "US"), new Locale("de", "DE"));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a Bean, managed by Spring.
|
* Creates a Bean, managed by Spring.
|
||||||
|
@ -23,9 +25,10 @@ public class I18nConfig extends WebMvcConfigurerAdapter {
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public LocaleResolver localeResolver() {
|
public LocaleResolver localeResolver() {
|
||||||
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
|
Locale defaultLocale = SUPPORTED_LOCALES.get(0);
|
||||||
|
AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLookupLocaleResolver(defaultLocale);
|
||||||
localeResolver.setSupportedLocales(SUPPORTED_LOCALES);
|
localeResolver.setSupportedLocales(SUPPORTED_LOCALES);
|
||||||
localeResolver.setDefaultLocale(Locale.US);
|
localeResolver.setDefaultLocale(defaultLocale);
|
||||||
return localeResolver;
|
return localeResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package de.mstock.monolith.web.i18n;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Locale.LanguageRange;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
|
||||||
|
|
||||||
|
public class AcceptHeaderLookupLocaleResolver extends AcceptHeaderLocaleResolver {
|
||||||
|
|
||||||
|
private final Locale fallback;
|
||||||
|
private final ArrayList<LanguageRange> ranges = new ArrayList<>();
|
||||||
|
|
||||||
|
public AcceptHeaderLookupLocaleResolver(Locale fallback) {
|
||||||
|
this.fallback = fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSupportedLocales(List<Locale> locales) {
|
||||||
|
super.setSupportedLocales(locales);
|
||||||
|
ranges.clear();
|
||||||
|
for (Locale supportedLocale : getSupportedLocales()) {
|
||||||
|
ranges.add(new LanguageRange(supportedLocale.getLanguage() + "-*"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Locale resolveLocale(HttpServletRequest request) {
|
||||||
|
Locale resolvedLocale = super.resolveLocale(request);
|
||||||
|
if (getSupportedLocales().contains(resolvedLocale)) {
|
||||||
|
return resolvedLocale;
|
||||||
|
}
|
||||||
|
Locale lookup = Locale.lookup(ranges, Arrays.asList(resolvedLocale));
|
||||||
|
if (lookup != null) {
|
||||||
|
return lookup;
|
||||||
|
}
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,18 +1 @@
|
||||||
company = Mosh
|
company = Mosh
|
||||||
general.backToTop = Back to top
|
|
||||||
general.sampleImage = Sample image
|
|
||||||
navigation.toggle = Toggle navigation
|
|
||||||
navigation.legalNotice = Legal Notice
|
|
||||||
products.kiwis=Kiwis
|
|
||||||
products.blueberries=Blueberries
|
|
||||||
products.cherries=Cherries
|
|
||||||
products.kiwis.prettyUrlFragment=kiwis
|
|
||||||
products.blueberries.prettyUrlFragment=blueberries
|
|
||||||
products.cherries.prettyUrlFragment=cherries
|
|
||||||
products.goto = Go to product
|
|
||||||
features.headline1 = Delicious Fruits.
|
|
||||||
features.subheadline1 = It'll blow your mind.
|
|
||||||
features.headline2 = Oh yeah, it's that good.
|
|
||||||
features.subheadline2 = See for yourself.
|
|
||||||
features.headline3 = And lastly, this one.
|
|
||||||
features.subheadline3 = Checkmate.
|
|
|
@ -14,4 +14,4 @@ features.subheadline1 = Es wird dich umhauen.
|
||||||
features.headline2 = Das ist gut.
|
features.headline2 = Das ist gut.
|
||||||
features.subheadline2 = Sieh' selbst.
|
features.subheadline2 = Sieh' selbst.
|
||||||
features.headline3 = Und zum Schluss, das hier.
|
features.headline3 = Und zum Schluss, das hier.
|
||||||
features.subheadline3 = Bingo.
|
features.subheadline3 = Bingo.
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
general.backToTop = Back to top
|
||||||
|
general.sampleImage = Sample image
|
||||||
|
navigation.toggle = Toggle navigation
|
||||||
|
navigation.legalNotice = Legal Notice
|
||||||
|
products.kiwis=Kiwis
|
||||||
|
products.blueberries=Blueberries
|
||||||
|
products.cherries=Cherries
|
||||||
|
products.kiwis.prettyUrlFragment=kiwis
|
||||||
|
products.blueberries.prettyUrlFragment=blueberries
|
||||||
|
products.cherries.prettyUrlFragment=cherries
|
||||||
|
products.goto = Go to product
|
||||||
|
features.headline1 = Delicious Fruits.
|
||||||
|
features.subheadline1 = It'll blow your mind.
|
||||||
|
features.headline2 = Oh yeah, it's that good.
|
||||||
|
features.subheadline2 = See for yourself.
|
||||||
|
features.headline3 = And lastly, this one.
|
||||||
|
features.subheadline3 = Checkmate.
|
|
@ -1,19 +0,0 @@
|
||||||
package de.mstock.monolith;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
|
||||||
|
|
||||||
@RunWith(SpringRunner.class)
|
|
||||||
@SpringBootTest
|
|
||||||
public class MonolithApplicationTests {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void contextLoads() {
|
|
||||||
assertTrue(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
package de.mstock.monolith.web;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.containsString;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
import org.springframework.test.context.web.WebAppConfiguration;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||||
|
import org.springframework.web.context.WebApplicationContext;
|
||||||
|
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
@SpringBootTest
|
||||||
|
@WebAppConfiguration
|
||||||
|
public class HomepageControllerTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private WebApplicationContext webApplicationContext;
|
||||||
|
|
||||||
|
private MockMvc mockMvc;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldPrintEnglishTexts() throws Exception {
|
||||||
|
mockMvc.perform(get("/").header(HttpHeaders.ACCEPT_LANGUAGE, "en").locale(new Locale("en")))
|
||||||
|
.andExpect(status().isOk()).andExpect(content().string(containsString("Fruits")))
|
||||||
|
.andExpect(content().string(containsString("to top")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldPrintGermanTexts() throws Exception {
|
||||||
|
mockMvc.perform(get("/").header(HttpHeaders.ACCEPT_LANGUAGE, "de").locale(new Locale("de")))
|
||||||
|
.andExpect(status().isOk()).andExpect(status().isOk())
|
||||||
|
.andExpect(content().string(containsString("Obst")))
|
||||||
|
.andExpect(content().string(containsString("nach oben")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldPrintEnglishTextsForAustralia() throws Exception {
|
||||||
|
mockMvc
|
||||||
|
.perform(
|
||||||
|
get("/").header(HttpHeaders.ACCEPT_LANGUAGE, "en-AU").locale(new Locale("en", "AU")))
|
||||||
|
.andExpect(status().isOk()).andExpect(content().string(containsString("Fruits")))
|
||||||
|
.andExpect(content().string(containsString("to top")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldPrintGermanTextsForAustria() throws Exception {
|
||||||
|
mockMvc
|
||||||
|
.perform(
|
||||||
|
get("/").header(HttpHeaders.ACCEPT_LANGUAGE, "de-AT").locale(new Locale("de", "AT")))
|
||||||
|
.andExpect(status().isOk()).andExpect(status().isOk())
|
||||||
|
.andExpect(content().string(containsString("Obst")))
|
||||||
|
.andExpect(content().string(containsString("nach oben")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldPrintEnglishTextsForChina() throws Exception {
|
||||||
|
mockMvc
|
||||||
|
.perform(
|
||||||
|
get("/").header(HttpHeaders.ACCEPT_LANGUAGE, "zh-CN").locale(new Locale("zh", "CN")))
|
||||||
|
.andExpect(status().isOk()).andExpect(content().string(containsString("Fruits")))
|
||||||
|
.andExpect(content().string(containsString("to top")));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue