i18n-scan.pl 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use Text::Balanced qw(extract_bracketed extract_delimited extract_tagged);
  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/[\s\n]+/ /g;
  13. $s =~ s/\\n/\n/g;
  14. $s =~ s/\\t/\t/g;
  15. $s =~ s/\\(.)/$1/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, $text ) = extract_bracketed($text, q{('")});
  46. $line += () = $prefix =~ /\n/g;
  47. my $position = "$file:$line";
  48. $line += () = $suffix =~ /\n/g;
  49. $line += () = $code =~ /\n/g;
  50. $code =~ s/\\\n/ /g;
  51. $code =~ s/^\([\n\s]*//;
  52. $code =~ s/[\n\s]*\)$//;
  53. my $res = "";
  54. my $sub = "";
  55. if( $code =~ /^['"]/ )
  56. {
  57. while( defined $sub )
  58. {
  59. ( $sub, $code ) = extract_delimited($code, q{'"}, q{\s*(?:\.\.\s*)?});
  60. if( defined $sub && length($sub) > 2 )
  61. {
  62. $res .= substr $sub, 1, length($sub) - 2;
  63. }
  64. else
  65. {
  66. undef $sub;
  67. }
  68. }
  69. }
  70. elsif( $code =~ /^(\[=*\[)/ )
  71. {
  72. my $stag = quotemeta $1;
  73. my $etag = $stag;
  74. $etag =~ s/\[/]/g;
  75. ( $res ) = extract_tagged($code, $stag, $etag);
  76. $res =~ s/^$stag//;
  77. $res =~ s/$etag$//;
  78. }
  79. $res = dec_lua_str($res);
  80. if ($res) {
  81. $stringtable{$res} ||= [ ];
  82. push @{$stringtable{$res}}, $position;
  83. }
  84. }
  85. $text = $raw;
  86. $line = 1;
  87. while( $text =~ s/ ^ (.*?) <% -? [:_] /<%/sgx )
  88. {
  89. $line += () = $1 =~ /\n/g;
  90. ( my $code, $text ) = extract_tagged($text, '<%', '%>');
  91. if( defined $code )
  92. {
  93. my $position = "$file:$line";
  94. $line += () = $code =~ /\n/g;
  95. $code = dec_tpl_str(substr $code, 2, length($code) - 4);
  96. $stringtable{$code} ||= [];
  97. push @{$stringtable{$code}}, $position;
  98. }
  99. }
  100. }
  101. }
  102. close F;
  103. }
  104. if( open C, "| msgcat -" )
  105. {
  106. printf C "msgid \"\"\nmsgstr \"Content-Type: text/plain; charset=UTF-8\"\n\n";
  107. foreach my $key ( sort keys %stringtable )
  108. {
  109. if( length $key )
  110. {
  111. my @positions = @{$stringtable{$key}};
  112. $key =~ s/\\/\\\\/g;
  113. $key =~ s/\n/\\n/g;
  114. $key =~ s/\t/\\t/g;
  115. $key =~ s/"/\\"/g;
  116. printf C "#: %s\nmsgid \"%s\"\nmsgstr \"\"\n\n",
  117. join(' ', @positions), $key;
  118. }
  119. }
  120. close C;
  121. }