Skip to content

Commit f05b1e6

Browse files
juguyumaoka
authored andcommitted
using double single quote in message format
1 parent 070b36e commit f05b1e6

5 files changed

Lines changed: 132 additions & 48 deletions

File tree

gp-res-filter/src/main/java/com/ibm/g11n/pipeline/resfilter/impl/JavaPropertiesResource.java

Lines changed: 71 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -842,18 +842,10 @@ public static String ConvertSingleQuote(String inputStr, MessagePatternEscape ms
842842
}
843843

844844
MessagePattern msgPat = null;
845-
try {
846-
msgPat = new MessagePattern(inputStr);
847-
} catch (IllegalArgumentException e) {
848-
// not a message format pattern - fall through
849-
} catch (IndexOutOfBoundsException e) {
850-
// might be a valid message format pattern, but cannot handle this - fall through
851-
}
852-
if (msgPat == null) {
853-
// if the string cannot be parsed as a MessageFormat pattern string,
854-
// just returns the input string.
845+
if (!isMessagePatternCompatible(inputStr)) {
855846
return inputStr;
856847
}
848+
msgPat = new MessagePattern(inputStr);
857849

858850
if (msgPatEsc == MessagePatternEscape.AUTO) {
859851
// In AUTO mode, checks if the input string contains arguments.
@@ -875,57 +867,92 @@ public static String ConvertSingleQuote(String inputStr, MessagePatternEscape ms
875867

876868

877869
/***
878-
* '{1}' -> '{1}'
870+
* '{1}' -> ''{1}''
879871
* '{''}' -> '{''}'
880872
* '{'' -> '{''
881873
* '{'}' -> '{'}''
882874
* developer's -> developer''s
883875
*/
884876

885877
StringBuilder outputBuf = new StringBuilder();
886-
int len = inputStr.length();
887-
boolean keepQuote = false; //Flag for '{ or '}
888-
int outstrIndex = 0;
889-
int quoteIndex = 0;
890-
891-
while (quoteIndex < len) {
892-
int idx = inputStr.indexOf("'", quoteIndex);
893-
894-
if (idx > -1) {
895-
if (!keepQuote && idx + 1 < len
896-
&& (inputStr.charAt(idx + 1) == '{' || inputStr.charAt(idx + 1) == '}')) {
897-
keepQuote = true;
898-
quoteIndex = idx + 2;
899-
} else {
900-
if (keepQuote) { // '{ or '} is not closed yet
901-
if (idx + 1 < len && inputStr.charAt(idx + 1) == '\'') { //Ignore ''
902-
quoteIndex = idx+2;
903-
} else {
904-
keepQuote = false; //Close '{ or '} with this '
905-
quoteIndex = idx+1;
906-
}
907-
} else {
908-
outputBuf
909-
.append(inputStr.substring(outstrIndex, idx))
910-
.append("''");
911-
quoteIndex = idx+1;
912-
outstrIndex = quoteIndex;
878+
879+
String[] quotedArr = inputStr.split("'");
880+
// Split the sentence into string array based on single quote
881+
// For each element of the array,
882+
// if the element begins with a expression {.*
883+
// then check the following elements of the array to determine where the expression ends with }
884+
// if the expression ends on the same element, then it means that the content within {.*}
885+
// doesn't contain any single quotes, and hence the expression can be easily appended/prepended with ''
886+
// Use single ' to append array elements between { and }
887+
// Use single ' to append on either end to wrap quoted {.*}, where the content inside { and } is having quotes.
888+
// This is still an incomplete fix, due to inconsistency in upload/download. However it handles most of the basic cases.
889+
outputBuf.append(quotedArr[0]);
890+
boolean doDoubleQuote = true;
891+
for (int i = 1; i < quotedArr.length; i++) {
892+
String interimStr = "";
893+
if (quotedArr[i].startsWith("{")) {
894+
if (quotedArr[i].endsWith("}")) {
895+
outputBuf.append("''").append(quotedArr[i]);
896+
if (i == quotedArr.length - 1) { // terminal element which ends with }'
897+
outputBuf.append("''");
898+
}
899+
continue;
900+
}
901+
doDoubleQuote = false;
902+
interimStr = quotedArr[i];
903+
int j = i + 1;
904+
// look whether there is an ending "}" in the subsequent elements
905+
for (;j < quotedArr.length && !quotedArr[j].endsWith("}"); j++) {
906+
// any element in this range will be appended with single quote.
907+
// we don't want to corrupt the pattern inside {}
908+
interimStr = interimStr + "'" + quotedArr[j];
909+
}
910+
i = Math.min (j, quotedArr.length);
911+
if (i < quotedArr.length) {
912+
outputBuf.append("'").append(interimStr).append("'").append(quotedArr[j]);
913+
if (i == quotedArr.length - 1 && inputStr.endsWith("'")) {
914+
outputBuf.append("'");
913915
}
916+
} else {
917+
outputBuf.append("'").append(interimStr);
914918
}
915919
} else {
916-
//No single quote is found
917-
outputBuf.append(inputStr.substring(outstrIndex));
918-
break;
920+
if (doDoubleQuote) {
921+
outputBuf.append("''").append(quotedArr[i]);
922+
} else {
923+
outputBuf.append("'").append(quotedArr[i]);
924+
doDoubleQuote = true;
925+
}
919926
}
920-
}//End while
927+
}
921928

922-
if (quoteIndex >= len) {
923-
outputBuf.append(inputStr.substring(outstrIndex));
929+
// Falling back to input string, if the operations yielded a non message compatible string
930+
if (!isMessagePatternCompatible(outputBuf.toString())) {
931+
System.out.println(outputBuf.toString() + " is not message pattern compatible");
932+
return inputStr;
924933
}
925934

926935
return outputBuf.toString();
927936
}
928937

938+
939+
public static boolean isMessagePatternCompatible(String inputStr) {
940+
MessagePattern msgPat = null;
941+
try {
942+
msgPat = new MessagePattern(inputStr);
943+
} catch (IllegalArgumentException e) {
944+
// not a message format pattern - fall through
945+
} catch (IndexOutOfBoundsException e) {
946+
// might be a valid message format pattern, but cannot handle this - fall through
947+
}
948+
if (msgPat == null) {
949+
// if the string cannot be parsed as a MessageFormat pattern string,
950+
// just returns the input string.
951+
return false;
952+
}
953+
return true;
954+
}
955+
929956
public static int findSingleQuote(String inputStr, int start){
930957
return -1;
931958
}

gp-res-filter/src/test/java/com/ibm/g11n/pipeline/resfilter/impl/JavaPropertiesResourceTest.java

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import com.ibm.g11n.pipeline.resfilter.ResourceFilterException;
4343
import com.ibm.g11n.pipeline.resfilter.ResourceString;
4444
import com.ibm.g11n.pipeline.resfilter.ResourceString.ResourceStringComparator;
45+
import com.ibm.g11n.pipeline.resfilter.impl.JavaPropertiesResource.Encoding;
4546
import com.ibm.g11n.pipeline.resfilter.impl.JavaPropertiesResource.MessagePatternEscape;
4647
import com.ibm.g11n.pipeline.resfilter.impl.JavaPropertiesResource.PropDef;
4748
import com.ibm.g11n.pipeline.resfilter.impl.JavaPropertiesResource.PropDef.PropSeparator;
@@ -55,6 +56,9 @@ public class JavaPropertiesResourceTest {
5556

5657
private static final File EXPECTED_WRITE_FILE = new File(
5758
"src/test/resource/resfilter/properties/write-output.properties");
59+
60+
private static final File EXPECTED_WRITE_FILE_ALL = new File(
61+
"src/test/resource/resfilter/properties/write-output-all.properties");
5862

5963
private static final File EXPECTED_MERGE_FILE = new File(
6064
"src/test/resource/resfilter/properties/merge-output.properties");
@@ -146,6 +150,29 @@ public class JavaPropertiesResourceTest {
146150
" a preceding backslash to ensure that they are properly loaded."));
147151
WRITE_BUNDLE = bundleBuilder.build();
148152
}
153+
154+
private static LanguageBundle WRITE_BUNDLE_ALL;
155+
156+
static {
157+
LanguageBundleBuilder bundleBuilder = new LanguageBundleBuilder(false);
158+
bundleBuilder.addResourceString("A","This is a test.", 1);
159+
bundleBuilder.addResourceString("B","This isn't a test.", 2);
160+
bundleBuilder.addResourceString("C","This is't and won't be a test.", 3);
161+
bundleBuilder.addResourceString("D","This isn't a '{0}'.", 4);
162+
bundleBuilder.addResourceString("E","This isn't a '{0}' but a {1}.", 5);
163+
bundleBuilder.addResourceString("F","This '{0}' isn't right.", 6);
164+
bundleBuilder.addResourceString("G","This '{wasn't}' isn't right.", 7);
165+
bundleBuilder.addResourceString("H","This '{''}' shouldn't be fine for '{0}'.", 8);
166+
bundleBuilder.addResourceString("I","{0}", 9);
167+
bundleBuilder.addResourceString("J","'{0}'", 10);
168+
bundleBuilder.addResourceString("K","Using '{' and '}'", 11);
169+
bundleBuilder.addResourceString("L","'{' is ok to use", 12);
170+
bundleBuilder.addResourceString("M","The name '{0}' is already in use.",13);
171+
bundleBuilder.addResourceString("N","length must be between '{min} and '{max}",14);
172+
bundleBuilder.addResourceString("O","Password should not contain:#.-_'().",15);
173+
bundleBuilder.addResourceString("P","[\\p'{'L'}'\\uFF65]", 16);
174+
WRITE_BUNDLE_ALL = bundleBuilder.build();
175+
}
149176

150177
private static LinkedList<PropDef> EXPECTED_PROP_DEF_LIST;
151178

@@ -322,10 +349,10 @@ public void testUnescapePropsValue() {
322349
private static final String[][] QUOTES_TEST_CASES =
323350
{
324351
{"You're about to delete {0} rows.","You''re about to delete {0} rows."},
325-
{"You're about to delete '{0}' rows in Mike's file {0}.","You''re about to delete '{0}' rows in Mike''s file {0}."},
352+
{"You're about to delete '{0}' rows in Mike's file {0}.","You''re about to delete ''{0}'' rows in Mike''s file {0}."},
326353
{"Log shows '{''}' in file {0}","Log shows '{''}' in file {0}"},
327354
{"Log shows '{''} in file {0}","Log shows '{''} in file {0}"},
328-
{"Log shows '{'}' in file {0}","Log shows '{'}'' in file {0}"},
355+
{"Log shows '{'}' in file {0}","Log shows '{'}' in file {0}"},
329356
{"Log shows '{'error'}' in file {0}","Log shows '{'error'}' in file {0}"},
330357
{"Log shows '{''error''}' in file {0}","Log shows '{''error''}' in file {0}"},
331358
{"File {0} shows '{''error''}'","File {0} shows '{''error''}'"},
@@ -402,4 +429,17 @@ public void testConvertDoubleSingleQuoteAuto(){
402429
assertEquals("ConvertDoubleSingleQuote(" + testCase[0] + ", ALL)", testCase[1], result);
403430
}
404431
}
432+
433+
@Test
434+
public void testWriteAllQuotes() throws IOException, ResourceFilterException {
435+
File tempFile = File.createTempFile(this.getClass().getSimpleName(), ".properties");
436+
JavaPropertiesResource res = new JavaPropertiesResource(Encoding.ISO_8859_1, MessagePatternEscape.ALL);
437+
tempFile.deleteOnExit();
438+
try (OutputStream os = new FileOutputStream(tempFile)) {
439+
res.write(os, WRITE_BUNDLE_ALL, null);
440+
os.flush();
441+
// Ignore first line in both the files (first line empty in expected, first line contains timestamp in actual)
442+
assertTrue(ResourceTestUtil.compareFiles(EXPECTED_WRITE_FILE_ALL, tempFile, 1));
443+
}
444+
}
405445
}

gp-res-filter/src/test/resource/resfilter/properties/merge-output.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ trailSPs = localized trailing SPs
2222
# tabs
2323
withTabs = localized Tab1\tTab2\tTab3\t
2424
# Quote
25-
withQuote = You''re about to delete '{1}' rows in Mike''s file {0}.
25+
withQuote = You''re about to delete ''{1}'' rows in Mike''s file {0}.
2626
# Not a Java MessageFormat param
2727
non-param = This {} is not a parameter.
2828
# A comment with backslashes - a\b\c \u3042\u3044 \t\n
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
A = This is a test.
3+
B = This isn''t a test.
4+
C = This is''t and won''t be a test.
5+
D = This isn''t a ''{0}''.
6+
E = This isn''t a ''{0}'' but a {1}.
7+
F = This ''{0}'' isn''t right.
8+
G = This '{wasn't}' isn''t right.
9+
H = This '{''}' shouldn''t be fine for ''{0}''.
10+
I = {0}
11+
J = ''{0}''
12+
K = Using '{' and '}'
13+
L = '{' is ok to use
14+
M = The name ''{0}'' is already in use.
15+
N = length must be between '{min} and '{max}
16+
O = Password should not contain\:\#.-_''().
17+
P = [\\p'{'L'}'\\uFF65]

gp-res-filter/src/test/resource/resfilter/properties/write-output.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ trailSPs = localized trailing SPs
2323
# tabs
2424
withTabs = localized Tab1\tTab2\tTab3\t
2525
# Quote
26-
withQuote = You''re about to delete '{1}' rows in Mike''s file {0}.
26+
withQuote = You''re about to delete ''{1}'' rows in Mike''s file {0}.
2727
# Not a Java MessageFormat param
2828
non-param = This {} is not a parameter.
2929
# A comment with backslashes - a\b\c \u3042\u3044 \t\n

0 commit comments

Comments
 (0)