poexam 0.0.5

Blazingly fast PO linter.
poexam-0.0.5 is not a library.

Poexam

Crates.io Build status REUSE status

Poexam is a blazingly fast PO file linter with a comprehensive diagnostic report.

It reports very few false positives and can be used in CI jobs and pre-commit hooks.

[!NOTE] Poexam is in active development and may not be fully stable yet.
The command-line interface and features may change at any time.
As it doesn't write anything on disk, there should be no risk of data loss, and bug reports are welcome.

Overview

  • ⚑️ Blazingly fast: large directories and files are checked in parallel, in a few milliseconds.
  • πŸ”Ž Rules: a lot of checks performed with very few false positives.
  • 🎯 Clear results: tricky errors in strings are highlighted with colors.
  • πŸ“Š Statistics: detailed statistics including progress, count of messages/words/characters.
  • πŸ’» Multi-platform: available wherever the Rust compiler is available.
  • 🎁 Free software: released under GPLv3.

Installation

With cargo:

cargo install poexam

Features

Poexam can check entire directories and a lot of PO files in just a few milliseconds.

It can perform a lot of checks via the default rules:

Rule name Severity Diagnostic reported
blank warning Blank translation (only whitespace).
brackets info Missing/extra brackets.
c-formats error Inconsistent C format strings.
double-quotes info Missing/extra double quotes.
double-spaces info Missing or extra double spaces.
encoding info Incorrect encoding (charset).
escapes error Missing/extra escape characters.
newlines error Missing/extra newlines.
pipes info Missing/extra pipes.
plurals error Incorrect number of plurals.
punc-end info Inconsistent trailing punctuation.
punc-start info Inconsistent leading punctuation.
tabs error Missing/extra tabs.
whitespace-end info Missing/extra whitespace at the end.
whitespace-start info Missing/extra whitespace at the start.

Some extra rules are not used by default because they are not really "checks", report too many false positives or can slow down the process.

You can enable them on-demand:

Rule name Severity Diagnostic reported
fuzzy info Fuzzy entry.
obsolete info Obsolete entry.
spelling-ctxt info Spelling error in the context string.
spelling-id info Spelling error in the source string.
spelling-str info Spelling error in the translated string.
unchanged info Translation is the same as the source string.
untranslated info Untranslated entry.

The result is very clear, almost all errors are highlighted in the strings so you can immediately see where the issue is.

You can check by yourself with the following command executed in the root directory of the project (output is truncated here):

$ poexam check --select all examples/fr.po
examples/fr.po:25: [warning:blank] blank translation
        |
     25 | Test: blank translation
        |
     26 |
        |

examples/fr.po:29: [info:brackets] missing opening and closing square brackets '[' (1 / 0) and ']' (1 / 0)
        |
     29 | Test [brackets]
        |
     30 | Test crochets
        |

examples/fr.po:34: [error:c-formats] inconsistent C format strings
        |
     34 | Name: %s, age: %d
        |
     35 | Γ‚ge : %2$d, nom : %1$f
        |

examples/fr.po:38: [info:double-quotes] missing double quotes (2 / 0)
        |
     38 | Test "double quotes"
        |
     39 | Test guillemets doubles
        |

(...)

1 files checked: 24 problems in 1 files (5 errors, 1 warnings, 18 info) [23.890354ms]

Poexam can also give statistics about the translation progress and number of lines/words/charecters, see: poexam help stats.

Example:

$ poexam stats --sort status
po/de.po    [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 3853 = 3853 (100%) + 0 (0%) + 0 (0%) + 0 (0%)
po/fr.po    [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 3853 = 3853 (100%) + 0 (0%) + 0 (0%) + 0 (0%)
po/pl.po    [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 3853 = 3853 (100%) + 0 (0%) + 0 (0%) + 0 (0%)
po/sr.po    [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ] 3853 = 3853 (100%) + 0 (0%) + 0 (0%) + 0 (0%)
po/tr.po    [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–’β–’     ] 3853 = 2519 (65%) + 480 (12%) + 854 (22%) + 0 (0%)
po/ja.po    [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–’β–’       ] 3853 = 1846 (47%) + 836 (21%) + 1171 (30%) + 0 (0%)
po/pt.po    [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–’β–’β–’       ] 3853 = 1586 (41%) + 1002 (26%) + 1265 (32%) + 0 (0%)
po/es.po    [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–’β–’β–’         ] 3853 = 1259 (32%) + 1113 (28%) + 1481 (38%) + 0 (0%)
po/it.po    [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–’β–’β–’β–’        ] 3853 = 1226 (31%) + 1183 (30%) + 1444 (37%) + 0 (0%)
po/cs.po    [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–’β–’β–’β–’        ] 3853 = 1178 (30%) + 1240 (32%) + 1435 (37%) + 0 (0%)
po/pt_BR.po [β–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–’β–’β–’β–’          ] 3853 = 853 (22%) + 1163 (30%) + 1837 (47%) + 0 (0%)
po/ru.po    [β–’β–’β–’β–’β–’β–’β–’β–’β–’           ] 3853 = 96 (2%) + 1782 (46%) + 1975 (51%) + 0 (0%)
po/hu.po    [β–’β–’β–’β–’β–’β–’β–’β–’β–’           ] 3853 = 76 (1%) + 1766 (45%) + 2011 (52%) + 0 (0%)
Total (13)  [β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–’β–’β–’β–’      ] 50089 = 26051 (52%) + 10565 (21%) + 13473 (26%) + 0 (0%)

Detailed statistics on words and characters:

$ poexam stats --words fr.po ja.po
fr.po:
                    Entries          Words (src / translated)     Chars (src / translated)
Translated           3853 (100%)      40634 (100%)      48504     184916 (100%)     226692
Fuzzy                   0 (  0%)          0 (  0%)          0          0 (  0%)          0
Untranslated            0 (  0%)          0 (  0%)          0          0 (  0%)          0
Obsolete                0 (  0%)          0 (  0%)          0          0 (  0%)          0
Total                3853             40634             48504     184916            226692

ja.po:
                    Entries          Words (src / translated)     Chars (src / translated)
Translated           1846 ( 47%)      16879 ( 41%)       7671      74349 ( 40%)      50055
Fuzzy                 836 ( 21%)       9763 ( 24%)       4787      45188 ( 24%)      29197
Untranslated         1171 ( 30%)      13992 ( 34%)          0      65379 ( 35%)          0
Obsolete                0 (  0%)          0 (  0%)          0          0 (  0%)          0
Total                3853             40634              7671     184916             50055

Total (2):
                    Entries          Words (src / translated)     Chars (src / translated)
Translated           5699 ( 73%)      57513 ( 70%)      56175     259265 ( 70%)     276747
Fuzzy                 836 ( 10%)       9763 ( 12%)       4787      45188 ( 12%)      29197
Untranslated         1171 ( 15%)      13992 ( 17%)          0      65379 ( 17%)          0
Obsolete                0 (  0%)          0 (  0%)          0          0 (  0%)          0
Total                7706             81268             56175     369832            276747

Roadmap

  • Add new rules.
  • Add support for custom rules and checks.
  • Add a server mode to integrate with IDEs and text editors.

Copyright

Copyright Β© 2026 SΓ©bastien Helleu

This file is part of Poexam, the blazingly fast PO file linter.

Poexam is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.

Poexam is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with Poexam. If not, see https://gnu.org/licenses/.