Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: directory parameter for pre-translate command #816

Merged
merged 2 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 for this type of project
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);
}
}
Loading