PageRenderTime 53ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/core/src/main/java/com/atlassian/soy/impl/functions/GetTextFunction.java

https://bitbucket.org/atlassian/atlassian-soy-templates
Java | 161 lines | 131 code | 24 blank | 6 comment | 12 complexity | 3ded438302054c3e49fabe156a7e4f82 MD5 | raw file
  1. package com.atlassian.soy.impl.functions;
  2. import com.atlassian.soy.impl.data.SoyValueUtils;
  3. import com.atlassian.soy.spi.i18n.I18nResolver;
  4. import com.atlassian.soy.spi.i18n.JsLocaleResolver;
  5. import com.google.common.base.Function;
  6. import com.google.common.collect.ImmutableSet;
  7. import com.google.common.collect.Iterables;
  8. import com.google.common.collect.Lists;
  9. import com.google.inject.Singleton;
  10. import com.google.template.soy.base.SoySyntaxException;
  11. import com.google.template.soy.data.SoyData;
  12. import com.google.template.soy.data.SoyValue;
  13. import com.google.template.soy.data.restricted.NullData;
  14. import com.google.template.soy.data.restricted.StringData;
  15. import com.google.template.soy.internal.base.CharEscaper;
  16. import com.google.template.soy.internal.base.CharEscapers;
  17. import com.google.template.soy.jssrc.restricted.JsExpr;
  18. import com.google.template.soy.jssrc.restricted.SoyJsSrcFunction;
  19. import com.google.template.soy.shared.restricted.SoyJavaFunction;
  20. import org.slf4j.Logger;
  21. import org.slf4j.LoggerFactory;
  22. import javax.inject.Inject;
  23. import javax.inject.Named;
  24. import java.io.Serializable;
  25. import java.util.List;
  26. import java.util.Set;
  27. import java.util.regex.Matcher;
  28. import java.util.regex.Pattern;
  29. import java.util.stream.Collectors;
  30. /**
  31. * I18N getText() soy function.
  32. *
  33. * @since 1.0
  34. */
  35. @Singleton
  36. public class GetTextFunction implements SoyJsSrcFunction, SoyJavaFunction {
  37. public static final String FUNCTION_NAME = "getText";
  38. private static final Logger log = LoggerFactory.getLogger(GetTextFunction.class);
  39. private static final Pattern STRING_ARG = Pattern.compile("^'(.*)'$");
  40. private static final Function<SoyValue, Serializable> SOY_DATA_TO_SERIALIZABLE_FUNCTION = new Function<SoyValue, Serializable>() {
  41. @Override
  42. public Serializable apply(SoyValue fromSoyData) {
  43. Object convertedSoyData = SoyValueUtils.fromSoyValue(fromSoyData);
  44. if (convertedSoyData instanceof Serializable) {
  45. return (Serializable) convertedSoyData;
  46. }
  47. if (convertedSoyData == null) {
  48. return NullData.INSTANCE.toString();
  49. }
  50. if (log.isDebugEnabled()) {
  51. log.debug("Conversion of {} from {} is not a Serializable, defaulting to toString() invocation.", convertedSoyData.getClass().getName(), fromSoyData.getClass().getName());
  52. }
  53. return convertedSoyData.toString();
  54. }
  55. };
  56. private static final Set<Integer> ARGS_SIZES;
  57. private final JsLocaleResolver jsLocaleResolver;
  58. private final I18nResolver i18nResolver;
  59. private boolean useAjsI18n;
  60. @Inject
  61. public GetTextFunction(JsLocaleResolver jsLocaleResolver, I18nResolver i18nResolver, @Named(SoyProperties.USE_AJS_I18N) boolean useAjsI18n) {
  62. this.jsLocaleResolver = jsLocaleResolver;
  63. this.i18nResolver = i18nResolver;
  64. this.useAjsI18n = useAjsI18n;
  65. }
  66. static {
  67. final ImmutableSet.Builder<Integer> args = ImmutableSet.builder();
  68. // we support 1 or more args, lets just pick an upper limit
  69. for (int i = 1; i < 20; i++) {
  70. args.add(i);
  71. }
  72. ARGS_SIZES = args.build();
  73. }
  74. @Override
  75. public String getName() {
  76. return FUNCTION_NAME;
  77. }
  78. @Override
  79. public Set<Integer> getValidArgsSizes() {
  80. return ARGS_SIZES;
  81. }
  82. @Override
  83. public JsExpr computeForJsSrc(List<JsExpr> args) {
  84. JsExpr keyExpr = args.get(0);
  85. final Matcher m = STRING_ARG.matcher(keyExpr.getText());
  86. if (!m.matches()) {
  87. throw SoySyntaxException.createWithoutMetaInfo("Argument to getText() is not a literal string: " + keyExpr.getText());
  88. }
  89. String key = m.group(1);
  90. List<String> i18nArgs = Lists.newArrayList();
  91. if (args.size() > 1) {
  92. i18nArgs = args.subList(1, args.size())
  93. .stream()
  94. .map(JsExpr::getText)
  95. .collect(Collectors.toList());
  96. }
  97. String output;
  98. if (useAjsI18n) {
  99. output = getAjsI18nJsOutput(key, i18nArgs);
  100. } else {
  101. output = getJsOutput(key, i18nArgs);
  102. }
  103. return new JsExpr(output, Integer.MAX_VALUE);
  104. }
  105. @Override
  106. public SoyData computeForJava(List<SoyValue> args) {
  107. SoyValue data = args.get(0);
  108. if (!(data instanceof StringData)) {
  109. throw SoySyntaxException.createWithoutMetaInfo("Argument to getText() is not a literal string");
  110. }
  111. List<SoyValue> params = args.subList(1, args.size());
  112. StringData stringData = (StringData) data;
  113. String text = i18nResolver.getText(stringData.getValue(), transformSoyDataListToSerializableArray(params));
  114. return StringData.forValue(text);
  115. }
  116. private String getJsOutput(String key, List<String> args) {
  117. CharEscaper jsEscaper = CharEscapers.javascriptEscaper();
  118. if (args.isEmpty()) {
  119. return "'" + jsEscaper.escape(i18nResolver.getText(jsLocaleResolver.getLocale(), key)) + "'";
  120. } else {
  121. StringBuilder call = new StringBuilder();
  122. final String msg = i18nResolver.getRawText(jsLocaleResolver.getLocale(), key);
  123. call.append("AJS.format(");
  124. call.append("'").append(jsEscaper.escape(msg)).append("'");
  125. args.forEach((arg) -> call.append(",").append(arg));
  126. return call.append(")").toString();
  127. }
  128. }
  129. private String getAjsI18nJsOutput(String key, List<String> args) {
  130. StringBuilder call = new StringBuilder().append(String.format("AJS.I18n.getText('%s'", key));
  131. args.forEach((arg) -> call.append(",").append(arg));
  132. return call.append(")").toString();
  133. }
  134. private Serializable[] transformSoyDataListToSerializableArray(List<SoyValue> params) {
  135. return Iterables.toArray(Iterables.transform(params, SOY_DATA_TO_SERIALIZABLE_FUNCTION), Serializable.class);
  136. }
  137. }