Skip to content

Commit

Permalink
feat: add the 'export_quotes' support for JavaScript files
Browse files Browse the repository at this point in the history
  • Loading branch information
andrii-bodnar committed Aug 23, 2023
1 parent 6887f03 commit 0cb25d6
Show file tree
Hide file tree
Showing 15 changed files with 245 additions and 79 deletions.
5 changes: 3 additions & 2 deletions src/main/java/com/crowdin/cli/client/ClientBundle.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.crowdin.cli.client;

import com.crowdin.client.bundles.model.AddBundleRequest;
import com.crowdin.client.bundles.model.Bundle;
import com.crowdin.client.bundles.model.BundleExport;

Expand All @@ -11,13 +12,13 @@ public interface ClientBundle extends Client {

List<Bundle> listBundle();

Bundle addBundle(Bundle request);
Bundle addBundle(AddBundleRequest request);

Optional<Bundle> getBundle(Long id);

URL downloadBundle(Long id, String exportId);

BundleExport startExportingBundle(Long id, Bundle bundle);
BundleExport startExportingBundle(Long id);

BundleExport checkExportingBundle(Long tmId, String exportId);

Expand Down
7 changes: 4 additions & 3 deletions src/main/java/com/crowdin/cli/client/CrowdinClientBundle.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.crowdin.cli.client;


import com.crowdin.client.bundles.model.AddBundleRequest;
import com.crowdin.client.bundles.model.Bundle;
import com.crowdin.client.bundles.model.BundleExport;

Expand All @@ -24,7 +25,7 @@ public List<Bundle> listBundle() {
}

@Override
public Bundle addBundle(Bundle bundleRequest) {
public Bundle addBundle(AddBundleRequest bundleRequest) {
return executeRequest(() -> this.client.getBundlesApi()
.addBundle(Long.valueOf(projectId), bundleRequest)
.getData());
Expand All @@ -49,9 +50,9 @@ public URL downloadBundle(Long id, String exportId) {
}

@Override
public BundleExport startExportingBundle(Long id, Bundle bundle) {
public BundleExport startExportingBundle(Long id) {
return executeRequest(() -> this.client.getBundlesApi()
.exportBundle(Long.valueOf(projectId), id, bundle)
.exportBundle(Long.valueOf(projectId), id)
.getData());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.crowdin.cli.commands.NewAction;
import com.crowdin.cli.commands.Outputter;
import com.crowdin.cli.properties.ProjectProperties;
import com.crowdin.client.bundles.model.AddBundleRequest;
import com.crowdin.client.bundles.model.Bundle;
import lombok.AllArgsConstructor;

Expand Down Expand Up @@ -33,7 +34,8 @@ class BundleAddAction implements NewAction<ProjectProperties, ClientBundle> {
@Override
public void act(Outputter out, ProjectProperties pb, ClientBundle client) {
Bundle bundle;
Bundle addBundleRequest = new Bundle();
AddBundleRequest addBundleRequest = new AddBundleRequest();

Optional.ofNullable(name).ifPresent(addBundleRequest::setName);
Optional.ofNullable(format).ifPresent(addBundleRequest::setFormat);
Optional.ofNullable(source).ifPresent(addBundleRequest::setSourcePatterns);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public DownloadBundleAction(Long id, FilesInterface files, boolean plainView, bo
public void act(Outputter out, ProjectProperties pb, ClientBundle client) {
this.out = out;
Bundle bundle = getBundle(client);
BundleExport status = this.buildBundle(out, client, bundle.getId(), bundle);
BundleExport status = this.buildBundle(out, client, bundle.getId());
to = new File("bundle-" + status.getIdentifier() + ".zip");
downloadBundle(client, bundle.getId(), status.getIdentifier());
out.println(OK.withIcon(String.format(RESOURCE_BUNDLE.getString("message.bundle.download_success"), bundle.getId(), bundle.getName())));
Expand Down Expand Up @@ -78,15 +78,15 @@ private Bundle getBundle(ClientBundle client) {
.orElseThrow(() -> new RuntimeException(RESOURCE_BUNDLE.getString("error.bundle.not_found_by_id")));
}

private BundleExport buildBundle(Outputter out, ClientBundle client, Long bundleId, Bundle request) {
private BundleExport buildBundle(Outputter out, ClientBundle client, Long bundleId) {
return ConsoleSpinner.execute(
out,
"message.spinner.building_bundle",
"error.bundle.build_bundle",
this.noProgress,
false,
() -> {
BundleExport status = client.startExportingBundle(bundleId, request);
BundleExport status = client.startExportingBundle(bundleId);

while (!status.getStatus().equalsIgnoreCase("finished")) {
ConsoleSpinner.update(String.format(RESOURCE_BUNDLE.getString("message.spinner.building_bundle_percents"), status.getProgress()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@
import com.crowdin.client.sourcefiles.model.Branch;
import com.crowdin.client.sourcefiles.model.ExportOptions;
import com.crowdin.client.sourcefiles.model.FileInfo;
import com.crowdin.client.sourcefiles.model.GeneralFileExportOptions;
import com.crowdin.client.sourcefiles.model.ImportOptions;
import com.crowdin.client.sourcefiles.model.OtherFileImportOptions;
import com.crowdin.client.sourcefiles.model.PropertyFileExportOptions;
import com.crowdin.client.sourcefiles.model.SpreadsheetFileImportOptions;
import com.crowdin.client.sourcefiles.model.JavaScriptFileExportOptions;
import com.crowdin.client.sourcefiles.model.UpdateFileRequest;
import com.crowdin.client.sourcefiles.model.XmlFileImportOptions;
import org.apache.commons.io.FilenameUtils;
Expand All @@ -53,6 +55,8 @@
import static com.crowdin.cli.utils.console.ExecutionStatus.OK;
import static com.crowdin.cli.utils.console.ExecutionStatus.SKIPPED;
import static com.crowdin.cli.utils.console.ExecutionStatus.WARNING;
import static com.crowdin.client.sourcefiles.model.ExportQuotes.SINGLE;
import static com.crowdin.client.sourcefiles.model.ExportQuotes.DOUBLE;

class UploadSourcesAction implements NewAction<PropertiesWithFiles, ProjectClient> {

Expand Down Expand Up @@ -350,21 +354,40 @@ private boolean isXml(java.io.File file) {
}

private ExportOptions buildExportOptions(java.io.File sourceFile, FileBean fileBean, String basePath) {
PropertyFileExportOptions exportOptions = new PropertyFileExportOptions();
String exportPattern = TranslationsUtils.replaceDoubleAsterisk(
fileBean.getSource(),
fileBean.getTranslation(),
StringUtils.removeStart(sourceFile.getAbsolutePath(), basePath)
);

exportPattern = StringUtils.replacePattern(exportPattern, "[\\\\/]+", "/");
exportOptions.setExportPattern(exportPattern);
exportOptions.setEscapeQuotes(fileBean.getEscapeQuotes());
if (fileBean.getEscapeSpecialCharacters() != null) {
exportOptions.setEscapeSpecialCharacters(fileBean.getEscapeSpecialCharacters());
} else if (SourcesUtils.isFileProperties(sourceFile)) {

if (SourcesUtils.isFileProperties(sourceFile)) {
PropertyFileExportOptions exportOptions = new PropertyFileExportOptions();
exportOptions.setExportPattern(exportPattern);
exportOptions.setEscapeQuotes(fileBean.getEscapeQuotes());
exportOptions.setEscapeSpecialCharacters(1);

if (fileBean.getEscapeSpecialCharacters() != null) {
exportOptions.setEscapeSpecialCharacters(fileBean.getEscapeSpecialCharacters());
}

return exportOptions;
} else if (SourcesUtils.isFileJavaScript(sourceFile)) {
JavaScriptFileExportOptions exportOptions = new JavaScriptFileExportOptions();
exportOptions.setExportPattern(exportPattern);

if (fileBean.getExportQuotes() != null) {
exportOptions.setExportQuotes(fileBean.getExportQuotes() == "single" ? SINGLE : DOUBLE);
}

return exportOptions;
} else {
GeneralFileExportOptions exportOptions = new GeneralFileExportOptions();
exportOptions.setExportPattern(exportPattern);

return exportOptions;
}
return exportOptions;
}

private Branch getOrCreateBranch(Outputter out, String branchName, ProjectClient client, CrowdinProjectFull project) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,8 @@ public static String getCommonPath(List<String> sources, String basePath) {
public static boolean isFileProperties(File source) {
return FilenameUtils.isExtension(source.getName(), "properties");
}

public static boolean isFileJavaScript(File source) {
return FilenameUtils.isExtension(source.getName(), "js");
}
}
64 changes: 40 additions & 24 deletions src/main/java/com/crowdin/cli/properties/FileBean.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import static com.crowdin.cli.properties.PropertiesBuilder.DEST;
import static com.crowdin.cli.properties.PropertiesBuilder.ESCAPE_QUOTES;
import static com.crowdin.cli.properties.PropertiesBuilder.ESCAPE_SPECIAL_CHARACTERS;
import static com.crowdin.cli.properties.PropertiesBuilder.EXPORT_QUOTES;
import static com.crowdin.cli.properties.PropertiesBuilder.EXCLUDED_TARGET_LANGUAGES;
import static com.crowdin.cli.properties.PropertiesBuilder.EXPORT_APPROVED_ONLY;
import static com.crowdin.cli.properties.PropertiesBuilder.FIRST_LINE_CONTAINS_HEADER;
Expand Down Expand Up @@ -60,6 +61,7 @@ public class FileBean {
private Boolean contentSegmentation;
private Integer escapeQuotes;
private Integer escapeSpecialCharacters;
private String exportQuotes;
private Map<String, String> translationReplace;
private Boolean skipTranslatedOnly;
private Boolean skipUntranslatedFiles;
Expand All @@ -79,31 +81,33 @@ private FileBeanConfigurator() {
@Override
public FileBean buildFromMap(Map<String, Object> map) {
FileBean fileBean = new FileBean();
PropertiesBuilder.setPropertyIfExists(fileBean::setSource, map, SOURCE, String.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setDest, map, DEST, String.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setType, map, TYPE, String.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setTranslation, map, TRANSLATION, String.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setUpdateOption, map, UPDATE_OPTION, String.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setScheme, map, SCHEME, String.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setIgnore, map, IGNORE, List.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setTranslatableElements, map, TRANSLATABLE_ELEMENTS, List.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setLanguagesMapping, map, LANGUAGES_MAPPING, Map.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setTranslationReplace, map, TRANSLATION_REPLACE, Map.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setEscapeQuotes, map, ESCAPE_QUOTES, Integer.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setEscapeSpecialCharacters, map, ESCAPE_SPECIAL_CHARACTERS, Integer.class);
PropertiesBuilder.setBooleanPropertyIfExists(fileBean::setFirstLineContainsHeader, map, FIRST_LINE_CONTAINS_HEADER);
PropertiesBuilder.setBooleanPropertyIfExists(fileBean::setTranslateAttributes, map, TRANSLATE_ATTRIBUTES);
PropertiesBuilder.setBooleanPropertyIfExists(fileBean::setTranslateContent, map, TRANSLATE_CONTENT);
PropertiesBuilder.setBooleanPropertyIfExists(fileBean::setContentSegmentation, map, CONTENT_SEGMENTATION);
PropertiesBuilder.setBooleanPropertyIfExists(fileBean::setMultilingualSpreadsheet, map, MULTILINGUAL_SPREADSHEET);
PropertiesBuilder.setBooleanPropertyIfExists(fileBean::setSkipTranslatedOnly, map, SKIP_UNTRANSLATED_STRINGS);
PropertiesBuilder.setBooleanPropertyIfExists(fileBean::setSkipUntranslatedFiles, map, SKIP_UNTRANSLATED_FILES);
PropertiesBuilder.setBooleanPropertyIfExists(fileBean::setExportApprovedOnly, map, EXPORT_APPROVED_ONLY);
PropertiesBuilder.setPropertyIfExists(fileBean::setSource, map, SOURCE, String.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setDest, map, DEST, String.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setType, map, TYPE, String.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setTranslation, map, TRANSLATION, String.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setUpdateOption, map, UPDATE_OPTION, String.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setScheme, map, SCHEME, String.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setIgnore, map, IGNORE, List.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setTranslatableElements, map, TRANSLATABLE_ELEMENTS, List.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setLanguagesMapping, map, LANGUAGES_MAPPING, Map.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setTranslationReplace, map, TRANSLATION_REPLACE, Map.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setEscapeQuotes, map, ESCAPE_QUOTES, Integer.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setEscapeSpecialCharacters, map, ESCAPE_SPECIAL_CHARACTERS, Integer.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setExportQuotes, map, EXPORT_QUOTES, String.class);
PropertiesBuilder.setBooleanPropertyIfExists(fileBean::setFirstLineContainsHeader, map, FIRST_LINE_CONTAINS_HEADER);
PropertiesBuilder.setBooleanPropertyIfExists(fileBean::setTranslateAttributes, map, TRANSLATE_ATTRIBUTES);
PropertiesBuilder.setBooleanPropertyIfExists(fileBean::setTranslateContent, map, TRANSLATE_CONTENT);
PropertiesBuilder.setBooleanPropertyIfExists(fileBean::setContentSegmentation, map, CONTENT_SEGMENTATION);
PropertiesBuilder.setBooleanPropertyIfExists(fileBean::setMultilingualSpreadsheet, map, MULTILINGUAL_SPREADSHEET);
PropertiesBuilder.setBooleanPropertyIfExists(fileBean::setSkipTranslatedOnly, map, SKIP_UNTRANSLATED_STRINGS);
PropertiesBuilder.setBooleanPropertyIfExists(fileBean::setSkipUntranslatedFiles, map, SKIP_UNTRANSLATED_FILES);
PropertiesBuilder.setBooleanPropertyIfExists(fileBean::setExportApprovedOnly, map, EXPORT_APPROVED_ONLY);
PropertiesBuilder.setBooleanPropertyIfExists(fileBean::setExportStringsThatPassedWorkflow, map, EXPORT_STRINGS_THAT_PASSED_WORKFLOW);
PropertiesBuilder.setPropertyIfExists(fileBean::setLabels, map, LABELS, List.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setExcludedTargetLanguages, map, EXCLUDED_TARGET_LANGUAGES, List.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setCustomSegmentation, map, CUSTOM_SEGMENTATION, String.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setLabels, map, LABELS, List.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setExcludedTargetLanguages, map, EXCLUDED_TARGET_LANGUAGES, List.class);
PropertiesBuilder.setPropertyIfExists(fileBean::setCustomSegmentation, map, CUSTOM_SEGMENTATION, String.class);
PropertiesBuilder.setBooleanPropertyIfExists(fileBean::setImportTranslations, map, IMPORT_TRANSLATIONS);

return fileBean;
}

Expand All @@ -123,7 +127,6 @@ public void populateWithDefaultValues(FileBean bean) {
}
}


//Ignore
if (bean.getIgnore() != null && !bean.getIgnore().isEmpty()) {
List<String> ignores = new ArrayList<>();
Expand Down Expand Up @@ -164,18 +167,22 @@ public void populateWithDefaultValues(FileBean bean) {
@Override
public List<String> checkProperties(FileBean bean) {
List<String> errors = new ArrayList<>();

if (StringUtils.isEmpty(bean.getSource())) {
errors.add(RESOURCE_BUNDLE.getString("error.config.empty_source_section"));
}

if (StringUtils.isEmpty(bean.getTranslation())) {
errors.add(RESOURCE_BUNDLE.getString("error.config.empty_translation_section"));
} else {
if (!checkForDoubleAsterisks(bean.getSource(), bean.getTranslation())) {
errors.add(RESOURCE_BUNDLE.getString("error.config.double_asterisk"));
}

if (!PlaceholderUtil.containsLangPlaceholders(bean.getTranslation()) && bean.getScheme() == null) {
errors.add(RESOURCE_BUNDLE.getString("error.config.translation_has_no_language_placeholders"));
}

if (hasRelativePaths(bean.getTranslation())) {
errors.add(RESOURCE_BUNDLE.getString("error.config.translation_contains_relative_paths"));
}
Expand All @@ -185,22 +192,31 @@ public List<String> checkProperties(FileBean bean) {
if (updateOption != null && !(updateOption.equals("update_as_unapproved") || updateOption.equals("update_without_changes"))) {
errors.add(RESOURCE_BUNDLE.getString("error.config.update_option"));
}

Integer escQuotes = bean.getEscapeQuotes();
if (escQuotes != null && (escQuotes < 0 || escQuotes > 3)) {
errors.add(RESOURCE_BUNDLE.getString("error.config.escape_quotes"));
}

Integer escSpecialCharacters = bean.getEscapeSpecialCharacters();
if (escSpecialCharacters != null && (escSpecialCharacters < 0 || escSpecialCharacters > 1)) {
errors.add(RESOURCE_BUNDLE.getString("error.config.escape_special_characters"));
}

String exportQuotes = bean.getExportQuotes();
if (exportQuotes != null && !(exportQuotes.equals("single") || exportQuotes.equals("double"))) {
errors.add(RESOURCE_BUNDLE.getString("error.config.export_quotes"));
}

if (StringUtils.isNotEmpty(bean.getDest()) && !checkDest(bean.getDest(), bean.getSource())) {
errors.add(RESOURCE_BUNDLE.getString("error.dest_and_pattern_in_source"));
}

if (bean.getSkipTranslatedOnly() != null && bean.getSkipUntranslatedFiles() != null
&& bean.getSkipTranslatedOnly() && bean.getSkipUntranslatedFiles()) {
errors.add(RESOURCE_BUNDLE.getString("error.skip_untranslated_both_strings_and_files"));
}

return errors;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ public abstract class PropertiesBuilder<T extends Properties, P extends Params>

public static final String ESCAPE_SPECIAL_CHARACTERS = "escape_special_characters";

public static final String EXPORT_QUOTES = "export_quotes";

public static final String MULTILINGUAL_SPREADSHEET = "multilingual_spreadsheet";

public static final String SCHEME = "scheme";
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/messages/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,7 @@ error.config.translation_contains_relative_paths=The 'translation' parameter can
error.config.update_option=Configuration file contains unexpected 'update_option' value. The expected values are 'update_as_unapproved' or 'update_without_changes'
error.config.escape_quotes=Acceptable values for 'escape_quotes' are: 0, 1, 2, 3. Default is 3. Read more about 'escape_quotes': https://developer.crowdin.com/configuration-file/#escape-quotes-options-for-properties-file-format
error.config.escape_special_characters=Acceptable values for 'escape_special_characters' are: 0 and 1. Default is 1. Read more about 'escape_special_characters': https://developer.crowdin.com/configuration-file/#escape-quotes-options-for-properties-file-format
error.config.export_quotes=Acceptable values for the 'export_quotes' are: 'single' and 'double'. Default is 'single'
error.config.params_xor_source_translation=Both the 'source' and the 'translation' must be specified in the parameters
error.config.params_dest='dest' must be specified with both 'source' and 'translation' parameters
error.config.target_has_no_name=Required target 'name' field is missing in the configuration file
Expand Down
Loading

0 comments on commit 0cb25d6

Please sign in to comment.