Direction estimators are simple classes which estimate a string's direction using various heuristics. This is useful for automatically setting the direction of an element that contains text. Review at http://gwt-code-reviews.appspot.com/338801 git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7973 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/i18n/shared/AnyRtlDirectionEstimator.java b/user/src/com/google/gwt/i18n/shared/AnyRtlDirectionEstimator.java new file mode 100644 index 0000000..e3855d4 --- /dev/null +++ b/user/src/com/google/gwt/i18n/shared/AnyRtlDirectionEstimator.java
@@ -0,0 +1,52 @@ +/* + * Copyright 2010 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.i18n.shared; + +import com.google.gwt.i18n.client.HasDirection.Direction; + +/** + * Direction estimator that uses the "any RTL" heuristic. + */ +public class AnyRtlDirectionEstimator extends DirectionEstimator { + + /** + * An instance of AnyRtlDirectionEstimator, to be returned by {@link #get}. + */ + private static final AnyRtlDirectionEstimator instance = + new AnyRtlDirectionEstimator(); + + /** + * Get an instance of AnyRtlDirectionEstimator. + * + * @return An instance of AnyRtlDirectionEstimator. + */ + public static AnyRtlDirectionEstimator get() { + return instance; + } + + /** + * Estimates the direction of a given string using the "any RTL" heuristic: + * the return value is RTL if the string contains at least one RTL character. + * Otherwise, it is LTR. + * + * @param str Input string. + * @return Direction The estimated direction of {@code str}. + */ + @Override + public Direction estimateDirection(String str) { + return BidiUtils.get().hasAnyRtl(str) ? Direction.RTL : Direction.LTR; + } +}
diff --git a/user/src/com/google/gwt/i18n/shared/DirectionEstimator.java b/user/src/com/google/gwt/i18n/shared/DirectionEstimator.java new file mode 100644 index 0000000..9488e54 --- /dev/null +++ b/user/src/com/google/gwt/i18n/shared/DirectionEstimator.java
@@ -0,0 +1,44 @@ +/* + * Copyright 2010 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.i18n.shared; + +import com.google.gwt.i18n.client.HasDirection.Direction; + +/** + * Interface for direction estimators. + */ +public abstract class DirectionEstimator { + + /** + * Estimates the direction of a plain-text string. + * + * @param str The string to check. + * @return {@code str}'s estimated direction. + */ + public abstract Direction estimateDirection(String str); + + /** + * Estimates the direction of a string. + * + * @param str The string to check. + * @param isHtml Whether {@code str} is HTML / HTML-escaped. {@code false} + * means that {@code str} is plain-text. + * @return {@code str}'s estimated direction. + */ + public Direction estimateDirection(String str, boolean isHtml) { + return estimateDirection(BidiUtils.get().stripHtmlIfNeeded(str, isHtml)); + } +}
diff --git a/user/src/com/google/gwt/i18n/shared/FirstStrongDirectionEstimator.java b/user/src/com/google/gwt/i18n/shared/FirstStrongDirectionEstimator.java new file mode 100644 index 0000000..ca596a3 --- /dev/null +++ b/user/src/com/google/gwt/i18n/shared/FirstStrongDirectionEstimator.java
@@ -0,0 +1,55 @@ +/* + * Copyright 2010 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.i18n.shared; + +import com.google.gwt.i18n.client.HasDirection.Direction; + +/** + * Direction estimator that uses the "first strong" heuristic. + */ +public class FirstStrongDirectionEstimator extends DirectionEstimator { + + /** + * An instance of FirstStrongDirectionEstimator, to be returned by + * {@link #get}. + */ + private static final FirstStrongDirectionEstimator instance = + new FirstStrongDirectionEstimator(); + + /** + * Get an instance of FirstStrongDirectionEstimator. + * + * @return An instance of FirstStrongDirectionEstimator. + */ + public static FirstStrongDirectionEstimator get() { + return instance; + } + + /** + * Estimates the direction of a given string using the "first strong" + * heuristic: The return value is determined by the first character in the + * string with strong directionality. If there is no such character, the + * return value is DEFAULT. + * + * @param str Input string. + * @return Direction The estimated direction of {@code str}. + */ + @Override + public Direction estimateDirection(String str) { + return BidiUtils.get().startsWithRtl(str) ? Direction.RTL : + BidiUtils.get().startsWithLtr(str) ? Direction.LTR : Direction.DEFAULT; + } +}
diff --git a/user/src/com/google/gwt/i18n/shared/HasDirectionEstimator.java b/user/src/com/google/gwt/i18n/shared/HasDirectionEstimator.java new file mode 100644 index 0000000..df86681 --- /dev/null +++ b/user/src/com/google/gwt/i18n/shared/HasDirectionEstimator.java
@@ -0,0 +1,43 @@ +/* + * Copyright 2010 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.i18n.shared; + +/** + * Interface for objects that have a direction estimator. + */ +public interface HasDirectionEstimator { + + /** + * @return the {@code DirectionEstimator} object. + */ + DirectionEstimator getDirectionEstimator(); + + /** + * Toggles on / off direction estimation. + * + * @param enabled Whether to enable direction estimation. If {@true}, sets the + * DirectionEstimator object to a default {@DirectionEstimator}. + */ + void setDirectionEstimator(boolean enabled); + + /** + * Sets the DirectionEstimator object. + * + * @param directionEstimator The {@code directionEstimator} to be set. {@code + * null} means turning off direction estimation. + */ + void setDirectionEstimator(DirectionEstimator directionEstimator); +}
diff --git a/user/src/com/google/gwt/i18n/shared/WordCountDirectionEstimator.java b/user/src/com/google/gwt/i18n/shared/WordCountDirectionEstimator.java new file mode 100644 index 0000000..0333609 --- /dev/null +++ b/user/src/com/google/gwt/i18n/shared/WordCountDirectionEstimator.java
@@ -0,0 +1,53 @@ +/* + * Copyright 2010 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.i18n.shared; + +import com.google.gwt.i18n.client.HasDirection.Direction; + +/** + * Direction estimator that uses the "word count" heuristic. + * + * <p> Note: this is probably the recommended estimator for most use cases. + */ +public class WordCountDirectionEstimator extends DirectionEstimator { + + /** + * An instance of WordCountDirectionEstimator, to be returned by {@link #get}. + */ + private static final WordCountDirectionEstimator instance = + new WordCountDirectionEstimator(); + + /** + * Get an instance of WordCountDirectionEstimator. + * + * @return An instance of WordCountDirectionEstimator. + */ + public static WordCountDirectionEstimator get() { + return instance; + } + + /** + * Estimates the direction of a given string using the "word count" heuristic, + * as defined at {@link BidiUtils#estimateDirection}. + * + * @param str Input string. + * @return Direction The estimated direction of {@code str}. + */ + @Override + public Direction estimateDirection(String str) { + return BidiUtils.get().estimateDirection(str); + } +}
diff --git a/user/test/com/google/gwt/i18n/I18NSuite.java b/user/test/com/google/gwt/i18n/I18NSuite.java index 0088aad..a1357fc 100644 --- a/user/test/com/google/gwt/i18n/I18NSuite.java +++ b/user/test/com/google/gwt/i18n/I18NSuite.java
@@ -44,9 +44,12 @@ import com.google.gwt.i18n.rebind.MessageFormatParserTest; import com.google.gwt.i18n.server.GwtLocaleTest; import com.google.gwt.i18n.server.RegionInheritanceTest; +import com.google.gwt.i18n.shared.AnyRtlDirectionEstimatorTest; import com.google.gwt.i18n.shared.BidiFormatterTest; import com.google.gwt.i18n.shared.BidiUtilsTest; +import com.google.gwt.i18n.shared.FirstStrongDirectionEstimatorTest; import com.google.gwt.i18n.shared.GwtBidiUtilsTest; +import com.google.gwt.i18n.shared.WordCountDirectionEstimatorTest; import com.google.gwt.junit.tools.GWTTestSuite; import junit.framework.Test; @@ -61,6 +64,7 @@ // $JUnit-BEGIN$ suite.addTestSuite(ArabicPluralsTest.class); suite.addTestSuite(AnnotationsTest.class); + suite.addTestSuite(AnyRtlDirectionEstimatorTest.class); suite.addTestSuite(BidiFormatterTest.class); suite.addTestSuite(BidiUtilsTest.class); suite.addTestSuite(ConstantMapTest.class); @@ -72,6 +76,7 @@ suite.addTestSuite(DateTimeFormat_pl_Test.class); suite.addTestSuite(DateTimeParse_en_Test.class); suite.addTestSuite(DateTimeParse_zh_CN_Test.class); + suite.addTestSuite(FirstStrongDirectionEstimatorTest.class); suite.addTestSuite(GwtBidiUtilsTest.class); suite.addTestSuite(GwtLocaleTest.class); suite.addTestSuite(I18NTest.class); @@ -92,6 +97,7 @@ suite.addTestSuite(RuntimeLocalesTest.class); suite.addTestSuite(TimeZoneInfoTest.class); suite.addTestSuite(TimeZoneTest.class); + suite.addTestSuite(WordCountDirectionEstimatorTest.class); // $JUnit-END$ return suite;
diff --git a/user/test/com/google/gwt/i18n/shared/AnyRtlDirectionEstimatorTest.java b/user/test/com/google/gwt/i18n/shared/AnyRtlDirectionEstimatorTest.java new file mode 100644 index 0000000..66d7687 --- /dev/null +++ b/user/test/com/google/gwt/i18n/shared/AnyRtlDirectionEstimatorTest.java
@@ -0,0 +1,44 @@ +/* + * Copyright 2010 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.i18n.shared; + +import com.google.gwt.i18n.client.HasDirection.Direction; + +/** + * Unit tests for {@link AnyRtlDirectionEstimator}. + */ +public class AnyRtlDirectionEstimatorTest extends DirectionEstimatorTestBase { + + @Override + protected void assertDirectionEstimation(Direction expectedDirection, + String str, boolean isHtml) { + assertDirectionEstimation(expectedDirection, AnyRtlDirectionEstimator.get(), + str, isHtml); + } + + private final String containsRtlChar = EN_WORD + DIGITS_WORD + + WORD_WITH_ONE_RTL_CHAR; + private final String noRtlChars = EN_WORD + DIGITS_WORD + NEUTRAL_WORD; + private final String noRtlCharsHtml = LONG_MIXED_TAG + EN_WORD + DIGITS_WORD; + + public void testEstimateDirection() { + assertDirectionEstimation(Direction.RTL, containsRtlChar); + assertDirectionEstimation(Direction.LTR, noRtlChars); + + assertDirectionEstimation(Direction.RTL, noRtlCharsHtml); + assertDirectionEstimationHtml(Direction.LTR, noRtlCharsHtml); + } +}
diff --git a/user/test/com/google/gwt/i18n/shared/DirectionEstimatorTestBase.java b/user/test/com/google/gwt/i18n/shared/DirectionEstimatorTestBase.java new file mode 100644 index 0000000..7960906 --- /dev/null +++ b/user/test/com/google/gwt/i18n/shared/DirectionEstimatorTestBase.java
@@ -0,0 +1,88 @@ +/* + * Copyright 2010 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.i18n.shared; + +import com.google.gwt.i18n.client.HasDirection.Direction; + +import junit.framework.TestCase; + +/** + * TestCase extension that includes some useful variables for estimation tests. + */ +public abstract class DirectionEstimatorTestBase extends TestCase { + + protected final String DIGITS_WORD = " 012"; + protected final String EN_WORD = " abc"; + protected final String IW_WORD = " \u05e0\u05e1\u05e2"; + protected final String LONG_LTR_TAG = "<some nasty tag>"; + + protected final String LONG_MIXED_TAG = "<some nasty tag" + IW_WORD + ">"; + protected final String NEUTRAL_WORD = " ___"; + protected final String WORD_WITH_ONE_RTL_CHAR = " ab\u05e0cd"; + + /** + * Asserts that the estimated direction of a given String matches the expected + * direction. + * + * @param expectedDirection The expected direction. + * @param directionEstimator A direction estimator object. + * @param str A String to estimate its direction. + * @param isHtml Whether {@code str} is HTML / HTML-escaped. + */ + protected void assertDirectionEstimation(Direction expectedDirection, + DirectionEstimator directionEstimator, String str, boolean isHtml) { + assertEquals(expectedDirection, + directionEstimator.estimateDirection(str, isHtml)); + } + + /** + * Asserts that the estimated direction of a given String matches the expected + * direction. + * The implementation will usually call {@link #assertDirectionEstimation( + * Direction, DirectionEstimator, String, boolean)} with the {@code + * DirectionEstimator} object to be tested. + * + * @param expectedDirection The expected direction. + * @param str A String whose direction is estimated. + * @param isHtml Whether {@code str} is HTML / HTML-escaped. + */ + protected abstract void assertDirectionEstimation(Direction expectedDirection, + String str, boolean isHtml); + + /** + * Operates like {@link #assertDirectionEstimation(Direction, String, + * boolean)}, but assuming {@code str} is not HTML / HTML-escaped. + * + * @param expectedDirection The expected direction. + * @param str A String whose direction is estimated. + */ + protected void assertDirectionEstimation(Direction expectedDirection, + String str) { + assertDirectionEstimation(expectedDirection, str, false); + } + + /** + * Operates like {@link #assertDirectionEstimation(Direction, String, + * boolean)}, but assuming {@code str} is HTML / HTML-escaped. + * + * @param expectedDirection The expected direction. + * @param str A String whose direction is estimated. + */ + protected void assertDirectionEstimationHtml(Direction expectedDirection, + String str) { + assertDirectionEstimation(expectedDirection, str, true); + } +}
diff --git a/user/test/com/google/gwt/i18n/shared/FirstStrongDirectionEstimatorTest.java b/user/test/com/google/gwt/i18n/shared/FirstStrongDirectionEstimatorTest.java new file mode 100644 index 0000000..efb0d2d --- /dev/null +++ b/user/test/com/google/gwt/i18n/shared/FirstStrongDirectionEstimatorTest.java
@@ -0,0 +1,46 @@ +/* + * Copyright 2010 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.i18n.shared; + +import com.google.gwt.i18n.client.HasDirection.Direction; + +/** + * Unit tests for {@link FirstStrongDirectionEstimator}. + */ +public class FirstStrongDirectionEstimatorTest extends DirectionEstimatorTestBase { + + @Override + protected void assertDirectionEstimation(Direction expectedDirection, + String str, boolean isHtml) { + assertDirectionEstimation(expectedDirection, + FirstStrongDirectionEstimator.get(), str, isHtml); + } + + private String firstStrongLtr = DIGITS_WORD + EN_WORD + IW_WORD + IW_WORD; + private String firstStrongRtl = DIGITS_WORD + IW_WORD + EN_WORD + EN_WORD; + private String firstStrongRtlHtml = DIGITS_WORD + LONG_LTR_TAG + IW_WORD + + EN_WORD; + private String noStrongChars = NEUTRAL_WORD + DIGITS_WORD; + + public void testEstimateDirection() { + assertDirectionEstimation(Direction.LTR, firstStrongLtr); + assertDirectionEstimation(Direction.RTL, firstStrongRtl); + assertDirectionEstimation(Direction.DEFAULT, noStrongChars); + + assertDirectionEstimation(Direction.LTR, firstStrongRtlHtml); + assertDirectionEstimationHtml(Direction.RTL, firstStrongRtlHtml); + } +}
diff --git a/user/test/com/google/gwt/i18n/shared/WordCountDirectionEstimatorTest.java b/user/test/com/google/gwt/i18n/shared/WordCountDirectionEstimatorTest.java new file mode 100644 index 0000000..dfb6561 --- /dev/null +++ b/user/test/com/google/gwt/i18n/shared/WordCountDirectionEstimatorTest.java
@@ -0,0 +1,47 @@ +/* + * Copyright 2010 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.i18n.shared; + +import com.google.gwt.i18n.client.HasDirection.Direction; + +/** + * Unit tests for {@link WordCountDirectionEstimator}. + */ +public class WordCountDirectionEstimatorTest extends DirectionEstimatorTestBase { + + @Override + protected void assertDirectionEstimation(Direction expectedDirection, + String str, boolean isHtml) { + assertDirectionEstimation(expectedDirection, + WordCountDirectionEstimator.get(), str, isHtml); + } + + private String pureNeutral = NEUTRAL_WORD; + private String rtlAboveThreshold = EN_WORD + IW_WORD; + private String rtlBelowThreshold = IW_WORD + EN_WORD + EN_WORD; + private String rtlHtml = LONG_LTR_TAG + IW_WORD; + private String weaklyLtr = NEUTRAL_WORD + DIGITS_WORD; + + public void testEstimateDirection() { + assertDirectionEstimation(Direction.RTL, rtlAboveThreshold); + assertDirectionEstimation(Direction.LTR, rtlBelowThreshold); + assertDirectionEstimation(Direction.LTR, weaklyLtr); + assertDirectionEstimation(Direction.DEFAULT, pureNeutral); + + assertDirectionEstimation(Direction.LTR, rtlHtml); + assertDirectionEstimationHtml(Direction.RTL, rtlHtml); + } +}