All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gwt.i18n.server.GwtLocaleFactoryImpl Maven / Gradle / Ivy

/*
 * Copyright 2009 Google Inc.
 * 
 * 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.
 */
package com.google.gwt.i18n.server;

import com.google.gwt.i18n.shared.GwtLocale;
import com.google.gwt.i18n.shared.GwtLocaleFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

/**
 * Creates server-side GwtLocale instances.  Thread-safe.
 */
public class GwtLocaleFactoryImpl implements GwtLocaleFactory {

  private static boolean isAlpha(String str, int min, int max) {
    return matches(str, min, max, true);
  }

  private static boolean isDigit(String str, int min, int max) {
    return matches(str, min, max, false);
  }

  /**
   * Check if the supplied string matches length and composition requirements.
   * 
   * @param str string to check
   * @param min minimum length
   * @param max maximum length
   * @param lettersNotDigits true if all characters should be letters, false if
   *     all characters should be digits
   * @return true if the string is of a proper length and contains only the
   *     specified characters 
   */
  private static boolean matches(String str, int min, int max,
      boolean lettersNotDigits) {
    int len = str.length();
    if (len < min || len > max) {
      return false;
    }
    for (int i = 0; i < len; ++i) {
      if ((lettersNotDigits && !Character.isLetter(str.charAt(i)))
          || (!lettersNotDigits && !Character.isDigit(str.charAt(i)))) {
        return false;
      }
    }
    return true;
  }

  private static String titleCase(String str) {
    if (str.length() < 2) {
      return str.toUpperCase(Locale.ROOT);
    }
    return String.valueOf(Character.toTitleCase(str.charAt(0))) +
        str.substring(1).toLowerCase(Locale.ROOT);
  }

  private final Object instanceCacheLock = new Object[0];
  
  // Locales are stored pointing at themselves. A new instance is created,
  // which is pretty cheap, then looked up here. If it exists, the old
  // one is used instead to preserved cached data structures.
  private Map instanceCache
      = new HashMap();

  /**
   * Clear an embedded cache of instances when they are no longer needed.
   * 

* Note that GwtLocale instances constructed after this is called will not * maintain identity with instances constructed before this call. */ public void clear() { synchronized (instanceCacheLock) { instanceCache.clear(); } } public GwtLocale fromComponents(String language, String script, String region, String variant) { if (language != null && language.length() == 0) { language = null; } if (language != null) { language = language.toLowerCase(Locale.ROOT); } if (script != null && script.length() == 0) { script = null; } if (script != null) { script = titleCase(script); } if (region != null && region.length() == 0) { region = null; } if (region != null) { region = region.toUpperCase(Locale.ROOT); } if (variant != null && variant.length() == 0) { variant = null; } if (variant != null) { variant = variant.toUpperCase(Locale.ROOT); } GwtLocaleImpl locale = new GwtLocaleImpl(this, language, region, script, variant); synchronized (instanceCacheLock) { if (instanceCache.containsKey(locale)) { return instanceCache.get(locale); } instanceCache.put(locale, locale); } return locale; } /** * @throws IllegalArgumentException if the supplied locale does not match * BCP47 structural requirements. */ public GwtLocale fromString(String localeName) { String language = null; String script = null; String region = null; String variant = null; if (localeName != null && !GwtLocale.DEFAULT_LOCALE.equals(localeName)) { // split into component parts ArrayList localeParts = new ArrayList(); String[] parts = localeName.split("[-_]"); for (int i = 0; i < parts.length; ++i) { if (parts[i].length() == 1 && i + 1 < parts.length) { localeParts.add(parts[i] + '-' + parts[++i]); } else { localeParts.add(parts[i]); } } // figure out the role of each part int partIdx = 1; int numParts = localeParts.size(); if (numParts > 0) { // Treat an initial private-use tag as the language tag // Otherwise, language tags are 2-3 characters plus up to three // 3-letter extensions, or 4-8 characters. language = localeParts.get(0); int len = language.length(); // TODO: verify language tag length // See if we have extended language tags if ((len == 2 || len == 3) && partIdx < numParts) { String part = localeParts.get(partIdx); while (partIdx < numParts && partIdx < 4 && isAlpha(part, 3, 3)) { language += '-' + part; if (++partIdx >= numParts) { break; } part = localeParts.get(partIdx); } } } if (numParts > partIdx && isAlpha(localeParts.get(partIdx), 4, 4)) { // Scripts are exactly 4 letters script = localeParts.get(partIdx++); } if (partIdx < numParts) { // Regions may be 2 letters or 3 digits String part = localeParts.get(partIdx); if (isAlpha(part, 2, 2) || isDigit(part, 3, 3)) { region = part; ++partIdx; } } if (partIdx < numParts) { // Variants are 5-8 alphanum, or 4 alphanum if first is digit String part = localeParts.get(partIdx); int len = part.length(); if ((len >= 5 && len <= 8) || (len == 4 && Character.isDigit(part.charAt(0)))) { variant = part; ++partIdx; } } if (partIdx < numParts) { throw new IllegalArgumentException("Unrecognized locale format: " + localeName); } } return fromComponents(language, script, region, variant); } public GwtLocale getDefault() { return fromComponents(null, null, null, null); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy