 So, hello everyone. Welcome to DrupalCon. I hope you are having a great time. This is Drupal8 Multilingual APIs, building for the entire world. I hope you enjoy the keynote and the pre keynote and the keynote. So what we are going to talk here is about code, because this is part of the code and development track, not site building. If you are interested in the site building parts of the multilingual improvements in Drupal8, there's a lot of sessions that we've been doing in the past and they are recorded in Drupal8multilingual.org. And you can even find a full workshop guide, three-hour workshop guide, with multilingual demo distribution that you can use, so you can check all the improvements and learn more about it. But today we are going to talk about code. So my name is Christian Lopez. I'm Peñasquito on Drupal.org and I've been contributing to the Drupal8multilingual initiative. So, how many of you have built Drupal7multilingual sites? Quite a lot, if not everyone. How many of you have already built Drupal8 sites and multilingual Drupal8 sites? Okay, so quite a lot, like more than half of the room. So if you remember, which you probably do, multilingual was an afterthought in Drupal7multilingual, so there was not really good support out of the box with Drupal Core, so you needed to use a lot of contributed models. And in Drupal8, this was thought that it wasn't ideal, so there was a good investment of people who wanted to work on that and make the situation better. So I'm presenting this here, but this is the work of a lot of people, so please thank them and if you find them around the conference, hack them. So, Drupal7multilingual, the situation is that you had a Drupal Core and the support, you needed the locale module for allowing people to add a list of languages and making them possible to provide user interface translations. And you had to download them manually, which if you have like 50 modules in four languages, you need to download 2200 PO files that you have to import on your site, which can be quite a painful task. So then the community built the localization update module, which does that automatically for you. And then you want to translate your content and you need to install the content translation module, which makes copies of your notes for each language. But then you have your menus and you have taxonomy terms, so you need to install the internationalization suite, which has modules like the IATN terms and a lot of modules that help you to translate your site. And then you want to translate your title in your site name and you need the variable module for that. And maybe you want to make money online and then you use DrupalCommerce and DrupalCommerce has entity translation for translating your products, which was a country module that appeared later and this module instead of doing copies of your notes, it translates each fields. But then you find out that the title of your entities and your notes is not really a field, so you need to install the title module. So at the end you end up like having 40, 50 country modules installed on your site for translating all your data and you have multiple solutions for translating the same content. So if you may have notes and you may be translating them with content translation, but maybe you can also do it with entity translations and you have your taxonomies and your taxonomy terms can be translation with the IATN suite, but you can also use the entity translation. So there were a lot of options and at the end you can mix them all and it can be quite confusing and your site becomes highly harder to manage. So this is something that we wanted to solve in Drupal 8. And for that we introduced four modules in Drupal 8. Each of them has a very concrete task and we are going to see a short summary of them. So the first one is the language module. In Drupal 7 you have the locale module and it allows you to add languages to your site and to translate the user interface. Now we split that in Drupal 8 so we have the language module which provides services for dealing with data and which language your data is in. And it's useful not only for multilingual sites, also for monolingual sites because you may want to install in Spanish and you want to track which data your site is on because maybe you want to add more languages later or you want to separate to know which language your data is in. The second module, the second pillar is the interface translation module which allows you to translate your user interface. And before we needed the localization update module for downloading your PO files automatically. So now this is in core already so you can use interface translation module and it has this available there and it improves the usability a lot. Then we have the content translation module which allows you to translate all your content not only notes and taxonomy terms but also any kind of entity that you can have in your site. If you have Drupal commerce it can translate your products and provides the user interface for actually translating them. And then we have the config translation module and in Drupal 8 we introduced the config management system which allows you to move configuration around different environments or share them with different sites. So we actually need to translate this configuration to and the config translation module allows you to translate your blocks, your views, your field settings and it provides a unified translation UI and it looks like the content translation one. So starting with the language module we are going to see which APIs we have available here. So the first thing we want to do is we need to deal with the languages and for that we have a service which is the language manager and even in if you don't install any module this is part of core so you can actually use it. You don't even need to install the language module. You have a language manager available because for dealing with languages we need to put that in there so we can manage the language of our data even if it's in English only. So calling the Drupal language manager returns a language manager object which is a service that you can use for tracking and managing your language but if you install the language module the same call will return a configurable language manager. And they share the same interface so you can check this, you can call the same methods on them. The way that you don't really know to be aware if you have a multilingual site or a monolingual site when you are dealing with APIs from your country for custom modules. So one of the most important methods that our language manager has is the get language methods with if you don't have language module enabled it has three languages. The default which will be English as it used to be in Drupal 7 and in Drupal 7 we had a special language which was the UND language which was somehow confusing for people. So now we added a new one which is the not applicable language so we can maybe double the confusion. So actually the difference is that in our site we may have data which is in a language which may be English in this case if we didn't install the language module but we may want to track the language of data when a language doesn't make sense. So we may have users that are loading content and we don't know the language of this content and they don't select it maybe we are automatically retrieving it from somewhere. And then we would assign the not a specified language like we don't know the language of this data but there's also the possibility that we are loading an image and the image has no text on it so actually the language doesn't make sense there so in that case we would be using the not applicable language. And if we install the language module we can actually use different languages so in this case we will have Hungarian and Italian and we still have the two special languages not specified and not applicable. This if we install the configurable the language module or language will be configurable so we can edit them add them anything you can do with languages and they are actually they are actually config objects so you can deploy them and anything so they are safe like any other config entities in the system and you can export them to a YAML file. And in our interface when you pick the language you are using in some cases it doesn't make sense that you see the not a specified or the not applicable languages so they are special and we don't want you to edit them or delete them so they are locked and this is something that you can see when you export your config and your configurable languages you will see that they have a lot of property and your regular languages are not locked so how we deal with languages how we can create languages so if you have the language module installed you will have a configurable language class which has a create a method so you can create your languages but if you want to use the 95 standard languages that come with Ruble so you don't want to provide the native names or the names you only need to provide to use the LAN code they will be used so you call configurable language create from LAN code you pass the LAN code and then you can save them but if you want to have your own languages you can just call the constructor of this class and save it in the same way you can do whatever you want with languages so you can load them you can edit them you can delete them through the APIs and it works exactly the API will look exactly the same that the API you would use like dealing with nodes and another thing that the language module does is that it detects the language you are requesting in your page and if you need to deal with the language that is being used currently in this request you can use the language manager get current language method for that and it will return the current language object so in summary languages are configurable entities so you can do CRAT operations on them you can also get the language which is being negotiated on the page and you can do whatever you need with them from the APIs like you can edit them assign change their name which may be not that common but you can do whatever you want so now that we have languages on our side the next logical step is translating the user interface and for that you may remember for from Drupal 7 the T function that is still there and in most of the cases is all you want to know about how to translate your user interface so we could say that there's no change and we just leave the room but actually internally it's really different and you may not want to use that one actually because in Drupal 8 we introduced this concept of dependency injection who is aware of dependency injection half of the room so usually in our before Drupal 8 in Drupal 7 what we usually did is like we had our logic in our code and we need to know about the user that is in our site so we we could call methods for dealing with the users and we need to know the configuration of our site because we may have a user that has a different preference of a language we may want to know the configuration of the language on our site and then we need to actually call the translation functionality so with dependency injection what we are doing is just reversing the arrows and in some way we provide when we have a class or a service that is dealing with any logic what we want is to know which other parts of the system it depends on and the a good way of knowing this is like instead of having calling external code what we do is that during we inject we pass through the constructor or any other ways we pass the dependencies they need so they keep an instance of a reference of them so they can actually call them one good thing about this is that we can switch them if we have an interface and we know that we need to know some data about the user and we know that there's a method for that we don't really need to know which user system is you we are using maybe we are integrating with an external system and it provides the user who saw we don't really need to know about the details of that we just know that there's a contract and this service will use that contract so we know which methods there will be and we don't really need to know what they are doing so here we want to have a way of having this so we don't really need to know if and there's a translation system in place because we may be in a monolingual site and actually we want like the language we saw before the language manager can be different if you are in a monolingual site or if you have the language module installed so we need a way to provide this translation service and a way that we can switch it and for that what we will use is the this T method so if we are creating a controller or a form we are probably standing from base classes that are available in Drupal 8 core like form base and it will already have a T method that we can use so we will be calling the this T function instead and it will call the translate the proper translation service and it will call the T function on that one but if we are creating our own class that doesn't extend from anything else in the Drupal system we can actually use the string translation trade so we don't have to repeat our code about creating the T method and storing this reference to the translation service so this string translation trade will be providing us with the reference to the translation service and it will provide the T the D3 function that we want to use and as we said T is actually the same as Drupal 7 this T but internal is quite different so when we call T in Drupal 7 we get the string translated in Drupal 8 we actually are getting an object so we are getting a translatable markup object and we can call methods on it so we can actually if we call T in this in this string we can actually check the langcode option and we have several methods for knowing about this translation this way we can even alter how this would be translated later before the output is actually created and we could even avoid operation so if in Drupal 7 if we had a T call which returns a translation and then in maybe in a form alter later we are not dealing we are not really printing that string we had to translate it here if it's not going to be rendered we are not really translating it so at the end we may even make the performance of our site better so this is only the translation is actually only done when we are going to render the HTML of the page in the same way we had format plural in Drupal 7 now in Drupal 8 is gone so we have the this format plural method for that and it will work the same way so you you call the format plural and you will get an object that you can actually alter or whatever you need and if you are doing javascript it didn't change that much from Drupal 7 we still have the Drupal T method and the Drupal format plural method so for templates now in Drupal 8 we have tweak and we usually had PHP template before so you would call T on your PHP templates now we don't have that anymore so what we have is there are two different methods for translating your strings your literals in your templates so the first one is the trans filter which you can if you have a string you can pass the trans filter and it will provide the proper translation and like in the T function in Drupal 7 we have we can pass the context for maybe we want to request the translation not in the current language but in a special language defined language and if you use the first way it can be quite complex to read so there's another way which is using the trans tag like you can see that's downside there and this makes that the all the text that is between the trans and n trans will be used for calling the T function internally so and you can also have like variables there like you would have in in your PHP code another special thing is that in Drupal 7 you had your hook menu where you had your routes you had your links you had your menu links your tasks everything was in there now we split that and these are all located in Jamel files they are separated so we have your menu links in one side your routing is in a different place and you can it's a more flexible system and in Drupal 7 one thing you couldn't do is in your head hook menu you shouldn't be calling the T function for your title because it this way it would be possible to to cache your links and Drupal would take care of translating those in Drupal 8 is mostly the same and actually they are Jamel files so you can actually you cannot call any function on them but what we have here is that we have some special keys that Drupal 8 will take care of translating and if and the POTX module the POTX module will take care of extracting them and making them available like for provided configuration and provided links from core you want to translate them in localized Drupal.org maybe so this module takes care of knowing which keys from these Jamel files should be translated or not so in this case we will have the title and the description and they will be translated for you by Drupal 8. So this was about the interface APIs the interface translation APIs so at the end interface translation module what it does is that it provides the ability to translate from English to any other language and now next module is the content translation module and as we said before it's not based on copies of your notes or your entities so what we have here is that we have we will have clever objects that know about them so if you are creating your own entity type content entity types Drupal 8 would make easier to translate them so actually for creating a content entity type what you need to do is create a class in a special name space in your in your module and you have an annotation which describes the metadata of it defines what your content entity how it will behave so here we have the node PHP from core and there we have a content entity type with ID node then we want to provide a label and it's and for translating your labels in annotations you can use the translation this at translation and it will provide it will be extracted so you can translate them on your UI and for translating your content itself you only need to say that this flag translatable is true and if you want to translate your entities you need to know which language they are in so you need to define the lang code in the entity keys arrive and so just by doing this and you are actually telling Drupal that these entities are translatable or that the user could opt-in for translating them so this doesn't mean that the all your nodes can be translatable this means that the user can go to the language content interface and set up if they want to translate them or not and as we said we need a lang code field for that in our entity in Drupal 8 as in Drupal 7 we have two different kind of fields so first one is that the fields that are defined as part of the entity and then we have the fields that we can add to and that we can configure in the interface of the entity so if we are standing from content entity base when creating our content entities which we may we should do we have to define the base field definitions which provides these base properties that every entity of this kind will have and it already has the code for creating the field for you the lang code field for you so you only need to in the entity keys arrive define that you have a long code and you have to provide the name that you want to use for this field and if you extend and call the base field definition methods they will be created for you so in your definition when you are creating your entity you only need to ensure that you call the parent base field definition methods and you use the fields from there and then you can add your own fields so for your own fields you will you can you need to create the base field definition from there and then you have the a method for making them translatable what this makes again is is not that they are translatable is that the user can set them up as translatable and it will provide if we call the set translatable method in our base properties Drupal will know about it and actually it will provide defaults for same defaults for that so the user can configure them but if you make an entity translatable any field that have this flag on will be translatable by default and if we are creating our own fields how we can make them translatable there's nothing you need to do actually they will be translatable automatically so Drupal 8 knows how to make them translatable but at some point you may want to make more granular options like next example we have we are defining an image field here this is another example from core and in our field in our image we will have a file which is the file an entity reference to a file entity actually and we want to know the width and the height of this image and then we want to define the alternative text and the title of the of this image so a field can be composed of different sub properties and we may want to provide different translatability options for them so in case of an image you probably don't want to translate the image itself but you want to translate the alternative text and the title so what we have here is that in our annotation we can actually create groups like here we are creating a file group and we are saying that the columns of this group target ID width and height are part of this file and we don't say anything about translatability and for the alternative text we are saying translatable translatable true what this makes is that it will provide same defaults for when you are configuring your site so when you check translating an image file and image field in an entity you will see by default that you can provide different configuration for the file itself for the alternative text and for the title and by default the alternative text and the title will be translatable but not the file itself but you can actually make it translatable if you want so this is how you deal with your with your own entities how you make your own entities translatable and how you can provide more granular options for translatability of your fields so then we are going to see how you actually manage your your entities so the entity language API is quite straightforward so you have a node class for dealing with your nodes but you probably will have you will have the same for any kind of entity that you may create and you have a load method for it so you can load your entity and then you can call the get translation method so if you call the get translation method you will you can request which translation you want to work with and you will get a reference to the translation but it's actually another node it's the same node so you can do any operations you want with it and then save it or edit their fields as you were with nodes in any other situation so language here is quite easy to use and translations from these from these nodes are quite easy to use and if as before we said we may not want we may not know which translation we want like we may want the translation from the current language that has been negotiated so in that case what we would use is from the entity repository we will call the get translation from context method and we pass the node and what we get there is the node in the current negotiated language so there are a lot of functions or a lot of methods that we can use in our entities so we have a get and translated method that gets us the source translation the node originally was created in the language that it was originally created we can get the language object from the node calling the language method we can see which languages this node has been translated to with the get translation languages we get the list of the language objects we have the has translation method for knowing if there's a translation for a specific langcode the translation for actually creating it and remove translation for removing them so these are the API's that content translation provides for for dealing with your language or your content translation so but one thing is that in ruble 8 views is in core and its language support has been improved a lot so the purpose of views is actually it has two different functionalities one is making queries to the system so you can query the system about your data and then render it and these are the two different columns that you can see in the views UI so a language is quite integrated in in view so in the query part you can actually filter by language so you can actually filter your views by a specific language so you can say I want to filter by the language which is actually negotiated for the page and in the rendering side you can actually pick which language you should render your entities so you can actually with views do give me all the notes that are in English and then render the German translations so this is like a different the two different ways that you deal with language in views and it's quite powerful so you may even not need these API's at all so this was about content translation so what it provides is the ability for translating from any language to any other language and your entities are intelligent objects so you can actually call the methods on them for getting the translations for dealing with translation adding translations and anything so the next module is the config translation model in Rupert we have two kinds of configuration configuration objects and configuration entities for those objects which we can have a lot of them and we don't know how much like languages and we are going to see how we can actually translate them so our configuration is storing jammer files and what we do here is that we have or any a property in our configuration which is the LAN code and there any configuration object will have the LAN code this is in and for knowing for making our config translatable what we need is to provide a schema which it was introduced in Rupert 8 actually for translating your for knowing how to translate or dealing with languages in your configuration but that's actually used for for a lot of other things so here we are defining a config object and then we say that it has a LAN code and these are the data types from the core so we have a LAN code which will be a string and it's the language code and then we have another type of data type which is a text which it will be a string that it's actually translatable another thing that this config schema provides is that when you are calling your objects from PHP because you have the config schema you know the data types that this data is in so if you have an integer in your config and you call you load your configuration from PHP it will be automatically cast in PHP so you already will have an integer so for creating your own schemas you need to create in the folder config schema for module you create the schema jammel file and here you define the type of your configuration fields so here we are defining a we are defining the system maintenance object and we are saying that it's a config object this means that it will have a LAN code and then we are defining its attributes that there are in the that there are in this config object like in this case we have a message and we know it's a text so it will be a translatable string so our config will look like this we will have the message and we will have a LAN code and then when we translate this in our config folder we will have a language folder and then we will have a the land a folder for its land why for for its language with the LAN code as a name and then we will have a file with the same name and the properties that we are going to translate are the only ones that we will have there so if we have a Hungarian site and we have the system maintenance a message we will have a language hu system maintenance jammel where we will have this message translated same for Italian so how we deal with this configuration so when we want to know the configuration of our site we have the Drupal config service and we pass there the name of the configuration object that we want to retrieve and then we can access their properties with with the get method so we can get the message from the system maintenance object and if we have language overrides they will apply as appropriate so if we have this config object is translating and we are in a and we are in a Hungarian in the and the language negotiated for page was Hungarian we will get the message in Hungarian so this is how you usually will use your configuration from your system if you have a settings PHP and you are overriding some config there and you call the Drupal config method you will get this overrides applied to so there are different kinds of configuration that you may want to deal with so because this Drupal config method has the overrides applied we don't actually we cannot actually edit them it's mostly for reading configuration about the system but if we want maybe we want to get the configuration in a given language that we want we know which language configuration we want so then what we need to use is the language manager which knows about languages and it will we can call the com get config overrides language for for storing the language that we are currently using then you can set a different one if we want to use a concrete one like here set config overrides language and then calling the Drupal config will actually give us the configuration for a Hungarian for the Hungarian site so this can be quite useful if we are sending emails so the user maybe visiting maybe an admin is visiting your site your admin interface in English and it's mailing users but you want the users to get the emails in the language they prefer so this way you can actually get the language from the user object set the config overrides then call the config for getting the string of the email that you want to send and you will get a translated version of this email for that user preference and then you can set it back to the original language that you were using so we have three different ways for dealing with languages with configuration the first one is the system Drupal config this provides your configuration with every override applied so they are applied you will have like a priority system so any kind of override will be overriding the previous one so you pile your configuration values then we have the Drupal config factory get the table for getting the actual the current configuration in the original language so no overrides apply this is useful mostly if you are creating your own config forms and then we have as we saw we have another method for getting a concrete configuration object if we know the language we want from it which is the Drupal language manager get language config override so we can get the override the config with all the overrides we can get the config as raw data with no overrides or we can actually as the system for getting a concrete override so summarizing the config translation model allows to translate your configuration from any language to any other language and in difference with the content translation model where you have intelligent objects here you mostly have a rise that they are if there are config overrides they are going to be merged but you are actually using a rise so the APIs are maybe not that beautiful as the content translation once so this was I hope you like the different APIs that we have this was the work of a lot of people so please thank them if you find them around and thanks also to Gabor Hoitzi which part of this presentation is based in a previous presentation and here's the initiative lead which did an amazing work on making languages better in Drupal 8 and if you like it but maybe you want to improve it or maybe you think that it could be quite better you are welcome to join us in the contribution experience there will be workshop for five-time sprinters so anyone is welcome no matter your experience so please drop by and there will be mentor course print where we can help each other to improve Drupal and the general experience too if you already know what to work on so that was it thank you very much for attending if there are questions there is a mic there so hello hello I have a question concerning performance do you know how does it scale when you enable couple of dozens of languages and when you work extensively with revisions how does it work in the background and in the database you know does the node load take them longer does it load every all translation at once or does it only load on the trend the language is only month so the quest so the translations the different revisions so when you load a note you are actually loading the last revision that is published and for that and you are actually loading the current language of the language negotiated for that page and you are getting that object and when you access a different translation these are actually great to system so when you load a note you are not loading all the translations but you are loading the current language one or the one that you are asking for does that answer your question so related to that does that mean that the the cash tag metadata includes the language components yes so when you load okay so the question is about how the caching works in ruble so in ruble it we have this new caching metadata which allows you to provide different tags that you can then invalidate so when you load a note this note is actually cached and the question is how language applies to that so when you are when you are loading a note the language that you are requesting is actually provided as a cash tag so you can invalidate you can actually cash your notes by the language you are requesting and then you can invalidate the concrete translation that you want to so if there are not more questions thank you for coming please evaluate the session and enjoy the conference thank you