Skip to content

Translation zh_CN - #2757

Merged
simonmichael merged 1 commit into
hledgerorg:mainfrom
jack9603301:translation-zh_CN
Sep 30, 2026
Merged

simonmichael merged 1 commit into
hledgerorg:mainfrom
jack9603301:translation-zh_CN

Conversation

@jack9603301

@jack9603301 jack9603301 commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

imp: Add translation support for Simplified Chinese.

This PR adds translation files for Simplified Chinese (zh_CN).

In accordance with PO standards, frameworks that follow this convention typically use compiled .mo files. however, Hledger does not appear to do so. If you do not need them, please let me know, and I can remove the .mo files.

@jack9603301
jack9603301 force-pushed the translation-zh_CN branch 2 times, most recently from 0428655 to c70f097 Compare September 30, 2026 13:26
@acinader

Copy link
Copy Markdown
Contributor

HI Jack,

.mo files are not used

Can you post a screen shot or two? I'd like to see it.

Are you able to translate it the way that you would like? Did you have any problems where you aren't able to make the translation well?

I am not sure what policy hledger will use for accepting translations, but can you confirm that it is working well for you?

@jack9603301

Copy link
Copy Markdown
Contributor Author

HI Jack,

.mo files are not used

Can you post a screen shot or two? I'd like to see it.

Are you able to translate it the way that you would like? Did you have any problems where you aren't able to make the translation well?

I am not sure what policy hledger will use for accepting translations, but can you confirm that it is working well for you?

image

At least to me, the only question that seems reasonable is:

image

2008 损益表

From a Chinese semantic perspective, it is rather odd; typically, it should be written as:

2008 Income Statement

2008年度 损益表

However, it is obvious that the PO cannot selectively perform translation based on the passed parameters; therefore, unless the source code is modified to add an injection point for the Unit type, this is likely the best option.

@jack9603301
jack9603301 force-pushed the translation-zh_CN branch 2 times, most recently from 3f7bb28 to d89bf41 Compare September 30, 2026 13:56
Signed-off-by: Chunhui Ouyang <jack9603301@qhjack.top>
@jack9603301 jack9603301 reopened this Sep 30, 2026
@jack9603301

jack9603301 commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor Author

I cleaned up the commit history. there were a lot of inexplicable commits adding the .github/workflows/haskell.yml file.

It should be fine now.

@acinader

Copy link
Copy Markdown
Contributor

we should be able to alter the source code so that both english and Chinese (and German) can be represnted properly. Can you look at how you would change the source? It is probably a common problem and you can google how other people have handled it using gettext?

@jack9603301

jack9603301 commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor Author

we should be able to alter the source code so that both english and Chinese (and German) can be represnted properly. Can you look at how you would change the source? It is probably a common problem and you can google how other people have handled it using gettext?

I apologize, but since it is neither C/C++ nor any procedural or object-oriented language similar to them—and although I have used Typst (which is a fine typesetting system based on functional programming principles), I ultimately could not adapt well to Haskell's obscure and difficult development style—I am unable to truly grasp Haskell development. I intend for this PR to be editable by anyone. if you or others are willing, you are welcome to make edits and submit new changes to the PR's branch.

I would be happy to join the discussion. A simple approach is to adopt a strategy similar to using injection points: for instance, when the program enters a non-English translation mode, it generates specific injection tags based on variables such as the year, month, or day. Under a 2008 income statement view, a year_unit tag would be inserted while other injection tags remain unused. This allows the program to load the correct translation file based on parameters and respond to user input.

@acinader

acinader commented Sep 30, 2026 via email

Copy link
Copy Markdown
Contributor

@jack9603301

Copy link
Copy Markdown
Contributor Author

@acinader Of course, let's wait for the initial translation to be merged first.

@simonmichael simonmichael added the i18n Internationalisation/localisation-related. label Sep 30, 2026
@simonmichael

Copy link
Copy Markdown
Member

This is great, thank you very much!

@simonmichael
simonmichael merged commit f493382 into hledgerorg:main Sep 30, 2026
4 checks passed
@jack9603301
jack9603301 deleted the translation-zh_CN branch September 30, 2026 16:41
@jack9603301

Copy link
Copy Markdown
Contributor Author

Thanks

@simonmichael

Copy link
Copy Markdown
Member

Oops, I should have tested first. These aren't working yet:

The Chinese commit added only the catalog file. It didn't register it as a built-in catalog, so hledger doesn't know it exists. The error message lists the built-in catalogs plus any user catalogs in the config directory.

A catalog is built in only when both of these are true. The second step of TRANSLATING.md describes them.

  • It is listed in builtinCatalogSources in I18n.hs, which still lists only German.
  • It is listed under extra-source-files in package.yaml, which also lists only German.

The name matters when you register it. hledger turns zh, zh_CN and zh-CN into the tag zh-Hans before looking up a catalog. If the catalog were registered as zh_CN, it would never match any --lang value. It should be registered as zh-Hans, and the file renamed to zh-Hans.po to follow the convention. The fix would be:

[ ("de", $(embedFileRelativeBytes "locale/de.po"))
, ("zh-Hans", $(embedFileRelativeBytes "locale/zh-Hans.po"))
]
and in package.yaml:

  • locale/zh-Hans.po

The catalog itself loads fine. I tested it as a user catalog, and zh, zh-CN, zh_CN and zh-Hans all select it. The error message then lists it as zh-Hans.

It is out of date, though. It was made from an older template, before this week's hledger-web strings were added. The catalog check tool reports this:

hledger-lib/locale/zh_CN.po: 228 entries, 0 untranslated, 54 missing from catalog, 7 stale

The stale entries are the old balance report links, which have since been replaced. Running just i18n-merge would update it and mark the changed entries for review. The missing strings would show in English until someone translates them.

This slipped through because nothing checks it automatically. Running just i18n-check in CI would have failed on the stale entries. A unit test comparing the files in the locale directory with the registered catalogs would have caught the missing registration.

@jack9603301

Copy link
Copy Markdown
Contributor Author

Oops, I should have tested first. These aren't working yet:

The Chinese commit added only the catalog file. It didn't register it as a built-in catalog, so hledger doesn't know it exists. The error message lists the built-in catalogs plus any user catalogs in the config directory.
A catalog is built in only when both of these are true. The second step of TRANSLATING.md describes them.

  • It is listed in builtinCatalogSources in I18n.hs, which still lists only German.
  • It is listed under extra-source-files in package.yaml, which also lists only German.

The name matters when you register it. hledger turns zh, zh_CN and zh-CN into the tag zh-Hans before looking up a catalog. If the catalog were registered as zh_CN, it would never match any --lang value. It should be registered as zh-Hans, and the file renamed to zh-Hans.po to follow the convention. The fix would be:
[ ("de", $(embedFileRelativeBytes "locale/de.po"))
, ("zh-Hans", $(embedFileRelativeBytes "locale/zh-Hans.po"))
]
and in package.yaml:

  • locale/zh-Hans.po

The catalog itself loads fine. I tested it as a user catalog, and zh, zh-CN, zh_CN and zh-Hans all select it. The error message then lists it as zh-Hans.
It is out of date, though. It was made from an older template, before this week's hledger-web strings were added. The catalog check tool reports this:
hledger-lib/locale/zh_CN.po: 228 entries, 0 untranslated, 54 missing from catalog, 7 stale
The stale entries are the old balance report links, which have since been replaced. Running just i18n-merge would update it and mark the changed entries for review. The missing strings would show in English until someone translates them.
This slipped through because nothing checks it automatically. Running just i18n-check in CI would have failed on the stale entries. A unit test comparing the files in the locale directory with the registered catalogs would have caught the missing registration.

That's strange; I’m pretty sure I tested it.

@jack9603301

Copy link
Copy Markdown
Contributor Author

I tested hledger again, and it reads and executes the translations correctly.

@simonmichael

Copy link
Copy Markdown
Member

On your machine, maybe it correctly detected your locale by another method. I have pushed fixes now which apparently follow conventions and should make --lang work as expected on all machines.

@simonmichael

Copy link
Copy Markdown
Member

To be more precise: all of these now work with --lang, including on non-Chinese-configured machines: zh, zh_CN, zh-CN, zh-Hans, and all case variations of these.

@simonmichael

Copy link
Copy Markdown
Member

And now I've pushed some followup improvements to the tools/process:

  • Registered the catalog (8a43249). It is renamed to hledger-lib/locale/zh-Hans.po, because zh, zh_CN and zh-CN are all normalised to the tag zh-Hans, and a catalog registered under any other name can't be selected. It is now listed in builtinCatalogSources in Hledger/Utils/I18n.hs and in hledger-lib's package.yaml.
  • Updated the catalog. It was made from an older template, and the hledger.pot template on main was also 12 entries behind the sources. Both are updated now: the template is regenerated and merged into zh-Hans.po with msgmerge. All existing translations are kept. Most of the diff is source references losing their line numbers, after a recent extractor change.
  • Added checks (eea5097). just i18n-check now fails when the template is out of date with the sources, and when a catalog in hledger-lib/locale isn't registered (it says what to add). A unit test fails if a built-in catalog is registered under a tag that --lang can't select.
  • Tests and docs. New functional tests in hledger/test/i18n.test cover the Chinese tag spellings and the available-languages list in the error message. The manual and hledger-lib/locale/README.md mention Chinese. doc/TRANSLATING.md (6c56f71) now explains that the file name is the tag --lang selects, how to convert the names translation tools suggest (like zh_CN.po), and to update against the latest template before sending.

The catalog is not yet complete. These strings show in English until they are translated:

State Entries
Translated 221
Fuzzy: suggested by msgmerge, not used until confirmed 19
Untranslated 35

To finish it, open hledger-lib/locale/zh-Hans.po in Poedit, translate the remaining entries, and check the fuzzy ones. Poedit lists both kinds first. just i18n-check shows the current counts. A PR with the completed file would be very welcome.

@simonmichael

Copy link
Copy Markdown
Member

(@acinader: we could check the pot file as part of CI, requiring all PRs which change output strings to update the .pot as well, but I haven't gone that far. Do you think we should ?)

@jack9603301

Copy link
Copy Markdown
Contributor Author

(@acinader: we could check the pot file as part of CI, requiring all PRs which change output strings to update the .pot as well, but I haven't gone that far. Do you think we should ?)

I highly doubt you can do that, because the absence of a translation entry in the .po file does not mean the translation file itself is invalid.

@simonmichael

simonmichael commented Sep 30, 2026 •

Copy link
Copy Markdown
Member

You misunderstood; by checking the pot file, I mean checking that all the translatable texts in the code are present in the pot file, so that translators working on po files will see the correct status. This is a check we can do automatically.

@jack9603301

Copy link
Copy Markdown
Contributor Author

You misunderstood; by checking the pot file, I mean checking that all the translatable texts in the code are present in the pot file, so that translators working on po files will see the correct status. This is a check we can do automatically.

oh Thank you for the clarification.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

i18n Internationalisation/localisation-related.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants