From 0cddd96728dac277d415545019e432e255c7d3a4 Mon Sep 17 00:00:00 2001 From: Jan Cizmar Date: Wed, 5 Feb 2025 11:39:01 +0100 Subject: [PATCH 1/5] feat: Add Apple xc strings --- package.json | 2 +- schema.json | 1 + src/client/internal/schema.generated.ts | 14 ++-- src/options.ts | 1 + src/schema.d.ts | 1 + src/utils/mapExportFormat.ts | 2 + src/utils/mapImportFormat.ts | 2 + .../apple-xcstrings.json | 12 +++ .../apple-xcstrings/Localizable.xcstrings | 79 +++++++++++++++++++ test/e2e/formats.test.ts | 9 +++ 10 files changed, 116 insertions(+), 7 deletions(-) create mode 100644 test/__fixtures__/differentFormatsProject/apple-xcstrings.json create mode 100644 test/__fixtures__/differentFormatsProject/apple-xcstrings/Localizable.xcstrings diff --git a/package.json b/package.json index 032be14e..a0f1198a 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "eslint": "eslint --max-warnings 0", "format": "eslint --fix", "run-dev": "tsx ./src/cli.ts", - "schema": "openapi-typescript http://localhost:22222/v3/api-docs/All%20Internal%20-%20for%20Tolgee%20Web%20application --output src/client/internal/schema.generated.ts", + "schema": "openapi-typescript http://localhost:8080/v3/api-docs/All%20Internal%20-%20for%20Tolgee%20Web%20application --output src/client/internal/schema.generated.ts", "release": "semantic-release", "config:type": "tsx scripts/configType.ts" }, diff --git a/schema.json b/schema.json index fdede985..199dfaf0 100644 --- a/schema.json +++ b/schema.json @@ -251,6 +251,7 @@ "PO_PYTHON", "APPLE_STRINGS", "APPLE_XLIFF", + "APPLE_XCSTRINGS", "PROPERTIES_ICU", "PROPERTIES_JAVA", "ANDROID_XML", diff --git a/src/client/internal/schema.generated.ts b/src/client/internal/schema.generated.ts index 9031ba78..d943a4eb 100644 --- a/src/client/internal/schema.generated.ts +++ b/src/client/internal/schema.generated.ts @@ -4639,7 +4639,7 @@ export interface components { * @description Format to export to * @enum {string} */ - format: "JSON" | "JSON_TOLGEE" | "XLIFF" | "PO" | "APPLE_STRINGS_STRINGSDICT" | "APPLE_XLIFF" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "PROPERTIES" | "YAML_RUBY" | "YAML" | "JSON_I18NEXT" | "CSV" | "RESX_ICU" | "XLSX"; + format: "JSON" | "JSON_TOLGEE" | "XLIFF" | "PO" | "APPLE_STRINGS_STRINGSDICT" | "APPLE_XLIFF" | "APPLE_XCSTRINGS" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "PROPERTIES" | "YAML_RUBY" | "YAML" | "JSON_I18NEXT" | "CSV" | "RESX_ICU" | "XLSX"; /** Format: int64 */ id: number; /** @@ -4723,7 +4723,7 @@ export interface components { * @description Format to export to * @enum {string} */ - format: "JSON" | "JSON_TOLGEE" | "XLIFF" | "PO" | "APPLE_STRINGS_STRINGSDICT" | "APPLE_XLIFF" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "PROPERTIES" | "YAML_RUBY" | "YAML" | "JSON_I18NEXT" | "CSV" | "RESX_ICU" | "XLSX"; + format: "JSON" | "JSON_TOLGEE" | "XLIFF" | "PO" | "APPLE_STRINGS_STRINGSDICT" | "APPLE_XLIFF" | "APPLE_XCSTRINGS" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "PROPERTIES" | "YAML_RUBY" | "YAML" | "JSON_I18NEXT" | "CSV" | "RESX_ICU" | "XLSX"; /** * @description Languages to be contained in export. * @@ -4973,7 +4973,7 @@ export interface components { defaultFileStructureTemplate: string; extension: string; /** @enum {string} */ - format: "JSON" | "JSON_TOLGEE" | "XLIFF" | "PO" | "APPLE_STRINGS_STRINGSDICT" | "APPLE_XLIFF" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "PROPERTIES" | "YAML_RUBY" | "YAML" | "JSON_I18NEXT" | "CSV" | "RESX_ICU" | "XLSX"; + format: "JSON" | "JSON_TOLGEE" | "XLIFF" | "PO" | "APPLE_STRINGS_STRINGSDICT" | "APPLE_XLIFF" | "APPLE_XCSTRINGS" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "PROPERTIES" | "YAML_RUBY" | "YAML" | "JSON_I18NEXT" | "CSV" | "RESX_ICU" | "XLSX"; mediaType: string; }; ExportParams: { @@ -5013,7 +5013,7 @@ export interface components { * @description Format to export to * @enum {string} */ - format: "JSON" | "JSON_TOLGEE" | "XLIFF" | "PO" | "APPLE_STRINGS_STRINGSDICT" | "APPLE_XLIFF" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "PROPERTIES" | "YAML_RUBY" | "YAML" | "JSON_I18NEXT" | "CSV" | "RESX_ICU" | "XLSX"; + format: "JSON" | "JSON_TOLGEE" | "XLIFF" | "PO" | "APPLE_STRINGS_STRINGSDICT" | "APPLE_XLIFF" | "APPLE_XCSTRINGS" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "PROPERTIES" | "YAML_RUBY" | "YAML" | "JSON_I18NEXT" | "CSV" | "RESX_ICU" | "XLSX"; /** * @description Languages to be contained in export. * @@ -5091,7 +5091,7 @@ export interface components { * It is recommended to provide these values to prevent any issues with format detection. * @enum {string} */ - format?: "CSV_ICU" | "CSV_JAVA" | "CSV_PHP" | "CSV_RUBY" | "JSON_I18NEXT" | "JSON_ICU" | "JSON_JAVA" | "JSON_PHP" | "JSON_RUBY" | "JSON_C" | "PO_PHP" | "PO_C" | "PO_JAVA" | "PO_ICU" | "PO_RUBY" | "PO_PYTHON" | "STRINGS" | "STRINGSDICT" | "APPLE_XLIFF" | "PROPERTIES_ICU" | "PROPERTIES_JAVA" | "PROPERTIES_UNKNOWN" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "YAML_RUBY" | "YAML_JAVA" | "YAML_ICU" | "YAML_PHP" | "YAML_UNKNOWN" | "XLIFF_ICU" | "XLIFF_JAVA" | "XLIFF_PHP" | "XLIFF_RUBY" | "RESX_ICU" | "XLSX_ICU" | "XLSX_JAVA" | "XLSX_PHP" | "XLSX_RUBY"; + format?: "CSV_ICU" | "CSV_JAVA" | "CSV_PHP" | "CSV_RUBY" | "JSON_I18NEXT" | "JSON_ICU" | "JSON_JAVA" | "JSON_PHP" | "JSON_RUBY" | "JSON_C" | "PO_PHP" | "PO_C" | "PO_JAVA" | "PO_ICU" | "PO_RUBY" | "PO_PYTHON" | "STRINGS" | "STRINGSDICT" | "APPLE_XLIFF" | "XCSTRINGS" | "PROPERTIES_ICU" | "PROPERTIES_JAVA" | "PROPERTIES_UNKNOWN" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "YAML_RUBY" | "YAML_JAVA" | "YAML_ICU" | "YAML_PHP" | "YAML_UNKNOWN" | "XLIFF_ICU" | "XLIFF_JAVA" | "XLIFF_PHP" | "XLIFF_RUBY" | "RESX_ICU" | "XLSX_ICU" | "XLSX_JAVA" | "XLSX_PHP" | "XLSX_RUBY"; /** @description The existing language tag in the Tolgee platform to which the imported language should be mapped. * * When null, Tolgee will try to guess the language from the file contents or file name. */ @@ -6595,6 +6595,8 @@ export interface components { id: number; keyReferences: components["schemas"]["KeyInScreenshotModel"][]; location?: string; + middleSized?: string; + middleSizedUrl?: string; /** @description Thumbnail file name, which may be downloaded from the screenshot path. * * When images are secured. Encrypted timestamp is appended to the filename. @@ -13928,7 +13930,7 @@ export interface operations { */ languages?: string[]; /** @description Format to export to */ - format?: "JSON" | "JSON_TOLGEE" | "XLIFF" | "PO" | "APPLE_STRINGS_STRINGSDICT" | "APPLE_XLIFF" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "PROPERTIES" | "YAML_RUBY" | "YAML" | "JSON_I18NEXT" | "CSV" | "RESX_ICU" | "XLSX"; + format?: "JSON" | "JSON_TOLGEE" | "XLIFF" | "PO" | "APPLE_STRINGS_STRINGSDICT" | "APPLE_XLIFF" | "APPLE_XCSTRINGS" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "PROPERTIES" | "YAML_RUBY" | "YAML" | "JSON_I18NEXT" | "CSV" | "RESX_ICU" | "XLSX"; /** @description Delimiter to structure file content. * * e.g. For key "home.header.title" would result in {"home": {"header": "title": {"Hello"}}} structure. diff --git a/src/options.ts b/src/options.ts index 98923f66..cf72be4e 100644 --- a/src/options.ts +++ b/src/options.ts @@ -84,6 +84,7 @@ export const FORMAT_OPT = new Option( 'PO_PYTHON', 'APPLE_STRINGS', 'APPLE_XLIFF', + 'APPLE_XCSTRINGS', 'PROPERTIES_ICU', 'PROPERTIES_JAVA', 'ANDROID_XML', diff --git a/src/schema.d.ts b/src/schema.d.ts index e961e43a..1886ed89 100644 --- a/src/schema.d.ts +++ b/src/schema.d.ts @@ -24,6 +24,7 @@ export type Format = | "PO_PYTHON" | "APPLE_STRINGS" | "APPLE_XLIFF" + | "APPLE_XCSTRINGS" | "PROPERTIES_ICU" | "PROPERTIES_JAVA" | "ANDROID_XML" diff --git a/src/utils/mapExportFormat.ts b/src/utils/mapExportFormat.ts index 00834ede..7a3eef46 100644 --- a/src/utils/mapExportFormat.ts +++ b/src/utils/mapExportFormat.ts @@ -17,6 +17,8 @@ export const mapExportFormat = (format: Schema['format']): FormatResult => { }; case 'APPLE_XLIFF': return { format: 'APPLE_XLIFF', messageFormat: 'APPLE_SPRINTF' }; + case 'APPLE_XCSTRINGS': + return { format: 'APPLE_XCSTRINGS', messageFormat: 'APPLE_SPRINTF' }; case 'COMPOSE_XML': return { format: 'COMPOSE_XML', messageFormat: 'JAVA_STRING_FORMAT' }; case 'FLUTTER_ARB': diff --git a/src/utils/mapImportFormat.ts b/src/utils/mapImportFormat.ts index 2edf7b59..fd7b89bf 100644 --- a/src/utils/mapImportFormat.ts +++ b/src/utils/mapImportFormat.ts @@ -8,6 +8,8 @@ export const mapImportFormat = ( extension: string ): FormatResult => { switch (format) { + case 'APPLE_XCSTRINGS': + return 'XCSTRINGS'; case 'APPLE_STRINGS': { // apple separates translations to two separate files // we keep it under one format for the cli diff --git a/test/__fixtures__/differentFormatsProject/apple-xcstrings.json b/test/__fixtures__/differentFormatsProject/apple-xcstrings.json new file mode 100644 index 00000000..39e709b1 --- /dev/null +++ b/test/__fixtures__/differentFormatsProject/apple-xcstrings.json @@ -0,0 +1,12 @@ +{ + "$schema": "../../../schema.json", + "format": "APPLE_XCSTRINGS", + "push": { + "files": [ + { + "path": "./apple-xcstrings/Localizable.xcstrings", + "language": "en" + } + ] + } +} diff --git a/test/__fixtures__/differentFormatsProject/apple-xcstrings/Localizable.xcstrings b/test/__fixtures__/differentFormatsProject/apple-xcstrings/Localizable.xcstrings new file mode 100644 index 00000000..477a4593 --- /dev/null +++ b/test/__fixtures__/differentFormatsProject/apple-xcstrings/Localizable.xcstrings @@ -0,0 +1,79 @@ +{ + "sourceLanguage" : "cs", + "strings" : { + "dog_count" : { + "localizations" : { + "cs" : { + "variations" : { + "plural" : { + "few" : { + "stringUnit" : { + "state" : "translated", + "value" : "Já mám %lli psi." + } + }, + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Já mám jednoho psa." + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Já mám %lli psů." + } + } + } + } + }, + "en" : { + "variations" : { + "plural" : { + "other" : { + "stringUnit" : { + "state" : "needs_review", + "value" : "I have %%lli dogs." + } + } + } + } + } + } + }, + "my_mom" : { + "extractionState" : "manual", + "localizations" : { + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tohle je moje máma!" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This is my mom!" + } + } + } + }, + "test_key" : { + "localizations" : { + "cs" : { + "stringUnit" : { + "state" : "translated", + "value" : "O muj boze!" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Oh my god!" + } + } + } + } + }, + "version" : "1.0" +} \ No newline at end of file diff --git a/test/e2e/formats.test.ts b/test/e2e/formats.test.ts index f93c139f..22305ffb 100644 --- a/test/e2e/formats.test.ts +++ b/test/e2e/formats.test.ts @@ -141,6 +141,15 @@ describe('push and pull with different formats', () => { }); }); + it('works with Apple xcstrings (StringCatalog) format', async () => { + await testWithConfig({ + config: 'apple-xcstrings', + inPlatform: 'This is my mom!', + fileLocation: 'Localizable.strings', + inFile: 'I have %%lli dogs.', + }); + }); + it('works with android-xml icu format', async () => { await testWithConfig({ config: 'android-xml', From f6e5fc98dcb11a101796fa819e2ef61971450596 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0t=C4=9Bp=C3=A1n=20Gran=C3=A1t?= Date: Wed, 26 Feb 2025 16:43:49 +0100 Subject: [PATCH 2/5] fix: provide description for language field --- package.json | 2 +- schema.json | 7 +- src/client/internal/schema.generated.ts | 357 +++++++++++++++++- src/commands/push.ts | 16 +- src/utils/mapImportFormat.ts | 2 - .../apple-xcstrings.json | 3 +- .../apple-xcstrings/Localizable.xcstrings | 62 +-- test/e2e/formats.test.ts | 14 +- test/e2e/utils/run.ts | 6 +- 9 files changed, 373 insertions(+), 96 deletions(-) diff --git a/package.json b/package.json index a0f1198a..032be14e 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "eslint": "eslint --max-warnings 0", "format": "eslint --fix", "run-dev": "tsx ./src/cli.ts", - "schema": "openapi-typescript http://localhost:8080/v3/api-docs/All%20Internal%20-%20for%20Tolgee%20Web%20application --output src/client/internal/schema.generated.ts", + "schema": "openapi-typescript http://localhost:22222/v3/api-docs/All%20Internal%20-%20for%20Tolgee%20Web%20application --output src/client/internal/schema.generated.ts", "release": "semantic-release", "config:type": "tsx scripts/configType.ts" }, diff --git a/schema.json b/schema.json index 199dfaf0..75f1bbc2 100644 --- a/schema.json +++ b/schema.json @@ -219,10 +219,13 @@ "type": "object", "properties": { "path": { "$ref": "#/$defs/path" }, - "language": { "type": "string" }, + "language": { + "description": "Explicitly map file to language.\n\nIf not provided backend will try to detect language from language name or it's content.", + "type": "string" + }, "namespace": { "type": "string" } }, - "required": ["path", "language"] + "required": ["path"] }, "forceMode": { "description": "Specifies how to solve potential conflicts in the pushed data.\n\nOptions:\n\n `OVERRIDE` - update everything according to local files\n `KEEP` - create only non-existent strings, don't touch existing ones\n `NO_FORCE` - throw an error, if there are any conflict", diff --git a/src/client/internal/schema.generated.ts b/src/client/internal/schema.generated.ts index d943a4eb..8524e15a 100644 --- a/src/client/internal/schema.generated.ts +++ b/src/client/internal/schema.generated.ts @@ -507,6 +507,74 @@ export interface paths { patch?: never; trace?: never; }; + "/v2/auth-provider/changed": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get info about authentication provider which can replace the current one */ + get: operations["getChangedAuthProvider"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v2/auth-provider/changed/accept": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Accept change of the third party authentication provider */ + post: operations["acceptChangeAuthProvider"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v2/auth-provider/changed/reject": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Reject change of the third party authentication provider */ + post: operations["rejectChangeAuthProvider"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/v2/auth-provider/current": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get current third party authentication provider */ + get: operations["getCurrentAuthProvider"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; "/v2/ee-license/info": { parameters: { query?: never; @@ -4285,6 +4353,13 @@ export interface components { ssoGlobal: components["schemas"]["SsoGlobalPublicConfigDTO"]; ssoOrganizations: components["schemas"]["SsoOrganizationsPublicConfigDTO"]; }; + AuthProviderDto: { + /** @enum {string} */ + accountType?: "LOCAL" | "MANAGED" | "THIRD_PARTY"; + /** @enum {string} */ + authType?: "GOOGLE" | "GITHUB" | "OAUTH2" | "SSO" | "SSO_GLOBAL"; + ssoDomain?: string; + }; AutoTranslationConfigModel: { /** @description If true, import will trigger batch operation to translate the new new keys. * It includes also the data imported via CLI, Figma, or other integrations using batch key import. */ @@ -4362,7 +4437,7 @@ export interface components { * @description Type of the batch job * @enum {string} */ - type: "PRE_TRANSLATE_BT_TM" | "MACHINE_TRANSLATE" | "AUTO_TRANSLATE" | "DELETE_KEYS" | "SET_TRANSLATIONS_STATE" | "CLEAR_TRANSLATIONS" | "COPY_TRANSLATIONS" | "TAG_KEYS" | "UNTAG_KEYS" | "SET_KEYS_NAMESPACE" | "AUTOMATION"; + type: "PRE_TRANSLATE_BT_TM" | "MACHINE_TRANSLATE" | "AUTO_TRANSLATE" | "DELETE_KEYS" | "SET_TRANSLATIONS_STATE" | "CLEAR_TRANSLATIONS" | "COPY_TRANSLATIONS" | "TAG_KEYS" | "UNTAG_KEYS" | "SET_KEYS_NAMESPACE" | "AUTOMATION" | "BILLING_TRIAL_EXPIRATION_NOTICE"; /** * Format: int64 * @description The time when the job was last updated (status change) @@ -4639,7 +4714,7 @@ export interface components { * @description Format to export to * @enum {string} */ - format: "JSON" | "JSON_TOLGEE" | "XLIFF" | "PO" | "APPLE_STRINGS_STRINGSDICT" | "APPLE_XLIFF" | "APPLE_XCSTRINGS" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "PROPERTIES" | "YAML_RUBY" | "YAML" | "JSON_I18NEXT" | "CSV" | "RESX_ICU" | "XLSX"; + format: "JSON" | "JSON_TOLGEE" | "XLIFF" | "PO" | "APPLE_STRINGS_STRINGSDICT" | "APPLE_XLIFF" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "PROPERTIES" | "YAML_RUBY" | "YAML" | "JSON_I18NEXT" | "CSV" | "RESX_ICU" | "XLSX" | "APPLE_XCSTRINGS"; /** Format: int64 */ id: number; /** @@ -4723,7 +4798,7 @@ export interface components { * @description Format to export to * @enum {string} */ - format: "JSON" | "JSON_TOLGEE" | "XLIFF" | "PO" | "APPLE_STRINGS_STRINGSDICT" | "APPLE_XLIFF" | "APPLE_XCSTRINGS" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "PROPERTIES" | "YAML_RUBY" | "YAML" | "JSON_I18NEXT" | "CSV" | "RESX_ICU" | "XLSX"; + format: "JSON" | "JSON_TOLGEE" | "XLIFF" | "PO" | "APPLE_STRINGS_STRINGSDICT" | "APPLE_XLIFF" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "PROPERTIES" | "YAML_RUBY" | "YAML" | "JSON_I18NEXT" | "CSV" | "RESX_ICU" | "XLSX" | "APPLE_XCSTRINGS"; /** * @description Languages to be contained in export. * @@ -4858,6 +4933,7 @@ export interface components { clientSecret: string; domain: string; enabled: boolean; + force: boolean; tokenUri: string; }; CreateTaskRequest: { @@ -4885,7 +4961,13 @@ export interface components { bucketSize: number; /** Format: int64 */ creditBalance: number; - /** Format: int64 */ + /** + * Format: int64 + * @deprecated + * @description Customers were able to buy extra credits separately in the past. + * + * This option is not available anymore and this field is kept only for backward compatibility purposes and is always 0. + */ extraCreditBalance: number; }; DeleteKeysDto: { @@ -4938,7 +5020,7 @@ export interface components { name: string; nonCommerical: boolean; /** @enum {string} */ - status: "ACTIVE" | "CANCELED" | "PAST_DUE" | "UNPAID" | "ERROR" | "KEY_USED_BY_ANOTHER_INSTANCE"; + status: "ACTIVE" | "CANCELED" | "PAST_DUE" | "UNPAID" | "ERROR" | "TRIALING" | "KEY_USED_BY_ANOTHER_INSTANCE" | "UNKNOWN"; }; EntityDescriptionWithRelations: { data: { @@ -4954,7 +5036,7 @@ export interface components { }; ErrorResponseTyped: { /** @enum {string} */ - code: "unauthenticated" | "api_access_forbidden" | "api_key_not_found" | "invalid_api_key" | "invalid_project_api_key" | "project_api_key_expired" | "bad_credentials" | "mfa_enabled" | "invalid_otp_code" | "mfa_not_enabled" | "can_not_revoke_own_permissions" | "data_corrupted" | "invitation_code_does_not_exist_or_expired" | "language_tag_exists" | "language_name_exists" | "language_not_found" | "operation_not_permitted" | "registrations_not_allowed" | "project_not_found" | "resource_not_found" | "scope_not_found" | "key_exists" | "third_party_auth_error_message" | "third_party_auth_no_email" | "third_party_auth_no_sub" | "third_party_auth_unknown_error" | "email_already_verified" | "third_party_unauthorized" | "third_party_google_workspace_mismatch" | "username_already_exists" | "username_or_password_invalid" | "user_already_has_permissions" | "user_already_has_role" | "user_not_found" | "file_not_image" | "file_too_big" | "invalid_timestamp" | "email_not_verified" | "missing_callback_url" | "invalid_jwt_token" | "expired_jwt_token" | "general_jwt_error" | "cannot_find_suitable_address_part" | "address_part_not_unique" | "user_is_not_member_of_organization" | "organization_has_no_other_owner" | "user_has_no_project_access" | "user_is_organization_owner" | "cannot_set_your_own_permissions" | "user_is_organization_member" | "property_not_mutable" | "import_language_not_from_project" | "existing_language_not_selected" | "conflict_is_not_resolved" | "language_already_selected" | "cannot_parse_file" | "could_not_resolve_property" | "cannot_add_more_then_100_languages" | "no_languages_provided" | "language_with_base_language_tag_not_found" | "language_not_from_project" | "namespace_not_from_project" | "cannot_delete_base_language" | "key_not_from_project" | "max_screenshots_exceeded" | "translation_not_from_project" | "can_edit_only_own_comment" | "request_parse_error" | "filter_by_value_state_not_valid" | "import_has_expired" | "tag_not_from_project" | "translation_text_too_long" | "invalid_recaptcha_token" | "cannot_leave_owning_project" | "cannot_leave_project_with_organization_role" | "dont_have_direct_permissions" | "tag_too_log" | "too_many_uploaded_images" | "one_or_more_images_not_found" | "screenshot_not_of_key" | "service_not_found" | "too_many_requests" | "translation_not_found" | "out_of_credits" | "key_not_found" | "organization_not_found" | "cannot_find_base_language" | "base_language_not_found" | "no_exported_result" | "cannot_set_your_own_role" | "only_translate_review_or_view_permission_accepts_view_languages" | "oauth2_token_url_not_set" | "oauth2_user_url_not_set" | "email_already_invited_or_member" | "price_not_found" | "invoice_not_from_organization" | "invoice_not_found" | "plan_not_found" | "plan_not_available_any_more" | "no_auto_translation_method" | "cannot_translate_base_language" | "pat_not_found" | "invalid_pat" | "pat_expired" | "operation_unavailable_for_account_type" | "validation_email_is_not_valid" | "current_password_required" | "cannot_create_organization" | "wrong_current_password" | "wrong_param_type" | "expired_super_jwt_token" | "cannot_delete_your_own_account" | "cannot_sort_by_this_column" | "namespace_not_found" | "namespace_exists" | "invalid_authentication_method" | "unknown_sort_property" | "only_review_permission_accepts_state_change_languages" | "only_translate_or_review_permission_accepts_translate_languages" | "cannot_set_language_permissions_for_admin_scope" | "cannot_set_view_languages_without_translations_view_scope" | "cannot_set_translate_languages_without_translations_edit_scope" | "cannot_set_state_change_languages_without_translations_state_edit_scope" | "language_not_permitted" | "scopes_has_to_be_set" | "set_exactly_one_of_scopes_or_type" | "translation_exists" | "import_keys_error" | "provide_only_one_of_screenshots_and_screenshot_uploaded_image_ids" | "multiple_projects_not_supported" | "plan_translation_limit_exceeded" | "feature_not_enabled" | "license_key_not_found" | "cannot_set_view_languages_without_for_level_based_permissions" | "cannot_set_different_translate_and_state_change_languages_for_level_based_permissions" | "cannot_disable_your_own_account" | "subscription_not_found" | "invoice_does_not_have_usage" | "customer_not_found" | "subscription_not_active" | "organization_already_subscribed" | "organization_not_subscribed" | "license_key_used_by_another_instance" | "translation_spending_limit_exceeded" | "credit_spending_limit_exceeded" | "seats_spending_limit_exceeded" | "this_instance_is_already_licensed" | "big_meta_not_from_project" | "mt_service_not_enabled" | "project_not_selected" | "organization_not_selected" | "plan_has_subscribers" | "translation_failed" | "batch_job_not_found" | "key_exists_in_namespace" | "tag_is_blank" | "execution_failed_on_management_error" | "translation_api_rate_limit" | "cannot_finalize_activity" | "formality_not_supported_by_service" | "language_not_supported_by_service" | "rate_limited" | "pat_access_not_allowed" | "pak_access_not_allowed" | "cannot_modify_disabled_translation" | "azure_config_required" | "s3_config_required" | "content_storage_config_required" | "content_storage_test_failed" | "content_storage_config_invalid" | "invalid_connection_string" | "cannot_create_azure_storage_client" | "s3_access_key_required" | "azure_connection_string_required" | "s3_secret_key_required" | "cannot_store_file_to_content_storage" | "unexpected_error_while_publishing_to_content_storage" | "webhook_responded_with_non_200_status" | "unexpected_error_while_executing_webhook" | "content_storage_is_in_use" | "cannot_set_state_for_missing_translation" | "no_project_id_provided" | "license_key_not_provided" | "subscription_already_canceled" | "user_is_subscribed_to_paid_plan" | "cannot_create_free_plan_without_fixed_type" | "cannot_modify_plan_free_status" | "key_id_not_provided" | "free_self_hosted_seat_limit_exceeded" | "advanced_params_not_supported" | "plural_forms_not_found_for_language" | "nested_plurals_not_supported" | "message_is_not_plural" | "content_outside_plural_forms" | "invalid_plural_form" | "multiple_plurals_not_supported" | "custom_values_json_too_long" | "unsupported_po_message_format" | "plural_forms_data_loss" | "current_user_does_not_own_image" | "user_cannot_view_this_organization" | "user_is_not_owner_of_organization" | "pak_created_for_different_project" | "custom_slug_is_only_applicable_for_custom_storage" | "invalid_slug_format" | "batch_job_cancellation_timeout" | "import_failed" | "cannot_add_more_then_1000_languages" | "no_data_to_import" | "multiple_namespaces_mapped_to_single_file" | "multiple_mappings_for_same_file_language_name" | "multiple_mappings_for_null_file_language_name" | "too_many_mappings_for_file" | "missing_placeholder_in_template" | "tag_not_found" | "cannot_parse_encrypted_slack_login_data" | "slack_workspace_not_found" | "cannot_fetch_user_details_from_slack" | "slack_missing_scope" | "slack_not_connected_to_your_account" | "slack_invalid_command" | "slack_not_subscribed_yet" | "slack_connection_failed" | "tolgee_account_already_connected" | "slack_not_configured" | "slack_workspace_already_connected" | "slack_connection_error" | "email_verification_code_not_valid" | "cannot_subscribe_to_free_plan" | "plan_auto_assignment_only_for_free_plans" | "plan_auto_assignment_only_for_private_plans" | "plan_auto_assignment_organization_ids_not_in_for_organization_ids" | "task_not_found" | "task_not_finished" | "task_not_open" | "translation_agency_not_found" | "this_feature_is_not_implemented_in_oss" | "sso_token_exchange_failed" | "sso_user_info_retrieval_failed" | "sso_id_token_expired" | "sso_user_cannot_create_organization" | "sso_cant_verify_user" | "sso_auth_missing_domain" | "sso_domain_not_found_or_disabled" | "native_authentication_disabled" | "invitation_organization_mismatch" | "user_is_managed_by_organization" | "cannot_set_sso_provider_missing_fields" | "namespaces_cannot_be_disabled_when_namespace_exists" | "namespace_cannot_be_used_when_feature_is_disabled"; + code: "unauthenticated" | "api_access_forbidden" | "api_key_not_found" | "invalid_api_key" | "invalid_project_api_key" | "project_api_key_expired" | "bad_credentials" | "mfa_enabled" | "invalid_otp_code" | "mfa_not_enabled" | "can_not_revoke_own_permissions" | "data_corrupted" | "invitation_code_does_not_exist_or_expired" | "language_tag_exists" | "language_name_exists" | "language_not_found" | "operation_not_permitted" | "registrations_not_allowed" | "project_not_found" | "resource_not_found" | "scope_not_found" | "key_exists" | "third_party_auth_error_message" | "third_party_auth_no_email" | "third_party_auth_non_matching_email" | "third_party_auth_no_sub" | "third_party_auth_unknown_error" | "email_already_verified" | "third_party_unauthorized" | "third_party_google_workspace_mismatch" | "third_party_switch_initiated" | "username_already_exists" | "username_or_password_invalid" | "user_already_has_permissions" | "user_already_has_role" | "user_not_found" | "file_not_image" | "file_too_big" | "invalid_timestamp" | "email_not_verified" | "missing_callback_url" | "invalid_jwt_token" | "expired_jwt_token" | "general_jwt_error" | "cannot_find_suitable_address_part" | "slug_not_unique" | "user_is_not_member_of_organization" | "organization_has_no_other_owner" | "user_has_no_project_access" | "user_is_organization_owner" | "cannot_set_your_own_permissions" | "user_is_organization_member" | "property_not_mutable" | "import_language_not_from_project" | "existing_language_not_selected" | "conflict_is_not_resolved" | "language_already_selected" | "cannot_parse_file" | "could_not_resolve_property" | "cannot_add_more_then_100_languages" | "no_languages_provided" | "language_with_base_language_tag_not_found" | "language_not_from_project" | "namespace_not_from_project" | "cannot_delete_base_language" | "key_not_from_project" | "max_screenshots_exceeded" | "translation_not_from_project" | "can_edit_only_own_comment" | "request_parse_error" | "filter_by_value_state_not_valid" | "import_has_expired" | "tag_not_from_project" | "translation_text_too_long" | "invalid_recaptcha_token" | "cannot_leave_owning_project" | "cannot_leave_project_with_organization_role" | "dont_have_direct_permissions" | "tag_too_log" | "too_many_uploaded_images" | "one_or_more_images_not_found" | "screenshot_not_of_key" | "service_not_found" | "too_many_requests" | "translation_not_found" | "out_of_credits" | "key_not_found" | "organization_not_found" | "cannot_find_base_language" | "base_language_not_found" | "no_exported_result" | "cannot_set_your_own_role" | "only_translate_review_or_view_permission_accepts_view_languages" | "oauth2_token_url_not_set" | "oauth2_user_url_not_set" | "email_already_invited_or_member" | "price_not_found" | "invoice_not_from_organization" | "invoice_not_found" | "plan_not_found" | "plan_not_available_any_more" | "no_auto_translation_method" | "cannot_translate_base_language" | "pat_not_found" | "invalid_pat" | "pat_expired" | "operation_unavailable_for_account_type" | "validation_email_is_not_valid" | "current_password_required" | "cannot_create_organization" | "wrong_current_password" | "wrong_param_type" | "expired_super_jwt_token" | "cannot_delete_your_own_account" | "cannot_sort_by_this_column" | "namespace_not_found" | "namespace_exists" | "invalid_authentication_method" | "unknown_sort_property" | "only_review_permission_accepts_state_change_languages" | "only_translate_or_review_permission_accepts_translate_languages" | "cannot_set_language_permissions_for_admin_scope" | "cannot_set_view_languages_without_translations_view_scope" | "cannot_set_translate_languages_without_translations_edit_scope" | "cannot_set_state_change_languages_without_translations_state_edit_scope" | "language_not_permitted" | "scopes_has_to_be_set" | "set_exactly_one_of_scopes_or_type" | "translation_exists" | "import_keys_error" | "provide_only_one_of_screenshots_and_screenshot_uploaded_image_ids" | "multiple_projects_not_supported" | "plan_translation_limit_exceeded" | "feature_not_enabled" | "license_key_not_found" | "cannot_set_view_languages_without_for_level_based_permissions" | "cannot_set_different_translate_and_state_change_languages_for_level_based_permissions" | "cannot_disable_your_own_account" | "subscription_not_found" | "invoice_does_not_have_usage" | "customer_not_found" | "subscription_not_active" | "organization_already_subscribed" | "organization_not_subscribed" | "license_key_used_by_another_instance" | "translation_spending_limit_exceeded" | "credit_spending_limit_exceeded" | "seats_spending_limit_exceeded" | "this_instance_is_already_licensed" | "big_meta_not_from_project" | "mt_service_not_enabled" | "project_not_selected" | "organization_not_selected" | "plan_has_subscribers" | "translation_failed" | "batch_job_not_found" | "key_exists_in_namespace" | "tag_is_blank" | "execution_failed_on_management_error" | "translation_api_rate_limit" | "cannot_finalize_activity" | "formality_not_supported_by_service" | "language_not_supported_by_service" | "rate_limited" | "pat_access_not_allowed" | "pak_access_not_allowed" | "cannot_modify_disabled_translation" | "azure_config_required" | "s3_config_required" | "content_storage_config_required" | "content_storage_test_failed" | "content_storage_config_invalid" | "invalid_connection_string" | "cannot_create_azure_storage_client" | "s3_access_key_required" | "azure_connection_string_required" | "s3_secret_key_required" | "cannot_store_file_to_content_storage" | "unexpected_error_while_publishing_to_content_storage" | "webhook_responded_with_non_200_status" | "unexpected_error_while_executing_webhook" | "content_storage_is_in_use" | "cannot_set_state_for_missing_translation" | "no_project_id_provided" | "license_key_not_provided" | "subscription_already_canceled" | "user_is_subscribed_to_paid_plan" | "cannot_create_free_plan_without_fixed_type" | "cannot_modify_plan_free_status" | "key_id_not_provided" | "free_self_hosted_seat_limit_exceeded" | "advanced_params_not_supported" | "plural_forms_not_found_for_language" | "nested_plurals_not_supported" | "message_is_not_plural" | "content_outside_plural_forms" | "invalid_plural_form" | "multiple_plurals_not_supported" | "custom_values_json_too_long" | "unsupported_po_message_format" | "plural_forms_data_loss" | "current_user_does_not_own_image" | "user_cannot_view_this_organization" | "user_is_not_owner_of_organization" | "pak_created_for_different_project" | "custom_slug_is_only_applicable_for_custom_storage" | "invalid_slug_format" | "batch_job_cancellation_timeout" | "import_failed" | "cannot_add_more_then_1000_languages" | "no_data_to_import" | "multiple_namespaces_mapped_to_single_file" | "multiple_mappings_for_same_file_language_name" | "multiple_mappings_for_null_file_language_name" | "too_many_mappings_for_file" | "missing_placeholder_in_template" | "tag_not_found" | "cannot_parse_encrypted_slack_login_data" | "slack_workspace_not_found" | "cannot_fetch_user_details_from_slack" | "slack_missing_scope" | "slack_not_connected_to_your_account" | "slack_invalid_command" | "slack_not_subscribed_yet" | "slack_connection_failed" | "tolgee_account_already_connected" | "slack_not_configured" | "slack_workspace_already_connected" | "slack_connection_error" | "email_verification_code_not_valid" | "cannot_subscribe_to_free_plan" | "plan_auto_assignment_only_for_free_plans" | "plan_auto_assignment_only_for_private_plans" | "task_not_found" | "task_not_finished" | "task_not_open" | "translation_agency_not_found" | "this_feature_is_not_implemented_in_oss" | "sso_token_exchange_failed" | "sso_user_info_retrieval_failed" | "sso_id_token_expired" | "sso_user_cannot_create_organization" | "sso_cant_verify_user" | "sso_auth_missing_domain" | "sso_domain_not_found_or_disabled" | "native_authentication_disabled" | "invitation_organization_mismatch" | "user_is_managed_by_organization" | "cannot_set_sso_provider_missing_fields" | "namespaces_cannot_be_disabled_when_namespace_exists" | "namespace_cannot_be_used_when_feature_is_disabled" | "sso_domain_not_allowed" | "sso_login_forced_for_this_account" | "date_has_to_be_in_the_future" | "custom_plan_and_plan_id_cannot_be_set_together" | "specify_plan_id_or_custom_plan" | "custom_plans_has_to_be_private" | "cannot_create_free_plan_with_prices" | "subscription_not_scheduled_for_cancellation" | "cannot_cancel_trial" | "cannot_update_without_modification" | "current_subscription_is_not_trialing"; params?: Record[]; }; ExistenceEntityDescription: { @@ -4973,7 +5055,7 @@ export interface components { defaultFileStructureTemplate: string; extension: string; /** @enum {string} */ - format: "JSON" | "JSON_TOLGEE" | "XLIFF" | "PO" | "APPLE_STRINGS_STRINGSDICT" | "APPLE_XLIFF" | "APPLE_XCSTRINGS" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "PROPERTIES" | "YAML_RUBY" | "YAML" | "JSON_I18NEXT" | "CSV" | "RESX_ICU" | "XLSX"; + format: "JSON" | "JSON_TOLGEE" | "XLIFF" | "PO" | "APPLE_STRINGS_STRINGSDICT" | "APPLE_XLIFF" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "PROPERTIES" | "YAML_RUBY" | "YAML" | "JSON_I18NEXT" | "CSV" | "RESX_ICU" | "XLSX" | "APPLE_XCSTRINGS"; mediaType: string; }; ExportParams: { @@ -5013,7 +5095,7 @@ export interface components { * @description Format to export to * @enum {string} */ - format: "JSON" | "JSON_TOLGEE" | "XLIFF" | "PO" | "APPLE_STRINGS_STRINGSDICT" | "APPLE_XLIFF" | "APPLE_XCSTRINGS" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "PROPERTIES" | "YAML_RUBY" | "YAML" | "JSON_I18NEXT" | "CSV" | "RESX_ICU" | "XLSX"; + format: "JSON" | "JSON_TOLGEE" | "XLIFF" | "PO" | "APPLE_STRINGS_STRINGSDICT" | "APPLE_XLIFF" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "PROPERTIES" | "YAML_RUBY" | "YAML" | "JSON_I18NEXT" | "CSV" | "RESX_ICU" | "XLSX" | "APPLE_XCSTRINGS"; /** * @description Languages to be contained in export. * @@ -5091,11 +5173,15 @@ export interface components { * It is recommended to provide these values to prevent any issues with format detection. * @enum {string} */ - format?: "CSV_ICU" | "CSV_JAVA" | "CSV_PHP" | "CSV_RUBY" | "JSON_I18NEXT" | "JSON_ICU" | "JSON_JAVA" | "JSON_PHP" | "JSON_RUBY" | "JSON_C" | "PO_PHP" | "PO_C" | "PO_JAVA" | "PO_ICU" | "PO_RUBY" | "PO_PYTHON" | "STRINGS" | "STRINGSDICT" | "APPLE_XLIFF" | "XCSTRINGS" | "PROPERTIES_ICU" | "PROPERTIES_JAVA" | "PROPERTIES_UNKNOWN" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "YAML_RUBY" | "YAML_JAVA" | "YAML_ICU" | "YAML_PHP" | "YAML_UNKNOWN" | "XLIFF_ICU" | "XLIFF_JAVA" | "XLIFF_PHP" | "XLIFF_RUBY" | "RESX_ICU" | "XLSX_ICU" | "XLSX_JAVA" | "XLSX_PHP" | "XLSX_RUBY"; + format?: "CSV_ICU" | "CSV_JAVA" | "CSV_PHP" | "CSV_RUBY" | "JSON_I18NEXT" | "JSON_ICU" | "JSON_JAVA" | "JSON_PHP" | "JSON_RUBY" | "JSON_C" | "PO_PHP" | "PO_C" | "PO_JAVA" | "PO_ICU" | "PO_RUBY" | "PO_PYTHON" | "STRINGS" | "STRINGSDICT" | "APPLE_XLIFF" | "APPLE_XCSTRINGS" | "PROPERTIES_ICU" | "PROPERTIES_JAVA" | "PROPERTIES_UNKNOWN" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "YAML_RUBY" | "YAML_JAVA" | "YAML_ICU" | "YAML_PHP" | "YAML_UNKNOWN" | "XLIFF_ICU" | "XLIFF_JAVA" | "XLIFF_PHP" | "XLIFF_RUBY" | "RESX_ICU" | "XLSX_ICU" | "XLSX_JAVA" | "XLSX_PHP" | "XLSX_RUBY"; /** @description The existing language tag in the Tolgee platform to which the imported language should be mapped. * * When null, Tolgee will try to guess the language from the file contents or file name. */ languageTag?: string; + /** @description Tags of languages to be imported. When null, all languages from will be imported. + * + * This field is useful when the file contains multiple languages and you want to import only some of them. For example when importing Apple String Catalog (APPLE_XCSTRINGS), you might want only to import the base language. */ + languageTagsToImport?: string[]; /** @description Namespace to import the file to. If not provided, the key will be imported without namespace. */ namespace?: string; }; @@ -6178,6 +6264,7 @@ export interface components { usage: components["schemas"]["UsageModel"]; }; PrivateOrganizationModel: { + activeCloudSubscription?: components["schemas"]["PublicCloudSubscriptionModel"]; avatar?: components["schemas"]["Avatar"]; basePermissions: components["schemas"]["PermissionModel"]; /** @@ -6385,6 +6472,16 @@ export interface components { PublicBillingConfigurationDTO: { enabled: boolean; }; + /** @example Current active subscription info */ + PublicCloudSubscriptionModel: { + cancelAtPeriodEnd: boolean; + /** @enum {string} */ + currentBillingPeriod?: "MONTHLY" | "YEARLY"; + /** @enum {string} */ + status: "ACTIVE" | "CANCELED" | "PAST_DUE" | "UNPAID" | "ERROR" | "TRIALING" | "KEY_USED_BY_ANOTHER_INSTANCE" | "UNKNOWN"; + /** Format: int64 */ + trialEnd?: number; + }; PublicConfigurationDTO: { allowRegistrations: boolean; appName: string; @@ -6462,7 +6559,10 @@ export interface components { currentTranslations: number; /** * Format: int64 - * @description Extra credits, which are neither refilled nor reset every month. These credits are used when there are no standard credits + * @deprecated + * @description Customers were able to buy extra credits separately in the past. + * + * This option is not available anymore and this field is kept only for backward compatibility purposes and is always 0. */ extraCreditBalance: number; /** @@ -6843,6 +6943,7 @@ export interface components { clientSecret: string; domain: string; enabled: boolean; + force: boolean; global: boolean; tokenUri: string; }; @@ -6851,7 +6952,7 @@ export interface components { }; StorageTestResult: { /** @enum {string} */ - message?: "unauthenticated" | "api_access_forbidden" | "api_key_not_found" | "invalid_api_key" | "invalid_project_api_key" | "project_api_key_expired" | "bad_credentials" | "mfa_enabled" | "invalid_otp_code" | "mfa_not_enabled" | "can_not_revoke_own_permissions" | "data_corrupted" | "invitation_code_does_not_exist_or_expired" | "language_tag_exists" | "language_name_exists" | "language_not_found" | "operation_not_permitted" | "registrations_not_allowed" | "project_not_found" | "resource_not_found" | "scope_not_found" | "key_exists" | "third_party_auth_error_message" | "third_party_auth_no_email" | "third_party_auth_no_sub" | "third_party_auth_unknown_error" | "email_already_verified" | "third_party_unauthorized" | "third_party_google_workspace_mismatch" | "username_already_exists" | "username_or_password_invalid" | "user_already_has_permissions" | "user_already_has_role" | "user_not_found" | "file_not_image" | "file_too_big" | "invalid_timestamp" | "email_not_verified" | "missing_callback_url" | "invalid_jwt_token" | "expired_jwt_token" | "general_jwt_error" | "cannot_find_suitable_address_part" | "address_part_not_unique" | "user_is_not_member_of_organization" | "organization_has_no_other_owner" | "user_has_no_project_access" | "user_is_organization_owner" | "cannot_set_your_own_permissions" | "user_is_organization_member" | "property_not_mutable" | "import_language_not_from_project" | "existing_language_not_selected" | "conflict_is_not_resolved" | "language_already_selected" | "cannot_parse_file" | "could_not_resolve_property" | "cannot_add_more_then_100_languages" | "no_languages_provided" | "language_with_base_language_tag_not_found" | "language_not_from_project" | "namespace_not_from_project" | "cannot_delete_base_language" | "key_not_from_project" | "max_screenshots_exceeded" | "translation_not_from_project" | "can_edit_only_own_comment" | "request_parse_error" | "filter_by_value_state_not_valid" | "import_has_expired" | "tag_not_from_project" | "translation_text_too_long" | "invalid_recaptcha_token" | "cannot_leave_owning_project" | "cannot_leave_project_with_organization_role" | "dont_have_direct_permissions" | "tag_too_log" | "too_many_uploaded_images" | "one_or_more_images_not_found" | "screenshot_not_of_key" | "service_not_found" | "too_many_requests" | "translation_not_found" | "out_of_credits" | "key_not_found" | "organization_not_found" | "cannot_find_base_language" | "base_language_not_found" | "no_exported_result" | "cannot_set_your_own_role" | "only_translate_review_or_view_permission_accepts_view_languages" | "oauth2_token_url_not_set" | "oauth2_user_url_not_set" | "email_already_invited_or_member" | "price_not_found" | "invoice_not_from_organization" | "invoice_not_found" | "plan_not_found" | "plan_not_available_any_more" | "no_auto_translation_method" | "cannot_translate_base_language" | "pat_not_found" | "invalid_pat" | "pat_expired" | "operation_unavailable_for_account_type" | "validation_email_is_not_valid" | "current_password_required" | "cannot_create_organization" | "wrong_current_password" | "wrong_param_type" | "expired_super_jwt_token" | "cannot_delete_your_own_account" | "cannot_sort_by_this_column" | "namespace_not_found" | "namespace_exists" | "invalid_authentication_method" | "unknown_sort_property" | "only_review_permission_accepts_state_change_languages" | "only_translate_or_review_permission_accepts_translate_languages" | "cannot_set_language_permissions_for_admin_scope" | "cannot_set_view_languages_without_translations_view_scope" | "cannot_set_translate_languages_without_translations_edit_scope" | "cannot_set_state_change_languages_without_translations_state_edit_scope" | "language_not_permitted" | "scopes_has_to_be_set" | "set_exactly_one_of_scopes_or_type" | "translation_exists" | "import_keys_error" | "provide_only_one_of_screenshots_and_screenshot_uploaded_image_ids" | "multiple_projects_not_supported" | "plan_translation_limit_exceeded" | "feature_not_enabled" | "license_key_not_found" | "cannot_set_view_languages_without_for_level_based_permissions" | "cannot_set_different_translate_and_state_change_languages_for_level_based_permissions" | "cannot_disable_your_own_account" | "subscription_not_found" | "invoice_does_not_have_usage" | "customer_not_found" | "subscription_not_active" | "organization_already_subscribed" | "organization_not_subscribed" | "license_key_used_by_another_instance" | "translation_spending_limit_exceeded" | "credit_spending_limit_exceeded" | "seats_spending_limit_exceeded" | "this_instance_is_already_licensed" | "big_meta_not_from_project" | "mt_service_not_enabled" | "project_not_selected" | "organization_not_selected" | "plan_has_subscribers" | "translation_failed" | "batch_job_not_found" | "key_exists_in_namespace" | "tag_is_blank" | "execution_failed_on_management_error" | "translation_api_rate_limit" | "cannot_finalize_activity" | "formality_not_supported_by_service" | "language_not_supported_by_service" | "rate_limited" | "pat_access_not_allowed" | "pak_access_not_allowed" | "cannot_modify_disabled_translation" | "azure_config_required" | "s3_config_required" | "content_storage_config_required" | "content_storage_test_failed" | "content_storage_config_invalid" | "invalid_connection_string" | "cannot_create_azure_storage_client" | "s3_access_key_required" | "azure_connection_string_required" | "s3_secret_key_required" | "cannot_store_file_to_content_storage" | "unexpected_error_while_publishing_to_content_storage" | "webhook_responded_with_non_200_status" | "unexpected_error_while_executing_webhook" | "content_storage_is_in_use" | "cannot_set_state_for_missing_translation" | "no_project_id_provided" | "license_key_not_provided" | "subscription_already_canceled" | "user_is_subscribed_to_paid_plan" | "cannot_create_free_plan_without_fixed_type" | "cannot_modify_plan_free_status" | "key_id_not_provided" | "free_self_hosted_seat_limit_exceeded" | "advanced_params_not_supported" | "plural_forms_not_found_for_language" | "nested_plurals_not_supported" | "message_is_not_plural" | "content_outside_plural_forms" | "invalid_plural_form" | "multiple_plurals_not_supported" | "custom_values_json_too_long" | "unsupported_po_message_format" | "plural_forms_data_loss" | "current_user_does_not_own_image" | "user_cannot_view_this_organization" | "user_is_not_owner_of_organization" | "pak_created_for_different_project" | "custom_slug_is_only_applicable_for_custom_storage" | "invalid_slug_format" | "batch_job_cancellation_timeout" | "import_failed" | "cannot_add_more_then_1000_languages" | "no_data_to_import" | "multiple_namespaces_mapped_to_single_file" | "multiple_mappings_for_same_file_language_name" | "multiple_mappings_for_null_file_language_name" | "too_many_mappings_for_file" | "missing_placeholder_in_template" | "tag_not_found" | "cannot_parse_encrypted_slack_login_data" | "slack_workspace_not_found" | "cannot_fetch_user_details_from_slack" | "slack_missing_scope" | "slack_not_connected_to_your_account" | "slack_invalid_command" | "slack_not_subscribed_yet" | "slack_connection_failed" | "tolgee_account_already_connected" | "slack_not_configured" | "slack_workspace_already_connected" | "slack_connection_error" | "email_verification_code_not_valid" | "cannot_subscribe_to_free_plan" | "plan_auto_assignment_only_for_free_plans" | "plan_auto_assignment_only_for_private_plans" | "plan_auto_assignment_organization_ids_not_in_for_organization_ids" | "task_not_found" | "task_not_finished" | "task_not_open" | "translation_agency_not_found" | "this_feature_is_not_implemented_in_oss" | "sso_token_exchange_failed" | "sso_user_info_retrieval_failed" | "sso_id_token_expired" | "sso_user_cannot_create_organization" | "sso_cant_verify_user" | "sso_auth_missing_domain" | "sso_domain_not_found_or_disabled" | "native_authentication_disabled" | "invitation_organization_mismatch" | "user_is_managed_by_organization" | "cannot_set_sso_provider_missing_fields" | "namespaces_cannot_be_disabled_when_namespace_exists" | "namespace_cannot_be_used_when_feature_is_disabled"; + message?: "unauthenticated" | "api_access_forbidden" | "api_key_not_found" | "invalid_api_key" | "invalid_project_api_key" | "project_api_key_expired" | "bad_credentials" | "mfa_enabled" | "invalid_otp_code" | "mfa_not_enabled" | "can_not_revoke_own_permissions" | "data_corrupted" | "invitation_code_does_not_exist_or_expired" | "language_tag_exists" | "language_name_exists" | "language_not_found" | "operation_not_permitted" | "registrations_not_allowed" | "project_not_found" | "resource_not_found" | "scope_not_found" | "key_exists" | "third_party_auth_error_message" | "third_party_auth_no_email" | "third_party_auth_non_matching_email" | "third_party_auth_no_sub" | "third_party_auth_unknown_error" | "email_already_verified" | "third_party_unauthorized" | "third_party_google_workspace_mismatch" | "third_party_switch_initiated" | "username_already_exists" | "username_or_password_invalid" | "user_already_has_permissions" | "user_already_has_role" | "user_not_found" | "file_not_image" | "file_too_big" | "invalid_timestamp" | "email_not_verified" | "missing_callback_url" | "invalid_jwt_token" | "expired_jwt_token" | "general_jwt_error" | "cannot_find_suitable_address_part" | "slug_not_unique" | "user_is_not_member_of_organization" | "organization_has_no_other_owner" | "user_has_no_project_access" | "user_is_organization_owner" | "cannot_set_your_own_permissions" | "user_is_organization_member" | "property_not_mutable" | "import_language_not_from_project" | "existing_language_not_selected" | "conflict_is_not_resolved" | "language_already_selected" | "cannot_parse_file" | "could_not_resolve_property" | "cannot_add_more_then_100_languages" | "no_languages_provided" | "language_with_base_language_tag_not_found" | "language_not_from_project" | "namespace_not_from_project" | "cannot_delete_base_language" | "key_not_from_project" | "max_screenshots_exceeded" | "translation_not_from_project" | "can_edit_only_own_comment" | "request_parse_error" | "filter_by_value_state_not_valid" | "import_has_expired" | "tag_not_from_project" | "translation_text_too_long" | "invalid_recaptcha_token" | "cannot_leave_owning_project" | "cannot_leave_project_with_organization_role" | "dont_have_direct_permissions" | "tag_too_log" | "too_many_uploaded_images" | "one_or_more_images_not_found" | "screenshot_not_of_key" | "service_not_found" | "too_many_requests" | "translation_not_found" | "out_of_credits" | "key_not_found" | "organization_not_found" | "cannot_find_base_language" | "base_language_not_found" | "no_exported_result" | "cannot_set_your_own_role" | "only_translate_review_or_view_permission_accepts_view_languages" | "oauth2_token_url_not_set" | "oauth2_user_url_not_set" | "email_already_invited_or_member" | "price_not_found" | "invoice_not_from_organization" | "invoice_not_found" | "plan_not_found" | "plan_not_available_any_more" | "no_auto_translation_method" | "cannot_translate_base_language" | "pat_not_found" | "invalid_pat" | "pat_expired" | "operation_unavailable_for_account_type" | "validation_email_is_not_valid" | "current_password_required" | "cannot_create_organization" | "wrong_current_password" | "wrong_param_type" | "expired_super_jwt_token" | "cannot_delete_your_own_account" | "cannot_sort_by_this_column" | "namespace_not_found" | "namespace_exists" | "invalid_authentication_method" | "unknown_sort_property" | "only_review_permission_accepts_state_change_languages" | "only_translate_or_review_permission_accepts_translate_languages" | "cannot_set_language_permissions_for_admin_scope" | "cannot_set_view_languages_without_translations_view_scope" | "cannot_set_translate_languages_without_translations_edit_scope" | "cannot_set_state_change_languages_without_translations_state_edit_scope" | "language_not_permitted" | "scopes_has_to_be_set" | "set_exactly_one_of_scopes_or_type" | "translation_exists" | "import_keys_error" | "provide_only_one_of_screenshots_and_screenshot_uploaded_image_ids" | "multiple_projects_not_supported" | "plan_translation_limit_exceeded" | "feature_not_enabled" | "license_key_not_found" | "cannot_set_view_languages_without_for_level_based_permissions" | "cannot_set_different_translate_and_state_change_languages_for_level_based_permissions" | "cannot_disable_your_own_account" | "subscription_not_found" | "invoice_does_not_have_usage" | "customer_not_found" | "subscription_not_active" | "organization_already_subscribed" | "organization_not_subscribed" | "license_key_used_by_another_instance" | "translation_spending_limit_exceeded" | "credit_spending_limit_exceeded" | "seats_spending_limit_exceeded" | "this_instance_is_already_licensed" | "big_meta_not_from_project" | "mt_service_not_enabled" | "project_not_selected" | "organization_not_selected" | "plan_has_subscribers" | "translation_failed" | "batch_job_not_found" | "key_exists_in_namespace" | "tag_is_blank" | "execution_failed_on_management_error" | "translation_api_rate_limit" | "cannot_finalize_activity" | "formality_not_supported_by_service" | "language_not_supported_by_service" | "rate_limited" | "pat_access_not_allowed" | "pak_access_not_allowed" | "cannot_modify_disabled_translation" | "azure_config_required" | "s3_config_required" | "content_storage_config_required" | "content_storage_test_failed" | "content_storage_config_invalid" | "invalid_connection_string" | "cannot_create_azure_storage_client" | "s3_access_key_required" | "azure_connection_string_required" | "s3_secret_key_required" | "cannot_store_file_to_content_storage" | "unexpected_error_while_publishing_to_content_storage" | "webhook_responded_with_non_200_status" | "unexpected_error_while_executing_webhook" | "content_storage_is_in_use" | "cannot_set_state_for_missing_translation" | "no_project_id_provided" | "license_key_not_provided" | "subscription_already_canceled" | "user_is_subscribed_to_paid_plan" | "cannot_create_free_plan_without_fixed_type" | "cannot_modify_plan_free_status" | "key_id_not_provided" | "free_self_hosted_seat_limit_exceeded" | "advanced_params_not_supported" | "plural_forms_not_found_for_language" | "nested_plurals_not_supported" | "message_is_not_plural" | "content_outside_plural_forms" | "invalid_plural_form" | "multiple_plurals_not_supported" | "custom_values_json_too_long" | "unsupported_po_message_format" | "plural_forms_data_loss" | "current_user_does_not_own_image" | "user_cannot_view_this_organization" | "user_is_not_owner_of_organization" | "pak_created_for_different_project" | "custom_slug_is_only_applicable_for_custom_storage" | "invalid_slug_format" | "batch_job_cancellation_timeout" | "import_failed" | "cannot_add_more_then_1000_languages" | "no_data_to_import" | "multiple_namespaces_mapped_to_single_file" | "multiple_mappings_for_same_file_language_name" | "multiple_mappings_for_null_file_language_name" | "too_many_mappings_for_file" | "missing_placeholder_in_template" | "tag_not_found" | "cannot_parse_encrypted_slack_login_data" | "slack_workspace_not_found" | "cannot_fetch_user_details_from_slack" | "slack_missing_scope" | "slack_not_connected_to_your_account" | "slack_invalid_command" | "slack_not_subscribed_yet" | "slack_connection_failed" | "tolgee_account_already_connected" | "slack_not_configured" | "slack_workspace_already_connected" | "slack_connection_error" | "email_verification_code_not_valid" | "cannot_subscribe_to_free_plan" | "plan_auto_assignment_only_for_free_plans" | "plan_auto_assignment_only_for_private_plans" | "task_not_found" | "task_not_finished" | "task_not_open" | "translation_agency_not_found" | "this_feature_is_not_implemented_in_oss" | "sso_token_exchange_failed" | "sso_user_info_retrieval_failed" | "sso_id_token_expired" | "sso_user_cannot_create_organization" | "sso_cant_verify_user" | "sso_auth_missing_domain" | "sso_domain_not_found_or_disabled" | "native_authentication_disabled" | "invitation_organization_mismatch" | "user_is_managed_by_organization" | "cannot_set_sso_provider_missing_fields" | "namespaces_cannot_be_disabled_when_namespace_exists" | "namespace_cannot_be_used_when_feature_is_disabled" | "sso_domain_not_allowed" | "sso_login_forced_for_this_account" | "date_has_to_be_in_the_future" | "custom_plan_and_plan_id_cannot_be_set_together" | "specify_plan_id_or_custom_plan" | "custom_plans_has_to_be_private" | "cannot_create_free_plan_with_prices" | "subscription_not_scheduled_for_cancellation" | "cannot_cancel_trial" | "cannot_update_without_modification" | "current_subscription_is_not_trialing"; params?: Record[]; success: boolean; }; @@ -9039,6 +9140,228 @@ export interface operations { }; }; }; + getChangedAuthProvider: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["AuthProviderDto"]; + }; + }; + /** @description Bad Request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + acceptChangeAuthProvider: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["JwtAuthenticationResponse"]; + }; + }; + /** @description Bad Request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + rejectChangeAuthProvider: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Bad Request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; + getCurrentAuthProvider: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["AuthProviderDto"]; + }; + }; + /** @description Bad Request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + /** @description Not Found */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ErrorResponseTyped"] | components["schemas"]["ErrorResponseBody"]; + }; + }; + }; + }; getInfo_5: { parameters: { query?: never; @@ -13930,7 +14253,7 @@ export interface operations { */ languages?: string[]; /** @description Format to export to */ - format?: "JSON" | "JSON_TOLGEE" | "XLIFF" | "PO" | "APPLE_STRINGS_STRINGSDICT" | "APPLE_XLIFF" | "APPLE_XCSTRINGS" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "PROPERTIES" | "YAML_RUBY" | "YAML" | "JSON_I18NEXT" | "CSV" | "RESX_ICU" | "XLSX"; + format?: "JSON" | "JSON_TOLGEE" | "XLIFF" | "PO" | "APPLE_STRINGS_STRINGSDICT" | "APPLE_XLIFF" | "ANDROID_XML" | "COMPOSE_XML" | "FLUTTER_ARB" | "PROPERTIES" | "YAML_RUBY" | "YAML" | "JSON_I18NEXT" | "CSV" | "RESX_ICU" | "XLSX" | "APPLE_XCSTRINGS"; /** @description Delimiter to structure file content. * * e.g. For key "home.header.title" would result in {"home": {"header": "title": {"Hello"}}} structure. @@ -13994,13 +14317,14 @@ export interface operations { }; requestBody?: never; responses: { - /** @description OK */ + /** @description When multiple files are exported, they are zipped and returned as a single zip file. + * When a single file is exported, it is returned directly. */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["StreamingResponseBody"]; + "application/*": unknown; }; }; /** @description Bad Request */ @@ -14056,13 +14380,14 @@ export interface operations { }; }; responses: { - /** @description OK */ + /** @description When multiple files are exported, they are zipped and returned as a single zip file. + * When a single file is exported, it is returned directly. */ 200: { headers: { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["StreamingResponseBody"]; + "application/*": unknown; }; }; /** @description Bad Request */ diff --git a/src/commands/push.ts b/src/commands/push.ts index fa15d184..a62bf342 100644 --- a/src/commands/push.ts +++ b/src/commands/push.ts @@ -136,7 +136,11 @@ const pushHandler = (config: Schema) => } const filteredMatchers = config.push.files.filter((r) => { - if (opts.languages && !opts.languages.includes(r.language)) { + if ( + r.language && + opts.languages && + !opts.languages.includes(r.language) + ) { return false; } if (opts.namespaces && !opts.namespaces.includes(r.namespace ?? '')) { @@ -168,11 +172,21 @@ const pushHandler = (config: Schema) => format: format, languageTag: f.language, namespace: f.namespace ?? '', + languageTagsToImport: opts.languages, }; }), removeOtherKeys: opts.removeOtherKeys, }; + console.log(JSON.stringify(params, null, 2)); + console.log( + JSON.stringify( + files.map((f) => f.name), + null, + 2 + ) + ); + const attempt1 = await loading( 'Importing...', importData(opts.client, { diff --git a/src/utils/mapImportFormat.ts b/src/utils/mapImportFormat.ts index fd7b89bf..2edf7b59 100644 --- a/src/utils/mapImportFormat.ts +++ b/src/utils/mapImportFormat.ts @@ -8,8 +8,6 @@ export const mapImportFormat = ( extension: string ): FormatResult => { switch (format) { - case 'APPLE_XCSTRINGS': - return 'XCSTRINGS'; case 'APPLE_STRINGS': { // apple separates translations to two separate files // we keep it under one format for the cli diff --git a/test/__fixtures__/differentFormatsProject/apple-xcstrings.json b/test/__fixtures__/differentFormatsProject/apple-xcstrings.json index 39e709b1..7d1dd99f 100644 --- a/test/__fixtures__/differentFormatsProject/apple-xcstrings.json +++ b/test/__fixtures__/differentFormatsProject/apple-xcstrings.json @@ -4,8 +4,7 @@ "push": { "files": [ { - "path": "./apple-xcstrings/Localizable.xcstrings", - "language": "en" + "path": "./apple-xcstrings/Localizable.xcstrings" } ] } diff --git a/test/__fixtures__/differentFormatsProject/apple-xcstrings/Localizable.xcstrings b/test/__fixtures__/differentFormatsProject/apple-xcstrings/Localizable.xcstrings index 477a4593..1098d98e 100644 --- a/test/__fixtures__/differentFormatsProject/apple-xcstrings/Localizable.xcstrings +++ b/test/__fixtures__/differentFormatsProject/apple-xcstrings/Localizable.xcstrings @@ -1,75 +1,19 @@ { "sourceLanguage" : "cs", "strings" : { - "dog_count" : { - "localizations" : { - "cs" : { - "variations" : { - "plural" : { - "few" : { - "stringUnit" : { - "state" : "translated", - "value" : "Já mám %lli psi." - } - }, - "one" : { - "stringUnit" : { - "state" : "translated", - "value" : "Já mám jednoho psa." - } - }, - "other" : { - "stringUnit" : { - "state" : "translated", - "value" : "Já mám %lli psů." - } - } - } - } - }, - "en" : { - "variations" : { - "plural" : { - "other" : { - "stringUnit" : { - "state" : "needs_review", - "value" : "I have %%lli dogs." - } - } - } - } - } - } - }, - "my_mom" : { + "controller" : { "extractionState" : "manual", "localizations" : { "cs" : { "stringUnit" : { "state" : "translated", - "value" : "Tohle je moje máma!" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "This is my mom!" - } - } - } - }, - "test_key" : { - "localizations" : { - "cs" : { - "stringUnit" : { - "state" : "translated", - "value" : "O muj boze!" + "value" : "Máš %lld položek" } }, "en" : { "stringUnit" : { "state" : "translated", - "value" : "Oh my god!" + "value" : "You have %lld items" } } } diff --git a/test/e2e/formats.test.ts b/test/e2e/formats.test.ts index 22305ffb..151b0c49 100644 --- a/test/e2e/formats.test.ts +++ b/test/e2e/formats.test.ts @@ -7,11 +7,7 @@ import { join } from 'path'; import { readFileSync } from 'fs'; import { TolgeeClient } from '#cli/client/TolgeeClient.js'; import { PROJECT_1 } from './utils/api/project1.js'; -import { - createPak, - createProjectWithClient, - deleteProject, -} from './utils/api/common.js'; +import { createPak, createProjectWithClient } from './utils/api/common.js'; const FIXTURES_PATH = new URL('../__fixtures__/', import.meta.url); @@ -85,7 +81,7 @@ describe('push and pull with different formats', () => { pak = await createPak(client); }); afterEach(async () => { - await deleteProject(client); + // await deleteProject(client); }); it('works with tolgee icu format', async () => { @@ -144,9 +140,9 @@ describe('push and pull with different formats', () => { it('works with Apple xcstrings (StringCatalog) format', async () => { await testWithConfig({ config: 'apple-xcstrings', - inPlatform: 'This is my mom!', - fileLocation: 'Localizable.strings', - inFile: 'I have %%lli dogs.', + inPlatform: 'You have {0, number} items', + fileLocation: 'Localizable.xcstrings', + inFile: 'You have %lld items', }); }); diff --git a/test/e2e/utils/run.ts b/test/e2e/utils/run.ts index 31fedd0c..16500ec8 100644 --- a/test/e2e/utils/run.ts +++ b/test/e2e/utils/run.ts @@ -73,10 +73,8 @@ function runProcess( }, timeoutTime); cliProcess.on('exit', (code) => { - if (DEBUG_ENABLED) { - console.log('::group::stdout\n%s\n::endgroup::', stdout); - console.log('::group::stderr\n%s\n::endgroup::', stderr); - } + console.log('::group::stdout\n%s\n::endgroup::', stdout); + console.log('::group::stderr\n%s\n::endgroup::', stderr); if (killed) return; clearTimeout(timeout); From 37b2118799c38940fd16b6ca256b6b28317b21c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0t=C4=9Bp=C3=A1n=20Gran=C3=A1t?= Date: Wed, 26 Feb 2025 16:46:10 +0100 Subject: [PATCH 3/5] fix: provide description for language field --- schema.json | 2 +- src/schema.d.ts | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/schema.json b/schema.json index 75f1bbc2..eb5b8d71 100644 --- a/schema.json +++ b/schema.json @@ -220,7 +220,7 @@ "properties": { "path": { "$ref": "#/$defs/path" }, "language": { - "description": "Explicitly map file to language.\n\nIf not provided backend will try to detect language from language name or it's content.", + "description": "Explicitly map file to language.\n\nIf not provided, backend will try to detect language from language name or it's content.", "type": "string" }, "namespace": { "type": "string" } diff --git a/src/schema.d.ts b/src/schema.d.ts index 1886ed89..3b39515e 100644 --- a/src/schema.d.ts +++ b/src/schema.d.ts @@ -225,6 +225,11 @@ export interface Schema { } export interface FileMatch { path: Path; - language: string; + /** + * Explicitly map file to language. + * + * If not provided, backend will try to detect language from language name or it's content. + */ + language?: string; namespace?: string; } From 0e17b9c225cae01e8974313133d12279ef5ee04d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0t=C4=9Bp=C3=A1n=20Gran=C3=A1t?= Date: Thu, 27 Feb 2025 10:11:06 +0100 Subject: [PATCH 4/5] fix: add descriptive error --- src/commands/push.ts | 29 +++++++++++++------ .../differentFormatsProject/tolgee-json.json | 2 +- .../tolgee-json/{en.json => abc.json} | 0 3 files changed, 21 insertions(+), 10 deletions(-) rename test/__fixtures__/differentFormatsProject/tolgee-json/{en.json => abc.json} (100%) diff --git a/src/commands/push.ts b/src/commands/push.ts index a62bf342..fe4db79a 100644 --- a/src/commands/push.ts +++ b/src/commands/push.ts @@ -11,12 +11,15 @@ import { error, warn, exitWithError, + info, } from '../utils/logger.js'; import { ForceMode, Format, Schema, FileMatch } from '../schema.js'; import { askString } from '../utils/ask.js'; import { mapImportFormat } from '../utils/mapImportFormat.js'; import { TolgeeClient, handleLoadableError } from '../client/TolgeeClient.js'; import { BodyOf } from '../client/internal/schema.utils.js'; +import { exit } from 'process'; +import { components } from '#cli/client/internal/schema.generated.js'; type ImportRequest = BodyOf< '/v2/projects/{projectId}/single-step-import', @@ -28,6 +31,8 @@ export type ImportProps = Omit & { files: Array; }; +type ImportFileMapping = components['schemas']['ImportFileMapping']; + type FileRecord = File & { language?: string; namespace?: string; @@ -127,6 +132,18 @@ async function readRecords(matchers: FileMatch[]) { return result; } +function handleMappingError(fileMappings: ImportFileMapping[]): never { + error('Not able to map files to existing languages in the platform'); + console.log(`Pushed files:`); + fileMappings.forEach(({ fileName, languageTag }) => { + console.log(`"${fileName}"${languageTag ? ` => "${languageTag}"` : ''}`); + }); + console.log( + '\nYou can use `push.files[*].language` property in `tolgeerc` file to map language correctly' + ); + exit(1); +} + const pushHandler = (config: Schema) => async function (this: Command) { const opts: PushOptions = this.optsWithGlobals(); @@ -178,15 +195,6 @@ const pushHandler = (config: Schema) => removeOtherKeys: opts.removeOtherKeys, }; - console.log(JSON.stringify(params, null, 2)); - console.log( - JSON.stringify( - files.map((f) => f.name), - null, - 2 - ) - ); - const attempt1 = await loading( 'Importing...', importData(opts.client, { @@ -196,6 +204,9 @@ const pushHandler = (config: Schema) => ); if (attempt1.error) { + if (attempt1.error.code === 'existing_language_not_selected') { + handleMappingError(params.fileMappings); + } if (attempt1.error.code !== 'conflict_is_not_resolved') { handleLoadableError(attempt1); } diff --git a/test/__fixtures__/differentFormatsProject/tolgee-json.json b/test/__fixtures__/differentFormatsProject/tolgee-json.json index 668f32a9..593a3837 100644 --- a/test/__fixtures__/differentFormatsProject/tolgee-json.json +++ b/test/__fixtures__/differentFormatsProject/tolgee-json.json @@ -2,6 +2,6 @@ "$schema": "../../../schema.json", "format": "JSON_ICU", "push": { - "files": [{ "path": "./tolgee-json/en.json", "language": "en" }] + "files": [{ "path": "./tolgee-json/abc.json" }] } } diff --git a/test/__fixtures__/differentFormatsProject/tolgee-json/en.json b/test/__fixtures__/differentFormatsProject/tolgee-json/abc.json similarity index 100% rename from test/__fixtures__/differentFormatsProject/tolgee-json/en.json rename to test/__fixtures__/differentFormatsProject/tolgee-json/abc.json From c1c103815c3d2ebae34652158868a7decae529e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=A0t=C4=9Bp=C3=A1n=20Gran=C3=A1t?= Date: Thu, 27 Feb 2025 10:12:40 +0100 Subject: [PATCH 5/5] fix: add descriptive error --- test/__fixtures__/differentFormatsProject/tolgee-json.json | 2 +- .../differentFormatsProject/tolgee-json/{abc.json => en.json} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename test/__fixtures__/differentFormatsProject/tolgee-json/{abc.json => en.json} (100%) diff --git a/test/__fixtures__/differentFormatsProject/tolgee-json.json b/test/__fixtures__/differentFormatsProject/tolgee-json.json index 593a3837..b9902702 100644 --- a/test/__fixtures__/differentFormatsProject/tolgee-json.json +++ b/test/__fixtures__/differentFormatsProject/tolgee-json.json @@ -2,6 +2,6 @@ "$schema": "../../../schema.json", "format": "JSON_ICU", "push": { - "files": [{ "path": "./tolgee-json/abc.json" }] + "files": [{ "path": "./tolgee-json/en.json" }] } } diff --git a/test/__fixtures__/differentFormatsProject/tolgee-json/abc.json b/test/__fixtures__/differentFormatsProject/tolgee-json/en.json similarity index 100% rename from test/__fixtures__/differentFormatsProject/tolgee-json/abc.json rename to test/__fixtures__/differentFormatsProject/tolgee-json/en.json