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

com.squarespace.cldrengine.numbers.NumberParamsCache Maven / Gradle / Ivy

The newest version!
package com.squarespace.cldrengine.numbers;

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

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.squarespace.cldrengine.api.Bundle;
import com.squarespace.cldrengine.api.CurrencySpacingPattern;
import com.squarespace.cldrengine.api.CurrencySpacingPos;
import com.squarespace.cldrengine.api.NumberSymbolType;
import com.squarespace.cldrengine.api.NumberSystemCategory;
import com.squarespace.cldrengine.api.NumberSystemName;
import com.squarespace.cldrengine.internal.Internals;
import com.squarespace.cldrengine.internal.NumberExternalData;
import com.squarespace.cldrengine.internal.NumberSystemInfo;
import com.squarespace.cldrengine.internal.NumbersSchema;
import com.squarespace.cldrengine.parsing.NumberPattern;
import com.squarespace.cldrengine.utils.Cache;

public class NumberParamsCache {

  private static final Map DECIMAL_NUMBERING_DIGITS = new HashMap<>();

  static {
    JsonObject root = JsonParser.parseString(NumberExternalData.DECIMALNUMBERINGDIGITS).getAsJsonObject();
    for (String name : root.keySet()) {
      List digits = new ArrayList<>();
      JsonArray raw = root.getAsJsonArray(name);
      if (raw.size() == 10) {
        for (int i = 0; i < raw.size(); i++) {
          digits.add(raw.get(i).getAsString());
        }
      } else {
        String base = raw.get(0).getAsString();
        digits.add(base);
        int code = base.codePointAt(0);
        for (int i = 1; i < 10; i++) {
          StringBuilder buf = new StringBuilder();
          buf.appendCodePoint(code + i);
          digits.add(buf.toString());
        }
      }
      DECIMAL_NUMBERING_DIGITS.put(name, digits.stream().toArray(String[]::new));
    }
  }

  private final Bundle bundle;
  private final Internals internals;
  private final NumbersSchema numbers;
  private NumberingSystem latnSystem;
  private NumberSystemInfo latnSystemInfo;

  private Cache storage;

  public NumberParamsCache(Bundle bundle, Internals internals) {
    this.bundle = bundle;
    this.internals = internals;
    this.numbers = internals.schema.Numbers;
    this.latnSystemInfo = this.numbers.numberSystem.get("latn");
    this.latnSystem = this.buildNumberSystem("latn");
    this.storage = new Cache<>(this::build, 20);
  }

  public NumberParams getNumberParams(String numberSystem, String defaultSystem) {
    // Default numbering system for a locale unless explicitly overridden
    // https://www.unicode.org/reports/tr35/tr35-33/tr35-numbers.html#defaultNumberingSystem
    if (defaultSystem == null) {
      defaultSystem = "default";
    }
    if (numberSystem == null) {
      numberSystem = bundle.numberSystem();
    }

    NumberSystemName realName = this.select(numberSystem);

    // Handle invalid number systems by returning the specified default
    // TODO: include algorithmic number system check
    if (!DECIMAL_NUMBERING_DIGITS.containsKey(realName.value())) {
      realName = this.select(defaultSystem);

      // TODO: temporary double-check to default for zh finance until we
      // have rbnf implemented.
      if (!DECIMAL_NUMBERING_DIGITS.containsKey(realName.value())) {
        realName = this.select("default"); // always exists
      }
    }
    return this.storage.get(realName.value());
  }

  protected NumberSystemName select(String numberSystem) {
    switch (numberSystem) {
      case "default":
      case "native":
      case "finance":
      case "traditional":
        String raw = this.numbers.numberSystems.get(bundle, NumberSystemCategory.fromString(numberSystem));
        return NumberSystemName.fromString(raw);
      default:
        return NumberSystemName.fromString(numberSystem);
    }
  }

  protected NumberParams build(String name) {
    NumberingSystem system = name.equals("latn") ? this.latnSystem : this.buildNumberSystem(name);
    NumberSystemInfo info = this.numbers.numberSystem.get(name);
    if (info == null) {
      info = this.latnSystemInfo;
    }
    Map> currencySpacing =
        info.currencyFormats.spacing.exists(bundle)
            ? info.currencyFormats.spacing.mapping(bundle)
            : latnSystemInfo.currencyFormats.spacing.mapping(bundle);

    return new NumberParams(
        NumberSystemName.fromString(name),
        system,
        latnSystem,
        DECIMAL_NUMBERING_DIGITS.get(name),
        DECIMAL_NUMBERING_DIGITS.get("latn"),
        system.symbols,
        system.minimumGroupingDigits,
        system.primaryGroupingSize,
        system.secondaryGroupingSize,
        currencySpacing);
  }


  protected NumberingSystem buildNumberSystem(String name) {
    Map system = this.numbers.numberSystem;
    NumberSystemInfo info = system.get(name);
    if (info == null) {
      info = this.latnSystemInfo;
    }
    Map symbols = info.symbols.exists(bundle)
        ? info.symbols.mapping(bundle)
        : latnSystemInfo.symbols.mapping(bundle);
    String standardRaw = info.decimalFormats.standard.get(bundle);
    if (standardRaw == null) {
      latnSystemInfo.decimalFormats.standard.get(bundle);
    }
    NumberPattern standard = this.internals.numbers.getNumberPattern(standardRaw, false);
    int minimumGroupingDigits = Integer.parseInt(this.numbers.minimumGroupingDigits.get(bundle), 10);
    return new DecimalNumberingSystem(
        name,
        DECIMAL_NUMBERING_DIGITS.get(name),
        symbols,
        minimumGroupingDigits,
        standard.priGroup,
        standard.secGroup);
  };
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy