i18n-scan.pl 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use Text::Balanced qw(extract_tagged gen_delimited_pat);
  5. use POSIX;
  6. POSIX::setlocale(POSIX::LC_ALL, "C");
  7. @ARGV >= 1 || die "Usage: $0 <source directory>\n";
  8. my %stringtable;
  9. sub dec_lua_str
  10. {
  11. my $s = shift;
  12. $s =~ s/\\n/\n/g;
  13. $s =~ s/\\t/\t/g;
  14. $s =~ s/\\(.)/$1/sg;
  15. $s =~ s/[\s\n]+/ /g;
  16. $s =~ s/^ //;
  17. $s =~ s/ $//;
  18. return $s;
  19. }
  20. sub dec_tpl_str
  21. {
  22. my $s = shift;
  23. $s =~ s/-$//;
  24. $s =~ s/[\s\n]+/ /g;
  25. $s =~ s/^ //;
  26. $s =~ s/ $//;
  27. $s =~ s/\\/\\\\/g;
  28. return $s;
  29. }
  30. if( open F, "find @ARGV -type f '(' -name '*.htm' -o -name '*.lua' -o -name '*.js' ')' | sort |" )
  31. {
  32. while( defined( my $file = readline F ) )
  33. {
  34. chomp $file;
  35. if( open S, "< $file" )
  36. {
  37. local $/ = undef;
  38. my $raw = <S>;
  39. close S;
  40. my $text = $raw;
  41. my $line = 1;
  42. while ($text =~ s/ ^ (.*?) (?:translate|translatef|i18n|_) ([\n\s]*) \( //sgx)
  43. {
  44. my ($prefix, $suffix) = ($1, $2);
  45. my $code;
  46. my $res = "";
  47. my $sub = "";
  48. $line += () = $prefix =~ /\n/g;
  49. my $position = "$file:$line";
  50. $line += () = $suffix =~ /\n/g;
  51. while (defined $sub)
  52. {
  53. undef $sub;
  54. if ($text =~ /^ ([\n\s]*(?:\.\.[\n\s]*)?) (\[=*\[) /sx)
  55. {
  56. my $ws = $1;
  57. my $stag = quotemeta $2;
  58. (my $etag = $stag) =~ y/[/]/;
  59. ($sub, $text) = extract_tagged($text, $stag, $etag, q{\s*(?:\.\.\s*)?});
  60. $line += () = $ws =~ /\n/g;
  61. if (defined($sub) && length($sub)) {
  62. $line += () = $sub =~ /\n/g;
  63. $sub =~ s/^$stag//;
  64. $sub =~ s/$etag$//;
  65. $res .= $sub;
  66. }
  67. }
  68. elsif ($text =~ /^ ([\n\s]*(?:\.\.[\n\s]*)?) (['"]) /sx)
  69. {
  70. my $ws = $1;
  71. my $quote = $2;
  72. my $re = gen_delimited_pat($quote, '\\');
  73. if ($text =~ m/\G\s*(?:\.\.\s*)?($re)/gcs)
  74. {
  75. $sub = $1;
  76. $text = substr $text, pos $text;
  77. }
  78. $line += () = $ws =~ /\n/g;
  79. if (defined($sub) && length($sub)) {
  80. $line += () = $sub =~ /\n/g;
  81. $sub =~ s/^$quote//;
  82. $sub =~ s/$quote$//;
  83. $res .= $sub;
  84. }
  85. }
  86. }
  87. if (defined($res))
  88. {
  89. $res = dec_lua_str($res);
  90. if ($res) {
  91. $stringtable{$res} ||= [ ];
  92. push @{$stringtable{$res}}, $position;
  93. }
  94. }
  95. }
  96. $text = $raw;
  97. $line = 1;
  98. while( $text =~ s/ ^ (.*?) <% -? [:_] /<%/sgx )
  99. {
  100. $line += () = $1 =~ /\n/g;
  101. ( my $code, $text ) = extract_tagged($text, '<%', '%>');
  102. if( defined $code )
  103. {
  104. my $position = "$file:$line";
  105. $line += () = $code =~ /\n/g;
  106. $code = dec_tpl_str(substr $code, 2, length($code) - 4);
  107. $stringtable{$code} ||= [];
  108. push @{$stringtable{$code}}, $position;
  109. }
  110. }
  111. }
  112. }
  113. close F;
  114. }
  115. if( open C, "| msgcat -" )
  116. {
  117. printf C "msgid \"\"\nmsgstr \"Content-Type: text/plain; charset=UTF-8\"\n\n";
  118. foreach my $key ( sort keys %stringtable )
  119. {
  120. if( length $key )
  121. {
  122. my @positions = @{$stringtable{$key}};
  123. $key =~ s/\\/\\\\/g;
  124. $key =~ s/\n/\\n/g;
  125. $key =~ s/\t/\\t/g;
  126. $key =~ s/"/\\"/g;
  127. printf C "#: %s\nmsgid \"%s\"\nmsgstr \"\"\n\n",
  128. join(' ', @positions), $key;
  129. }
  130. }
  131. close C;
  132. }