Fekide / strapi-plugin-translate

Strapi plugin for automated translations using different Translate Providers
https://market.strapi.io/plugins/strapi-plugin-translate
MIT License
42 stars 16 forks source link

[BUG]: Translating entity failed: texts parameter must be a non-empty string or array of non-empty strings #252

Open emvhaccuranker opened 1 year ago

emvhaccuranker commented 1 year ago

Describe the bug There seems to be an issue with field translation on the Frontpage content type (see Additional context). When attempting to translate from another locale, the operation fails and returns an error message stating Translating entity failed: texts parameter must be a non-empty string or array of non-empty strings.

However, if the translation option for Frontpage.features.featurePoints.subtitle is changed from translate to copy, translation from another locale executes without an error.

To Reproduce

Steps to reproduce the behavior:

Error Scenario

  1. Navigate to Content Manager view for Frontpage.
  2. In the right-side menu under the Internationalization section, select a different locale.
  3. Click on Translate from another locale, select English (en), and confirm by clicking on Yes, fill in.
  4. The following error is encountered: Translating entity failed: texts parameter must be a non-empty string or array of non-empty strings.

Success Scenario

  1. For Frontpage.features.featurePoints.subtitle, change the translate option from translate to copy.
  2. Execute the operation to translate from another locale.
  3. The translation operation executes successfully, but subtitle is copied from source locale.

Expected behavior The expectation is that the translation process should be executed successfully without any errors, regardless of the translation options set for specific fields.

Screenshots N/A

System

Plugin config

<...>

  translate: {
    enabled: true,
    config: {
      provider: 'deepl',
      providerOptions: {
        apiKey: <redacted>
      }
    }
  }

<...>

Additional context

api/frontpage/content-types/frontpage/schema.json ```json { "kind": "singleType", "collectionName": "frontpages", "info": { "singularName": "frontpage", "pluralName": "frontpages", "displayName": "Frontpage", "name": "frontpage", "description": "" }, "options": { "increments": true, "timestamps": true, "draftAndPublish": true }, "pluginOptions": { "i18n": { "localized": true } }, "attributes": { "hero": { "type": "component", "repeatable": false, "component": "frontpage.hero", "pluginOptions": { "i18n": { "localized": true }, "translate": { "translate": "translate" } } }, "numbers": { "type": "component", "repeatable": true, "component": "frontpage.numbers", "required": false, "pluginOptions": { "i18n": { "localized": true }, "translate": { "translate": "translate" } } }, "valuePropositionTitle": { "type": "string", "required": false, "pluginOptions": { "i18n": { "localized": true }, "translate": { "translate": "translate" } } }, "valuePropositions": { "type": "component", "repeatable": true, "component": "shared.title-description", "max": 3, "pluginOptions": { "i18n": { "localized": true }, "translate": { "translate": "translate" } } }, "features": { "type": "component", "repeatable": true, "component": "frontpage.features", "pluginOptions": { "i18n": { "localized": true }, "translate": { "translate": "translate" } } }, "customer_case": { "type": "relation", "relation": "oneToOne", "target": "api::customer-case.customer-case", "pluginOptions": { "translate": { "translate": "" } } }, "pageTitle": { "type": "string", "pluginOptions": { "i18n": { "localized": true }, "translate": { "translate": "translate" } } }, "book_demo": { "type": "relation", "relation": "oneToOne", "target": "api::book-demo.book-demo", "pluginOptions": { "translate": { "translate": "" } } }, "seo": { "type": "component", "repeatable": false, "component": "shared.seo-meta-fields", "required": true, "pluginOptions": { "i18n": { "localized": true }, "translate": { "translate": "translate" } } } } } ```
src/components/frontpage/feature-points.json ```json { "collectionName": "components_frontpage_feature_points", "info": { "icon": "list", "displayName": "feature points", "description": "" }, "options": {}, "attributes": { "title": { "type": "string", "pluginOptions": { "translate": { "translate": "translate" } } }, "subtitle": { "type": "richtext", "pluginOptions": { "translate": { "translate": "translate" } } } } } ```
yarn.lock ``` <...> "@strapi/strapi@4.6.1": version "4.6.1" resolved "https://registry.yarnpkg.com/@strapi/strapi/-/strapi-4.6.1.tgz#4b7ae63bfcfdb53d71406f1c569f731c1b877320" integrity sha512-CQzy8pDI4lJ9wUNe9MaAD8nJGCKM9+XmDsNdnIwXzRpMHJbWUGQpyJ4eZVJjAQSTyQkiC0kRf04r7CC/Ur/jog== dependencies: "@koa/cors" "3.4.3" "@koa/router" "10.1.1" "@strapi/admin" "4.6.1" "@strapi/data-transfer" "4.6.1" "@strapi/database" "4.6.1" "@strapi/generate-new" "4.6.1" "@strapi/generators" "4.6.1" "@strapi/logger" "4.6.1" "@strapi/permissions" "4.6.1" "@strapi/plugin-content-manager" "4.6.1" "@strapi/plugin-content-type-builder" "4.6.1" "@strapi/plugin-email" "4.6.1" "@strapi/plugin-upload" "4.6.1" "@strapi/typescript-utils" "4.6.1" "@strapi/utils" "4.6.1" bcryptjs "2.4.3" boxen "5.1.2" chalk "4.1.2" chokidar "3.5.2" ci-info "3.5.0" cli-table3 "0.6.2" commander "8.3.0" configstore "5.0.1" debug "4.3.4" delegates "1.0.0" dotenv "10.0.0" execa "5.1.1" fs-extra "10.0.0" glob "7.2.0" http-errors "1.8.1" inquirer "8.2.5" is-docker "2.2.1" koa "2.13.4" koa-body "4.2.0" koa-compose "4.1.0" koa-compress "5.1.0" koa-favicon "2.1.0" koa-helmet "6.1.0" koa-ip "^2.1.2" koa-session "6.2.0" koa-static "5.0.0" lodash "4.17.21" mime-types "2.1.35" node-fetch "2.6.7" node-machine-id "1.1.12" node-schedule "2.1.0" open "8.4.0" ora "5.4.1" package-json "7.0.0" qs "6.11.0" resolve-cwd "3.0.0" semver "7.3.8" statuses "2.0.1" uuid "^8.3.2" <...> strapi-plugin-translate@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/strapi-plugin-translate/-/strapi-plugin-translate-1.1.5.tgz#e8e4e423c60acddb5309c63e282291662b5f769f" integrity sha512-ExNEGL1Xk7b1e4M4l3Wcw0Rl9p1Pog8RSWsWMq5BT1afvhTJ6ij/PIr+8ZZZJcjOI8EAl9XDfgUEF6zfT0SSxQ== dependencies: "@strapi/helper-plugin" "^4.1.4" axios "^1.2.2" bottleneck "^2.19.5" jsdom "^21.1.1" showdown "^2.1.0" strapi-provider-translate-deepl@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/strapi-provider-translate-deepl/-/strapi-provider-translate-deepl-1.1.5.tgz#96347cdd4cd2b772c6fbacb9bb4c7901b21cc548" integrity sha512-mGkZyuRBv/X9Ci/TFvKcddO/TYv+CFhW6Bv7IeUQy9nA7MzUlsZH7+EYmtiIK+14Y08dAfzpKhLOLTchW4lPNw== dependencies: bottleneck "^2.19.5" deepl-node "^1.8.0" <...> ```
real world data `graphql request` ```graphql query LandingPageData { strapiFrontpage { features { featurePoints { title subtitle { data { childMarkdownRemark { ...MarkdownNode } } } } } } } ``` `graphql response` ```json { "data": { "strapiFrontpage": { "features": [ { "featurePoints": [ { "title": "Mulitiple filtering options", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "", "rawMarkdownBody": "", "html": "", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": null, "paragraphs": null, "sentences": null } } } } }, { "title": "Save segments", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "Instead of adding the same filtering options when working with your data, you can save these as segments, making it very intutive for both…", "rawMarkdownBody": "Instead of adding the same filtering options when working with your data, you can save these as segments, making it very intutive for both you and your colleagues to get back to a specific data set.", "html": "

Instead of adding the same filtering options when working with your data, you can save these as segments, making it very intutive for both you and your colleagues to get back to a specific data set.

", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": 36, "paragraphs": 1, "sentences": 1 } } } } }, { "title": "API filters", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "The segments that you save, can also be applied to your API calls, which will save Enterprise SEO and SEO Agencies developers a lot of time…", "rawMarkdownBody": "The segments that you save, can also be applied to your API calls, which will save Enterprise SEO and SEO Agencies developers a lot of time on advanced logic on the fetched data.\nCreate your logic in your filters, and apply them in your API calls - easy!", "html": "

The segments that you save, can also be applied to your API calls, which will save Enterprise SEO and SEO Agencies developers a lot of time on advanced logic on the fetched data.\nCreate your logic in your filters, and apply them in your API calls - easy!

", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": 47, "paragraphs": 2, "sentences": 2 } } } } } ] }, { "featurePoints": [ { "title": "Competitor analysis", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "Which competitors are you competing with? AccuRanker is answering this Enterprise and SEO Agency dilemma.", "rawMarkdownBody": "Which competitors are you competing with? \n\nAccuRanker is answering this Enterprise and SEO Agency dilemma.", "html": "

Which competitors are you competing with?

\n

AccuRanker is answering this Enterprise and SEO Agency dilemma.

", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": 15, "paragraphs": 2, "sentences": 2 } } } } }, { "title": "Keyword research", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "See what you and your competitors are indexed for on every page or category level.\nEnterprise and SEO Agency - let AccuRanker be your spy…", "rawMarkdownBody": "See what you and your competitors are indexed for on every page or category level.\nEnterprise and SEO Agency - let AccuRanker be your spy and eye your competitors' edge on a per-page level.", "html": "

See what you and your competitors are indexed for on every page or category level.\nEnterprise and SEO Agency - let AccuRanker be your spy and eye your competitors' edge on a per-page level.

", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": 33, "paragraphs": 2, "sentences": 2 } } } } }, { "title": "Easy sizing", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "See how large each of your pages and subpages are based on the count of keywords or total search volume pointing to each page", "rawMarkdownBody": "See how large each of your pages and subpages are based on the count of keywords or total search volume pointing to each page", "html": "

See how large each of your pages and subpages are based on the count of keywords or total search volume pointing to each page

", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": 24, "paragraphs": 1, "sentences": 1 } } } } } ] }, { "featurePoints": [ { "title": "Wide range of metrics available", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "", "rawMarkdownBody": "", "html": "", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": null, "paragraphs": null, "sentences": null } } } } }, { "title": "Filter data in hundreds of ways", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "", "rawMarkdownBody": "", "html": "", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": null, "paragraphs": null, "sentences": null } } } } }, { "title": "Share of Voice shows market performance", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "", "rawMarkdownBody": "", "html": "", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": null, "paragraphs": null, "sentences": null } } } } } ] }, { "featurePoints": [ { "title": "SERP Feature Ownership", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "See what featured elements you already own.", "rawMarkdownBody": "See what featured elements you already own.", "html": "

See what featured elements you already own.

", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": 7, "paragraphs": 1, "sentences": 1 } } } } }, { "title": "Historical insights", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "Easily see the historically progress for specific featured elements.", "rawMarkdownBody": "Easily see the historically progress for specific featured elements.", "html": "

Easily see the historically progress for specific featured elements.

", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": 9, "paragraphs": 1, "sentences": 1 } } } } }, { "title": "Total SERP feature overview", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "Get a full insight on all the elements that is available on the SERP for a segment of keywords. This makes every Enterprises SEO work easy.", "rawMarkdownBody": "Get a full insight on all the elements that is available on the SERP for a segment of keywords. This makes every Enterprises SEO work easy.", "html": "

Get a full insight on all the elements that is available on the SERP for a segment of keywords. This makes every Enterprises SEO work easy.

", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": 26, "paragraphs": 1, "sentences": 2 } } } } } ] }, { "featurePoints": [ { "title": "Keyword", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "", "rawMarkdownBody": "\n", "html": "", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": null, "paragraphs": null, "sentences": null } } } } }, { "title": "Title", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "", "rawMarkdownBody": "", "html": "", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": null, "paragraphs": null, "sentences": null } } } } }, { "title": "URL", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "", "rawMarkdownBody": "", "html": "", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": null, "paragraphs": null, "sentences": null } } } } }, { "title": "Operators", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "", "rawMarkdownBody": "", "html": "", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": null, "paragraphs": null, "sentences": null } } } } } ] }, { "featurePoints": [ { "title": "Daily & on-demand keyword update", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "All of your keywords will be updated every 24 hours.\nIf you need to get the latest, you are able to do on-demand update, updating an entire…", "rawMarkdownBody": "All of your keywords will be updated every 24 hours.\nIf you need to get the latest, you are able to do on-demand update, updating an entire domain within a few minutes.", "html": "

All of your keywords will be updated every 24 hours.\nIf you need to get the latest, you are able to do on-demand update, updating an entire domain within a few minutes.

", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": 32, "paragraphs": 2, "sentences": 2 } } } } }, { "title": "Desktop & mobile", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "For certain sites, especially ecommerce sites, mobile traffic is responsible for up to more than 80% of the total traffic, and this number…", "rawMarkdownBody": "For certain sites, especially ecommerce sites, mobile traffic is responsible for up to more than 80% of the total traffic, and this number is only growing every single day.\nWith AccuRanker, you can track both desktop and mobile rankings.", "html": "

For certain sites, especially ecommerce sites, mobile traffic is responsible for up to more than 80% of the total traffic, and this number is only growing every single day.\nWith AccuRanker, you can track both desktop and mobile rankings.

", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": 39, "paragraphs": 2, "sentences": 2 } } } } }, { "title": "Search locally", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "AccuRanker allows you to enter any location around the world, to see how your keywords is ranking within a street, zip, city, county. This…", "rawMarkdownBody": "AccuRanker allows you to enter any location around the world, to see how your keywords is ranking within a street, zip, city, county. This is maybe the most important advantage of AccuRanker over the other keyword tracking tools. Very few competitors to AccuRanker can check and track keyword rankings within a street, zip and city.", "html": "

AccuRanker allows you to enter any location around the world, to see how your keywords is ranking within a street, zip, city, county. This is maybe the most important advantage of AccuRanker over the other keyword tracking tools. Very few competitors to AccuRanker can check and track keyword rankings within a street, zip and city.

", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": 55, "paragraphs": 1, "sentences": 3 } } } } }, { "title": "Dynamic competitors", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "Who is actual taking your valuable traffic?\nWith the help of data cubing, you will be able to see how the competitor landscape changes for…", "rawMarkdownBody": "Who is actual taking your valuable traffic?\nWith the help of data cubing, you will be able to see how the competitor landscape changes for each product and category for your website.\nTake those positions back, and leave your competitors left in the dust.\nMain formula of the Enterprise SEO and Digital Marketing Agencies.", "html": "

Who is actual taking your valuable traffic?\nWith the help of data cubing, you will be able to see how the competitor landscape changes for each product and category for your website.\nTake those positions back, and leave your competitors left in the dust.\nMain formula of the Enterprise SEO and Digital Marketing Agencies.

", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": 54, "paragraphs": 4, "sentences": 4 } } } } }, { "title": "Dynamic CTR", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "The days when a #1 position would give you 33% of all clicks on the SERP page are long gone.\nWith AccuRanker's proprietary AI model, we are…", "rawMarkdownBody": "The days when a #1 position would give you 33% of all clicks on the SERP page are long gone.\nWith AccuRanker's proprietary AI model, we are now able to give precise estimates of the CTR for each of your keywords.\nWhen knowing the CTR, you can get a 90% estimate of how much traffic you and your competitors will be receiving all the way down to a single landing page! This makes the Dynamic CTR feature vital to Enterprises and SEO Agencies.", "html": "

The days when a #1 position would give you 33% of all clicks on the SERP page are long gone.\nWith AccuRanker's proprietary AI model, we are now able to give precise estimates of the CTR for each of your keywords.\nWhen knowing the CTR, you can get a 90% estimate of how much traffic you and your competitors will be receiving all the way down to a single landing page! This makes the Dynamic CTR feature vital to Enterprises and SEO Agencies.

", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": 83, "paragraphs": 3, "sentences": 4 } } } } }, { "title": "Share of voice", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "Share of Voice (SoV) is an indicator of how your most important keywords are performing. All keywords that rank between positions 1 to 2…", "rawMarkdownBody": "Share of Voice (SoV) is an indicator of how your most important keywords are performing. All keywords that rank between positions 1 to 20 are used for the calculation. The average CTR for the position is multiplied by the search volume of each keyword, allowing you to see if high traffic keywords are losing or gaining ranks. ", "html": "

Share of Voice (SoV) is an indicator of how your most important keywords are performing. All keywords that rank between positions 1 to 20 are used for the calculation. The average CTR for the position is multiplied by the search volume of each keyword, allowing you to see if high traffic keywords are losing or gaining ranks.

", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": 57, "paragraphs": 1, "sentences": 3 } } } } }, { "title": "Traffic value", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "How much is your organic traffic worth, if you should have bought it from ads? Easily track your progress in dollars and cents.", "rawMarkdownBody": "How much is your organic traffic worth, if you should have bought it from ads? Easily track your progress in dollars and cents.", "html": "

How much is your organic traffic worth, if you should have bought it from ads? Easily track your progress in dollars and cents.

", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": 23, "paragraphs": 1, "sentences": 2 } } } } } ] }, { "featurePoints": [ { "title": "X & Y coordinates", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "", "rawMarkdownBody": "", "html": "", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": null, "paragraphs": null, "sentences": null } } } } }, { "title": "Above the fold", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "", "rawMarkdownBody": "", "html": "", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": null, "paragraphs": null, "sentences": null } } } } } ] }, { "featurePoints": [ { "title": "Google Looker Studio", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "", "rawMarkdownBody": "", "html": "", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": null, "paragraphs": null, "sentences": null } } } } }, { "title": "Google Analytics", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "", "rawMarkdownBody": "", "html": "", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": null, "paragraphs": null, "sentences": null } } } } }, { "title": "Adobe Analytics", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "", "rawMarkdownBody": "", "html": "", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": null, "paragraphs": null, "sentences": null } } } } }, { "title": "Google Search Console", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "", "rawMarkdownBody": "", "html": "", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": null, "paragraphs": null, "sentences": null } } } } }, { "title": "Google Sheets", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "", "rawMarkdownBody": "", "html": "", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": null, "paragraphs": null, "sentences": null } } } } }, { "title": "Historically data migration", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "", "rawMarkdownBody": "", "html": "", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": null, "paragraphs": null, "sentences": null } } } } }, { "title": "Rest API", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "", "rawMarkdownBody": "", "html": "", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": null, "paragraphs": null, "sentences": null } } } } } ] }, { "featurePoints": [ { "title": "24 Billion world wide", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "", "rawMarkdownBody": "", "html": "", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": null, "paragraphs": null, "sentences": null } } } } }, { "title": "Easy filtering", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "", "rawMarkdownBody": "", "html": "", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": null, "paragraphs": null, "sentences": null } } } } }, { "title": "Exclusive keyword set for nordic countries", "subtitle": { "data": { "childMarkdownRemark": { "excerpt": "", "rawMarkdownBody": "", "html": "", "tableOfContents": "", "timeToRead": 1, "wordCount": { "words": null, "paragraphs": null, "sentences": null } } } } } ] } ] } }, "extensions": { "enableRefresh": "true" } } ```
emvhaccuranker commented 1 year ago

The error doesn't occur when none of the subtitle fields have empty contents - though, the field isn't marked as required.

mtrofimiuk commented 3 months ago

I had the same issue for a field with white space characters. Few spaces plus and new line.