      /**
       * The constants used in this Content Widget.
       */
      public static interface CwConstants extends Constants {
        String cwBidiFormattingArg0Label();

        String cwBidiFormattingArg1Label();

        String cwBidiFormattingArg2Label();

        String cwBidiFormattingBidiFormattedLabel();

        String cwBidiFormattingDescription();

        String cwBidiFormattingLinkText();

        String cwBidiFormattingName();

        String cwBidiFormattingNonbidiFormattedLabel();

        String cwBidiFormattingTemplateLabel();
      }

      /**
       * The {@link TextBox} where the user enters argument 0.
       */
      private TextBox arg0Box = null;

      /**
       * The {@link TextBox} where the user enters argument 1.
       */
      private TextBox arg1Box = null;

      /**
       * The {@link TextBox} where the user enters argument 2.
       */
      private TextBox arg2Box = null;

      /**
       * A {@link com.google.gwt.i18n.shared.BidiFormatter} instance used for
       * bidi-formatting of user input.
       */
      private BidiFormatter bidiFormatter =
          BidiFormatter.getInstanceForCurrentLocale();

      /**
       * An instance of the constants.
       */
      private final CwConstants constants;

      /**
       * The blog messages used in this example.
       */
      private BlogMessages blogMessages = null;

      /**
       * The {@link HTML} used to display the message.
       */
      private HTML message = null;

      /**
       * The {@link HTML} used to display the bidi formatted message.
       */
      private HTML bidiFormattedMessage = null;

      /**
       * Initialize this example.
       */
      @Override
      public Widget onInitialize() {
        // Create the internationalized blog messages
        blogMessages = GWT.create(BlogMessages.class);

        // Use a FlexTable to layout the content
        FlexTable layout = new FlexTable();
        FlexCellFormatter formatter = layout.getFlexCellFormatter();
        layout.setCellSpacing(5);

        // Add a link to the source code of the Interface
        final String rawFile = getSimpleName(BlogMessages.class);
        Anchor link = new Anchor(rawFile);
        link.addClickHandler(new ClickHandler() {
          public void onClick(ClickEvent event) {
            fireRawSourceRequest(rawFile + ".java");
          }
        });
        HorizontalPanel linkPanel = new HorizontalPanel();
        linkPanel.setSpacing(3);
        linkPanel.add(new HTML(constants.cwBidiFormattingLinkText()));
        linkPanel.add(link);
        layout.setWidget(0, 0, linkPanel);
        formatter.setColSpan(0, 0, 2);

        // Show the template for reference
        String template = blogMessages.userComment("{0}", "{1}", "{2}");
        layout.setHTML(1, 0, constants.cwBidiFormattingTemplateLabel());
        layout.setHTML(1, 1, template);

        // Add argument 0
        arg0Box = new TextBox();
        // Using an initial value whose direction is opposite the locale's direction
        // demonstrates the need for and effect of bidi formatting.
        arg0Box.setText(
            LocaleInfo.getCurrentLocale().isRTL() ? "Tom Bombadil" : "תומר גרין");
        layout.setHTML(2, 0, constants.cwBidiFormattingArg0Label());
        layout.setWidget(2, 1, arg0Box);

        // Add argument 1
        arg1Box = new TextBox();
        arg1Box.setText("16");
        layout.setHTML(3, 0, constants.cwBidiFormattingArg1Label());
        layout.setWidget(3, 1, arg1Box);

        // Add argument 2
        arg2Box = new TextBox();
        // Using an initial value whose direction is opposite the locale's direction
        // demonstrates the need for and effect of bidi formatting.
        arg2Box.setText(LocaleInfo.getCurrentLocale().isRTL()
            ? "How deep is your love?" : "כמה חול יש בחוף?");
        layout.setHTML(4, 0, constants.cwBidiFormattingArg2Label());
        layout.setWidget(4, 1, arg2Box);

        // Add the unformatted message
        message = new HTML();
        layout.setHTML(5, 0, constants.cwBidiFormattingNonbidiFormattedLabel());
        layout.setWidget(5, 1, message);
        formatter.setVerticalAlignment(5, 0, HasVerticalAlignment.ALIGN_TOP);

        // Add the bidi formatted message
        bidiFormattedMessage = new HTML();
        layout.setHTML(6, 0, constants.cwBidiFormattingBidiFormattedLabel());
        layout.setWidget(6, 1, bidiFormattedMessage);
        formatter.setVerticalAlignment(6, 0, HasVerticalAlignment.ALIGN_TOP);

        // Add handlers to all of the argument boxes
        KeyUpHandler keyUpHandler = new KeyUpHandler() {
          public void onKeyUp(KeyUpEvent event) {
            updateMessages();
          }
        };
        arg0Box.addKeyUpHandler(keyUpHandler);
        arg1Box.addKeyUpHandler(keyUpHandler);
        arg2Box.addKeyUpHandler(keyUpHandler);

        // Return the layout Widget
        updateMessages();

        return layout;
      }

      /**
       * Update the formatted message.
       */
      private void updateMessages() {
        String arg0 = arg0Box.getText().trim();
        String arg1 = arg1Box.getText().trim();
        String arg2 = arg2Box.getText().trim();
        message.setText(blogMessages.userComment(arg0, arg1, arg2));

        bidiFormattedMessage.setHTML(
            blogMessages.userComment(bidiFormatter.spanWrap(arg0),
            // arg1 is intended to be an unsigned number, so bidi formatting is not
            // needed. However, HTML escaping is a must to avoid an XSS attack hole!
                SafeHtmlUtils.htmlEscape(arg1), bidiFormatter.spanWrap(arg2)));
      }