mirror of
https://github.com/openharmony/developtools_global_resource_tool.git
synced 2026-07-19 19:33:46 -04:00
@@ -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 = [
|
||||
|
||||
@@ -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_;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Executable
+40
@@ -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
@@ -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);
|
||||
|
||||
Executable
+186
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user