Content Internationalization (i18n) beta is live 🌍

Hello,

great work :rocket:

I still have some questions/problems though:

  1. When using the GraphQL API, the Accept-Language header doesn’t seem to be picked up, am I correct? It works with the REST API.
  2. When querying for a single collection item using GraphQL, no locale parameter can be passed in. If the Accept-Language header had an effect, that wouldn’t be a problem. Is this intended behavior?

Hi,
Is there something planned like a view or dialog for translators where they can see the original-locale text (e.g. in English) and enter the translation (e.g. in French) right next to it? Such a view (like typical translator tools have it) would be necessary for the work of translators I believe.
Thanks

Hello,
It is a good idea but unfortunately it is not planned.
The closest feature would be ‘the fill in from another locale’ button that fills all your translated inputs with one locale.

If you really need such feature the best way would be to develop with a dedicated view.

Hello,

I’m currently testing i18n plugin with Strapi and I have one question. I have some function like that below

Przechwytywanie

This piece of code create new entries only for my default locale. How I can improve it so that it also create entires for other locales ?

You need to include the locale key and set it to the shortcode, we have our docs PR pending for the dev docs that can give more context: https://github.com/strapi/documentation/pull/224

These will be released on Wednesday (dev docs and user docs), not the I18N feature which I believe is slated for Thursday.

1 Like

Hi everyone,

We have released the beta.3 version of I18N for testing, this will be the final beta release before the stable one. (Assuming no major issues come up).

Rough Change-log is:

  • Fixed an issue with default locale not being set / Switching default locale
  • Fix an issue with localization of media fields
  • The i18n plugin is now installed by default (not enabled, does not affect existing projects that will update)
  • Fix single type delete
  • Fix issue fetching single-type entries that have localization enabled
  • Fix single type updates (PUT)
  • Fix bulk delete on entries that aren’t in default locale
  • Fix sticky header and select the first locale for copy by default
  • Update Buffet.js to 3.3.5
  • Various dependency updates (merged from master branch)

For a more detailed changelog, please review the features/i18n branch on GitHub: https://github.com/strapi/strapi/commits/features/i18n

Creating a new project on this beta is the same as before:

npx create-strapi-app@beta test-project --quickstart --no-run (remove the --quickstart and --no-run if you want to test on other databases).

At this time, if you want to test upgrading existing applications there should be no migration steps (minus installing the i18n plugin) but we still do not recommend this version for production usage

If you update your existing project, you do so at your own risk, please do not post bug reports on GitHub until the stable version is released.


If you want to review both the User and Developer docs for I18N you can find them here (please don’t comment on them) and they will be released before the stable on Wednesday.

8 Likes

Awesome feature. Great work! Just tried it out and it works fine with most of my content types. But when I enable it for one specific content type, strapi actually crashes. How/where do you want me to report that issue?

[2021-04-20T14:59:04.305Z] [2021-04-20t14:59:04.304z] debug ⛔️ Server wasn't able to start properly.
[2021-04-20T14:59:04.305Z] [2021-04-20t14:59:04.305z] error Error: Unknown type "updateRecipesInput". Did you mean "updateRecipeInput", "createRecipeInput", "deleteRecipeInput", "editRecipeInput", or "updateRoleInput"?
    at assertValidSDL (/Users/vinzenzweber/Development/rootshealth/glucose-cms/node_modules/graphql/validation/validate.js:107:11)
    at Object.buildASTSchema (/Users/vinzenzweber/Development/rootshealth/glucose-cms/node_modules/graphql/utilities/buildASTSchema.js:45:34)
    at Object.buildSchemaFromTypeDefinitions (/Users/vinzenzweber/Development/rootshealth/glucose-cms/node_modules/graphql-tools/dist/generate/buildSchemaFromTypeDefinitions.js:25:28)
    at makeExecutableSchema (/Users/vinzenzweber/Development/rootshealth/glucose-cms/node_modules/graphql-tools/dist/makeExecutableSchema.js:26:29)
    at Object.generateSchema (/Users/vinzenzweber/Development/rootshealth/glucose-cms/node_modules/strapi-plugin-graphql/services/schema-generator.js:101:18)
    at Object.initialize (/Users/vinzenzweber/Development/rootshealth/glucose-cms/node_modules/strapi-plugin-graphql/hooks/graphql/index.js:76:74)
    at /Users/vinzenzweber/Development/rootshealth/glucose-cms/node_modules/strapi/lib/hooks/index.js:37:28
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
1 Like

Can you give us a bit more information that content-type?

It seems to be an issue with the GraphQL plugin while it creates the schema. I tried to extract the part of my project that would make the app crash and summarised it here: https://github.com/vinzenzweber/strapi-i18n-debug

So after a little testing the one thing that makes all the difference is wether I create a content-type with Display name ending with an “s”. Using “Recipe” as Display name works fine, while “Recipes” would crash the app. Same for “Lesson” vs “Lessons” etc.

@vinzenzweber can you test this PR?

2 Likes

Awesome, that fixed my bug! Love how quick you guys handled this! :raised_hands:

I just installed the newest version, which works great for most of the things, but I stumbled upon some problems (I already mentioned some of them here, but maybe you overlooked it).

When querying with GraphQL, I can only specify the locale for a Content Type which has localization enabled, which makes sense in the first place, but has a major drawback: I can’t populate a relation with the needed locale. For example if I have a Content Type Hotel and a Content Type WelcomeMessage and the hotel has a 1-1 relation with the welcome message and my query looks like this:

query FindHotel($id: ID!) {
  hotels(where: { id: $id }) {
    id
    name
    welcomeMessage {
      title
      locale
    }
  }
}

How is it possible to retrieve a different locale for the welcomeMessage then the default one? As a workaround, I could just query the localizations field on welcomeMessage and filter the content on the client side, which would be less than ideal and not very scalable.

Also, it is not possible to specify the locale when querying a single instance of a collection type by ID (screenshot of the generated schema):

Proposed solution for the above problems:
Instead of always returning the default locale or adding a locale parameter to each and every query, you could simply use the Accept-Language header which every browser sends by default to determine the current content language. This would also work nicely with nested GQL queries.

In the meantime, is there any other possibility to make nested queries fully localized, e.g. by manipulating the context object or something?

It is still in progress and it seems not to be finished any soon as far as I can understand. Is there any workaround documented which we can use as a base?

Thanks

Hi @sam-pires @Jab : could you confirm you are looking into the possibility to derive localised relationships when clicking “Fill in from another locale” ? My CMS manager is getting crazy :smiley:

Are you talking about this? Unable to disable localization for relationship fields. ¡ Issue #10322 ¡ strapi/strapi ¡ GitHub

Hello @justus
Thanks for the feedback :+1: It’s made on purpose.
We took that decision to stay coherent with the current behavior on RBAC when you add a new field or CT: by default the permissions are not checked. So that motivated us to apply the same behavior for i18n.
I agree that it’s might not be the fastest way to get roles ready, but we consider that it is safer to hide newly created content (CT, field, I18n activation) by default and then to allow access to it, than the other way around :slight_smile:

Hello @wlixw87

Here is some info you probably wait for :slight_smile:
(cc @glo and @LuisAlaguna)

We don’t take the relations when using the “fill in from” feature because of a technical limitation. In some cases, depending on the relationship type between 2 entities, and depending on the activation of i18n on only one or both Collection-types (CT), recreating the same relation in several locales could break it.
e.g. In the case where i18n is activated on a CT but not on the other one, and where the relationship type is one-to-one, then if we just recreate the same relation in a new locale we break it on the other side of the relation (the other CT) without knowing it.

We thought about limiting the use of some relationship types in the CTB (content type builder) directly to avoid ending up in this kind of situation. But i18n being a plugin we were too limited and it would have been too complex to implement.

To avoid having the same issue when adding a relation manually from the Edit View, we now apply a filter on the relations you can add, depending on whether i18n is activated on one or both CTs you’ll only be able to create a relation to an entity with the same locale.

That’s also why localization is forced on Relational fields.

The good news is that the new db model in the v4 will solve this technical limitation :slight_smile:
I18n helped us identify several limitations in our model and the v4 is here to make Strapi more robust and offer more flexibility.

Feel free if you have any questions.


By the way, talking about relations, we are currently doing some researches on this topic and it would be awesome if you could share some info about your Strapi projects, your use cases, and needs regarding relations in this forum post. It’s gonna help us make the most of the new model in the v4 :wink:

Hi guys,

I’m quite new at the Strapi and I have a problem how fetch localized data using GraphQL. Here I found the information how to query data using REST API, but I cannot find what I’m doing wrong using GraphQL.

This is a JSON structure of response for the default lang (de-CH):

{
“id”: 5,
“locale”: “de-CH”,
“published_at”: “2021-05-11T12:04:23.616Z”,
“created_at”: “2021-05-11T11:56:10.146Z”,
“updated_at”: “2021-05-11T16:44:59.947Z”,
“mainTitle”: null,
“content”: null,
“openDialogButtonLabel”: "Ich abonniere! ",
“seo”: {
“id”: 40,
“metaTitle”: “Kommt bald”,
“metaDescription”: “Kommt bald desc”,
“metaKeywords”: “”,
“preventIndexing”: false,
“cannonicalLink”: null,
“sharedImage”: null
},
“dialog”: {
“id”: 5,
“Title”: null,
“OfferSummary”: null,
“ConfiramtionReminder”: null,
“RepeatConfirmationReminder”: null,
“Clause”: null,
“title”: null,
“confiramtionReminder”: null,
“repeatConfirmationReminder”: null,
“clause”: null,
“offerSummary”: null,
“form”: null
},
“logo”: null,
“localizations”: [
{
“id”: 3,
“locale”: “pl-PL”,
“published_at”: “2021-05-12T17:14:19.643Z”
},
{
“id”: 6,
“locale”: “en-GB”,
“published_at”: “2021-05-12T17:16:01.446Z”
}
]
}

When I test the query without any filters like this:

query MyQuery {
strapiComingSoon {
openDialogButtonLabel
locale
}
}

I get the correct response:

{
“data”: {
“strapiComingSoon”: {
“openDialogButtonLabel”: "Ich abonniere! ",
“locale”: “de-CH”
}
},
“extensions”: {
“enableRefresh”: “1”
}
}

This is a JSON structure of response for PL version (url/page?_locale=pl=PL)

{
“id”: 3,
“locale”: “pl-PL”,
“published_at”: “2021-05-12T17:14:19.643Z”,
“created_at”: “2021-05-07T12:55:24.182Z”,
“updated_at”: “2021-05-12T17:14:19.859Z”,
“mainTitle”: “Strona w budowie”,
“content”: null,
“openDialogButtonLabel”: “Zapisuję się!”,
“seo”: {
“id”: 41,
“metaTitle”: “Strona w budowie”,
“metaDescription”: “Opis strony w budowie”,
“metaKeywords”: null,
“preventIndexing”: false,
“cannonicalLink”: null,
“sharedImage”: null
},
“dialog”: {
“id”: 6,
“Title”: null,
“OfferSummary”: null,
“ConfiramtionReminder”: null,
“RepeatConfirmationReminder”: null,
“Clause”: null,
“title”: null,
“confiramtionReminder”: null,
“repeatConfirmationReminder”: null,
“clause”: null,
“offerSummary”: null,
“form”: null
},
“logo”: null,
“localizations”: [
{
“id”: 5,
“locale”: “de-CH”,
“published_at”: “2021-05-11T12:04:23.616Z”
},
{
“id”: 6,
“locale”: “en-GB”,
“published_at”: “2021-05-12T17:16:01.446Z”
}
]
}

And when I trying query using GraphQL like this (with filter):

query MyQuery {
strapiComingSoon(locale: {eq: “pl-PL”}) {
openDialogButtonLabel
locale
}
}

In response I get:

{
“data”: {
“strapiComingSoon”: null
},
“extensions”: {
“enableRefresh”: “1”
}
}

What should I do to fetch Polish version of the Single Type? Thanks in advance for every help

Is it also working for images or text only?