View Javadoc
1   /*
2    * Copyright 2018-2020 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.bremersee.common.model;
18  
19  import com.fasterxml.jackson.annotation.JsonIgnore;
20  import com.fasterxml.jackson.annotation.JsonProperty;
21  import io.swagger.v3.oas.annotations.media.Schema;
22  import java.io.Serializable;
23  import java.util.Arrays;
24  import java.util.Locale;
25  import java.util.MissingResourceException;
26  import java.util.regex.Pattern;
27  import lombok.Builder;
28  import lombok.EqualsAndHashCode;
29  import lombok.NoArgsConstructor;
30  import org.springframework.util.StringUtils;
31  
32  /**
33   * Java locale model.
34   *
35   * @author Christian Bremer
36   */
37  @Schema(description = "A locale representation.")
38  @EqualsAndHashCode
39  @NoArgsConstructor
40  public class JavaLocale implements Serializable {
41  
42    private static final long serialVersionUID = 1L;
43  
44    @JsonIgnore
45    private String language;
46  
47    @JsonIgnore
48    private String country;
49  
50    /**
51     * Instantiates a new java locale.
52     *
53     * @param value the value
54     */
55    protected JavaLocale(String value) {
56      if (value == null || value.trim().length() < 2) {
57        setLanguage(null);
58        setCountry(null);
59      } else {
60        String source = value.trim().replace("-", "_");
61        String[] parts = source.split(Pattern.quote("_"));
62        setLanguage(parts[0]);
63        if (parts.length > 1) {
64          setCountry(parts[1]);
65        }
66      }
67    }
68  
69    /**
70     * Instantiates a new java locale.
71     *
72     * @param language the language
73     * @param country the country
74     */
75    @Builder(toBuilder = true)
76    public JavaLocale(String language, String country) {
77      setLanguage(language);
78      setCountry(country);
79    }
80  
81    /**
82     * Instantiates a new java locale.
83     *
84     * @param language the language
85     * @param country the country
86     */
87    public JavaLocale(TwoLetterLanguageCode language, TwoLetterCountryCode country) {
88      this.language = language != null ? language.toString() : null;
89      this.country = country != null ? country.toString() : null;
90    }
91  
92    /**
93     * Instantiates a new java locale.
94     *
95     * @param language the language
96     * @param country the country
97     */
98    public JavaLocale(ThreeLetterLanguageCode language, ThreeLetterCountryCode country) {
99      this.language = language != null ? language.toLocale().getLanguage() : null;
100     this.country = country != null ? country.toLocale().getCountry() : null;
101   }
102 
103   /**
104    * Gets language.
105    *
106    * @return the language
107    */
108   @Schema(description = "The two letter language code.", example = "de")
109   @JsonProperty("language")
110   public String getLanguage() {
111     return language;
112   }
113 
114   /**
115    * Sets language.
116    *
117    * @param language the language
118    */
119   @JsonProperty("language")
120   public void setLanguage(String language) {
121     if (StringUtils.hasText(language)) {
122       for (Locale l : Locale.getAvailableLocales()) {
123         try {
124           if (l.getLanguage().equalsIgnoreCase(language)
125               || (l.getISO3Language() != null && l.getISO3Language().equalsIgnoreCase(language))) {
126             this.language = l.getLanguage();
127             return;
128           }
129         } catch (MissingResourceException ignored) {
130           // ignored
131         }
132       }
133       if (Arrays.stream(Locale.getISOLanguages()).anyMatch(iso -> iso.equalsIgnoreCase(language))) {
134         this.language = language.toLowerCase();
135         return;
136       }
137     }
138     this.language = null;
139   }
140 
141   /**
142    * Gets country.
143    *
144    * @return the country
145    */
146   @Schema(description = "The two letter country code.", example = "DE")
147   @JsonProperty("country")
148   public String getCountry() {
149     return country;
150   }
151 
152   /**
153    * Sets country.
154    *
155    * @param country the country
156    */
157   @JsonProperty("country")
158   public void setCountry(String country) {
159     if (StringUtils.hasText(country)) {
160       for (Locale l : Locale.getAvailableLocales()) {
161         try {
162           if (l.getCountry().equalsIgnoreCase(country)
163               || (l.getISO3Country() != null && l.getISO3Country().equalsIgnoreCase(country))) {
164             this.country = l.getCountry();
165             return;
166           }
167         } catch (MissingResourceException ignored) {
168           // ignored
169         }
170       }
171       if (Arrays.stream(Locale.getISOCountries()).anyMatch(iso -> iso.equalsIgnoreCase(country))) {
172         this.country = country.toUpperCase();
173         return;
174       }
175     }
176     this.country = null;
177   }
178 
179   @Override
180   public String toString() {
181     return toString(Separator.HYPHEN);
182   }
183 
184   /**
185    * To string with separator.
186    *
187    * @param separator the separator
188    * @return the locale string
189    */
190   public String toString(Separator separator) {
191     StringBuilder sb = new StringBuilder();
192     if (StringUtils.hasText(getLanguage())) {
193       sb.append(getLanguage());
194       if (StringUtils.hasText(getCountry())) {
195         sb.append(Separator.fromNullable(separator).toString());
196         sb.append(getCountry());
197       }
198     }
199     return sb.toString();
200   }
201 
202   /**
203    * To locale.
204    *
205    * @return the locale
206    */
207   public Locale toLocale() {
208     return toLocale(null);
209   }
210 
211   /**
212    * To locale.
213    *
214    * @param defaultLocale the default locale
215    * @return the locale
216    */
217   public Locale toLocale(Locale defaultLocale) {
218     if (!StringUtils.hasText(getLanguage()) && !StringUtils.hasText(getCountry())) {
219       return defaultLocale;
220     }
221     String language = getLanguage() == null ? "" : getLanguage();
222     String country = getCountry() == null ? "" : getCountry();
223     return new Locale(language, country);
224   }
225 
226   /**
227    * From value.
228    *
229    * @param value the value
230    * @return the java locale
231    */
232   public static JavaLocale fromValue(String value) {
233     return new JavaLocale(value);
234   }
235 
236   /**
237    * From locale.
238    *
239    * @param locale the locale
240    * @return the java locale
241    */
242   public static JavaLocale fromLocale(Locale locale) {
243     return locale == null ? null : fromValue(locale.toString());
244   }
245 
246   /**
247    * The enum Separator.
248    */
249   public enum Separator {
250 
251     /**
252      * Hyphen separator ({@literal -}).
253      */
254     HYPHEN("-"),
255 
256     /**
257      * Underscore separator ({@literal _}).
258      */
259     UNDERSCORE("_");
260 
261     private String value;
262 
263     Separator(String value) {
264       this.value = value;
265     }
266 
267     @Override
268     public String toString() {
269       return value;
270     }
271 
272     /**
273      * From nullable separator.
274      *
275      * @param separator the separator
276      * @return the separator
277      */
278     public static Separator fromNullable(Separator separator) {
279       return separator == null ? HYPHEN : separator;
280     }
281   }
282 
283 }
284