Problem/Motivation
When you add a language to a site, you'd expect that the language names would be provided with translations automatically. They aren't.
For instance, if I add Spanish to a site installed in English, I would expect that my site would now know at least that Spanish was "Español" and English was "Inglés", in Spanish. These translations are available on localize.drupal.org, but they're not getting into my D8 site automatically. The reason this is not happening is that languages are config entities that are not provided by Core, but are created by users after installation. Much like if you create a field labeled Foo, you don't automatically get "Foo" translated. But languages are a special case -- the language name labels are translated on localize.d.o, because they are part of the "Add a language" dialog (originally sources from LanguageManager.php). So they are somewhere between a shipped configuration entity and a custom one.
Proposed resolution
1. Modify LocaleConfigManager to also fake language entities as if they were in install storage for the scope of locale integration. This integrates perfectly with the interface translation system and will translate built-in languages.
2. Add tests.
Remaining tasks
Review. Commit.
User interface changes
Language config entities would automatically receive translations.
API changes
None.
Comment | File | Size | Author |
---|---|---|---|
#27 | interdif-20-27.txt | 763 bytes | fran seva |
#27 | 2397281-language-translations-27.patch | 5.22 KB | fran seva |
#27 | 2397281-27-language-translations-ONLY-TEST.patch | 1.15 KB | fran seva |
#20 | interdif-5-20.txt | 1.15 KB | fran seva |
#20 | 2397281-language-translations-20.patch | 5.22 KB | fran seva |
Comments
Comment #1
Gábor HojtsyI think the solution would be something like this, if the language list is updated at that point is save() already.
Comment #2
Gábor HojtsyNeeds at least tests :D Anyone wants to help with that?
Comment #3
jhodgdonCan a test get the stuff from localize, and depend on it being there?
Comment #4
Gábor Hojtsy@jhodgdon: No we should hardcode a .po file that has translations for the languages being tested. Such as LocaleImportFunctionalTest has a de and an xx .po file which are copied to the translations dir. It also has .po files written out from test methods that are manually imported. I think from a results perspective, either should work fine.
The real catch here is my patch will have mixed results, because you can only import translations for languages you added before, so trying to t() a language name to the one you just added will not work. What will work is the newly added language will be translated to languages already on the site as available.
Also doing this in the form is not very nice. It will not happen if you import configuration for example or use the API to add a language. I think instead of doing what the patch does, we'll need to trick the LocaleConfigManager to think that the languages have some default install storage. Ie. add 2 new methods to LocaleConfigManager to wrap getComponentNames/listAll and read() on the install storage and fake the languages as if they were in install storage as afar as LocaleConfigManager is concerned. That should not be very hard hopefully :D
Comment #5
Gábor HojtsySo I think the patch would be something like this to work seamlessly with configuration translation creation and update. This is totally untested but may already work :D Basically we simulate configured languages that also have a predefined language as if it was shipped config with the predefined language name.
Comment #6
Gábor HojtsyTried this out. Installed site in English, added German and Hungarian. Shipped languages (English, Not specified and Not applicable) were all translated properly to German and Hungarian but German and Hungarian were also. Looks to me like it works perfectly :) I also tested installing in Hungarian out of the gate and then adding Afrikaans and German. While not all languages had translations (I think due to missing language translations on l.d.o), it worked similarly well.
(BTW I found #2407907: Configuration translation entity listings displays items overriden on the way).
Still needs tests. I think I explained in #4 how to add tests for this. Anybody up for this? If you want to use the .po single file import UI in the test, then #2095787: Configuration translations not updated when manually importing a .po file is a pre-requisite for the test to work).
Comment #7
Gábor HojtsyComment #8
rodrigoaguileraI will give this a try (add test as I understood) without the .po single import UI
Comment #9
Gábor HojtsyThat will fail without #2095787: Configuration translations not updated when manually importing a .po file, so if you want to go that way, that needs fixing first.
Comment #10
rodrigoaguileraOk, I'll wait for that fix then
Comment #11
Gábor HojtsyWell, that one actually needs a test written, the fix is there, so if you want :)
Comment #12
DevElCuy CreditAttribution: DevElCuy commentedComment #13
DevElCuy CreditAttribution: DevElCuy commentedRemoved tag by mistake.
Comment #14
DevElCuy CreditAttribution: DevElCuy commentedRemoved tag by mistake.
Comment #15
fran seva CreditAttribution: fran seva commentedComment #16
Gábor Hojtsy#2095787: Configuration translations not updated when manually importing a .po file landed, so should be relatively easy to do a test for this. Easiest to add a language by importing the .po file that has the translation for a language, and then check.
Comment #17
Gábor Hojtsy@fran seva: still working on this one?
Comment #18
fran seva CreditAttribution: fran seva commentedHi Gabor.
I think I didn't understand what I should check after add the .po that create the language.
What I understood is the test should do:
1. Import a translated string for a language. I chose import from a hardcode .po using importPoFile method
2. Search the the translated string for the "new" language created in the import process.
I made a test with this steps but when I run it in 8.0.x branch the test does not fails. That make me think I'm not checking what is expected.
Attach the test and a snapshot with the test result in 8.0.x branch.
In other hand, reading the issue motivation I tried to import an spanish .po and created the "es" language and then check if the Spanish word were automatically translated but it wasn't.
Comment #19
Gábor HojtsyExtra spaces :)
The goal of this issue is to translate the languages themselves. So the .po file should contain the string "English" and "Hungarian" and check that those are properly translated. (Feel free to use Spanish or another language of your choosing BTW :)
You the test with $override = \Drupal::languageManager()->getLanguageConfigOverride('es', 'language.entity.es'); to check if the override was created properly. Checking for the anonymous user name does not prove anything about this issue unfortunately.
Comment #20
fran seva CreditAttribution: fran seva commentedThe test should work :p
Comment #22
Gábor HojtsyYup, the test looks straightforward and makes sense :) @jhodgdon: what do you think?
Updated issue summary.
Comment #23
jhodgdonYes, the test looks good to me!
One nitpick is that the comment says:
but the code is adding "de". ;)
Looking at the code... Wow, that's a lot of extra code just for this special case. I wish I'd looked at this patch sooner!
So the config system has this concept of defining "storages", of which there are already a few on the LocaleConfigManager. I'm wondering if it would actually make more sense (and really cut the lines of code down) to write out the default language config items to config files, perhaps in core/modules/locale/config/language, and define a storage that would read that one directory? Then for instance you'd have something like:
That seems a LOT cleaner than what's in the patch now, and similar things would be done in those other methods.
I think all you'd need to do is use the \Drupal\Core\Config\ExtensionInstallStorage class and do something like
Does that make sense? I guess it would technically make the patch bigger, since we'd need to create all the language config files, but it really seems like the code would be a lot cleaner and clearer that way to me. The way it's written now, it's a mashup of reading stuff from disk like normal and checking the default languages; using a config storage, it would just be reading stuff from disk like normal plus looking in one other place.
Anyway setting to Needs Work for the nitpick comment.
Comment #24
Gábor Hojtsy@jhodgdon: so we maintain this built-in language list now in LanguageManager::getStandardLanguageList. We could have a shipped config file for each, though if its in a special directory, we need to make the potx module have special support for it. Then we need to redo LanguageManager::getStandardLanguageList() to read from that directory or we have two copies of the list (one in there and one in YML files). At that point I am not sure that solution is much of an improvement, it is a lot more special case code in multiple places, instead of the self-contained solution here.
One more way to solve this would be to ship the language files actually as default config, but then remove them in the installer after they are all imported, so they are actually kept as default config but not in active config. Then we need to redo the LanguageManager::getStandardLanguageList() and/or the add language process to read from that special install storage.
While there are other options, I don't see those as simpler than what we do in this patch or more self-contained in any way.
Comment #25
Gábor HojtsyIf we think outsourcing the storage to some other service would be good, then we can subclass the install storage to an "install storage with languages" and put the special case code there and inject that to the locale config manager. That would also be more code because we'd set up our own storage and inject it here but would be very similar to what we do here. I did not think we would need the overall list of the entries or their contents elsewhere other than in the locale config manager, so I did not do that, but that may be an option I could stand behind.
Comment #26
jhodgdonOK. It was just an idea... I've been doing stuff with the ExtensionInstallStorage class lately in https://www.drupal.org/project/config_update and got familiar with it, so it just struck me that the code would be more symmetrical like this, but I see your point that you have other code already for the default languages.
But the code isn't actually too bad as it is. It's very understandable, at least -- it feels a bit like a kludge, but that's because it's merging two concepts, which is probably what it needs to do given #24.
I think if that one comment about 'hu' in the test is fixed it's probably ready to go.
Comment #27
fran seva CreditAttribution: fran seva commentedAttach the comment change :)
Comment #28
fran seva CreditAttribution: fran seva commentedComment #30
Gábor Hojtsy@jhodgdon: what do you think?
Comment #31
jhodgdonLooks good to me!
Comment #32
alexpottMe too. This issue is a normal bug fix, and doesn't include any disruptive changes, so it is allowed per https://www.drupal.org/core/beta-changes. Committed b9819fa and pushed to 8.0.x. Thanks!
Comment #34
Gábor HojtsyYay, magic, thanks!