Problem/Motivation
Some modules want to include the built-in translations as .po files, especially those that aren't published on Drupal.org and don't have a project in localize.drupal.org.
Usually, they place them here [module_root]/translations/[langcode].po.
And we have special configuration keys in the my_module.info.yml file to automatically import those translations during the module install:
'interface translation project': my_module
'interface translation server pattern': translations/%language.po
But suddenly, they don't work as expected because the configured path translations/%language.po is considered as the path from the Drupal root, not from the module root!
Steps to reproduce
1. Create a custom module my_module and put the translation info into the my_module.info.yml file:
'interface translation project': my_module
'interface translation server pattern': translations/%language.po
2. Place some translation files there, for example - translations/de.po with some translation strings.
3. Install the module.
4. See that no translation strings were imported during the installation.
Proposed resolution
To not break the previous behavior, I'd propose to introduce the module-relative path placeholder module:// and use it like this:
'interface translation project': my_module
'interface translation server pattern': module://translations/%language.poAnd extend the current Drupal Core logic to replace it with the actual module path.
For now, we can use a workaround with a custom hook like this:
function my_module_locale_translation_projects_alter(&$projects) {
$moduleName = 'my_module';
$modulePath = \Drupal::service('module_handler')->getModule($moduleName)->getPath();
$projects[$moduleName]['info']['interface translation server pattern'] =
str_replace(
'module://',
$modulePath . '/',
$projects[$moduleName]['info']['interface translation server pattern']
);
Remaining tasks
User interface changes
Introduced terminology
API changes
Data model changes
Release notes snippet
Issue fork drupal-3483087
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #3
murzI proposed a fix for this in the MR, please review. If it's okay, I can extend the tests to check this feature.
Comment #4
smustgrave commentedHave not reviewed yet but MR should be pointed at 11.x
thanks!
Comment #5
murzReworked MR to the 11.x branch, please review.
Comment #8
smustgrave commentedThanks for reporting, think next step would be to get test coverage added.
Comment #10
liam morlandI have added commits that improve the documentation comments.
Existing tests are passing. Tests need to be added for the new functionality.
Another approach would be to make a
%project_roottoken available for use ininterface translation server pattern.Comment #11
liam morlandComment #12
johnatas commentedHi,
I'm in the same situation, and MR !10167 works perfectly for my modules.
Note that — though I'm not sure if it's considered best practice — I'm experiencing the same issue with my themes as well.
Would it be possible to extend this fix to themes too?
Just for reference, I tested the following code on my project (based on the MR), and it works as expected:
Thanks!
Comment #13
murz@johnatas, good point about themes! So, maybe let's use a more general term
extension://instead ofmodule/themethen? Because, as I see in the Drupal Core, both modules and themes are named with a general term "extension" in functions, that work with both types.In the context of the Drupal installation with many modules, the %project_root usually means the Drupal installation root, not the module/theme root directory. And for that, we already have the default behavior, which searches for files from the Drupal root.
Also, token means that it can be used in any place of the string, but for that specific case, we usually need to generate the prefix of the path, not the middle part, so it's better to go with the protocol prefix approach, than with the token, I believe.
So, I think
extension://would be the best name for this. What do you think?Comment #14
johnatas commented@murz,
Yeah, that approach sounds good to me.
Now that I think about it, would this also make it possible to extend the functionality to profiles as well?
If needed, I can work on a patch with this approach in the next few days.
Comment #15
murzYes, profiles, as I suppose, are a subset of extensions too. @johnatas, and yeah, would be great if you can update the MR, cuz I want too, but too busy with other urgent tasks :(
Comment #16
murzAnd seems it's better to switch to the service "extension.path.resolver" and use the method
ExtensionPathResolver::getPath(string $type, string $name)but there we have to know the extension type again, it looks like the first idea with having "module://", "theme://" and "profile://" was good :)Here are all supported extension types:
But that splitting is strange, cuz we can't install modules, themes, and profiles with the same name together to one Drupal installation - see #371375: Do not allow a module and theme to use the same name.
Comment #17
johnatas commentedI’ve updated the merge request with the "extension" approach.
It works for both modules and themes.
However, it’s much more complex for profiles and theme engines, since using
ProjectInfo()->processInfoList()isn’t possible in those cases.Having never created a custom profile or theme engine myself, I’m not sure if they would even be concerned by custom translation handling?
It would be a shame to invest a lot of effort unnecessarily ;)
Comment #18
murzLooks good to me, thank you! So, the last step seems is to write tests.
Comment #19
murzAbout theme engines and profiles, I don't see cases when they can need translations, and profiles seems to be replaced by recepies, so I believe we can go as you've done now.
Comment #20
johnatas commentedHi @murz,
Sorry for the delay — I’ve just rebased the branch, which fixed the failing test jobs.
Is that what you were referring to? Or were you talking about writing new tests for the new code?
Thanks.