{"id":19777489,"url":"https://github.com/ilib-js/ilib-loctool-po","last_synced_at":"2025-09-17T23:31:44.548Z","repository":{"id":42697684,"uuid":"172765609","full_name":"iLib-js/ilib-loctool-po","owner":"iLib-js","description":"Ilib loctool plugin to parse and localize GNU gettext po files","archived":false,"fork":false,"pushed_at":"2024-11-08T16:43:56.000Z","size":119,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-11-12T05:30:45.121Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/iLib-js.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-02-26T18:21:25.000Z","updated_at":"2021-11-15T02:22:08.000Z","dependencies_parsed_at":"2023-09-25T19:21:57.013Z","dependency_job_id":null,"html_url":"https://github.com/iLib-js/ilib-loctool-po","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iLib-js%2Filib-loctool-po","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iLib-js%2Filib-loctool-po/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iLib-js%2Filib-loctool-po/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iLib-js%2Filib-loctool-po/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/iLib-js","download_url":"https://codeload.github.com/iLib-js/ilib-loctool-po/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":233430256,"owners_count":18675058,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-12T05:25:16.336Z","updated_at":"2025-09-17T23:31:37.650Z","avatar_url":"https://github.com/iLib-js.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n\u003e :warning: **Deprecation Notice** :warning:\n\u003e This repository has been deprecated. Please use the corresponding package from the [iLib-js monorepo](https://github.com/iLib-js/ilib-mono) instead.\n\n# ilib-loctool-po\n\nAn ilib loctool plugin to parse and localize GNU gettext po files.\n\nThis plugin can parse and localize po or pot files written by\ntools such as easygettext.\n\n## Regular PO and POT Files\n\nEntries in a PO file have the following format:\n\n```\nwhite-space\n#  translator-comments\n#. extracted-comments\n#: reference…\n#, flag…\n#| msgctxt previous-context\n#| msgid previous-untranslated-string\nmsgctxt context\nmsgid untranslated-string\nmsgstr translated-string\n```\n\nThe format is specified on the [gnu website](https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html).\n\nThis plugin can read any file with this format. Individual entries\nare registered at string resources and will appear in the extracted\nxliff and the new strings files.\n\nIf an entry has a context line, it will get a context in the xliff\noutput and will be differentiated from other strings that have the\nsame source but a different (or missing). That is, two entries that\ndiffer only by their context will appear as two separate strings in\nthe xliff output.\n\nIn POT files, there are often no translations, as it is the \"template\"\nthat is used to generate all the translated po files. This plugin can\nsupport any string with or without translations.\n\n### Plurals\n\nThis plugin can also support plural strings. Plurals have the following\nformat:\n\n```\nmsgid untranslated-string-singular\nmsgid_plural untranslated-string-plural\nmsgstr[0] translated-string-case-0\n...\nmsgstr[N] translated-string-case-n\n```\n\nThe string in `msgid` will be considered to be the string for the\n`one` category used as the singular in English source.\nThe `msgstr_plural`\nwill be considered the `other` category, which is used as the plural\nstring in English. See the\n[Unicode plural categories](http://cldr.unicode.org/index/cldr-spec/plural-rules)\ndocument for details on what the categories mean.\n\nThe lines `msgstr[0]` through `msgstr[N]` are the translations of\nthese categories. The numbers are mapped to Unicode categories according\nto the mappings included below in Appendix A. The mappings are different\nfor each language. That is, in one language, `0` might map to the `one`\ncategory, whereas in another, it might be the `zero` category. The\nstrings in the xliff output will include the category only, and the\ncategories will be mapped back to numbers in the translated po file output.\n\nNote that for some languages, the number of categories is different\nthan in English. For example, English uses 2 categories (`one` and\n`other`) but Russian uses 3 (`one`, `few`, and `other`). The\nxliff output will contain the right number of category strings for\nthe target language. Your translators should note the category given\nin the `extype` attribute when translating each string. They will\nnot have to add or subtract any\nxliff trans-unit entries. They only need to translate the contents\nof the target tag in the given trans-units.\n\n#### Example\n\nInput po or pot file:\n\n```\nmsgid \"There is {n} object.\"\nmsgstr_plural \"There are {n} objects.\"\n```\n\nOutput xliff snippet:\n\n```xml\n      \u003ctrans-unit id=\"4\" resname=\"There is {n} object.\" restype=\"plural\" datatype=\"po\" extype=\"one\"\u003e\n        \u003csource\u003eThere is {n} object.\u003c/source\u003e\n        \u003ctarget state=\"new\"\u003eThere is {n} object.\u003c/target\u003e\n      \u003c/trans-unit\u003e\n      \u003ctrans-unit id=\"5\" resname=\"There is {n} object.\" restype=\"plural\" datatype=\"po\" extype=\"few\"\u003e\n        \u003csource\u003eThere are {n} objects.\u003c/source\u003e\n        \u003ctarget state=\"new\"\u003eThere are {n} objects.\u003c/target\u003e\n      \u003c/trans-unit\u003e\n      \u003ctrans-unit id=\"6\" resname=\"There is {n} object.\" restype=\"plural\" datatype=\"po\" extype=\"other\"\u003e\n        \u003csource\u003eThere are {n} objects.\u003c/source\u003e\n        \u003ctarget state=\"new\"\u003eThere are {n} objects.\u003c/target\u003e\n      \u003c/trans-unit\u003e\n```\n\nNote that the `msgid` string (the English singular) is used as the\nresource name (`resname`) for each of the xliff entries so that\nthey can be connected again later when the xliff file is read in.\nAlso, the\nsource string for every category other than `one` is the source\nstring given on the `msgstr_plural` line.\n\n## Configuring the Plugin\n\nThe plugin will look for the `po` property within the `settings`\nof your `project.json` file. The following setting is\nused within the po property:\n\n- mappings: a mapping between file matchers and an object that gives\n  info used to localize the files that match it. This allows different\n  po files within the project to be processed into different output\n  files. The matchers are\n  a [micromatch-style string](https://www.npmjs.com/package/micromatch),\n  similar to the the `includes` and `excludes` section of a\n  `project.json` file. The value of that mapping is an object that\n  can contain the following properties:\n    - template: a path template to use to generate the path to\n      the translated\n      output files. The template replaces strings in square brackets\n      with special values, and keeps any characters intact that are\n      not in square brackets. The default template, if not specified is\n      \"[dir]/[locale].po\". The plugin recognizes\n      and replaces the following strings in template strings:\n        - [dir] the original directory where the matched source file\n          came from. This is given as a directory that is relative\n          to the root of the project. eg. \"foo/bar/strings.po\" -\u003e \"foo/bar\"\n        - [filename] the file name of the matching file.\n          eg. \"foo/bar/strings.po\" -\u003e \"strings.po\"\n        - [basename] the basename of the matching file without any extension\n          eg. \"foo/bar/strings.po\" -\u003e \"strings\"\n        - [extension] the extension part of the file name of the source file.\n          etc. \"foo/bar/strings.po\" -\u003e \"po\"\n        - [locale] the full BCP-47 locale specification for the target locale\n          eg. \"zh-Hans-CN\" -\u003e \"zh-Hans-CN\"\n        - [language] the language portion of the full locale\n          eg. \"zh-Hans-CN\" -\u003e \"zh\"\n        - [script] the script portion of the full locale\n          eg. \"zh-Hans-CN\" -\u003e \"Hans\"\n        - [region] the region portion of the full locale\n          eg. \"zh-Hans-CN\" -\u003e \"CN\"\n        - [localeDir] the full locale where each portion of the locale\n          is a directory in this order: [langage], [script], [region].\n          eg, \"zh-Hans-CN\" -\u003e \"zh/Hans/CN\", but \"en\" -\u003e \"en\".\n        - [localeUnder] the full BCP-47 locale specification, but using\n          underscores to separate the locale parts instead of dashes.\n          eg. \"zh-Hans-CN\" -\u003e \"zh_Hans_CN\"\n    - localeMap: an output locale map that maps the locale used in the\n      translations to a different locale for use in the file name template.\n      For example, an app may wish to use the locale specifier \"zh-CN\"\n      instead of the full \"zh-Hans-CN\" for some output files, but not\n      all of them. In this case, a locale map for this template mapping\n      is how this can be achieved. Any locale not listed in the mapping\n      will be used as-is. The overall [shared] locale map is also applied\n      if there is no locale map in the template mapping for a particular\n      locale.\n    - ignoreComments: specify whether to ignore types of comments. Possible values are:\n        - *true* All comment types should be ignored\n        - *false* No comment types should be ignored (default)\n        - Array of strings. Name the types of comments that should be\n          ignored. Possible values are:\n            - \"translator\" - ignore translator comments (prefix is \"# \")\n            - \"extracted\" - ignore comments extracted from the source code (prefix is \"#.\")\n            - \"flags\" - ignore special processing flags (prefix is \"#,\")\n            - \"previous\" - ignore previous translation (prefix is \"#|\")\n            - \"paths\" - ignore file names and line numbers (prefix is \"#:\")\n    - headerLocale: specify what kind of locale to put in the file header. Possible values\n        are:\n        - *full*: put the fully specified locale spec in the header\n        - *abbreviated*: put an abbreviated locale spec in the header (language only)\n        - *mapped*: put the results of the output locale mapping (see above) into the header\n    - contextInKey: some translation management systems cannot support separate context\n      fields, and therefore two translation units that only differ in their context cannot\n      be distinguished from each other. If this setting is set to \"true\", then the context\n      is added to the key for a unit. eg. if the string is \"Sent\" and the context is \"Email\",\n      a translation unit will be produced with the key \"Sent --- Email\" and the source string\n      is \"Sent\".\n\nExample configuration:\n\n```json\n{\n    \"settings\": {\n        \"po\": {\n            \"mappings\": {\n                \"**/template.pot\": {\n                    \"template\": \"resources/[locale].po\",\n                    \"ignoreComments\": [\"paths\"]\n                },\n                \"sublibrary/**/library.pot\": {\n                    \"template\": \"[dir]/[locale].po\",\n                    \"localeMap\": {\n                        \"nb-NO\": \"no\",\n                        \"sr-Cyrl-RS\": \"sr-RS\",\n                        \"zh-Hans-CN\": \"zh-CN\"\n                    },\n                    \"ignoreComments\": true\n                }\n            }\n        }\n    }\n}\n```\n\nIn the above example, any file named `template.pot` will be localized and\nthe output is sent to a file named after the target locale located in the\n`resources` directory. In these files, the translator and extracted\ntype of comments are ignored and will not be extracted into the resources\nand therefore will not appear in the xliff files.\n\nIn the second part of the example, any `library.pot` file that appears in\nthe `sublibrary` directory will be localized and the results sent to a\npo file named after each target locale which will appear in the same\ndirectory where the source file was located. If the locale is one of the\nones listed in the locale map, it will be mapped before being substituted\nin to the template. For these files, all comment types are ignored and none\nare sent to the translators in the xliff files.\n\nIf the name of the localized file that the template produces is the same as\nthe source file name, this plugin will throw an exception, the file will not\nbe localized, and the loctool will continue on to the next file.\n\n\n## License\n\nCopyright © 2019, 2022-2023 JEDLSoft\n\nThis plugin is license under Apache2. See the [LICENSE](./LICENSE)\nfile for more details.\n\n## Release Notes\n\n### v1.6.3\n\n- update dependencies\n- convert all unit tests from nodeunit to jest\n\n### v1.6.2\n\n- update dependencies\n- remove dependency on log4js. Get the logger from loctool instead.\n\n### v1.6.1\n\n- make sure the msgctxt line comes out before the msgid line. Some libraries\n  cannot handle it the other way around.\n\n### v1.6.0\n\n- added the contextInKey setting so that we can support translation\n  management systems that do not support contexts. Instead, we add the context\n  to the key for each translation unit, so that two translations units\n  that differ only in their context can still be dinstinguished from each\n  other.\n\n### v1.5.1\n\n- fixed a bug in the getOutputLocale function when you are missing a\n  locale in the localeMap that is mentioned in the list of locales\n\n### v1.5.0\n\n- Added headerLocale setting to the mappings. This allows you to specify\n  the style of the locale spec listed in the header of the po file as it\n  is written out to disk.\n\n### v1.4.1\n\n- Fixed the po header output so that it shows the locale spec of the mapped\n  output locale, not of the source locale.\n\n### v1.4.0\n\n- added the ability to ignore comments. This solves the problem where file names\n  and line numbers for each resource change when someone makes an unrelated\n  change to a source file, but the resource itself nor the code around it has\n  changed. This causes some translation management systems to treat the string\n  as changed and therefore requiring useless retranslation.\n    - Added the \"ignoreComments\" config option (see above for details)\n\n### v1.3.1\n\n- Fixed a bug where the plugin would not work when generating pseudo localizations\n  for plurals\n\n### v1.3.0\n\n- Added the ability to specify a locale map in the file name template\n  mapping. This allows for different locale specifications for different\n  sets of output files, which may be necessary if those output files\n  are intended to be used in different programming languages or on\n  different platforms that support a different set of locales.\n\n### v1.2.2\n\n- Fix a bug where the target locale was not used when specified to\n  POFileType.newFile. It was never passed in to the POFile constructor.\n- Fix a bug where the target locale was specified for string and\n  plural resources and there were no target strings or plurals. Having\n  the locale but no target confuses mojito.\n\n### v1.2.1\n\n- Make sure to output an empty string if the translated string is the\n  same as the source string so that `gettext()` will default back to\n  the source string\n\n### v1.2.0\n\n- added the ability to specify a locale map so that output file names of\n  po files are mapped from the internal locale to the output locale\n\n### v1.1.2\n\n- fixed a bug where path names in #: comments that did not have a\n  colon and a line number were not being extracted properly\n\n### v1.1.1\n\n- fixed a bug where every resource from the PO file had its own file tag\n  in the xliff output because the \"original\" path was set to the file\n  name colon line number.\n\n### v1.1.0\n\n- Added the ability to use po files as output resource files by adding a write\n  method. This means it can also be used as an output format for the new\n  convert action.\n    - if resources are added where the target locale\n      does not match the locale of the PO file, then those resources\n      will be added as source-only resources\n    - handles resources with missing translations and puts a placeholder\n      entry into the PO file\n    - handles missing plural strings as well, depending on the language\n\n### v1.0.1\n\n- Make this plugin able to read already-localized po files\n  The output file name template is used to construct a regular expression to \n  recognize already localized files and what the locale of that file is. \n  Without the template, the locale was never extracted and the source and \n  target were both en-US which is not correct. This was a bigger problem\n  for those languages where the plural resources have more plural categories\n  than in English, such as Russian or Polish.\n\n### v1.0.0\n\n- initial version\n- read regular po and pot files and output translated po files\n\n## Appendix A. Mappings From GNU gettext Plural Number and Unicode Category\n\nThese mappings are encoded in the file pluralforms.json which is packaged\nwith this plugin. The languages are listed below by their ISO 639 2 letter codes.\nThis plugin assumes that any language not explicitly listed below has only the\n`one` and `other` categories.\n\n### ar\n\n| number | category |\n| ---- | ---- |\n| 0 | zero |\n| 1 | one |\n| 2 | two |\n| 3 | few |\n| 4 | many |\n| 5 | other |\n\n### be\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | few |\n| 2 | other |\n\n### bg\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | other |\n\n### cs\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | few |\n| 2 | other |\n\n### da\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | other |\n\n### de\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | other |\n\n### el\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | other |\n\n### en\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | other |\n\n### eo\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | other |\n\n### es\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | other |\n\n### et\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | other |\n\n### fi\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | other |\n\n### fo\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | other |\n\n### fr\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | other |\n\n### ga\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | few |\n| 2 | other |\n\n### he\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | other |\n\n### hr\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | few |\n| 2 | other |\n\n### hu\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | other |\n\n### id\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | other |\n\n### it\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | other |\n\n### ja\n\n| number | category |\n| ---- | ---- |\n| 0 | other |\n\n### ko\n\n| number | category |\n| ---- | ---- |\n| 0 | other |\n\n### lt\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | few |\n| 2 | other |\n\n### lv\n\n| number | category |\n| ---- | ---- |\n| 0 | zero |\n| 1 | one |\n| 2 | other |\n\n### nl\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | other |\n\n### no\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | other |\n\n### pl\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | few |\n| 2 | other |\n\n### pt\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | other |\n\n### ro\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | few |\n| 2 | other |\n\n### ru\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | few |\n| 2 | other |\n\n### sk\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | few |\n| 2 | other |\n\n### sl\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | two |\n| 2 | few |\n| 3 | other |\n\n### sr\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | few |\n| 2 | other |\n\n### sv\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | other |\n\n### th\n\n| number | category |\n| ---- | ---- |\n| 0 | other |\n\n### tr\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | other |\n\n### uk\n\n| number | category |\n| ---- | ---- |\n| 0 | one |\n| 1 | few |\n| 2 | other |\n\n### zh\n\n| number | category |\n| ---- | ---- |\n| 0 | other |\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Filib-js%2Filib-loctool-po","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Filib-js%2Filib-loctool-po","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Filib-js%2Filib-loctool-po/lists"}