!135 支持可翻译特性

Merge pull request !135 from 张婷/master
This commit is contained in:
openharmony_ci
2024-02-28 09:26:59 +00:00
committed by Gitee
6 changed files with 244 additions and 15 deletions
+1
View File
@@ -44,6 +44,7 @@ ohos_executable("restool") {
"src/restool.cpp",
"src/select_compile_parse.cpp",
"src/task_handle.cpp",
"src/translatable_parser.cpp",
]
include_dirs = [
+2 -6
View File
@@ -33,7 +33,7 @@ protected:
private:
void InitParser();
bool ParseJsonArrayLevel(const cJSON *arrayNode, const FileInfo &fileInfo);
bool ParseJsonObjectLevel(const cJSON *objectNode, const FileInfo &fileInfo);
bool ParseJsonObjectLevel(cJSON *objectNode, const FileInfo &fileInfo);
using HandleResource = std::function<bool(const cJSON *, ResourceItem&)>;
bool HandleString(const cJSON *objectNode, ResourceItem &resourceItem) const;
@@ -62,11 +62,7 @@ private:
bool CheckPluralValue(const cJSON *arrayItem, const ResourceItem &resourceItem) const;
bool CheckColorValue(const char *s) const;
std::map<ResType, HandleResource> handles_;
static const std::string TAG_NAME;
static const std::string TAG_VALUE;
static const std::string TAG_PARENT;
static const std::string TAG_QUANTITY;
static const std::vector<std::string> QUANTITY_ATTRS;
bool isBaseString_;
cJSON *root_;
};
}
+1 -1
View File
@@ -39,7 +39,7 @@ const static std::string NEW_LINE_PATH = "\nat ";
const static std::string LONG_PATH_HEAD = "\\\\?\\";
const static int32_t VERSION_MAX_LEN = 128;
const static int32_t INT_TO_BYTES = sizeof(uint32_t);
static const int8_t RESTOOL_VERSION[VERSION_MAX_LEN] = { "Restool 5.001" };
static const int8_t RESTOOL_VERSION[VERSION_MAX_LEN] = { "Restool 5.002" };
const static int32_t TAG_LEN = 4;
enum class KeyType {
+40
View File
@@ -0,0 +1,40 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef OHOS_TRANSLATABLE_H
#define OHOS_TRANSLATABLE_H
#include <cJSON.h>
#include "resource_data.h"
namespace OHOS {
namespace Global {
namespace Restool {
class TranslatableParse {
public:
static bool ParseTranslatable(cJSON *objectNode, const FileInfo &fileInfo, const std::string &name);
private:
static bool ParseTranslatable(cJSON *objectNode, const std::string &filePath);
static bool CheckBaseStringAttr(const cJSON *objectNode);
static bool CheckBaseStringTranslatable(const cJSON *attrNode);
static bool CheckBaseStringPriority(const cJSON *attrNode);
static bool ReplaceTranslateTags(cJSON *node, const char *key);
static bool GetReplaceStringTranslate(std::string &str);
static bool FindTranslatePairs(const std::string &str, std::vector<size_t> &posData);
};
}
}
}
#endif
+14 -8
View File
@@ -18,19 +18,21 @@
#include <limits>
#include <regex>
#include "restool_errors.h"
#include "translatable_parser.h"
namespace OHOS {
namespace Global {
namespace Restool {
using namespace std;
const string JsonCompiler::TAG_NAME = "name";
const string JsonCompiler::TAG_VALUE = "value";
const string JsonCompiler::TAG_PARENT = "parent";
const string JsonCompiler::TAG_QUANTITY = "quantity";
const vector<string> JsonCompiler::QUANTITY_ATTRS = { "zero", "one", "two", "few", "many", "other" };
const string TAG_NAME = "name";
const string TAG_VALUE = "value";
const string TAG_PARENT = "parent";
const string TAG_QUANTITY = "quantity";
const vector<string> QUANTITY_ATTRS = { "zero", "one", "two", "few", "many", "other" };
const vector<string> TRANSLATION_TYPE = { "string", "strarray", "plural" };
JsonCompiler::JsonCompiler(ResType type, const string &output)
: IResourceCompiler(type, output), root_(nullptr)
: IResourceCompiler(type, output), isBaseString_(false), root_(nullptr)
{
InitParser();
}
@@ -72,7 +74,8 @@ uint32_t JsonCompiler::CompileSingleFile(const FileInfo &fileInfo)
cerr << NEW_LINE_PATH << fileInfo.filePath << endl;
return RESTOOL_ERROR;
}
isBaseString_ = (fileInfo.limitKey == "base" &&
find(TRANSLATION_TYPE.begin(), TRANSLATION_TYPE.end(), tag) != TRANSLATION_TYPE.end());
FileInfo copy = fileInfo;
copy.fileType = ret->second;
if (!ParseJsonArrayLevel(item, copy)) {
@@ -125,7 +128,7 @@ bool JsonCompiler::ParseJsonArrayLevel(const cJSON *arrayNode, const FileInfo &f
return true;
}
bool JsonCompiler::ParseJsonObjectLevel(const cJSON *objectNode, const FileInfo &fileInfo)
bool JsonCompiler::ParseJsonObjectLevel(cJSON *objectNode, const FileInfo &fileInfo)
{
cJSON *nameNode = cJSON_GetObjectItem(objectNode, TAG_NAME.c_str());
if (!nameNode) {
@@ -138,6 +141,9 @@ bool JsonCompiler::ParseJsonObjectLevel(const cJSON *objectNode, const FileInfo
return false;
}
if (isBaseString_ && !TranslatableParse::ParseTranslatable(objectNode, fileInfo, nameNode->valuestring)) {
return false;
}
ResourceItem resourceItem(nameNode->valuestring, fileInfo.keyParams, fileInfo.fileType);
resourceItem.SetFilePath(fileInfo.filePath);
resourceItem.SetLimitKey(fileInfo.limitKey);
+186
View File
@@ -0,0 +1,186 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "translatable_parser.h"
#include <algorithm>
#include <iostream>
#include "resource_util.h"
namespace OHOS {
namespace Global {
namespace Restool {
using namespace std;
const string TAG_VALUE = "value";
const string TAG_ATTR = "attr";
const string TAG_TRANSLATABLE = "translatable";
const string TAG_PRIORITY = "priority";
const string NO_TRANSLATE_START = "{noTranslateStart}";
const string NO_TRANSLATE_END = "{noTranslateEnd}";
const vector<string> PRIORITY_ATTRS = { "code", "translate", "LT", "customer" };
bool TranslatableParse::ParseTranslatable(cJSON *objectNode, const FileInfo &fileInfo, const string &name)
{
if (fileInfo.fileType == ResType::STRING) {
return ParseTranslatable(objectNode, fileInfo.filePath);
}
cJSON *arrayNode = cJSON_GetObjectItem(objectNode, TAG_VALUE.c_str());
if (!arrayNode || !cJSON_IsArray(arrayNode)) {
cerr << "Error: '" << name << "' value not array.";
cerr << NEW_LINE_PATH << fileInfo.filePath << endl;
return false;
}
if (cJSON_GetArraySize(arrayNode) == 0) {
cerr << "Error: '" << name << "' value empty.";
cerr << NEW_LINE_PATH << fileInfo.filePath << endl;
return false;
}
int32_t index = -1;
for (cJSON *item = arrayNode->child; item; item = item->next) {
index++;
if (!item || !cJSON_IsObject(item)) {
cerr << "Error: '" << name << "' value the seq=" << index << " item must be object.";
cerr << NEW_LINE_PATH << fileInfo.filePath << endl;
return false;
}
if (!ParseTranslatable(item, fileInfo.filePath)) {
return false;
}
}
return true;
}
bool TranslatableParse::ParseTranslatable(cJSON *objectNode, const string &filePath)
{
if (!CheckBaseStringAttr(objectNode)) {
cerr << NEW_LINE_PATH << filePath << endl;
return false;
}
if (!ReplaceTranslateTags(objectNode, TAG_VALUE.c_str())) {
cerr << NEW_LINE_PATH << filePath << endl;
return false;
}
return true;
}
bool TranslatableParse::CheckBaseStringAttr(const cJSON *objectNode)
{
cJSON *attrNode = cJSON_GetObjectItem(objectNode, TAG_ATTR.c_str());
if (!attrNode) {
return true;
}
if (!cJSON_IsObject(attrNode)) {
cerr << "Error: attr node not obeject.";
return false;
}
return CheckBaseStringTranslatable(attrNode);
}
bool TranslatableParse::CheckBaseStringTranslatable(const cJSON *attrNode)
{
cJSON *translatableNode = cJSON_GetObjectItem(attrNode, TAG_TRANSLATABLE.c_str());
if (!translatableNode) {
return CheckBaseStringPriority(attrNode);
}
if (!cJSON_IsBool(translatableNode)) {
cerr << "Error: invalid value for '" << TAG_TRANSLATABLE << "'. Must be a boolean.";
return false;
}
return CheckBaseStringPriority(attrNode);
}
bool TranslatableParse::CheckBaseStringPriority(const cJSON *attrNode)
{
cJSON *priorityNode = cJSON_GetObjectItem(attrNode, TAG_PRIORITY.c_str());
if (!priorityNode) {
return true;
}
if (!cJSON_IsString(priorityNode)) {
cerr << "Error: invalid value for '" << TAG_PRIORITY << "'. Must be a string.";
return false;
}
string priorityValue = priorityNode->valuestring;
if (find(PRIORITY_ATTRS.begin(), PRIORITY_ATTRS.end(), priorityValue) == PRIORITY_ATTRS.end()) {
string message("[ ");
for (auto &value : PRIORITY_ATTRS) {
message.append("'" + value + "' ");
}
message.append("]");
cerr << "Error: invalid value for '" << TAG_PRIORITY << "'. Must in " << message;
return false;
}
return true;
}
bool TranslatableParse::ReplaceTranslateTags(cJSON *node, const char *key)
{
cJSON *valueNode = cJSON_GetObjectItem(node, TAG_VALUE.c_str());
if (!valueNode || !cJSON_IsString(valueNode)) {
cerr << "Error: value not string.";
return false;
}
string value = valueNode->valuestring;
if (GetReplaceStringTranslate(value)) {
return cJSON_ReplaceItemInObject(node, key, cJSON_CreateString(value.c_str()));
}
return true;
}
bool TranslatableParse::GetReplaceStringTranslate(string &str)
{
vector<size_t> posData;
if (!FindTranslatePairs(str, posData) || posData.empty()) {
return false;
}
size_t startIndex = 0;
size_t endIndex = 0;
string tmp;
for (size_t index = 0; index < posData.size(); index++) {
endIndex = posData[index];
tmp.append(str, startIndex, endIndex - startIndex);
startIndex = posData[++index];
}
str = tmp.append(str, posData.back());
return true;
}
bool TranslatableParse::FindTranslatePairs(const string &str, vector<size_t> &posData)
{
auto startPos = str.find(NO_TRANSLATE_START, 0);
auto endPos = str.find(NO_TRANSLATE_END, 0);
auto startLength = NO_TRANSLATE_START.length();
auto endLength = NO_TRANSLATE_END.length();
while (!(startPos == string::npos && endPos == string::npos)) {
if (startPos == string::npos || endPos == string::npos) {
return false;
}
if (startPos >= endPos || (!posData.empty() && posData.back() >= startPos)) {
return false;
}
posData.emplace_back(startPos);
posData.emplace_back(startPos + startLength);
posData.emplace_back(endPos);
posData.emplace_back(endPos + endLength);
startPos = str.find(NO_TRANSLATE_START, startPos + startLength);
endPos = str.find(NO_TRANSLATE_END, endPos + endLength);
}
return true;
}
}
}
}