Skip to content

Commit fe6f1c3

Browse files
committed
feat: shoudTranslate
1 parent 3efac40 commit fe6f1c3

2 files changed

Lines changed: 104 additions & 1 deletion

File tree

packages/cli/src/cli/loaders/index.spec.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,79 @@ user.password=Contraseña
10661066
expect(spaceIdx).toBeLessThan(stringKeys.indexOf("apple"));
10671067
}
10681068
});
1069+
1070+
it("should respect shouldTranslate: false flag", async () => {
1071+
setupFileMocks();
1072+
1073+
// Create input with a key that has shouldTranslate: false
1074+
const input = `{
1075+
"sourceLanguage": "en",
1076+
"strings": {
1077+
"do_not_translate": {
1078+
"shouldTranslate": false,
1079+
"localizations": {
1080+
"en": {
1081+
"stringUnit": {
1082+
"state": "translated",
1083+
"value": "This should not be translated"
1084+
}
1085+
}
1086+
}
1087+
},
1088+
"normal_key": {
1089+
"extractionState": "manual",
1090+
"localizations": {
1091+
"en": {
1092+
"stringUnit": {
1093+
"state": "translated",
1094+
"value": "This should be translated"
1095+
}
1096+
}
1097+
}
1098+
}
1099+
}
1100+
}`;
1101+
1102+
mockFileOperations(input);
1103+
1104+
const xcodeXcstringsLoader = createBucketLoader("xcode-xcstrings", "i18n/[locale].xcstrings", { isCacheRestore: false, defaultLocale: "en" });
1105+
xcodeXcstringsLoader.setDefaultLocale("en");
1106+
1107+
// Pull data and verify that the shouldTranslate: false entry is skipped
1108+
const data = await xcodeXcstringsLoader.pull("en");
1109+
1110+
expect(data).toHaveProperty("normal_key", "This should be translated");
1111+
expect(data).not.toHaveProperty("do_not_translate");
1112+
1113+
// Now push a translation for the normal key
1114+
const payload = {
1115+
"normal_key": "Ceci devrait être traduit"
1116+
};
1117+
1118+
await xcodeXcstringsLoader.push("fr", payload);
1119+
1120+
expect(fs.writeFile).toHaveBeenCalled();
1121+
const writeFileCall = (fs.writeFile as any).mock.calls[0];
1122+
const writtenContent = JSON.parse(writeFileCall[1]);
1123+
1124+
// Verify that the normal key was translated
1125+
expect(writtenContent.strings.normal_key.localizations.fr.stringUnit.value).toBe("Ceci devrait être traduit");
1126+
1127+
// Verify that the do_not_translate key was preserved with its shouldTranslate: false flag
1128+
expect(writtenContent.strings.do_not_translate).toHaveProperty("shouldTranslate", false);
1129+
1130+
// Check that the do_not_translate key has no localizations for the target language
1131+
expect(writtenContent.strings.do_not_translate.localizations).not.toHaveProperty("fr");
1132+
1133+
// Now also test pushing with empty {} content to verify the flag is still preserved
1134+
await xcodeXcstringsLoader.push("fr", {});
1135+
1136+
const secondWriteFileCall = (fs.writeFile as any).mock.calls[1];
1137+
const secondWrittenContent = JSON.parse(secondWriteFileCall[1]);
1138+
1139+
// Verify the flag is still there
1140+
expect(secondWrittenContent.strings.do_not_translate).toHaveProperty("shouldTranslate", false);
1141+
});
10691142
});
10701143

10711144
describe("yaml bucket loader", () => {

packages/cli/src/cli/loaders/xcode-xcstrings.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ export default function createXcodeXcstringsLoader(defaultLocale: string): ILoad
1010

1111
for (const [translationKey, _translationEntity] of Object.entries((input as any).strings)) {
1212
const rootTranslationEntity = _translationEntity as any;
13+
14+
// Skip translation keys marked with shouldTranslate: false
15+
if (rootTranslationEntity.shouldTranslate === false) {
16+
continue;
17+
}
18+
1319
const langTranslationEntity = rootTranslationEntity?.localizations?.[locale];
1420

1521
if (langTranslationEntity) {
@@ -42,8 +48,22 @@ export default function createXcodeXcstringsLoader(defaultLocale: string): ILoad
4248
async push(locale, payload, originalInput) {
4349
const langDataToMerge: any = {};
4450
langDataToMerge.strings = {};
45-
51+
52+
// Copy original input if it exists, or create a new structure
53+
const input = _.cloneDeep(originalInput) || { sourceLanguage: locale, strings: {} };
54+
4655
for (const [key, value] of Object.entries(payload)) {
56+
// Skip keys with null or undefined values
57+
if (value === null || value === undefined) {
58+
continue;
59+
}
60+
61+
// Check if this key has shouldTranslate: false in the original input
62+
const hasDoNotTranslateFlag = originalInput &&
63+
(originalInput as any).strings &&
64+
(originalInput as any).strings[key] &&
65+
(originalInput as any).strings[key].shouldTranslate === false;
66+
4767
if (typeof value === "string") {
4868
langDataToMerge.strings[key] = {
4969
extractionState: "manual",
@@ -56,6 +76,11 @@ export default function createXcodeXcstringsLoader(defaultLocale: string): ILoad
5676
},
5777
},
5878
};
79+
80+
// Preserve shouldTranslate flag if it exists in the original input
81+
if (hasDoNotTranslateFlag) {
82+
langDataToMerge.strings[key].shouldTranslate = false;
83+
}
5984
} else {
6085
const updatedVariations: any = {};
6186

@@ -78,6 +103,11 @@ export default function createXcodeXcstringsLoader(defaultLocale: string): ILoad
78103
},
79104
},
80105
};
106+
107+
// Preserve shouldTranslate flag if it exists in the original input
108+
if (hasDoNotTranslateFlag) {
109+
langDataToMerge.strings[key].shouldTranslate = false;
110+
}
81111
}
82112
}
83113

0 commit comments

Comments
 (0)