com.google.template.soy.i18ndirectives.FormatNumDirective.java Source code

Java tutorial

Introduction

Here is the source code for com.google.template.soy.i18ndirectives.FormatNumDirective.java

Source

/*
 * Copyright 2012 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.template.soy.i18ndirectives;

import static com.google.template.soy.shared.restricted.SoyJavaRuntimeFunctionUtils.toSoyData;

import java.util.List;
import java.util.Locale;
import java.util.Set;

import org.apache.commons.lang3.StringEscapeUtils;

import com.google.common.collect.ImmutableSet;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.template.soy.data.SoyData;
import com.google.template.soy.jssrc.restricted.JsExpr;
import com.google.template.soy.jssrc.restricted.SoyJsSrcPrintDirective;
import com.google.template.soy.shared.restricted.ApiCallScopeBindingAnnotations.LocaleString;
import com.google.template.soy.tofu.restricted.SoyAbstractTofuPrintDirective;
import com.ibm.icu.text.NumberFormat;

/**
 * A directive that formats an input number based on Locale of the current SoyMsgBundle.
 * It takes a single argument : an optional lower-case string describing the type of format to
 * apply, which can be one of 'decimal', 'currency', 'percent', or 'scientific'. If the argument is
 * not provided, the default, 'decimal' will be used.
 *
 * @author Jeff Craig
 */
class FormatNumDirective extends SoyAbstractTofuPrintDirective implements SoyJsSrcPrintDirective {

    /**
     * Provide the current Locale string.
     *
     * Note that this Locale value is only used in the Java environment. Closure does not provide a
     * clear mechanism to override the NumberFormat defined when the NumberFormat module loads. This
     * is probably not a significant loss of functionality, since the primary reason to inject the
     * LocaleString is because the Java VM's default Locale may not be the same as the desired Locale
     * for the page, while in the JavaScript environment, the value of goog.LOCALE should reliably
     * indicate which Locale Soy should use.
     */
    private Provider<String> localeStringProvider;

    @Inject
    FormatNumDirective(@LocaleString Provider<String> localeStringProvider) {
        this.localeStringProvider = localeStringProvider;
    }

    @Override
    public String getName() {
        return "|formatNum";
    }

    @Override
    public Set<Integer> getValidArgsSizes() {
        return ImmutableSet.of(1);
    }

    @Override
    public boolean shouldCancelAutoescape() {
        return false;
    }

    @Override
    public SoyData apply(SoyData value, List<SoyData> args) {
        Locale locale = I18nUtils.parseLocale(localeStringProvider.get());
        NumberFormat instance;
        String formatType = args.isEmpty() ? "decimal" : args.get(0).stringValue();

        if (formatType.equals("decimal")) {
            instance = NumberFormat.getInstance(locale);
        } else if (formatType.equals("percent")) {
            instance = NumberFormat.getPercentInstance(locale);
        } else if (formatType.equals("currency")) {
            instance = NumberFormat.getCurrencyInstance(locale);
        } else if (formatType.equals("scientific")) {
            instance = NumberFormat.getScientificInstance(locale);
        } else {
            throw new IllegalArgumentException(String.format("Unrecognized Number Format Type: {0}", formatType));
        }
        return toSoyData(StringEscapeUtils.escapeHtml4(instance.format(Float.parseFloat(value.stringValue()))));
    }

    @Override
    public JsExpr applyForJsSrc(JsExpr value, List<JsExpr> args) {
        String numberFormatNameJsExprText;

        if (args.isEmpty()) {
            numberFormatNameJsExprText = "'DECIMAL'";
        } else {
            numberFormatNameJsExprText = "(" + args.get(0).getText() + ").toUpperCase()";
        }
        String numberFormatDecl = "goog.i18n.NumberFormat.Format[" + numberFormatNameJsExprText + "]";

        return new JsExpr("(new goog.i18n.NumberFormat(" + numberFormatDecl + ")).format(" + value.getText() + ")",
                Integer.MAX_VALUE);
    }
}