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