OrchardCoreContrib.PoExtractor icon indicating copy to clipboard operation
OrchardCoreContrib.PoExtractor copied to clipboard

Workflow question

Open skyflyer opened this issue 4 months ago • 12 comments

First of all, thanks for the effort you're putting in.

I've been using gettext style translations in Django and I'm considering using PO files for easier localisation into multiple languages. I see that the tool generates a POT (template) file, so I'm wondering if the workflow I am used to from Django is not applicable and what kind of workflow are you using?

In django, one uses makemessages to extract the translations to a file for a particular locale. e.g. django-admin makemessages -l sl would generate .po files for Slovene language.

One can then translate those messages, update code and when you run django-admin makemessages -l sl it just updates the translations with either additional context (msgctxt) or with new entries that are not yet translated but leaves the translations in the file.

Is this a feature that is on the roadmap? What kind of workflow are you using? Are you just generating the messages once and then... not anymore?

I can see two options:

  1. Use extractpo to generate the template file
  2. Use msginit the first time, to create the PO file
  3. Use msgmerge after that to update the PO file with the newly found translations added to the POT file (generated by extractpo command)

or

  1. Use extractpo to generate the template file
  2. Use Poedit (or similar) to update the translation file based on the generated file

Any feedback appreciated, thanks!

skyflyer avatar Aug 06 '25 20:08 skyflyer

Thanks for the input, @skyflyer. We usually use this tool to extract the PO for Orchard Core localized strings. For more information, please check https://github.com/OrchardCMS/OrchardCore.Translations

For custom development, we could use the extractpo tool to extract the localized strings

hishamco avatar Aug 07 '25 00:08 hishamco

BTW, we could add a locale option like what Django is doing nowadays, if you would like to propose a PR, I will glad to accept it

hishamco avatar Aug 07 '25 00:08 hishamco

Thanks for the feedback!

I will look into it and if I decide to pursue this path, I will surely provide a PR. I'm currently still figuring out how make it work, since the msgctx provided by extractpo seems to be wrong. The views have it as Project.Name.Views.Home.Index, whereas the actual classname is AspNetCore.Views_Home_Index or AspNetCoreGeneratedDocument.Views_Home_Index. So currently, I need to remove all msgctxt entries from POT so that translations work (which is a not so great workaround).

skyflyer avatar Aug 07 '25 06:08 skyflyer

A couple more observations and questions:

  • running extractpo global tool finds 343 strings
  • running from source code finds 4 strings (only in files ending with .cs) even if I explicitly pass -t Razor (the difference being that the nuget package is older and it used to default to both processors). OK, I figured I need to pass --localizers T, otherwise the defaults are not taken into account.
  • both, the tool and the source from the main branch produce msgctxt with the project name included, e.g. msgctxt "ProjectName.Shared.Views.Shared._SelectLanguagePartial" where only Views.Shared._SelectLanguagePartial is what the context should be.

I'm wondering what the correct usage or approach is here. I suppose I'm using this wrong? Could you please advise?

I will, in the mean time, create a PR at least for the default localizers program argument... as I believe this to be a bug.

To summarize:

  • the tool includes the project name in the msgctxt - the project name is not included in the context when translations are being looked up
  • the code in the main branch does not have any default "localizers" (field names to look for)

skyflyer avatar Aug 07 '25 11:08 skyflyer

So here is a "fix" that removes the project name from context (msgctxt) in the Razor CSHTML files: https://github.com/skyflyer/OrchardCoreContrib.PoExtractor/tree/msgctxt-without-project-name

All tests are passing (none are written for Razor) and I've tested it with deeply nested projects as well and it works (on my machine :)).

What are your thoughts? Am I using the PO localization infrastructure wrong, or is this fix in the right direction?

skyflyer avatar Aug 07 '25 12:08 skyflyer

@hishamco, what are your thoughts on the workflow and proposed fix?

skyflyer avatar Aug 08 '25 06:08 skyflyer

Why do you want to remove the project name from the context? We use it to distinguish between two identical localization strings that are located in multiple projects

hishamco avatar Aug 08 '25 16:08 hishamco

Why do you want to remove the project name from the context? We use it to distinguish between two identical localization strings that are located in multiple projects

Because, if the project name is not removed, the translation is not found - the provider provides the context without the project name. Is this something which can be configured?

builder.Services.AddPortableObjectLocalization(options => {
    options.ResourcesPath = "Localization";
});

There's only one option to configure.

skyflyer avatar Aug 08 '25 16:08 skyflyer

Could you please write a unit test to break this?

hishamco avatar Aug 08 '25 16:08 hishamco

I just looked at the Orchard code: The PO factory passes the context to the localizer and this context equals to Views.Home.Index (if the IViewLocalizer is injected into Home/Index.cshtml view.

With regards to unit test: there is little point in it, the way I see it, because you can put in it whatever you want - the way I understand it (and please, correct me if I'm wrong) is that OrchardCore localization factory decides what the context is - it is not up the extractor to decide what the context needs to be. At least that's my understanding.

If you look at the PortableObjectStringLocalizerFactory.Create method, it is called with ProjectName.Views.Home.Index as the baseName and ProjectName as the location arguments. And then, the location (project name) is removed from the resulting value that is passed as the context to the localizer instance.

Would it help if I prepare a simple repro website that uses PO localization so you can see for yourself?

PS: If it is just a unit test for the removal of the project name from the context (for the Razor part), that is another story - I can certainly write such unit test.

skyflyer avatar Aug 08 '25 17:08 skyflyer

Would it help if I prepare a simple repro website that uses PO localization so you can see for yourself?

As I mentioned before, OrchardCore.Transaltions is the repo that uses the current tool

PS: If it is just a unit test for the removal of the project name from the context (for the Razor part), that is another story - I can certainly write such a unit test.

It would be useful, thanks

hishamco avatar Aug 08 '25 21:08 hishamco

I created a pull request which includes two unit tests and a change to remove the project name from the .cshtml msgctx.

I created a sample project that this can be tested on: https://github.com/skyflyer/DotnetPoLocalizationDemo

The sample projects includes localization in .cshtml as well as localization in .cs (HomeController), which must preserve the project name (as it is part of the fully qualified class name).

skyflyer avatar Aug 10 '25 16:08 skyflyer