Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(525)

Unified Diff: lib/i18n/bidi_utils.dart

Issue 10703030: Get rid of BidiUtils as a class holding only static methods. I was reminded by (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/i18n/bidi_formatter.dart ('k') | tests/lib/i18n/bidi_format_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/i18n/bidi_utils.dart
===================================================================
--- lib/i18n/bidi_utils.dart (revision 9206)
+++ lib/i18n/bidi_utils.dart (working copy)
@@ -48,346 +48,344 @@
}
}
-class BidiUtils {
- /** Unicode "Left-To-Right Embedding" (LRE) character. */
- static final LRE = '\u202A';
+/** Unicode "Left-To-Right Embedding" (LRE) character. */
+final LRE = '\u202A';
- /** Unicode "Right-To-Left Embedding" (RLE) character. */
- static final RLE = '\u202B';
+/** Unicode "Right-To-Left Embedding" (RLE) character. */
+final RLE = '\u202B';
- /** Unicode "Pop Directional Formatting" (PDF) character. */
- static final PDF = '\u202C';
+/** Unicode "Pop Directional Formatting" (PDF) character. */
+final PDF = '\u202C';
- /** Unicode "Left-To-Right Mark" (LRM) character. */
- static final LRM = '\u200E';
+/** Unicode "Left-To-Right Mark" (LRM) character. */
+final LRM = '\u200E';
- /** Unicode "Right-To-Left Mark" (RLM) character. */
- static final RLM = '\u200F';
+/** Unicode "Right-To-Left Mark" (RLM) character. */
+final RLM = '\u200F';
- /** Constant to define the threshold of RTL directionality. */
- static num _RTL_DETECTION_THRESHOLD = 0.40;
+/** Constant to define the threshold of RTL directionality. */
+num _RTL_DETECTION_THRESHOLD = 0.40;
- /**
- * Practical patterns to identify strong LTR and RTL characters, respectively.
- * These patterns are not completely correct according to the Unicode
- * standard. They are simplified for performance and small code size.
- */
- static final String _LTR_CHARS =
- @'A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02B8\u0300-\u0590'
- @'\u0800-\u1FFF\u2C00-\uFB1C\uFDFE-\uFE6F\uFEFD-\uFFFF';
- static final String _RTL_CHARS = @'\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC';
+/**
+ * Practical patterns to identify strong LTR and RTL characters, respectively.
+ * These patterns are not completely correct according to the Unicode
+ * standard. They are simplified for performance and small code size.
+ */
+final String _LTR_CHARS =
+ @'A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02B8\u0300-\u0590'
+ @'\u0800-\u1FFF\u2C00-\uFB1C\uFDFE-\uFE6F\uFEFD-\uFFFF';
+final String _RTL_CHARS = @'\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC';
- /**
- * Returns the input [text] with spaces instead of HTML tags or HTML escapes,
- * which is helpful for text directionality estimation.
- * Note: This function should not be used in other contexts.
- * It does not deal well with many things: comments, script,
- * elements, style elements, dir attribute,`>` in quoted attribute values,
- * etc. But it does handle well enough the most common use cases.
- * Since the worst that can happen as a result of these shortcomings is that
- * the wrong directionality will be estimated, we have not invested in
- * improving this.
- */
- static String stripHtmlIfNeeded(String text) {
- // The regular expression is simplified for an HTML tag (opening or
- // closing) or an HTML escape. We might want to skip over such expressions
- // when estimating the text directionality.
- return text.replaceAll(const RegExp(@'<[^>]*>|&[^;]+;'), ' ');
- }
+/**
+ * Returns the input [text] with spaces instead of HTML tags or HTML escapes,
+ * which is helpful for text directionality estimation.
+ * Note: This function should not be used in other contexts.
+ * It does not deal well with many things: comments, script,
+ * elements, style elements, dir attribute,`>` in quoted attribute values,
+ * etc. But it does handle well enough the most common use cases.
+ * Since the worst that can happen as a result of these shortcomings is that
+ * the wrong directionality will be estimated, we have not invested in
+ * improving this.
+ */
+String stripHtmlIfNeeded(String text) {
+ // The regular expression is simplified for an HTML tag (opening or
+ // closing) or an HTML escape. We might want to skip over such expressions
+ // when estimating the text directionality.
+ return text.replaceAll(const RegExp(@'<[^>]*>|&[^;]+;'), ' ');
+}
- /**
- * Determines if the first character in [text] with strong directionality is
- * LTR. If [isHtml] is true, the text is HTML or HTML-escaped.
- */
- static bool startsWithLtr(String text, [isHtml=false]) {
- return const RegExp('^[^$_RTL_CHARS]*[$_LTR_CHARS]').hasMatch(
- isHtml? stripHtmlIfNeeded(text) : text);
- }
+/**
+ * Determines if the first character in [text] with strong directionality is
+ * LTR. If [isHtml] is true, the text is HTML or HTML-escaped.
+ */
+bool startsWithLtr(String text, [isHtml=false]) {
+ return const RegExp('^[^$_RTL_CHARS]*[$_LTR_CHARS]').hasMatch(
+ isHtml? stripHtmlIfNeeded(text) : text);
+}
- /**
- * Determines if the first character in [text] with strong directionality is
- * RTL. If [isHtml] is true, the text is HTML or HTML-escaped.
- */
- static bool startsWithRtl(String text, [isHtml=false]) {
- return const RegExp('^[^$_LTR_CHARS]*[$_RTL_CHARS]').hasMatch(
- isHtml? stripHtmlIfNeeded(text) : text);
- }
+/**
+ * Determines if the first character in [text] with strong directionality is
+ * RTL. If [isHtml] is true, the text is HTML or HTML-escaped.
+ */
+bool startsWithRtl(String text, [isHtml=false]) {
+ return const RegExp('^[^$_LTR_CHARS]*[$_RTL_CHARS]').hasMatch(
+ isHtml? stripHtmlIfNeeded(text) : text);
+}
- /**
- * Determines if the exit directionality (ie, the last strongly-directional
- * character in [text] is LTR. If [isHtml] is true, the text is HTML or
- * HTML-escaped.
- */
- static bool endsWithLtr(String text, [isHtml=false]) {
- return const RegExp('[$_LTR_CHARS][^$_RTL_CHARS]*\$').hasMatch(
- isHtml? stripHtmlIfNeeded(text) : text);
- }
+/**
+ * Determines if the exit directionality (ie, the last strongly-directional
+ * character in [text] is LTR. If [isHtml] is true, the text is HTML or
+ * HTML-escaped.
+ */
+bool endsWithLtr(String text, [isHtml=false]) {
+ return const RegExp('[$_LTR_CHARS][^$_RTL_CHARS]*\$').hasMatch(
+ isHtml? stripHtmlIfNeeded(text) : text);
+}
- /**
- * Determines if the exit directionality (ie, the last strongly-directional
- * character in [text] is RTL. If [isHtml] is true, the text is HTML or
- * HTML-escaped.
- */
- static bool endsWithRtl(String text, [isHtml=false]) {
- return const RegExp('[$_RTL_CHARS][^$_LTR_CHARS]*\$').hasMatch(
- isHtml? stripHtmlIfNeeded(text) : text);
- }
+/**
+ * Determines if the exit directionality (ie, the last strongly-directional
+ * character in [text] is RTL. If [isHtml] is true, the text is HTML or
+ * HTML-escaped.
+ */
+bool endsWithRtl(String text, [isHtml=false]) {
+ return const RegExp('[$_RTL_CHARS][^$_LTR_CHARS]*\$').hasMatch(
+ isHtml? stripHtmlIfNeeded(text) : text);
+}
- /**
- * Determines if the given [text] has any LTR characters in it.
- * If [isHtml] is true, the text is HTML or HTML-escaped.
- */
- static bool hasAnyLtr(String text, [isHtml=false]) {
- return const RegExp(@'[' '$_LTR_CHARS' @']').hasMatch(
- isHtml? stripHtmlIfNeeded(text) : text);
- }
+/**
+ * Determines if the given [text] has any LTR characters in it.
+ * If [isHtml] is true, the text is HTML or HTML-escaped.
+ */
+bool hasAnyLtr(String text, [isHtml=false]) {
+ return const RegExp(@'[' '$_LTR_CHARS' @']').hasMatch(
+ isHtml? stripHtmlIfNeeded(text) : text);
+}
- /**
- * Determines if the given [text] has any RTL characters in it.
- * If [isHtml] is true, the text is HTML or HTML-escaped.
- */
- static bool hasAnyRtl(String text, [isHtml=false]) {
- return const RegExp(@'[' '$_RTL_CHARS' @']').hasMatch(
- isHtml? stripHtmlIfNeeded(text) : text);
- }
+/**
+ * Determines if the given [text] has any RTL characters in it.
+ * If [isHtml] is true, the text is HTML or HTML-escaped.
+ */
+bool hasAnyRtl(String text, [isHtml=false]) {
+ return const RegExp(@'[' '$_RTL_CHARS' @']').hasMatch(
+ isHtml? stripHtmlIfNeeded(text) : text);
+}
- /**
- * Check if a BCP 47 / III [languageString] indicates an RTL language.
- *
- * i.e. either:
- * - a language code explicitly specifying one of the right-to-left scripts,
- * e.g. "az-Arab", or
- * - a language code specifying one of the languages normally written in a
- * right-to-left script, e.g. "fa" (Farsi), except ones explicitly
- * specifying Latin or Cyrillic script (which are the usual LTR
- * alternatives).
- *
- * The list of right-to-left scripts appears in the 100-199 range in
- * http://www.unicode.org/iso15924/iso15924-num.html, of which Arabic and
- * Hebrew are by far the most widely used. We also recognize Thaana, N'Ko, and
- * Tifinagh, which also have significant modern usage. The rest (Syriac,
- * Samaritan, Mandaic, etc.) seem to have extremely limited or no modern usage
- * and are not recognized.
- * The languages usually written in a right-to-left script are taken as those
- * with Suppress-Script: Hebr|Arab|Thaa|Nkoo|Tfng in
- * http://www.iana.org/assignments/language-subtag-registry,
- * as well as Sindhi (sd) and Uyghur (ug).
- * The presence of other subtags of the language code, e.g. regions like EG
- * (Egypt), is ignored.
- */
- static bool isRtlLanguage(String languageString) {
- return const RegExp(@'^(ar|dv|he|iw|fa|nqo|ps|sd|ug|ur|yi|.*[-_]'
- @'(Arab|Hebr|Thaa|Nkoo|Tfng))(?!.*[-_](Latn|Cyrl)($|-|_))'
- @'($|-|_)', ignoreCase : true).hasMatch(languageString);
- }
+/**
+ * Check if a BCP 47 / III [languageString] indicates an RTL language.
+ *
+ * i.e. either:
+ * - a language code explicitly specifying one of the right-to-left scripts,
+ * e.g. "az-Arab", or
+ * - a language code specifying one of the languages normally written in a
+ * right-to-left script, e.g. "fa" (Farsi), except ones explicitly
+ * specifying Latin or Cyrillic script (which are the usual LTR
+ * alternatives).
+ *
+ * The list of right-to-left scripts appears in the 100-199 range in
+ * http://www.unicode.org/iso15924/iso15924-num.html, of which Arabic and
+ * Hebrew are by far the most widely used. We also recognize Thaana, N'Ko, and
+ * Tifinagh, which also have significant modern usage. The rest (Syriac,
+ * Samaritan, Mandaic, etc.) seem to have extremely limited or no modern usage
+ * and are not recognized.
+ * The languages usually written in a right-to-left script are taken as those
+ * with Suppress-Script: Hebr|Arab|Thaa|Nkoo|Tfng in
+ * http://www.iana.org/assignments/language-subtag-registry,
+ * as well as Sindhi (sd) and Uyghur (ug).
+ * The presence of other subtags of the language code, e.g. regions like EG
+ * (Egypt), is ignored.
+ */
+bool isRtlLanguage(String languageString) {
+ return const RegExp(@'^(ar|dv|he|iw|fa|nqo|ps|sd|ug|ur|yi|.*[-_]'
+ @'(Arab|Hebr|Thaa|Nkoo|Tfng))(?!.*[-_](Latn|Cyrl)($|-|_))'
+ @'($|-|_)', ignoreCase : true).hasMatch(languageString);
+}
- /**
- * Enforce the [html] snippet in RTL directionality regardless of overall
- * context. If the html piece was enclosed by a tag, the direction will be
- * applied to existing tag, otherwise a span tag will be added as wrapper.
- * For this reason, if html snippet start with with tag, this tag must enclose
- * the whole piece. If the tag already has a direction specified, this new one
- * will override existing one in behavior (should work on Chrome, FF, and IE
- * since this was ported directly from the Closure version).
- */
- static String enforceRtlInHtml(String html) {
- return _enforceInHtmlHelper(html, 'rtl');
- }
+/**
+ * Enforce the [html] snippet in RTL directionality regardless of overall
+ * context. If the html piece was enclosed by a tag, the direction will be
+ * applied to existing tag, otherwise a span tag will be added as wrapper.
+ * For this reason, if html snippet start with with tag, this tag must enclose
+ * the whole piece. If the tag already has a direction specified, this new one
+ * will override existing one in behavior (should work on Chrome, FF, and IE
+ * since this was ported directly from the Closure version).
+ */
+String enforceRtlInHtml(String html) {
+ return _enforceInHtmlHelper(html, 'rtl');
+}
- /**
- * Enforce RTL on both end of the given [text] using unicode BiDi formatting
- * characters RLE and PDF.
- */
- static String enforceRtlInText(String text) {
- return '$RLE$text$PDF';
- }
+/**
+ * Enforce RTL on both end of the given [text] using unicode BiDi formatting
+ * characters RLE and PDF.
+ */
+String enforceRtlInText(String text) {
+ return '$RLE$text$PDF';
+}
- /**
- * Enforce the [html] snippet in LTR directionality regardless of overall
- * context. If the html piece was enclosed by a tag, the direction will be
- * applied to existing tag, otherwise a span tag will be added as wrapper.
- * For this reason, if html snippet start with with tag, this tag must enclose
- * the whole piece. If the tag already has a direction specified, this new one
- * will override existing one in behavior (tested on FF and IE).
- */
- static String enforceLtrInHtml(String html) {
- return _enforceInHtmlHelper(html, 'ltr');
- }
+/**
+ * Enforce the [html] snippet in LTR directionality regardless of overall
+ * context. If the html piece was enclosed by a tag, the direction will be
+ * applied to existing tag, otherwise a span tag will be added as wrapper.
+ * For this reason, if html snippet start with with tag, this tag must enclose
+ * the whole piece. If the tag already has a direction specified, this new one
+ * will override existing one in behavior (tested on FF and IE).
+ */
+String enforceLtrInHtml(String html) {
+ return _enforceInHtmlHelper(html, 'ltr');
+}
- /**
- * Enforce LTR on both end of the given [text] using unicode BiDi formatting
- * characters LRE and PDF.
- */
- static String enforceLtrInText(String text) {
- return '$LRE$text$PDF';
- }
+/**
+ * Enforce LTR on both end of the given [text] using unicode BiDi formatting
+ * characters LRE and PDF.
+ */
+String enforceLtrInText(String text) {
+ return '$LRE$text$PDF';
+}
- /**
- * Enforce the [html] snippet in the desired [direction] regardless of overall
- * context. If the html piece was enclosed by a tag, the direction will be
- * applied to existing tag, otherwise a span tag will be added as wrapper.
- * For this reason, if html snippet start with with tag, this tag must enclose
- * the whole piece. If the tag already has a direction specified, this new one
- * will override existing one in behavior (tested on FF and IE).
- */
- static String _enforceInHtmlHelper(String html, String direction) {
- if (html.startsWith('<')) {
- StringBuffer buffer = new StringBuffer();
- var startIndex = 0;
- Match match = const RegExp('<\\w+').firstMatch(html);
- if (match != null) {
- buffer.add(html.substring(
- startIndex, match.end())).add(' dir=$direction');
- startIndex = match.end();
- }
- return buffer.add(html.substring(startIndex)).toString();
+/**
+ * Enforce the [html] snippet in the desired [direction] regardless of overall
+ * context. If the html piece was enclosed by a tag, the direction will be
+ * applied to existing tag, otherwise a span tag will be added as wrapper.
+ * For this reason, if html snippet start with with tag, this tag must enclose
+ * the whole piece. If the tag already has a direction specified, this new one
+ * will override existing one in behavior (tested on FF and IE).
+ */
+String _enforceInHtmlHelper(String html, String direction) {
+ if (html.startsWith('<')) {
+ StringBuffer buffer = new StringBuffer();
+ var startIndex = 0;
+ Match match = const RegExp('<\\w+').firstMatch(html);
+ if (match != null) {
+ buffer.add(html.substring(
+ startIndex, match.end())).add(' dir=$direction');
+ startIndex = match.end();
}
- // '\n' is important for FF so that it won't incorrectly merge span groups.
- return '\n<span dir=$direction>$html</span>';
+ return buffer.add(html.substring(startIndex)).toString();
}
+ // '\n' is important for FF so that it won't incorrectly merge span groups.
+ return '\n<span dir=$direction>$html</span>';
+}
- /**
- * Apply bracket guard to [str] using html span tag. This is to address the
- * problem of messy bracket display that frequently happens in RTL layout.
- * If [isRtlContext] is true, then we explicitly want to wrap in a span of RTL
- * directionality, regardless of the estimated directionality.
- */
- static String guardBracketInHtml(String str, [bool isRtlContext]) {
- var useRtl = isRtlContext == null ? hasAnyRtl(str) : isRtlContext;
- RegExp matchingBrackets =
- const RegExp(@'(\(.*?\)+)|(\[.*?\]+)|(\{.*?\}+)|(&lt;.*?(&gt;)+)');
- return _guardBracketHelper(str, matchingBrackets,
- '<span dir=${useRtl? "rtl" : "ltr"}>', '</span>');
- }
+/**
+ * Apply bracket guard to [str] using html span tag. This is to address the
+ * problem of messy bracket display that frequently happens in RTL layout.
+ * If [isRtlContext] is true, then we explicitly want to wrap in a span of RTL
+ * directionality, regardless of the estimated directionality.
+ */
+String guardBracketInHtml(String str, [bool isRtlContext]) {
+ var useRtl = isRtlContext == null ? hasAnyRtl(str) : isRtlContext;
+ RegExp matchingBrackets =
+ const RegExp(@'(\(.*?\)+)|(\[.*?\]+)|(\{.*?\}+)|(&lt;.*?(&gt;)+)');
+ return _guardBracketHelper(str, matchingBrackets,
+ '<span dir=${useRtl? "rtl" : "ltr"}>', '</span>');
+}
- /**
- * Apply bracket guard to [str] using LRM and RLM. This is to address the
- * problem of messy bracket display that frequently happens in RTL layout.
- * This version works for both plain text and html, but in some cases is not
- * as good as guardBracketInHtml.
- * If [isRtlContext] is true, then we explicitly want to wrap in a span of RTL
- * directionality, regardless of the estimated directionality.
- */
- static String guardBracketInText(String str, [bool isRtlContext]) {
- var useRtl = isRtlContext == null ? hasAnyRtl(str) : isRtlContext;
- var mark = useRtl ? RLM : LRM;
- return _guardBracketHelper(str,
- const RegExp(@'(\(.*?\)+)|(\[.*?\]+)|(\{.*?\}+)|(<.*?>+)'), mark, mark);
+/**
+ * Apply bracket guard to [str] using LRM and RLM. This is to address the
+ * problem of messy bracket display that frequently happens in RTL layout.
+ * This version works for both plain text and html, but in some cases is not
+ * as good as guardBracketInHtml.
+ * If [isRtlContext] is true, then we explicitly want to wrap in a span of RTL
+ * directionality, regardless of the estimated directionality.
+ */
+String guardBracketInText(String str, [bool isRtlContext]) {
+ var useRtl = isRtlContext == null ? hasAnyRtl(str) : isRtlContext;
+ var mark = useRtl ? RLM : LRM;
+ return _guardBracketHelper(str,
+ const RegExp(@'(\(.*?\)+)|(\[.*?\]+)|(\{.*?\}+)|(<.*?>+)'), mark, mark);
+}
+
+/**
+ * (Mostly) reimplements the $& functionality of "replace" in JavaScript.
+ * Given a [str] and the [regexp] to match with, optionally supply a string to
+ * be inserted [before] the match and/or [after]. For example,
+ * `_guardBracketHelper('firetruck', const RegExp('truck'), 'hydrant', '!')`
+ * would return 'firehydrant!'.
+ */
+// TODO(efortuna): Get rid of this once this is implemented in Dart.
+// See Issue 2979.
+String _guardBracketHelper(String str, RegExp regexp, [String before,
+ String after]) {
+ StringBuffer buffer = new StringBuffer();
+ var startIndex = 0;
+ Iterable matches = regexp.allMatches(str);
+ for (Match match in matches) {
+ buffer.add(str.substring(startIndex, match.start())).add(before);
+ buffer.add(str.substring(match.start(), match.end())).add(after);
+ startIndex = match.end();
}
+ return buffer.add(str.substring(startIndex)).toString();
+}
- /**
- * (Mostly) reimplements the $& functionality of "replace" in JavaScript.
- * Given a [str] and the [regexp] to match with, optionally supply a string to
- * be inserted [before] the match and/or [after]. For example,
- * `_guardBracketHelper('firetruck', const RegExp('truck'), 'hydrant', '!')`
- * would return 'firehydrant!'.
- */
- // TODO(efortuna): Get rid of this once this is implemented in Dart.
- // See Issue 2979.
- static String _guardBracketHelper(String str, RegExp regexp, [String before,
- String after]) {
- StringBuffer buffer = new StringBuffer();
- var startIndex = 0;
- Iterable matches = regexp.allMatches(str);
- for (Match match in matches) {
- buffer.add(str.substring(startIndex, match.start())).add(before);
- buffer.add(str.substring(match.start(), match.end())).add(after);
- startIndex = match.end();
+/**
+ * Estimates the directionality of [text] using the best known
+ * general-purpose method (using relative word counts). A
+ * TextDirection.UNKNOWN return value indicates completely neutral input.
+ * [isHtml] is true if [text] HTML or HTML-escaped.
+ *
+ * If the number of RTL words is above a certain percentage of the total
+ * number of strongly directional words, returns RTL.
+ * Otherwise, if any words are strongly or weakly LTR, returns LTR.
+ * Otherwise, returns UNKNOWN, which is used to mean `neutral`.
+ * Numbers and URLs are counted as weakly LTR.
+ */
+TextDirection estimateDirectionOfText(String text, [bool isHtml=false]) {
+ text = isHtml? stripHtmlIfNeeded(text) : text;
+ var rtlCount = 0;
+ var total = 0;
+ var hasWeaklyLtr = false;
+ // Split a string into 'words' for directionality estimation based on
+ // relative word counts.
+ for (String token in text.split(const RegExp(@'\s+'))) {
+ if (startsWithRtl(token)) {
+ rtlCount++;
+ total++;
+ } else if (const RegExp(@'^http://').hasMatch(token)) {
+ // Checked if token looks like something that must always be LTR even in
+ // RTL text, such as a URL.
+ hasWeaklyLtr = true;
+ } else if (hasAnyLtr(token)) {
+ total++;
+ } else if (const RegExp(@'\d').hasMatch(token)) {
+ // Checked if token contains any numerals.
+ hasWeaklyLtr = true;
}
- return buffer.add(str.substring(startIndex)).toString();
}
- /**
- * Estimates the directionality of [text] using the best known
- * general-purpose method (using relative word counts). A
- * TextDirection.UNKNOWN return value indicates completely neutral input.
- * [isHtml] is true if [text] HTML or HTML-escaped.
- *
- * If the number of RTL words is above a certain percentage of the total
- * number of strongly directional words, returns RTL.
- * Otherwise, if any words are strongly or weakly LTR, returns LTR.
- * Otherwise, returns UNKNOWN, which is used to mean `neutral`.
- * Numbers and URLs are counted as weakly LTR.
- */
- static TextDirection estimateDirection(String text, [bool isHtml=false]) {
- text = isHtml? stripHtmlIfNeeded(text) : text;
- var rtlCount = 0;
- var total = 0;
- var hasWeaklyLtr = false;
- // Split a string into 'words' for directionality estimation based on
- // relative word counts.
- for (String token in text.split(const RegExp(@'\s+'))) {
- if (BidiUtils.startsWithRtl(token)) {
- rtlCount++;
- total++;
- } else if (const RegExp(@'^http://').hasMatch(token)) {
- // Checked if token looks like something that must always be LTR even in
- // RTL text, such as a URL.
- hasWeaklyLtr = true;
- } else if (BidiUtils.hasAnyLtr(token)) {
- total++;
- } else if (const RegExp(@'\d').hasMatch(token)) {
- // Checked if token contains any numerals.
- hasWeaklyLtr = true;
- }
- }
-
- if (total == 0) {
- return hasWeaklyLtr ? TextDirection.LTR : TextDirection.UNKNOWN;
- } else if (rtlCount > BidiUtils._RTL_DETECTION_THRESHOLD * total) {
- return TextDirection.RTL;
- } else {
- return TextDirection.LTR;
- }
+ if (total == 0) {
+ return hasWeaklyLtr ? TextDirection.LTR : TextDirection.UNKNOWN;
+ } else if (rtlCount > _RTL_DETECTION_THRESHOLD * total) {
+ return TextDirection.RTL;
+ } else {
+ return TextDirection.LTR;
}
+}
- /**
- * Find the first index in [str] of the first closing parenthesis that does
- * not match an opening parenthesis.
- */
- static int _unmatchedParenIndex(String str) {
- int sum = 0;
- int index = 0;
- while (sum >= 0 || index > str.length) {
- int char = str.charCodeAt(index);
- if (char == '('.charCodeAt(0)) sum++;
- else if (char == ')'.charCodeAt(0)) sum--;
- index++;
- }
- return index;
+/**
+ * Find the first index in [str] of the first closing parenthesis that does
+ * not match an opening parenthesis.
+ */
+int _unmatchedParenIndex(String str) {
+ int sum = 0;
+ int index = 0;
+ while (sum >= 0 || index > str.length) {
+ int char = str.charCodeAt(index);
+ if (char == '('.charCodeAt(0)) sum++;
+ else if (char == ')'.charCodeAt(0)) sum--;
+ index++;
}
+ return index;
+}
- /**
- * Replace the double and single quote directly after a Hebrew character in
- * [str] with GERESH and GERSHAYIM. This is most likely the user's intention.
- */
- static String normalizeHebrewQuote(String str) {
- StringBuffer buf = new StringBuffer();
- if (str.length > 0) {
- buf.add(str.substring(0, 1));
+/**
+ * Replace the double and single quote directly after a Hebrew character in
+ * [str] with GERESH and GERSHAYIM. This is most likely the user's intention.
+ */
+String normalizeHebrewQuote(String str) {
+ StringBuffer buf = new StringBuffer();
+ if (str.length > 0) {
+ buf.add(str.substring(0, 1));
+ }
+ // Start at 1 because we're looking for the patterns [\u0591-\u05f2])" or
+ // [\u0591-\u05f2]'.
+ for (int i = 1; i < str.length; i++) {
+ if (str.substring(i, i+1) == '"'
+ && const RegExp('[\u0591-\u05f2]').hasMatch(str.substring(i-1, i))) {
+ buf.add('\u05f4');
+ } else if (str.substring(i, i+1) == "'"
+ && const RegExp('[\u0591-\u05f2]').hasMatch(str.substring(i-1, i))) {
+ buf.add('\u05f3');
+ } else {
+ buf.add(str.substring(i, i+1));
}
- // Start at 1 because we're looking for the patterns [\u0591-\u05f2])" or
- // [\u0591-\u05f2]'.
- for (int i = 1; i < str.length; i++) {
- if (str.substring(i, i+1) == '"'
- && const RegExp('[\u0591-\u05f2]').hasMatch(str.substring(i-1, i))) {
- buf.add('\u05f4');
- } else if (str.substring(i, i+1) == "'"
- && const RegExp('[\u0591-\u05f2]').hasMatch(str.substring(i-1, i))) {
- buf.add('\u05f3');
- } else {
- buf.add(str.substring(i, i+1));
- }
- }
- return buf.toString();
}
+ return buf.toString();
+}
- /**
- * Check the directionality of [str], return true if the piece of
- * text should be laid out in RTL direction. If [isHtml] is true, the string
- * is HTML or HTML-escaped.
- */
- static bool detectRtlDirectionality(String str, [bool isHtml]) {
- return estimateDirection(str, isHtml) == TextDirection.RTL;
- }
+/**
+ * Check the estimated directionality of [str], return true if the piece of
+ * text should be laid out in RTL direction. If [isHtml] is true, the string
+ * is HTML or HTML-escaped.
+ */
+bool detectRtlDirectionality(String str, [bool isHtml]) {
+ return estimateDirectionOfText(str, isHtml) == TextDirection.RTL;
}
« no previous file with comments | « lib/i18n/bidi_formatter.dart ('k') | tests/lib/i18n/bidi_format_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698