]> git.proxmox.com Git - proxmox-i18n.git/blob - po2js.pl
d/control: define compat level via build-depends and raise to 13
[proxmox-i18n.git] / po2js.pl
1 #!/usr/bin/perl
2
3 use strict;
4 use warnings;
5
6 use Encode;
7 use Getopt::Long;
8 use JSON;
9 use Locale::PO;
10
11 # current limits:
12 # - we do not support plural. forms
13 # - no message content support
14
15 my $options = {};
16 GetOptions($options, 't=s', 'o=s', 'v=s') or die "unable to parse options\n";
17
18 die "no files specified\n" if !scalar(@ARGV);
19
20 # like FNV32a, but we only return 31 bits (positive numbers)
21 sub fnv31a {
22 my ($string) = @_;
23
24 my $hval = 0x811c9dc5;
25 for my $c (unpack('C*', $string)) {
26 $hval ^= $c;
27 $hval += ($hval << 1) + ($hval << 4) + ($hval << 7) + ($hval << 8) + ($hval << 24);
28 $hval = $hval & 0xffffffff;
29 }
30 return $hval & 0x7fffffff;
31 }
32
33 my $catalog = {};
34
35 foreach my $filename (@ARGV) {
36 my $href = Locale::PO->load_file_ashash($filename) ||
37 die "unable to load '$filename'\n";
38
39 my $charset;
40 my $hpo = $href->{'""'} || die "no header";
41 my $header = $hpo->dequote($hpo->msgstr);
42 if ($header =~ m|^Content-Type:\s+text/plain;\s+charset=(\S+)$|im) {
43 $charset = $1;
44 } else {
45 die "unable to get charset\n" if !$charset;
46 }
47
48 for my $k (keys %$href) {
49 my $po = $href->{$k};
50 next if $po->fuzzy(); # skip fuzzy entries
51 my $ref = $po->reference() or next; # skip unused entries
52
53 # skip entries if "t" is defined (pve/pmg) and the string is
54 # not used there or in the widget toolkit
55 next if $options->{t} && $ref !~ m/($options->{t}|proxmox)\-/;
56
57 my $qmsgid = decode($charset, $po->msgid);
58 my $msgid = $po->dequote($qmsgid);
59
60 my $qmsgstr = decode($charset, $po->msgstr);
61 my $msgstr = $po->dequote($qmsgstr);
62
63 next if !length($msgid); # skip header
64 next if !length($msgstr); # skip untranslated entries
65
66 my $digest = fnv31a($msgid);
67
68 die "duplicate digest '$digest' (msgid '$msgid')\n" if $catalog->{$digest};
69
70 $catalog->{$digest} = [ $msgstr ];
71 # later, we can add plural forms to the array
72 }
73 }
74
75 my $json = to_json($catalog, {canonical => 1, utf8 => 1});
76
77 my $version = $options->{v} // ("dev-build " . localtime());
78 my $content = "// $version\n"; # write version to the beginning to better avoid stale cache
79
80 my $outfile = $options->{o};
81
82 $content .= "// Proxmox Message Catalog: $outfile\n" if $outfile;
83
84 $content .= <<__EOD;
85 const __proxmox_i18n_msgcat__ = $json;
86
87 function fnv31a(text) {
88 let hval = 0x811c9dc5;
89 for (const c of text) {
90 hval ^= c;
91 hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
92 }
93 hval &= 0x7fffffff;
94 return hval;
95 }
96
97 function gettext(buf) {
98 let digest = fnv31a(buf);
99 return __proxmox_i18n_msgcat__[digest]?.[0] ?? buf;
100 }
101 __EOD
102
103 if ($outfile) {
104 open(my $fh, '>', $outfile) ||
105 die "unable to open '$outfile' - $!\n";
106 print $fh $content;
107 } else {
108 print $content;
109 }