Skip to content

Commit

Permalink
feat: directory parameter for pre-translate command
Browse files Browse the repository at this point in the history
  • Loading branch information
katerina20 committed Jun 14, 2024
1 parent 19d2654 commit 1f52223
Show file tree
Hide file tree
Showing 9 changed files with 239 additions and 20 deletions.
2 changes: 1 addition & 1 deletion src/main/java/com/crowdin/cli/commands/Actions.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ NewAction<ProjectProperties, ClientTask> taskAdd(
NewAction<NoProperties, NoClient> checkNewVersion();

NewAction<PropertiesWithFiles, ProjectClient> preTranslate(
List<String> languageIds, List<String> files, Method method, Long engineId, String branchName, AutoApproveOption autoApproveOption, Boolean duplicateTranslations,
List<String> languageIds, List<String> files, Method method, Long engineId, String branchName, String directory, AutoApproveOption autoApproveOption, Boolean duplicateTranslations,
Boolean translateUntranslatedOnly, Boolean translateWithPerfectMatchOnly, boolean noProgress, boolean plainView, List<String> labelNames, Long aiPrompt);

NewAction<ProjectProperties, ProjectClient> branchAdd(String name, String title, String exportPattern, Priority priority, boolean plainView);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,10 +222,10 @@ public NewAction<NoProperties, NoClient> checkNewVersion() {

@Override
public NewAction<PropertiesWithFiles, ProjectClient> preTranslate(
List<String> languageIds, List<String> files, Method method, Long engineId, String branchName, AutoApproveOption autoApproveOption, Boolean duplicateTranslations,
Boolean translateUntranslatedOnly, Boolean translateWithPerfectMatchOnly, boolean noProgress, boolean plainView, List<String> labelNames, Long aiPrompt
List<String> languageIds, List<String> files, Method method, Long engineId, String branchName, String directory, AutoApproveOption autoApproveOption,
Boolean duplicateTranslations, Boolean translateUntranslatedOnly, Boolean translateWithPerfectMatchOnly, boolean noProgress, boolean plainView, List<String> labelNames, Long aiPrompt
) {
return new PreTranslateAction(languageIds, files, method, engineId, branchName, autoApproveOption, duplicateTranslations,
return new PreTranslateAction(languageIds, files, method, engineId, branchName, directory, autoApproveOption, duplicateTranslations,
translateUntranslatedOnly, translateWithPerfectMatchOnly, noProgress, plainView, labelNames, aiPrompt);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.crowdin.client.sourcefiles.model.FileInfo;
import com.crowdin.client.translations.model.*;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.stream.Collectors;
Expand All @@ -33,6 +34,7 @@ class PreTranslateAction implements NewAction<PropertiesWithFiles, ProjectClient
private final Method method;
private final Long engineId;
private final String branchName;
private final String directory;
private final AutoApproveOption autoApproveOption;
private final Boolean duplicateTranslations;
private final Boolean translateUntranslatedOnly;
Expand All @@ -52,7 +54,7 @@ public void act(Outputter out, PropertiesWithFiles properties, ProjectClient cli
List<Long> labelIds = this.prepareLabelIds(out, client);

if (isStringsBasedProject) {
if (files != null && !files.isEmpty()) {
if ((files != null && !files.isEmpty()) || directory != null) {
throw new ExitCodeExceptionMapper.ValidationException(RESOURCE_BUNDLE.getString("message.no_file_string_project"));
}
Branch branch = project.findBranchByName(branchName)
Expand All @@ -64,8 +66,8 @@ public void act(Outputter out, PropertiesWithFiles properties, ProjectClient cli
return;
}

if (files == null || files.isEmpty()) {
throw new ExitCodeExceptionMapper.ValidationException(RESOURCE_BUNDLE.getString("error.file_required"));
if ((files == null || files.isEmpty()) && StringUtils.isEmpty(directory)) {
throw new ExitCodeExceptionMapper.ValidationException(RESOURCE_BUNDLE.getString("error.file_or_directory_required"));
}

Optional<Branch> branch = Optional.ofNullable(branchName).flatMap(project::findBranchByName);
Expand All @@ -75,26 +77,36 @@ public void act(Outputter out, PropertiesWithFiles properties, ProjectClient cli
}

List<FileInfo> fileInfos = project
.getFileInfos()
.stream().filter(f -> !branch.isPresent() || branch.get().getId().equals(f.getBranchId()))
.collect(Collectors.toList());
.getFileInfos()
.stream()
.filter(f -> (branch.isEmpty() && f.getBranchId() == null)
|| (branch.isPresent() && branch.get().getId().equals(f.getBranchId())))
.collect(Collectors.toList());
Map<String, FileInfo> paths = ProjectFilesUtils.buildFilePaths(project.getDirectories(), fileInfos);
boolean containsError = false;

List<Long> fileIds = new ArrayList<>();

for (String file : files) {
if (!paths.containsKey(file)) {
if (files.size() > 1) {
containsError = true;
out.println(WARNING.withIcon(String.format(RESOURCE_BUNDLE.getString("error.file_not_exists"), file)));
continue;
} else {
throw new ExitCodeExceptionMapper.NotFoundException(String.format(RESOURCE_BUNDLE.getString("error.file_not_exists"), file));
if ((files != null && !files.isEmpty())) {
for (String file : files) {
if (!paths.containsKey(file)) {
if (files.size() > 1) {
containsError = true;
out.println(WARNING.withIcon(String.format(RESOURCE_BUNDLE.getString("error.file_not_exists"), file)));
continue;
} else {
throw new ExitCodeExceptionMapper.NotFoundException(String.format(RESOURCE_BUNDLE.getString("error.file_not_exists"), file));
}
}
Long fileId = paths.get(file).getId();
fileIds.add(fileId);
}
} else if (!StringUtils.isEmpty(directory)) {
for (Map.Entry<String, FileInfo> entry : paths.entrySet()) {
if (entry.getKey().startsWith(directory)) {
fileIds.add(entry.getValue().getId());
}
}
Long fileId = paths.get(file).getId();
fileIds.add(fileId);
}

if (fileIds.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ public class PreTranslateSubcommand extends ActCommandWithFiles {
@CommandLine.Option(names = {"-b", "--branch"}, paramLabel = "...", descriptionKey = "branch", order = -2)
protected String branch;

@CommandLine.Option(names = {"--directory"}, paramLabel = "...", order = -2, descriptionKey = "crowdin.pre-translate.directory-path")
protected String directory;

@CommandLine.Option(names = {"--auto-approve-option"}, descriptionKey = "crowdin.pre-translate.auto-approve-option", paramLabel = "...", order = -2)
protected String autoApproveOption;

Expand Down Expand Up @@ -80,6 +83,7 @@ protected NewAction<PropertiesWithFiles, ProjectClient> getAction(Actions action
method,
engineId,
branch,
directory,
autoApproveOptionWrapper.get(autoApproveOption),
duplicateTranslations,
translateUntranslatedOnly,
Expand All @@ -94,6 +98,9 @@ protected NewAction<PropertiesWithFiles, ProjectClient> getAction(Actions action
@Override
protected List<String> checkOptions() {
List<String> errors = new ArrayList<>();
if (directory != null && files != null && !files.isEmpty()) {
errors.add(RESOURCE_BUNDLE.getString("error.pre_translate.directory_or_file_only"));
}
if ((Method.MT == method) && (engineId == null)) {
errors.add(RESOURCE_BUNDLE.getString("error.pre_translate.engine_id"));
}
Expand Down Expand Up @@ -122,6 +129,9 @@ protected List<String> checkOptions() {
files.set(i, normalizedFile);
}
}
if (directory != null) {
directory = StringUtils.removeStart(Utils.normalizePath(directory), Utils.PATH_SEPARATOR);
}
return errors;
}
}
3 changes: 3 additions & 0 deletions src/main/resources/messages/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ crowdin.pre-translate.file=Path to the file in the Crowdin project. Can be speci
crowdin.pre-translate.method=Defines pre-translation method. Supported values: mt, tm, ai
crowdin.pre-translate.engine-id=Machine Translation engine Identifier
crowdin.pre-translate.ai-prompt=AI Prompt Identifier. Required for 'ai' method
crowdin.pre-translate.directory-path=Path to the directory in Crowdin
crowdin.pre-translate.auto-approve-option=Defines which translations added by TM pre-translation should be auto-approved. Supported values: all, except-auto-substituted, perfect-match-only. Default: none
crowdin.pre-translate.duplicate-translations=Adds translations even if the same translation already exists
crowdin.pre-translate.translate-untranslated-only=Applies pre-translation for untranslated strings only
Expand Down Expand Up @@ -496,6 +497,7 @@ error.while_checking_base_path=Failed to check the base path. Try to run the app
error.skip_untranslated_both_strings_and_files=You cannot skip strings and files at the same time. Please use one of these parameters instead.
error.file_not_exists=Project doesn't contain the '%s' file
error.file_required=The '--file' parameter is required for this type of project
error.file_or_directory_required=The '--file' or '--directory' parameter is required
error.dir_not_exists=Project doesn't contain the '%s' directory
error.branch_not_exists=Project doesn't contain the '%s' branch
error.source_string_no_edit=Specify some parameters to edit the string
Expand Down Expand Up @@ -564,6 +566,7 @@ error.distribution.empty_bundle_ids=The '--bundle-id' value can not be empty for
error.distribution.incorrect_file_command_usage=The '--file' is used only for the 'default' export mode
error.distribution.incorrect_bundle_id_command_usage=The '--bundle-id' is used only for the 'bundle' export mode

error.pre_translate.directory_or_file_only=Either "--file" or "--directory" can be specified
error.pre_translate.engine_id=Machine Translation should be used with the '--engine-id' parameter
error.pre_translate.ai_prompt=AI should be used with the '--ai-prompt' parameter
error.pre_translate.duplicate_translations='--duplicate-translations' only works with the TM pre-translation method
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,11 @@ public void testCheckNewVersion() {
assertNotNull(actions.checkNewVersion());
}

@Test
void testPreTranslate() {
assertNotNull(actions.preTranslate(null, null, null, null, null, null, null, null, null, null,false, false, null, null));
}

@Test
void testScreenshotList() {
assertNotNull(actions.screenshotList(null, false));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package com.crowdin.cli.commands.actions;

import com.crowdin.cli.client.CrowdinProjectFull;
import com.crowdin.cli.client.ProjectBuilder;
import com.crowdin.cli.client.ProjectClient;
import com.crowdin.cli.commands.Outputter;
import com.crowdin.cli.properties.NewPropertiesWithFilesUtilBuilder;
import com.crowdin.cli.properties.PropertiesWithFiles;
import com.crowdin.cli.properties.helper.FileHelperTest;
import com.crowdin.cli.properties.helper.TempProject;
import com.crowdin.cli.utils.Utils;
import com.crowdin.client.labels.model.Label;
import com.crowdin.client.projectsgroups.model.Type;
import com.crowdin.client.translations.model.ApplyPreTranslationRequest;
import com.crowdin.client.translations.model.ApplyPreTranslationStringsBasedRequest;
import com.crowdin.client.translations.model.PreTranslationStatus;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.List;

import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;

class PreTranslateActionTest {

private TempProject project;

@BeforeEach
public void createProj() {
project = new TempProject(FileHelperTest.class);
}

@AfterEach
public void deleteProj() {
project.delete();
}

@Test
public void testPreTranslate() {
String fileName = "first.po";
String labelName = "label_1";
String branchName = "main";
NewPropertiesWithFilesUtilBuilder pbBuilder = NewPropertiesWithFilesUtilBuilder
.minimalBuiltPropertiesBean("*", Utils.PATH_SEPARATOR + "%original_file_name%-CR-%locale%")
.setBasePath(project.getBasePath());
PropertiesWithFiles pb = pbBuilder.build();
ProjectBuilder projectBuilder = ProjectBuilder.emptyProject(Long.parseLong(pb.getProjectId()))
.addFile(fileName, "gettext", 101L, null, 81L)
.addBranches(81L, branchName);
CrowdinProjectFull crowdinProjectFull = projectBuilder.build();
crowdinProjectFull.setType(Type.FILES_BASED);

Label label1 = new Label() {{
setId(91L);
setTitle(labelName);
}};
List<Label> labels = List.of(label1);

ApplyPreTranslationRequest request = new ApplyPreTranslationRequest() {{
setLabelIds(List.of(91L));
setFileIds(List.of(101L));
setLanguageIds(List.of("ua"));
}};
PreTranslationStatus preTransInProgress = new PreTranslationStatus() {{
setStatus("progress");
setProgress(10);
setIdentifier("121");
}};
PreTranslationStatus preTransFinished = new PreTranslationStatus() {{
setStatus("finished");
setIdentifier("121");
}};

ProjectClient client = mock(ProjectClient.class);

when(client.downloadFullProject(eq(branchName))).thenReturn(crowdinProjectFull);
when(client.startPreTranslation(eq(request))).thenReturn(preTransInProgress);
when(client.checkPreTranslation("121")).thenReturn(preTransFinished);
when(client.listLabels()).thenReturn(labels);

PreTranslateAction action = new PreTranslateAction(List.of("ua"), List.of(fileName), null, null, branchName, null,
null, null, null, null, false, false, List.of(labelName), null);
action.act(Outputter.getDefault(), pb, client);

verify(client).downloadFullProject(eq(branchName));
verify(client).listLabels();
verify(client).startPreTranslation(eq(request));
verify(client).checkPreTranslation(eq("121"));
verifyNoMoreInteractions(client);
}

@Test
public void testPreTranslate_Directory() {
String fileName = "first.po";
String directoryName = "src";
String branchName = "main";
NewPropertiesWithFilesUtilBuilder pbBuilder = NewPropertiesWithFilesUtilBuilder
.minimalBuiltPropertiesBean("*", Utils.PATH_SEPARATOR + "%original_file_name%-CR-%locale%")
.setBasePath(project.getBasePath());
PropertiesWithFiles pb = pbBuilder.build();
ProjectBuilder projectBuilder = ProjectBuilder.emptyProject(Long.parseLong(pb.getProjectId()))
.addDirectory(directoryName, 61L, null, 81L)
.addFile(fileName, "gettext", 101L, 61L, 81L)
.addBranches(81L, branchName);
CrowdinProjectFull crowdinProjectFull = projectBuilder.build();
crowdinProjectFull.setType(Type.FILES_BASED);

ApplyPreTranslationRequest request = new ApplyPreTranslationRequest() {{
setFileIds(List.of(101L));
setLanguageIds(List.of("ua"));
}};
PreTranslationStatus preTranslationStatus = new PreTranslationStatus() {{
setStatus("finished");
setProgress(10);
setIdentifier("121");
}};

ProjectClient client = mock(ProjectClient.class);

when(client.downloadFullProject(eq(branchName))).thenReturn(crowdinProjectFull);
when(client.startPreTranslation(eq(request))).thenReturn(preTranslationStatus);

PreTranslateAction action = new PreTranslateAction(List.of("ua"), null, null, null, branchName, directoryName,
null, null, null, null, true, true, null, null);
action.act(Outputter.getDefault(), pb, client);

verify(client).downloadFullProject(eq(branchName));
verify(client).startPreTranslation(eq(request));
verifyNoMoreInteractions(client);
}

@Test
public void testPreTranslate_StringsBased() {
String branchName = "main";
NewPropertiesWithFilesUtilBuilder pbBuilder = NewPropertiesWithFilesUtilBuilder
.minimalBuiltPropertiesBean("*", Utils.PATH_SEPARATOR + "%original_file_name%-CR-%locale%")
.setBasePath(project.getBasePath());
PropertiesWithFiles pb = pbBuilder.build();
ProjectBuilder projectBuilder = ProjectBuilder.emptyProject(Long.parseLong(pb.getProjectId()))
.addBranches(81L, branchName);
CrowdinProjectFull crowdinProjectFull = projectBuilder.build();
crowdinProjectFull.setType(Type.STRINGS_BASED);

ApplyPreTranslationStringsBasedRequest request = new ApplyPreTranslationStringsBasedRequest() {{
setLanguageIds(List.of("ua"));
setBranchIds(List.of(81L));
}};
PreTranslationStatus preTranslationStatus = new PreTranslationStatus() {{
setStatus("finished");
setProgress(10);
setIdentifier("121");
}};

ProjectClient client = mock(ProjectClient.class);

when(client.downloadFullProject(eq(branchName))).thenReturn(crowdinProjectFull);
when(client.startPreTranslationStringsBased(eq(request))).thenReturn(preTranslationStatus);

PreTranslateAction action = new PreTranslateAction(List.of("ua"), null, null, null, branchName, null,
null, null, null, null, false, false, null, null);
action.act(Outputter.getDefault(), pb, client);

verify(client).downloadFullProject(eq(branchName));
verify(client).startPreTranslationStringsBased(eq(request));
verifyNoMoreInteractions(client);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ void mockActions() {
.thenReturn(actionMock);
when(actionsMock.bundleAdd(any(), any(), any(), any(), any(), any(), anyBoolean()))
.thenReturn(actionMock);
when(actionsMock.preTranslate(any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), anyBoolean(), anyBoolean(), any(), any()))
.thenReturn(actionMock);
when(actionsMock.screenshotList(any(), anyBoolean()))
.thenReturn(actionMock);
when(actionsMock.screenshotUpload(any(), any(), any(), any(), any(), anyBoolean(), anyBoolean(), anyBoolean(), any()))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.crowdin.cli.commands.picocli;

import org.junit.jupiter.api.Test;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.verify;

class PreTranslateSubcommandTest extends PicocliTestUtils {

@Test
public void testPreTranslate() {
this.execute(CommandNames.PRE_TRANSLATE, "--method", "TM");
verify(actionsMock)
.preTranslate(any(), any(), any(), any(), any(), any(), any(), any(), any(), any(), anyBoolean(), anyBoolean(), any(), any());
this.check(true);
}
}

0 comments on commit 1f52223

Please sign in to comment.