| /* |
| * Copyright 2008 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.uibinder.rebind.messages; |
| |
| import com.google.gwt.core.ext.UnableToCompleteException; |
| import com.google.gwt.uibinder.rebind.Tokenator; |
| import com.google.gwt.uibinder.rebind.UiBinderWriter; |
| import com.google.gwt.uibinder.rebind.XMLElement; |
| import com.google.gwt.uibinder.rebind.Tokenator.Resolver; |
| import com.google.gwt.uibinder.rebind.XMLElement.PostProcessingInterpreter; |
| |
| /** |
| * Abstract class performs the heavy lifting for processing ph children of a msg |
| * element. |
| */ |
| public abstract class PlaceholderInterpreter implements |
| PostProcessingInterpreter<String> { |
| |
| protected final UiBinderWriter uiWriter; |
| protected final MessageWriter message; |
| protected final Tokenator tokenator = new Tokenator(); |
| |
| public PlaceholderInterpreter(UiBinderWriter writer, MessageWriter message) { |
| this.uiWriter = writer; |
| this.message = message; |
| } |
| |
| public String interpretElement(XMLElement elem) |
| throws UnableToCompleteException { |
| if (isPlaceholderElement(elem)) { |
| /* |
| * The innerHTML or innerText of the <ui:ph> will be provided as the value |
| * of the appropriate parameter when the Messages method is called. |
| * |
| * E.g. |
| * |
| * <ui:msg>Able <ui:ph name="foo" example"baz">baker</ui:ph> charlie</ui:msg> |
| * |
| * becomes |
| * |
| * @Default("Able {0} charlie) |
| * String message1(@Example("baz") String foo) |
| * |
| * and in the generated innerHTML is invoked |
| * |
| * message1("baker") |
| */ |
| |
| MessagesWriter mw = getMessagesWriter(); |
| String name = mw.consumeRequiredMessageElementAttribute("name", elem); |
| String example = mw.consumeMessageElementAttribute("example", elem); |
| String value = consumePlaceholderInnards(elem); |
| |
| // Use the value as the example if none is provided |
| if ("".equals(example)) { |
| |
| /* |
| * The value may contain tokens vended by the TemplateWriter, which will |
| * be substituted for runtime-computed values (like unique dom ids). We |
| * don't want those in the example text shown to the translator, so snip |
| * them |
| */ |
| example = stripTokens(value); |
| } |
| |
| /* |
| * Likewise, if there are tokens from the UiWriter in the value string, we |
| * need it to replace them with the real expresions. |
| */ |
| value = uiWriter.detokenate(value); |
| return nextPlaceholder(name, example, value); |
| } |
| |
| if (uiWriter.isWidgetElement(elem)) { |
| uiWriter.die(elem, "Found widget in a message that cannot contain widgets"); |
| } |
| return null; |
| } |
| |
| /** |
| * Called by various {@link XMLElement} consumeInner*() methods after all |
| * elements have been handed to {@link #interpretElement}. |
| * <p> |
| * Performs escaping on the consumed text to make it safe for use as a |
| * Messages {@literal @}Default value |
| */ |
| public String postProcess(String consumed) throws UnableToCompleteException { |
| return tokenator.detokenate(MessageWriter.escapeMessageFormat(consumed)); |
| } |
| |
| protected abstract String consumePlaceholderInnards(XMLElement elem) |
| throws UnableToCompleteException; |
| |
| /** |
| * To be called from {@link #interpretElement(XMLElement)}. Creates the next |
| * placeholder in the {@link MessageWriter} we're building, and returns the |
| * text to stand in its place. |
| * |
| * @param name |
| * @param example |
| * @param value |
| * @return |
| */ |
| protected String nextPlaceholder(String name, String example, String value) { |
| message.addPlaceholder(new PlaceholderWriter(name, example, value)); |
| |
| /* |
| * We can't just return the {0} placeholder text, because it will be |
| * clobbered by the escaping performed in postProcess. We use a tokenator to |
| * hide the placeholder from the escaping step, and postProcess resolves the |
| * tokens when the escaping is done. |
| */ |
| String placeholder = String.format("{%d}", |
| message.getPlaceholderCount() - 1); |
| |
| return tokenator.nextToken(placeholder); |
| } |
| |
| protected String stripTokens(String value) { |
| String rtn = Tokenator.detokenate(value, new Resolver() { |
| public String resolveToken(String token) { |
| return ""; |
| } |
| }); |
| return rtn; |
| } |
| |
| private MessagesWriter getMessagesWriter() { |
| return uiWriter.getMessages(); |
| } |
| |
| private boolean isPlaceholderElement(XMLElement elem) { |
| return getMessagesWriter().isMessagePrefixed(elem) |
| && "ph".equals(elem.getLocalName()); |
| } |
| } |