Commit 872f3108 authored by Luc Didry's avatar Luc Didry

Add theme system

parent a7796aa3
...@@ -2,6 +2,8 @@ Revision history for Perl application Lstu ...@@ -2,6 +2,8 @@ Revision history for Perl application Lstu
0.07 ? 0.07 ?
- Add logo - Add logo
- Add theme system
- Better Spamhaus checking
0.06 Fri Sep 04 11:47:00 2015 +0200 0.06 Fri Sep 04 11:47:00 2015 +0200
- Add Spamhaus checking before accepting the URL - Add Spamhaus checking before accepting the URL
......
EXTRACTFILES=utilities/locales_files.txt EXTRACTFILES=utilities/locales_files.txt
EN=lib/Lstu/I18N/en.po EN=themes/default/lib/Lstu/I18N/en.po
FR=lib/Lstu/I18N/fr.po FR=themes/default/lib/Lstu/I18N/fr.po
XGETTEXT=carton exec local/bin/xgettext.pl XGETTEXT=carton exec local/bin/xgettext.pl
CARTON=carton exec CARTON=carton exec
REAL_LSTU=script/application REAL_LSTU=script/application
...@@ -14,4 +14,4 @@ test: ...@@ -14,4 +14,4 @@ test:
$(CARTON) $(REAL_LSTU) test $(CARTON) $(REAL_LSTU) test
dev: dev:
$(CARTON) morbo $(LSTU) --listen http://0.0.0.0:3000 $(CARTON) morbo $(LSTU) --listen http://0.0.0.0:3000 --watch lib/ --watch script/ --watch themes/ --watch lstu.conf
requires 'Mojolicious', '>= 4.63'; requires 'Mojolicious', '>= 4.63';
requires 'ORLite'; requires 'ORLite';
requires 'Data::Validate::URI'; requires 'Data::Validate::URI';
requires 'Net::Domain::TLD', '>= 1.73'; # Must have the last version to handle (at least) .xyz and .link requires 'Net::Domain::TLD', '>= 1.74';
requires 'Mojolicious::Plugin::I18N'; requires 'Mojolicious::Plugin::I18N';
requires "Mojolicious::Plugin::DebugDumperHelper";
requires 'Locale::Maketext'; requires 'Locale::Maketext';
requires 'Locale::Maketext::Extract'; requires 'Locale::Maketext::Extract';
requires 'Net::Abuse::Utils::Spamhaus'; requires 'Net::Abuse::Utils::Spamhaus';
......
...@@ -160,10 +160,10 @@ DISTRIBUTIONS ...@@ -160,10 +160,10 @@ DISTRIBUTIONS
Scalar::Util 0 Scalar::Util 0
strict 0 strict 0
warnings 0 warnings 0
Data-Validate-URI-0.06 Data-Validate-URI-0.07
pathname: S/SO/SONNEN/Data-Validate-URI-0.06.tar.gz pathname: S/SO/SONNEN/Data-Validate-URI-0.07.tar.gz
provides: provides:
Data::Validate::URI 0.06 Data::Validate::URI 0.07
requirements: requirements:
Data::Validate::Domain 0 Data::Validate::Domain 0
Data::Validate::IP 0 Data::Validate::IP 0
...@@ -197,17 +197,17 @@ DISTRIBUTIONS ...@@ -197,17 +197,17 @@ DISTRIBUTIONS
IO::Socket 0 IO::Socket 0
Socket 1.97 Socket 1.97
Test::More 0.88 Test::More 0.88
IO-Socket-SSL-2.022 IO-Socket-SSL-2.024
pathname: S/SU/SULLR/IO-Socket-SSL-2.022.tar.gz pathname: S/SU/SULLR/IO-Socket-SSL-2.024.tar.gz
provides: provides:
IO::Socket::SSL 2.022 IO::Socket::SSL 2.024
IO::Socket::SSL::Intercept 2.014 IO::Socket::SSL::Intercept 2.014
IO::Socket::SSL::OCSP_Cache 2.022 IO::Socket::SSL::OCSP_Cache 2.024
IO::Socket::SSL::OCSP_Resolver 2.022 IO::Socket::SSL::OCSP_Resolver 2.024
IO::Socket::SSL::PublicSuffix undef IO::Socket::SSL::PublicSuffix undef
IO::Socket::SSL::SSL_Context 2.022 IO::Socket::SSL::SSL_Context 2.024
IO::Socket::SSL::SSL_HANDLE 2.022 IO::Socket::SSL::SSL_HANDLE 2.024
IO::Socket::SSL::Session_Cache 2.022 IO::Socket::SSL::Session_Cache 2.024
IO::Socket::SSL::Utils 2.014 IO::Socket::SSL::Utils 2.014
requirements: requirements:
ExtUtils::MakeMaker 0 ExtUtils::MakeMaker 0
...@@ -299,8 +299,8 @@ DISTRIBUTIONS ...@@ -299,8 +299,8 @@ DISTRIBUTIONS
Text::ParseWords 0 Text::ParseWords 0
perl 5.008000 perl 5.008000
version 0.87 version 0.87
Mojolicious-6.38 Mojolicious-6.52
pathname: S/SR/SRI/Mojolicious-6.38.tar.gz pathname: S/SR/SRI/Mojolicious-6.52.tar.gz
provides: provides:
Mojo undef Mojo undef
Mojo::Asset undef Mojo::Asset undef
...@@ -362,7 +362,8 @@ DISTRIBUTIONS ...@@ -362,7 +362,8 @@ DISTRIBUTIONS
Mojo::UserAgent::Server undef Mojo::UserAgent::Server undef
Mojo::UserAgent::Transactor undef Mojo::UserAgent::Transactor undef
Mojo::Util undef Mojo::Util undef
Mojolicious 6.38 Mojo::WebSocket undef
Mojolicious 6.52
Mojolicious::Command undef Mojolicious::Command undef
Mojolicious::Command::cgi undef Mojolicious::Command::cgi undef
Mojolicious::Command::cpanify undef Mojolicious::Command::cpanify undef
...@@ -414,6 +415,13 @@ DISTRIBUTIONS ...@@ -414,6 +415,13 @@ DISTRIBUTIONS
JSON::PP 2.27103 JSON::PP 2.27103
Pod::Simple 3.09 Pod::Simple 3.09
Time::Local 1.2 Time::Local 1.2
Mojolicious-Plugin-DebugDumperHelper-0.02
pathname: L/LD/LDIDRY/Mojolicious-Plugin-DebugDumperHelper-0.02.tar.gz
provides:
Mojolicious::Plugin::DebugDumperHelper 0.02
requirements:
ExtUtils::MakeMaker 0
Mojolicious 6.11
Mojolicious-Plugin-I18N-1.6 Mojolicious-Plugin-I18N-1.6
pathname: S/SH/SHARIFULN/Mojolicious-Plugin-I18N-1.6.tar.gz pathname: S/SH/SHARIFULN/Mojolicious-Plugin-I18N-1.6.tar.gz
provides: provides:
...@@ -534,10 +542,10 @@ DISTRIBUTIONS ...@@ -534,10 +542,10 @@ DISTRIBUTIONS
Test::More 0.52 Test::More 0.52
Time::Local 1.19 Time::Local 1.19
perl 5.00404 perl 5.00404
Net-Domain-TLD-1.73 Net-Domain-TLD-1.74
pathname: A/AL/ALEXP/Net-Domain-TLD-1.73.tar.gz pathname: A/AL/ALEXP/Net-Domain-TLD-1.74.tar.gz
provides: provides:
Net::Domain::TLD 1.73 Net::Domain::TLD 1.74
requirements: requirements:
Carp 0 Carp 0
ExtUtils::MakeMaker 0 ExtUtils::MakeMaker 0
......
...@@ -21,6 +21,7 @@ sub startup { ...@@ -21,6 +21,7 @@ sub startup {
length => 8, length => 8,
secret => ['hfudsifdsih'], secret => ['hfudsifdsih'],
page_offset => 10, page_offset => 10,
theme => 'default'
} }
}); });
...@@ -28,8 +29,25 @@ sub startup { ...@@ -28,8 +29,25 @@ sub startup {
die "You need to provide a contact information in lstu.conf!" unless (defined($config->{contact})); die "You need to provide a contact information in lstu.conf!" unless (defined($config->{contact}));
# Themes handling
shift @{$self->renderer->paths};
shift @{$self->static->paths};
if ($config->{theme} ne 'default') {
my $theme = $self->home->rel_dir('themes/'.$config->{theme});
push @{$self->renderer->paths}, $theme.'/templates' if -d $theme.'/templates';
push @{$self->static->paths}, $theme.'/public' if -d $theme.'/public';
}
push @{$self->renderer->paths}, $self->home->rel_dir('themes/default/templates');
push @{$self->static->paths}, $self->home->rel_dir('themes/default/public');
# Internationalization
my $lib = $self->home->rel_dir('themes/'.$config->{theme}.'/lib');
eval qq(use lib "$lib");
$self->plugin('I18N'); $self->plugin('I18N');
# Debug
$self->plugin('DebugDumperHelper');
$self->secrets($config->{secret}); $self->secrets($config->{secret});
$self->helper( $self->helper(
...@@ -93,7 +111,7 @@ sub startup { ...@@ -93,7 +111,7 @@ sub startup {
if (defined $res) { if (defined $res) {
return { return {
is_spam => 1, is_spam => 1,
msg => $c->l('The URL host or one of its redirection(s) ([_1]) is blacklisted at Spamhaus. I refuse to shorten it.', $url->host) msg => $c->l('The URL host or one of its redirection(s) (%1) is blacklisted at Spamhaus. I refuse to shorten it.', $url->host)
} }
} else { } else {
my $res = $c->ua->get($url)->res; my $res = $c->ua->get($url)->res;
...@@ -164,9 +182,9 @@ sub startup { ...@@ -164,9 +182,9 @@ sub startup {
my ($msg, $short); my ($msg, $short);
if (defined($custom_url) && ($custom_url =~ m/^a(pi)?$|^stats$/ || $custom_url =~ m/\.json$/ || $custom_url !~ m/^[-a-zA-Z0-9_]+$/)) { if (defined($custom_url) && ($custom_url =~ m/^a(pi)?$|^stats$/ || $custom_url =~ m/\.json$/ || $custom_url !~ m/^[-a-zA-Z0-9_]+$/)) {
$msg = $c->l('The shortened text can contain only numbers, letters and the - and _ character, can\'t be "a", "api" or "stats" or end with ".json". Your URL to shorten: [_1]', $url); $msg = $c->l('The shortened text can contain only numbers, letters and the - and _ character, can\'t be "a", "api" or "stats" or end with ".json". Your URL to shorten: %1', $url);
} elsif (defined($custom_url) && LstuModel::Lstu->count('WHERE short = ?', $custom_url) > 0) { } elsif (defined($custom_url) && LstuModel::Lstu->count('WHERE short = ?', $custom_url) > 0) {
$msg = $c->l('The shortened text ([_1]) is already used. Please choose another one.', $custom_url); $msg = $c->l('The shortened text (%1) is already used. Please choose another one.', $custom_url);
} elsif (is_http_uri($url->to_string) || is_https_uri($url->to_string)) { } elsif (is_http_uri($url->to_string) || is_https_uri($url->to_string)) {
my $res = $c->is_spam($url, 0); my $res = $c->is_spam($url, 0);
if ($res->{is_spam}) { if ($res->{is_spam}) {
...@@ -200,7 +218,7 @@ sub startup { ...@@ -200,7 +218,7 @@ sub startup {
$short = $records[0]->short; $short = $records[0]->short;
} else { } else {
# Houston, we have a problem # Houston, we have a problem
$msg = $c->l('No shortened URL available. Please retry or contact the administrator at [_1]. Your URL to shorten: [_2]', $c->config('contact'), $url); $msg = $c->l('No shortened URL available. Please retry or contact the administrator at %1. Your URL to shorten: [_2]', $c->config('contact'), $url);
} }
} }
LstuModel->commit; LstuModel->commit;
...@@ -208,7 +226,7 @@ sub startup { ...@@ -208,7 +226,7 @@ sub startup {
} }
} }
} else { } else {
$msg = $c->l('[_1] is not a valid URL.', $url); $msg = $c->l('%1 is not a valid URL.', $url);
} }
if ($msg) { if ($msg) {
$c->respond_to( $c->respond_to(
...@@ -349,7 +367,7 @@ sub startup { ...@@ -349,7 +367,7 @@ sub startup {
$urls[0]->update (counter => $counter); $urls[0]->update (counter => $counter);
}); });
} else { } else {
my $msg = $c->l('The shortened URL [_1] doesn\'t exist.', $c->url_for('/')->to_abs.$short); my $msg = $c->l('The shortened URL %1 doesn\'t exist.', $c->url_for('/')->to_abs.$short);
$c->respond_to( $c->respond_to(
json => { json => { success => Mojo::JSON->false, msg => $msg } }, json => { json => { success => Mojo::JSON->false, msg => $msg } },
any => sub { any => sub {
......
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lstu::Command::theme;
use Mojo::Base 'Mojolicious::Commands';
use FindBin qw($Bin);
use File::Spec qw(catfile cat dir);
use File::Path qw(make_path);
has description => 'Create new theme skeleton.';
has usage => sub { shift->extract_usage };
has message => sub { shift->extract_usage . "\nCreate new theme skeleton:\n" };
has namespaces => sub { ['Lstu::Command::theme'] };
sub run {
my $c = shift;
my $name = shift;
unless (defined $name) {
say $c->extract_usage;
exit 1;
}
my $home = File::Spec->catdir($Bin, '..', 'themes', $name);
unless (-d $home) {
# Create skeleton
mkdir $home;
mkdir File::Spec->catdir($home, 'public');
make_path(File::Spec->catdir($home, 'templates', 'layouts'));
make_path(File::Spec->catdir($home, 'lib', 'Lstu', 'I18N'));
my $i18n = <<EOF;
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package Lstu::I18N;
use base 'Locale::Maketext';
use File::Basename qw/dirname/;
use Locale::Maketext::Lexicon {
_auto => 1,
_decode => 1,
_style => 'gettext',
'*' => [
Gettext => dirname(__FILE__) . '/I18N/*.po',
Gettext => dirname(__FILE__) . '/../../../default/lib/Lstu/I18N/*.po',
]
};
1;
EOF
open my $f, '>', File::Spec->catfile($home, 'lib', 'Lstu', 'I18N.pm') or die "Unable to open $home/lib/Lstu/I18N.pm: $!";
print $f $i18n;
close $f;
my $makefile = <<EOF;
EN=lib/Lstu/I18N/en.po
FR=lib/Lstu/I18N/fr.po
SEDOPTS=-e "s\@SOME DESCRIPTIVE TITLE\@Lstu language file\@" \\
-e "s\@YEAR THE PACKAGE'S COPYRIGHT HOLDER\@2015 Luc Didry\@" \\
-e "s\@CHARSET\@utf8\@" \\
-e "s\@the PACKAGE package\@the Lstu package\@" \\
-e '/^\\#\\. (/{N;/\\n\\#\\. (/{N;/\\n.*\\.\\.\\/default\\//{s/\\#\\..*\\n.*\\#\\./\\#. (/g}}}' \\
-e '/^\\#\\. (/{N;/\\n.*\\.\\.\\/default\\//{s/\\n/ /}}'
SEDOPTS2=-e '/^\\#.*\\.\\.\\/default\\//,+3d'
XGETTEXT=carton exec ../../local/bin/xgettext.pl
CARTON=carton exec
locales:
\$(XGETTEXT) -D templates -D ../default/templates -o \$(EN) 2>/dev/null
\$(XGETTEXT) -D templates -D ../default/templates -o \$(FR) 2>/dev/null
sed \$(SEDOPTS) -i \$(EN)
sed \$(SEDOPTS2) -i \$(EN)
sed \$(SEDOPTS) -i \$(FR)
sed \$(SEDOPTS2) -i \$(FR)
EOF
open $f, '>', File::Spec->catfile($home, 'Makefile') or die "Unable to open $home/Makefile: $!";
print $f $makefile;
close $f;
} else {
say "$name theme already exists. Aborting.";
exit 1;
}
}
=encoding utf8
=head1 NAME
Lstu::Command::theme - Create new theme skeleton.
=head1 SYNOPSIS
Usage: script/lstu theme THEME_NAME
Your new theme will be available in the themes directory.
=cut
1;
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
package LstuModel; package LstuModel;
use Mojolicious;
use FindBin qw($Bin);
use File::Spec::Functions;
BEGIN {
my $m = Mojolicious->new;
our $config = $m->plugin('Config' =>
{
file => catfile($Bin, '..' ,'lstu.conf'),
default => {
db_path => 'lstu.db'
}
}
);
}
# Create database # Create database
use ORLite { use ORLite {
file => 'lstu.db', file => $config->{db_path},
unicode => 1, unicode => 1,
create => sub { create => sub {
my $dbh = shift; my $dbh = shift;
......
...@@ -7,15 +7,26 @@ use File::Spec qw(catfile); ...@@ -7,15 +7,26 @@ use File::Spec qw(catfile);
sub startup { sub startup {
my $self = shift; my $self = shift;
push @{$self->commands->namespaces}, 'Lstu::Command';
my $config = $self->plugin('Config' => my $config = $self->plugin('Config' =>
{ {
file => File::Spec->catfile($Bin, '..' ,'lstu.conf'), file => File::Spec->catfile($Bin, '..' ,'lstu.conf'),
default => { default => {
prefix => '/' prefix => '/',
theme => 'default',
} }
} }
); );
# Themes handling
shift @{$self->static->paths};
if ($config->{theme} ne 'default') {
my $theme = $self->home->rel_dir('themes/'.$config->{theme});
push @{$self->static->paths}, $theme.'/public' if -d $theme.'/public';
}
push @{$self->static->paths}, $self->home->rel_dir('themes/default/public');
$self->plugin('Mount' => {$config->{prefix} => File::Spec->catfile($Bin, '..', 'script', 'application')}); $self->plugin('Mount' => {$config->{prefix} => File::Spec->catfile($Bin, '..', 'script', 'application')});
} }
......
...@@ -7,12 +7,9 @@ ...@@ -7,12 +7,9 @@
hypnotoad => { hypnotoad => {
# array of IP addresses and ports you want to listen to # array of IP addresses and ports you want to listen to
listen => ['http://127.0.0.1:8080'], listen => ['http://127.0.0.1:8080'],
# user and group you want for Lstu to run with # if you use Lstu behind a reverse proxy like Nginx, you want to set proxy to 1
# be sure that this user/group have rights on the lstu directory # if you use Lstu directly, let it commented
# if you launch lstu from a different user, be sure that this user have the right to su this user/group #proxy => 1,
# => if current_user is not the user that you sets here and is not root, there's chances that it will fail (see https://github.com/ldidry/lstu/issues/25)
user => 'www-data',
group => 'www-data'
}, },
# put a way to contact you here and uncomment it # put a way to contact you here and uncomment it
...@@ -27,6 +24,10 @@ ...@@ -27,6 +24,10 @@
# optional, but you won't have access to admin /stats if not set # optional, but you won't have access to admin /stats if not set
#adminpwd => 's3cr3T', #adminpwd => 's3cr3T',
# choose a theme. See the available themes in `themes` directory
# optional, default is 'default'
#theme => 'default',
# number of URLs to be displayed per page in /stats # number of URLs to be displayed per page in /stats
# optional, default is 10 # optional, default is 10
#page_offset => 10, #page_offset => 10,
...@@ -57,4 +58,10 @@ ...@@ -57,4 +58,10 @@
# if set, the shortened URLs will use this domain # if set, the shortened URLs will use this domain
# optional # optional
#fixed_domain => 'example.org', #fixed_domain => 'example.org',
# define a path to the SQLite database
# you can define it relative to lstu directory or set an absolute path
# remember that it has to be in a directory writable by Lstu user
# optional, default is lstu.db
#db_path => 'lstu.db',
}; };
File mode changed from 100644 to 100755
...@@ -5,6 +5,7 @@ use File::Basename qw/dirname/; ...@@ -5,6 +5,7 @@ use File::Basename qw/dirname/;
use Locale::Maketext::Lexicon { use Locale::Maketext::Lexicon {
_auto => 1, _auto => 1,
_decode => 1, _decode => 1,
_style => 'gettext',
'*' => [Gettext => dirname(__FILE__) . '/I18N/*.po'] '*' => [Gettext => dirname(__FILE__) . '/I18N/*.po']
}; };
......
...@@ -20,160 +20,40 @@ msgstr "" ...@@ -20,160 +20,40 @@ msgstr ""
"X-Poedit-SourceCharset: UTF-8\n" "X-Poedit-SourceCharset: UTF-8\n"
#. ($url) #. ($url)
#: lib/Lstu.pm:211 #: lib/Lstu.pm:228
msgid "%1 is not a valid URL." msgid "%1 is not a valid URL."
msgstr "" msgstr ""
#: templates/layouts/default.html.ep:57 #: lib/Lstu.pm:343
msgid "About"
msgstr ""
#: templates/stats.html.ep:12 templates/stats.html.ep:13
msgid "Admin password"
msgstr ""
#: lib/Lstu.pm:326
msgid "Bad password" msgid "Bad password"
msgstr "" msgstr ""
#: templates/index.html.ep:20
msgid "Copy to clipboard"
msgstr ""
#: templates/stats.html.ep:29
msgid "Counter"
msgstr ""
#: templates/stats.html.ep:30
msgid "Created"
msgstr ""
#: templates/api.html.ep:15 templates/index.html.ep:10 templates/index.html.ep:9
msgid "Custom shortened text"
msgstr ""
#: templates/api.html.ep:21 templates/api.html.ep:39
msgid "Failure reason"
msgstr ""
#: templates/index.html.ep:12 templates/stats.html.ep:16
msgid "Go!"
msgstr ""
#: templates/layouts/default.html.ep:36
msgid "Henny Penny"
msgstr ""
#: templates/layouts/default.html.ep:36
msgid "HennyPenny-Regular"
msgstr ""
#: templates/index.html.ep:52
msgid "Hit Enter, then Ctrl+C to copy the short link"
msgstr ""
#: templates/api.html.ep:16
msgid "If equal to \"json\", response will be in JSON format, HTML format otherwise"
msgstr ""
#: templates/api.html.ep:21 templates/api.html.ep:39
msgid "JSON: failure"
msgstr ""
#: templates/api.html.ep:20 templates/api.html.ep:38
msgid "JSON: success"
msgstr ""
#: templates/layouts/default.html.ep:56
msgid "License:"
msgstr ""
#: templates/stats.html.ep:9
msgid "Logout from admin stats"
msgstr ""
#: templates/stats.html.ep:53
msgid "Next"
msgstr ""
#. ($c->config('contact') #. ($c->config('contact')
#: lib/Lstu.pm:203 #: lib/Lstu.pm:220
msgid "No shortened URL available. Please retry or contact the administrator at %1. Your URL to shorten: %2" msgid "No shortened URL available. Please retry or contact the administrator at %1. Your URL to shorten: %2"
msgstr "" msgstr ""
#: templates/api.html.ep:12
msgid "Parameters:"
msgstr ""
#: templates/stats.html.ep:51
msgid "Previous"
msgstr ""
#: templates/api.html.ep:22
msgid "Response for HTML format"
msgstr ""
#: templates/api.html.ep:18 templates/api.html.ep:27 templates/api.html.ep:36
msgid "Response:"
msgstr ""
#: templates/stats.html.ep:28
msgid "Shortened URL"
msgstr ""
#: templates/layouts/default.html.ep:59 templates/stats.html.ep:4
msgid "Statistics"
msgstr ""
#. ($url->host) #. ($url->host)
#: lib/Lstu.pm:96 #: lib/Lstu.pm:113
msgid "The URL host or one of its redirection(s) (%1) is blacklisted at Spamhaus. I refuse to shorten it." msgid "The URL host or one of its redirection(s) (%1) is blacklisted at Spamhaus. I refuse to shorten it."
msgstr "" msgstr ""
#. ($url->host) #. ($url->host)
#: lib/Lstu.pm:109 #: lib/Lstu.pm:126
msgid "The URL redirects 10 times or most. It's most likely a dangerous URL (spam, phishing, etc.). I refuse to shorten it." msgid "The URL redirects 10 times or most. It's most likely a dangerous URL (spam, phishing, etc.). I refuse to shorten it."
msgstr "" msgstr ""
#. ($c->url_for('/') #. ($c->url_for('/')
#: lib/Lstu.pm:352 #: lib/Lstu.pm:369
msgid "The shortened URL %1 doesn't exist." msgid "The shortened URL %1 doesn't exist."
msgstr "" msgstr ""
#. ($custom_url) #. ($custom_url)
#: lib/Lstu.pm:169 #: lib/Lstu.pm:186
msgid "The shortened text (%1) is already used. Please choose another one." msgid "The shortened text (%1) is already used. Please choose another one."
msgstr "" msgstr ""
#. ($url) #. ($url)
#: lib/Lstu.pm:167 #: lib/Lstu.pm:184
msgid "The shortened text can contain only numbers, letters and the - and _ character, can't be \"a\", \"api\" or \"stats\" or end with \".json\". Your URL to shorten: %1" msgid "The shortened text can contain only numbers, letters and the - and _ character, can't be \"a\", \"api\" or \"stats\" or end with \".json\". Your URL to shorten: %1"
msgstr "" msgstr ""
#: templates/stats.html.ep:27
msgid "URL"
msgstr ""
#: templates/api.html.ep:14 templates/index.html.ep:5 templates/index.html.ep:6
msgid "URL to shorten"
msgstr ""
#: templates/api.html.ep:22
msgid "You will be redirected to the Lstu interface with a message giving the shortened URL"
msgstr ""
#: templates/api.html.ep:30
msgid "You will be redirected to the targeted URL or to the Lstu interface with a message giving the failure reason"
msgstr ""
#: templates/api.html.ep:14
msgid "mandatory"
msgstr ""
#: templates/api.html.ep:15 templates/api.html.ep:16
msgid "optional"
msgstr ""
#: templates/api.html.ep:25 templates/api.html.ep:34
msgid "shortened_url"
msgstr ""
...@@ -25,160 +25,152 @@ msgstr "" ...@@ -25,160 +25,152 @@ msgstr ""
"X-Poedit-SourceCharset: UTF-8\n" "X-Poedit-SourceCharset: UTF-8\n"
#. ($url) #. ($url)
#: lib/Lstu.pm:211 #: lib/Lstu.pm:228
msgid "%1 is not a valid URL." msgid "%1 is not a valid URL."
msgstr "%1 n’est pas une URL valide." msgstr "%1 n’est pas une URL valide."
#: templates/layouts/default.html.ep:57 #:
msgid "About" msgid "About"
msgstr "À propos" msgstr "À propos"
#: templates/stats.html.ep:12 templates/stats.html.ep:13 #:
msgid "Admin password" msgid "Admin password"
msgstr "Mot de passe administrateur" msgstr "Mot de passe administrateur"
#: lib/Lstu.pm:326 #: lib/Lstu.pm:343
msgid "Bad password" msgid "Bad password"
msgstr "Mot de passe incorrect" msgstr "Mot de passe incorrect"
#: templates/index.html.ep:20 #:
msgid "Copy to clipboard" msgid "Copy to clipboard"
msgstr "Copier dans le presse-papier" msgstr "Copier dans le presse-papier"
#: templates/stats.html.ep:29 #:
msgid "Counter" msgid "Counter"
msgstr "Compteur"