FlightGear next
TranslationResource.cxx
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2025 Florent Rougon
2// SPDX-License-Identifier: GPL-2.0-or-later
3
8
9#include <cassert>
10#include <cstddef>
11#include <memory>
12#include <string>
13#include <utility>
14#include <vector>
15
16#include <simgear/debug/logstream.hxx>
17#include <simgear/nasal/cppbind/Ghost.hxx>
18
20#include "TranslationUnit.hxx"
21
22using std::string;
23using std::vector;
24
26 : _name(std::move(name))
27{ }
28
30 std::string sourceText,
31 bool hasPlural)
32{
33 _map.emplace(KeyType(std::move(name), index),
34 new TranslationUnit(std::move(sourceText), {}, hasPlural));
35}
36
38 std::string name, int index, std::string targetText)
39{
40 const auto key = std::make_pair(std::move(name), index);
41 const auto translationUnit = _map[key];
42
43 // If the smart pointer is empty, it means addTranslationUnit() wasn't
44 // called for this string, therefore it isn't in the default translation.
45 // It's an obsolete string from the XLIFF file being loaded → ignore it.
46 if (translationUnit) {
47 // Set the first plural form
48 translationUnit->setTargetText(0, std::move(targetText));
49 }
50}
51
53 std::string name, int index, std::vector<std::string> targetTexts)
54{
55 const auto key = std::make_pair(std::move(name), index);
56 const auto translationUnit = _map[key];
57
58 // Set the target texts only if this is not an obsolete string (see above)
59 if (translationUnit) {
60 translationUnit->setTargetTexts(std::move(targetTexts));
61 }
62}
63
64TranslationResource::TranslationUnitRef
65TranslationResource::translationUnit(const std::string& name, int index) const
66{
67 auto it = _map.find(std::make_pair(name, index));
68 if (it != _map.end()) {
69 return it->second;
70 }
71
72 return {};
73}
74
75string TranslationResource::get(const string& basicId, int index) const
76{
77 const auto translUnit = translationUnit(basicId, index);
78
79 if (!translUnit) {
80 return {};
81 }
82
83 if (translUnit->getPluralStatus()) {
84 SG_LOG(SG_GENERAL, SG_DEV_ALERT,
85 "TranslationResource::get() or "
86 "TranslationResource::getWithDefault() used on translatable "
87 "string '" << _name << "/" << basicId << ":" << index <<
88 "' defined with has-plural=\"true\" in the default translation. "
89 "Use TranslationResource::getPlural() or "
90 "TranslationResource::getPluralWithDefault() instead.");
91 return translUnit->getSourceText();
92 } else {
93 return translUnit->getTranslation();
94 }
95}
96
98 const string& basicId, int index) const
99{
100 const auto translUnit = translationUnit(basicId, index);
101
102 if (!translUnit) {
103 return {};
104 }
105
106 if (!translUnit->getPluralStatus()) {
107 SG_LOG(SG_GENERAL, SG_DEV_ALERT,
108 "TranslationResource::getPlural() or "
109 "TranslationResource::getPluralWithDefault() used on "
110 "translatable string '" << _name << "/" << basicId << ":" <<
111 index << "' that isn't defined with has-plural=\"true\" in the "
112 "default translation. Use TranslationResource::get() or "
113 "TranslationResource::getWithDefault() instead.");
114 return translUnit->getSourceText();
115 } else {
116 return translUnit->getTranslation(cardinalNumber);
117 }
118
119 return {};
120}
121
123 const string& basicId, const string& defaultValue, int index) const
124{
125 const string result = get(basicId, index);
126
127 return result.empty() ? defaultValue : result;
128}
129
131 intType cardinalNumber, const string& basicId, const string& defaultValue,
132 int index) const
133{
134 const string result = getPlural(cardinalNumber, basicId, index);
135
136 return result.empty() ? defaultValue : result;
137}
138
139vector<string> TranslationResource::getAll(const string& name) const
140{
141 vector<string> result;
142 decltype(_map)::const_iterator it;
143
144 for (int index = 0;
145 (it = _map.find(std::make_pair(name, index))) != _map.end();
146 index++) {
147 const auto& transUnit = it->second;
148 // Plural form indices all hardcoded to 0
149 const string targetText = transUnit->getTargetText(0);
150 result.push_back(
151 targetText.empty() ? transUnit->getSourceText() : targetText);
152 }
153
154 return result;
155}
156
157std::size_t TranslationResource::getCount(const string& name) const
158{
159 std::size_t index = 0;
160
161 while (_map.find(std::make_pair(name, index)) != _map.end()) {
162 index++;
163 }
164
165 return index;
166}
167
168static naRef f_get(const TranslationResource& tr, const nasal::CallContext& ctx)
169{
170 if (ctx.argc < 1 || ctx.argc > 2) {
171 ctx.runtimeError("TranslationResource.get(basicId[, index])");
172 }
173
174 const auto basicId = ctx.requireArg<std::string>(0);
175 const auto index = ctx.getArg<int>(1); // the index defaults to 0
176
177 return ctx.to_nasal(tr.get(std::move(basicId), index));
178}
179
180static naRef f_getPlural(const TranslationResource& tr, const nasal::CallContext& ctx)
181{
182 if (ctx.argc < 2 || ctx.argc > 3) {
183 ctx.runtimeError(
184 "TranslationResource.getPlural(cardinalNumber, basicId[, index])");
185 }
186
187 const auto cardinalNumber = ctx.requireArg<TranslationResource::intType>(0);
188 const auto basicId = ctx.requireArg<std::string>(1);
189 const auto index = ctx.getArg<int>(2); // the index defaults to 0
190
191 return ctx.to_nasal(tr.getPlural(cardinalNumber, std::move(basicId),
192 index));
193}
194
196 const nasal::CallContext& ctx)
197{
198 if (ctx.argc < 2 || ctx.argc > 3) {
199 ctx.runtimeError("TranslationResource.getWithDefault(basicId, "
200 "defaultValue[, index])");
201 }
202
203 const auto basicId = ctx.requireArg<std::string>(0);
204 const auto defaultValue = ctx.requireArg<std::string>(1);
205 const auto index = ctx.getArg<int>(2); // the index defaults to 0
206
207 return ctx.to_nasal(
208 tr.getWithDefault(std::move(basicId), std::move(defaultValue), index));
209}
210
212 const nasal::CallContext& ctx)
213{
214 if (ctx.argc < 3 || ctx.argc > 4) {
215 ctx.runtimeError(
216 "TranslationResource.getPluralWithDefault(cardinalNumber, "
217 "basicId, defaultValue[, index])");
218 }
219
220 const auto cardinalNumber = ctx.requireArg<TranslationResource::intType>(0);
221 const auto basicId = ctx.requireArg<std::string>(1);
222 const auto defaultValue = ctx.requireArg<std::string>(2);
223 const auto index = ctx.getArg<int>(3); // the index defaults to 0
224
225 return ctx.to_nasal(
226 tr.getPluralWithDefault(cardinalNumber, std::move(basicId),
227 std::move(defaultValue), index));
228}
229
231 const nasal::CallContext& ctx)
232{
233 if (ctx.argc < 1 || ctx.argc > 2) {
234 ctx.runtimeError(
235 "TranslationResource.translationUnit(basicId[, index])");
236 }
237
238 const auto basicId = ctx.requireArg<std::string>(0);
239 const auto index = ctx.getArg<int>(1); // the index defaults to 0
240
241 return ctx.to_nasal(
242 tr.translationUnit(std::move(basicId), index));
243}
244
245// Static member function
247{
248 using TranslationResourceRef = std::shared_ptr<TranslationResource>;
249 using NasalTranslationResource = nasal::Ghost<TranslationResourceRef>;
250
251 NasalTranslationResource::init("TranslationResource")
252 .method("get", &f_get)
253 .method("getPlural", &f_getPlural)
254 .method("getWithDefault", &f_getWithDefault)
255 .method("getPluralWithDefault", &f_getPluralWithDefault)
256 .method("getAll", &TranslationResource::getAll)
257 .method("getCount", &TranslationResource::getCount)
258 .method("translationUnit", &f_translationUnit);
259}
static naRef f_getPlural(const FGTranslate &tr, const nasal::CallContext &ctx)
static naRef f_getWithDefault(const FGTranslate &tr, const nasal::CallContext &ctx)
static naRef f_translationUnit(const FGTranslate &tr, const nasal::CallContext &ctx)
static naRef f_getPluralWithDefault(const FGTranslate &tr, const nasal::CallContext &ctx)
static naRef f_get(const FGTranslate &tr, const nasal::CallContext &ctx)
static naRef f_getPluralWithDefault(const TranslationResource &tr, const nasal::CallContext &ctx)
static naRef f_translationUnit(const TranslationResource &tr, const nasal::CallContext &ctx)
static naRef f_getWithDefault(const TranslationResource &tr, const nasal::CallContext &ctx)
static naRef f_getPlural(const TranslationResource &tr, const nasal::CallContext &ctx)
static naRef f_get(const TranslationResource &tr, const nasal::CallContext &ctx)
Container class for related translation units.
Container class for a string and its translation.
Class that holds translation units within a resource (“context”)
flightgear::LanguageInfo::intType intType
std::shared_ptr< TranslationUnit > translationUnit(const std::string &name, int index=0) const
Return a shared pointer to a TranslationUnit.
TranslationResource()=delete
std::string getWithDefault(const std::string &basicId, const std::string &defaultValue, int index=0) const
Get a single translation, with default for missing or empty strings.
static void setupGhost()
Set up a Nasal type that wraps TranslationResource.
std::vector< std::string > getAll(const std::string &name) const
Get translations for all strings with a given element name.
void setFirstTargetText(std::string name, int index, std::string targetText)
Set the first target text of a translation unit.
void setTargetTexts(std::string name, int index, std::vector< std::string > targetTexts)
Set all target texts of a translation unit.
std::string getPlural(intType cardinalNumber, const std::string &basicId, int index=0) const
Same as get(), but for a string that has plural forms.
std::string getPluralWithDefault(intType cardinalNumber, const std::string &basicId, const std::string &defaultValue, int index=0) const
Same as getWithDefault(), but for a string that has plural forms.
std::string get(const std::string &basicId, int index=0) const
Get a single translation.
void addTranslationUnit(std::string name, int index, std::string sourceText, bool hasPlural=false)
Add a translation unit to the TranslationResource.
std::size_t getCount(const std::string &name) const
Get the number of translated strings with the given element name.
Class holding a source string and its translation in a language.
const char * name