diff --git a/java/res/values-ar/config-spacing-and-punctuations.xml b/java/res/values-ar/config-spacing-and-punctuations.xml
index 9e637e458db33bfc97f8c29a73ffe8184861eff1..8d4d4bfc736611336074ae5829a2a0825b822533 100644
--- a/java/res/values-ar/config-spacing-and-punctuations.xml
+++ b/java/res/values-ar/config-spacing-and-punctuations.xml
@@ -21,5 +21,6 @@
     <!-- The all letters need to be mirrored are found at
          http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt -->
     <!-- Symbols that are suggested between words -->
+    <!-- TODO: Use !text resources to merge LTR and RTL punctuations. -->
     <string name="suggested_punctuations" translatable="false">!,?,\\,,:,;,\",(|),)|(,\',-,/,@,_</string>
 </resources>
diff --git a/java/res/values-fa/config-spacing-and-punctuations.xml b/java/res/values-fa/config-spacing-and-punctuations.xml
index 9e637e458db33bfc97f8c29a73ffe8184861eff1..8d4d4bfc736611336074ae5829a2a0825b822533 100644
--- a/java/res/values-fa/config-spacing-and-punctuations.xml
+++ b/java/res/values-fa/config-spacing-and-punctuations.xml
@@ -21,5 +21,6 @@
     <!-- The all letters need to be mirrored are found at
          http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt -->
     <!-- Symbols that are suggested between words -->
+    <!-- TODO: Use !text resources to merge LTR and RTL punctuations. -->
     <string name="suggested_punctuations" translatable="false">!,?,\\,,:,;,\",(|),)|(,\',-,/,@,_</string>
 </resources>
diff --git a/java/res/values-iw/config-spacing-and-punctuations.xml b/java/res/values-iw/config-spacing-and-punctuations.xml
index 9e637e458db33bfc97f8c29a73ffe8184861eff1..8d4d4bfc736611336074ae5829a2a0825b822533 100644
--- a/java/res/values-iw/config-spacing-and-punctuations.xml
+++ b/java/res/values-iw/config-spacing-and-punctuations.xml
@@ -21,5 +21,6 @@
     <!-- The all letters need to be mirrored are found at
          http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt -->
     <!-- Symbols that are suggested between words -->
+    <!-- TODO: Use !text resources to merge LTR and RTL punctuations. -->
     <string name="suggested_punctuations" translatable="false">!,?,\\,,:,;,\",(|),)|(,\',-,/,@,_</string>
 </resources>
diff --git a/java/res/values/config-spacing-and-punctuations.xml b/java/res/values/config-spacing-and-punctuations.xml
index 2f52edd4a57c29acbbc5b5c243f34873b887d419..5b2918fe80156f8699e5d610051fa7a06429bd83 100644
--- a/java/res/values/config-spacing-and-punctuations.xml
+++ b/java/res/values/config-spacing-and-punctuations.xml
@@ -21,6 +21,8 @@
     <!-- TODO: these settings depend on the language. They should be put either in the dictionary
          header, or in the subtype maybe? -->
     <!-- Symbols that are suggested between words -->
+    <!-- TODO: Use !text resources to merge LTR and RTL punctuations. -->
+    <!-- TODO: We should have different punctuations list for tablet. -->
     <string name="suggested_punctuations" translatable="false">!,?,\\,,:,;,\",(,),\',-,/,@,_</string>
     <!-- Symbols that are normally preceded by a space (used to add an auto-space before these) -->
     <string name="symbols_preceded_by_space" translatable="false">([{&amp;</string>
diff --git a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java
index a32d76c3016e41600767b05536d79e2b31c36e2b..60f7e2defa8846a7e4c3c5bb32686fad430a5152 100644
--- a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java
+++ b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java
@@ -23,7 +23,6 @@ import android.text.Spanned;
 import android.text.TextUtils;
 import android.text.style.SuggestionSpan;
 
-import com.android.inputmethod.latin.Dictionary;
 import com.android.inputmethod.latin.LatinImeLogger;
 import com.android.inputmethod.latin.SuggestedWords;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
@@ -70,7 +69,7 @@ public final class SuggestionSpanUtils {
     public static CharSequence getTextWithSuggestionSpan(final Context context,
             final String pickedWord, final SuggestedWords suggestedWords) {
         if (TextUtils.isEmpty(pickedWord) || suggestedWords.isEmpty()
-                || suggestedWords.mIsPrediction || suggestedWords.mIsPunctuationSuggestions) {
+                || suggestedWords.mIsPrediction || suggestedWords.isPunctuationSuggestions()) {
             return pickedWord;
         }
 
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 7b72e804447c94e4c35e5b00e31b6eda3b4c02b5..d1125afcc4df8719770b27cd4d18243f169c3c61 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1001,7 +1001,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
                 applicationSuggestedWords, null /* rawSuggestions */,
                 false /* typedWordValid */,
                 false /* willAutoCorrect */,
-                false /* isPunctuationSuggestions */,
                 false /* isObsoleteSuggestions */,
                 false /* isPrediction */);
         // When in fullscreen mode, show completions generated by the application
@@ -1354,7 +1353,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         if (mSuggestionStripView != null) {
             final boolean showSuggestions;
             if (SuggestedWords.EMPTY == suggestedWords
-                    || suggestedWords.mIsPunctuationSuggestions
+                    || suggestedWords.isPunctuationSuggestions()
                     || !mSettings.getCurrent().isSuggestionsRequested()) {
                 showSuggestions = !mSuggestionStripView.maybeShowImportantNoticeTitle();
             } else {
@@ -1433,7 +1432,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
             return new SuggestedWords(typedWordAndPreviousSuggestions, null /* rawSuggestions */,
                     false /* typedWordValid */,
                     false /* hasAutoCorrectionCandidate */,
-                    false /* isPunctuationSuggestions */,
                     true /* isObsoleteSuggestions */,
                     false /* isPrediction */);
         }
diff --git a/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java b/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java
new file mode 100644
index 0000000000000000000000000000000000000000..4911bcdf63925942a1061da25a442ac248595ca9
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * 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.android.inputmethod.latin;
+
+import com.android.inputmethod.keyboard.internal.KeySpecParser;
+import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.StringUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * The extended {@link SuggestedWords} class to represent punctuation suggestions.
+ *
+ * Each punctuation specification string is the key specification that can be parsed by
+ * {@link KeySpecParser}.
+ */
+public final class PunctuationSuggestions extends SuggestedWords {
+    private PunctuationSuggestions(final ArrayList<SuggestedWordInfo> punctuationsList) {
+        super(punctuationsList,
+                null /* rawSuggestions */,
+                false /* typedWordValid */,
+                false /* hasAutoCorrectionCandidate */,
+                false /* isObsoleteSuggestions */,
+                false /* isPrediction */);
+    }
+
+    /**
+     * Create new instance of {@link PunctuationSuggestions} from the array of punctuation key
+     * specifications.
+     *
+     * @param punctuationSpecs The array of punctuation key specifications.
+     * @return The {@link PunctuationSuggestions} object.
+     */
+    public static PunctuationSuggestions newPunctuationSuggestions(
+            final String[] punctuationSpecs) {
+        final ArrayList<SuggestedWordInfo> puncuationsList = CollectionUtils.newArrayList();
+        for (final String puncSpec : punctuationSpecs) {
+            puncuationsList.add(newHardCodedWordInfo(puncSpec));
+        }
+        return new PunctuationSuggestions(puncuationsList);
+    }
+
+    /**
+     * {@inheritDoc}
+     * Note that {@link super#getWord(int)} returns a punctuation key specification text.
+     * The suggested punctuation should be gotten by parsing the key specification.
+     */
+    @Override
+    public String getWord(final int index) {
+        final String keySpec = super.getWord(index);
+        final int code = KeySpecParser.getCode(keySpec);
+        return (code == Constants.CODE_OUTPUT_TEXT)
+                ? KeySpecParser.getOutputText(keySpec)
+                : StringUtils.newSingleCodePointString(code);
+    }
+
+    /**
+     * {@inheritDoc}
+     * Note that {@link super#getWord(int)} returns a punctuation key specification text.
+     * The displayed text should be gotten by parsing the key specification.
+     */
+    @Override
+    public String getLabel(final int index) {
+        final String keySpec = super.getWord(index);
+        return KeySpecParser.getLabel(keySpec);
+    }
+
+    /**
+     * {@inheritDoc}
+     * Note that {@link #getWord(int)} returns a suggested punctuation. We should create a
+     * {@link SuggestedWordInfo} object that represents a hard coded word.
+     */
+    @Override
+    public SuggestedWordInfo getInfo(final int index) {
+        return newHardCodedWordInfo(getWord(index));
+    }
+
+    /**
+     * The predicator to tell whether this object represents punctuation suggestions.
+     * @return true if this object represents punctuation suggestions.
+     */
+    @Override
+    public boolean isPunctuationSuggestions() {
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "PunctuationSuggestions: "
+                + " words=" + Arrays.toString(mSuggestedWordInfoList.toArray());
+    }
+
+    private static SuggestedWordInfo newHardCodedWordInfo(final String keySpec) {
+        return new SuggestedWordInfo(keySpec, SuggestedWordInfo.MAX_SCORE,
+                SuggestedWordInfo.KIND_HARDCODED,
+                Dictionary.DICTIONARY_HARDCODED,
+                SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+                SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */);
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 5e74d75b0fd490d2da2e299ce96469f05e51f5e0..abf831a28f8e3ed8f7718a7643e0ec0264b05345 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -227,7 +227,6 @@ public final class Suggest {
                 // rename the attribute or change the value.
                 !allowsToBeAutoCorrected /* typedWordValid */,
                 hasAutoCorrection, /* willAutoCorrect */
-                false /* isPunctuationSuggestions */,
                 false /* isObsoleteSuggestions */,
                 !wordComposer.isComposingWord() /* isPrediction */, sequenceNumber));
     }
@@ -289,7 +288,6 @@ public final class Suggest {
         callback.onGetSuggestedWords(new SuggestedWords(suggestionsContainer, rawSuggestions,
                 true /* typedWordValid */,
                 false /* willAutoCorrect */,
-                false /* isPunctuationSuggestions */,
                 false /* isObsoleteSuggestions */,
                 false /* isPrediction */, sequenceNumber));
     }
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index b2efc4a865ff6bf7ece282f04deafbc0876910d2..46df3e88c6e9497cf44971957f02653360dd05e9 100644
--- a/java/src/com/android/inputmethod/latin/SuggestedWords.java
+++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java
@@ -26,7 +26,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
 
-public final class SuggestedWords {
+public class SuggestedWords {
     public static final int INDEX_OF_TYPED_WORD = 0;
     public static final int INDEX_OF_AUTO_CORRECTION = 1;
     public static final int NOT_A_SEQUENCE_NUMBER = -1;
@@ -37,7 +37,7 @@ public final class SuggestedWords {
     private static final ArrayList<SuggestedWordInfo> EMPTY_WORD_INFO_LIST =
             CollectionUtils.newArrayList(0);
     public static final SuggestedWords EMPTY = new SuggestedWords(
-            EMPTY_WORD_INFO_LIST, null /* rawSuggestions */, false, false, false, false, false);
+            EMPTY_WORD_INFO_LIST, null /* rawSuggestions */, false, false, false, false);
 
     public final String mTypedWord;
     public final boolean mTypedWordValid;
@@ -45,38 +45,34 @@ public final class SuggestedWords {
     // of what this flag means would be "the top suggestion is strong enough to auto-correct",
     // whether this exactly matches the user entry or not.
     public final boolean mWillAutoCorrect;
-    public final boolean mIsPunctuationSuggestions;
     public final boolean mIsObsoleteSuggestions;
     public final boolean mIsPrediction;
     public final int mSequenceNumber; // Sequence number for auto-commit.
-    private final ArrayList<SuggestedWordInfo> mSuggestedWordInfoList;
+    protected final ArrayList<SuggestedWordInfo> mSuggestedWordInfoList;
     public final ArrayList<SuggestedWordInfo> mRawSuggestions;
 
     public SuggestedWords(final ArrayList<SuggestedWordInfo> suggestedWordInfoList,
             final ArrayList<SuggestedWordInfo> rawSuggestions,
             final boolean typedWordValid,
             final boolean willAutoCorrect,
-            final boolean isPunctuationSuggestions,
             final boolean isObsoleteSuggestions,
             final boolean isPrediction) {
         this(suggestedWordInfoList, rawSuggestions, typedWordValid, willAutoCorrect,
-                isPunctuationSuggestions, isObsoleteSuggestions, isPrediction,
-                NOT_A_SEQUENCE_NUMBER);
+                isObsoleteSuggestions, isPrediction, NOT_A_SEQUENCE_NUMBER);
     }
 
     public SuggestedWords(final ArrayList<SuggestedWordInfo> suggestedWordInfoList,
             final ArrayList<SuggestedWordInfo> rawSuggestions,
             final boolean typedWordValid,
             final boolean willAutoCorrect,
-            final boolean isPunctuationSuggestions,
             final boolean isObsoleteSuggestions,
             final boolean isPrediction,
             final int sequenceNumber) {
         this(suggestedWordInfoList, rawSuggestions,
                 suggestedWordInfoList.isEmpty() ? null
                         : suggestedWordInfoList.get(INDEX_OF_TYPED_WORD).mWord,
-                typedWordValid, willAutoCorrect, isPunctuationSuggestions,
-                isObsoleteSuggestions, isPrediction, sequenceNumber);
+                typedWordValid, willAutoCorrect, isObsoleteSuggestions, isPrediction,
+                sequenceNumber);
     }
 
     public SuggestedWords(final ArrayList<SuggestedWordInfo> suggestedWordInfoList,
@@ -84,7 +80,6 @@ public final class SuggestedWords {
             final String typedWord,
             final boolean typedWordValid,
             final boolean willAutoCorrect,
-            final boolean isPunctuationSuggestions,
             final boolean isObsoleteSuggestions,
             final boolean isPrediction,
             final int sequenceNumber) {
@@ -92,7 +87,6 @@ public final class SuggestedWords {
         mRawSuggestions = rawSuggestions;
         mTypedWordValid = typedWordValid;
         mWillAutoCorrect = willAutoCorrect;
-        mIsPunctuationSuggestions = isPunctuationSuggestions;
         mIsObsoleteSuggestions = isObsoleteSuggestions;
         mIsPrediction = isPrediction;
         mSequenceNumber = sequenceNumber;
@@ -107,10 +101,32 @@ public final class SuggestedWords {
         return mSuggestedWordInfoList.size();
     }
 
+    /**
+     * Get suggested word at <code>index</code>.
+     * @param index The index of the suggested word.
+     * @return The suggested word.
+     */
     public String getWord(final int index) {
         return mSuggestedWordInfoList.get(index).mWord;
     }
 
+    /**
+     * Get displayed text at <code>index</code>.
+     * In RTL languages, the displayed text on the suggestion strip may be different from the
+     * suggested word that is returned from {@link #getWord(int)}. For example the displayed text
+     * of punctuation suggestion "(" should be ")".
+     * @param index The index of the text to display.
+     * @return The text to be displayed.
+     */
+    public String getLabel(final int index) {
+        return mSuggestedWordInfoList.get(index).mWord;
+    }
+
+    /**
+     * Get {@link SuggestedWordInfo} object at <code>index</code>.
+     * @param index The index of the {@link SuggestedWordInfo}.
+     * @return The {@link SuggestedWordInfo} object.
+     */
     public SuggestedWordInfo getInfo(final int index) {
         return mSuggestedWordInfoList.get(index);
     }
@@ -130,13 +146,20 @@ public final class SuggestedWords {
         return debugString;
     }
 
+    /**
+     * The predicator to tell whether this object represents punctuation suggestions.
+     * @return false if this object desn't represent punctuation suggestions.
+     */
+    public boolean isPunctuationSuggestions() {
+        return false;
+    }
+
     @Override
     public String toString() {
         // Pretty-print method to help debug
         return "SuggestedWords:"
                 + " mTypedWordValid=" + mTypedWordValid
                 + " mWillAutoCorrect=" + mWillAutoCorrect
-                + " mIsPunctuationSuggestions=" + mIsPunctuationSuggestions
                 + " words=" + Arrays.toString(mSuggestedWordInfoList.toArray());
     }
 
@@ -313,8 +336,8 @@ public final class SuggestedWords {
         // We should never autocorrect, so we say the typed word is valid. Also, in this case,
         // no auto-correction should take place hence willAutoCorrect = false.
         return new SuggestedWords(newSuggestions, null /* rawSuggestions */, typedWord,
-                true /* typedWordValid */, false /* willAutoCorrect */, mIsPunctuationSuggestions,
-                mIsObsoleteSuggestions, mIsPrediction, NOT_A_SEQUENCE_NUMBER);
+                true /* typedWordValid */, false /* willAutoCorrect */, mIsObsoleteSuggestions,
+                mIsPrediction, NOT_A_SEQUENCE_NUMBER);
     }
 
     // Creates a new SuggestedWordInfo from the currently suggested words that removes all but the
@@ -333,7 +356,6 @@ public final class SuggestedWords {
                     SuggestedWordInfo.NOT_A_CONFIDENCE));
         }
         return new SuggestedWords(newSuggestions, null /* rawSuggestions */, mTypedWordValid,
-                mWillAutoCorrect, mIsPunctuationSuggestions, mIsObsoleteSuggestions,
-                mIsPrediction);
+                mWillAutoCorrect, mIsObsoleteSuggestions, mIsPrediction);
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index bd114ebcaf2648036ce55b3cd8ab648b07d20cab..6f73859e8a89f38fc131b61ce141cfc8b39d313c 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -1341,8 +1341,8 @@ public final class InputLogic {
             final SuggestedWords suggestedWords = new SuggestedWords(suggestions,
                     null /* rawSuggestions */, typedWord,
                     true /* typedWordValid */, false /* willAutoCorrect */,
-                    false /* isPunctuationSuggestions */, false /* isObsoleteSuggestions */,
-                    false /* isPrediction */, SuggestedWords.NOT_A_SEQUENCE_NUMBER);
+                    false /* isObsoleteSuggestions */, false /* isPrediction */,
+                    SuggestedWords.NOT_A_SEQUENCE_NUMBER);
             mIsAutoCorrectionIndicatorOn = false;
             mLatinIME.mHandler.showSuggestionStrip(suggestedWords);
         }
diff --git a/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java b/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java
index 03883a48b0cb7b05df9924ac14759fd8316a3e40..5954758aa69846b2fe76c3fe27637078a9568888 100644
--- a/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java
+++ b/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java
@@ -18,17 +18,13 @@ package com.android.inputmethod.latin.settings;
 
 import android.content.res.Resources;
 
-import com.android.inputmethod.keyboard.internal.KeySpecParser;
+import com.android.inputmethod.keyboard.internal.KeyboardTextsSet;
 import com.android.inputmethod.keyboard.internal.MoreKeySpec;
 import com.android.inputmethod.latin.Constants;
-import com.android.inputmethod.latin.Dictionary;
+import com.android.inputmethod.latin.PunctuationSuggestions;
 import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.SuggestedWords;
-import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
-import com.android.inputmethod.latin.utils.CollectionUtils;
 import com.android.inputmethod.latin.utils.StringUtils;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Locale;
 
@@ -37,7 +33,7 @@ public final class SpacingAndPunctuations {
     private final int[] mSortedSymbolsFollowedBySpace;
     private final int[] mSortedWordConnectors;
     public final int[] mSortedWordSeparators;
-    public final SuggestedWords mSuggestPuncList;
+    public final PunctuationSuggestions mSuggestPuncList;
     private final int mSentenceSeparator;
     public final String mSentenceSeparatorAndSpace;
     public final boolean mCurrentLanguageHasSpaces;
@@ -56,9 +52,6 @@ public final class SpacingAndPunctuations {
                 res.getString(R.string.symbols_word_connectors));
         mSortedWordSeparators = StringUtils.toSortedCodePointArray(
                 res.getString(R.string.symbols_word_separators));
-        final String[] suggestPuncsSpec = MoreKeySpec.splitKeySpecs(res.getString(
-                R.string.suggested_punctuations));
-        mSuggestPuncList = createSuggestPuncList(suggestPuncsSpec);
         mSentenceSeparator = res.getInteger(R.integer.sentence_separator);
         mSentenceSeparatorAndSpace = new String(new int[] {
                 mSentenceSeparator, Constants.CODE_SPACE }, 0, 2);
@@ -68,28 +61,11 @@ public final class SpacingAndPunctuations {
         // English variants. German rules (not "German typography") also have small gotchas.
         mUsesAmericanTypography = Locale.ENGLISH.getLanguage().equals(locale.getLanguage());
         mUsesGermanRules = Locale.GERMAN.getLanguage().equals(locale.getLanguage());
-    }
-
-    // Helper functions to create member values.
-    private static SuggestedWords createSuggestPuncList(final String[] puncs) {
-        final ArrayList<SuggestedWordInfo> puncList = CollectionUtils.newArrayList();
-        if (puncs != null) {
-            for (final String puncSpec : puncs) {
-                // TODO: Stop using KeySpecParser.getLabel().
-                // TODO: Punctuation suggestions should honor RTL languages.
-                puncList.add(new SuggestedWordInfo(KeySpecParser.getLabel(puncSpec),
-                        SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_HARDCODED,
-                        Dictionary.DICTIONARY_HARDCODED,
-                        SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
-                        SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
-            }
-        }
-        return new SuggestedWords(puncList, null /* rawSuggestions */,
-                false /* typedWordValid */,
-                false /* hasAutoCorrectionCandidate */,
-                true /* isPunctuationSuggestions */,
-                false /* isObsoleteSuggestions */,
-                false /* isPrediction */);
+        final KeyboardTextsSet textsSet = new KeyboardTextsSet();
+        textsSet.setLocale(locale);
+        final String[] suggestPuncsSpec = MoreKeySpec.splitKeySpecs(
+                textsSet.resolveTextReference(res.getString(R.string.suggested_punctuations)));
+        mSuggestPuncList = PunctuationSuggestions.newPunctuationSuggestions(suggestPuncsSpec);
     }
 
     public boolean isWordSeparator(final int code) {
diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
index 2f4c1839bfe6395c82a15b8cde1ddcabbf1329ab..a104baa0825396b76579907c6a3c97229db2adc9 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
@@ -74,7 +74,7 @@ public final class MoreSuggestions extends Keyboard {
             int rowStartIndex = fromIndex;
             final int size = Math.min(suggestedWords.size(), SuggestedWords.MAX_SUGGESTIONS);
             while (index < size) {
-                final String word = suggestedWords.getWord(index);
+                final String word = suggestedWords.getLabel(index);
                 // TODO: Should take care of text x-scaling.
                 mWidths[index] = (int)(TypefaceUtils.getStringWidth(word, paint) + padding);
                 final int numColumn = index - rowStartIndex + 1;
@@ -206,7 +206,7 @@ public final class MoreSuggestions extends Keyboard {
                 final int x = params.getX(index);
                 final int y = params.getY(index);
                 final int width = params.getWidth(index);
-                final String word = mSuggestedWords.getWord(index);
+                final String word = mSuggestedWords.getLabel(index);
                 final String info = mSuggestedWords.getDebugString(index);
                 final int indexInMoreSuggestions = index + SUGGESTION_CODE_BASE;
                 final Key key = new Key(word, KeyboardIconsSet.ICON_UNDEFINED,
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
index 5f05b48d4f6d9e95f88825bcfedd264439b1a6f6..7c11f5432c1cdaa4c192f26a00573a792b32d769 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
@@ -46,6 +46,7 @@ import android.widget.TextView;
 
 import com.android.inputmethod.compat.TextViewCompatUtils;
 import com.android.inputmethod.latin.LatinImeLogger;
+import com.android.inputmethod.latin.PunctuationSuggestions;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.SuggestedWords;
 import com.android.inputmethod.latin.utils.AutoCorrectionUtils;
@@ -199,7 +200,7 @@ final class SuggestionStripLayoutHelper {
         if (indexInSuggestedWords >= suggestedWords.size()) {
             return null;
         }
-        final String word = suggestedWords.getWord(indexInSuggestedWords);
+        final String word = suggestedWords.getLabel(indexInSuggestedWords);
         final boolean isAutoCorrect = indexInSuggestedWords == 1
                 && suggestedWords.mWillAutoCorrect;
         final boolean isTypedWordValid = indexInSuggestedWords == 0
@@ -264,8 +265,8 @@ final class SuggestionStripLayoutHelper {
             // is in slot 1.
             if (positionInStrip == mCenterPositionInStrip
                     && AutoCorrectionUtils.shouldBlockAutoCorrectionBySafetyNet(
-                            suggestedWords.getWord(SuggestedWords.INDEX_OF_AUTO_CORRECTION),
-                            suggestedWords.getWord(SuggestedWords.INDEX_OF_TYPED_WORD))) {
+                            suggestedWords.getLabel(SuggestedWords.INDEX_OF_AUTO_CORRECTION),
+                            suggestedWords.getLabel(SuggestedWords.INDEX_OF_TYPED_WORD))) {
                 return 0xFFFF0000;
             }
         }
@@ -299,9 +300,9 @@ final class SuggestionStripLayoutHelper {
      */
     public int layoutAndReturnSuggestionCountInStrip(final SuggestedWords suggestedWords,
             final ViewGroup stripView, final ViewGroup placerView) {
-        if (suggestedWords.mIsPunctuationSuggestions) {
+        if (suggestedWords.isPunctuationSuggestions()) {
             return layoutPunctuationSuggestionsAndReturnSuggestionCountInStrip(
-                    suggestedWords, stripView);
+                    (PunctuationSuggestions)suggestedWords, stripView);
         }
 
         setupWordViewsTextAndColor(suggestedWords, mSuggestionsCountInStrip);
@@ -447,8 +448,8 @@ final class SuggestionStripLayoutHelper {
     }
 
     private int layoutPunctuationSuggestionsAndReturnSuggestionCountInStrip(
-            final SuggestedWords suggestedWords, final ViewGroup stripView) {
-        final int countInStrip = Math.min(suggestedWords.size(), PUNCTUATIONS_IN_STRIP);
+            final PunctuationSuggestions punctuationSuggestions, final ViewGroup stripView) {
+        final int countInStrip = Math.min(punctuationSuggestions.size(), PUNCTUATIONS_IN_STRIP);
         for (int positionInStrip = 0; positionInStrip < countInStrip; positionInStrip++) {
             if (positionInStrip != 0) {
                 // Add divider if this isn't the left most suggestion in suggestions strip.
@@ -461,13 +462,13 @@ final class SuggestionStripLayoutHelper {
             // {@link TextView#getTag()} is used to get the index in suggestedWords at
             // {@link SuggestionStripView#onClick(View)}.
             wordView.setTag(positionInStrip);
-            wordView.setText(suggestedWords.getWord(positionInStrip));
+            wordView.setText(punctuationSuggestions.getLabel(positionInStrip));
             wordView.setTextScaleX(1.0f);
             wordView.setCompoundDrawables(null, null, null, null);
             stripView.addView(wordView);
             setLayoutWeight(wordView, 1.0f, mSuggestionsStripHeight);
         }
-        mMoreSuggestionsAvailable = (suggestedWords.size() > countInStrip);
+        mMoreSuggestionsAvailable = (punctuationSuggestions.size() > countInStrip);
         return countInStrip;
     }
 
diff --git a/java/src/com/android/inputmethod/research/JsonUtils.java b/java/src/com/android/inputmethod/research/JsonUtils.java
index 2beebdfaeca916d534f3126478bc30e5acced14b..6170b4339aa363ddfab912b4ee279b77cefdc969 100644
--- a/java/src/com/android/inputmethod/research/JsonUtils.java
+++ b/java/src/com/android/inputmethod/research/JsonUtils.java
@@ -91,7 +91,7 @@ import java.util.Map;
         jsonWriter.name("willAutoCorrect")
                 .value(words.mWillAutoCorrect);
         jsonWriter.name("isPunctuationSuggestions")
-                .value(words.mIsPunctuationSuggestions);
+                .value(words.isPunctuationSuggestions());
         jsonWriter.name("isObsoleteSuggestions").value(words.mIsObsoleteSuggestions);
         jsonWriter.name("isPrediction").value(words.mIsPrediction);
         jsonWriter.name("suggestedWords");
diff --git a/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java b/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
index 53839b67fcd89e381effc25b14edc31f44768476..8fe473523fa57c6cefc35e1a229287945a596ed4 100644
--- a/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
+++ b/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
@@ -49,7 +49,6 @@ public class SuggestedWordsTests extends AndroidTestCase {
                 list, null /* rawSuggestions */,
                 false /* typedWordValid */,
                 false /* willAutoCorrect */,
-                false /* isPunctuationSuggestions */,
                 false /* isObsoleteSuggestions */,
                 false /* isPrediction*/);
         assertEquals(NUMBER_OF_ADDED_SUGGESTIONS + 1, words.size());
diff --git a/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java b/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java
index 424e7ff1bfa5d48fc228cf63d3f1d746d30af8e4..09920bfe9e591181ded9cf9a734c004835b4514d 100644
--- a/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java
+++ b/tests/src/com/android/inputmethod/latin/settings/SpacingAndPunctuationsTests.java
@@ -373,29 +373,37 @@ public class SpacingAndPunctuationsTests extends AndroidTestCase {
         assertTrue(SWISS_GERMAN.mUsesGermanRules);
     }
 
-    private static void testingStandardPunctuationSuggestions(final SpacingAndPunctuations sp) {
+    private static final String[] PUNCTUATION_LABELS = {
+        "!", "?", ",", ":", ";", "\"", "(", ")", "'", "-", "/", "@", "_"
+    };
+    private static final String[] PUNCTUATION_WORDS_LTR = PUNCTUATION_LABELS;
+    private static final String[] PUNCTUATION_WORDS_RTL = {
+        "!", "?", ",", ":", ";", "\"", ")", "(", "'", "-", "/", "@", "_"
+    };
+
+    private static void testingStandardPunctuationSuggestions(final SpacingAndPunctuations sp,
+            final String[] punctuationWords) {
         final SuggestedWords suggestedWords = sp.mSuggestPuncList;
         assertFalse("typedWordValid", suggestedWords.mTypedWordValid);
         assertFalse("willAutoCorrect", suggestedWords.mWillAutoCorrect);
-        assertTrue("isPunctuationSuggestions", suggestedWords.mIsPunctuationSuggestions);
+        assertTrue("isPunctuationSuggestions", suggestedWords.isPunctuationSuggestions());
         assertFalse("isObsoleteSuggestions", suggestedWords.mIsObsoleteSuggestions);
         assertFalse("isPrediction", suggestedWords.mIsPrediction);
-        final String[] punctuations = {
-            "!", "?", ",", ":", ";", "\"", "(", ")", "'", "-", "/", "@", "_"
-        };
-        assertEquals("size", punctuations.length, suggestedWords.size());
-        for (int index = 0; index < punctuations.length; index++) {
-            assertEquals("punctuation at " + index,
-                    punctuations[index], suggestedWords.getWord(index));
+        assertEquals("size", PUNCTUATION_LABELS.length, suggestedWords.size());
+        for (int index = 0; index < suggestedWords.size(); index++) {
+            assertEquals("punctuation label at " + index,
+                    PUNCTUATION_LABELS[index], suggestedWords.getLabel(index));
+            assertEquals("punctuation word at " + index,
+                    punctuationWords[index], suggestedWords.getWord(index));
         }
     }
+
     public void testPunctuationSuggestions() {
-        testingStandardPunctuationSuggestions(ENGLISH);
-        testingStandardPunctuationSuggestions(FRENCH);
-        testingStandardPunctuationSuggestions(GERMAN);
-        // TODO: Should fix these RTL languages
-        testingStandardPunctuationSuggestions(ARABIC);
-        testingStandardPunctuationSuggestions(PERSIAN);
-        testingStandardPunctuationSuggestions(HEBREW);
+        testingStandardPunctuationSuggestions(ENGLISH, PUNCTUATION_WORDS_LTR);
+        testingStandardPunctuationSuggestions(FRENCH, PUNCTUATION_WORDS_LTR);
+        testingStandardPunctuationSuggestions(GERMAN, PUNCTUATION_WORDS_LTR);
+        testingStandardPunctuationSuggestions(ARABIC, PUNCTUATION_WORDS_RTL);
+        testingStandardPunctuationSuggestions(PERSIAN, PUNCTUATION_WORDS_RTL);
+        testingStandardPunctuationSuggestions(HEBREW, PUNCTUATION_WORDS_RTL);
     }
 }