PseudolocaleGenerator.cpp revision ce5e56e243d262a9b65459c3bd0bb9eaadd40628
1393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski/* 2393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski * Copyright (C) 2016 The Android Open Source Project 3393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski * 4393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 5393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski * you may not use this file except in compliance with the License. 6393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski * You may obtain a copy of the License at 7393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski * 8393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 9393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski * 10393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski * Unless required by applicable law or agreed to in writing, software 11393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 12393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski * See the License for the specific language governing permissions and 14393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski * limitations under the License. 15393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski */ 16393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski 17cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski#include "compile/PseudolocaleGenerator.h" 18ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 19ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include <algorithm> 20ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 21393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski#include "ResourceTable.h" 22393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski#include "ResourceValues.h" 23393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski#include "ValueVisitor.h" 24393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski#include "compile/Pseudolocalizer.h" 25393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski 26393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinskinamespace aapt { 27393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski 28ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistd::unique_ptr<StyledString> PseudolocalizeStyledString( 29cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski StyledString* string, Pseudolocalizer::Method method, StringPool* pool) { 30cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski Pseudolocalizer localizer(method); 31cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 32ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const StringPiece original_text = *string->value->str; 33cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 34cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski StyleString localized; 35cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 36cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Copy the spans. We will update their offsets when we localize. 37cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski localized.spans.reserve(string->value->spans.size()); 38cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski for (const StringPool::Span& span : string->value->spans) { 39ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski localized.spans.push_back( 40ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Span{*span.name, span.first_char, span.last_char}); 41cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 42cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 43cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // The ranges are all represented with a single value. This is the start of 44cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // one range and 45cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // end of another. 46cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski struct Range { 47cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski size_t start; 48cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 49cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Once the new string is localized, these are the pointers to the spans to 50cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // adjust. 51cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Since this struct represents the start of one range and end of another, 52cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // we have 53cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // the two pointers respectively. 54ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski uint32_t* update_start; 55ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski uint32_t* update_end; 56cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski }; 57cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 58cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski auto cmp = [](const Range& r, size_t index) -> bool { 59cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return r.start < index; 60cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski }; 61cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 62cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Construct the ranges. The ranges are represented like so: [0, 2, 5, 7] 63cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // The ranges are the spaces in between. In this example, with a total string 64cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // length of 9, 65cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // the vector represents: (0,1], (2,4], (5,6], (7,9] 66cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // 67cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::vector<Range> ranges; 68cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ranges.push_back(Range{0}); 69ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ranges.push_back(Range{original_text.size() - 1}); 70cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski for (size_t i = 0; i < string->value->spans.size(); i++) { 71cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski const StringPool::Span& span = string->value->spans[i]; 72cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 73cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Insert or update the Range marker for the start of this span. 74cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski auto iter = 75ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::lower_bound(ranges.begin(), ranges.end(), span.first_char, cmp); 76ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (iter != ranges.end() && iter->start == span.first_char) { 77ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski iter->update_start = &localized.spans[i].first_char; 78cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 79ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ranges.insert(iter, Range{span.first_char, &localized.spans[i].first_char, 80ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski nullptr}); 81393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski } 82393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski 83cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Insert or update the Range marker for the end of this span. 84ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski iter = std::lower_bound(ranges.begin(), ranges.end(), span.last_char, cmp); 85ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (iter != ranges.end() && iter->start == span.last_char) { 86ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski iter->update_end = &localized.spans[i].last_char; 87cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 88cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ranges.insert( 89ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski iter, Range{span.last_char, nullptr, &localized.spans[i].last_char}); 90393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski } 91cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 92393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski 93ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski localized.str += localizer.Start(); 94393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski 95cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Iterate over the ranges and localize each section. 96cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski for (size_t i = 0; i < ranges.size(); i++) { 97cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski const size_t start = ranges[i].start; 98ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski size_t len = original_text.size() - start; 99cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (i + 1 < ranges.size()) { 100cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski len = ranges[i + 1].start - start; 101cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 102393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski 103ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (ranges[i].update_start) { 104ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski *ranges[i].update_start = localized.str.size(); 105cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 106393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski 107ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (ranges[i].update_end) { 108ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski *ranges[i].update_end = localized.str.size(); 109393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski } 110393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski 111ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski localized.str += localizer.Text(original_text.substr(start, len)); 112cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 113cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 114ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski localized.str += localizer.End(); 115393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski 116ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::unique_ptr<StyledString> localized_string = 117ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski util::make_unique<StyledString>(pool->MakeRef(localized)); 118ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski localized_string->SetSource(string->GetSource()); 119ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return localized_string; 120393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski} 121393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski 122393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinskinamespace { 123393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski 124ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskiclass Visitor : public RawValueVisitor { 125ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski public: 126cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Either value or item will be populated upon visiting the value. 127ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::unique_ptr<Value> value; 128ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::unique_ptr<Item> item; 129cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 130cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski Visitor(StringPool* pool, Pseudolocalizer::Method method) 131ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski : pool_(pool), method_(method), localizer_(method) {} 132cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 133ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski void Visit(Plural* plural) override { 134cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::unique_ptr<Plural> localized = util::make_unique<Plural>(); 135cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski for (size_t i = 0; i < plural->values.size(); i++) { 136ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Visitor sub_visitor(pool_, method_); 137cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (plural->values[i]) { 138ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski plural->values[i]->Accept(&sub_visitor); 139ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (sub_visitor.value) { 140ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski localized->values[i] = std::move(sub_visitor.item); 141cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 142cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski localized->values[i] = 143ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::unique_ptr<Item>(plural->values[i]->Clone(pool_)); 144393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski } 145cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 146393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski } 147ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski localized->SetSource(plural->GetSource()); 148ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski localized->SetWeak(true); 149ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value = std::move(localized); 150cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 151cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 152ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski void Visit(String* string) override { 153cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::string result = 154ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski localizer_.Start() + localizer_.Text(*string->value) + localizer_.End(); 155cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::unique_ptr<String> localized = 156ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski util::make_unique<String>(pool_->MakeRef(result)); 157ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski localized->SetSource(string->GetSource()); 158ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski localized->SetWeak(true); 159ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski item = std::move(localized); 160cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 161cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 162ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski void Visit(StyledString* string) override { 163ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski item = PseudolocalizeStyledString(string, method_, pool_); 164ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski item->SetWeak(true); 165cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 166ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 167ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski private: 168ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski DISALLOW_COPY_AND_ASSIGN(Visitor); 169ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 170ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski StringPool* pool_; 171ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Pseudolocalizer::Method method_; 172ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski Pseudolocalizer localizer_; 173393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski}; 174393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski 175ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam LesinskiConfigDescription ModifyConfigForPseudoLocale(const ConfigDescription& base, 176393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski Pseudolocalizer::Method m) { 177cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ConfigDescription modified = base; 178cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski switch (m) { 179393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski case Pseudolocalizer::Method::kAccent: 180cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski modified.language[0] = 'e'; 181cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski modified.language[1] = 'n'; 182cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski modified.country[0] = 'X'; 183cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski modified.country[1] = 'A'; 184cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski break; 185393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski 186393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski case Pseudolocalizer::Method::kBidi: 187cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski modified.language[0] = 'a'; 188cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski modified.language[1] = 'r'; 189cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski modified.country[0] = 'X'; 190cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski modified.country[1] = 'B'; 191cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski break; 192393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski default: 193cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski break; 194cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 195cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return modified; 196393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski} 197393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski 198ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskivoid PseudolocalizeIfNeeded(const Pseudolocalizer::Method method, 199ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceConfigValue* original_value, 200cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski StringPool* pool, ResourceEntry* entry) { 201cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski Visitor visitor(pool, method); 202ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski original_value->value->Accept(&visitor); 203cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 204ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::unique_ptr<Value> localized_value; 205ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (visitor.value) { 206ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski localized_value = std::move(visitor.value); 207ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } else if (visitor.item) { 208ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski localized_value = std::move(visitor.item); 209cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 210cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 211ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!localized_value) { 212cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return; 213cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 214cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 215ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ConfigDescription config_with_accent = 216ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ModifyConfigForPseudoLocale(original_value->config, method); 217cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 218ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceConfigValue* new_config_value = 219ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski entry->FindOrCreateValue(config_with_accent, original_value->product); 220ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!new_config_value->value) { 221cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Only use auto-generated pseudo-localization if none is defined. 222ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski new_config_value->value = std::move(localized_value); 223cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 224393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski} 225393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski 226458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski/** 227cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski * A value is pseudolocalizable if it does not define a locale (or is the 228cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski * default locale) 229458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski * and is translateable. 230458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski */ 231ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistatic bool IsPseudolocalizable(ResourceConfigValue* config_value) { 232ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const int diff = 233ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski config_value->config.diff(ConfigDescription::DefaultConfig()); 234cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (diff & ConfigDescription::CONFIG_LOCALE) { 235cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 236cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 237ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return config_value->value->IsTranslateable(); 238458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski} 239458b877488c12ea4336d8fc00a95d9c0298bd6d0Adam Lesinski 240cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski} // namespace 241cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 242ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskibool PseudolocaleGenerator::Consume(IAaptContext* context, 243cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ResourceTable* table) { 244cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski for (auto& package : table->packages) { 245cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski for (auto& type : package->types) { 246cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski for (auto& entry : type->entries) { 247cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::vector<ResourceConfigValue*> values = 248ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski entry->FindValuesIf(IsPseudolocalizable); 249cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 250cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski for (ResourceConfigValue* value : values) { 251ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski PseudolocalizeIfNeeded(Pseudolocalizer::Method::kAccent, value, 252ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski &table->string_pool, entry.get()); 253ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski PseudolocalizeIfNeeded(Pseudolocalizer::Method::kBidi, value, 254ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski &table->string_pool, entry.get()); 255393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski } 256cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 257393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski } 258cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 259cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return true; 260393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski} 261393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski 262cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski} // namespace aapt 263