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: crowdin string updates #766

Merged
merged 7 commits into from
Apr 15, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
12 changes: 10 additions & 2 deletions src/main/java/com/crowdin/cli/client/CrowdinProjectClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -354,9 +354,17 @@ public SourceString addSourcePluralStringStringsBased(AddSourcePluralStringStrin
}

@Override
public List<SourceString> listSourceString(Long fileId, Long branchId, String labelIds, String filter, String croql) {
public List<SourceString> listSourceString(Long fileId, Long branchId, String labelIds, String filter, String croql, Long directory, String scope) {
ListSourceStringsParams.ListSourceStringsParamsBuilder builder = ListSourceStringsParams.builder()
.fileId(fileId)
.branchId(branchId)
.labelIds(labelIds)
.filter(filter)
.croql(croql)
.directoryId(directory)
.scope(scope);
return executeRequestFullList((limit, offset) -> this.client.getSourceStringsApi()
.listSourceStrings(this.projectId, fileId, null, branchId, labelIds, croql, filter, null, limit, offset));
.listSourceStrings(this.projectId, builder.limit(limit).offset(offset).build()));
}

@Override
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/crowdin/cli/client/ProjectClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ default CrowdinProjectFull downloadFullProject() {

SourceString addSourcePluralStringStringsBased(AddSourcePluralStringStringsBasedRequest request);

List<SourceString> listSourceString(Long fileId, Long branchId, String labelIds, String filter, String croql);
List<SourceString> listSourceString(Long fileId, Long branchId, String labelIds, String filter, String croql, Long directory, String scope);

void deleteSourceString(Long id);

Expand Down
7 changes: 3 additions & 4 deletions src/main/java/com/crowdin/cli/commands/Actions.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,13 @@ NewAction<ProjectProperties, ProjectClient> stringAdd(
NewAction<ProjectProperties, ProjectClient> stringComment(boolean plainView,
boolean noProgress, String text, String stringId, String language, String type, String issueType);

NewAction<ProjectProperties, ProjectClient> stringDelete(
boolean noProgress, List<Long> ids, List<String> texts, List<String> identifiers);
NewAction<ProjectProperties, ProjectClient> stringDelete(Long id);

NewAction<ProjectProperties, ProjectClient> stringEdit(
boolean noProgress, Long id, String identifier, String newText, String newContext, Integer newMaxLength, List<String> labelNames, Boolean isHidden);
boolean noProgress, boolean isVerbose, Long id, String identifier, String newText, String newContext, Integer newMaxLength, List<String> labelNames, Boolean isHidden);

NewAction<ProjectProperties, ProjectClient> stringList(
boolean noProgress, boolean isVerbose, String file, String filter, String branchName, List<String> labelNames, String croql);
boolean noProgress, boolean isVerbose, String file, String filter, String branchName, List<String> labelNames, String croql, Long directory, String scope);

NewAction<PropertiesWithFiles, ProjectClient> uploadSources(
String branchName, boolean deleteObsolete, boolean noProgress, boolean autoUpdate, boolean debug, boolean plainView);
Expand Down
14 changes: 6 additions & 8 deletions src/main/java/com/crowdin/cli/commands/actions/CliActions.java
Original file line number Diff line number Diff line change
Expand Up @@ -91,24 +91,22 @@ public NewAction<ProjectProperties, ProjectClient> stringComment(boolean plainVi
}

@Override
public NewAction<ProjectProperties, ProjectClient> stringDelete(
boolean noProgress, List<Long> ids, List<String> texts, List<String> identifiers
) {
return new StringDeleteAction(noProgress, ids, texts, identifiers);
public NewAction<ProjectProperties, ProjectClient> stringDelete(Long id) {
return new StringDeleteAction(id);
}

@Override
public NewAction<ProjectProperties, ProjectClient> stringEdit(
boolean noProgress, Long id, String identifier, String newText, String newContext, Integer newMaxLength, List<String> labelNames, Boolean isHidden
boolean noProgress, boolean isVerbose, Long id, String identifier, String newText, String newContext, Integer newMaxLength, List<String> labelNames, Boolean isHidden
) {
return new StringEditAction(noProgress, id, identifier, newText, newContext, newMaxLength, labelNames, isHidden);
return new StringEditAction(noProgress, isVerbose, id, identifier, newText, newContext, newMaxLength, labelNames, isHidden);
}

@Override
public NewAction<ProjectProperties, ProjectClient> stringList(
boolean noProgress, boolean isVerbose, String file, String filter, String branchName, List<String> labelNames, String croql
boolean noProgress, boolean isVerbose, String file, String filter, String branchName, List<String> labelNames, String croql, Long directory, String scope
) {
return new StringListAction(noProgress, isVerbose, file, filter, branchName, labelNames, croql);
return new StringListAction(noProgress, isVerbose, file, filter, branchName, labelNames, croql, directory, scope);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,60 +1,24 @@
package com.crowdin.cli.commands.actions;

import com.crowdin.cli.client.CrowdinProjectFull;
import com.crowdin.cli.client.ProjectClient;
import com.crowdin.cli.commands.NewAction;
import com.crowdin.cli.commands.Outputter;
import com.crowdin.cli.commands.functionality.ProjectFilesUtils;
import com.crowdin.cli.properties.ProjectProperties;
import com.crowdin.cli.utils.console.ConsoleSpinner;
import com.crowdin.client.sourcestrings.model.SourceString;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.crowdin.cli.BaseCli.RESOURCE_BUNDLE;
import static com.crowdin.cli.utils.console.ExecutionStatus.OK;

class StringDeleteAction implements NewAction<ProjectProperties, ProjectClient> {

private final boolean noProgress;
private final List<Long> ids;
private final List<String> texts;
private final List<String> identifiers;
private final Long id;

public StringDeleteAction(boolean noProgress, List<Long> ids, List<String> texts, List<String> identifiers) {
this.noProgress = noProgress;
this.ids = ids;
this.texts = texts;
this.identifiers = identifiers;
public StringDeleteAction(Long id) {
this.id = id;
}

@Override
public void act(Outputter out, ProjectProperties pb, ProjectClient client) {
CrowdinProjectFull project = ConsoleSpinner.execute(out, "message.spinner.fetching_project_info", "error.collect_project_info",
this.noProgress, false, client::downloadFullProject);

Map<Long, String> paths = ProjectFilesUtils.buildFilePaths(project.getDirectories(), project.getBranches(), project.getFiles())
.entrySet()
.stream()
.collect(Collectors.toMap((entry) -> entry.getValue().getId(), Map.Entry::getKey));

List<SourceString> sourceStrings = client.listSourceString(null, null, null, null, null)
.stream()
.filter(sourceString -> (ids != null && ids.contains(sourceString.getId()))
|| (texts != null && sourceString.getText() instanceof String && texts.contains(sourceString.getText()))
|| (identifiers != null && identifiers.contains(sourceString.getIdentifier())))
.collect(Collectors.toList());

for (SourceString sourceString : sourceStrings) {
client.deleteSourceString(sourceString.getId());
out.println(OK.withIcon(String.format(RESOURCE_BUNDLE.getString("message.source_string_deleted"),
sourceString.getText(), sourceString.getId(), paths.get(sourceString.getFileId()))));
}

if (sourceStrings.isEmpty()) {
throw new RuntimeException(RESOURCE_BUNDLE.getString("error.source_string_not_found"));
}
client.deleteSourceString(id);
out.println(OK.withIcon(String.format(RESOURCE_BUNDLE.getString("message.source_string_deleted"), this.id)));
}
}
Original file line number Diff line number Diff line change
@@ -1,71 +1,70 @@
package com.crowdin.cli.commands.actions;

import com.crowdin.cli.client.CrowdinProjectFull;
import com.crowdin.cli.client.ProjectClient;
import com.crowdin.cli.commands.NewAction;
import com.crowdin.cli.commands.Outputter;
import com.crowdin.cli.commands.functionality.ProjectFilesUtils;
import com.crowdin.cli.commands.functionality.RequestBuilder;
import com.crowdin.cli.properties.ProjectProperties;
import com.crowdin.cli.utils.console.ConsoleSpinner;
import com.crowdin.client.core.model.PatchOperation;
import com.crowdin.client.core.model.PatchRequest;
import com.crowdin.client.labels.model.Label;
import com.crowdin.client.projectsgroups.model.Type;
import com.crowdin.client.sourcefiles.model.FileInfo;
import com.crowdin.client.sourcestrings.model.SourceString;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;

import static com.crowdin.cli.BaseCli.RESOURCE_BUNDLE;
import static com.crowdin.cli.commands.actions.StringListAction.printSourceString;
import static com.crowdin.cli.utils.console.ExecutionStatus.OK;

class StringEditAction implements NewAction<ProjectProperties, ProjectClient> {

private final boolean noProgress;
private final Long id;
private final String identifier;
private final String newText;
private final String newContext;
private final Integer newMaxLength;
private final List<String> labelNames;
private final Boolean isHidden;
private final boolean isVerbose;
private final boolean noProgress;

public StringEditAction(
boolean noProgress, Long id, String identifier, String newText, String newContext, Integer newMaxLength, List<String> labelNames, Boolean isHidden
boolean noProgress, boolean isVerbose, Long id, String identifier, String newText, String newContext, Integer newMaxLength, List<String> labelNames, Boolean isHidden
) {
this.noProgress = noProgress;
this.id = id;
this.identifier = identifier;
this.newText = newText;
this.newContext = newContext;
this.newMaxLength = newMaxLength;
this.labelNames = labelNames;
this.isHidden = isHidden;
this.isVerbose = isVerbose;
this.noProgress = noProgress;
}

@Override
public void act(Outputter out, ProjectProperties pb, ProjectClient client) {
CrowdinProjectFull project = ConsoleSpinner.execute(out, "message.spinner.fetching_project_info", "error.collect_project_info",
this.noProgress, false, client::downloadFullProject);
boolean isStringsBasedProject = Objects.equals(project.getType(), Type.STRINGS_BASED);

List<SourceString> sourceStrings = client.listSourceString(null, null, null, null, null);
Map<Long, String> reversePaths = null;
if (!isStringsBasedProject) {
Map<String, FileInfo> paths = ProjectFilesUtils.buildFilePaths(project.getDirectories(), project.getBranches(), project.getFileInfos());
reversePaths = paths.entrySet()
.stream()
.collect(Collectors.toMap((entry) -> entry.getValue().getId(), Map.Entry::getKey));
}
Map<Long, String> finalReversePaths = reversePaths;

List<Long> labelIds = (labelNames != null && !labelNames.isEmpty()) ? this.prepareLabelIds(client) : null;

Long foundStringId;
if (id != null) {
foundStringId = sourceStrings.stream()
.filter(ss -> id.equals(ss.getId()))
.findAny()
.orElseThrow(() -> new RuntimeException(RESOURCE_BUNDLE.getString("error.source_string_not_found")))
.getId();
} else if (identifier != null) {
foundStringId = sourceStrings.stream()
.filter(ss -> identifier.equals(ss.getIdentifier()))
.findAny()
.orElseThrow(() -> new RuntimeException(RESOURCE_BUNDLE.getString("error.source_string_not_found")))
.getId();
} else {
throw new RuntimeException("Unexpected error: no 'id' or 'identifier' specified");
}

List<PatchRequest> requests = new ArrayList<>();
if (newText != null) {
PatchRequest request = RequestBuilder.patch(newText, PatchOperation.REPLACE, "/text");
Expand All @@ -83,13 +82,21 @@ public void act(Outputter out, ProjectProperties pb, ProjectClient client) {
PatchRequest request = RequestBuilder.patch(isHidden, PatchOperation.REPLACE, "/isHidden");
requests.add(request);
}
if (identifier != null) {
PatchRequest request = RequestBuilder.patch(identifier, PatchOperation.REPLACE, "/identifier");
requests.add(request);
}
if (labelIds != null) {
PatchRequest request = RequestBuilder.patch(labelIds, PatchOperation.REPLACE, "/labelIds");
requests.add(request);
}

client.editSourceString(foundStringId, requests);
out.println(OK.withIcon(String.format(RESOURCE_BUNDLE.getString("message.source_string_updated"), foundStringId)));
SourceString updatedString = client.editSourceString(this.id, requests);
out.println(OK.withIcon(String.format(RESOURCE_BUNDLE.getString("message.source_string_updated"), this.id)));

Map<Long, String> labelsMap = client.listLabels().stream()
.collect(Collectors.toMap(Label::getId, Label::getTitle));
printSourceString(updatedString, labelsMap, out, isStringsBasedProject, finalReversePaths, isVerbose);
}

private List<Long> prepareLabelIds(ProjectClient client) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,19 @@ class StringListAction implements NewAction<ProjectProperties, ProjectClient> {
private final String branchName;
private final List<String> labelNames;
private final String croql;
private final Long directory;
private final String scope;

public StringListAction(boolean noProgress, boolean isVerbose, String file, String filter, String branchName, List<String> labelNames, String croql) {
public StringListAction(boolean noProgress, boolean isVerbose, String file, String filter, String branchName, List<String> labelNames, String croql, Long directory, String scope) {
this.noProgress = noProgress;
this.isVerbose = isVerbose;
this.file = file;
this.filter = filter;
this.branchName = branchName;
this.labelNames = labelNames;
this.croql = croql;
this.directory = directory;
this.scope = scope;
}

@Override
Expand Down Expand Up @@ -76,55 +80,66 @@ public void act(Outputter out, ProjectProperties pb, ProjectClient client) {
String labelIds = nonNull(labelNames) ? prepareLabelIds(labels) : null;
String fullPath = nonNull(branchName) ? (BranchUtils.normalizeBranchName(branchName) + Utils.PATH_SEPARATOR + file) : file;

if ((!StringUtils.isEmpty(file) || Objects.nonNull(directory)) && isStringsBasedProject) {
throw new RuntimeException(RESOURCE_BUNDLE.getString("message.no_file_string_project"));
}

List<SourceString> sourceStrings;
if (StringUtils.isEmpty(file)) {
sourceStrings = client.listSourceString(null, branchId, labelIds, encodedFilter, encodedCroql);
sourceStrings = client.listSourceString(null, branchId, labelIds, encodedFilter, encodedCroql, directory, scope);
} else {
if (isStringsBasedProject) {
throw new RuntimeException(RESOURCE_BUNDLE.getString("message.no_file_string_project"));
}
if (paths.containsKey(fullPath)) {
sourceStrings = client.listSourceString(paths.get(fullPath).getId(), branchId, labelIds, encodedFilter, encodedCroql);
sourceStrings = client.listSourceString(paths.get(fullPath).getId(), branchId, labelIds, encodedFilter, encodedCroql, directory, scope);
} else {
throw new RuntimeException(String.format(RESOURCE_BUNDLE.getString("error.file_not_exists"), fullPath));
}
}
if (sourceStrings.isEmpty()) {
out.println(WARNING.withIcon(RESOURCE_BUNDLE.getString("message.source_string_list_not_found")));
}
sourceStrings.forEach(ss -> {
String labelsString = (ss.getLabelIds() != null)
? ss.getLabelIds().stream().map(labelsMap::get).map(s -> String.format("[@|cyan %s|@]", s)).collect(Collectors.joining(" "))
sourceStrings.forEach(ss -> printSourceString(ss, labelsMap, out, isStringsBasedProject, finalReversePaths, isVerbose));
}

public static void printSourceString(
SourceString ss,
Map<Long, String> labelsMap,
Outputter out,
boolean isStringsBasedProject,
Map<Long, String> finalReversePaths,
boolean isVerbose
) {
String labelsString = (ss.getLabelIds() != null)
? ss.getLabelIds().stream().map(labelsMap::get).map(s -> String.format("@|cyan %s|@", s)).collect(Collectors.joining(", "))
: "";
StringBuilder text = new StringBuilder();
if (ss.getText() instanceof HashMap<?, ?>) {
HashMap<?, ?> map = (HashMap<?, ?>) ss.getText();
for (Map.Entry<?, ?> entry : map.entrySet()) {
text.append(entry.getKey()).append(": ").append(entry.getValue()).append(" | ");
}
if (text.length() > 0) {
text.delete(text.length() - 3, text.length());
}
} else {
text.append((String) ss.getText());
StringBuilder text = new StringBuilder();
if (ss.getText() instanceof HashMap<?, ?>) {
HashMap<?, ?> map = (HashMap<?, ?>) ss.getText();
for (Map.Entry<?, ?> entry : map.entrySet()) {
text.append(entry.getKey()).append(": ").append(entry.getValue()).append(" | ");
}
if (text.length() > 0) {
text.delete(text.length() - 3, text.length());
}
out.println(String.format(RESOURCE_BUNDLE.getString("message.source_string_list_text"), ss.getId(), text, labelsString));
if (isVerbose) {
if (ss.getIdentifier() != null) {
out.println(String.format("\t- @|bold identifier|@: '%s'", ss.getIdentifier()));
}
if (ss.getContext() != null) {
out.println(String.format(
} else {
text.append((String) ss.getText());
}
if (ss.getIdentifier() == null) {
out.println(String.format(RESOURCE_BUNDLE.getString("message.source_string_list_text_short"), ss.getId(), text));
} else {
out.println(String.format(RESOURCE_BUNDLE.getString("message.source_string_list_text"), ss.getId(), ss.getIdentifier(), text));
}
if (isVerbose) {
if (!isStringsBasedProject && (ss.getFileId() != null)) {
out.println(String.format(RESOURCE_BUNDLE.getString("message.source_string_list_file"), finalReversePaths.get(ss.getFileId())));
}
if (!StringUtils.isEmpty(labelsString)) {
out.println(String.format(RESOURCE_BUNDLE.getString("message.source_string_list_labels"), labelsString));
}
if (ss.getContext() != null) {
out.println(String.format(
RESOURCE_BUNDLE.getString("message.source_string_list_context"), ss.getContext().trim().replaceAll("\n", "\n\t\t")));
}
if (!isStringsBasedProject && (ss.getFileId() != null)) {
out.println(String.format(RESOURCE_BUNDLE.getString("message.source_string_list_file"), finalReversePaths.get(ss.getFileId())));
}
if (ss.getMaxLength() != null && ss.getMaxLength() != 0) {
out.println(String.format(RESOURCE_BUNDLE.getString("message.source_string_list_max_length"), ss.getMaxLength()));
}
}
});
}
}

private String prepareLabelIds(List<Label> labels) {
Expand Down
Loading
Loading