summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/VNDB/DB/ULists.pm8
-rw-r--r--lib/VNDB/DB/Users.pm4
-rw-r--r--lib/VNDB/Func.pm75
-rw-r--r--lib/VNDB/Handler/Discussions.pm102
-rw-r--r--lib/VNDB/Handler/Misc.pm261
-rw-r--r--lib/VNDB/Handler/Producers.pm69
-rw-r--r--lib/VNDB/Handler/Releases.pm300
-rw-r--r--lib/VNDB/Handler/Tags.pm281
-rw-r--r--lib/VNDB/Handler/ULists.pm69
-rw-r--r--lib/VNDB/Handler/Users.pm225
-rw-r--r--lib/VNDB/Handler/VNBrowse.pm67
-rw-r--r--lib/VNDB/Handler/VNEdit.pm92
-rw-r--r--lib/VNDB/Handler/VNPage.pm164
-rw-r--r--lib/VNDB/L10N.pm189
-rw-r--r--lib/VNDB/Util/Auth.pm2
-rw-r--r--lib/VNDB/Util/CommonHTML.pm164
-rw-r--r--lib/VNDB/Util/FormHTML.pm132
-rw-r--r--lib/VNDB/Util/LayoutHTML.pm84
18 files changed, 1162 insertions, 1126 deletions
diff --git a/lib/VNDB/DB/ULists.pm b/lib/VNDB/DB/ULists.pm
index 34bdc2aa..e9b38e57 100644
--- a/lib/VNDB/DB/ULists.pm
+++ b/lib/VNDB/DB/ULists.pm
@@ -155,6 +155,7 @@ sub dbVoteGet {
$o{uid} ? ( 'n.uid = ?' => $o{uid} ) : (),
$o{vid} ? ( 'n.vid = ?' => $o{vid} ) : (),
$o{hide} ? ( 'u.show_list = TRUE' => 1 ) : (),
+ $o{hide_ign} ? ( '(NOT u.ign_votes OR u.id = ?)' => $self->authInfo->{id}||0 ) : (),
);
my @select = (
@@ -186,16 +187,19 @@ sub dbVoteGet {
}
-# Arguments: (uid|vid), id
+# Arguments: (uid|vid), id, use_ignore_list
# Returns an arrayref with 10 elements containing the number of votes for index+1
sub dbVoteStats {
- my($self, $col, $id) = @_;
+ my($self, $col, $id, $ign) = @_;
+ my $u = $self->authInfo->{id};
my $r = [ qw| 0 0 0 0 0 0 0 0 0 0 | ];
$r->[$_->{vote}-1] = $_->{votes} for (@{$self->dbAll(q|
SELECT vote, COUNT(vote) as votes
FROM votes
+ !s
!W
GROUP BY vote|,
+ $ign ? 'JOIN users ON id = uid AND (NOT ign_votes'.($u?sprintf(' OR id = %d',$u):'').')' : '',
$col ? { '!s = ?' => [ $col, $id ] } : {},
)});
return $r;
diff --git a/lib/VNDB/DB/Users.pm b/lib/VNDB/DB/Users.pm
index e1f4c378..b2cd1a31 100644
--- a/lib/VNDB/DB/Users.pm
+++ b/lib/VNDB/DB/Users.pm
@@ -43,7 +43,7 @@ sub dbUserGet {
);
my @select = (
- qw|id username mail rank salt c_votes c_changes show_nsfw show_list skin customcss ip c_tags|,
+ qw|id username mail rank salt c_votes c_changes show_nsfw show_list skin customcss ip c_tags ign_votes|,
q|encode(passwd, 'hex') AS passwd|, q|extract('epoch' from registered) as registered|,
$o{what} =~ /stats/ ? (
'(SELECT COUNT(*) FROM rlists WHERE uid = u.id) AS releasecount',
@@ -74,7 +74,7 @@ sub dbUserEdit {
my %h;
defined $o{$_} && ($h{$_.' = ?'} = $o{$_})
- for (qw| username mail rank show_nsfw show_list skin customcss salt |);
+ for (qw| username mail rank show_nsfw show_list skin customcss salt ign_votes |);
$h{'passwd = decode(?, \'hex\')'} = $o{passwd}
if defined $o{passwd};
diff --git a/lib/VNDB/Func.pm b/lib/VNDB/Func.pm
index 4ca20dc5..cd4c4b62 100644
--- a/lib/VNDB/Func.pm
+++ b/lib/VNDB/Func.pm
@@ -6,7 +6,7 @@ use warnings;
use YAWF ':html';
use Exporter 'import';
use POSIX 'strftime', 'ceil', 'floor';
-our @EXPORT = qw| shorten age date datestr monthstr userstr bb2html gtintype liststat clearfloat cssicon tagscore|;
+our @EXPORT = qw| shorten bb2html gtintype liststat clearfloat cssicon tagscore mt |;
# I would've done this as a #define if this was C...
@@ -16,72 +16,6 @@ sub shorten {
}
-# Argument: unix timestamp
-# Returns: age
-sub age {
- my $a = time-$_[0];
- return sprintf '%d %s ago',
- $a > 60*60*24*365*2 ? ( $a/60/60/24/365, 'years' ) :
- $a > 60*60*24*(365/12)*2 ? ( $a/60/60/24/(365/12), 'months' ) :
- $a > 60*60*24*7*2 ? ( $a/60/60/24/7, 'weeks' ) :
- $a > 60*60*24*2 ? ( $a/60/60/24, 'days' ) :
- $a > 60*60*2 ? ( $a/60/60, 'hours' ) :
- $a > 60*2 ? ( $a/60, 'min' ) :
- ( $a, 'sec' );
-}
-
-
-# argument: unix timestamp and optional format (compact/full)
-# return value: yyyy-mm-dd
-# (maybe an idea to use cgit-style ages for recent timestamps)
-sub date {
- my($t, $f) = @_;
- return strftime '%Y-%m-%d', gmtime $t if !$f || $f eq 'compact';
- return strftime '%Y-%m-%d at %R', gmtime $t;
-}
-
-
-# argument: database release date format (yyyymmdd)
-# y = 0000 -> unknown
-# y = 9999 -> TBA
-# m = 99 -> month+day unknown
-# d = 99 -> day unknown
-# return value: (unknown|TBA|yyyy|yyyy-mm|yyyy-mm-dd)
-# if date > now: <b class="future">str</b>
-sub datestr {
- my $date = sprintf '%08d', shift||0;
- my $future = $date > strftime '%Y%m%d', gmtime;
- my($y, $m, $d) = ($1, $2, $3) if $date =~ /^([0-9]{4})([0-9]{2})([0-9]{2})$/;
-
- my $str = $y == 0 ? 'unknown' : $y == 9999 ? 'TBA' :
- $m == 99 ? sprintf('%04d', $y) :
- $d == 99 ? sprintf('%04d-%02d', $y, $m) :
- sprintf('%04d-%02d-%02d', $y, $m, $d);
-
- return $str if !$future;
- return qq|<b class="future">$str</b>|;
-}
-
-# same as datestr(), but different output format:
-# e.g.: 'Jan 2009', '2009', 'unknown', 'TBA'
-sub monthstr {
- my $date = sprintf '%08d', shift||0;
- my($y, $m, $d) = ($1, $2, $3) if $date =~ /^([0-9]{4})([0-9]{2})([0-9]{2})/;
- return 'TBA' if $y == 9999;
- return 'unknown' if $y == 0;
- return $y if $m == 99;
- my $r = sprintf '%s %d', [qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)]->[$m-1], $y;
- return $d == 99 ? "<i>$r</i>" : $r;
-}
-
-
-# Arguments: (uid, username), or a hashref containing that info
-sub userstr {
- my($id,$n) = ref($_[0])eq'HASH'?($_[0]{uid}||$_[0]{requester}, $_[0]{username}):@_;
- return !$id ? '[deleted]' : '<a href="/u'.$id.'">'.$n.'</a>';
-}
-
-
# Arguments: input, and optionally the maximum length
# Parses:
# [url=..] [/url]
@@ -267,5 +201,12 @@ sub tagscore {
}
+# short wrapper around maketext()
+# (not thread-safe, in the same sense as YAWF::XML. But who cares about threads, anyway?)
+sub mt {
+ return $YAWF::OBJ->{l10n}->maketext(@_);
+}
+
+
1;
diff --git a/lib/VNDB/Handler/Discussions.pm b/lib/VNDB/Handler/Discussions.pm
index 811bd74a..1d74ac6a 100644
--- a/lib/VNDB/Handler/Discussions.pm
+++ b/lib/VNDB/Handler/Discussions.pm
@@ -33,11 +33,11 @@ sub thread {
div class => 'mainbox';
h1 $t->{title};
- h2 'Posted in';
+ h2 mt '_thread_postedin';
ul;
for (sort { $a->{type}.$a->{iid} cmp $b->{type}.$b->{iid} } @{$t->{boards}}) {
li;
- a href => "/t/$_->{type}", $self->{discussion_boards}{$_->{type}};
+ a href => "/t/$_->{type}", mt "_dboard_$_->{type}";
if($_->{iid}) {
txt ' > ';
a style => 'font-weight: bold', href => "/t/$_->{type}$_->{iid}", "$_->{type}$_->{iid}";
@@ -60,25 +60,24 @@ sub thread {
td class => 'tc1';
a href => "/t$tid.$_->{num}", name => $_->{num}, "#$_->{num}";
if(!$_->{hidden}) {
- txt ' by ';
- lit userstr $_;
+ lit ' '.mt "_thread_byuser", $_;
br;
- lit date $_->{date}, 'full';
+ lit $self->{l10n}->date($_->{date}, 'full');
}
end;
td class => 'tc2';
if($self->authCan('boardmod') || $self->authInfo->{id} && $_->{uid} == $self->authInfo->{id} && !$_->{hidden}) {
i class => 'edit';
txt '< ';
- a href => "/t$tid.$_->{num}/edit", 'edit';
+ a href => "/t$tid.$_->{num}/edit", mt '_thread_editpost';
txt ' >';
end;
}
if($_->{hidden}) {
- i class => 'deleted', 'Post deleted.';
+ i class => 'deleted', mt '_thread_deletedpost';
} else {
lit bb2html $_->{msg};
- i class => 'lastmod', 'Last modified on '.date($_->{edited}, 'full') if $_->{edited};
+ i class => 'lastmod', mt '_thread_lastmodified', $_->{edited} if $_->{edited};
}
end;
end;
@@ -89,24 +88,28 @@ sub thread {
if($t->{locked}) {
div class => 'mainbox';
- h1 'Reply';
- p class => 'center', 'This thread has been locked, you can\'t reply to it anymore.';
+ h1 mt '_thread_noreply_title';
+ p class => 'center', mt '_thread_noreply_locked';
end;
} elsif($t->{count} <= $page*25 && $self->authCan('board')) {
form action => "/t$tid/reply", method => 'post', 'accept-charset' => 'UTF-8';
div class => 'mainbox';
fieldset class => 'submit';
- h2 'Quick reply';
+ h2;
+ txt mt '_thread_quickreply_title';
+ b class => 'standout', ' ('.mt('_inenglish').')';
+ end;
textarea name => 'msg', id => 'msg', rows => 4, cols => 50, '';
br;
- input type => 'submit', value => 'Reply', class => 'submit';
+ input type => 'submit', value => mt('_thread_quickreply_submit'), class => 'submit';
+ input type => 'submit', value => mt('_thread_quickreply_full'), class => 'submit', name => 'fullreply';
end;
end;
end;
} elsif(!$self->authCan('board')) {
div class => 'mainbox';
- h1 'Reply';
- p class => 'center', 'You must be logged in to reply to this thread.';
+ h1 mt '_thread_noreply_title';
+ p class => 'center', mt '_thread_noreply_login';
end;
}
@@ -164,10 +167,13 @@ sub edit {
{ name => 'nolastmod', required => 0 },
) : (),
{ name => 'msg', maxlenght => 5000 },
+ { name => 'fullreply', required => 0 },
);
+ $frm->{_err} = 1 if $frm->{fullreply};
+
# check for double-posting
- push @{$frm->{_err}}, 'doublepost' if !$num && $self->dbPostGet(
+ push @{$frm->{_err}}, 'doublepost' if !$num && !$frm->{_err} && $self->dbPostGet(
uid => $self->authInfo->{id}, tid => $tid, mindate => time - 30, results => 1, $tid ? () : (num => 1))->[0]{num};
# parse and validate the boards
@@ -177,7 +183,7 @@ sub edit {
my($ty, $id) = ($1, $2) if /^([a-z]{1,2})([0-9]*)$/;
push @boards, [ $ty, $id ];
push @{$frm->{_err}}, [ 'boards', 'wrongboard', $_ ] if
- !$ty || !$self->{discussion_boards}{$ty}
+ !$ty || !grep($_ eq $ty, @{$self->{discussion_boards}})
|| $ty eq 'an' && ($id || !$self->authCan('boardmod'))
|| $ty eq 'db' && $id
|| $ty eq 'v' && (!$id || !$self->dbVNGet(id => $id)->[0]{id})
@@ -225,35 +231,36 @@ sub edit {
$frm->{hidden} = $t->{hidden} if !exists $frm->{hidden};
}
}
+ delete $frm->{_err} unless ref $frm->{_err};
$frm->{boards} ||= $board;
$frm->{nolastmod} = 1 if $num && $self->authCan('boardmod') && !exists $frm->{nolastmod};
# generate html
- my $title = !$tid ? 'Start new thread' :
- !$num ? 'Reply to '.$t->{title} :
- 'Edit post';
+ my $title = mt !$tid ? '_postedit_newthread' :
+ !$num ? ('_postedit_replyto', $t->{title}) :
+ '_postedit_edit';
my $url = !$tid ? "/t/$board/new" : !$num ? "/t$tid/reply" : "/t$tid.$num/edit";
$self->htmlHeader(title => $title, noindex => 1);
- $self->htmlForm({ frm => $frm, action => $url }, $title => [
- [ static => label => 'Username', content => userstr($self->authInfo->{id}, $self->authInfo->{username}) ],
+ $self->htmlForm({ frm => $frm, action => $url }, 'postedit' => [$title,
+ [ static => label => mt('_postedit_form_username'), content => $self->{l10n}->userstr($self->authInfo->{id}, $self->authInfo->{username}) ],
!$tid || $num == 1 ? (
- [ input => short => 'title', name => 'Thread title' ],
- [ input => short => 'boards', name => 'Board(s)' ],
- [ static => content => 'Read <a href="/d9.2">d9.2</a> for information about how to specify boards' ],
+ [ input => short => 'title', name => mt('_postedit_form_title') ],
+ [ input => short => 'boards', name => mt('_postedit_form_boards') ],
+ [ static => content => mt('_postedit_form_boards_info') ],
$self->authCan('boardmod') ? (
- [ check => name => 'Locked', short => 'locked' ],
+ [ check => name => mt('_postedit_form_locked'), short => 'locked' ],
) : (),
) : (
- [ static => label => 'Topic', content => qq|<a href="/t$tid">|.xml_escape($t->{title}).'</a>' ],
+ [ static => label => mt('_postedit_form_topic'), content => qq|<a href="/t$tid">|.xml_escape($t->{title}).'</a>' ],
),
$self->authCan('boardmod') ? (
- [ check => name => 'Hidden', short => 'hidden' ],
+ [ check => name => mt('_postedit_form_hidden'), short => 'hidden' ],
$num ? (
- [ check => name => 'Don\'t update last modified field', short => 'nolastmod' ],
+ [ check => name => mt('_postedit_form_nolastmod'), short => 'nolastmod' ],
) : (),
) : (),
- [ text => name => 'Message', short => 'msg', rows => 10 ],
- [ static => content => 'See <a href="/d9.3">d9.3</a> for the allowed formatting codes' ],
+ [ text => name => mt('_postedit_form_msg').'<br /><b class="standout">'.mt('_inenglish').'</b>', short => 'msg', rows => 25, cols => 75 ],
+ [ static => content => mt('_postedit_form_msg_format') ],
]);
$self->htmlFooter;
}
@@ -275,7 +282,7 @@ sub board {
$self->dbVNGet(id => $iid)->[0];
return 404 if $iid && !$obj;
my $ititle = $obj && ($obj->{title}||$obj->{name}||$obj->{username});
- my $title = !$obj ? $self->{discussion_boards}{$type} : 'Related discussions for '.$ititle;
+ my $title = !$obj ? mt("_dboard_$type") : mt '_disboard_item_title', $ititle;
my($list, $np) = $self->dbThreadGet(
type => $type,
@@ -292,9 +299,9 @@ sub board {
div class => 'mainbox';
h1 $title;
p;
- a href => '/t', 'Discussion board';
+ a href => '/t', mt '_disboard_rootlink';
txt ' > ';
- a href => "/t/$type", $self->{discussion_boards}{$type};
+ a href => "/t/$type", mt "_dboard_$type";
if($iid) {
txt ' > ';
a style => 'font-weight: bold', href => "/t/$type$iid", "$type$iid";
@@ -304,11 +311,11 @@ sub board {
end;
p class => 'center';
if(!@$list) {
- b 'No related threads found';
+ b mt '_disboard_nothreads';
br; br;
- a href => "/t/$type$iid/new", 'Why not create one yourself?';
+ a href => "/t/$type$iid/new", mt '_disboard_createyourown';
} else {
- a href => '/t/'.($iid ? $type.$iid : 'db').'/new', 'Start a new thread';
+ a href => '/t/'.($iid ? $type.$iid : 'db').'/new', mt '_disboard_startnew';
}
end;
end;
@@ -322,11 +329,11 @@ sub board {
sub index {
my $self = shift;
- $self->htmlHeader(title => 'Discussion board index');
+ $self->htmlHeader(title => mt '_disindex_title');
div class => 'mainbox';
- h1 'Discussion board index';
+ h1 mt '_disindex_title';
p class => 'browseopts';
- a href => '/t/'.$_, $self->{discussion_boards}{$_}
+ a href => '/t/'.$_, mt "_dboard_$_"
for (qw|an db v p u|);
end;
end;
@@ -340,7 +347,7 @@ sub index {
order => 'tpl.date DESC',
);
h1 class => 'boxtitle';
- a href => "/t/$_", $self->{discussion_boards}{$_};
+ a href => "/t/$_", mt "_dboard_$_";
end;
_threadlist($self, $list, {p=>1}, 0, "/t");
}
@@ -358,7 +365,10 @@ sub _threadlist {
pageurl => $url,
class => 'discussions',
header => [
- [ 'Topic' ], [ 'Replies' ], [ 'Starter' ], [ 'Last post' ]
+ [ mt '_threadlist_col_topic' ],
+ [ mt '_threadlist_col_replies' ],
+ [ mt '_threadlist_col_starter' ],
+ [ mt '_threadlist_col_lastpost' ],
],
row => sub {
my($self, $n, $o) = @_;
@@ -368,13 +378,13 @@ sub _threadlist {
end;
td class => 'tc2', $o->{count}-1;
td class => 'tc3';
- lit userstr $o->{fuid}, $o->{fusername};
+ lit $self->{l10n}->userstr($o->{fuid}, $o->{fusername});
end;
td class => 'tc4';
- lit userstr $o->{luid}, $o->{lusername};
+ lit $self->{l10n}->userstr($o->{luid}, $o->{lusername});
lit ' @ ';
a href => "/t$o->{id}.$o->{count}";
- lit date $o->{ldate};
+ lit $self->{l10n}->date($o->{ldate});
end;
end;
end;
@@ -386,8 +396,8 @@ sub _threadlist {
last if $i++ > 5;
txt ', ' if $i > 2;
a href => "/t/$_->{type}".($_->{iid}||''),
- title => $_->{original}||$self->{discussion_boards}{$_->{type}},
- shorten $_->{title}||$self->{discussion_boards}{$_->{type}}, 30;
+ title => $_->{original}||mt("_dboard_$_->{type}"),
+ shorten $_->{title}||mt("_dboard_$_->{type}"), 30;
}
txt ', ...' if @{$o->{boards}} > 5;
end;
diff --git a/lib/VNDB/Handler/Misc.pm b/lib/VNDB/Handler/Misc.pm
index ceae11ce..891a83f0 100644
--- a/lib/VNDB/Handler/Misc.pm
+++ b/lib/VNDB/Handler/Misc.pm
@@ -4,8 +4,9 @@ package VNDB::Handler::Misc;
use strict;
use warnings;
-use YAWF ':html', ':xml';
+use YAWF ':html', ':xml', 'xml_escape';
use VNDB::Func;
+use POSIX 'strftime';
YAWF::register(
@@ -36,23 +37,12 @@ YAWF::register(
sub homepage {
my $self = shift;
- $self->htmlHeader(title => $self->{site_title});
+ $self->htmlHeader(title => mt '_site_title');
div class => 'mainbox';
- h1 $self->{site_title};
+ h1 mt '_site_title';
p class => 'description';
- lit qq|
- VNDB.org strives to be a comprehensive database for information about visual novels and
- eroge.<br />
- This website is built as a wiki, meaning that anyone can freely add and contribute information
- to the database, allowing us to create the largest, most accurate and most up-to-date visual novel
- database on the web.<br />
- Registered users are also able to keep track of a personal list of games they want to play or have finished
- and they can vote on all visual novels.<br />
- <br />
- Feel free to <a href="/v/all">browse around</a>, <a href="/u/register">register an account</a>
- or to participate in the discussions about visual novels or VNDB on our <a href="/t">discussion board</a>.
- |;
+ lit mt '_home_intro';
end;
my $scr = $self->dbScreenshotRandom;
@@ -65,104 +55,121 @@ sub homepage {
end;
end;
- # Recent changes
- div class => 'mainbox threelayout';
- h1 'Recent changes';
- my $changes = $self->dbRevisionGet(what => 'item user', results => 10, auto => 1, hidden => 1);
- ul;
- for (@$changes) {
- my $t = (qw|v r p|)[$_->{type}];
- li;
- b "$t:";
- a href => "/$t$_->{iid}.$_->{rev}", title => $_->{ioriginal}||$_->{ititle}, shorten $_->{ititle}, 30;
- txt ' by ';
- a href => "/u$_->{requester}", $_->{username};
- end;
- }
- end;
- end;
+ table class => 'mainbox threelayout';
+ Tr;
- # Announcements
- div class => 'mainbox threelayout';
- my $an = $self->dbThreadGet(type => 'an', order => 't.id DESC', results => 2);
- a class => 'right', href => '/t/an', 'News archive';
- h1 'Announcements';
- for (@$an) {
- my $post = $self->dbPostGet(tid => $_->{id}, num => 1)->[0];
- h2;
- a href => "/t$_->{id}", $_->{title};
+ # Recent changes
+ td;
+ h1;
+ a href => '/hist', mt '_home_recentchanges';
end;
- p;
- lit bb2html $post->{msg}, 150;
+ my $changes = $self->dbRevisionGet(what => 'item user', results => 10, auto => 1, hidden => 1);
+ ul;
+ for (@$changes) {
+ my $t = (qw|v r p|)[$_->{type}];
+ li;
+ lit mt '_home_recentchanges_item', $t,
+ sprintf('<a href="%s" title="%s">%s</a>', "/$t$_->{iid}.$_->{rev}",
+ xml_escape($_->{ioriginal}||$_->{ititle}), xml_escape shorten $_->{ititle}, 33),
+ $_;
+ end;
+ }
end;
- }
- end;
+ end;
- # Recent posts
- div class => 'mainbox threelayout last';
- h1 'Recent posts';
- my $posts = $self->dbThreadGet(what => 'lastpost boardtitles', results => 10, order => 'tpl.date DESC', notusers => 1);
- ul;
- for (@$posts) {
- my $boards = join ', ', map $self->{discussion_boards}{$_->{type}}.($_->{iid}?' > '.$_->{title}:''), @{$_->{boards}};
- li;
- txt age($_->{ldate}).' ';
- a href => "/t$_->{id}.$_->{count}", title => "Posted in $boards", shorten $_->{title}, 20;
- txt ' by ';
- a href => "/u$_->{luid}", $_->{lusername};
- end;
- }
- end;
- end;
+ # Announcements
+ td;
+ my $an = $self->dbThreadGet(type => 'an', order => 't.id DESC', results => 2);
+ h1;
+ a href => '/t/an', mt '_home_announcements';
+ end;
+ for (@$an) {
+ my $post = $self->dbPostGet(tid => $_->{id}, num => 1)->[0];
+ h2;
+ a href => "/t$_->{id}", $_->{title};
+ end;
+ p;
+ lit bb2html $post->{msg}, 150;
+ end;
+ }
+ end;
- # Random visual novels
- div class => 'mainbox threelayout';
- h1 'Random visual novels';
- my $random = $self->dbVNGet(results => 10, order => 'RANDOM()');
- ul;
- for (@$random) {
- li;
- a href => "/v$_->{id}", title => $_->{original}||$_->{title}, shorten $_->{title}, 40;
- end;
- }
- end;
- end;
+ # Recent posts
+ td;
+ h1;
+ a href => '/t', mt '_home_recentposts';
+ end;
+ my $posts = $self->dbThreadGet(what => 'lastpost boardtitles', results => 10, order => 'tpl.date DESC', notusers => 1);
+ ul;
+ for (@$posts) {
+ my $boards = join ', ', map mt("_dboard_$_->{type}").($_->{iid}?' > '.$_->{title}:''), @{$_->{boards}};
+ li;
+ lit mt '_home_recentposts_item', $_->{ldate},
+ sprintf('<a href="%s" title="%s">%s</a>', "/t$_->{id}.$_->{count}",
+ xml_escape("Posted in $boards"), xml_escape shorten $_->{title}, 25),
+ {uid => $_->{luid}, username => $_->{lusername}};
+ end;
+ }
+ end;
+ end;
- # Upcoming releases
- div class => 'mainbox threelayout';
- h1 'Upcoming releases';
- my $upcoming = $self->dbReleaseGet(results => 10, unreleased => 1, what => 'platforms');
- ul;
- for (@$upcoming) {
- li;
- lit datestr $_->{released};
- txt ' ';
- cssicon $_, $self->{platforms}{$_} for (@{$_->{platforms}});
- txt ' ';
- a href => "/r$_->{id}", title => $_->{original}||$_->{title}, shorten $_->{title}, 30;
- end;
- }
end;
- end;
+ Tr;
+
+ # Random visual novels
+ td;
+ h1 mt '_home_randomvn';
+ my $random = $self->dbVNGet(results => 10, order => 'RANDOM()');
+ ul;
+ for (@$random) {
+ li;
+ a href => "/v$_->{id}", title => $_->{original}||$_->{title}, shorten $_->{title}, 40;
+ end;
+ }
+ end;
+ end;
- # Just released
- div class => 'mainbox threelayout last';
- h1 'Just released';
- my $justrel = $self->dbReleaseGet(results => 10, order => 'rr.released DESC', unreleased => 0, what => 'platforms');
- ul;
- for (@$justrel) {
- li;
- lit datestr $_->{released};
- txt ' ';
- cssicon $_, $self->{platforms}{$_} for (@{$_->{platforms}});
- txt ' ';
- a href => "/r$_->{id}", title => $_->{original}||$_->{title}, shorten $_->{title}, 30;
- end;
- }
- end;
- end;
+ # Upcoming releases
+ td;
+ h1;
+ a href => strftime('/r?mi=%Y%m%d;o=a;s=released', gmtime), mt '_home_upcoming';
+ end;
+ my $upcoming = $self->dbReleaseGet(results => 10, unreleased => 1, what => 'platforms');
+ ul;
+ for (@$upcoming) {
+ li;
+ lit $self->{l10n}->datestr($_->{released});
+ txt ' ';
+ cssicon $_, mt "_plat_$_" for (@{$_->{platforms}});
+ txt ' ';
+ a href => "/r$_->{id}", title => $_->{original}||$_->{title}, shorten $_->{title}, 30;
+ end;
+ }
+ end;
+ end;
+
+ # Just released
+ td;
+ h1;
+ a href => strftime('/r?ma=%Y%m%d;o=d;s=released', gmtime), mt '_home_justreleased';
+ end;
+ my $justrel = $self->dbReleaseGet(results => 10, order => 'rr.released DESC', unreleased => 0, what => 'platforms');
+ ul;
+ for (@$justrel) {
+ li;
+ lit $self->{l10n}->datestr($_->{released});
+ txt ' ';
+ cssicon $_, mt "_plat_$_" for (@{$_->{platforms}});
+ txt ' ';
+ a href => "/r$_->{id}", title => $_->{original}||$_->{title}, shorten $_->{title}, 30;
+ end;
+ }
+ end;
+ end;
+
+ end; # /tr
+ end; # /table
- clearfloat;
$self->htmlFooter;
}
@@ -187,7 +194,7 @@ sub history {
$type eq 'p' ? $self->dbProducerGet(id => $id)->[0] :
$type eq 'r' ? $self->dbReleaseGet(id => $id)->[0] :
$type eq 'v' ? $self->dbVNGet(id => $id)->[0] : undef;
- my $title = $type ? 'Edit history of '.($obj->{title} || $obj->{name} || $obj->{username}) : 'Recent changes';
+ my $title = mt $type ? ('_hist_title_item', $obj->{title} || $obj->{name} || $obj->{username}) : '_hist_title';
return 404 if $type && !$obj->{id};
# get the edit history
@@ -224,33 +231,33 @@ sub history {
h1 $title;
if($type ne 'u') {
p class => 'browseopts';
- a !$f->{m} ? (class => 'optselected') : (), href => $u->(m => 0), 'Show automated edits';
- a $f->{m} ? (class => 'optselected') : (), href => $u->(m => 1), 'Hide automated edits';
+ a !$f->{m} ? (class => 'optselected') : (), href => $u->(m => 0), mt '_hist_filter_showauto';
+ a $f->{m} ? (class => 'optselected') : (), href => $u->(m => 1), mt '_hist_filter_hideauto';
end;
}
if(!$type || $type eq 'u') {
if($self->authCan('del')) {
p class => 'browseopts';
- a $f->{h} == 1 ? (class => 'optselected') : (), href => $u->(h => 1), 'Hide deleted items';
- a $f->{h} == -1 ? (class => 'optselected') : (), href => $u->(h => -1), 'Show deleted items';
+ a $f->{h} == 1 ? (class => 'optselected') : (), href => $u->(h => 1), mt '_hist_filter_hidedel';
+ a $f->{h} == -1 ? (class => 'optselected') : (), href => $u->(h => -1), mt '_hist_filter_showdel';
end;
}
p class => 'browseopts';
- a !$f->{t} ? (class => 'optselected') : (), href => $u->(t => ''), 'Show all items';
- a $f->{t} eq 'v' ? (class => 'optselected') : (), href => $u->(t => 'v'), 'Only visual novels';
- a $f->{t} eq 'r' ? (class => 'optselected') : (), href => $u->(t => 'r'), 'Only releases';
- a $f->{t} eq 'p' ? (class => 'optselected') : (), href => $u->(t => 'p'), 'Only producers';
+ a !$f->{t} ? (class => 'optselected') : (), href => $u->(t => ''), mt '_hist_filter_alltypes';
+ a $f->{t} eq 'v' ? (class => 'optselected') : (), href => $u->(t => 'v'), mt '_hist_filter_onlyvn';
+ a $f->{t} eq 'r' ? (class => 'optselected') : (), href => $u->(t => 'r'), mt '_hist_filter_onlyreleases';
+ a $f->{t} eq 'p' ? (class => 'optselected') : (), href => $u->(t => 'p'), mt '_hist_filter_onlyproducers';
end;
p class => 'browseopts';
- a !$f->{e} ? (class => 'optselected') : (), href => $u->(e => 0), 'Show all changes';
- a $f->{e} == 1 ? (class => 'optselected') : (), href => $u->(e => 1), 'Only edits';
- a $f->{e} == -1 ? (class => 'optselected') : (), href => $u->(e => -1), 'Only newly created pages';
+ a !$f->{e} ? (class => 'optselected') : (), href => $u->(e => 0), mt '_hist_filter_allactions';
+ a $f->{e} == 1 ? (class => 'optselected') : (), href => $u->(e => 1), mt '_hist_filter_onlyedits';
+ a $f->{e} == -1 ? (class => 'optselected') : (), href => $u->(e => -1), mt '_hist_filter_onlynew';
end;
}
if($type eq 'v') {
p class => 'browseopts';
- a !$f->{r} ? (class => 'optselected') : (), href => $u->(r => 0), 'Exclude edits of releases';
- a $f->{r} ? (class => 'optselected') : (), href => $u->(r => 1), 'Include edits of releases';
+ a !$f->{r} ? (class => 'optselected') : (), href => $u->(r => 0), mt '_hist_filter_exrel';
+ a $f->{r} ? (class => 'optselected') : (), href => $u->(r => 1), mt '_hist_filter_increl';
end;
}
end;
@@ -263,7 +270,10 @@ sub history {
sub docpage {
my($self, $did) = @_;
- open my $F, '<', sprintf('%s/data/docs/%d', $VNDB::ROOT, $did) or return 404;
+ my $l = '.'.$self->{l10n}->language_tag();
+ my $f = sprintf('%s/data/docs/%d', $VNDB::ROOT, $did);
+ my $F;
+ open($F, '<:utf8', $f.$l) or open($F, '<:utf8', $f) or return 404;
my @c = <$F>;
close $F;
@@ -277,7 +287,8 @@ sub docpage {
qq|<h3><a href="#$sec" name="$sec">$sec. $1</a></h3>\n|
}eg;
s{^:INC:(.+)\r?\n$}{
- open $F, '<', sprintf('%s/data/docs/%s', $VNDB::ROOT, $1) or die $!;
+ $f = sprintf('%s/data/docs/%s', $VNDB::ROOT, $1);
+ open($F, '<:utf8', $f.$l) or open($F, '<:utf8', $f) or die $!;
my $ii = join('', <$F>);
close $F;
$ii;
@@ -297,13 +308,13 @@ sub docpage {
sub nospam {
my $self = shift;
- $self->htmlHeader(title => 'Could not send form', noindex => 1);
+ $self->htmlHeader(title => mt '_nospam_title', noindex => 1);
div class => 'mainbox';
- h1 'Could not send form';
+ h1 mt '_nospam_title';
div class => 'warning';
- h2 'Error';
- p 'The form could not be sent, please make sure you have Javascript enabled in your browser.';
+ h2 mt '_nospam_subtitle';
+ p mt '_nospam_msg';
end;
end;
@@ -354,7 +365,7 @@ sub ie6message {
end;
body;
div;
- h1 'Oops, we were too lazy support your browser!';
+ h1 'Oops, we were too lazy to support your browser!';
p;
lit qq|We decided to stop supporting Internet Explorer 6, as it's a royal pain in |
.qq|the ass to make our site look good in a browser that doesn't want to cooperate with us.<br />|
diff --git a/lib/VNDB/Handler/Producers.pm b/lib/VNDB/Handler/Producers.pm
index aa010e6e..e6477567 100644
--- a/lib/VNDB/Handler/Producers.pm
+++ b/lib/VNDB/Handler/Producers.pm
@@ -33,13 +33,13 @@ sub page {
if($rev) {
my $prev = $rev && $rev > 1 && $self->dbProducerGet(id => $pid, rev => $rev-1, what => 'changes extended')->[0];
$self->htmlRevision('p', $prev, $p,
- [ type => 'Type', serialize => sub { $self->{producer_types}{$_[0]} } ],
- [ name => 'Name (romaji)', diff => 1 ],
- [ original => 'Original name', diff => 1 ],
- [ alias => 'Aliases', diff => 1 ],
- [ lang => 'Language', serialize => sub { "$_[0] ($self->{languages}{$_[0]})" } ],
- [ website => 'Website', diff => 1 ],
- [ desc => 'Description', diff => 1 ],
+ [ type => serialize => sub { mt "_ptype_$_[0]" } ],
+ [ name => diff => 1 ],
+ [ original => diff => 1 ],
+ [ alias => diff => 1 ],
+ [ lang => serialize => sub { "$_[0] (".mt("_lang_$_[0]").')' } ],
+ [ website => diff => 1 ],
+ [ desc => diff => 1 ],
);
}
@@ -48,8 +48,8 @@ sub page {
h1 $p->{name};
h2 class => 'alttitle', $p->{original} if $p->{original};
p class => 'center';
- txt "$self->{languages}{$p->{lang}} \L$self->{producer_types}{$p->{type}}";
- txt "\na.k.a. $p->{alias}" if $p->{alias};
+ txt mt '_prodpage_langtype', mt("_lang_$p->{lang}"), mt "_ptype_$p->{type}";
+ txt "\n".mt '_prodpage_aliases', $p->{alias} if $p->{alias};
if($p->{website}) {
txt "\n";
a href => $p->{website}, $p->{website};
@@ -64,15 +64,15 @@ sub page {
end;
div class => 'mainbox producerpage';
- h1 'Visual Novel Relations';
+ h1 mt '_prodpage_vnrel';
if(!@{$p->{vn}}) {
- p 'We have currently no visual novels related to this producer.';
+ p mt '_prodpage_norel';
} else {
ul;
for (@{$p->{vn}}) {
li;
i;
- lit datestr $_->{date};
+ lit $self->{l10n}->datestr($_->{date});
end;
a href => "/v$_->{id}", title => $_->{original}, $_->{title};
end;
@@ -101,11 +101,11 @@ sub edit {
if($self->reqMethod eq 'POST') {
$frm = $self->formValidate(
- { name => 'type', enum => [ keys %{$self->{producer_types}} ] },
+ { name => 'type', enum => $self->{producer_types} },
{ name => 'name', maxlength => 200 },
{ name => 'original', required => 0, maxlength => 200, default => '' },
{ name => 'alias', required => 0, maxlength => 500, default => '' },
- { name => 'lang', enum => [ keys %{$self->{languages}} ] },
+ { name => 'lang', enum => $self->{languages} },
{ name => 'website', required => 0, template => 'url', default => '' },
{ name => 'desc', required => 0, maxlength => 5000, default => '' },
{ name => 'editsum', maxlength => 5000 },
@@ -129,21 +129,22 @@ sub edit {
$frm->{lang} = 'ja' if !$pid && !defined $frm->{lang};
$frm->{editsum} = sprintf 'Reverted to revision p%d.%d', $pid, $rev if $rev && !defined $frm->{editsum};
- $self->htmlHeader(title => $pid ? 'Edit '.$p->{name} : 'Add new producer', noindex => 1);
+ my $title = mt $pid ? ('_pedit_title_edit', $p->{name}) : '_pedit_title_add';
+ $self->htmlHeader(title => $title, noindex => 1);
$self->htmlMainTabs('p', $p, 'edit') if $pid;
- $self->htmlEditMessage('p', $p);
- $self->htmlForm({ frm => $frm, action => $pid ? "/p$pid/edit" : '/p/new', editsum => 1 }, "General info" => [
- [ select => name => 'Type', short => 'type',
- options => [ map [ $_, $self->{producer_types}{$_} ], sort keys %{$self->{producer_types}} ] ],
- [ input => name => 'Name (romaji)', short => 'name' ],
- [ input => name => 'Original name', short => 'original' ],
- [ static => content => q|The original name of the producer, leave blank if it is already in the Latin alphabet.| ],
- [ input => name => 'Aliases', short => 'alias', width => 400 ],
- [ static => content => q|(Un)official aliases, separated by a comma.| ],
- [ select => name => 'Primary language', short => 'lang',
- options => [ map [ $_, "$_ ($self->{languages}{$_})" ], sort keys %{$self->{languages}} ] ],
- [ input => name => 'Website', short => 'website' ],
- [ text => name => 'Description', short => 'desc', rows => 6 ],
+ $self->htmlEditMessage('p', $p, $title);
+ $self->htmlForm({ frm => $frm, action => $pid ? "/p$pid/edit" : '/p/new', editsum => 1 }, 'pedit_geninfo' => [mt('_pedit_form_generalinfo'),
+ [ select => name => mt('_pedit_form_type'), short => 'type',
+ options => [ map [ $_, mt "_ptype_$_" ], sort @{$self->{producer_types}} ] ],
+ [ input => name => mt('_pedit_form_name'), short => 'name' ],
+ [ input => name => mt('_pedit_form_original'), short => 'original' ],
+ [ static => content => mt('_pedit_form_original_note') ],
+ [ input => name => mt('_pedit_form_alias'), short => 'alias', width => 400 ],
+ [ static => content => mt('_pedit_form_alias_note') ],
+ [ select => name => mt('_pedit_form_lang'), short => 'lang',
+ options => [ map [ $_, "$_ (".mt("_lang_$_").')' ], sort @{$self->{languages}} ] ],
+ [ input => name => mt('_pedit_form_website'), short => 'website' ],
+ [ text => name => mt('_pedit_form_desc').'<br /><b class="standout">'.mt('_inenglish').'</b>', short => 'desc', rows => 6 ],
]);
$self->htmlFooter;
}
@@ -165,16 +166,16 @@ sub list {
page => $f->{p}
);
- $self->htmlHeader(title => 'Browse producers');
+ $self->htmlHeader(title => mt '_pbrowse_title');
div class => 'mainbox';
- h1 'Browse producers';
+ h1 mt '_pbrowse_title';
form action => '/p/all', 'accept-charset' => 'UTF-8', method => 'get';
$self->htmlSearchBox('p', $f->{q});
end;
p class => 'browseopts';
for ('all', 'a'..'z', 0) {
- a href => "/p/$_", $_ eq $char ? (class => 'optselected') : (), $_ ? uc $_ : '#';
+ a href => "/p/$_", $_ eq $char ? (class => 'optselected') : (), $_ eq 'all' ? mt('_char_all') : $_ ? uc $_ : '#';
}
end;
end;
@@ -182,9 +183,9 @@ sub list {
my $pageurl = "/p/$char" . ($f->{q} ? "?q=$f->{q}" : '');
$self->htmlBrowseNavigate($pageurl, $f->{p}, $np, 't');
div class => 'mainbox producerbrowse';
- h1 $f->{q} ? 'Search results' : 'Producer list';
+ h1 mt $f->{q} ? '_pbrowse_searchres' : '_pbrowse_list';
if(!@$list) {
- p 'No results found';
+ p mt '_pbrowse_noresults';
} else {
# spread the results over 3 equivalent-sized lists
my $perlist = @$list/3 < 1 ? 1 : @$list/3;
@@ -192,7 +193,7 @@ sub list {
ul;
for ($perlist*$c..($perlist*($c+1))-1) {
li;
- cssicon 'lang '.$list->[$_]{lang}, $self->{languages}{$list->[$_]{lang}};
+ cssicon 'lang '.$list->[$_]{lang}, mt "_lang_$list->[$_]{lang}";
a href => "/p$list->[$_]{id}", title => $list->[$_]{original}, $list->[$_]{name};
end;
}
diff --git a/lib/VNDB/Handler/Releases.pm b/lib/VNDB/Handler/Releases.pm
index db234aea..f0daa4cb 100644
--- a/lib/VNDB/Handler/Releases.pm
+++ b/lib/VNDB/Handler/Releases.pm
@@ -36,34 +36,34 @@ sub page {
what => 'vn extended producers platforms media changes'
)->[0];
$self->htmlRevision('r', $prev, $r,
- [ vn => 'Relations', join => '<br />', split => sub {
+ [ vn => join => '<br />', split => sub {
map sprintf('<a href="/v%d" title="%s">%s</a>', $_->{vid}, $_->{original}||$_->{title}, shorten $_->{title}, 50), @{$_[0]};
} ],
- [ type => 'Type', serialize => sub { $self->{release_types}[$_[0]] } ],
- [ patch => 'Patch', serialize => sub { $_[0] ? 'Patch' : 'Not a patch' } ],
- [ freeware => 'Freeware', serialize => sub { $_[0] ? 'yes' : 'nope' } ],
- [ doujin => 'Doujin', serialize => sub { $_[0] ? 'yups' : 'nope' } ],
- [ title => 'Title (romaji)', diff => 1 ],
- [ original => 'Original title', diff => 1 ],
- [ gtin => 'JAN/UPC/EAN', serialize => sub { $_[0]||'[none]' } ],
- [ catalog => 'Catalog number', serialize => sub { $_[0]||'[none]' } ],
- [ languages => 'Language', join => ', ', split => sub { map $self->{languages}{$_}, @{$_[0]} } ],
- [ website => 'Website', ],
- [ released => 'Release date', htmlize => sub { datestr $_[0] } ],
- [ minage => 'Age rating', serialize => sub { $self->{age_ratings}{$_[0]}[0] } ],
- [ notes => 'Notes', diff => 1 ],
- [ platforms => 'Platforms', join => ', ', split => sub { map $self->{platforms}{$_}, @{$_[0]} } ],
- [ media => 'Media', join => ', ', split => sub {
+ [ type => serialize => sub { mt "_rtype_$_[0]" } ],
+ [ patch => serialize => sub { $_[0] ? 'Patch' : 'Not a patch' } ],
+ [ freeware => serialize => sub { $_[0] ? 'yes' : 'nope' } ],
+ [ doujin => serialize => sub { $_[0] ? 'yups' : 'nope' } ],
+ [ title => diff => 1 ],
+ [ original => diff => 1 ],
+ [ gtin => serialize => sub { $_[0]||'[none]' } ],
+ [ catalog => serialize => sub { $_[0]||'[none]' } ],
+ [ languages => join => ', ', split => sub { map mt("_lang_$_"), @{$_[0]} } ],
+ [ 'website' ],
+ [ released => htmlize => sub { $self->{l10n}->datestr($_[0]) } ],
+ [ minage => serialize => sub { $self->{age_ratings}{$_[0]}[0] } ],
+ [ notes => diff => 1 ],
+ [ platforms => join => ', ', split => sub { map mt("_plat_$_"), @{$_[0]} } ],
+ [ media => join => ', ', split => sub {
map {
my $med = $self->{media}{$_->{medium}};
$med->[1] ? sprintf('%d %s%s', $_->{qty}, $med->[0], $_->{qty}>1?'s':'') : $med->[0]
} @{$_[0]};
} ],
- [ resolution => 'Resolution', serialize => sub { $self->{resolutions}[$_[0]][0] } ],
- [ voiced => 'Voiced', serialize => sub { $self->{voiced}[$_[0]] } ],
- [ ani_story => 'Story animation',serialize => sub { $self->{animated}[$_[0]] } ],
- [ ani_ero => 'Ero animation', serialize => sub { $self->{animated}[$_[0]] } ],
- [ producers => 'Producers', join => '<br />', split => sub {
+ [ resolution => serialize => sub { $self->{resolutions}[$_[0]][0] } ],
+ [ voiced => serialize => sub { mt '_voiced_'.$_[0] } ],
+ [ ani_story => serialize => sub { mt '_animated_'.$_[0] } ],
+ [ ani_ero => serialize => sub { mt '_animated_'.$_[0] } ],
+ [ producers => join => '<br />', split => sub {
map sprintf('<a href="/p%d" title="%s">%s</a>', $_->{id}, $_->{original}||$_->{name}, shorten $_->{name}, 50), @{$_[0]};
} ],
);
@@ -93,7 +93,7 @@ sub _infotable {
my $i = 0;
Tr ++$i % 2 ? (class => 'odd') : ();
- td class => 'key', 'Relation';
+ td class => 'key', mt '_relinfo_vnrel';
td;
for (@{$r->{vn}}) {
a href => "/v$_->{vid}", title => $_->{original}||$_->{title}, shorten $_->{title}, 60;
@@ -103,50 +103,48 @@ sub _infotable {
end;
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'Title';
+ td mt '_relinfo_title';
td $r->{title};
end;
if($r->{original}) {
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'Original title';
+ td mt '_relinfo_original';
td $r->{original};
end;
}
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'Type';
+ td mt '_relinfo_type';
td;
- my $type = $self->{release_types}[$r->{type}];
- cssicon lc(substr $type, 0, 3), $type;
- txt ' '.$type;
- txt ' patch' if $r->{patch};
+ cssicon "rt$r->{type}", mt "_rtype_$r->{type}";
+ txt ' '.mt '_relinfo_type_format', mt("_rtype_$r->{type}"), $r->{patch}?1:0;
end;
end;
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'Language';
+ td mt '_relinfo_lang';
td;
for (@{$r->{languages}}) {
- cssicon "lang $_", $self->{languages}{$_};
- txt ' '.$self->{languages}{$_};
+ cssicon "lang $_", mt "_lang_$_";
+ txt ' '.mt("_lang_$_");
br if $_ ne $r->{languages}[$#{$r->{languages}}];
}
end;
end;
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'Publication';
- td join ', ', $r->{freeware} ? 'Freeware' : 'Non-free', $r->{patch} ? () : $r->{doujin} ? 'doujin' : 'commercial';
+ td mt '_relinfo_publication';
+ td mt $r->{patch} ? '_relinfo_pub_patch' : '_relinfo_pub_nopatch', $r->{freeware}?0:1, $r->{doujin}?0:1;
end;
if(@{$r->{platforms}}) {
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'Platform'.($#{$r->{platforms}} ? 's' : '');
+ td mt '_relinfo_platform', scalar @{$r->{platforms}};
td;
for(@{$r->{platforms}}) {
- cssicon $_, $self->{platforms}{$_};
- txt ' '.$self->{platforms}{$_};
+ cssicon $_, mt "_plat_$_";
+ txt ' '.mt("_plat_$_");
br if $_ ne $r->{platforms}[$#{$r->{platforms}}];
}
end;
@@ -155,7 +153,8 @@ sub _infotable {
if(@{$r->{media}}) {
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'Medi'.($#{$r->{media}} ? 'a' : 'um');
+ td mt '_relinfo_media', scalar @{$r->{media}};
+ # TODO: TL the media
td join ', ', map {
my $med = $self->{media}{$_->{medium}};
$med->[1] ? sprintf('%d %s%s', $_->{qty}, $med->[0], $_->{qty}>1?'s':'') : $med->[0]
@@ -165,44 +164,44 @@ sub _infotable {
if($r->{resolution}) {
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'Resolution';
+ td mt '_relinfo_resolution';
td $self->{resolutions}[$r->{resolution}][0];
end;
}
if($r->{voiced}) {
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'Voiced';
- td $self->{voiced}[$r->{voiced}];
+ td mt '_relinfo_voiced';
+ td mt '_voiced_'.$r->{voiced};
end;
}
if($r->{ani_story} || $r->{ani_ero}) {
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'Animation';
+ td mt '_relinfo_ani';
td join ', ',
- $r->{ani_story} ? ('Story: ' .$self->{animated}[$r->{ani_story}]):(),
- $r->{ani_ero} ? ('Ero scenes: '.$self->{animated}[$r->{ani_ero} ]):();
+ $r->{ani_story} ? mt('_relinfo_ani_story', mt '_animated_'.$r->{ani_story}):(),
+ $r->{ani_ero} ? mt('_relinfo_ani_ero', mt '_animated_'.$r->{ani_ero} ):();
end;
}
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'Released';
+ td mt '_relinfo_released';
td;
- lit datestr $r->{released};
+ lit $self->{l10n}->datestr($r->{released});
end;
end;
if($r->{minage} >= 0) {
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'Age rating';
+ td mt '_relinfo_minage';
td $self->{age_ratings}{$r->{minage}}[0];
end;
}
if(@{$r->{producers}}) {
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'Producer'.($#{$r->{producers}} ? 's' : '');
+ td mt '_relinfo_producer', scalar @{$r->{producers}};
td;
for (@{$r->{producers}}) {
a href => "/p$_->{id}", title => $_->{original}||$_->{name}, shorten $_->{name}, 60;
@@ -221,16 +220,16 @@ sub _infotable {
if($r->{catalog}) {
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'Catalog no.';
+ td mt '_relinfo_catalog';
td $r->{catalog};
end;
}
if($r->{website}) {
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'Links';
+ td mt '_relinfo_links';
td;
- a href => $r->{website}, rel => 'nofollow', 'Official website';
+ a href => $r->{website}, rel => 'nofollow', mt '_relinfo_website';
end;
end;
}
@@ -238,19 +237,20 @@ sub _infotable {
if($self->authInfo->{id}) {
my $rl = $self->dbVNListGet(uid => $self->authInfo->{id}, rid => $r->{id})->[0];
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'User options';
+ td mt '_relinfo_user';
td;
Select id => 'listsel', name => 'listsel';
- option !$rl ? 'not in your list' : "Status: $self->{vn_rstat}[$rl->{rstat}] / $self->{vn_vstat}[$rl->{vstat}]";
- optgroup label => 'Set release status';
+ option mt !$rl ? '_relinfo_user_notlist' :
+ ('_relinfo_user_inlist', $self->{vn_rstat}[$rl->{rstat}], $self->{vn_vstat}[$rl->{vstat}]);
+ optgroup label => mt '_relinfo_user_setr';
option value => "r$_", $self->{vn_rstat}[$_]
for (0..$#{$self->{vn_rstat}});
end;
- optgroup label => 'Set play status';
+ optgroup label => mt '_relinfo_user_setv';
option value => "v$_", $self->{vn_vstat}[$_]
for (0..$#{$self->{vn_vstat}});
end;
- option value => 'del', 'remove from list' if $rl;
+ option value => 'del', mt '_relinfo_user_del' if $rl;
end;
end;
end;
@@ -296,7 +296,7 @@ sub edit {
if($self->reqMethod eq 'POST') {
$frm = $self->formValidate(
- { name => 'type', enum => [ 0..$#{$self->{release_types}} ] },
+ { name => 'type', enum => $self->{release_types} },
{ name => 'patch', required => 0, default => 0 },
{ name => 'freeware', required => 0, default => 0 },
{ name => 'doujin', required => 0, default => 0 },
@@ -305,17 +305,17 @@ sub edit {
{ name => 'gtin', required => 0, default => '0',
func => [ \&gtintype, 'Not a valid JAN/UPC/EAN code' ] },
{ name => 'catalog', required => 0, default => '', maxlength => 50 },
- { name => 'languages', multi => 1, enum => [ keys %{$self->{languages}} ] },
+ { name => 'languages', multi => 1, enum => $self->{languages} },
{ name => 'website', required => 0, default => '', template => 'url' },
{ name => 'released', required => 0, default => 0, template => 'int' },
{ name => 'minage' , required => 0, default => -1, enum => [ keys %{$self->{age_ratings}} ] },
{ name => 'notes', required => 0, default => '', maxlength => 10240 },
- { name => 'platforms', required => 0, default => '', multi => 1, enum => [ keys %{$self->{platforms}} ] },
+ { name => 'platforms', required => 0, default => '', multi => 1, enum => $self->{platforms} },
{ name => 'media', required => 0, default => '' },
{ name => 'resolution',required => 0, default => 0, enum => [ 0..$#{$self->{resolutions}} ] },
- { name => 'voiced', required => 0, default => 0, enum => [ 0..$#{$self->{voiced}} ] },
- { name => 'ani_story', required => 0, default => 0, enum => [ 0..$#{$self->{animated}} ] },
- { name => 'ani_ero', required => 0, default => 0, enum => [ 0..$#{$self->{animated}} ] },
+ { name => 'voiced', required => 0, default => 0, enum => $self->{voiced} },
+ { name => 'ani_story', required => 0, default => 0, enum => $self->{animated} },
+ { name => 'ani_ero', required => 0, default => 0, enum => $self->{animated} },
{ name => 'producers', required => 0, default => '' },
{ name => 'vn', maxlength => 5000 },
{ name => 'editsum', maxlength => 5000 },
@@ -329,7 +329,9 @@ sub edit {
$new_vn = [ map { /^([0-9]+)/ ? $1 : () } split /\|\|\|/, $frm->{vn} ];
$frm->{platforms} = [ grep $_, @{$frm->{platforms}} ];
$frm->{$_} = $frm->{$_} ? 1 : 0 for (qw|patch freeware doujin|);
- $frm->{doujin} = 0 if $frm->{patch};
+
+ # reset some fields when the patch flag is set
+ $frm->{doujin} = $frm->{resolution} = $frm->{voiced} = $frm->{ani_story} = $frm->{ani_ero} = 0 if $frm->{patch};
my $same = $rid &&
(join(',', sort @{$b4{platforms}}) eq join(',', sort @{$frm->{platforms}})) &&
@@ -367,10 +369,11 @@ sub edit {
$frm->{title} = $v->{title} if !defined $frm->{title} && !$r;
$frm->{original} = $v->{original} if !defined $frm->{original} && !$r;
- $self->htmlHeader(js => 'forms', title => $rid ? ''.($copy ? 'Copy ':'Edit ').$r->{title} : 'Add release to '.$v->{title}, noindex => 1);
+ my $title = mt $rid ? ($copy ? '_redit_title_copy' : '_redit_title_edit', $r->{title}) : ('_redit_title_add', $v->{title});
+ $self->htmlHeader(js => 'forms', title => $title, noindex => 1);
$self->htmlMainTabs('r', $r, $copy ? 'copy' : 'edit') if $rid;
$self->htmlMainTabs('v', $v, 'edit') if $vid;
- $self->htmlEditMessage('r', $r, $copy);
+ $self->htmlEditMessage('r', $r, $title, $copy);
_form($self, $r, $v, $frm, $copy);
$self->htmlFooter;
}
@@ -380,57 +383,56 @@ sub _form {
my($self, $r, $v, $frm, $copy) = @_;
$self->htmlForm({ frm => $frm, action => $r ? "/r$r->{id}/".($copy ? 'copy' : 'edit') : "/v$v->{id}/add", editsum => 1 },
- "General info" => [
- [ select => short => 'type', name => 'Type',
- options => [ map [ $_, $self->{release_types}[$_] ], 0..$#{$self->{release_types}} ] ],
- [ check => short => 'patch', name => 'This release is a patch to another release.' ],
- [ check => short => 'freeware', name => 'Freeware (i.e. available at no cost)' ],
- [ check => short => 'doujin', name => 'Doujin (self-published / not by a commercial company)' ],
- [ input => short => 'title', name => 'Title (romaji)', width => 300 ],
- [ input => short => 'original', name => 'Original title', width => 300 ],
- [ static => content => 'The original title of this release, leave blank if it already is in the Latin alphabet.' ],
- [ select => short => 'languages', name => 'Language(s)', multi => 1,
- options => [ map [ $_, "$_ ($self->{languages}{$_})" ], sort keys %{$self->{languages}} ] ],
- [ input => short => 'gtin', name => 'JAN/UPC/EAN' ],
- [ input => short => 'catalog', name => 'Catalog number' ],
- [ input => short => 'website', name => 'Official website' ],
- [ date => short => 'released', name => 'Release date' ],
- [ static => content => 'Leave month or day blank if they are unknown' ],
- [ select => short => 'minage', name => 'Age rating',
+ rel_geninfo => [ mt('_redit_form_geninfo'),
+ [ select => short => 'type', name => mt('_redit_form_type'),
+ options => [ map [ $_, mt "_rtype_$_" ], @{$self->{release_types}} ] ],
+ [ check => short => 'patch', name => mt('_redit_form_patch') ],
+ [ check => short => 'freeware', name => mt('_redit_form_freeware') ],
+ [ check => short => 'doujin', name => mt('_redit_form_doujin') ],
+ [ input => short => 'title', name => mt('_redit_form_title'), width => 300 ],
+ [ input => short => 'original', name => mt('_redit_form_original'), width => 300 ],
+ [ static => content => mt '_redit_form_original_note' ],
+ [ select => short => 'languages', name => mt('_redit_form_languages'), multi => 1,
+ options => [ map [ $_, "$_ (".mt("_lang_$_").')' ], sort @{$self->{languages}} ] ],
+ [ input => short => 'gtin', name => mt('_redit_form_gtin') ],
+ [ input => short => 'catalog', name => mt('_redit_form_catalog') ],
+ [ input => short => 'website', name => mt('_redit_form_website') ],
+ [ date => short => 'released', name => mt('_redit_form_released') ],
+ [ static => content => mt('_redit_form_released_note') ],
+ [ select => short => 'minage', name => mt('_redit_form_minage'),
options => [ map [ $_, $self->{age_ratings}{$_}[0].($self->{age_ratings}{$_}[1]?" (e.g. $self->{age_ratings}{$_}[1])":'') ],
sort { $a <=> $b } keys %{$self->{age_ratings}} ] ],
- [ textarea => short => 'notes', name => 'Notes' ],
- [ static => content => 'Miscellaneous notes/comments, information that does not fit in the above fields. '
- .'E.g.: Censored/uncensored or for which releases this patch applies. Max. 250 characters.' ],
+ [ textarea => short => 'notes', name => mt('_redit_form_notes').'<br /><b class="standout">'.mt('_inenglish').'</b>' ],
+ [ static => content => mt('_redit_form_notes_note') ],
],
- 'Format' => [
- [ select => short => 'resolution', name => 'Resolution', options => [
+ rel_format => [ mt('_redit_form_format'),
+ [ select => short => 'resolution', name => mt('_redit_form_resolution'), options => [
map [ $_, @{$self->{resolutions}[$_]} ], 0..$#{$self->{resolutions}} ] ],
- [ select => short => 'voiced', name => 'Voiced', options => [
- map [ $_, $self->{voiced}[$_] ], 0..$#{$self->{voiced}} ] ],
- [ select => short => 'ani_story', name => 'Story animation', options => [
- map [ $_, $self->{animated}[$_] ], 0..$#{$self->{animated}} ] ],
- [ select => short => 'ani_ero', name => 'Ero animation', options => [
- map [ $_, $_ ? $self->{animated}[$_] : 'Unknown / no ero scenes' ], 0..$#{$self->{animated}} ] ],
- [ static => content => 'Animation in erotic scenes, leave to unknown if there are no ero scenes.' ],
+ [ select => short => 'voiced', name => mt('_redit_form_voiced'), options => [
+ map [ $_, mt '_voiced_'.$_ ], @{$self->{voiced}} ] ],
+ [ select => short => 'ani_story', name => mt('_redit_form_ani_story'), options => [
+ map [ $_, mt '_animated_'.$_ ], @{$self->{animated}} ] ],
+ [ select => short => 'ani_ero', name => mt('_redit_form_ani_ero'), options => [
+ map [ $_, $_ ? mt '_animated_'.$_ : mt('_redit_form_ani_ero_none') ], @{$self->{animated}} ] ],
+ [ static => content => mt('_redit_form_ani_ero_note') ],
[ hidden => short => 'media' ],
[ static => nolabel => 1, content => sub {
- h2 'Platforms';
+ h2 mt '_redit_form_platforms';
div class => 'platforms';
- for my $p (sort keys %{$self->{platforms}}) {
+ for my $p (sort @{$self->{platforms}}) {
span;
input type => 'checkbox', name => 'platforms', value => $p, id => $p,
$frm->{platforms} && grep($_ eq $p, @{$frm->{platforms}}) ? (checked => 'checked') : ();
label for => $p;
- cssicon $p, $self->{platforms}{$p};
- txt ' '.$self->{platforms}{$p};
+ cssicon $p, mt "_plat_$p";
+ txt ' '.mt("_plat_$p");
end;
end;
}
end;
- h2 'Media';
+ h2 mt '_redit_form_media';
div id => 'media_div';
Select;
option value => $_, class => $self->{media}{$_}[1] ? 'qty' : 'noqty', $self->{media}{$_}[0]
@@ -440,13 +442,13 @@ sub _form {
}],
],
- 'Producers' => [
+ rel_prod => [ mt('_redit_form_prod'),
[ hidden => short => 'producers' ],
[ static => nolabel => 1, content => sub {
- h2 'Selected producers';
+ h2 mt('_redit_form_prod_sel');
div id => 'producerssel';
end;
- h2 'Add producer';
+ h2 mt('_redit_form_prod_add');
div;
input type => 'text', class => 'text';
a href => '#', 'add';
@@ -454,13 +456,13 @@ sub _form {
}],
],
- 'Visual novels' => [
+ rel_vn => [ mt('_redit_form_vn'),
[ hidden => short => 'vn' ],
[ static => nolabel => 1, content => sub {
- h2 'Selected visual novels';
+ h2 mt('_redit_form_vn_sel');
div id => 'vnsel';
end;
- h2 'Add visual novel';
+ h2 mt('_redit_form_vn_add');
div;
input type => 'text', class => 'text';
a href => '#', 'add';
@@ -479,10 +481,10 @@ sub browse {
{ name => 's', required => 0, default => 'title', enum => [qw|released minage title|] },
{ name => 'o', required => 0, default => 'a', enum => ['a', 'd'] },
{ name => 'q', required => 0, default => '', maxlength => 500 },
- { name => 'ln', required => 0, multi => 1, default => '', enum => [ keys %{$self->{languages}} ] },
- { name => 'pl', required => 0, multi => 1, default => '', enum => [ keys %{$self->{platforms}} ] },
+ { name => 'ln', required => 0, multi => 1, default => '', enum => $self->{languages} },
+ { name => 'pl', required => 0, multi => 1, default => '', enum => $self->{platforms} },
{ name => 'me', required => 0, multi => 1, default => '', enum => [ keys %{$self->{media}} ] },
- { name => 'tp', required => 0, default => -1, enum => [ -1..$#{$self->{release_types}} ] },
+ { name => 'tp', required => 0, default => -1, enum => [ -1, @{$self->{release_types}} ] },
{ name => 'pa', required => 0, default => 0, enum => [ 0..2 ] },
{ name => 'fw', required => 0, default => 0, enum => [ 0..2 ] },
{ name => 'do', required => 0, default => 0, enum => [ 0..2 ] },
@@ -521,7 +523,7 @@ sub browse {
$_&&($url .= ";re=$_") for @{$f->{re}};
$_&&($url .= ";me=$_") for @{$f->{me}};
- $self->htmlHeader(title => 'Browse releases');
+ $self->htmlHeader(title => mt('_rbrowse_title'));
_filters($self, $f, !@filters || !@$list);
$self->htmlBrowse(
class => 'relbrowse',
@@ -531,22 +533,22 @@ sub browse {
pageurl => "$url;s=$f->{s};o=$f->{o}",
sorturl => $url,
header => [
- [ 'Released', 'released' ],
- [ 'Rating', 'minage' ],
+ [ mt('_rbrowse_col_released'), 'released' ],
+ [ mt('_rbrowse_col_minage'), 'minage' ],
[ '', '' ],
- [ 'Title', 'title' ],
+ [ mt('_rbrowse_col_title'), 'title' ],
],
row => sub {
my($s, $n, $l) = @_;
Tr $n % 2 ? (class => 'odd') : ();
td class => 'tc1';
- lit datestr $l->{released};
+ lit $self->{l10n}->datestr($l->{released});
end;
td class => 'tc2', $l->{minage} > -1 ? $self->{age_ratings}{$l->{minage}}[0] : '';
td class => 'tc3';
- $_ ne 'oth' && cssicon $_, $self->{platforms}{$_} for (@{$l->{platforms}});
- cssicon "lang $_", $self->{languages}{$_} for (@{$l->{languages}});
- cssicon lc(substr($self->{release_types}[$l->{type}],0,3)), $self->{release_types}[$l->{type}];
+ $_ ne 'oth' && cssicon $_, mt "_plat_$_" for (@{$l->{platforms}});
+ cssicon "lang $_", mt "_lang_$_" for (@{$l->{languages}});
+ cssicon "rt$l->{type}", mt "_rtype_$l->{type}";
end;
td class => 'tc4';
a href => "/r$l->{id}", title => $l->{original}||$l->{title}, shorten $l->{title}, 90;
@@ -557,11 +559,9 @@ sub browse {
) if @$list;
if(@filters && !@$list) {
div class => 'mainbox';
- h1 'No results found';
+ h1 mt '_rbrowse_noresults_title';
div class => 'notice';
- p qq|Sorry, couldn't find anything that comes through your filters. You might want to disable a few filters to get more results.\n\n|
- .qq|Also, keep in mind that we don't have all information about all releases. So e.g. filtering on screen resolution will exclude |
- .qq|all releases of which we don't know it's resolution, even though it might in fact be in the resolution you're looking for.|;
+ p mt '_rbrowse_noresults_msg';
end;
end;
}
@@ -574,32 +574,31 @@ sub _filters {
form method => 'get', action => '/r', 'accept-charset' => 'UTF-8';
div class => 'mainbox';
- h1 'Browse releases';
+ h1 mt '_rbrowse_title';
$self->htmlSearchBox('r', $f->{q});
a id => 'advselect', href => '#';
- lit '<i>'.($shown?'&#9662;':'&#9656;').'</i> filters';
+ lit '<i>'.($shown?'&#9662;':'&#9656;').'</i> '.mt('_rbrowse_filters');
end;
div id => 'advoptions', !$shown ? (class => 'hidden') : ();
- h2 'Filters';
+ h2 mt '_rbrowse_filters';
table class => 'formtable', style => 'margin-left: 0';
Tr class => 'newfield';
- td class => 'label'; label for => 'ma_m', 'Age rating'; end;
+ td class => 'label'; label for => 'ma_m', mt '_rbrowse_minage'; end;
td class => 'field';
- Select id => 'ma_m', name => 'ma_m', style => 'width: 70px';
- option value => 0, $f->{ma_m} == 0 ? ('selected' => 'selected') : (), 'greater';
- option value => 1, $f->{ma_m} == 1 ? ('selected' => 'selected') : (), 'smaller';
+ Select id => 'ma_m', name => 'ma_m', style => 'width: 160px';
+ option value => 0, $f->{ma_m} == 0 ? ('selected' => 'selected') : (), mt '_rbrowse_ge';
+ option value => 1, $f->{ma_m} == 1 ? ('selected' => 'selected') : (), mt '_rbrowse_le';
end;
- txt ' than or equal to ';
Select id => 'ma_a', name => 'ma_a', style => 'width: 80px; text-align: center';
$_>=0 && option value => $_, $f->{ma_a} == $_ ? ('selected' => 'selected') : (), $self->{age_ratings}{$_}[0]
for (sort { $a <=> $b } keys %{$self->{age_ratings}});
end;
end;
td rowspan => 5, style => 'padding-left: 40px';
- label for => 're', 'Screen resolution'; br;
+ label for => 're', mt '_rbrowse_resolution'; br;
Select id => 're', name => 're', multiple => 'multiple', size => 8;
my $l='';
for my $i (1..$#{$self->{resolutions}}) {
@@ -614,47 +613,50 @@ sub _filters {
end;
end;
end;
- $self->htmlFormPart($f, [ select => short => 'tp', name => 'Release type',
- options => [ [-1, 'All'], map [ $_, $self->{release_types}[$_] ], 0..$#{$self->{release_types}} ]]);
- $self->htmlFormPart($f, [ select => short => 'pa', name => 'Patch status',
- options => [ [0, 'All'], [1, 'Only patches'], [2, 'Only standalone releases']]]);
- $self->htmlFormPart($f, [ select => short => 'fw', name => 'Freeware',
- options => [ [0, 'All'], [1, 'Freeware only'], [2, 'Only non-free releases']]]);
- $self->htmlFormPart($f, [ select => short => 'do', name => 'Doujin',
- options => [ [0, 'All'], [1, 'Only doujin releases'], [2, 'Only commercial releases']]]);
- $self->htmlFormPart($f, [ date => short => 'mi', name => 'Released after' ]);
- $self->htmlFormPart($f, [ date => short => 'ma', name => 'Released before' ]);
+ $self->htmlFormPart($f, [ select => short => 'tp', name => mt('_rbrowse_type'),
+ options => [ [-1, mt '_rbrowse_all'], map [ $_, mt "_rtype_$_" ], @{$self->{release_types}} ]]);
+ $self->htmlFormPart($f, [ select => short => 'pa', name => mt('_rbrowse_patch'),
+ options => [ [0, mt '_rbrowse_all' ], [1, mt '_rbrowse_patchonly'], [2, mt '_rbrowse_patchnone']]]);
+ $self->htmlFormPart($f, [ select => short => 'fw', name => mt('_rbrowse_freeware'),
+ options => [ [0, mt '_rbrowse_all' ], [1, mt '_rbrowse_freewareonly'], [2, mt '_rbrowse_freewarenone']]]);
+ $self->htmlFormPart($f, [ select => short => 'do', name => mt('_rbrowse_doujin'),
+ options => [ [0, mt '_rbrowse_all' ], [1, mt '_rbrowse_doujinonly'], [2, mt '_rbrowse_doujinnone']]]);
+ $self->htmlFormPart($f, [ date => short => 'mi', name => mt '_rbrowse_dateafter' ]);
+ $self->htmlFormPart($f, [ date => short => 'ma', name => mt '_rbrowse_datebefore' ]);
end;
h2;
- lit 'Languages <b>(boolean or, selecting more gives more results)</b>';
+ txt mt '_rbrowse_languages';
+ b ' ('.mt('_rbrowse_boolor').')';
end;
for my $i (sort @{$self->dbLanguages}) {
span;
input type => 'checkbox', name => 'ln', value => $i, id => "lang_$i", grep($_ eq $i, @{$f->{ln}}) ? (checked => 'checked') : ();
label for => "lang_$i";
- cssicon "lang $i", $self->{languages}{$i};
- txt $self->{languages}{$i};
+ cssicon "lang $i", mt "_lang_$i";
+ txt mt "_lang_$i";
end;
end;
}
h2;
- lit 'Platforms <b>(boolean or, selecting more gives more results)</b>';
+ txt mt '_rbrowse_platforms';
+ b ' ('.mt('_rbrowse_boolor').')';
end;
- for my $i (sort keys %{$self->{platforms}}) {
+ for my $i (sort @{$self->{platforms}}) {
next if $i eq 'oth';
span;
input type => 'checkbox', name => 'pl', value => $i, id => "plat_$i", grep($_ eq $i, @{$f->{pl}}) ? (checked => 'checked') : ();
label for => "plat_$i";
- cssicon $i, $self->{platforms}{$i};
- txt $self->{platforms}{$i};
+ cssicon $i, mt "_plat_$i";
+ txt mt "_plat_$i";
end;
end;
}
h2;
- lit 'Media <b>(boolean or, selecting more gives more results)</b>';
+ txt mt '_rbrowse_media';
+ b ' ('.mt('_rbrowse_boolor').')';
end;
for my $i (sort keys %{$self->{media}}) {
next if $i eq 'otc';
@@ -665,8 +667,8 @@ sub _filters {
}
div style => 'text-align: center; clear: left;';
- input type => 'submit', value => 'Apply', class => 'submit';
- input type => 'reset', value => 'Clear', class => 'submit', onclick => 'location.href="/r"';
+ input type => 'submit', value => mt('_rbrowse_apply'), class => 'submit';
+ input type => 'reset', value => mt('_rbrowse_clear'), class => 'submit', onclick => 'location.href="/r"';
end;
end;
end;
diff --git a/lib/VNDB/Handler/Tags.pm b/lib/VNDB/Handler/Tags.pm
index 8f0e1486..ae240d38 100644
--- a/lib/VNDB/Handler/Tags.pm
+++ b/lib/VNDB/Handler/Tags.pm
@@ -46,32 +46,31 @@ sub tagpage {
maxspoil => $f->{m},
);
- my $title = ($t->{meta} ? 'Meta tag: ' : 'Tag: ').$t->{name};
+ my $title = mt '_tagp_title', $t->{meta}?0:1, $t->{name};
$self->htmlHeader(title => $title, noindex => $t->{state} != 2);
$self->htmlMainTabs('g', $t);
if($t->{state} != 2) {
div class => 'mainbox';
- h1 "Tag: $t->{name}";
+ h1 $title;
if($t->{state} == 1) {
div class => 'warning';
- h2 'Tag deleted';
+ h2 mt '_tagp_del_title';
p;
- lit qq|This tag has been removed from the database, and cannot be used or re-added.|.
- qq| File a request on the <a href="/t/db">discussion board</a> if you disagree with this.|;
+ lit mt '_tagp_del_msg';
end;
end;
} else {
div class => 'notice';
- h2 'Waiting for approval';
- p 'This tag is waiting for a moderator to approve it. You can still use it to tag VNs as you would with a normal tag.';
+ h2 mt '_tagp_pending_title';
+ p mt '_tagp_pending_msg';
end;
}
end;
}
div class => 'mainbox';
- a class => 'addnew', href => "/g$tag/add", ($self->authCan('tagmod')?'Create':'Request').' child tag' if $self->authCan('tag');
+ a class => 'addnew', href => "/g$tag/add", mt '_tagp_addchild' if $self->authCan('tag') && $t->{state} != 1;
h1 $title;
p;
@@ -84,7 +83,7 @@ sub tagpage {
if($_ < $#p && $p[$_+1]{lvl} < $p[$_]{lvl}) {
push @r, $p[$_];
} elsif($#p == $_ || $p[$_+1]{lvl} >= $p[$_]{lvl}) {
- a href => '/g', 'Tags';
+ a href => '/g', mt '_tagp_indexlink';
for ($p[$_], reverse @r) {
txt ' > ';
a href => "/g$_->{tag}", $_->{name};
@@ -93,7 +92,7 @@ sub tagpage {
}
}
if(!@p) {
- a href => '/g', 'Tags';
+ a href => '/g', mt '_tagp_indexlink';
txt " > $t->{name}\n";
}
end;
@@ -105,7 +104,7 @@ sub tagpage {
}
if(@{$t->{aliases}}) {
p class => 'center';
- b "Aliases:\n";
+ b mt('_tagp_aliases')."\n";
txt "$_\n" for (@{$t->{aliases}});
end;
}
@@ -133,11 +132,7 @@ sub _childtags {
}
div class => 'mainbox';
- if(!$index) {
- h1 'Child tags';
- } else {
- h1 'Tag tree';
- }
+ h1 mt $index ? '_tagp_tree' : '_tagp_childs';
ul class => 'tagtree';
for my $p (sort { @{$b->{childs}} <=> @{$a->{childs}} } @tags) {
li;
@@ -156,7 +151,7 @@ sub _childtags {
if(@{$p->{childs}} > 6) {
li;
txt '> ';
- a href => "/g$p->{tag}", style => 'font-style: italic', sprintf '%d more tags...', @{$p->{childs}}-5;
+ a href => "/g$p->{tag}", style => 'font-style: italic', mt '_tagp_moretags', @{$p->{childs}}-5;
end;
}
end;
@@ -171,16 +166,16 @@ sub _childtags {
sub _vnlist {
my($self, $t, $f, $list, $np) = @_;
div class => 'mainbox';
- h1 'Visual novels';
+ h1 mt '_tagp_vnlist';
p class => 'browseopts';
- a href => "/g$t->{id}?m=0", $f->{m} == 0 ? (class => 'optselected') : (), onclick => "setCookie('tagspoil', 0);return true;", 'Hide spoilers';
- a href => "/g$t->{id}?m=1", $f->{m} == 1 ? (class => 'optselected') : (), onclick => "setCookie('tagspoil', 1);return true;", 'Show minor spoilers';
- a href => "/g$t->{id}?m=2", $f->{m} == 2 ? (class => 'optselected') : (), onclick => "setCookie('tagspoil', 2);return true;", 'Show major spoilers';
+ a href => "/g$t->{id}?m=0", $f->{m} == 0 ? (class => 'optselected') : (), onclick => "setCookie('tagspoil', 0);return true;", mt '_tagp_spoil0';
+ a href => "/g$t->{id}?m=1", $f->{m} == 1 ? (class => 'optselected') : (), onclick => "setCookie('tagspoil', 1);return true;", mt '_tagp_spoil1';
+ a href => "/g$t->{id}?m=2", $f->{m} == 2 ? (class => 'optselected') : (), onclick => "setCookie('tagspoil', 2);return true;", mt '_tagp_spoil2';
end;
if(!@$list) {
- p "\n\nThis tag has not been linked to any visual novels yet, or they were hidden because of the spoiler settings.";
+ p "\n\n".mt '_tagp_novn';
}
- p "\nNOTE: This list is cached, it can take up to 24 hours after a visual novel has been tagged for it to show up on this page.";
+ p "\n".mt '_tagp_cached';
end;
return if !@$list;
$self->htmlBrowse(
@@ -191,12 +186,12 @@ sub _vnlist {
pageurl => "/g$t->{id}?m=$f->{m};o=$f->{o};s=$f->{s}",
sorturl => "/g$t->{id}?m=$f->{m}",
header => [
- [ 'Score', 'score' ],
- [ 'Title', 'title' ],
- [ '', 0 ],
- [ '', 0 ],
- [ 'Released', 'rel' ],
- [ 'Popularity', 'pop' ],
+ [ mt('_tagp_vncol_score'), 'score' ],
+ [ mt('_tagp_vncol_title'), 'title' ],
+ [ '', 0 ],
+ [ '', 0 ],
+ [ mt('_tagp_vncol_rel'), 'rel' ],
+ [ mt('_tagp_vncol_pop'), 'pop' ],
],
row => sub {
my($s, $n, $l) = @_;
@@ -209,15 +204,15 @@ sub _vnlist {
a href => '/v'.$l->{vid}, title => $l->{original}||$l->{title}, shorten $l->{title}, 100;
end;
td class => 'tc3';
- $_ ne 'oth' && cssicon $_, $self->{platforms}{$_}
+ $_ ne 'oth' && cssicon $_, mt "_plat_$_"
for (sort split /\//, $l->{c_platforms});
end;
td class => 'tc4';
- cssicon "lang $_", $self->{languages}{$_}
+ cssicon "lang $_", mt "_lang_$_"
for (reverse sort split /\//, $l->{c_languages});
end;
td class => 'tc5';
- lit monthstr $l->{c_released};
+ lit $self->{l10n}->datestr($l->{c_released});
end;
td class => 'tc6', sprintf '%.2f', $l->{c_popularity}*100;
end;
@@ -264,7 +259,7 @@ sub tagedit {
}
for(@parents, @merge) {
my $c = $self->dbTagGet(name => $_, noid => $tag);
- push @{$frm->{_err}}, [ 'parents', 'func', [ 0, "Tag '$_' not found." ]] if !@$c;
+ push @{$frm->{_err}}, [ 'parents', 'func', [ 0, mt '_tagedit_err_notfound', $_ ]] if !@$c;
$_ = $c->[0]{id};
}
}
@@ -295,50 +290,42 @@ sub tagedit {
$frm->{parents} ||= join ', ', map $_->{name}, @{$t->{parents}};
}
- my $title = $par ? "Add child tag to $par->{name}" : $tag ? "Edit tag: $t->{name}" : 'Add new tag';
+ my $title = $par ? mt('_tagedit_title_add', $par->{name}) : $tag ? mt('_tagedit_title_edit', $t->{name}) : mt '_tagedit_title_new';
$self->htmlHeader(title => $title, noindex => 1);
$self->htmlMainTabs('g', $par || $t, 'edit') if $t || $par;
if(!$self->authCan('tagmod')) {
div class => 'mainbox';
- h1 'Requesting new tag';
+ h1 mt '_tagedit_req_title';
div class => 'notice';
- h2 'Your tag must be approved';
+ h2 mt '_tagedit_req_subtitle';
p;
- txt 'Because all tags have to be approved by moderators, it can take a while before it '.
- 'will show up in the tag list or on visual novel pages. You can still vote on tag even if '.
- 'it has not been approved yet, though.'.
- "\n\n";
- lit 'Also, make sure you\'ve read the <a href="/d10">guidelines</a>, so you can predict whether '.
- 'your tag will be accepted or not.';
+ lit mt '_tagedit_req_msg';
end;
end;
end;
}
- $self->htmlForm({ frm => $frm, action => $par ? "/g$par->{id}/add" : $tag ? "/g$tag/edit" : '/g/new' }, $title => [
- [ input => short => 'name', name => 'Primary name' ],
+ $self->htmlForm({ frm => $frm, action => $par ? "/g$par->{id}/add" : $tag ? "/g$tag/edit" : '/g/new' }, 'tagedit' => [ $title,
+ [ input => short => 'name', name => mt '_tagedit_frm_name' ],
$self->authCan('tagmod') ? (
$tag ?
- [ static => label => 'Added by', content => sub { a href => "/u$t->{addedby}", $t->{username}; } ] : (),
- [ select => short => 'state', name => 'State', options => [
- [ 0, 'Awaiting moderation' ], [ 1, 'Deleted/hidden' ], [ 2, 'Approved' ] ] ],
- [ checkbox => short => 'meta', name => 'This is a meta-tag (only to be used as parent for other tags, not for linking to VN entries)' ],
+ [ static => label => mt('_tagedit_frm_by'), content => $self->{l10n}->userstr($t->{addedby}, $t->{username}) ] : (),
+ [ select => short => 'state', name => mt('_tagedit_frm_state'), options => [
+ map [$_, mt '_tagedit_frm_state'.$_], 0..2 ] ],
+ [ checkbox => short => 'meta', name => mt '_tagedit_frm_meta' ],
$tag ?
- [ static => content => 'WARNING: Checking this option or selecting "Deleted" as state will permanently delete all existing VN relations!' ] : (),
+ [ static => content => mt '_tagedit_frm_meta_warn' ] : (),
) : (),
- [ textarea => short => 'alias', name => "Aliases\n(separated by newlines)", cols => 30, rows => 4 ],
- [ textarea => short => 'description', name => 'Description' ],
- [ static => content => 'What should the tag be used for? Having a good description helps users choose which tags to link to a VN.' ],
- [ input => short => 'parents', name => 'Parent tags' ],
- [ static => content => "Comma separated list of tag names to be used as parent for this tag." ],
+ [ textarea => short => 'alias', name => mt('_tagedit_frm_alias'), cols => 30, rows => 4 ],
+ [ textarea => short => 'description', name => mt '_tagedit_frm_desc' ],
+ [ static => content => mt '_tagedit_frm_desc_msg' ],
+ [ input => short => 'parents', name => mt '_tagedit_frm_parents' ],
+ [ static => content => mt '_tagedit_frm_parents_msg' ],
$self->authCan('tagmod') ? (
- [ part => title => 'Merge tags' ],
- [ input => short => 'merge', name => 'Tags to merge' ],
- [ static => content => 'Comma separated list of tag names to merge into this one.'
- .' All votes and aliases/names will be moved over to this tag, and the old tags will be deleted.'
- .' Just leave this field empty if you don\'t intend to do a merge.'
- .'<br />WARNING: this action cannot be undone!' ],
+ [ part => title => mt '_tagedit_frm_merge' ],
+ [ input => short => 'merge', name => mt '_tagedit_frm_merge_tags' ],
+ [ static => content => mt '_tagedit_frm_merge_msg' ],
) : (),
]);
$self->htmlFooter;
@@ -365,22 +352,21 @@ sub taglist {
search => $f->{q}
);
- my $title = $f->{t} == -1 ? 'Browse tags' : $f->{t} == 0 ? 'Tags awaiting moderation' : $f->{t} == 1 ? 'Deleted tags' : 'All visible tags';
- $self->htmlHeader(title => $title);
+ $self->htmlHeader(title => mt '_tagb_title');
div class => 'mainbox';
- h1 $title;
+ h1 mt '_tagb_title';
form action => '/g/list', 'accept-charset' => 'UTF-8', method => 'get';
input type => 'hidden', name => 't', value => $f->{t};
$self->htmlSearchBox('g', $f->{q});
end;
p class => 'browseopts';
- a href => "/g/list?q=$f->{q};t=-1", $f->{t} == -1 ? (class => 'optselected') : (), 'All';
- a href => "/g/list?q=$f->{q};t=0", $f->{t} == 0 ? (class => 'optselected') : (), 'Awaiting moderation';
- a href => "/g/list?q=$f->{q};t=1", $f->{t} == 1 ? (class => 'optselected') : (), 'Deleted';
- a href => "/g/list?q=$f->{q};t=2", $f->{t} == 2 ? (class => 'optselected') : (), 'Accepted';
+ a href => "/g/list?q=$f->{q};t=-1", $f->{t} == -1 ? (class => 'optselected') : (), mt '_tagb_state-1';
+ a href => "/g/list?q=$f->{q};t=0", $f->{t} == 0 ? (class => 'optselected') : (), mt '_tagb_state0';
+ a href => "/g/list?q=$f->{q};t=1", $f->{t} == 1 ? (class => 'optselected') : (), mt '_tagb_state1';
+ a href => "/g/list?q=$f->{q};t=2", $f->{t} == 2 ? (class => 'optselected') : (), mt '_tagb_state2';
end;
if(!@$t) {
- p 'No results found';
+ p mt '_tagb_noresults';
}
end;
if(@$t) {
@@ -392,18 +378,18 @@ sub taglist {
pageurl => "/g/list?t=$f->{t};q=$f->{q};s=$f->{s};o=$f->{o}",
sorturl => "/g/list?t=$f->{t};q=$f->{q}",
header => [
- [ 'Created', 'added' ],
- [ 'Tag', 'name' ],
+ [ mt('_tagb_col_added'), 'added' ],
+ [ mt('_tagb_col_name'), 'name' ],
],
row => sub {
my($s, $n, $l) = @_;
Tr $n % 2 ? (class => 'odd') : ();
- td class => 'tc1', age $l->{added};
+ td class => 'tc1', $self->{l10n}->age($l->{added});
td class => 'tc3';
a href => "/g$l->{id}", $l->{name};
if($f->{t} == -1) {
- b class => 'grayedout', ' awaiting moderation' if $l->{state} == 0;
- b class => 'grayedout', ' deleted' if $l->{state} == 1;
+ b class => 'grayedout', ' '.mt '_tagb_note_awaiting' if $l->{state} == 0;
+ b class => 'grayedout', ' '.mt '_tagb_note_del' if $l->{state} == 1;
}
end;
end;
@@ -435,44 +421,43 @@ sub vntagmod {
my $frm;
- $self->htmlHeader(title => "Add/remove tags for $v->{title}", noindex => 1, js => 'forms');
+ my $title = mt '_tagv_title', $v->{title};
+ $self->htmlHeader(title => $title, noindex => 1, js => 'forms');
$self->htmlMainTabs('v', $v, 'tagmod');
div class => 'mainbox';
- h1 "Add/remove tags for $v->{title}";
+ h1 $title;
div class => 'notice';
- h2 'Tagging';
+ h2 mt '_tagv_msg_title';
ul;
- li;
- lit 'Make sure you have read the <a href="/d10">guidelines</a>!';
- end;
- li "Don't forget to hit the submit button on the bottom of the page to make your changes permanent.";
- li 'Some tag information on the site is cached, it can take up to an hour for your changes to be visible everywhere.';
+ li; lit mt '_tagv_msg_guidelines'; end;
+ li mt '_tagv_msg_submit';
+ li mt '_tagv_msg_cache';
end;
end;
end;
- $self->htmlForm({ frm => $frm, action => "/v$vid/tagmod", hitsubmit => 1 }, 'Tags' => [
+ $self->htmlForm({ frm => $frm, action => "/v$vid/tagmod", nosubmit => 1 }, tagmod => [ mt('_tagv_frm_title'),
[ hidden => short => 'taglinks', value => '' ],
[ static => nolabel => 1, content => sub {
table id => 'tagtable';
thead;
Tr;
td '';
- td colspan => 2, class => 'tc2_1', 'You';
- td colspan => 2, class => 'tc3_1', 'Others';
+ td colspan => 2, class => 'tc2_1', mt '_tagv_col_you';
+ td colspan => 2, class => 'tc3_1', mt '_tagv_col_others';
end;
Tr;
my $i=0;
- td class => 'tc'.++$i, $_ for(qw|Tag Rating Spoiler Rating Spoiler|);
+ td class => 'tc'.++$i, mt '_tagv_col_'.$_ for(qw|tag rating spoiler rating spoiler|);
end;
end;
tfoot; Tr;
td colspan => 5;
+ input type => 'submit', class => 'submit', value => mt('_tagv_save'), style => 'float: right';
input type => 'text', class => 'text', name => 'addtag', value => '';
- input type => 'button', class => 'submit', value => 'Add tag';
+ input type => 'button', class => 'submit', value => mt '_tagv_add';
br;
p;
- lit 'Check the <a href="/g">tag list</a> to browse all available tags.'.
- '<br />Can\'t find what you\'re looking for? <a href="/g/new">Request a new tag</a>.';
+ lit mt '_tagv_addmsg';
end;
end;
end; end;
@@ -521,14 +506,15 @@ sub usertags {
what => 'vns',
);
- $self->htmlHeader(title => "Tags by $u->{username}", noindex => 1);
+ my $title = mt '_tagu_title', $u->{username};
+ $self->htmlHeader(title => $title, noindex => 1);
$self->htmlMainTabs('u', $u, 'tags');
div class => 'mainbox';
- h1 "Tags by $u->{username}";
+ h1 $title;
if(@$list) {
- p 'Warning: spoilery tags are not hidden in this list!';
+ p mt '_tagu_spoilerwarn';
} else {
- p "$u->{username} doesn't seem to have used the tagging system yet...";
+ p mt '_tagu_notags', $u->{username};
}
end;
@@ -544,13 +530,13 @@ sub usertags {
sub {
td class => 'tc1';
b id => 'relhidall';
- lit '<i>&#9656;</i> #VNs ';
+ lit '<i>&#9656;</i> '.mt('_tagu_col_num').' ';
end;
lit $f->{s} eq 'cnt' && $f->{o} eq 'a' ? "\x{25B4}" : qq|<a href="/u$u->{id}/tags?o=a;s=cnt">\x{25B4}</a>|;
lit $f->{s} eq 'cnt' && $f->{o} eq 'd' ? "\x{25BE}" : qq|<a href="/u$u->{id}/tags?o=d;s=cnt">\x{25BE}</a>|;
end;
},
- [ 'Tag', 'name' ],
+ [ mt('_tagu_col_name'), 'name' ],
[ ' ', '' ],
],
row => sub {
@@ -571,7 +557,7 @@ sub usertags {
td class => 'tc1_2';
a href => "/v$_->{vid}", title => $_->{original}||$_->{title}, shorten $_->{title}, 50;
end;
- td class => 'tc1_3', !defined $_->{spoiler} ? ' ' : ['No spoiler', 'Minor spoiler', 'Major spoiler']->[$_->{spoiler}];
+ td class => 'tc1_3', !defined $_->{spoiler} ? ' ' : mt "_tagu_spoil$_->{spoiler}";
end;
}
},
@@ -584,10 +570,10 @@ sub usertags {
sub tagindex {
my $self = shift;
- $self->htmlHeader(title => 'Browse tags');
+ $self->htmlHeader(title => mt '_tagidx_title');
div class => 'mainbox';
- a class => 'addnew', href => "/g/new", ($self->authCan('tagmod')?'Create':'Request').' new tag' if $self->authCan('tag');
- h1 'Search tags';
+ a class => 'addnew', href => "/g/new", mt '_tagidx_create' if $self->authCan('tag');
+ h1 mt '_tagidx_search';
form action => '/g/list', 'accept-charset' => 'UTF-8', method => 'get';
$self->htmlSearchBox('g', '');
end;
@@ -596,58 +582,63 @@ sub tagindex {
my $t = $self->dbTagTree(0, 2, 1);
_childtags($self, {childs => $t}, 1);
- # Recently added
- div class => 'mainbox threelayout';
- a class => 'right', href => '/g/list', 'Browse all tags';
- my $r = $self->dbTagGet(order => 'added DESC', results => 10, state => 2);
- h1 'Recently added';
- ul;
- for (@$r) {
- li;
- txt age $_->{added};
- txt ' ';
- a href => "/g$_->{id}", $_->{name};
- end;
- }
- end;
- end;
+ table class => 'mainbox threelayout';
+ Tr;
+
+ # Recently added
+ td;
+ a class => 'right', href => '/g/list', mt '_tagidx_browseall';
+ my $r = $self->dbTagGet(order => 'added DESC', results => 10, state => 2);
+ h1 mt '_tagidx_recent';
+ ul;
+ for (@$r) {
+ li;
+ txt $self->{l10n}->age($_->{added});
+ txt ' ';
+ a href => "/g$_->{id}", $_->{name};
+ end;
+ }
+ end;
+ end;
- # Popular
- div class => 'mainbox threelayout';
- $r = $self->dbTagGet(order => 'c_vns DESC', meta => 0, results => 10);
- h1 'Popular tags';
- ul;
- for (@$r) {
- li;
- a href => "/g$_->{id}", $_->{name};
- txt " ($_->{c_vns})";
- end;
- }
- end;
- end;
+ # Popular
+ td;
+ $r = $self->dbTagGet(order => 'c_vns DESC', meta => 0, results => 10);
+ h1 mt '_tagidx_popular';
+ ul;
+ for (@$r) {
+ li;
+ a href => "/g$_->{id}", $_->{name};
+ txt " ($_->{c_vns})";
+ end;
+ }
+ end;
+ end;
- # Moderation queue
- div class => 'mainbox threelayout last';
- h1 'Awaiting moderation';
- $r = $self->dbTagGet(state => 0, order => 'added DESC', results => 10);
- ul;
- li "Moderation queue empty! yay!" if !@$r;
- for (@$r) {
+ # Moderation queue
+ td;
+ h1 mt '_tagidx_queue';
+ $r = $self->dbTagGet(state => 0, order => 'added DESC', results => 10);
+ ul;
+ li mt '_tagidx_queue_empty' if !@$r;
+ for (@$r) {
+ li;
+ txt $self->{l10n}->age($_->{added});
+ txt ' ';
+ a href => "/g$_->{id}", $_->{name};
+ end;
+ }
li;
- txt age $_->{added};
- txt ' ';
- a href => "/g$_->{id}", $_->{name};
+ txt "\n";
+ a href => '/g/list?t=0;o=d;s=added', mt '_tagidx_queue_link';
+ txt ' - ';
+ a href => '/g/list?t=1;o=d;s=added', mt '_tagidx_denied';
end;
- }
- li;
- txt "\n";
- a href => '/g/list?t=0;o=d;s=added', 'Moderation queue';
- txt ' - ';
- a href => '/g/list?t=1;o=d;s=added', 'Denied tags';
+ end;
end;
- end;
- end;
- clearfloat;
+
+ end; # /tr
+ end; # /table
$self->htmlFooter;
}
diff --git a/lib/VNDB/Handler/ULists.pm b/lib/VNDB/Handler/ULists.pm
index 05b1f60f..7d1a9304 100644
--- a/lib/VNDB/Handler/ULists.pm
+++ b/lib/VNDB/Handler/ULists.pm
@@ -42,7 +42,7 @@ sub vnwish {
return $self->htmlDenied() if !$uid;
my $f = $self->formValidate(
- { name => 's', enum => [ -1..$#{$self->{wishlist_status}} ] }
+ { name => 's', enum => [ -1, @{$self->{wishlist_status}} ] }
);
return 404 if $f->{_err};
@@ -99,20 +99,20 @@ sub wishlist {
my $own = $self->authInfo->{id} && $self->authInfo->{id} == $uid;
my $u = $self->dbUserGet(uid => $uid)->[0];
- return 404 if !$u || !$own && !$u->{show_list};
+ return 404 if !$u || !$own && !($u->{show_list} || $self->authCan('usermod'));
my $f = $self->formValidate(
{ name => 'p', required => 0, default => 1, template => 'int' },
{ name => 'o', required => 0, default => 'd', enum => [ 'a', 'd' ] },
{ name => 's', required => 0, default => 'wstat', enum => [qw|title added wstat|] },
- { name => 'f', required => 0, default => -1, enum => [ -1..$#{$self->{wishlist_status}} ] },
+ { name => 'f', required => 0, default => -1, enum => [ -1, @{$self->{wishlist_status}} ] },
);
return 404 if $f->{_err};
if($own && $self->reqMethod eq 'POST') {
my $frm = $self->formValidate(
{ name => 'sel', required => 0, default => 0, multi => 1, template => 'int' },
- { name => 'batchedit', required => 1, enum => [ -1..$#{$self->{wishlist_status}} ] },
+ { name => 'batchedit', required => 1, enum => [ -1, @{$self->{wishlist_status}} ] },
);
if(!$frm->{_err} && @{$frm->{sel}} && $frm->{sel}[0]) {
$self->dbWishListDel($uid, $frm->{sel}) if $frm->{batchedit} == -1;
@@ -129,20 +129,20 @@ sub wishlist {
page => $f->{p},
);
- my $title = $own ? 'My wishlist' : "\u$u->{username}'s wishlist";
+ my $title = $own ? mt('_wishlist_title_my') : mt('_wishlist_title_other', $u->{username});
$self->htmlHeader(title => $title, noindex => 1);
$self->htmlMainTabs('u', $u, 'wish');
div class => 'mainbox';
h1 $title;
if(!@$list && $f->{f} == -1) {
- p 'Wishlist empty...';
+ p mt '_wishlist_noresults';
end;
return $self->htmlFooter;
}
p class => 'browseopts';
a $f->{f} == $_ ? (class => 'optselected') : (), href => "/u$uid/wish?f=$_",
- $_ == -1 ? 'All priorities' : ucfirst $self->{wishlist_status}[$_]
- for (-1..$#{$self->{wishlist_status}});
+ $_ == -1 ? mt '_wishlist_prio_all' : mt "_wish_$_"
+ for (-1, @{$self->{wishlist_status}});
end;
end;
@@ -157,9 +157,9 @@ sub wishlist {
pageurl => "/u$uid/wish?f=$f->{f};o=$f->{o};s=$f->{s}",
sorturl => "/u$uid/wish?f=$f->{f}",
header => [
- [ Title => 'title' ],
- [ Priority => 'wstat' ],
- [ Added => 'added' ],
+ [ mt('_wishlist_col_title') => 'title' ],
+ [ mt('_wishlist_col_prio') => 'wstat' ],
+ [ mt('_wishlist_col_added') => 'added' ],
],
row => sub {
my($s, $n, $i) = @_;
@@ -169,20 +169,20 @@ sub wishlist {
if $own;
a href => "/v$i->{vid}", title => $i->{original}||$i->{title}, ' '.shorten $i->{title}, 70;
end;
- td class => 'tc2', ucfirst $self->{wishlist_status}[$i->{wstat}];
- td class => 'tc3', date $i->{added}, 'compact';
+ td class => 'tc2', mt "_wish_$i->{wstat}";
+ td class => 'tc3', $self->{l10n}->date($i->{added}, 'compact');
end;
},
$own ? (footer => sub {
Tr;
td colspan => 3;
Select name => 'batchedit', id => 'batchedit';
- option '-- with selected --';
- optgroup label => 'Change priority';
- option value => $_, $self->{wishlist_status}[$_]
- for (0..$#{$self->{wishlist_status}});
+ option mt '_wishlist_select';
+ optgroup label => mt '_wishlist_changeprio';
+ option value => $_, mt "_wish_$_"
+ for (@{$self->{wishlist_status}});
end;
- option value => -1, 'remove from wishlist';
+ option value => -1, mt '_wishlist_remove';
end;
end;
end;
@@ -198,7 +198,7 @@ sub vnlist {
my $own = $self->authInfo->{id} && $self->authInfo->{id} == $uid;
my $u = $self->dbUserGet(uid => $uid)->[0];
- return 404 if !$u || !$own && !$u->{show_list};
+ return 404 if !$u || !$own && !($u->{show_list} || $self->authCan('usermod'));
my $f = $self->formValidate(
{ name => 'p', required => 0, default => 1, template => 'int' },
@@ -234,7 +234,7 @@ sub vnlist {
$f->{c} ne 'all' ? (char => $f->{c}) : (),
);
- my $title = $own ? 'My visual novel list' : "\u$u->{username}'s visual novel list";
+ my $title = $own ? mt '_rlist_title_my' : mt '_rlist_title_other', $u->{username};
$self->htmlHeader(title => $title, noindex => 1);
$self->htmlMainTabs('u', $u, 'list');
@@ -260,9 +260,9 @@ sub vnlist {
}
end;
p class => 'browseopts';
- a href => $url->(v => 0), 0 == $f->{v} ? (class => 'optselected') : (), 'All';
- a href => $url->(v => 1), 1 == $f->{v} ? (class => 'optselected') : (), 'Only voted';
- a href => $url->(v => -1), -1 == $f->{v} ? (class => 'optselected') : (), 'Hide voted';
+ a href => $url->(v => 0), 0 == $f->{v} ? (class => 'optselected') : (), mt '_rlist_voted_all';
+ a href => $url->(v => 1), 1 == $f->{v} ? (class => 'optselected') : (), mt '_rlist_voted_only';
+ a href => $url->(v => -1), -1 == $f->{v} ? (class => 'optselected') : (), mt '_rlist_voted_none';
end;
end;
@@ -284,12 +284,11 @@ sub _vnlist_browse {
sorturl => $url->(),
pageurl => $url->('page'),
header => [
- [ Title => 'title', 3 ],
- sub { td class => 'tc2', id => 'relhidall'; lit '<i>&#9656;</i>Releases*'; end; },
- [ Vote => 'vote' ],
+ [ mt('_rlist_col_title') => 'title', 3 ],
+ sub { td class => 'tc2', id => 'relhidall'; lit '<i>&#9656;</i>'.mt('_rlist_col_releases').'*'; end; },
+ [ mt('_rlist_col_vote') => 'vote' ],
],
row => sub {
-
my($s, $n, $i) = @_;
Tr $n % 2 == 0 ? (class => 'odd') : ();
td class => 'tc1', colspan => 3;
@@ -312,11 +311,11 @@ sub _vnlist_browse {
td class => 'tc1'.($own ? ' own' : '');
input type => 'checkbox', name => 'sel', value => $_->{rid}
if $own;
- lit datestr $_->{released};
+ lit $self->{l10n}->datestr($_->{released});
end;
td class => 'tc2';
- cssicon "lang $_", $self->{languages}{$_} for @{$_->{languages}};
- cssicon substr(lc $self->{release_types}[$_->{type}], 0, 3), $self->{release_types}[$_->{type}].' release';
+ cssicon "lang $_", mt "_lang_$_" for @{$_->{languages}};
+ cssicon "rt$_->{type}", mt "_rtype_$_->{type}";
end;
td class => 'tc3';
a href => "/r$_->{rid}", title => $_->{original}||$_->{title}, shorten $_->{title}, 50;
@@ -332,19 +331,19 @@ sub _vnlist_browse {
Tr;
td class => 'tc1', colspan => 3;
Select id => 'batchedit', name => 'batchedit';
- option '- with selected -';
- optgroup label => 'Change release status';
+ option mt '_rlist_selection';
+ optgroup label => mt '_rlist_changerel';
option value => "r$_", $self->{vn_rstat}[$_]
for (0..$#{$self->{vn_rstat}});
end;
- optgroup label => 'Change play status';
+ optgroup label => mt '_rlist_changeplay';
option value => "v$_", $self->{vn_vstat}[$_]
for (0..$#{$self->{vn_vstat}});
end;
- option value => 'del', 'remove from list';
+ option value => 'del', mt '_rlist_del';
end;
end;
- td class => 'tc2', colspan => 2, '* Obtained/finished/total';
+ td class => 'tc2', colspan => 2, mt '_rlist_releasenote';
end;
}) : (),
);
diff --git a/lib/VNDB/Handler/Users.pm b/lib/VNDB/Handler/Users.pm
index 2e8ac8ee..8575771e 100644
--- a/lib/VNDB/Handler/Users.pm
+++ b/lib/VNDB/Handler/Users.pm
@@ -29,20 +29,17 @@ sub userpage {
my $votes = $u->{c_votes} && $self->dbVoteStats(uid => $uid);
- $self->htmlHeader(title => ucfirst($u->{username})."'s profile");
+ my $title = mt '_userpage_title', $u->{username};
+ $self->htmlHeader(title => $title);
$self->htmlMainTabs('u', $u);
div class => 'mainbox userpage';
- h1 ucfirst($u->{username})."'s profile";
+ h1 $title;
table;
- Tr;
- td class => 'key', ' ';
- td ' ';
- end;
my $i = 0;
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'Username';
+ td class => 'key', mt '_userpage_username';
td;
txt ucfirst($u->{username}).' (';
a href => "/u$uid", "u$uid";
@@ -51,12 +48,12 @@ sub userpage {
end;
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'Registered';
- td date $u->{registered};
+ td mt '_userpage_registered';
+ td $self->{l10n}->date($u->{registered});
end;
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'Edits';
+ td mt '_userpage_edits';
td;
if($u->{c_changes}) {
a href => "/u$uid/hist", $u->{c_changes};
@@ -67,18 +64,17 @@ sub userpage {
end;
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'Votes';
+ td mt '_userpage_votes';
td;
if(!$u->{show_list}) {
- txt 'hidden';
+ txt mt '_userpage_hidden';
} elsif($votes) {
my($total, $count) = (0, 0);
for (1..@$votes) {
$total += $_*$votes->[$_-1];
$count += $votes->[$_-1];
}
- a href => "/u$uid/list?v=1", $count;
- txt sprintf ' (%.2f average)', $total/$count;
+ lit mt '_userpage_votes_item', "/u$uid/list?v=1", $count, sprintf '%.2f', $total/$count;
} else {
txt '-';
}
@@ -86,27 +82,23 @@ sub userpage {
end;
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'Tags';
- td !$u->{c_tags} ? '-' : sprintf '%d votes on %d distinct tags and %d visual novels',
- $u->{c_tags}, $u->{tagcount}, $u->{tagvncount};
+ td mt '_userpage_tags';
+ td !$u->{c_tags} ? '-' : mt '_userpage_tags_item', $u->{c_tags}, $u->{tagcount}, $u->{tagvncount};
end;
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'List stats';
- td !$u->{show_list} ? 'hidden' :
- sprintf '%d release%s of %d visual novel%s',
- $u->{releasecount}, $u->{releasecount} != 1 ? 's' : '',
- $u->{vncount}, $u->{vncount} != 1 ? 's' : '';
+ td mt '_userpage_list';
+ td !$u->{show_list} ? mt('_userpage_hidden') :
+ mt('_userpage_list_item', $u->{releasecount}, $u->{vncount});
end;
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'Forum stats';
+ td mt '_userpage_forum';
td;
- txt sprintf '%d post%s, %d new thread%s. ',
- $u->{postcount}, $u->{postcount} != 1 ? 's' : '',
- $u->{threadcount}, $u->{threadcount} != 1 ? 's' : '';
+ lit mt '_userpage_forum_item',$u->{postcount}, $u->{threadcount};
if($u->{postcount}) {
- a href => "/u$uid/posts"; lit 'Browse posts &raquo;'; end;
+ txt ' ';
+ a href => "/u$uid/posts"; lit mt('_userpage_forum_browse').' &raquo;'; end;
}
end;
end;
@@ -115,7 +107,7 @@ sub userpage {
if($u->{show_list} && $votes) {
div class => 'mainbox';
- h1 'Vote statistics';
+ h1 mt '_userpage_votestats';
$self->htmlVoteStats(u => $u, $votes);
end;
}
@@ -123,7 +115,7 @@ sub userpage {
if($u->{c_changes}) {
my $list = $self->dbRevisionGet(what => 'item user', uid => $uid, results => 5, hidden => 1);
h1 class => 'boxtitle';
- a href => "/u$uid/hist", 'Recent changes';
+ a href => "/u$uid/hist", mt '_userpage_changes';
end;
$self->htmlHistory($list, { p => 1 }, 0, "/u$uid/hist");
}
@@ -149,12 +141,12 @@ sub login {
$frm->{_err} = [ 'login_failed' ] if !$frm->{_err};
}
- $self->htmlHeader(title => 'Login', noindex => 1);
- $self->htmlForm({ frm => $frm, action => '/u/login' }, Login => [
- [ input => name => 'Username', short => 'usrname' ],
- [ static => content => '<a href="/u/register">No account yet?</a>' ],
- [ passwd => name => 'Password', short => 'usrpass' ],
- [ static => content => '<a href="/u/newpass">Forgot your password?</a>' ],
+ $self->htmlHeader(noindex => 1, title => mt '_login_title');
+ $self->htmlForm({ frm => $frm, action => '/u/login' }, login => [ mt('_login_title'),
+ [ input => short => 'usrname', name => mt '_login_username' ],
+ [ static => content => '<a href="/u/register">'.mt('_login_register').'</a>' ],
+ [ passwd => short => 'usrpass', name => mt '_login_password' ],
+ [ static => content => '<a href="/u/newpass">'.mt('_login_forgotpass').'</a>' ],
]);
$self->htmlFooter;
}
@@ -185,38 +177,22 @@ sub newpass {
my %o;
($o{passwd}, $o{salt}) = $self->authPreparePass($pass);
$self->dbUserEdit($u->{id}, %o);
- my $body = <<'__';
-Hello %s,
-
-Your password has been reset, you can now login at http://vndb.org/ with the
-following information:
-
-Username: %1$s
-Password: %s
-
-Now don't forget your password again! :-)
-
-vndb.org
-__
- $self->mail(
- sprintf($body, $u->{username}, $pass),
+ $self->mail(mt('_newpass_mail_body', $u->{username}, $pass),
To => $u->{mail},
From => 'VNDB <noreply@vndb.org>',
- Subject => 'New password for '.$u->{username}
+ Subject => mt('_newpass_mail_subject', $u->{username}),
);
return $self->resRedirect('/u/newpass/sent', 'post');
}
}
- $self->htmlHeader(title => 'Forgot Password', noindex => 1);
+ $self->htmlHeader(title => mt('_newpass_title'), noindex => 1);
div class => 'mainbox';
- h1 'Forgot Password';
- p "Forgot your password and can't login to VNDB anymore?\n"
- ."Don't worry! Just give us the email address you used to register on VNDB,\n"
- ."and we'll send you a new password within a few minutes!";
+ h1 mt '_newpass_title';
+ p mt '_newpass_msg';
end;
- $self->htmlForm({ frm => $frm, action => '/u/newpass' }, 'Reset Password' => [
- [ input => name => 'Email', short => 'mail' ],
+ $self->htmlForm({ frm => $frm, action => '/u/newpass' }, newpass => [ mt('_newpass_reset_title'),
+ [ input => short => 'mail', name => mt '_newpass_mail' ],
]);
$self->htmlFooter;
}
@@ -225,15 +201,13 @@ __
sub newpass_sent {
my $self = shift;
return $self->resRedirect('/') if $self->authInfo->{id};
- $self->htmlHeader(title => 'New Password', noindex => 1);
+ $self->htmlHeader(title => mt('_newpass_sent_title'), noindex => 1);
div class => 'mainbox';
- h1 'New Password';
+ h1 mt '_newpass_sent_title';
div class => 'notice';
- h2 'Password Reset';
+ h2 mt '_newpass_sent_subtitle';
p;
- txt "Your password has been reset and your new password should reach your mailbox in a few minutes.\n"
- ."You can always change your password again after logging in.\n\n";
- lit '<a href="/u/login">Login</a> - <a href="/">Home</a>';
+ lit mt '_newpass_sent_msg';
end;
end;
end;
@@ -243,7 +217,7 @@ sub newpass_sent {
sub register {
my $self = shift;
- return $self->resRedirect('/') if $self->authInfo->{id};
+ #return $self->resRedirect('/') if $self->authInfo->{id};
my $frm;
if($self->reqMethod eq 'POST') {
@@ -265,33 +239,22 @@ sub register {
}
}
- $self->htmlHeader(title => 'Create an Account', noindex => 1);
+ $self->htmlHeader(title => mt('_register_title'), noindex => 1);
div class => 'mainbox';
- h1 'Create an Account';
- h2 'Why should I register?';
- p 'Creating an account is completely painless, the only thing we need to know is your prefered username '
- .'and a password. You can just use any email address that isn\'t yours, as we don\'t even confirm '
- .'that the address you gave us is really yours. Keep in mind, however, that you would probably '
- .'want to remember your password if you do choose to give us an invalid email address...';
-
- p 'Anyway, having an account here has a few advantages over being just a regular visitor:';
- ul;
- li 'You can contribute to the database by editing any entries and adding new ones';
- li 'Keep track of all visual novels and releases you have, you\'d like to play, are playing, or have finished playing';
- li 'Vote on the visual novels you liked or disliked';
- li 'Contribute to the discussions on the boards';
- li 'And boast about the fact that you have an account on the best visual novel database in the world!';
+ h1 mt '_register_title';
+ h2 mt '_register_why';
+ p;
+ lit mt '_register_why_msg';
end;
end;
- $self->htmlForm({ frm => $frm, action => '/u/register' }, 'New Account' => [
- [ input => short => 'usrname', name => 'Username' ],
- [ static => content => 'Requested username. Must be lowercase and can only consist of alphanumeric characters.' ],
- [ input => short => 'mail', name => 'Email' ],
- [ static => content => 'Your email address will only be used in case you lose your password. We will never send'
- .' spam or newsletters unless you explicitly ask us for it.<br /><br />' ],
- [ passwd => short => 'usrpass', name => 'Password' ],
- [ passwd => short => 'usrpass2', name => 'Confirm pass.' ],
+ $self->htmlForm({ frm => $frm, action => '/u/register' }, register => [ mt('_register_form_title'),
+ [ input => short => 'usrname', name => mt '_register_username' ],
+ [ static => content => mt '_register_username_msg' ],
+ [ input => short => 'mail', name => mt '_register_mail' ],
+ [ static => content => mt('_register_mail_msg').'<br /><br />' ],
+ [ passwd => short => 'usrpass', name => mt('_register_password') ],
+ [ passwd => short => 'usrpass2', name => mt('_register_confirm') ],
]);
$self->htmlFooter;
}
@@ -314,6 +277,7 @@ sub edit {
$self->authCan('usermod') ? (
{ name => 'usrname', template => 'pname', minlength => 2, maxlength => 15 },
{ name => 'rank', enum => [ 1..$#{$self->{user_ranks}} ] },
+ { name => 'ign_votes', required => 0, default => 0 },
) : (),
{ name => 'mail', template => 'mail' },
{ name => 'usrpass', required => 0, minlength => 4, maxlength => 64, template => 'asciiprint' },
@@ -335,6 +299,7 @@ sub edit {
($o{passwd}, $o{salt}) = $self->authPreparePass($frm->{usrpass}) if $frm->{usrpass};
$o{show_list} = $frm->{flags_list} ? 1 : 0;
$o{show_nsfw} = $frm->{flags_nsfw} ? 1 : 0;
+ $o{ign_votes} = $frm->{ign_votes} ? 1 : 0 if $self->authCan('usermod');
$self->dbUserEdit($uid, %o);
$self->dbSessionDel($uid) if $frm->{usrpass};
return $self->resRedirect("/u$uid/edit?d=1", 'post') if $uid != $self->authInfo->{id} || !$frm->{usrpass};
@@ -347,43 +312,42 @@ sub edit {
$frm->{$_} ||= $u->{$_} for(qw|rank mail skin customcss|);
$frm->{flags_list} = $u->{show_list} if !defined $frm->{flags_list};
$frm->{flags_nsfw} = $u->{show_nsfw} if !defined $frm->{flags_nsfw};
+ $frm->{ign_votes} = $u->{ign_votes} if !defined $frm->{ign_votes};
# create the page
- my $title = $self->authInfo->{id} != $uid ? "Edit $u->{username}'s Account" : 'My Account';
- $self->htmlHeader(title => $title, noindex => 1);
+ $self->htmlHeader(title => mt('_usere_title'), noindex => 1);
$self->htmlMainTabs('u', $u, 'edit');
if($self->reqParam('d')) {
div class => 'mainbox';
- h1 'Settings saved';
+ h1 mt '_usere_saved_title';
div class => 'notice';
- p 'Settings successfully saved.';
+ p mt '_usere_saved_msg';
end;
end
}
- $self->htmlForm({ frm => $frm, action => "/u$uid/edit" }, $title => [
- [ part => title => 'General Info' ],
+ $self->htmlForm({ frm => $frm, action => "/u$uid/edit" }, useredit => [ mt('_usere_title'),
+ [ part => title => mt '_usere_geninfo' ],
$self->authCan('usermod') ? (
- [ input => short => 'usrname', name => 'Username' ],
- [ select => short => 'rank', name => 'Rank', options => [
- map [ $_, $self->{user_ranks}[$_][0] ], 1..$#{$self->{user_ranks}} ] ],
+ [ input => short => 'usrname', name => mt('_usere_username') ],
+ [ select => short => 'rank', name => mt('_usere_rank'), options => [
+ map [ $_, mt '_urank_'.$_ ], 1..$#{$self->{user_ranks}} ] ],
+ [ check => short => 'ign_votes', name => mt '_usere_ignvotes' ],
) : (
- [ static => label => 'Username', content => $frm->{usrname} ],
+ [ static => label => mt('_usere_username'), content => $frm->{usrname} ],
),
- [ input => short => 'mail', name => 'Email' ],
-
- [ part => title => 'Change Password' ],
- [ static => content => 'Leave blank to keep your current password' ],
- [ passwd => short => 'usrpass', name => 'Password' ],
- [ passwd => short => 'usrpass2', name => 'Confirm pass.' ],
-
- [ part => title => 'Options' ],
- [ check => short => 'flags_list', name =>
- qq|Allow other people to see my visual novel list (<a href="/u$uid/list">/u$uid/list</a>) |.
- qq|and wishlist (<a href="/u$uid/wish">/u$uid/wish</a>)| ],
- [ check => short => 'flags_nsfw', name => 'Disable warnings for images that are not safe for work.' ],
- [ select => short => 'skin', name => 'Prefered skin', width => 300, options => [
+ [ input => short => 'mail', name => mt '_usere_mail' ],
+
+ [ part => title => mt '_usere_changepass' ],
+ [ static => content => mt '_usere_changepass_msg' ],
+ [ passwd => short => 'usrpass', name => mt '_usere_password' ],
+ [ passwd => short => 'usrpass2', name => mt '_usere_confirm' ],
+
+ [ part => title => mt '_usere_options' ],
+ [ check => short => 'flags_list', name => mt '_usere_flist' ],
+ [ check => short => 'flags_nsfw', name => mt '_usere_fnsfw' ],
+ [ select => short => 'skin', name => mt('_usere_skin'), width => 300, options => [
map [ $_ eq $self->{skin_default} ? '' : $_, $self->{skins}{$_}.($self->debug?" [$_]":'') ], sort { $self->{skins}{$a} cmp $self->{skins}{$b} } keys %{$self->{skins}} ] ],
- [ textarea => short => 'customcss', name => 'Additional <a href="http://en.wikipedia.org/wiki/Cascading_Style_Sheets">CSS</a>' ],
+ [ textarea => short => 'customcss', name => mt '_usere_css' ],
]);
$self->htmlFooter;
}
@@ -402,12 +366,13 @@ sub posts {
my($posts, $np) = $self->dbPostGet(uid => $uid, hide => 1, what => 'thread', page => $f->{p}, order => 'tp.date DESC');
- $self->htmlHeader(title => "Posts made by $u->{username}", noindex => 1);
+ my $title = mt '_uposts_title', $u->{username};
+ $self->htmlHeader(title => $title, noindex => 1);
$self->htmlMainTabs(u => $u, 'posts');
div class => 'mainbox';
- h1 "Posts made by $u->{username}";
+ h1 $title;
if(!@$posts) {
- p "\u$u->{username} hasn't made any posts yet.";
+ p mt '_uposts_noresults', $u->{username};
}
end;
@@ -420,15 +385,15 @@ sub posts {
header => [
[ '' ],
[ '' ],
- [ 'Date' ],
- sub { td; a href => '#', id => 'history_comments', 'expand'; txt 'Title'; end; }
+ [ mt '_uposts_col_date' ],
+ sub { td; a href => '#', id => 'history_comments', 'expand'; txt mt '_uposts_col_title'; end; }
],
row => sub {
my($s, $n, $l) = @_;
Tr $n % 2 ? (class => 'odd') : ();
td class => 'tc1'; a href => "/t$l->{tid}.$l->{num}", 't'.$l->{tid}; end;
td class => 'tc2'; a href => "/t$l->{tid}.$l->{num}", '.'.$l->{num}; end;
- td class => 'tc3', date $l->{date};
+ td class => 'tc3', $self->{l10n}->date($l->{date});
td class => 'tc4'; a href => "/t$l->{tid}.$l->{num}", $l->{title}; end;
end;
Tr class => $n % 2 ? 'editsum odd hidden' : 'editsum hidden';
@@ -446,6 +411,8 @@ sub delete {
my($self, $uid, $act) = @_;
return $self->htmlDenied if !$self->authCan('usermod');
+ # rarely used admin function, won't really need translating
+
# confirm
if(!$act) {
my $u = $self->dbUserGet(uid => $uid)->[0];
@@ -492,16 +459,16 @@ sub list {
);
return 404 if $f->{_err};
- $self->htmlHeader(title => 'Browse users');
+ $self->htmlHeader(noindex => 1, title => mt '_ulist_title');
div class => 'mainbox';
- h1 'Browse users';
+ h1 mt '_ulist_title';
form action => '/u/all', 'accept-charset' => 'UTF-8', method => 'get';
$self->htmlSearchBox('u', $f->{q});
end;
p class => 'browseopts';
for ('all', 'a'..'z', 0) {
- a href => "/u/$_", $_ eq $char ? (class => 'optselected') : (), $_ ? uc $_ : '#';
+ a href => "/u/$_", $_ eq $char ? (class => 'optselected') : (), $_ eq 'all' ? mt('_char_all') : $_ ? uc $_ : '#';
}
end;
end;
@@ -522,11 +489,11 @@ sub list {
pageurl => "/u/$char?o=$f->{o};s=$f->{s};q=$f->{q}",
sorturl => "/u/$char?q=$f->{q}",
header => [
- [ 'Username', 'username' ],
- [ 'Registered', 'registered' ],
- [ 'Votes', 'votes' ],
- [ 'Edits', 'changes' ],
- [ 'Tags', 'tags' ],
+ [ mt('_ulist_col_username'), 'username' ],
+ [ mt('_ulist_col_registered'), 'registered' ],
+ [ mt('_ulist_col_votes'), 'votes' ],
+ [ mt('_ulist_col_edits'), 'changes' ],
+ [ mt('_ulist_col_tags'), 'tags' ],
],
row => sub {
my($s, $n, $l) = @_;
@@ -534,9 +501,9 @@ sub list {
td class => 'tc1';
a href => '/u'.$l->{id}, $l->{username};
end;
- td class => 'tc2', date $l->{registered};
- td class => 'tc3';
- lit !$l->{show_list} ? '-' : !$l->{c_votes} ? 0 :
+ td class => 'tc2', $self->{l10n}->date($l->{registered});
+ td class => 'tc3'.(!$l->{show_list} && $self->authCan('usermod') ? ' linethrough' : '');
+ lit !$l->{show_list} && !$self->authCan('usermod') ? '-' : !$l->{c_votes} ? 0 :
qq|<a href="/u$l->{id}/list">$l->{c_votes}</a>|;
end;
td class => 'tc4';
diff --git a/lib/VNDB/Handler/VNBrowse.pm b/lib/VNDB/Handler/VNBrowse.pm
index 5a22bccc..2a6d6cd7 100644
--- a/lib/VNDB/Handler/VNBrowse.pm
+++ b/lib/VNDB/Handler/VNBrowse.pm
@@ -21,8 +21,8 @@ sub list {
{ name => 'p', required => 0, default => 1, template => 'int' },
{ name => 'q', required => 0, default => '' },
{ name => 'sq', required => 0, default => '' },
- { name => 'ln', required => 0, multi => 1, enum => [ keys %{$self->{languages}} ], default => '' },
- { name => 'pl', required => 0, multi => 1, enum => [ keys %{$self->{platforms}} ], default => '' },
+ { name => 'ln', required => 0, multi => 1, enum => $self->{languages}, default => '' },
+ { name => 'pl', required => 0, multi => 1, enum => $self->{platforms}, default => '' },
{ name => 'ti', required => 0, default => '', maxlength => 200 },
{ name => 'te', required => 0, default => '', maxlength => 200 },
{ name => 'sp', required => 0, default => $self->reqCookie('tagspoil') =~ /^([0-2])$/ ? $1 : 1, enum => [0..2] },
@@ -34,9 +34,9 @@ sub list {
return $self->resRedirect('/'.$1.$2.(!$3 ? '' : $1 eq 'd' ? '#'.$3 : '.'.$3), 'temp')
if $f->{q} =~ /^([gvrptud])([0-9]+)(?:\.([0-9]+))?$/;
- # for URL compatibilty with older versions
+ # for URL compatibilty with older versions (ugly hack to get English strings)
my @lang;
- $f->{q} =~ s/\s*$self->{languages}{$_}\s*//&&push @lang, $_ for (keys %{$self->{languages}});
+ $f->{q} =~ s/\s*$VNDB::L10N::en::Lexicon{"_lang_$_"}\s*//&&push @lang, $_ for (@{$self->{languages}});
$f->{ln} = $f->{ln}[0] ? [ @{$f->{ln}}, @lang ] : \@lang;
}
@@ -70,7 +70,7 @@ sub list {
$self->resRedirect('/v'.$list->[0]{id}, 'temp')
if $f->{q} && @$list == 1;
- $self->htmlHeader(title => 'Browse visual novels', search => $f->{q}, js => 'forms');
+ $self->htmlHeader(title => mt('_vnbrowse_title'), search => $f->{q}, js => 'forms');
_filters($self, $f, $char, \@ignored);
my $url = "/v/$char?q=$f->{q};ti=$f->{ti};te=$f->{te}";
@@ -84,12 +84,12 @@ sub list {
pageurl => "$url;o=$f->{o};s=$f->{s}",
sorturl => $url,
header => [
- @ti ? [ 'Score', 'tagscore', undef, 'tc_s' ] : (),
- [ 'Title', 'title', undef, @ti ? 'tc_t' : 'tc1' ],
- [ '', 0, undef, 'tc2' ],
- [ '', 0, undef, 'tc3' ],
- [ 'Released', 'rel', undef, 'tc4' ],
- [ 'Popularity', 'pop', undef, 'tc5' ],
+ @ti ? [ mt('_vnbrowse_col_score'), 'tagscore', undef, 'tc_s' ] : (),
+ [ mt('_vnbrowse_col_title'), 'title', undef, @ti ? 'tc_t' : 'tc1' ],
+ [ '', 0, undef, 'tc2' ],
+ [ '', 0, undef, 'tc3' ],
+ [ mt('_vnbrowse_col_released'), 'rel', undef, 'tc4' ],
+ [ mt('_vnbrowse_col_popularity'), 'pop', undef, 'tc5' ],
],
row => sub {
my($s, $n, $l) = @_;
@@ -103,15 +103,15 @@ sub list {
a href => '/v'.$l->{id}, title => $l->{original}||$l->{title}, shorten $l->{title}, 100;
end;
td class => 'tc2';
- $_ ne 'oth' && cssicon $_, $self->{platforms}{$_}
+ $_ ne 'oth' && cssicon $_, mt "_plat_$_"
for (sort split /\//, $l->{c_platforms});
end;
td class => 'tc3';
- cssicon "lang $_", $self->{languages}{$_}
+ cssicon "lang $_", mt "_lang_$_"
for (reverse sort split /\//, $l->{c_languages});
end;
td class => 'tc4';
- lit monthstr $l->{c_released};
+ lit $self->{l10n}->datestr($l->{c_released});
end;
td class => 'tc5', sprintf '%.2f', $l->{c_popularity}*100;
end;
@@ -126,69 +126,72 @@ sub _filters {
form action => '/v/all', 'accept-charset' => 'UTF-8', method => 'get';
div class => 'mainbox';
- h1 'Browse visual novels';
+ h1 mt '_vnbrowse_title';
$self->htmlSearchBox('v', $f->{q});
p class => 'browseopts';
for ('all', 'a'..'z', 0) {
- a href => "/v/$_", $_ eq $char ? (class => 'optselected') : (), $_ ? uc $_ : '#';
+ a href => "/v/$_", $_ eq $char ? (class => 'optselected') : (), $_ eq 'all' ? mt('_char_all') : $_ ? uc $_ : '#';
}
end;
if(@$ign) {
div class => 'warning';
- h2 'The following tags were ignored:';
+ h2 mt '_vnbrowse_tagign_title';
ul;
- li $_->[0].' ('.($_->[1]?"can't filter on meta tags":"no such tag found").')' for @$ign;
+ li $_->[0].' ('.mt('_vnbrowse_tagign_'.($_->[1]?'meta':'notfound')).')' for @$ign;
end;
end;
}
a id => 'advselect', href => '#';
- lit '<i>&#9656;</i> advanced search';
+ lit '<i>&#9656;</i> '.mt('_vnbrowse_advsearch');
end;
div id => 'advoptions', class => 'hidden vnoptions';
h2;
- lit 'Tag filters <b>(boolean and, selecting more gives less results)</b>';
+ txt mt '_vnbrowse_tags';
+ b ' ('.mt('_vnbrowse_booland').')';
end;
table class => 'formtable', style => 'margin-left: 0';
- $self->htmlFormPart($f, [ input => short => 'ti', name => 'Tags to include', width => 350 ]);
- $self->htmlFormPart($f, [ radio => short => 'sp', name => '', options => [[0,'Hide spoilers'],[1,'Show minor spoilers'],[2,'Show major spoilers']]]);
- $self->htmlFormPart($f, [ input => short => 'te', name => 'Tags to exclude', width => 350 ]);
+ $self->htmlFormPart($f, [ input => short => 'ti', name => mt('_vnbrowse_taginc'), width => 350 ]);
+ $self->htmlFormPart($f, [ radio => short => 'sp', name => '', options => [map [$_, mt '_vnbrowse_spoil'.$_], 0..2]]);
+ $self->htmlFormPart($f, [ input => short => 'te', name => mt('_vnbrowse_tagexc'), width => 350 ]);
end;
h2;
- lit 'Languages <b>(boolean or, selecting more gives more results)</b>';
+ txt mt '_vnbrowse_lang';
+ b ' ('.mt('_vnbrowse_boolor').')';
end;
for my $i (sort @{$self->dbLanguages}) {
span;
input type => 'checkbox', name => 'ln', value => $i, id => "lang_$i",
(scalar grep $_ eq $i, @{$f->{ln}}) ? (checked => 'checked') : ();
label for => "lang_$i";
- cssicon "lang $i", $self->{languages}{$i};
- txt $self->{languages}{$i};
+ cssicon "lang $i", mt "_lang_$i";
+ txt mt "_lang_$i";
end;
end;
}
h2;
- lit 'Platforms <b>(boolean or, selecting more gives more results)</b>';
+ txt mt '_vnbrowse_plat';
+ b ' ('.mt('_vnbrowse_boolor').')';
end;
- for my $i (sort keys %{$self->{platforms}}) {
+ for my $i (sort @{$self->{platforms}}) {
next if $i eq 'oth';
span;
input type => 'checkbox', id => "plat_$i", name => 'pl', value => $i,
(scalar grep $_ eq $i, @{$f->{pl}}) ? (checked => 'checked') : ();
label for => "plat_$i";
- cssicon $i, $self->{platforms}{$i};
- txt $self->{platforms}{$i};
+ cssicon $i, mt "_plat_$i";
+ txt mt "_plat_$i";
end;
end;
}
div style => 'text-align: center; clear: left;';
- input type => 'submit', value => 'Apply', class => 'submit';
- input type => 'reset', value => 'Clear', class => 'submit', onclick => 'location.href="/v/all"';
+ input type => 'submit', value => mt('_vnbrowse_apply'), class => 'submit';
+ input type => 'reset', value => mt('_vnbrowse_clear'), class => 'submit', onclick => 'location.href="/v/all"';
end;
end;
end;
diff --git a/lib/VNDB/Handler/VNEdit.pm b/lib/VNDB/Handler/VNEdit.pm
index feca72d6..fcbe6753 100644
--- a/lib/VNDB/Handler/VNEdit.pm
+++ b/lib/VNDB/Handler/VNEdit.pm
@@ -4,6 +4,7 @@ package VNDB::Handler::VNEdit;
use strict;
use warnings;
use YAWF ':html', ':xml';
+use VNDB::Func;
YAWF::register(
@@ -37,12 +38,12 @@ sub edit {
{ name => 'title', maxlength => 250 },
{ name => 'original', required => 0, maxlength => 250, default => '' },
{ name => 'alias', required => 0, maxlength => 500, default => '' },
- { name => 'desc', maxlength => 10240 },
- { name => 'length', required => 0, default => 0, enum => [ 0..$#{$self->{vn_lengths}} ] },
+ { name => 'desc', required => 0, default => '', maxlength => 10240 },
+ { name => 'length', required => 0, default => 0, enum => $self->{vn_lengths} },
{ name => 'l_wp', required => 0, default => '', maxlength => 150 },
{ name => 'l_encubed', required => 0, default => '', maxlength => 100 },
{ name => 'l_renai', required => 0, default => '', maxlength => 100 },
- { name => 'l_vnn', required => 0, default => 0, template => 'int' },
+ { name => 'l_vnn', required => 0, default => $b4{l_vnn}, template => 'int' },
{ name => 'anime', required => 0, default => '' },
{ name => 'img_nsfw', required => 0, default => 0 },
{ name => 'relations', required => 0, default => '', maxlength => 5000 },
@@ -95,9 +96,10 @@ sub edit {
!exists $frm->{$_} && ($frm->{$_} = $b4{$_}) for (keys %b4);
$frm->{editsum} = sprintf 'Reverted to revision v%d.%d', $vid, $rev if $rev && !defined $frm->{editsum};
- $self->htmlHeader(js => 'forms', title => $vid ? "Edit $v->{title}" : 'Add a new visual novel', noindex => 1);
+ my $title = $vid ? mt('_vnedit_title_edit', $v->{title}) : mt '_vnedit_title_add';
+ $self->htmlHeader(js => 'forms', title => $title, noindex => 1);
$self->htmlMainTabs('v', $v, 'edit') if $vid;
- $self->htmlEditMessage('v', $v);
+ $self->htmlEditMessage('v', $v, $title);
_form($self, $v, $frm);
$self->htmlFooter;
}
@@ -139,72 +141,59 @@ sub _form {
my($self, $v, $frm) = @_;
my $r = $v ? $self->dbReleaseGet(vid => $v->{id}) : [];
$self->htmlForm({ frm => $frm, action => $v ? "/v$v->{id}/edit" : '/v/new', editsum => 1, upload => 1 },
- 'General info' => [
- [ input => short => 'title', name => 'Title (romaji)' ],
- [ input => short => 'original', name => 'Original title' ],
- [ static => content => 'The original title of this visual novel, leave blank if it already is in the Latin alphabet.' ],
- [ textarea => short => 'alias', name => 'Aliases', rows => 4 ],
- [ static => content => q|
- Comma seperated list of alternative titles or abbreviations. Can include both official
- (japanese/english) titles and unofficial titles used around net.<br />
- <b>Titles that are listed in the releases do not have to be added here.</b>
- |],
- [ textarea => short => 'desc', name => 'Description', rows => 10 ],
- [ static => content => q|
- Short description of the main story. Please do not include spoilers, and don't forget to list
- the source in case you didn't write the description yourself. (formatting codes are allowed)
- |],
- [ select => short => 'length', name => 'Length', width => 300, options =>
- [ map [ $_ => $self->{vn_lengths}[$_][0].($_ ? " ($self->{vn_lengths}[$_][2])" : '') ], 0..$#{$self->{vn_lengths}} ] ],
-
- [ input => short => 'l_wp', name => 'External links', pre => 'http://en.wikipedia.org/wiki/' ],
+ vn_geninfo => [ mt('_vnedit_geninfo'),
+ [ input => short => 'title', name => mt '_vnedit_frm_title' ],
+ [ input => short => 'original', name => mt '_vnedit_original' ],
+ [ static => content => mt '_vnedit_original_msg' ],
+ [ textarea => short => 'alias', name => mt('_vnedit_alias'), rows => 4 ],
+ [ static => content => mt '_vnedit_alias_msg' ],
+ [ textarea => short => 'desc', name => mt('_vnedit_desc').'<br /><b class="standout">'.mt('_inenglish').'</b>', rows => 10 ],
+ [ static => content => mt '_vnedit_desc_msg' ],
+ [ select => short => 'length', name => mt('_vnedit_length'), width => 300, options =>
+ [ map [ $_ => mt '_vnlength_'.$_, 2 ], @{$self->{vn_lengths}} ] ],
+
+ [ input => short => 'l_wp', name => mt('_vnedit_links'), pre => 'http://en.wikipedia.org/wiki/' ],
[ input => short => 'l_encubed', pre => 'http://novelnews.net/tag/', post => '/' ],
[ input => short => 'l_renai', pre => 'http://renai.us/game/', post => '.shtml' ],
- [ input => short => 'l_vnn', pre => 'http://visual-novels.net/vn/index.php?option=com_content&amp;task=view&amp;id=', width => 40 ],
-
- [ input => short => 'anime', name => 'Anime' ],
- [ static => content => q|
- Whitespace seperated list of <a href="http://anidb.net/">AniDB</a> anime IDs.
- E.g. "1015 3348" will add <a href="http://anidb.net/a1015">Shingetsutan Tsukihime</a>
- and <a href="http://anidb.net/a3348">Fate/stay night</a> as related anime.<br />
- <b>Note:</b> It can take a few minutes for the anime titles to appear on the VN page.
- |],
+
+ [ input => short => 'anime', name => mt '_vnedit_anime' ],
+ [ static => content => mt '_vnedit_anime_msg' ],
],
- 'Image' => [
+ vn_img => [ mt('_vnedit_image'),
[ static => nolabel => 1, content => sub {
div class => 'img';
- p 'No image uploaded yet' if !$v || !$v->{image};
- p '[processing image, please return in a few minutes]' if $v && $v->{image} < 0;
+ p mt '_vnedit_image_none' if !$v || !$v->{image};
+ p mt '_vnedit_image_processing' if $v && $v->{image} < 0;
img src => sprintf("%s/cv/%02d/%d.jpg", $self->{url_static}, $v->{image}%100, $v->{image}), alt => $v->{title} if $v && $v->{image} > 0;
end;
div;
- h2 'Upload new image';
+ h2 mt '_vnedit_image_upload';
input type => 'file', class => 'text', name => 'img', id => 'img';
- p 'Preferably the cover of the CD/DVD/package. Image must be in JPEG or PNG format'
- ." and at most 500kB. Images larger than 256x400 will automatically be resized.\n\n\n";
+ p mt('_vnedit_image_upload_msg')."\n\n\n";
- h2 'NSFW';
+ h2 mt '_vnedit_image_nsfw';
input type => 'checkbox', class => 'checkbox', id => 'img_nsfw', name => 'img_nsfw',
$frm->{img_nsfw} ? (checked => 'checked') : ();
- label class => 'checkbox', for => 'img_nsfw', "Not Safe For Work.\n";
- p 'Please check this option if the image contains nudity, gore, or is otherwise not safe in a work-friendly environment.';
+ label class => 'checkbox', for => 'img_nsfw', mt '_vnedit_image_nsfw_check';
+ p "\n".mt '_vnedit_image_nsfw_msg';
end;
}],
],
- 'Relations' => [
+ vn_rel => [ mt('_vnedit_rel'),
[ hidden => short => 'relations' ],
[ static => nolabel => 1, content => sub {
- h2 'Selected relations';
+ h2 mt '_vnedit_rel_sel';
table;
tbody id => 'relation_tbl';
# to be filled using javascript
end;
end;
- h2 'Add relation';
+ h2 mt '_vnedit_rel_add';
+ # TODO: localize JS relartion selector
table;
Tr id => 'relation_new';
td class => 'tc1';
@@ -226,21 +215,14 @@ sub _form {
}],
],
- !@$r ? () : ( 'Screenshots' => [
+ !@$r ? () : ( vn_scr => [ mt('_vnedit_scr'),
[ hidden => short => 'screenshots' ],
[ static => nolabel => 1, content => sub {
div class => 'warning';
- b 'Please keep the following in mind when uploading screenshots:';
- ul;
- li 'Screenshots have to be in the native resolution of the game,';
- li 'Remove any window borders and make sure the image is unmarked,';
- li 'Don\'t only upload event CGs.';
- end;
- lit 'Please read the <a href="/d2#6">guidelines</a> for more information.';
- br;
- b 'Make sure to submit the form after the upload has finished!';
+ lit mt '_vnedit_scr_msg';
end;
br;
+ # TODO: localize screenshot uploader
table;
tbody id => 'scr_table', '';
end;
diff --git a/lib/VNDB/Handler/VNPage.pm b/lib/VNDB/Handler/VNPage.pm
index 0563c1dc..361963a8 100644
--- a/lib/VNDB/Handler/VNPage.pm
+++ b/lib/VNDB/Handler/VNPage.pm
@@ -8,25 +8,33 @@ use VNDB::Func;
YAWF::register(
+ qr{v/rand} => \&rand,
qr{v([1-9]\d*)/rg} => \&rg,
qr{v([1-9]\d*)(?:\.([1-9]\d*))?} => \&page,
);
+sub rand {
+ my $self = shift;
+ $self->resRedirect('/v'.$self->dbVNGet(results => 1, order => 'RANDOM()')->[0]{id}, 'temp');
+}
+
+
sub rg {
my($self, $vid) = @_;
my $v = $self->dbVNGet(id => $vid, what => 'relgraph')->[0];
return 404 if !$v->{id} || !$v->{rgraph};
- $self->htmlHeader(title => 'Relation graph for '.$v->{title});
+ my $title = mt '_vnrg_title', $v->{title};
+ $self->htmlHeader(title => $title);
$self->htmlMainTabs('v', $v, 'rg');
div class => 'mainbox';
- h1 'Relation graph for '.$v->{title};
+ h1 $title;
lit $v->{cmap};
p class => 'center';
img src => sprintf('%s/rg/%02d/%d.png', $self->{url_static}, $v->{rgraph}%100, $v->{rgraph}),
- alt => 'Relation graph for '.$v->{title}, usemap => '#rgraph';
+ alt => $title, usemap => '#rgraph';
end;
end;
}
@@ -60,19 +68,19 @@ sub page {
# image
div class => 'vnimg';
if(!$v->{image}) {
- p 'No image uploaded yet';
+ p mt '_vnpage_noimg';
} elsif($v->{image} < 0) {
- p '[processing image, please return in a few minutes]';
+ p mt '_vnpage_imgproc';
} elsif($v->{img_nsfw} && !$self->authInfo->{show_nsfw}) {
img id => 'nsfw_hid', src => sprintf("%s/cv/%02d/%d.jpg", $self->{url_static}, $v->{image}%100, $v->{image}), alt => $v->{title};
p id => 'nsfw_show';
- txt "This image has been flagged\nas Not Safe For Work.\n\n";
- a href => '#', 'Show me anyway';
- txt "\n\n(This warning can be disabled in your account)";
+ txt mt('_vnpage_imgnsfw_msg')."\n\n";
+ a href => '#', mt '_vnpage_imgnsfw_show';
+ txt "\n\n".mt '_vnpage_imgnsfw_note';
end;
} else {
img src => sprintf("%s/cv/%02d/%d.jpg", $self->{url_static}, $v->{image}%100, $v->{image}), alt => $v->{title};
- i 'Flagged as NSFW' if $v->{img_nsfw} && $self->authInfo->{show_nsfw};
+ i mt '_vnpage_imgnsfw_foot' if $v->{img_nsfw} && $self->authInfo->{show_nsfw};
}
end;
@@ -80,36 +88,35 @@ sub page {
table;
my $i = 0;
Tr ++$i % 2 ? (class => 'odd') : ();
- td class => 'key', 'Title';
+ td class => 'key', mt '_vnpage_vntitle';
td $v->{title};
end;
if($v->{original}) {
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'Original title';
+ td mt '_vnpage_original';
td $v->{original};
end;
}
if($v->{alias}) {
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'Aliases';
+ td mt '_vnpage_alias';
td $v->{alias};
end;
}
if($v->{length}) {
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'Length';
- td "$self->{vn_lengths}[$v->{length}][0] ($self->{vn_lengths}[$v->{length}][1])";
+ td mt '_vnpage_length';
+ td mt '_vnlength_'.$v->{length}, 1;
end;
}
my @links = (
$v->{l_wp} ? [ 'Wikipedia', 'http://en.wikipedia.org/wiki/%s', $v->{l_wp} ] : (),
$v->{l_encubed} ? [ 'Encubed', 'http://novelnews.net/tag/%s/', $v->{l_encubed} ] : (),
$v->{l_renai} ? [ 'Renai.us', 'http://renai.us/game/%s.shtml', $v->{l_renai} ] : (),
- $v->{l_vnn} ? [ 'V-N.net', 'http://visual-novels.net/vn/index.php?option=com_content&task=view&id=%d', $v->{l_vnn} ] : (),
);
if(@links) {
Tr ++$i % 2 ? (class => 'odd') : ();
- td 'Links';
+ td mt '_vnpage_links';
td;
for(@links) {
a href => sprintf($_->[1], $_->[2]), $_->[0];
@@ -126,9 +133,9 @@ sub page {
Tr;
td class => 'vndesc', colspan => 2;
- h2 'Description';
+ h2 mt '_vnpage_description';
p;
- lit bb2html $v->{desc};
+ lit $v->{desc} ? bb2html $v->{desc} : '-';
end;
end;
end;
@@ -141,11 +148,11 @@ sub page {
my $t = $self->dbTagStats(vid => $v->{id}, order => 'avg(tv.vote) DESC', minrating => 0, results => 999);
if(@$t) {
div id => 'tagops';
- a href => '#', 'hide spoilers';
- a href => '#', class => 'tsel', 'show minor spoilers';
- a href => '#', 'spoil me!';
- a href => '#', class => 'sec', 'summary';
- a href => '#', 'all';
+ a href => '#', mt '_vnpage_tags_spoil0';
+ a href => '#', class => 'tsel', mt '_vnpage_tags_spoil1';
+ a href => '#', mt '_vnpage_tags_spoil2';
+ a href => '#', class => 'sec', mt '_vnpage_tags_summary';
+ a href => '#', mt '_vnpage_tags_all';
end;
div id => 'vntags';
for (@$t) {
@@ -176,41 +183,38 @@ sub _revision {
)->[0];
$self->htmlRevision('v', $prev, $v,
- [ title => 'Title (romaji)', diff => 1 ],
- [ original => 'Original title', diff => 1 ],
- [ alias => 'Alias', diff => 1 ],
- [ desc => 'Description', diff => 1 ],
- [ length => 'Length', serialize => sub { $self->{vn_lengths}[$_[0]][0] } ],
- [ l_wp => 'Wikipedia link', htmlize => sub {
- $_[0] ? sprintf '<a href="http://en.wikipedia.org/wiki/%s">%1$s</a>', xml_escape $_[0] : '[no link]'
- }],
- [ l_encubed => 'Encubed tag', htmlize => sub {
- $_[0] ? sprintf '<a href="http://novelnews.net/tag/%s/">%1$s</a>', xml_escape $_[0] : '[no link]'
+ [ title => diff => 1 ],
+ [ original => diff => 1 ],
+ [ alias => diff => 1 ],
+ [ desc => diff => 1 ],
+ [ length => serialize => sub { mt '_vnlength_'.$_[0] } ],
+ [ l_wp => htmlize => sub {
+ $_[0] ? sprintf '<a href="http://en.wikipedia.org/wiki/%s">%1$s</a>', xml_escape $_[0] : mt '_vndiff_nolink'
}],
- [ l_renai => 'Renai.us link', htmlize => sub {
- $_[0] ? sprintf '<a href="http://renai.us/game/%s.shtml">%1$s</a>', xml_escape $_[0] : '[no link]'
+ [ l_encubed => htmlize => sub {
+ $_[0] ? sprintf '<a href="http://novelnews.net/tag/%s/">%1$s</a>', xml_escape $_[0] : mt '_vndiff_nolink'
}],
- [ l_vnn => 'V-N.net link', htmlize => sub {
- $_[0] ? sprintf '<a href="http://visual-novels.net/vn/index.php?option=com_content&amp;task=view&amp;id=%d">%1$d</a>', xml_escape $_[0] : '[no link]'
+ [ l_renai => htmlize => sub {
+ $_[0] ? sprintf '<a href="http://renai.us/game/%s.shtml">%1$s</a>', xml_escape $_[0] : mt '_vndiff_nolink'
}],
- [ relations => 'Relations', join => '<br />', split => sub {
+ [ relations => join => '<br />', split => sub {
my @r = map sprintf('%s: <a href="/v%d" title="%s">%s</a>',
$self->{vn_relations}[$_->{relation}][0], $_->{id}, xml_escape($_->{original}||$_->{title}), xml_escape shorten $_->{title}, 40
), sort { $a->{id} <=> $b->{id} } @{$_[0]};
- return @r ? @r : ('[none]');
+ return @r ? @r : (mt '_vndiff_none');
}],
- [ anime => 'Anime', join => ', ', split => sub {
+ [ anime => join => ', ', split => sub {
my @r = map sprintf('<a href="http://anidb.net/a%d">a%1$d</a>', $_->{id}), sort { $a->{id} <=> $b->{id} } @{$_[0]};
- return @r ? @r : ('[none]');
+ return @r ? @r : (mt '_vndiff_none');
}],
- [ screenshots => 'Screenshots', join => '<br />', split => sub {
+ [ screenshots => join => '<br />', split => sub {
my @r = map sprintf('[%s] <a href="%s/sf/%02d/%d.jpg" rel="iv:%dx%d">%4$d</a> (%s)',
$_->{rid} ? qq|<a href="/r$_->{rid}">r$_->{rid}</a>| : 'no release',
$self->{url_static}, $_->{id}%100, $_->{id}, $_->{width}, $_->{height}, $_->{nsfw} ? 'NSFW' : 'Safe'
), @{$_[0]};
- return @r ? @r : ('[no screenshots]');
+ return @r ? @r : (mt '_vndiff_none');
}],
- [ image => 'Image', htmlize => sub {
+ [ image => htmlize => sub {
my $url = sprintf "%s/cv/%02d/%d.jpg", $self->{url_static}, $_[0]%100, $_[0];
if($_[0] > 0) {
return $_[1]->{img_nsfw} && !$self->authInfo->{show_nsfw} ? "<a href=\"$url\">(NSFW)</a>" : "<img src=\"$url\" />";
@@ -218,7 +222,7 @@ sub _revision {
return $_[0] < 0 ? '[processing]' : 'No image';
}
}],
- [ img_nsfw => 'Image NSFW', serialize => sub { $_[0] ? 'Not safe' : 'Safe' } ],
+ [ img_nsfw => serialize => sub { $_[0] ? 'Not safe' : 'Safe' } ],
);
}
@@ -231,13 +235,13 @@ sub _producers {
my @lang = grep !$lang{$_}++, map @{$_->{languages}}, @$r;
Tr ++$$i % 2 ? (class => 'odd') : ();
- td 'Producers';
+ td mt '_vnpage_producers';
td;
for my $l (@lang) {
my %p = map { $_->{id} => $_ } map @{$_->{producers}}, grep grep($_ eq $l, @{$_->{languages}}), @$r;
my @p = values %p;
next if !@p;
- cssicon "lang $l", $self->{languages}{$l};
+ cssicon "lang $l", mt "_lang_$l";
for (@p) {
a href => "/p$_->{id}", title => $_->{original}||$_->{name}, shorten $_->{name}, 30;
txt ' & ' if $_ != $p[$#p];
@@ -258,7 +262,7 @@ sub _relations {
Tr ++$$i % 2 ? (class => 'odd') : ();
- td 'Relations';
+ td mt '_vnpage_relations';
td class => 'relations';
dl;
for(sort keys %rel) {
@@ -280,14 +284,12 @@ sub _anime {
my($self, $i, $v) = @_;
Tr ++$$i % 2 ? (class => 'odd') : ();
- td 'Related anime';
+ td mt '_vnpage_anime';
td class => 'anime';
for (sort { ($a->{year}||9999) <=> ($b->{year}||9999) } @{$v->{anime}}) {
if(!$_->{lastfetch} || !$_->{year} || !$_->{title_romaji}) {
b;
- txt '[no information available at this time: ';
- a href => "http://anidb.net/a$_->{id}", $_->{id};
- txt ']';
+ lit mt '_vnpage_anime_noinfo', $_->{id}, "http://anidb.net/a$_->{id}";
end;
} else {
b;
@@ -320,25 +322,25 @@ sub _useroptions {
my $wish = $self->dbWishListGet(uid => $self->authInfo->{id}, vid => $v->{id})->[0];
Tr ++$$i % 2 ? (class => 'odd') : ();
- td 'User options';
+ td mt '_vnpage_uopt';
td;
if($vote || !$wish) {
Select id => 'votesel';
- option $vote ? "your vote: $vote->{vote}" : 'not voted yet';
- optgroup label => $vote ? 'Change vote' : 'Vote';
- option value => $_, "$_ ($self->{votes}[$_-1])" for (reverse 1..10);
+ option $vote ? mt '_vnpage_uopt_voted', $vote->{vote} : mt '_vnpage_uopt_novote';
+ optgroup label => $vote ? mt '_vnpage_uopt_changevote' : mt '_vnpage_uopt_dovote';
+ option value => $_, "$_ (".mt("_vote_$_").')' for (reverse 1..10);
end;
- option value => -1, 'revoke' if $vote;
+ option value => -1, mt '_vnpage_uopt_delvote' if $vote;
end;
br;
}
if(!$vote || $wish) {
Select id => 'wishsel';
- option $wish ? "wishlist: $self->{wishlist_status}[$wish->{wstat}]" : 'not on your wishlist';
- optgroup label => $wish ? 'Change status' : 'Add to wishlist';
- option value => $_, $self->{wishlist_status}[$_] for (0..$#{$self->{wishlist_status}});
+ option $wish ? mt '_vnpage_uopt_wishlisted', mt '_wish_'.$wish->{wstat} : mt '_vnpage_uopt_nowish';
+ optgroup label => $wish ? mt '_vnpage_uopt_changewish' : mt '_vnpage_uopt_addwish';
+ option value => $_, mt "_wish_$_" for (@{$self->{wishlist_status}});
end;
- option value => -1, 'remove from wishlist';
+ option value => -1, mt '_vnpage_uopt_delwish';
end;
}
end;
@@ -350,10 +352,10 @@ sub _releases {
my($self, $v, $r) = @_;
div class => 'mainbox releases';
- a class => 'addnew', href => "/v$v->{id}/add", 'add release';
- h1 'Releases';
+ a class => 'addnew', href => "/v$v->{id}/add", mt '_vnpage_rel_add';
+ h1 mt '_vnpage_rel';
if(!@$r) {
- p 'We don\'t have any information about releases of this visual novel yet...';
+ p mt '_vnpage_rel_none';
end;
return;
}
@@ -372,24 +374,24 @@ sub _releases {
for my $l (@lang) {
Tr class => 'lang';
td colspan => 6;
- cssicon "lang $l", $self->{languages}{$l};
- txt $self->{languages}{$l};
+ cssicon "lang $l", mt "_lang_$l";
+ txt mt "_lang_$l";
end;
end;
for my $rel (grep grep($_ eq $l, @{$_->{languages}}), @$r) {
Tr;
- td class => 'tc1'; lit datestr $rel->{released}; end;
+ td class => 'tc1'; lit $self->{l10n}->datestr($rel->{released}); end;
td class => 'tc2', $rel->{minage} < 0 ? '' : $self->{age_ratings}{$rel->{minage}}[0];
td class => 'tc3';
for (sort @{$rel->{platforms}}) {
next if $_ eq 'oth';
- cssicon $_, $self->{platforms}{$_};
+ cssicon $_, mt "_plat_$_";
}
- cssicon lc(substr($self->{release_types}[$rel->{type}],0,3)), $self->{release_types}[$rel->{type}];
+ cssicon "rt$rel->{type}", mt "_rtype_$rel->{type}";
end;
td class => 'tc4';
a href => "/r$rel->{id}", title => $rel->{original}||$rel->{title}, $rel->{title};
- b class => 'grayedout', ' (patch)' if $rel->{patch};
+ b class => 'grayedout', ' '.mt '_vnpage_rel_patch' if $rel->{patch};
end;
td class => 'tc5';
if($self->authInfo->{id}) {
@@ -403,7 +405,7 @@ sub _releases {
td class => 'tc6';
if($rel->{website}) {
a href => $rel->{website}, rel => 'nofollow';
- cssicon 'ext', 'External link';
+ cssicon 'ext', mt '_vnpage_rel_extlink';
end;
} else {
txt ' ';
@@ -423,22 +425,22 @@ sub _screenshots {
if(grep $_->{nsfw}, @{$v->{screenshots}}) {
p class => 'nsfwtoggle';
- lit sprintf 'Showing <i id="nsfwshown">%d</i> out of %d screenshots, ',
- $self->authInfo->{show_nsfw} ? scalar @{$v->{screenshots}} : scalar grep(!$_->{nsfw}, @{$v->{screenshots}}),
+ lit mt '_vnpage_scr_showing',
+ sprintf('<i id="nsfwshown">%d</i>', $self->authInfo->{show_nsfw} ? scalar @{$v->{screenshots}} : scalar grep(!$_->{nsfw}, @{$v->{screenshots}})),
scalar @{$v->{screenshots}};
- a href => '#', id => "nsfwhide", 'show/hide NSFW';
- txt '.';
+ txt " ";
+ a href => '#', id => "nsfwhide", mt '_vnpage_scr_nsfwhide';
end;
}
- h1 'Screenshots';
+ h1 mt '_vnpage_scr';
table;
for my $rel (@$r) {
my @scr = grep $_->{rid} && $rel->{id} == $_->{rid}, @{$v->{screenshots}};
next if !@scr;
Tr class => 'rel';
td colspan => 5;
- cssicon "lang $_", $self->{languages}{$_} for (@{$rel->{languages}});
+ cssicon "lang $_", mt "_lang_$_" for (@{$rel->{languages}});
txt $rel->{title};
end;
end;
@@ -448,7 +450,7 @@ sub _screenshots {
div $_->{nsfw} ? (class => 'nsfw'.(!$self->authInfo->{show_nsfw} ? ' hidden' : '')) : ();
a href => sprintf('%s/sf/%02d/%d.jpg', $self->{url_static}, $_->{id}%100, $_->{id}),
rel => "iv:$_->{width}x$_->{height}:scr", $_->{nsfw} && !$self->authInfo->{show_nsfw} ? (class => 'hidden') : ();
- img src => sprintf('%s/st/%02d/%d.jpg', $self->{url_static}, $_->{id}%100, $_->{id}), alt => "Screenshot #$_->{id}";
+ img src => sprintf('%s/st/%02d/%d.jpg', $self->{url_static}, $_->{id}%100, $_->{id}), alt => mt '_vnpage_scr_num', $_->{id};
end;
end;
}
@@ -463,11 +465,11 @@ sub _screenshots {
sub _stats {
my($self, $v) = @_;
- my $stats = $self->dbVoteStats(vid => $v->{id});
+ my $stats = $self->dbVoteStats(vid => $v->{id}, 1);
div class => 'mainbox';
- h1 'User stats';
+ h1 mt '_vnpage_stats';
if(!grep $_ > 0, @$stats) {
- p "Nobody has voted on this visual novel yet...";
+ p mt '_vnpage_stats_none';
} else {
$self->htmlVoteStats(v => $v, $stats);
}
diff --git a/lib/VNDB/L10N.pm b/lib/VNDB/L10N.pm
new file mode 100644
index 00000000..d4ff872c
--- /dev/null
+++ b/lib/VNDB/L10N.pm
@@ -0,0 +1,189 @@
+
+use strict;
+use warnings;
+
+{
+ package VNDB::L10N;
+ use base 'Locale::Maketext';
+
+ sub fallback_languages { ('en') };
+
+ # used for the language switch interface, language tags must
+ # be the same as in the languages hash in global.pl
+ sub languages { ('en', 'ru') }
+
+ sub maketext {
+ my $r = eval { shift->SUPER::maketext(@_) };
+ return $r if defined $r;
+ warn "maketext failed for '@_': $@\n";
+ return $_[0]||''; # not quite sure we want this
+ }
+
+ # can be called as either a subroutine or a method
+ sub loadfile {
+ my %lang = (
+ en => \%VNDB::L10N::en::Lexicon,
+ ru => \%VNDB::L10N::ru::Lexicon,
+ );
+
+ open my $F, '<:utf8', $VNDB::ROOT.'/data/lang.txt' or die "Opening language file: $!\n";
+ my($empty, $line, $key, $lang) = (0, 0);
+ while(<$F>) {
+ chomp;
+ $line++;
+
+ # ignore intro
+ if(!defined $key) {
+ $key = 0 if /^\/intro$/;
+ next;
+ }
+ # ignore comments
+ next if /^#/;
+ # key
+ if(/^:(.+)$/) {
+ $key = $1;
+ $lang = undef;
+ $empty = 0;
+ next;
+ }
+ # locale string
+ if(/^([a-z_-]{2,7})[ *]: (.+)$/) {
+ $lang = $1;
+ die "Unknown language on #$line: $lang\n" if !$lang{$lang};
+ die "Unknown key for locale on #$line\n" if !$key;
+ $lang{$lang}{$key} = $2;
+ $empty = 0;
+ next;
+ }
+ # multi-line locale string
+ if($lang && /^\s+([^\s].*)$/) {
+ $lang{$lang}{$key} .= ''.("\n"x$empty)."\n$1";
+ $empty = 0;
+ next;
+ }
+ # empty string (count them in case they're part of a multi-line locale string)
+ if(/^\s*$/) {
+ $empty++;
+ next;
+ }
+ # something we didn't expect
+ die "Don't know what to do with line $line\n" unless /^([a-z_-]{2,7})[ *]:/;
+ }
+ close $F;
+ }
+}
+
+
+{
+ package VNDB::L10N::en;
+ use base 'VNDB::L10N';
+ use POSIX 'strftime';
+ use YAWF 'xml_escape';
+ our %Lexicon;
+
+ sub quant {
+ return $_[1]==1 ? $_[2] : $_[3];
+ }
+
+ # Argument: unix timestamp
+ # Returns: age
+ sub age {
+ my $a = time-$_[1];
+ return sprintf '%d %s ago',
+ $a > 60*60*24*365*2 ? ( $a/60/60/24/365, 'years' ) :
+ $a > 60*60*24*(365/12)*2 ? ( $a/60/60/24/(365/12), 'months' ) :
+ $a > 60*60*24*7*2 ? ( $a/60/60/24/7, 'weeks' ) :
+ $a > 60*60*24*2 ? ( $a/60/60/24, 'days' ) :
+ $a > 60*60*2 ? ( $a/60/60, 'hours' ) :
+ $a > 60*2 ? ( $a/60, 'min' ) :
+ ( $a, 'sec' );
+ }
+
+ # argument: unix timestamp and optional format (compact/full)
+ # return value: yyyy-mm-dd
+ # (maybe an idea to use cgit-style ages for recent timestamps)
+ sub date {
+ my($s, $t, $f) = @_;
+ return strftime '%Y-%m-%d', gmtime $t if !$f || $f eq 'compact';
+ return strftime '%Y-%m-%d at %R', gmtime $t;
+ }
+
+ # argument: database release date format (yyyymmdd)
+ # y = 0000 -> unknown
+ # y = 9999 -> TBA
+ # m = 99 -> month+day unknown
+ # d = 99 -> day unknown
+ # return value: (unknown|TBA|yyyy|yyyy-mm|yyyy-mm-dd)
+ # if date > now: <b class="future">str</b>
+ sub datestr {
+ my $self = shift;
+ my $date = sprintf '%08d', shift||0;
+ my $future = $date > strftime '%Y%m%d', gmtime;
+ my($y, $m, $d) = ($1, $2, $3) if $date =~ /^([0-9]{4})([0-9]{2})([0-9]{2})$/;
+
+ my $str = $y == 0 ? 'unknown' : $y == 9999 ? 'TBA' :
+ $m == 99 ? sprintf('%04d', $y) :
+ $d == 99 ? sprintf('%04d-%02d', $y, $m) :
+ sprintf('%04d-%02d-%02d', $y, $m, $d);
+
+ return $str if !$future;
+ return qq|<b class="future">$str</b>|;
+ }
+
+ # Arguments: (uid, username), or a hashref containing that info
+ sub userstr {
+ my $self = shift;
+ my($id,$n) = ref($_[0])eq'HASH'?($_[0]{uid}||$_[0]{requester}, $_[0]{username}):@_;
+ return !$id ? '[deleted]' : '<a href="/u'.$id.'">'.$n.'</a>';
+ }
+
+ # Arguments: index, @list. returns $list[index]
+ sub index {
+ shift;
+ return $_[shift||0];
+ }
+
+ # Shortcut for <a href="arg1">arg2</a>
+ sub url {
+ return sprintf '<a href="%s">%s</a>', xml_escape($_[1]), xml_escape($_[2]);
+ }
+
+ # <br />
+ sub br { return '<br />' }
+}
+
+
+
+{
+ package VNDB::L10N::ru;
+ use base 'VNDB::L10N::en';
+ our %Lexicon;
+
+ sub quant {
+ my($self, $num, $single, $couple, $lots) = @_;
+ return $single if ($num % 10) == 1 && ($num % 100) != 11;
+ return $couple if ($num % 10) >= 2 && ($num % 10) <= 4 && !(($num % 100) >= 12 && ($num % 100) <= 14);
+ return $lots;
+ }
+
+ sub age {
+ my $self = shift;
+ my $a = time-shift;
+ use utf8;
+ my @l = (
+ $a > 60*60*24*365*2 ? ( $a/60/60/24/365, 'год', 'года', 'лет' ) :
+ $a > 60*60*24*(365/12)*2 ? ( $a/60/60/24/(365/12), 'месяц', 'месяца', 'месяцев' ) :
+ $a > 60*60*24*7*2 ? ( $a/60/60/24/7, 'неделя', 'недели', 'недель' ) :
+ $a > 60*60*24*2 ? ( $a/60/60/24, 'день', 'дня', 'дней' ) :
+ $a > 60*60*2 ? ( $a/60/60, 'час', 'часа', 'часов' ) :
+ $a > 60*2 ? ( $a/60, 'минута', 'минуты', 'минут' ) :
+ ( $a, 'секунда', 'секунды', 'секунд' )
+ );
+ return sprintf '%d %s назад', $l[0], $self->quant(@l);
+ }
+
+}
+
+
+1;
+
diff --git a/lib/VNDB/Util/Auth.pm b/lib/VNDB/Util/Auth.pm
index ad225d92..c4daffd9 100644
--- a/lib/VNDB/Util/Auth.pm
+++ b/lib/VNDB/Util/Auth.pm
@@ -83,7 +83,7 @@ sub authInfo {
sub authCan {
my($self, $act) = @_;
my $r = $self->{_auth}{rank}||0;
- return scalar grep $_ eq $act, @{$self->{user_ranks}[$r]}[1..$#{$self->{user_ranks}[$r]}];
+ return scalar grep $_ eq $act, @{$self->{user_ranks}[$r]}[0..$#{$self->{user_ranks}[$r]}];
}
diff --git a/lib/VNDB/Util/CommonHTML.pm b/lib/VNDB/Util/CommonHTML.pm
index 981edfe8..176f2960 100644
--- a/lib/VNDB/Util/CommonHTML.pm
+++ b/lib/VNDB/Util/CommonHTML.pm
@@ -29,48 +29,48 @@ sub htmlMainTabs {
ul class => 'maintabs';
if($type =~ /[uvrp]/) {
li $sel eq 'hist' ? (class => 'tabselected') : ();
- a href => "/$id/hist", 'history';
+ a href => "/$id/hist", mt '_mtabs_hist';
end;
}
if($type =~ /[uvp]/) {
my $cnt = $self->dbThreadCount($type, $obj->{id});
li $sel eq 'disc' ? (class => 'tabselected') : ();
- a href => "/t/$id", "discussions ($cnt)";
+ a href => "/t/$id", mt '_mtabs_discuss', $cnt;
end;
}
if($type eq 'u') {
li $sel eq 'posts' ? (class => 'tabselected') : ();
- a href => "/$id/posts", 'posts';
+ a href => "/$id/posts", mt '_mtabs_posts';
end;
}
- if($type eq 'u' && $obj->{show_list}) {
+ if($type eq 'u' && ($obj->{show_list} || $self->authCan('usermod'))) {
li $sel eq 'wish' ? (class => 'tabselected') : ();
- a href => "/$id/wish", 'wishlist';
+ a href => "/$id/wish", mt '_mtabs_wishlist';
end;
li $sel eq 'list' ? (class => 'tabselected') : ();
- a href => "/$id/list", 'list';
+ a href => "/$id/list", mt '_mtabs_list';
end;
}
if($type eq 'u') {
li $sel eq 'tags' ? (class => 'tabselected') : ();
- a href => "/$id/tags", 'tags';
+ a href => "/$id/tags", mt '_mtabs_tags';
end;
}
if($type eq 'v' && $self->authCan('tag') && !$obj->{hidden}) {
li $sel eq 'tagmod' ? (class => 'tabselected') : ();
- a href => "/$id/tagmod", 'modify tags';
+ a href => "/$id/tagmod", mt '_mtabs_tagmod';
end;
}
if($type eq 'r' && $self->authCan('edit')) {
li $sel eq 'copy' ? (class => 'tabselected') : ();
- a href => "/$id/copy", 'copy';
+ a href => "/$id/copy", mt '_mtabs_copy';
end;
}
@@ -79,31 +79,31 @@ sub htmlMainTabs {
|| $type eq 'g' && $self->authCan('tagmod')
) {
li $sel eq 'edit' ? (class => 'tabselected') : ();
- a href => "/$id/edit", 'edit';
+ a href => "/$id/edit", mt '_mtabs_edit';
end;
}
if($type =~ /[vrp]/ && $self->authCan('del')) {
li;
- a href => "/$id/hide", $obj->{hidden} ? 'unhide' : 'hide';
+ a href => "/$id/hide", mt $obj->{hidden} ? '_mtabs_unhide' : '_mtabs_hide';
end;
}
if($type =~ /[vrp]/ && $self->authCan('lock')) {
li;
- a href => "/$id/lock", $obj->{locked} ? 'unlock' : 'lock';
+ a href => "/$id/lock", mt $obj->{locked} ? '_mtabs_unlock' : '_mtabs_lock';
end;
}
if($type eq 'u' && $self->authCan('usermod')) {
li $sel eq 'del' ? (class => 'tabselected') : ();
- a href => "/$id/del", 'del';
+ a href => "/$id/del", mt '_mtabs_del';
end;
}
if($type eq 'v' && $obj->{rgraph}) {
li $sel eq 'rg' ? (class => 'tabselected') : ();
- a href => "/$id/rg", 'relations';
+ a href => "/$id/rg", mt '_mtabs_relations';
end;
}
@@ -117,19 +117,16 @@ sub htmlMainTabs {
# generates a full error page, including header and footer
sub htmlDenied {
my $self = shift;
- $self->htmlHeader(title => 'Access Denied');
+ $self->htmlHeader(title => mt '_denied_title');
div class => 'mainbox';
- h1 'Access Denied';
+ h1 mt '_denied_title';
div class => 'warning';
if(!$self->authInfo->{id}) {
- h2 'You need to be logged in to perform this action.';
- p;
- lit 'Please <a href="/u/login">login</a>, or <a href="/u/register">create an account</a> '
- .'if you don\'t have one yet.';
- end;
+ h2 mt '_denied_needlogin_title';
+ p; lit mt '_denied_needlogin_msg'; end;
} else {
- h2 "You are not allowed to perform this action.";
- p 'It seems you don\'t have the proper rights to perform the action you wanted to perform...';
+ h2 mt '_denied_noaccess_title';
+ p mt '_denied_noaccess_msg';
}
end;
end;
@@ -147,10 +144,9 @@ sub htmlHiddenMessage {
div class => 'mainbox';
h1 $obj->{title}||$obj->{name};
div class => 'warning';
- h2 'Item deleted';
+ h2 mt '_hiddenmsg_title';
p;
- lit qq|This item has been deleted from the database, File a request on the|
- .qq| <a href="/t/$board">discussion board</a> to undelete this page.|;
+ lit mt '_hiddenmsg_msg', "/t/$board";
end;
end;
end;
@@ -240,12 +236,12 @@ sub htmlBrowseNavigate {
ul class => 'maintabs ' . ($al eq 't' ? 'notfirst' : 'bottom');
if($p > 1) {
li class => 'left';
- a href => $url.($p-1), '<- previous';
+ a href => $url.($p-1), '<- '.mt '_browse_previous';
end;
}
if($np) {
li;
- a href => $url.($p+1), 'next ->';
+ a href => $url.($p+1), mt('_browse_next').' ->';
end;
}
end;
@@ -265,12 +261,12 @@ sub htmlBrowseNavigate {
sub htmlRevision {
my($self, $type, $old, $new, @fields) = @_;
div class => 'mainbox revision';
- h1 'Revision '.$new->{rev};
+ h1 mt '_revision_title', $new->{rev};
# previous/next revision links
- a class => 'prev', href => sprintf('/%s%d.%d', $type, $new->{id}, $new->{rev}-1), '<- earlier revision'
+ a class => 'prev', href => sprintf('/%s%d.%d', $type, $new->{id}, $new->{rev}-1), '<- '.mt '_revision_previous'
if $new->{rev} > 1;
- a class => 'next', href => sprintf('/%s%d.%d', $type, $new->{id}, $new->{rev}+1), 'later revision ->'
+ a class => 'next', href => sprintf('/%s%d.%d', $type, $new->{id}, $new->{rev}+1), mt('_revision_next').' ->'
if $new->{cid} != $new->{latest};
p class => 'center';
a href => "/$type$new->{id}", "$type$new->{id}";
@@ -279,11 +275,11 @@ sub htmlRevision {
# no previous revision, just show info about the revision itself
if(!$old) {
div;
- revheader($type, $new);
+ revheader($self, $type, $new);
br;
- b 'Edit summary:';
+ b mt '_revision_new_summary';
br; br;
- lit bb2html($new->{comments})||'[no summary]';
+ lit bb2html($new->{comments})||'-';
end;
}
@@ -293,40 +289,37 @@ sub htmlRevision {
thead;
Tr;
td; lit '&nbsp;'; end;
- td; revheader($type, $old); end;
- td; revheader($type, $new); end;
+ td; revheader($self, $type, $old); end;
+ td; revheader($self, $type, $new); end;
end;
Tr;
td; lit '&nbsp;'; end;
td colspan => 2;
- b 'Edit summary of revision '.$new->{rev}.':';
+ b mt '_revision_edit_summary', $new->{rev};
br; br;
- lit bb2html($new->{comments})||'[no summary]';
+ lit bb2html($new->{comments})||'-';
end;
end;
end;
my $i = 1;
- revdiff(\$i, $old, $new, @$_) for (@fields);
+ revdiff(\$i, $type, $old, $new, @$_) for (@fields);
end;
}
end;
}
sub revheader { # type, obj
- my($type, $obj) = @_;
- b 'Revision '.$obj->{rev};
+ my($self, $type, $obj) = @_;
+ b mt '_revision_title', $obj->{rev};
txt ' (';
- a href => "/$type$obj->{id}.$obj->{rev}/edit", 'edit';
+ a href => "/$type$obj->{id}.$obj->{rev}/edit", mt '_mtabs_edit';
txt ')';
br;
- txt 'By ';
- lit userstr($obj);
- txt ' on ';
- lit date $obj->{added}, 'full';
+ lit mt '_revision_user_date', $obj, $obj->{added};
}
sub revdiff {
- my($i, $old, $new, $short, $name, %o) = @_;
+ my($i, $type, $old, $new, $short, %o) = @_;
$o{serialize} ||= $o{htmlize};
$o{diff}++ if $o{split};
@@ -358,11 +351,11 @@ sub revdiff {
$ser2 = xml_escape $ser2;
}
- $ser1 = '[empty]' if !$ser1 && $ser1 ne '0';
- $ser2 = '[empty]' if !$ser2 && $ser2 ne '0';
+ $ser1 = mt '_revision_emptyfield' if !$ser1 && $ser1 ne '0';
+ $ser2 = mt '_revision_emptyfield' if !$ser2 && $ser2 ne '0';
Tr $$i++ % 2 ? (class => 'odd') : ();
- td $name;
+ td mt "_revfield_${type}_$short";
td class => 'tcval'; lit $ser1; end;
td class => 'tcval'; lit $ser2; end;
end;
@@ -372,38 +365,36 @@ sub revdiff {
# Generates a generic message to show as the header of the edit forms
# Arguments: v/r/p, obj
sub htmlEditMessage {
- my($self, $type, $obj, $copy) = @_;
- my $full = {v => 'visual novel', r => 'release', p => 'producer'}->{$type};
+ my($self, $type, $obj, $title, $copy) = @_;
+ my $num = {v => 0, r => 1, p => 2}->{$type};
my $guidelines = {v => 2, r => 3, p => 4}->{$type};
div class => 'mainbox';
- h1 $obj ? ''.($copy ? 'Copy ':'Edit ').($obj->{name}||$obj->{title}) : "Add new $full";
+ h1 $title;
if($copy) {
div class => 'warning';
- h2 "You're not editing a release!";
+ h2 mt '_editmsg_copy_title';
p;
- txt "You're about to insert a new release into the database with information based on ";
- a href => "/$type$obj->{id}", $obj->{title};
- txt ". Hit the 'edit' tab on the right-top if you intended to edit the release instead of creating a new one.";
+ lit mt '_editmsg_copy_msg', sprintf '<a href="/%s%d">%s</a>', $type, $obj->{id}, xml_escape $obj->{title},
end;
end;
}
div class => 'notice';
- h2 'Before editing:';
+ h2 mt '_editmsg_msg_title';
ul;
- li; lit qq|Read the <a href="/d$guidelines">guidelines</a>!|; end;
+ li; lit mt '_editmsg_msg_guidelines', "/d$guidelines"; end;
if($obj) {
- li; lit qq|Check for any existing discussions on the <a href="/t/$type$obj->{id}">discussion board</a>|; end;
- li; lit qq|Browse the <a href="/$type$obj->{id}/hist">edit history</a> for any recent changes related to what you want to change.|; end;
+ li; lit mt '_editmsg_msg_discuss', $type eq 'r' ? "/t/v$obj->{vn}[0]{vid}" : "/t/$type$obj->{id}"; end;
+ li; lit mt '_editmsg_msg_history', "/$type$obj->{id}/hist"; end;
} elsif($type ne 'r') {
- li; lit qq|<a href="/$type/all">Search the database</a> to see if we already have information about this $full|; end;
+ li; lit mt '_editmsg_msg_search', "/$type/all", $num; end;
}
end;
end;
if($obj && $obj->{latest} != $obj->{cid}) {
div class => 'warning';
- h2 'Reverting';
- p qq|You are editing an old revision of this $full. If you save it, all changes made after this revision will be reverted!|;
+ h2 mt '_editmsg_revert_title';
+ p mt '_editmsg_revert_msg', $num;
end;
}
end;
@@ -417,13 +408,13 @@ sub htmlItemMessage {
my($self, $type, $obj) = @_;
if($obj->{locked}) {
- p class => 'locked', 'Locked for editing'
+ p class => 'locked', mt '_itemmsg_locked';
} elsif(!$self->authInfo->{id}) {
p class => 'locked';
- lit 'You need to be <a href="/u/login">logged in</a> to edit this page';
+ lit mt '_itemmsg_login', '/u/login';
end;
} elsif(!$self->authCan('edit')) {
- p class => 'locked', "You're not allowed to edit this page";
+ p class => 'locked', mt '_itemmsg_denied';
}
}
@@ -441,11 +432,11 @@ sub htmlVoteStats {
div class => 'votestats';
table class => 'votegraph';
thead; Tr;
- td colspan => 2, 'Vote graph';
+ td colspan => 2, mt '_votestats_title';
end; end;
tfoot; Tr;
- td colspan => 2, sprintf '%d vote%s total, average %.2f%s', $count, $count != 1 ? 's' : '', $total/$count,
- $type eq 'v' ? ' ('.$self->{votes}[ceil($total/$count-1)].')' : '';
+ td colspan => 2, mt('_votestats_sum', $count, sprintf('%.2f', $total/$count))
+ .($type eq 'v' ? ' ('.mt('_vote_'.ceil($total/$count-1)).')' : '');
end; end;
for (reverse 0..$#$stats) {
Tr;
@@ -464,11 +455,12 @@ sub htmlVoteStats {
order => 'date DESC',
what => $type eq 'v' ? 'user' : 'vn',
hide => $type eq 'v',
+ hide_ign => $type eq 'v',
);
if(@$recent) {
table class => 'recentvotes';
thead; Tr;
- td colspan => 3, 'Recent votes';
+ td colspan => 3, mt '_votestats_recent';
end; end;
for (0..$#$recent) {
Tr $_ % 2 == 0 ? (class => 'odd') : ();
@@ -480,7 +472,7 @@ sub htmlVoteStats {
}
end;
td $recent->[$_]{vote};
- td date $recent->[$_]{date};
+ td $self->{l10n}->date($recent->[$_]{date});
end;
}
end;
@@ -489,8 +481,8 @@ sub htmlVoteStats {
clearfloat;
if($type eq 'v') {
div;
- h3 'Popularity';
- p sprintf 'Ranked #%d out of %d with a score of %.2f.', $obj->{ranking}, $self->{stats}{vn}, $obj->{c_popularity}*100;
+ h3 mt '_votestats_pop_title';
+ p mt '_votestats_pop_sum', $obj->{ranking}, $self->{stats}{vn}, sprintf('%0.2f',$obj->{c_popularity}*100);
end;
}
end;
@@ -506,10 +498,10 @@ sub htmlHistory {
pageurl => $url,
class => 'history',
header => [
- sub { td colspan => 2, class => 'tc1', 'Rev.' },
- [ 'Date' ],
- [ 'User' ],
- sub { td; a href => '#', id => 'history_comments', 'expand'; txt 'Page'; end; }
+ sub { td colspan => 2, class => 'tc1', mt '_hist_col_rev' },
+ [ mt '_hist_col_date' ],
+ [ mt '_hist_col_user' ],
+ sub { td; a href => '#', id => 'history_comments', 'expand'; txt mt '_hist_col_page'; end; }
],
row => sub {
my($s, $n, $i) = @_;
@@ -523,9 +515,9 @@ sub htmlHistory {
td class => 'tc1_2';
a href => $revurl, ".$i->{rev}";
end;
- td class => 'tc2', date $i->{added};
+ td class => 'tc2', $self->{l10n}->date($i->{added});
td class => 'tc3';
- lit userstr($i);
+ lit $self->{l10n}->userstr($i);
end;
td;
a href => $revurl, title => $i->{ioriginal}, shorten $i->{ititle}, 80;
@@ -548,14 +540,14 @@ sub htmlSearchBox {
fieldset class => 'search';
p class => 'searchtabs';
- a href => '/v/all', $sel eq 'v' ? (class => 'sel') : (), 'Visual novels';
- a href => '/r', $sel eq 'r' ? (class => 'sel') : (), 'Releases';
- a href => '/p/all', $sel eq 'p' ? (class => 'sel') : (), 'Producers';
- a href => '/g', $sel eq 'g' ? (class => 'sel') : (), 'Tags';
- a href => '/u/all', $sel eq 'u' ? (class => 'sel') : (), 'Users';
+ a href => '/v/all', $sel eq 'v' ? (class => 'sel') : (), mt '_searchbox_vn';
+ a href => '/r', $sel eq 'r' ? (class => 'sel') : (), mt '_searchbox_releases';
+ a href => '/p/all', $sel eq 'p' ? (class => 'sel') : (), mt '_searchbox_producers';
+ a href => '/g', $sel eq 'g' ? (class => 'sel') : (), mt '_searchbox_tags';
+ a href => '/u/all', $sel eq 'u' ? (class => 'sel') : (), mt '_searchbox_users';
end;
input type => 'text', name => 'q', id => 'q', class => 'text', value => $v;
- input type => 'submit', class => 'submit', value => 'Search!';
+ input type => 'submit', class => 'submit', value => mt '_searchbox_submit';
end;
}
diff --git a/lib/VNDB/Util/FormHTML.pm b/lib/VNDB/Util/FormHTML.pm
index f8047c4c..2882b4c4 100644
--- a/lib/VNDB/Util/FormHTML.pm
+++ b/lib/VNDB/Util/FormHTML.pm
@@ -6,58 +6,11 @@ use warnings;
use YAWF ':html';
use Exporter 'import';
use POSIX 'strftime';
+use VNDB::Func;
our @EXPORT = qw| htmlFormError htmlFormPart htmlForm |;
-# form error messages
-my %formerr_names = (
- alias => 'Aliases',
- anime => 'Anime',
- desc => 'Description',
- description => 'Description',
- editsum => 'Edit summary',
- gtin => 'JAN/EAN/UPC',
- lang => 'Language',
- language => 'Language',
- length => 'Length',
- l_wp => 'Wikipedia link',
- l_encubed => 'Novelnews link',
- l_renai => 'Renai.us link',
- l_vnn => 'V-N.net link',
- mail => 'Email',
- media => 'Media',
- minage => 'Age rating',
- msg => 'Message',
- name => 'Name',
- notes => 'Notes',
- original => 'Original',
- platforms => 'Platforms',
- producers => 'Producers',
- released => 'Release date',
- boards => 'Boards',
- title => 'Title',
- type => 'Type',
- usrname => 'Username',
- usrpass => 'Password',
- usrpass2 => 'Password (confirm)',
- vn => 'Visual novels',
- website => 'Website',
-);
-my %formerr_exeptions = (
- login_failed => 'Invalid username or password',
- nomail => 'No user found with that email address',
- passmatch => 'Passwords do not match',
- usrexists => 'Someone already has this username, please choose something else',
- mailexists => 'Someone already registered with that email address',
- noimage => 'Image must be in JPEG or PNG format',
- toolarge => 'Image is too large, only 500kB allowed',
- oneaday => 'You can only register one account from the same IP within 24 hours',
- nochanges => 'No changes, please don\'t create an entry that is fully -identical- to another',
- doublepost => 'Please wait 30 seconds before making another post',
-);
-
-
# Displays friendly error message when form validation failed
# Argument is the return value of formValidate, and an optional
# argument indicating whether we should create a special mainbox
@@ -67,40 +20,25 @@ sub htmlFormError {
return if !$frm->{_err};
if($mainbox) {
div class => 'mainbox';
- h1 'Error';
+ h1 mt '_formerr_title';
}
div class => 'warning';
- h2 'Form could not be sent:';
+ h2 mt '_formerr_subtitle';
ul;
for my $e (@{$frm->{_err}}) {
if(!ref $e) {
- li $formerr_exeptions{$e};
+ li mt '_formerr_e_'.$e;
next;
}
my($field, $type, $rule) = @$e;
- $field = $formerr_names{$field}||$field;
- li sprintf '%s is a required field!', $field if $type eq 'required';
- li sprintf '%s should have at least %d characters', $field, $rule if $type eq 'minlength';
- li sprintf '%s: only %d characters allowed', $field, $rule if $type eq 'maxlength';
- li sprintf '%s must be one of the following: %s', $field, join ', ', @$rule if $type eq 'enum';
- li sprintf 'Wrong board: %s', $rule if $type eq 'wrongboard';
- if($type eq 'tagexists') {
- li;
- lit $rule->{state} != 1 ? qq|Tag <a href="/g$rule->{id}">$rule->{name}</a> already exists!|
- : qq|A tag <a href="/g$rule->{id}">with the same name</a> has been deleted in the past,|
- .qq| please use <a href="/t/db">the discussion board</a> if you want it to be re-added.|;
- end;
- }
+ li mt '_formerr_required', $field if $type eq 'required';
+ li mt '_formerr_minlength', $field, $rule if $type eq 'minlength';
+ li mt '_formerr_maxlength', $field, $rule if $type eq 'maxlength';
+ li mt '_formerr_enum', $field, join ', ', @$rule if $type eq 'enum';
+ li mt '_formerr_wrongboard', $rule if $type eq 'wrongboard';
+ li mt '_formerr_tagexists', "/g$rule->{id}", $rule->{name} if $type eq 'tagexists';
li $rule->[1] if $type eq 'func' || $type eq 'regex';
- if($type eq 'template') {
- li sprintf
- $rule eq 'mail' ? 'Invalid email address' :
- $rule eq 'url' ? '%s: Invalid URL' :
- $rule eq 'asciiprint' ? '%s may only contain ASCII characters' :
- $rule eq 'int' ? '%s: Not a valid number' :
- $rule eq 'pname' ? '%s can only contain lowercase alphanumberic characters and a hyphen, and must start with a character' : '',
- $field;
- }
+ li mt "_formerr_tpl_$rule", $field if $type eq 'template';
}
end;
end;
@@ -246,21 +184,20 @@ sub htmlForm {
if(@subs > 2) {
ul class => 'maintabs notfirst', id => 'jt_select';
for (0..$#subs/2) {
- (my $short = lc $subs[$_*2]) =~ s/[^\w\d]+/_/g;
li class => 'left';
- a href => "#$short", id => "jt_sel_$short", $subs[$_*2];
+ a href => "#$subs[$_*2]", id => "jt_sel_$subs[$_*2]", $subs[$_*2+1][0];
end;
}
li class => 'left';
- a href => '#all', id => 'jt_sel_all', 'All items';
+ a href => '#all', id => 'jt_sel_all', mt '_form_tab_all';
end;
end;
}
# form subs
- while(my($name, $parts) = (shift(@subs), shift(@subs))) {
- last if !$name || !$parts;
- (my $short = lc $name) =~ s/[^\w\d]+/_/g;
+ while(my($short, $parts) = (shift(@subs), shift(@subs))) {
+ last if !$short || !$parts;
+ my $name = shift @$parts;
div class => 'mainbox', id => 'jt_box_'.$short;
h1 $name;
fieldset;
@@ -273,23 +210,26 @@ sub htmlForm {
}
# edit summary / submit button
- div class => 'mainbox';
- fieldset class => 'submit';
- if($options->{editsum}) {
- (my $txt = $options->{frm}{editsum}||'') =~ s/&/&amp;/;
- $txt =~ s/</&lt;/;
- $txt =~ s/>/&gt;/;
- h2 'Edit summary';
- textarea name => 'editsum', id => 'editsum', rows => 4, cols => 50;
- lit $txt;
- end;
- br;
- }
- b "Don't forget! -> " if $options->{hitsubmit};
- input type => 'submit', value => 'Submit', class => 'submit';
- b ' <-' if $options->{hitsubmit};
- end;
- end;
+ if(!$options->{nosubmit}) {
+ div class => 'mainbox';
+ fieldset class => 'submit';
+ if($options->{editsum}) {
+ (my $txt = $options->{frm}{editsum}||'') =~ s/&/&amp;/;
+ $txt =~ s/</&lt;/;
+ $txt =~ s/>/&gt;/;
+ h2;
+ txt mt '_form_editsum';
+ b class => 'standout', ' ('.mt('_inenglish').')';
+ end;
+ textarea name => 'editsum', id => 'editsum', rows => 4, cols => 50;
+ lit $txt;
+ end;
+ br;
+ }
+ input type => 'submit', value => mt('_form_submit'), class => 'submit';
+ end;
+ end;
+ }
end;
}
diff --git a/lib/VNDB/Util/LayoutHTML.pm b/lib/VNDB/Util/LayoutHTML.pm
index b5813330..85971ba9 100644
--- a/lib/VNDB/Util/LayoutHTML.pm
+++ b/lib/VNDB/Util/LayoutHTML.pm
@@ -38,7 +38,7 @@ sub htmlHeader { # %options->{ title, js, noindex, search }
div id => 'bgright', ' ';
div id => 'header';
h1;
- a href => '/', lc $self->{site_title};
+ a href => '/', lc mt '_site_title';
end;
end;
@@ -54,24 +54,34 @@ sub _menu {
div id => 'menulist';
div class => 'menubox';
- h2 'Menu';
+ h2;
+ span;
+ for (grep $self->{l10n}->language_tag() ne $_, $self->{l10n}->languages()) {
+ a href => "?l10n=$_";
+ cssicon "lang $_", mt "_lang_$_"; # NOTE: should actually be in the destination language...
+ end;
+ }
+ end;
+ txt mt '_menu';
+ end;
div;
- a href => '/', 'Home'; br;
- a href => '/v/all', 'Visual novels'; br;
- a href => '/r', 'Releases'; br;
- a href => '/p/all', 'Producers'; br;
- a href => '/g', 'Tags'; br;
- a href => '/u/all', 'Users'; br;
- a href => '/hist', 'Recent changes'; br;
- a href => '/t', 'Discussion board'; br;
- a href => '/d6', 'FAQ'; br;
+ a href => '/', mt '_menu_home'; br;
+ a href => '/v/all', mt '_menu_vn'; br;
+ a href => '/r', mt '_menu_releases'; br;
+ a href => '/p/all', mt '_menu_producers'; br;
+ a href => '/g', mt '_menu_tags'; br;
+ a href => '/u/all', mt '_menu_users'; br;
+ a href => '/hist', mt '_menu_recent_changes'; br;
+ a href => '/t', mt '_menu_discussion_board'; br;
+ a href => '/d6', mt '_menu_faq'; br;
+ a href => '/v/rand', mt '_menu_randvn'; br;
a href => 'irc://irc.synirc.net/vndb', '#vndb';
- lit ' (<a href="http://cgiirc.synirc.net/?chan=%23vndb">webchat</a>)';
+ lit ' (<a href="http://cgiirc.synirc.net/?chan=%23vndb">'.mt('_menu_webchat').'</a>)';
end;
form action => '/v/all', method => 'get', id => 'search';
fieldset;
legend 'Search';
- input type => 'text', class => 'text', id => 'sq', name => 'sq', value => $o{search}||'search';
+ input type => 'text', class => 'text', id => 'sq', name => 'sq', value => $o{search}||mt('_menu_emptysearch');
input type => 'submit', class => 'submit', value => 'Search';
end;
end;
@@ -82,24 +92,25 @@ sub _menu {
my $uid = sprintf '/u%d', $self->authInfo->{id};
h2;
a href => $uid, ucfirst $self->authInfo->{username};
- txt ' ('.$self->{user_ranks}[$self->authInfo->{rank}][0].')';
+ # note: user ranks aren't TL'ed (but might be in the future, hmm)
+ txt ' ('.mt('_urank_'.$self->authInfo->{rank}).')';
end;
div;
- a href => "$uid/edit", 'My Profile'; br;
- a href => "$uid/list", 'My Visual Novel List'; br;
- a href => "$uid/wish", 'My Wishlist'; br;
- a href => "/t$uid", sprintf 'My Messages (%d)', $self->authInfo->{mymessages}; br;
- a href => "$uid/hist", 'My Recent Changes'; br;
- a href => "$uid/tags", 'My Tags'; br;
+ a href => "$uid/edit", mt '_menu_myprofile'; br;
+ a href => "$uid/list", mt '_menu_myvnlist'; br;
+ a href => "$uid/wish", mt '_menu_mywishlist'; br;
+ a href => "/t$uid", mt '_menu_mymessages', $self->authInfo->{mymessages}; br;
+ a href => "$uid/hist", mt '_menu_mychanges'; br;
+ a href => "$uid/tags", mt '_menu_mytags'; br;
br;
- a href => '/v/new', 'Add Visual Novel'; br;
- a href => '/p/new', 'Add Producer'; br;
+ a href => '/v/new', mt '_menu_addvn'; br;
+ a href => '/p/new', mt '_menu_addproducer'; br;
br;
- a href => '/u/logout', 'Logout';
+ a href => '/u/logout', mt '_menu_logout';
end;
} else {
h2;
- a href => '/u/login', 'Login';
+ a href => '/u/login', mt '_menu_login';
end;
div;
form action => '/nospam?/u/login', id => 'loginform', method => 'post';
@@ -107,32 +118,23 @@ sub _menu {
legend 'Login';
input type => 'text', class => 'text', id => 'username', name => 'usrname';
input type => 'password', class => 'text', id => 'userpass', name => 'usrpass';
- input type => 'submit', class => 'submit', value => 'Login';
+ input type => 'submit', class => 'submit', value => mt '_menu_login';
end;
end;
p;
- lit 'Need to <a href="/u/register">register</a>,<br />';
- lit 'or <a href="/u/newpass">forgot your password?</a>';
+ lit mt '_menu_loginmsg', '/u/register', '/u/newpass';
end;
end;
}
end;
- my @stats = (
- [ vn => 'Visual Novels' ],
- [ releases => 'Releases' ],
- [ producers => 'Producers' ],
- [ users => 'Users' ],
- [ threads => 'Threads' ],
- [ posts => 'Posts' ],
- );
div class => 'menubox';
- h2 'Database Statistics';
+ h2 mt '_menu_dbstats';
div;
dl;
- for (@stats) {
- dt $$_[1];
- dd $self->{stats}{$$_[0]};
+ for (qw|vn releases producers users threads posts|) {
+ dt mt "_menu_stat_$_";
+ dd $self->{stats}{$_};
}
end;
clearfloat;
@@ -154,11 +156,11 @@ sub htmlFooter {
}
txt "vndb $self->{version} | ";
- a href => '/d7', 'about us';
+ a href => '/d7', mt '_footer_aboutus';
txt ' | ';
a href => "mailto:$self->{admin_email}", $self->{admin_email};
txt ' | ';
- a href => $self->{source_url}, 'source';
+ a href => $self->{source_url}, mt '_footer_source';
end;
end; # /div maincontent
end; # /body