Problem

Drupal 8 has the configuration schema system with schema files that describe configuration so translatable pieces can be identified. With #1905152: Integrate config schema with locale, so shipped configuration is translated committed, locale module uses this to pull in translations from localize.drupal.org and save locally, so shipped configuration is translatable. However for edited configuration or when creating new configuration (your own blocks, your own views, your own contact categories, menus, taxonomy vocabularies), there is no UI whatsoever to translate those. Heck, there is no user interface to translate your site name.

Regressions resolved by this issue

There are also regressions in Drupal 8 fixed by this issue.

Drupal 7 allowed to provide a native language name which Drupal 8 does not allow (in favor of translating language names and using the native translation). This module provides the user interface for that.

Proposal

Add a configuration translation user interface in core. The module builds forms off of configuration schemas and automatically attaches translation operations to overviews and edit forms. The most up to date work can be followed at http://drupal.org/project/config_translation with regular core patches posted here.

Finally, while we have been working on this issue, we identified and resolved dozens of core bugs and developer experience problems, all of which made Drupal better. This module is in many ways sitting across subsystems like Views. It maps sets of configuration keys to routes. These sets may be based on config entities as well. Then it generates new routes based on those, as well as tabs, config entity list operations and contextual links. These lead to pages served by a pluggable system presenting automatically generated language overviews and then automatically generated translation forms relying on the configuration schema API and typed configuration. The saved files are picked up by locale module as configuration translations.

High level architecture of the module

This is not a 100% detailed structure diagram, since that would probably be more confusing than helpful. This level should help understand what this module does and what subsystems are involved. In short, the module's sole purpose is to write config translation files (at the bottom) providing a user interface to that. Producing those user interfaces is based on configuration schemas (to structure forms) and then the placement of those pages in the right parts of the admin experience are ensured by mapping routes to the configuration names being edited. So in-context translation experiences are provided. For translator-only access, there is also an index of translatable configuration that only requires translator permissions, so every use case is covered.

This is a pure UI module that interacts with existing data from Drupal core from configuration, routes, configuration schema and locale overrides. The later is the only thing that it actually writes (or deletes) based on user interaction.

Sampling of user interfaces provided

Entry points provided are in-context (tab (2), operation for entity lists (4) and contextual link (3) as appropriate). For those without other admin permissions, there is a dedicated index of all translatable configuration (1):

The translate operations lead to a summary screen with language translation status and actions for editing/deleting and adding translations:

The overview screen delete operation leads to a standard confirm form (no screenshot here, its trivial). The edit/add operations lead to config schema based forms:

Remaining tasks

tl;dr: Commit!

We are only going in circles at this point doing different cleanups. These can be done anytime and will need to continue to adapt to core API changes anyway later on. The module has plenty of test coverage and singlehandedly found dozens of core issues since we are working on it. It has extensive phpunit test coverage and was accessibility tested (see #2003834: Accessibility fixes based on suggestions and then validated in person by @falcon03). See issues at http://drupal.org/project/issues/config_translation for ongoing work, but these can be moved to the core issue queue as well later on.

Core blockers are all fixed. There are core issues that may make parts of the code simpler. All in-code @todos are core dependent and have proper links to core issues.

Testing steps

1) Install Drupal 8 with this patch (or even better check out the 8.x-dev branch of the contrib config_translation module, eg click on http://simplytest.me/project/config_translation/8.x-1.x-dev and start testing there)
2) Enable configuration translations under 'Extend'
3) Add French and German as languages under 'Regional and language configuration' (and/or any other languages)
4) Go to 'Configuration' - 'Site information' => do the translations on this page.
5) Check that site name translates on front page (enable language switcher block for easy language switching)
6) Do the same for Views, contact categories (get multilingual contact emails!), block titles, user email text (get user's language specific block/approval emails) etc.

Known (core) issues

Note for anyone testing, you will most likely hit the "bug" that not all config entities have a proper translation tab. That is due to #2135787: Move static config entity local tasks to local_tasks.yml and #2111823: Convert field_ui / Entity local tasks to YAML definitions which are both core *lack of conversions* of old tabs to new tabs. The old tabs are not added to the new tab system, so we cannot extend them. There is *nothing* to change in this module, as the new tab conversions happen, the translation tabs will automatically show up. Unfortunately those two issues can only be fixed at the same time, again because they convert the old tabs to new tabs for the same pages in different modules.

However although not all config entities have translation tabs, they do have several other entry points as shown above, eg. operations buttons in list controllers and the config translation index itself. So this is not something this patch could change/fix in any way, it is dependent on core conversions that did not happen yet, and the translation pages are accessible and work perfectly.

Sub tasks

Summary of sub-tasks that has been found & fixed in config_translation module, since this issue created.

Here is a snapshot of the current version of the module. It puts translation tabs on things like taxonomy vocabularies, contact categories, views, site information, account settings and so on and on, and lets you translate them to foreign languages. There is obviously a form generation layer on top of the schema system, however there are three additional "layers" that we needed to build

- define configuration file groups, since some forms use multiple config files (eg. account settings form in core), we need to display the configuration for these at one screen too
- define a path to configuration file group system with optional Edit tab addition, so screens having no Edit tabs yet get a tab for that, so they can switch from translation to editing and vice versa
- define an entity mapping system on top of this for config entities, so path patterns are handled and concrete entity loads are then translated to above said config file groups

So the real missing pieces were UI <=> config files where UI is path first and foremost but also optional edit tabs, option to create translate as a tab (most of the time) or just callback (eg. views), etc. I don't think we can extract this kind of information from anywhere, so we have our own way to specify these. We are chipping away at tasks at http://drupal.org/project/issues/config_translation?categories=All but any review comments are welcome nonetheless.

So the real missing pieces were UI <=> config files where UI is path first and foremost but also optional edit tabs, option to create translate as a tab (most of the time) or just callback (eg. views), etc. I don't think we can extract this kind of information from anywhere, so we have our own way to specify these.

@plach: yeah, the operations API would help a bit. It would still not match non-config entity config files to paths and it would likely not give us the title in the form we need to produce a reasonable page title. So either way, this is a design decision in the config system that the config storage is entirely disconnected of the forms and UI managing the config, so we cannot really tell this without codifying the relationships for our needs AFAIS (at least for non entity config).

This code definitely needs to use the new routing system, forms classes, and so on I think. Many of those things are still baking and being applied to different parts of Drupal, so were not readily available when we worked out the initial version.

It might not be the final UI, but I think its ready for an accessibility review, yes. There may be minor accessibility issues with the source value markup, but generally we are just using plan operations lists, translation tabs with classes Drupal tables and classic Drupal forms. There is no JS for example in the whole module :) There is likely possibility to add some extra metainfo to the markup to aid accessibility definitely. Tips around that would be welcome!

@likin, here is check list:
1. Have more than 1 language enabled?
2. Logged in as admin or user with permission to administer config translation
3. Are you checking Core config page(site information is a easy one).
4. Last and bit silly, sure it is up to date config_transalation module from d.o/project/config_translation ?

1) installing drupal 8 with this patch
2) enabled languages under 'exted'
3) added French and German as languages under 'configuration'
4) went to 'configuration' - 'site information' => on this page I did not find the translation tab

First off, it is hard to distinguish the "source" information from the form field where to type its translation. This issue could be solved by adding the language to the label of the information that you are translating.
So, for instance, to translate the site name you could have something like:
Site name (Source language): site_name
Site name (Language_that_you_are_translating_the_information_into): form field to translate it
If this additional information should not be shown to sighted users, it can be wrapped in a span/div element which the "element-invisible" class can be assigned to, so that the information is available for screen reader users, but not for sighted ones.

When you try to translate the displays of a view, you get lots of buttons labelled "display settings". You can understand what display a button refers to only after clicking it. This is not good for accessibility and (maybe( for usability too. And I was also wondering: does it make sense, from a usability point of view, to have the display settings in collapsible details elements?

And finally, I think that the Source text that you are translating into another language should be wrapped in a div/span element, which "lang" attribute should be set to the appropriate value according to the source language. It could be also appropriate to set the "lang" attribute of the form element to translate an element (e.g. the site name) to the appropriate value according to the language that the text is going to be translated into.

Site configuration seems to work for site_name but it does not work when trying to enable block translation.

I have tried to enable block translation on the "Custom language settings" page. After doing this, when I create a block I am prompted for a language. However, when trying to add a translation I get the following error so I cannot get to the translation page:

Fatal error: Call to a member function getLangcode() on a non-object in /var/www/drupal/core/modules/config_translation/lib/Drupal/config_translation/Access/ConfigNameCheck.php on line 34

I saw that we have a selection when creating blocks to use "interface" translation, so I tried creating one using "content" translation. I have therefore tried using both methods.

Lastly, even if a language is selected when the block is created, it does not show this field when editing the block.

I have tried to enable block translation on the "Custom language settings" page. After doing this, when I create a block I am prompted for a language. However, when trying to add a translation I get the following error so I cannot get to the translation page:

This will conflict with the $arg patch if it gets in. Since the second argument isn't used, it could be left off - then if that patch does go in this won't break and vice versa.

+++ b/core/modules/config_translation/config_translation.moduleundefined@@ -0,0 +1,382 @@+ $output .= '<p>' . t('The Configuration Translation module lets you translate configuration from all around your Drupal site. Views, your site name, contact module categories, vocabularies, menus, blocks, and so on are all stored with Drupal\'s unified configuration system and can be translated with this module. Content, such as nodes, taxonomy terms, custom blocks, and so on are translatable with the <em>Content translation</em> module in Drupal core, while the built-in user interface (such as registration forms, content submission and administration interfaces) are translated with the <em>Interface translation</em> module. Use these tthree modules effectively together to translate your whole site to different languages.') . '</p>';

This should be a twig template straight off - it's not performance sensitive and there's still the goal to remove all theme functions by release - that goal might not get met but let's not add any new ones.

If your single language is not English, yes. The shipped config like menus, content types, etc. should be in English shipped with Drupal core, so you want to translate that to your non-English. If you only have English then no translate tabs should show.

I'm not sure we can target multilingual values as well if we want to see this land in the coming month or so, which is theoretically as much as we have. That would need extension of the schema API for things that are not translatable but multilingual and UI integration for that too (but no locale integration). It may or may not be a huge thing. If someone wants to run with it, sure, but I think we have enough to concentrate here to resolve still.

The translation worked fine for me for those two fields. Is there some specific/other testing that is needed?

As Gabor was saying, we cannot afford even a single critical, hence ideally we should test any use case reproducible with D8 core at least. I think a good test would be building a relatively complex site (with just D8 core) and try to translate views, (non-custom) blocks, fields, content types, vocabularies, image styles, contact categories, language names. Basically test any module that has a .schema.yml file in its config/schema directory :)

- configuration with 'label' and 'text' type elements should have translation screens (not all have, but that is not major, integrations are not full yet)
- those translation screens should work and save translations
- those translations should appear on the site when using the config (eg. menu, vocabulary, etc)
- those translations should not show up in the admin form for the config when editing the original value (this may be a problem for some of those config)

So any schema.yml files with "type: label" and "type: text" are relevant for us.

Check for list of .schema.yml that has either type: label or type: text

Check for corresponding front end UI of the config.

a. CASE 1: No UI - not sure how to deal it. But we can note.
b. CASE 2: UI exist, but no translation - we can add an issue in config_translation. config_translation_config_translation_group_info has the list of config page/entity that are added atm.
c. CASE 3: UI exist and translation tab available - We need to make sure we got all fields displaying proper. In case schema and config aren't sync, need to raise a issue with core.

I think it is time for some serious over-arching reviews here as well!

1. As pointed out by @pwolanin, hook_menu() is still pretty much in this patch and it has outside dependencies (that are also applicable to Views, et. al.). I don't think that should legitimately hold this up. See #92 above.

2. Apart from that this module introduces **one new hook** to map UI paths to sets of config files (or entities). This may be better suited for a plugin system. Anybody agrees? Anybody want to work on that?

There are outstanding configuration schema issues to cover all parts of configuration, but they are outstanding either way, so I don't think there is any pressure on this issue to complete them all before this can land. The proposed patch does include tests to ensure all config files and config entities in core covered actually have a working translation screen which implicitly also tests that there is at least high level configuration schema coverage for *all of them*.

1- Installed the site in English.
2- Added two languages -- Spanish and Turkish.
3- Browsing to /admin/config/system/site-information/translate, I've translated the site name and slogan to those two languages.
4- Adding the /es and /tr, I've confirmed that site name and slogan get translated.

Screenshots:

Attached screenshots.

Feedback: It would be nice if language names weren't all lowercase. I can submit a patch for that. Am I allowed to?

I installed the config_translation module. I checked the functionality. I manually reviewed the code and functionality.

Functionality is working fine.

Here are some points:
config_translation.api.php - line no 10 - why we kept the @ and curly bracket
config_translation/ConfigGroupMapper.php - line no 253 - why returns the method null, I am not sure about this.
Controller/ConfigTranslationController.php - line no 44 - $langcode = $request->query->get('langcode');
$langcode is unused variable.

I've opened #2083615: Use links annotation for config entity URI like for content entities which would help a great deal to not need to redefine the config entity URL patterns. That would make those available via the config entity info system, so we can automatically grab those, similar to how we do that for config prefix now. Would improve the DX a great deal not just in core itself but for config_translation. Again, another great synergy of this being developed. Support welcome there!

- the FormInterface has this method, so we cannot leave it out; however since we are saving translations where we don't know anything about specific required patterns or structures (beyond number, text, etc. fields that the form validation system already ensures), so this needs to stay

@purabkharat: also re the @todo's, I just removed two outdated ones from the code. There are 893 @todo comments in Drupal 8 core as of this point. So I'm not concerned that adding 3 more will be an issue. These are not critical, more nice to haves.

@all: we can simplify the config entity mapping stuff a great deal if we can automate path generation and simplify/automate tab generation. The following two core issues would help *A WHOLE LOT* with improving the DX of integrating with this module, so help on those are very welcome *now*:

+++ b/core/modules/config_translation/lib/Drupal/config_translation/Controller/ConfigTranslationController.php@@ -0,0 +1,182 @@+ // on a single route due to the hook_menu() parent limitation.

There is a plan to require an explicit parent entry rather than figure it out automatically by path.
Can we get an @todo to revisit this when that is in. I assume that means we can clean this up significantly? We had logic like this in forum module that we've since killed but I think this sort of stuff still lives on in taxonomy.
Also #2112711: Provide an easier mechanism for using drupal_get_form() directly makes a huge difference here, so perhaps a todo for cleaning that up here too.

In other places we're injecting the field.info service, here we're using the static method on Field, I think this approach limits unit-testability as it requires the container. It also means the dependency is hidden (not visible in the constructor).

@larowlan: thanks for the deep review. Some of your points are already fixed in our dev branch (eg. lack of scoping for test methods, block ID changes, etc. - there have been 4 commits before the above patch was rolled, things move fast https://drupal.org/node/1931812/commits :D), some others are resolved in #2113283: Small clean-ups all around... or to be resolved in other sub-issues already. Many are new though. We'll need to review your comments one by one to ensure all is taken care of as possible.

Promoted tstoeckler and webflo in the list of people based on their amazing work on the code, modernizing to D8, putting in the list UI, etc. Also added timplunkett for his work on the tabs code along with dawehner.

@larowlan: All right! You've got feedback for your feedback! All the items where I wrote "Fixed." are actually fixed in #2114439: Fixes for the big larowlan review, that is not yet committed as fixes but the patch is posted, so being tracked. (There are some items already fixed on 8.x as well as indicated). Still many to talk about / look into.

1. You figured this out :)

2. Fixed.

3. To discuss. language_load() does not have an OOP alternative/equivalent that I know of, if you look at https://api.drupal.org/api/drupal/core%21includes%21bootstrap.inc/functi... and language_list() consequently, there are lots of mangling done there on top of the config entities (the duality of config entity + runtime language classes exist to serve the config system depending on language); Suggestions welcome. Not that there is a LanguageManager in core which is *not* about managing language objects, it is for language negotiation (also being reworked in #1862202: Objectify the language system)

4. To discuss. Is it a requirement now that classes come with unit tests? :) We did not include lots of unit tests so far, however we have a whole lot of web tests to ensure integration and all the intricate details of how the mappers integrate with routing and form generation.

5. Fixed.

6. Fixed.

7. Debated. The return value tells you whether the action you wanted to do (set with the passed entity) worked. If there already was an entity, your action DID NOT work, so you get FALSE. IMHO the one-line comment properly summarizes that?

8. Fixed.

9. To discuss. Sounds to me like almost every method would need to throw that exception then? I mean most methods use the entity type, id, etc. Is that your suggestion?

19. Discuss. Inline docs on the type returned. I think @tstoeckler found some standard to follow here :) Debated?

20. Discuss: The problem is we cannot register each form on its own route, because menu_router() table only allows for items nested to a certain level. If this is not anymore a problem, we can register them as individual routes (ie. add 3 levels of depth to any path we attach to instead of the +1 level we have now with the translate tab taking arguments for langcode and action). I'm not sure any of the issues you linked are related? Did you understand the same problem that I re-explained here? :)

21. Discuss. Yeah, we should. Do you know of a good way to check access to that route/path in the curent system?

35. Todo. DerivativeBase does not have t on it :/ We'll need to inject ourselves.

36. Discuss. Same as 4.

37. Fixed (already in 8.x of the module).

38. Fixed (already in 8.x of the module).

39. Discuss. Sounds like this is still discussed, not decided. So not sure if we should move anywhere on this. Core did not decide yet either.

40. Discuss. Same as 39. I'd not follow experimental standards that may or may not be in effect later on. Following what core does is our best target, then conversions later are easier. If we are picking up on forming things, then conversions / updates are all the more painful.

3) Yeah not related to this issue, just saying 'ouch'
4) The class is loosely coupled and a good candidate for unit tests. Either they go in here or we have a follow-up. I know of at least two devs who are keen to write unit tests/get exposure to phpunit so a follow-up is entirely appropriate - so we should file it and mark postponed on this
7) Yes it does, but its weird - just saying
9) My understanding of this is that $this->entity can be NULL so calling ->id() on it would cause a FATAL
13) see 4
15) ok
18 ) ok
19) never seen it before, is all
20) i misunderstood, but this is certainly a different pattern, would be interested in someone like @timplunketts' input
21) See the PathBasedBreadcrumbBuilder, it has something like that, menu_item_route_access is a procedural equiv
35) I think timplunkett just added an issue to add it
36) see 4
39) just pointing out what @alexpott will if he reviews :)
40) ditto 39 but @dawehner

Regarding 19: I added that because PhpStorm then allows autocompleting on inline variables for which the return values cannot be type-hinted (This is the case for generic methods such as createInstance() and such). Since even without an IDE it can only help, I think, it makes sense to add. Also note that we've been adding these to core elsewhere as well, not very widespread, but some. @dawehner likes it just as much as I do :-)

First of all, the following tests were misnamed (Ui vs UI), so they haven't been running:
ConfigTranslationListUITest.php
ConfigTranslationUITest.php
ConfigTranslationViewListUITest.php
Check the last patch test results, you won't see them in there.

The patch I'm uploading renames them, but at least one of them fails.
If you're still running a sandbox you'll have to do some tricks to get them renamed with git (you can't do it easily on a mac).

----

Also, there are PHPUnit tests added, but with only 34% coverage. It shouldn't be too hard to boost that up.

This is a code only review, I saw a couple odd things while running the tests that I will call out during a UI review later.

----

I've also made a lot of nitpicky fixes as I went, because Dreditor was unstable with such a large patch.

I don't understand what is being passed through. It seems to be an Element always, except then it is foreached() through and then it is still an Element? The getDefinition() calls and all don't seem to match up. And I don't follow how it could ever be TypedConfigManager.

First of all, ConfigTranslationListUiTest fails for me locally.
Secondly, ConfigTranslationOverviewTest doesn't test enough of ConfigTranslationFieldInstanceListController, we need a time when displayBundle() is true. So, the test needs to set up a field instance, and check the page for that (like admin/config/regional/config-translation/comment_fields) or something).

- I'm not entirely sure what would be great to unit test. My feelings on the entity mapper unit test for example are a bit mixed. The class is so simple and the tests merely test minor data processing happening in the class. Probably useful to some degree, but not sure they are practical. I agree it would be great to improve the unit test coverage. Not sure about code coverage for core in terms of phpunit, but my sense is we may be in a very good place already :)

Review points in #125:

1. I'm not sure why we pass on an empty plugin definition (and then how are the instances created in the base class?). I'd ask @tstoeckler / @EclipseGC who were the masterminds behind this part of the code.

2/3. Yeah I think the only reason is we implemented config entity discovery in the findDefinitions() method, instead of putting it into our info hook implementation (where we discover the field_ui based mappers). I think we could just move the config entity definition discovery into the module info hook, use $this->discovery and then not need this method. What do you think?

Note that it passes on the plugin definition to the createInstance(). Then however the createInstance() totally ignores that and passes on an empty array. If you look at the createInstance on the factory (https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Plugin%21...), then you can see this array is not supposed to be the plugin definition but supposed to be the plugin *configuration*. The definition is retrieved here (again) from the definitions. The configuration (which in our case is an empty array) is passed on to the static create method. Finally the ConfigNamesMapper has a static create method that at that point properly takes that argument as $configuration, but does not use it. Which is right after all, since we don't have plugin configuration for these plugins, we only have definitions for them.

So the right fix would be to:
a) not pass the definition in getMappers() and
b) remove our createInstance() method, since there is no use for it
c) keep ignoring the $configuration in the static create in ConfigNamesMapper()

Although concerns from @timplunkett and @dawehner have been resolved, we are impeded to move further by a testbot issue blocking the tests on the contrib module we use to build this project out. It would be a huge waste to keep posting untested things here, so all help in resolving that would be welcome: #2125349: Testbot not testing contrib 8.x with up to date 8.x core?.

Committing this would also let us remove 500+ lines of confused and conflicting one-off date format translation code from system module that crosses into the realm of locale.module pretty aggressively.

I'd love to get this into the next alpha release on Nov 18th (Announcement at https://groups.drupal.org/node/364138). It would nicely coincide with DrupalCamp Vienna coming up a few days later (with lots of multilingual Drupal 8 content :)

Please unleash your reviews and things you consider are commit blockers. I think we have been pretty diligent in working through those.

Here is a (I think final) update to get this to as nice as any other core module (or I think actually nicer :D). This includes making contextual link and tab dynamic titles work cleanly instead of a hack, cleaning up all @todo comments and using routes for different operations instead of GET arguments that we were forced to do before due to hook_menu() path component limitations. Also some other minor cleanups.

5b8a47d Issue #2134895 by Gábor Hojtsy: @todo cleanup, have *core* issue links for all of them.

All of our remaining @todo elements are dependent on core. We could wait around for those to get resolved (we are active on most of them, not just standing by), but core modules are also inbetween different APIs and have plenty @todos to convert to new ones as they emerge. This is not less true to config translation.

The patch now also includes a MAINTAINERS.txt entry (which should be mandatory with any new module :) and splits the *.config_translation.yml files to the right core modules as appropriate. These were not in earlier patches and obviously only apply to the core patch not to the contrib project that we use to build the code.

Made sure the issue summary is fully up to date and concerns from the above reviews have been resolved. We cannot just sit around and wait for everything in core to snap into place perfectly. We kept marching on finding bugs in core and will do so in the future. I'm confident we will uncover more bugs with core thanks to this module being in. It will be better for core in the end as now finally there is a module integrating some APIs that none other use in core or where there was minimal use before.

I was planning on RTBCing this myself once those two were in and this was rerolled, but now that it is RTBC I would like the committers to postponing it on those two issues (which are RTBC themselves!)

Updated the patch so it considers all recent changes on paths vs. routes. Also improved DX on the default definitions of config translation name mappers to follow the pattern of local tasks, etc. where the name of the plugin === the route name. Also added tstoeckler and vijaycs85 both of whom requested to be added as a maintainers. :)

Once again I'm sure this module is not 100% perfect and there will be core changes which will need to be reflected and adjusted. There will also be more core bugs found through this module :) We can likely continue tinkering with the module in contrib but its likely as good as any core module at this point (IMHO better :) and people will benefit from seeing the complete picture, trying this out, finding more of the bugs (in this module and elsewhere in core thanks to this module). So I think its time for this to get in. :)

Changes in this patch:

af48bc7 Issue #2136723 by Gábor Hojtsy: Titles are translated too early (or not at all).

I'm posting the interdiff from gabor's patch (interdiff.txt), as well as some additional code changes I added (changes.txt).

The hook_config_translation_info() hook makes me shudder in fear. It's copied 1:1 from the config_translation_config_translation_info() implementation, but it does a lot of different things and uses the route provider in a scary way.

Awesome! I did not think of doing it this way. Makes perfect sense.
The rest of the changes.txt looks good as well.

Will open an issue to let the testbot have a go at your patch and then get it in.

The hook_config_translation_info() hook makes me shudder in fear. It's copied 1:1 from the config_translation_config_translation_info() implementation, but it does a lot of different things and uses the route provider in a scary way.

Discussed with tim.plunkett in IRC the docs we can improve alongside improving the implementation itself which needs more core issues to be opened (for field_ui to be reworked in how it defines its routes). So only looking for review on his changes.txt :)

Here's a stab at improving the insides of hook_config_translation_info(). I'm not providing a full patch, but only the interdiff, as the former would have required this to go back to "needs review", while I still don't think that the simplicity of the example code (while certainly an issue) should hold up the commit of this patch. If someone likes the interdiff, I'll roll a full patch.

Note for anyone testing it, you will most likely hit the "bug" that not all config entities have a proper translation tab. That is due to #2135787: Move static config entity local tasks to local_tasks.yml and #2111823: Convert field_ui / Entity local tasks to YAML definitions which are both core *lack of conversions* of old tabs to new tabs. The old tabs are not added to the new tab system, so we cannot extend them. There is *nothing* to change in this module, as the new tab conversions happen, the translation tabs will automatically show up. Unfortunately those two issues can only be fixed at the same time, again because they convert the old tabs to new tabs for the same pages in different modules.

However although not all config entities have translation tabs, they do have several other entry points, eg. operations buttons in list controllers and the config translation index itself. So this is not something this patch could change/fix in any way, it is dependent on core conversions that did not happen yet.

There are several other core issues which would lead to improvements in this module, they are linked in in @todo notes in the patch. I'm sure we'll find even more like that as time goes on. The point once again is the module is already very solid, and tinkering with it in contrib will not get us the benefits of it being in core (even more eyes on it, crowdsourcing finding more bugs, help resolve config context related issues as we can experiment with translations, etc :)

That's it for my little speech :) Looking forward to have this in core for the next alpha!

Here's how far I got. Will need to resume in a couple of hours (today is family day):

As per usual with UX issues, I went in blind without reading the issue summary, so I could try and be as neutral as possible.

1. First, went to the modules page and turned on Config Translation. This also turned on Language and Interface translation modules. (File and Field were already on. Curious that those are dependencies.)

2. Went to admin/structure/views, clicked "Translate" under operations.
Only thing I can do from admin/structure/views/view/content/translate is edit the English translation. Right. I need to set up a language first. Always forget to do that when I test multilingual patches. (Help page didn't mention this step either.)

@TODO: (Separate issue) Maybe show a class=warning DSM that they only have one language enabled on screens like admin/structure/views/view/content/translate that links off to the languages admin page so I don't get blocked.

3. Now I'm at admin/config/regional/language and add a language (Japanese, to see how it deals with RTL).

@TODO: (Separate issue) I'd love any kind of visibility (textual description of the batches) as to what is happening during these 11 steps that take about a minute to run. e.g. "Fetching the translations from localize.drupal.org, unpacking them, whatever"

4. Back to Views translate. Add Japanese translation: admin/structure/views/view/content/translate/ja/add

@TODO: (Follow-up) We should maybe discuss what to do with this screen a bit more. At a glance, it looks like I can only translate two things: Administrative description and Human readable name. But there are literally hundreds of other things, getting to most of them requires clicking into the various collapsed field sets/details. And getting to each one requires click to expand, fill out a bit, click to expand, fill out a bit, etc. which makes what is already a daunting task feel even worse.

TL;DR: Should we auto-expand all of these fieldsets/details by default? Particularly if the English and XXX language versions still match?

5. Lost interest in doing this after a few mins, so just clicked "Save translation." Seemed to save ok.

Re. 1: The only dependency listed is locale (interface translation) which is the module which actually will pick up the translation files (there is no actual interaction with that module's API outside of that). The module *does not* depend on file or field, I don't know how did you get that, but there is nothing in the info.yml or otherwise to that.

Re 2: Whether one language lets you translate or not *depends*. Eg. if your site is Japanese only, you can already translate the built-in English views (you don't need to have English configured on the website, however the built-in views come in English anyway). That is the practical one language use case, which is/will be very typical. A DSM might actually help explain the situation where there is only one language configured and the original config is in that language. That case would require you to add a new language indeed to do something useful on this screen. (Note that we did consider putting an access check to net let you access this page if the config original language is the only language on the site but concluded it would be very confusing that you have translate operations on some views in a views list (or translate contextual dropdowns on some of your views) but not others. You would have no chance to figure this out without seeing that screen and making the connection about why. It is true that we did not end up helping you make that connection (with a DSM) once you arrive on this screen (yet) :)

Re 3: The batches are pre-existing to this issue. Separate problem indeed :)

Re 4: There is indeed an issue in the config translation queue to improve the views translation experience itself. Most (if not all) other configs are much less structured and have way less depth. The structure of the views page starts to get overwhelming after a while but where is the full depth of a view not overwhelming? :) There are for example dozens of labels at different levels, depending on whether you are in a display or field, etc. the label applies to something else. Translators need to know this context. The API was architected so it allows specific mapper classes to be used for specific things (eg. views) or if not specific mapper classes, their routes may be altered to provide different / optimised user experience for translation, etc. There are several entry points where the experience may be tailored for this most custom use case. It is in core a very unique complexity that other configurations don't have. If you look at content types, date formats or blocks, they are absolutely very simplistic.

Thanks @webchick and @Gábor Hojtsy for the quick review & comments. just to add @Gábor Hojtsy's comment on#192.4,
Can we have views config schema as a separate custom module (views_config_ui) because:
1. As we can see except views all configuration translation pages are simple and clean.
2. Views is one complex configuration which we might want to split into multiple storage (may be in Drupal 9).
3. we can apply 3 strike rule. now we got views. once we have two more complex configuration (like views), we should look for better approach.
4. This will keep config_translation very generic and would allow as to provide views specific UI and theme (which can just simulate views UI page with in-place editor for labels).

1. Interface translation (locale.module) does in fact depend on File module, due to the file handling it does with the translation po files, it depends on Field module, that's why all those show up under Config translation as well.

2. DSM++

4. I have also pondered about providing a separate, custom-tailored form for Views, simply because it is such a special-case. So, yeah ++.

Thanks for the feedback, all! Back again for round 2. I'll take a look at blocks after I'm done views to see how it compares.

TL;DR: It's awesome. :) If you're curious about my thought process as I was reviewing, feel free to read the innards, else skip to the bottom.

6. Went to the blocks page and added the language switcher block so I could change languages.

@TODO: (Separate issue) Not sure how a normal person would ever know to do this; I only know because I've tested other multilingual patches. Could we enable this block by default when more than one language is added? And/or possibly add another entry point for language switching at admin/config/regional/language, since I already found that page once? Hm.

7. Switch to Japanese, back to admin/structure/views. Awesome!! Now the "Content" view shows "Discontent" as the view name! (I was feeling punchy. ;))

@TODO? (Separate issue) Why did may toolbar orientation and views table columns, etc. not flip RTL once I switched to Japanese?

Ok, so the crazy use case works! Hooray! Let's try the easier one.

8. Still in Japanese, go to ja/admin/structure/block. Click "Translate" on the Language switcher block

@TODO (totally separate issue) Why is "Translate" the only thing I can do? Not delete/remove the block from the layout?

9. Add a Japanese translation.

10. Only thing I can enter is a new description for "Language switcher." Hm. I guess that makes sense? Everything else would be provided via the interface translation module?

11. Tried adding the "Recent comments" block instead, which AFAIK is not yet converted to Views and AFAIK has a "number of comments to show" setting. Turns out, it does not. But something happened and now all my Drupal-provided blocks have a dropdown in the operations column with "Configure" as the default. Cool. So I guess #8's @todo is some kind of bug then.

12. Tried clicking "Translate block" from the tab at the top of a particular block. That works, too. Yay.

13. Give up on blocks for now, cos I can't seem to find a block with additional configuration settings beyond just the admin description.

16. Go to ja/node/add, b4s1c p4g3 is there. Yay! Click it and… Hm. t1tl3 is translated. Body, Text format, etc. aren't. That's kinda weird, but I suppose is the best we can do, given title isn't a field.

@Question: Is there an issue somewhere to re-make title a field, or is this the best we can do in D8?

Well, this is absolutely awesome. I tried kicking the tires on pretty much everything I can think of. Views, Blocks, Content types, and Fields all seemed to work very well. Things I found were minor UX issues or totally unrelated bugs. The code has already been reviewed (and worked on directly) by the best of the best, so I won't bother with that here. AWESOME work, everyone!!!! :D

Despite this being classified as a feature request, I feel this is fundamental to touting the multilingual features in the Drupal 8 release, so I'm happy to make an exception to thresholds in this case.

I don't think we should be doing this, in one of the earliest tests we did it showed that people where confused by the fact that a block suddenly appears when enabling a module. In the usability test its case the search module, in Drupal 6.

Placing a block is almost always a explicit action, when its not people get confused. A good way to inform people about a new block, is adding it to the install success message.

Oh, BTW I also dug up why file/field module is required for locale. This commit added that where some file functions were refactored to be in file module instead of global Drupal functions: http://drupalcode.org/project/drupal.git/commitdiff/316c1f4a7a2c9654c372... (locale handles manual .po file uploads and a set of files in a directory as a result). Then file module requires field module because its a field. That is a bit of a twisted relationship, but this is the state of it in core for 15 months at this point.

I'm currently defining a configuration entity type and see the config_prefix property in the entity type annotations I'm referencing, but I don't see it listed in \Drupal\Core\Entity\Annotation\EntityType or documented elsewhere. I couldn't tell which of the related issues added this (if any) so perhaps it's just a convention that isn't officially part of the entity type annotation?