Skip to content
Merged

Dev #138

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
20 changes: 10 additions & 10 deletions .github/workflows/build-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ jobs:
outputs:
version: ${{ steps.get-version.outputs.version }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
name: "Checkout"
- uses: actions/setup-java@v4
- uses: actions/setup-java@v6
name: "Install Java"
with:
java-version: '21'
Expand All @@ -39,13 +39,13 @@ jobs:
- name: 'Smoke test JAR'
run: ./scripts/smoke-test.sh java -jar target/simplelocalize-cli-${{env.VERSION}}.jar
- name: 'Upload artifact'
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: 'simplelocalize-cli-${{env.VERSION}}.jar'
path: 'target/simplelocalize-cli-${{env.VERSION}}.jar'
- name: 'Upload JAR to Release'
if: github.event_name == 'release'
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v3
with:
files: 'target/simplelocalize-cli-${{env.VERSION}}.jar'
env:
Expand Down Expand Up @@ -79,7 +79,7 @@ jobs:
downloadFilename: 'simplelocalize-cli-windows.exe'
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
name: "Checkout"
- name: "Print architecture"
run: uname -m
Expand All @@ -104,13 +104,13 @@ jobs:
codesign --force --deep --sign - ./target/${{ matrix.downloadFilename }}
codesign --verify --verbose ./target/${{ matrix.downloadFilename }}
- name: "Upload artifact"
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: simplelocalize-cli-${{ matrix.label }}
path: ./target/${{ matrix.downloadFilename }}
- name: 'Upload Executable to Release'
if: github.event_name == 'release'
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v3
with:
files: './target/${{ matrix.downloadFilename }}'
env:
Expand All @@ -122,7 +122,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: "Download all artifacts"
uses: actions/download-artifact@v4
uses: actions/download-artifact@v8
with:
path: dist
merge-multiple: true
Expand All @@ -131,13 +131,13 @@ jobs:
cd dist
zip -j "../simplelocalize-cli-${{ needs.build-jar.outputs.version }}.zip" *
- name: "Upload bundle artifact"
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: 'simplelocalize-cli-${{ needs.build-jar.outputs.version }}'
path: 'simplelocalize-cli-${{ needs.build-jar.outputs.version }}.zip'
- name: 'Upload bundle to Release'
if: github.event_name == 'release'
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v3
with:
files: 'simplelocalize-cli-${{ needs.build-jar.outputs.version }}.zip'
env:
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: actions/setup-java@v4
- uses: actions/setup-java@v6
name: "Install Java"
with:
java-version: '21'
distribution: 'corretto'
cache: 'maven'
- name: Cache SonarCloud packages
uses: actions/cache@v4
uses: actions/cache@v6
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/test-executables.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ jobs:
fail-fast: false
matrix:
os: [ macos-26, macos-26-intel, ubuntu-24.04-arm, ubuntu-latest ]
version: [ '2.10', '2.9', '2.8' ]
version: [ '2.11', '2.10' ]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v7
- name: Test on ${{ matrix.os }}
run: |
curl --fail -s https://get.simplelocalize.io/${{ matrix.version }}/install | bash
Expand All @@ -32,9 +32,9 @@ jobs:
fail-fast: false
matrix:
os: [ windows-latest ]
version: [ '2.10', '2.9', '2.8' ]
version: [ '2.11', '2.10' ]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v7
- name: Test on ${{ matrix.os }}
run: |
. { iwr -useb https://get.simplelocalize.io/${{ matrix.version }}/install-windows } | iex;
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ and it's a great tool for CI/CD pipelines and localization automation.
- [Synchronize files](https://simplelocalize.io/auto-translation/) - keep in sync all your translation files
- [Auto-translate](https://simplelocalize.io/auto-translation/) - auto-translate texts in seconds
- [Host translations](https://simplelocalize.io/translation-hosting/) - manage your hosted translations
- [GitHub Actions support](https://github.com/simplelocalize/github-action-cli/) - seemles integration with GitHub Actions
- [GitHub Actions support](https://github.com/simplelocalize/github-action-cli/) - seamless integration with GitHub Actions

## Installation

Expand Down
3 changes: 2 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>io.simplelocalize</groupId>
<artifactId>simplelocalize-cli</artifactId>
<version>2.11.1</version>
<version>2.12.0</version>
<packaging>jar</packaging>
<name>simplelocalize-cli</name>
<description>Official SimpleLocalize Command Line Interface</description>
Expand Down Expand Up @@ -254,6 +254,7 @@
<quickBuild>${graalvm.quickBuild}</quickBuild>
<buildArgs>
<arg>--no-fallback</arg>
<arg>-march=compatibility</arg>
<arg>--enable-http</arg>
<arg>--enable-https</arg>
<arg>-H:IncludeResources=logback.xml</arg>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ public void publish(

@Command(
name = "purge",
description = "Purge translations from Translation Hosting. Use 'simplelocalize purge --help' to learn more about the parameters.")
description = "Purge translations from the project. Use 'simplelocalize purge --help' to learn more about the parameters.")
public void purge(
@Option(names = {"--apiKey"}, description = "Project API Key") String apiKey,
@Option(names = {"--baseUrl"}, description = "(Optional) Set custom server URL") String baseUrl,
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/io/simplelocalize/cli/Version.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
public class Version
{

public static final String NUMBER = "2.11.1";
public static final String NUMBER = "2.12.0";

private Version()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,19 @@ private String prettyPrintJson(DocumentContext json) throws JsonProcessingExcept
return mapper.writeValueAsString(data);
}

public List<String> fetchMultiLanguageFileFormats() throws IOException, InterruptedException
{
URI uri = uriFactory.buildFileFormatsUri();
HttpRequest httpRequest = httpRequestFactory.createGetRequest(uri).build();
HttpResponse<String> httpResponse = httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());
if (httpResponse.statusCode() != 200)
{
throw new ApiRequestException(readErrorMessage(httpResponse));
}
DocumentContext json = JsonPath.parse(httpResponse.body());
return json.read("$.data.fileFormats[?(@.multiLanguageSupport == true)].value");
}

public List<DownloadableFile> exportFiles(ExportRequest exportRequest) throws IOException, InterruptedException
{
URI downloadUri = uriFactory.buildDownloadUri(exportRequest);
Expand Down Expand Up @@ -244,16 +257,22 @@ private void throwOnError(HttpResponse<?> httpResponse)
{
if (httpResponse.statusCode() != 200)
{
String message = tryReadErrorMessage(httpResponse);
if (StringUtils.isBlank(message))
{
message = "Unknown error, HTTP Status: " + httpResponse.statusCode();
}
String message = readErrorMessage(httpResponse);
log.error("Request failed: {}", message);
throw new ApiRequestException(message);
}
}

private String readErrorMessage(HttpResponse<?> httpResponse)
{
String message = tryReadErrorMessage(httpResponse);
if (StringUtils.isBlank(message))
{
message = "Unknown error, HTTP Status: " + httpResponse.statusCode();
}
return message;
}

private String tryReadErrorMessage(HttpResponse<?> httpResponse)
{
String stringBody = safeCastHttpBodyToString(httpResponse.body());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ public URI buildStacktraceUri()
return URI.create(baseUrl + "/cli/v1/stacktrace");
}

URI buildFileFormatsUri()
{
return URI.create(baseUrl + "/api/v1/file-formats");
}

URI buildGetRunningAutoTranslationJobsUri()
{
return URI.create(baseUrl + "/api/v2/jobs?status=RUNNING&type=AUTO_TRANSLATION");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.StringJoiner;

/**
* Single language mapping entry (configurable only via YAML configuration file, under mappings.lang).
* Maps a SimpleLocalize language key ({@code languageKey}) to the language name used in the
Expand All @@ -17,4 +19,13 @@ public class LanguageTransform
{
private String languageKey;
private String placeholder;

@Override
public String toString()
{
return new StringJoiner(", ", "(", ")")
.add("languageKey='" + languageKey + "'")
.add("placeholder='" + placeholder + "'")
.toString();
}
}
53 changes: 45 additions & 8 deletions src/main/java/io/simplelocalize/cli/command/UploadCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import java.util.Locale;

public class UploadCommand implements CliCommand
{
private static final Logger log = LoggerFactory.getLogger(UploadCommand.class);
private static final List<String> FALLBACK_MULTI_LANGUAGE_FILE_FORMATS = List.of("multi-language-json", "project-json", "excel", "csv-translations", "tsv", "localizable-xcstrings");
private final FileListReader fileListReader = new FileListReader();
private final SimpleLocalizeClient client;
private final Configuration configuration;
Expand Down Expand Up @@ -215,32 +217,67 @@ private void validateConfiguration(Configuration configuration)
throw new ConfigurationException("You cannot use {ns} placeholder in uploadPath and namespace parameter at the same time");
}

final boolean isMultiLanguage = isMultiLanguage(configuration);
if (isMultiLanguage && hasLanguagePlaceholder)
if (hasLanguagePlaceholder && isMultiLanguage(configuration))
{
throw new ConfigurationException("You cannot use language key parameter with multi-language file formats");
}
}

private boolean isMultiLanguage(Configuration configuration)
{
final List<String> multiLanguageFileFormats = List.of("multi-language-json", "excel", "csv-translations", "tsv", "localizable-xcstrings");
for (String uploadFormat : multiLanguageFileFormats)
final List<String> uploadOptions = configuration.getUploadOptions();
for (String uploadOption : uploadOptions)
{
if (uploadFormat.equalsIgnoreCase(configuration.getUploadFormat()))
if (uploadOption.equalsIgnoreCase("MULTI_LANGUAGE"))
{
return true;
}
}

final List<String> uploadOptions = configuration.getUploadOptions();
for (String uploadOption : uploadOptions)
final String uploadFormat = normalizeFileFormat(configuration.getUploadFormat());
for (String multiLanguageFileFormat : getMultiLanguageFileFormats())
{
if (uploadOption.equalsIgnoreCase("MULTI_LANGUAGE"))
if (normalizeFileFormat(multiLanguageFileFormat).equals(uploadFormat))
{
return true;
}
}
return false;
}

private String normalizeFileFormat(String fileFormat)
{
if (fileFormat == null)
{
return "";
}
return fileFormat.toLowerCase(Locale.ROOT).replaceAll("[^a-z0-9]", "");
}

private List<String> getMultiLanguageFileFormats()
{
try
{
final List<String> fileFormats = client.fetchMultiLanguageFileFormats();
if (fileFormats != null && !fileFormats.isEmpty())
{
return fileFormats;
}
log.warn("Could not load multi-language file formats from the API (empty response), using the list built into this CLI version");
} catch (InterruptedException e)
{
Thread.currentThread().interrupt();
logFileFormatsFallback(e);
} catch (Exception e)
{
logFileFormatsFallback(e);
}
return FALLBACK_MULTI_LANGUAGE_FILE_FORMATS;
}

private void logFileFormatsFallback(Exception e)
{
final String reason = StringUtils.isNotEmpty(e.getMessage()) ? e.getMessage() : e.getClass().getSimpleName();
log.warn("Could not load multi-language file formats from the API ({}), using the list built into this CLI version", reason);
}
}
Loading
Loading