diff options
Diffstat (limited to 'tools/aapt')
-rw-r--r-- | tools/aapt/Bundle.h | 19 | ||||
-rw-r--r-- | tools/aapt/Command.cpp | 7 | ||||
-rw-r--r-- | tools/aapt/ResourceFilter.cpp | 6 | ||||
-rw-r--r-- | tools/aapt/ResourceFilter.h | 9 | ||||
-rw-r--r-- | tools/aapt/ResourceTable.cpp | 94 | ||||
-rw-r--r-- | tools/aapt/XMLNode.cpp | 42 | ||||
-rw-r--r-- | tools/aapt/XMLNode.h | 2 | ||||
-rw-r--r-- | tools/aapt/pseudolocalize.cpp | 251 | ||||
-rw-r--r-- | tools/aapt/pseudolocalize.h | 11 |
9 files changed, 336 insertions, 105 deletions
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h index 5089b9d..a6f2442 100644 --- a/tools/aapt/Bundle.h +++ b/tools/aapt/Bundle.h @@ -42,6 +42,15 @@ typedef enum Command { } Command; /* + * Pseudolocalization methods + */ +typedef enum PseudolocalizationMethod { + NO_PSEUDOLOCALIZATION = 0, + PSEUDO_ACCENTED, + PSEUDO_BIDI, +} PseudolocalizationMethod; + +/* * Bundle of goodies, including everything specified on the command line. */ class Bundle { @@ -50,12 +59,12 @@ public: : mCmd(kCommandUnknown), mVerbose(false), mAndroidList(false), mForce(false), mGrayscaleTolerance(0), mMakePackageDirs(false), mUpdate(false), mExtending(false), - mRequireLocalization(false), mPseudolocalize(false), + mRequireLocalization(false), mPseudolocalize(NO_PSEUDOLOCALIZATION), mWantUTF16(false), mValues(false), mCompressionMethod(0), mJunkPath(false), mOutputAPKFile(NULL), mManifestPackageNameOverride(NULL), mInstrumentationPackageNameOverride(NULL), mAutoAddOverlay(false), mGenDependencies(false), - mAssetSourceDir(NULL), + mAssetSourceDir(NULL), mCrunchedOutputDir(NULL), mProguardFile(NULL), mAndroidManifestFile(NULL), mPublicOutputFile(NULL), mRClassDir(NULL), mResourceIntermediatesDir(NULL), mManifestMinSdkVersion(NULL), @@ -94,8 +103,8 @@ public: void setExtending(bool val) { mExtending = val; } bool getRequireLocalization(void) const { return mRequireLocalization; } void setRequireLocalization(bool val) { mRequireLocalization = val; } - bool getPseudolocalize(void) const { return mPseudolocalize; } - void setPseudolocalize(bool val) { mPseudolocalize = val; } + short getPseudolocalize(void) const { return mPseudolocalize; } + void setPseudolocalize(short val) { mPseudolocalize = val; } void setWantUTF16(bool val) { mWantUTF16 = val; } bool getValues(void) const { return mValues; } void setValues(bool val) { mValues = val; } @@ -250,7 +259,7 @@ private: bool mUpdate; bool mExtending; bool mRequireLocalization; - bool mPseudolocalize; + short mPseudolocalize; bool mWantUTF16; bool mValues; int mCompressionMethod; diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp index c7cce96..f7de558 100644 --- a/tools/aapt/Command.cpp +++ b/tools/aapt/Command.cpp @@ -1885,14 +1885,17 @@ int doPackage(Bundle* bundle) FILE* fp; String8 dependencyFile; - // -c zz_ZZ means do pseudolocalization + // -c en_XA or/and ar_XB means do pseudolocalization ResourceFilter filter; err = filter.parse(bundle->getConfigurations()); if (err != NO_ERROR) { goto bail; } if (filter.containsPseudo()) { - bundle->setPseudolocalize(true); + bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_ACCENTED); + } + if (filter.containsPseudoBidi()) { + bundle->setPseudolocalize(bundle->getPseudolocalize() | PSEUDO_BIDI); } N = bundle->getFileSpecCount(); diff --git a/tools/aapt/ResourceFilter.cpp b/tools/aapt/ResourceFilter.cpp index e8a2be4..8ca852e 100644 --- a/tools/aapt/ResourceFilter.cpp +++ b/tools/aapt/ResourceFilter.cpp @@ -24,8 +24,10 @@ ResourceFilter::parse(const char* arg) String8 part(p, q-p); - if (part == "zz_ZZ") { - mContainsPseudo = true; + if (part == "en_XA") { + mContainsPseudoAccented = true; + } else if (part == "ar_XB") { + mContainsPseudoBidi = true; } int axis; AxisValue value; diff --git a/tools/aapt/ResourceFilter.h b/tools/aapt/ResourceFilter.h index 0d127ba..c57770e 100644 --- a/tools/aapt/ResourceFilter.h +++ b/tools/aapt/ResourceFilter.h @@ -16,19 +16,22 @@ class ResourceFilter { public: - ResourceFilter() : mData(), mContainsPseudo(false) {} + ResourceFilter() : mData(), mContainsPseudoAccented(false), + mContainsPseudoBidi(false) {} status_t parse(const char* arg); bool isEmpty() const; bool match(int axis, const ResTable_config& config) const; bool match(const ResTable_config& config) const; const SortedVector<AxisValue>* configsForAxis(int axis) const; - inline bool containsPseudo() const { return mContainsPseudo; } + inline bool containsPseudo() const { return mContainsPseudoAccented; } + inline bool containsPseudoBidi() const { return mContainsPseudoBidi; } private: bool match(int axis, const AxisValue& value) const; KeyedVector<int,SortedVector<AxisValue> > mData; - bool mContainsPseudo; + bool mContainsPseudoAccented; + bool mContainsPseudoBidi; }; #endif diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp index 0b1f985..26b5bd6 100644 --- a/tools/aapt/ResourceTable.cpp +++ b/tools/aapt/ResourceTable.cpp @@ -25,7 +25,7 @@ status_t compileXmlFile(const sp<AaptAssets>& assets, if (root == NULL) { return UNKNOWN_ERROR; } - + return compileXmlFile(assets, root, target, table, options); } @@ -577,13 +577,13 @@ status_t parseAndAddBag(Bundle* bundle, int32_t curFormat, bool isFormatted, const String16& product, - bool pseudolocalize, + PseudolocalizationMethod pseudolocalize, const bool overwrite, ResourceTable* outTable) { status_t err; const String16 item16("item"); - + String16 str; Vector<StringPool::entry_style_span> spans; err = parseStyledString(bundle, in->getPrintableSource().string(), @@ -672,7 +672,7 @@ status_t parseAndAddEntry(Bundle* bundle, int32_t curFormat, bool isFormatted, const String16& product, - bool pseudolocalize, + PseudolocalizationMethod pseudolocalize, const bool overwrite, KeyedVector<type_ident_pair_t, bool>* skippedResourceNames, ResourceTable* outTable) @@ -854,10 +854,16 @@ status_t compileResourceFile(Bundle* bundle, ResTable_config curParams(defParams); ResTable_config pseudoParams(curParams); - pseudoParams.language[0] = 'z'; - pseudoParams.language[1] = 'z'; - pseudoParams.country[0] = 'Z'; - pseudoParams.country[1] = 'Z'; + pseudoParams.language[0] = 'e'; + pseudoParams.language[1] = 'n'; + pseudoParams.country[0] = 'X'; + pseudoParams.country[1] = 'A'; + + ResTable_config pseudoBidiParams(curParams); + pseudoBidiParams.language[0] = 'a'; + pseudoBidiParams.language[1] = 'r'; + pseudoBidiParams.country[0] = 'X'; + pseudoBidiParams.country[1] = 'B'; while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { if (code == ResXMLTree::START_TAG) { @@ -1334,6 +1340,7 @@ status_t compileResourceFile(Bundle* bundle, name, locale, SourcePos(in->getPrintableSource(), block.getLineNumber())); + curIsPseudolocalizable = fileIsTranslatable; } if (formatted == false16) { @@ -1389,6 +1396,7 @@ status_t compileResourceFile(Bundle* bundle, curTag = &plurals16; curType = plurals16; curIsBag = true; + curIsPseudolocalizable = fileIsTranslatable; } else if (strcmp16(block.getElementName(&len), array16.string()) == 0) { curTag = &array16; curType = array16; @@ -1410,25 +1418,23 @@ status_t compileResourceFile(Bundle* bundle, } else if (strcmp16(block.getElementName(&len), string_array16.string()) == 0) { // Check whether these strings need valid formats. // (simplified form of what string16 does above) + bool isTranslatable = false; size_t n = block.getAttributeCount(); // Pseudolocalizable by default, unless this string array isn't // translatable. - curIsPseudolocalizable = true; for (size_t i = 0; i < n; i++) { size_t length; const uint16_t* attr = block.getAttributeName(i, &length); - if (strcmp16(attr, translatable16.string()) == 0) { + if (strcmp16(attr, formatted16.string()) == 0) { const uint16_t* value = block.getAttributeStringValue(i, &length); if (strcmp16(value, false16.string()) == 0) { - curIsPseudolocalizable = false; + curIsFormatted = false; } - } - - if (strcmp16(attr, formatted16.string()) == 0) { + } else if (strcmp16(attr, translatable16.string()) == 0) { const uint16_t* value = block.getAttributeStringValue(i, &length); if (strcmp16(value, false16.string()) == 0) { - curIsFormatted = false; + isTranslatable = false; } } } @@ -1438,6 +1444,7 @@ status_t compileResourceFile(Bundle* bundle, curFormat = ResTable_map::TYPE_REFERENCE|ResTable_map::TYPE_STRING; curIsBag = true; curIsBagReplaceOnOverwrite = true; + curIsPseudolocalizable = isTranslatable && fileIsTranslatable; } else if (strcmp16(block.getElementName(&len), integer_array16.string()) == 0) { curTag = &integer_array16; curType = array16; @@ -1559,19 +1566,29 @@ status_t compileResourceFile(Bundle* bundle, err = parseAndAddBag(bundle, in, &block, curParams, myPackage, curType, ident, parentIdent, itemIdent, curFormat, curIsFormatted, - product, false, overwrite, outTable); + product, NO_PSEUDOLOCALIZATION, overwrite, outTable); if (err == NO_ERROR) { if (curIsPseudolocalizable && localeIsDefined(curParams) - && bundle->getPseudolocalize()) { + && bundle->getPseudolocalize() > 0) { // pseudolocalize here -#if 1 - block.setPosition(parserPosition); - err = parseAndAddBag(bundle, in, &block, pseudoParams, myPackage, - curType, ident, parentIdent, itemIdent, curFormat, - curIsFormatted, product, true, overwrite, outTable); -#endif + if ((PSEUDO_ACCENTED & bundle->getPseudolocalize()) == + PSEUDO_ACCENTED) { + block.setPosition(parserPosition); + err = parseAndAddBag(bundle, in, &block, pseudoParams, myPackage, + curType, ident, parentIdent, itemIdent, curFormat, + curIsFormatted, product, PSEUDO_ACCENTED, + overwrite, outTable); + } + if ((PSEUDO_BIDI & bundle->getPseudolocalize()) == + PSEUDO_BIDI) { + block.setPosition(parserPosition); + err = parseAndAddBag(bundle, in, &block, pseudoBidiParams, myPackage, + curType, ident, parentIdent, itemIdent, curFormat, + curIsFormatted, product, PSEUDO_BIDI, + overwrite, outTable); + } } - } + } if (err != NO_ERROR) { hasErrors = localHasErrors = true; } @@ -1592,20 +1609,31 @@ status_t compileResourceFile(Bundle* bundle, err = parseAndAddEntry(bundle, in, &block, curParams, myPackage, curType, ident, *curTag, curIsStyled, curFormat, curIsFormatted, - product, false, overwrite, &skippedResourceNames, outTable); + product, NO_PSEUDOLOCALIZATION, overwrite, &skippedResourceNames, outTable); if (err < NO_ERROR) { // Why err < NO_ERROR instead of err != NO_ERROR? hasErrors = localHasErrors = true; } else if (err == NO_ERROR) { if (curIsPseudolocalizable && localeIsDefined(curParams) - && bundle->getPseudolocalize()) { + && bundle->getPseudolocalize() > 0) { // pseudolocalize here - block.setPosition(parserPosition); - err = parseAndAddEntry(bundle, in, &block, pseudoParams, myPackage, curType, - ident, *curTag, curIsStyled, curFormat, - curIsFormatted, product, - true, overwrite, &skippedResourceNames, outTable); + if ((PSEUDO_ACCENTED & bundle->getPseudolocalize()) == + PSEUDO_ACCENTED) { + block.setPosition(parserPosition); + err = parseAndAddEntry(bundle, in, &block, pseudoParams, myPackage, curType, + ident, *curTag, curIsStyled, curFormat, + curIsFormatted, product, + PSEUDO_ACCENTED, overwrite, &skippedResourceNames, outTable); + } + if ((PSEUDO_BIDI & bundle->getPseudolocalize()) == + PSEUDO_BIDI) { + block.setPosition(parserPosition); + err = parseAndAddEntry(bundle, in, &block, pseudoBidiParams, + myPackage, curType, ident, *curTag, curIsStyled, curFormat, + curIsFormatted, product, + PSEUDO_BIDI, overwrite, &skippedResourceNames, outTable); + } if (err != NO_ERROR) { hasErrors = localHasErrors = true; } @@ -2636,8 +2664,8 @@ ResourceTable::validateLocalizations(void) continue; } - // don't bother with the pseudolocale "zz_ZZ" - if (config != "zz_ZZ") { + // don't bother with the pseudolocale "en_XA" or "ar_XB" + if (config != "en_XA" && config != "ar_XB") { if (configSrcMap.find(config) == configSrcMap.end()) { // okay, no specific localization found. it's possible that we are // requiring a specific regional localization [e.g. de_DE] but there is an diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp index a663ad5..607d419 100644 --- a/tools/aapt/XMLNode.cpp +++ b/tools/aapt/XMLNode.cpp @@ -187,7 +187,7 @@ status_t parseStyledString(Bundle* bundle, String16* outString, Vector<StringPool::entry_style_span>* outSpans, bool isFormatted, - bool pseudolocalize) + PseudolocalizationMethod pseudolocalize) { Vector<StringPool::entry_style_span> spanStack; String16 curString; @@ -198,21 +198,30 @@ status_t parseStyledString(Bundle* bundle, size_t len; ResXMLTree::event_code_t code; + // Bracketing if pseudolocalization accented method specified. + if (pseudolocalize == PSEUDO_ACCENTED) { + curString.append(String16(String8("["))); + } while ((code=inXml->next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { - if (code == ResXMLTree::TEXT) { String16 text(inXml->getText(&len)); if (firstTime && text.size() > 0) { firstTime = false; if (text.string()[0] == '@') { // If this is a resource reference, don't do the pseudoloc. - pseudolocalize = false; + pseudolocalize = NO_PSEUDOLOCALIZATION; } } - if (xliffDepth == 0 && pseudolocalize) { - std::string orig(String8(text).string()); - std::string pseudo = pseudolocalize_string(orig); - curString.append(String16(String8(pseudo.c_str()))); + if (xliffDepth == 0 && pseudolocalize > 0) { + String16 pseudo; + if (pseudolocalize == PSEUDO_ACCENTED) { + pseudo = pseudolocalize_string(text); + } else if (pseudolocalize == PSEUDO_BIDI) { + pseudo = pseudobidi_string(text); + } else { + pseudo = text; + } + curString.append(pseudo); } else { if (isFormatted && hasSubstitutionErrors(fileName, inXml, text) != NO_ERROR) { return UNKNOWN_ERROR; @@ -352,6 +361,25 @@ moveon: } } + // Bracketing if pseudolocalization accented method specified. + if (pseudolocalize == PSEUDO_ACCENTED) { + const char16_t* str = outString->string(); + const char16_t* p = str; + const char16_t* e = p + outString->size(); + int words_cnt = 0; + while (p < e) { + if (isspace(*p)) { + words_cnt++; + } + p++; + } + unsigned int length = words_cnt > 3 ? outString->size() : + outString->size() / 2; + curString.append(String16(String8(" "))); + curString.append(pseudo_generate_expansion(length)); + curString.append(String16(String8("]"))); + } + if (code == ResXMLTree::BAD_DOCUMENT) { SourcePos(String8(fileName), inXml->getLineNumber()).error( "Error parsing XML\n"); diff --git a/tools/aapt/XMLNode.h b/tools/aapt/XMLNode.h index 05624b7..ccbf9f4 100644 --- a/tools/aapt/XMLNode.h +++ b/tools/aapt/XMLNode.h @@ -26,7 +26,7 @@ status_t parseStyledString(Bundle* bundle, String16* outString, Vector<StringPool::entry_style_span>* outSpans, bool isFormatted, - bool isPseudolocalizable); + PseudolocalizationMethod isPseudolocalizable); void printXMLBlock(ResXMLTree* block); diff --git a/tools/aapt/pseudolocalize.cpp b/tools/aapt/pseudolocalize.cpp index 9e50c5a..c02327a 100644 --- a/tools/aapt/pseudolocalize.cpp +++ b/tools/aapt/pseudolocalize.cpp @@ -2,89 +2,155 @@ using namespace std; +// String basis to generate expansion +static const String16 k_expansion_string = String16("one two three " + "four five six seven eight nine ten eleven twelve thirteen " + "fourteen fiveteen sixteen seventeen nineteen twenty"); + +// Special unicode characters to override directionality of the words +static const String16 k_rlm = String16("\xe2\x80\x8f"); +static const String16 k_rlo = String16("\xE2\x80\xae"); +static const String16 k_pdf = String16("\xE2\x80\xac"); + +// Placeholder marks +static const String16 k_placeholder_open = String16("\xc2\xbb"); +static const String16 k_placeholder_close = String16("\xc2\xab"); + static const char* -pseudolocalize_char(char c) +pseudolocalize_char(const char16_t c) { switch (c) { - case 'a': return "\xc4\x83"; - case 'b': return "\xcf\x84"; - case 'c': return "\xc4\x8b"; - case 'd': return "\xc4\x8f"; - case 'e': return "\xc4\x99"; + case 'a': return "\xc3\xa5"; + case 'b': return "\xc9\x93"; + case 'c': return "\xc3\xa7"; + case 'd': return "\xc3\xb0"; + case 'e': return "\xc3\xa9"; case 'f': return "\xc6\x92"; case 'g': return "\xc4\x9d"; - case 'h': return "\xd1\x9b"; - case 'i': return "\xcf\x8a"; + case 'h': return "\xc4\xa5"; + case 'i': return "\xc3\xae"; case 'j': return "\xc4\xb5"; - case 'k': return "\xc4\xb8"; - case 'l': return "\xc4\xba"; + case 'k': return "\xc4\xb7"; + case 'l': return "\xc4\xbc"; case 'm': return "\xe1\xb8\xbf"; - case 'n': return "\xd0\xb8"; - case 'o': return "\xcf\x8c"; - case 'p': return "\xcf\x81"; + case 'n': return "\xc3\xb1"; + case 'o': return "\xc3\xb6"; + case 'p': return "\xc3\xbe"; case 'q': return "\x51"; - case 'r': return "\xd2\x91"; + case 'r': return "\xc5\x95"; case 's': return "\xc5\xa1"; - case 't': return "\xd1\x82"; - case 'u': return "\xce\xb0"; + case 't': return "\xc5\xa3"; + case 'u': return "\xc3\xbb"; case 'v': return "\x56"; - case 'w': return "\xe1\xba\x85"; + case 'w': return "\xc5\xb5"; case 'x': return "\xd1\x85"; - case 'y': return "\xe1\xbb\xb3"; - case 'z': return "\xc5\xba"; + case 'y': return "\xc3\xbd"; + case 'z': return "\xc5\xbe"; case 'A': return "\xc3\x85"; case 'B': return "\xce\xb2"; - case 'C': return "\xc4\x88"; - case 'D': return "\xc4\x90"; - case 'E': return "\xd0\x84"; - case 'F': return "\xce\x93"; - case 'G': return "\xc4\x9e"; - case 'H': return "\xc4\xa6"; - case 'I': return "\xd0\x87"; - case 'J': return "\xc4\xb5"; + case 'C': return "\xc3\x87"; + case 'D': return "\xc3\x90"; + case 'E': return "\xc3\x89"; + case 'G': return "\xc4\x9c"; + case 'H': return "\xc4\xa4"; + case 'I': return "\xc3\x8e"; + case 'J': return "\xc4\xb4"; case 'K': return "\xc4\xb6"; - case 'L': return "\xc5\x81"; + case 'L': return "\xc4\xbb"; case 'M': return "\xe1\xb8\xbe"; - case 'N': return "\xc5\x83"; - case 'O': return "\xce\x98"; - case 'P': return "\xcf\x81"; + case 'N': return "\xc3\x91"; + case 'O': return "\xc3\x96"; + case 'P': return "\xc3\x9e"; case 'Q': return "\x71"; - case 'R': return "\xd0\xaf"; - case 'S': return "\xc8\x98"; - case 'T': return "\xc5\xa6"; - case 'U': return "\xc5\xa8"; + case 'R': return "\xc5\x94"; + case 'S': return "\xc5\xa0"; + case 'T': return "\xc5\xa2"; + case 'U': return "\xc3\x9b"; case 'V': return "\xce\xbd"; - case 'W': return "\xe1\xba\x84"; + case 'W': return "\xc5\xb4"; case 'X': return "\xc3\x97"; - case 'Y': return "\xc2\xa5"; + case 'Y': return "\xc3\x9d"; case 'Z': return "\xc5\xbd"; + case '!': return "\xc2\xa1"; + case '?': return "\xc2\xbf"; + case '$': return "\xe2\x82\xac"; default: return NULL; } } +static const bool +is_possible_normal_placeholder_end(const char16_t c) { + switch (c) { + case 's': return true; + case 'S': return true; + case 'c': return true; + case 'C': return true; + case 'd': return true; + case 'o': return true; + case 'x': return true; + case 'X': return true; + case 'f': return true; + case 'e': return true; + case 'E': return true; + case 'g': return true; + case 'G': return true; + case 'a': return true; + case 'A': return true; + case 'b': return true; + case 'B': return true; + case 'h': return true; + case 'H': return true; + case '%': return true; + case 'n': return true; + default: return false; + } +} + +String16 +pseudo_generate_expansion(const unsigned int length) { + String16 result = k_expansion_string; + const char16_t* s = result.string(); + if (result.size() < length) { + result += String16(" "); + result += pseudo_generate_expansion(length - result.size()); + } else { + int ext = 0; + // Should contain only whole words, so looking for a space + for (unsigned int i = length + 1; i < result.size(); ++i) { + ++ext; + if (s[i] == ' ') { + break; + } + } + result.remove(length + ext, 0); + } + return result; +} + /** * Converts characters so they look like they've been localized. * * Note: This leaves escape sequences untouched so they can later be * processed by ResTable::collectString in the normal way. */ -string -pseudolocalize_string(const string& source) +String16 +pseudolocalize_string(const String16& source) { - const char* s = source.c_str(); - string result; - const size_t I = source.length(); + const char16_t* s = source.string(); + String16 result; + const size_t I = source.size(); for (size_t i=0; i<I; i++) { - char c = s[i]; + char16_t c = s[i]; if (c == '\\') { + // Escape syntax, no need to pseudolocalize if (i<I-1) { - result += '\\'; + result += String16("\\"); i++; c = s[i]; switch (c) { case 'u': // this one takes up 5 chars - result += string(s+i, 5); + result += String16(s+i, 5); i += 4; break; case 't': @@ -96,24 +162,107 @@ pseudolocalize_string(const string& source) case '\'': case '\\': default: - result += c; + result.append(&c, 1); break; } } else { - result += c; + result.append(&c, 1); + } + } else if (c == '%') { + // Placeholder syntax, no need to pseudolocalize + result += k_placeholder_open; + bool end = false; + result.append(&c, 1); + while (!end && i < I) { + ++i; + c = s[i]; + result.append(&c, 1); + if (is_possible_normal_placeholder_end(c)) { + end = true; + } else if (c == 't') { + ++i; + c = s[i]; + result.append(&c, 1); + end = true; + } + } + result += k_placeholder_close; + } else if (c == '<' || c == '&') { + // html syntax, no need to pseudolocalize + bool tag_closed = false; + while (!tag_closed && i < I) { + if (c == '&') { + String16 escape_text; + escape_text.append(&c, 1); + bool end = false; + size_t htmlCodePos = i; + while (!end && htmlCodePos < I) { + ++htmlCodePos; + c = s[htmlCodePos]; + escape_text.append(&c, 1); + // Valid html code + if (c == ';') { + end = true; + i = htmlCodePos; + } + // Wrong html code + else if (!((c == '#' || + (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9')))) { + end = true; + } + } + result += escape_text; + if (escape_text != String16("<")) { + tag_closed = true; + } + continue; + } + if (c == '>') { + tag_closed = true; + result.append(&c, 1); + continue; + } + result.append(&c, 1); + i++; + c = s[i]; } } else { + // This is a pure text that should be pseudolocalized const char* p = pseudolocalize_char(c); if (p != NULL) { - result += p; + result += String16(p); } else { - result += c; + result.append(&c, 1); } } } - - //printf("result=\'%s\'\n", result.c_str()); return result; } +String16 +pseudobidi_string(const String16& source) +{ + const char16_t* s = source.string(); + String16 result; + result += k_rlm; + result += k_rlo; + for (size_t i=0; i<source.size(); i++) { + char16_t c = s[i]; + switch(c) { + case ' ': result += k_pdf; + result += k_rlm; + result.append(&c, 1); + result += k_rlm; + result += k_rlo; + break; + default: result.append(&c, 1); + break; + } + } + result += k_pdf; + result += k_rlm; + return result; +} diff --git a/tools/aapt/pseudolocalize.h b/tools/aapt/pseudolocalize.h index 94cb034..e6ab18e 100644 --- a/tools/aapt/pseudolocalize.h +++ b/tools/aapt/pseudolocalize.h @@ -1,9 +1,18 @@ #ifndef HOST_PSEUDOLOCALIZE_H #define HOST_PSEUDOLOCALIZE_H +#include "StringPool.h" + #include <string> -std::string pseudolocalize_string(const std::string& source); +String16 pseudolocalize_string(const String16& source); +// Surrounds every word in the sentance with specific characters that makes +// the word directionality RTL. +String16 pseudobidi_string(const String16& source); +// Generates expansion string based on the specified lenght. +// Generated string could not be shorter that length, but it could be slightly +// longer. +String16 pseudo_generate_expansion(const unsigned int length); #endif // HOST_PSEUDOLOCALIZE_H |