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
0.07 ?
- Add logo
- Add theme system
- Better Spamhaus checking
0.06 Fri Sep 04 11:47:00 2015 +0200
- Add Spamhaus checking before accepting the URL
......
EXTRACTFILES=utilities/locales_files.txt
EN=lib/Lstu/I18N/en.po
FR=lib/Lstu/I18N/fr.po
EN=themes/default/lib/Lstu/I18N/en.po
FR=themes/default/lib/Lstu/I18N/fr.po
XGETTEXT=carton exec local/bin/xgettext.pl
CARTON=carton exec
REAL_LSTU=script/application
......@@ -14,4 +14,4 @@ test:
$(CARTON) $(REAL_LSTU) test
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 'ORLite';
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::DebugDumperHelper";
requires 'Locale::Maketext';
requires 'Locale::Maketext::Extract';
requires 'Net::Abuse::Utils::Spamhaus';
......
......@@ -160,10 +160,10 @@ DISTRIBUTIONS
Scalar::Util 0
strict 0
warnings 0
Data-Validate-URI-0.06
pathname: S/SO/SONNEN/Data-Validate-URI-0.06.tar.gz
Data-Validate-URI-0.07
pathname: S/SO/SONNEN/Data-Validate-URI-0.07.tar.gz
provides:
Data::Validate::URI 0.06
Data::Validate::URI 0.07
requirements:
Data::Validate::Domain 0
Data::Validate::IP 0
......@@ -197,17 +197,17 @@ DISTRIBUTIONS
IO::Socket 0
Socket 1.97
Test::More 0.88
IO-Socket-SSL-2.022
pathname: S/SU/SULLR/IO-Socket-SSL-2.022.tar.gz
IO-Socket-SSL-2.024
pathname: S/SU/SULLR/IO-Socket-SSL-2.024.tar.gz
provides:
IO::Socket::SSL 2.022
IO::Socket::SSL 2.024
IO::Socket::SSL::Intercept 2.014
IO::Socket::SSL::OCSP_Cache 2.022
IO::Socket::SSL::OCSP_Resolver 2.022
IO::Socket::SSL::OCSP_Cache 2.024
IO::Socket::SSL::OCSP_Resolver 2.024
IO::Socket::SSL::PublicSuffix undef
IO::Socket::SSL::SSL_Context 2.022
IO::Socket::SSL::SSL_HANDLE 2.022
IO::Socket::SSL::Session_Cache 2.022
IO::Socket::SSL::SSL_Context 2.024
IO::Socket::SSL::SSL_HANDLE 2.024
IO::Socket::SSL::Session_Cache 2.024
IO::Socket::SSL::Utils 2.014
requirements:
ExtUtils::MakeMaker 0
......@@ -299,8 +299,8 @@ DISTRIBUTIONS
Text::ParseWords 0
perl 5.008000
version 0.87
Mojolicious-6.38
pathname: S/SR/SRI/Mojolicious-6.38.tar.gz
Mojolicious-6.52
pathname: S/SR/SRI/Mojolicious-6.52.tar.gz
provides:
Mojo undef
Mojo::Asset undef
......@@ -362,7 +362,8 @@ DISTRIBUTIONS
Mojo::UserAgent::Server undef
Mojo::UserAgent::Transactor undef
Mojo::Util undef
Mojolicious 6.38
Mojo::WebSocket undef
Mojolicious 6.52
Mojolicious::Command undef
Mojolicious::Command::cgi undef
Mojolicious::Command::cpanify undef
......@@ -414,6 +415,13 @@ DISTRIBUTIONS
JSON::PP 2.27103
Pod::Simple 3.09
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
pathname: S/SH/SHARIFULN/Mojolicious-Plugin-I18N-1.6.tar.gz
provides:
......@@ -534,10 +542,10 @@ DISTRIBUTIONS
Test::More 0.52
Time::Local 1.19
perl 5.00404
Net-Domain-TLD-1.73
pathname: A/AL/ALEXP/Net-Domain-TLD-1.73.tar.gz
Net-Domain-TLD-1.74
pathname: A/AL/ALEXP/Net-Domain-TLD-1.74.tar.gz
provides:
Net::Domain::TLD 1.73
Net::Domain::TLD 1.74
requirements:
Carp 0
ExtUtils::MakeMaker 0
......
......@@ -21,6 +21,7 @@ sub startup {
length => 8,
secret => ['hfudsifdsih'],
page_offset => 10,
theme => 'default'
}
});
......@@ -28,8 +29,25 @@ sub startup {
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');
# Debug
$self->plugin('DebugDumperHelper');
$self->secrets($config->{secret});
$self->helper(
......@@ -93,7 +111,7 @@ sub startup {
if (defined $res) {
return {
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 {
my $res = $c->ua->get($url)->res;
......@@ -164,9 +182,9 @@ sub startup {
my ($msg, $short);
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) {
$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)) {
my $res = $c->is_spam($url, 0);
if ($res->{is_spam}) {
......@@ -200,7 +218,7 @@ sub startup {
$short = $records[0]->short;
} else {
# 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;
......@@ -208,7 +226,7 @@ sub startup {
}
}
} else {
$msg = $c->l('[_1] is not a valid URL.', $url);
$msg = $c->l('%1 is not a valid URL.', $url);
}
if ($msg) {
$c->respond_to(
......@@ -349,7 +367,7 @@ sub startup {
$urls[0]->update (counter => $counter);
});
} 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(
json => { json => { success => Mojo::JSON->false, msg => $msg } },
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;
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
use ORLite {
file => 'lstu.db',
file => $config->{db_path},
unicode => 1,
create => sub {
my $dbh = shift;
......
......@@ -7,15 +7,26 @@ use File::Spec qw(catfile);
sub startup {
my $self = shift;
push @{$self->commands->namespaces}, 'Lstu::Command';
my $config = $self->plugin('Config' =>
{
file => File::Spec->catfile($Bin, '..' ,'lstu.conf'),
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')});
}
......
......@@ -7,12 +7,9 @@
hypnotoad => {
# array of IP addresses and ports you want to listen to
listen => ['http://127.0.0.1:8080'],
# user and group you want for Lstu to run with
# be sure that this user/group have rights on the lstu directory
# if you launch lstu from a different user, be sure that this user have the right to su this user/group
# => 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'
# if you use Lstu behind a reverse proxy like Nginx, you want to set proxy to 1
# if you use Lstu directly, let it commented
#proxy => 1,
},
# put a way to contact you here and uncomment it
......@@ -27,6 +24,10 @@
# optional, but you won't have access to admin /stats if not set
#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
# optional, default is 10
#page_offset => 10,
......@@ -57,4 +58,10 @@
# if set, the shortened URLs will use this domain
# optional
#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/;
use Locale::Maketext::Lexicon {
_auto => 1,
_decode => 1,
_style => 'gettext',
'*' => [Gettext => dirname(__FILE__) . '/I18N/*.po']
};
......
......@@ -20,160 +20,40 @@ msgstr ""
"X-Poedit-SourceCharset: UTF-8\n"
#. ($url)
#: lib/Lstu.pm:211
#: lib/Lstu.pm:228
msgid "%1 is not a valid URL."
msgstr ""
#: templates/layouts/default.html.ep:57
msgid "About"
msgstr ""
#: templates/stats.html.ep:12 templates/stats.html.ep:13
msgid "Admin password"
msgstr ""
#: lib/Lstu.pm:326
#: lib/Lstu.pm:343
msgid "Bad password"
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')
#: 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"
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)
#: 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."
msgstr ""
#. ($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."
msgstr ""
#. ($c->url_for('/')
#: lib/Lstu.pm:352
#: lib/Lstu.pm:369
msgid "The shortened URL %1 doesn't exist."
msgstr ""
#. ($custom_url)
#: lib/Lstu.pm:169
#: lib/Lstu.pm:186
msgid "The shortened text (%1) is already used. Please choose another one."
msgstr ""
#. ($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"
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 ""
"X-Poedit-SourceCharset: UTF-8\n"
#. ($url)
#: lib/Lstu.pm:211
#: lib/Lstu.pm:228
msgid "%1 is not a valid URL."
msgstr "%1 n’est pas une URL valide."
#: templates/layouts/default.html.ep:57
#:
msgid "About"
msgstr "À propos"
#: templates/stats.html.ep:12 templates/stats.html.ep:13
#:
msgid "Admin password"
msgstr "Mot de passe administrateur"
#: lib/Lstu.pm:326
#: lib/Lstu.pm:343
msgid "Bad password"
msgstr "Mot de passe incorrect"
#: templates/index.html.ep:20
#:
msgid "Copy to clipboard"
msgstr "Copier dans le presse-papier"
#: templates/stats.html.ep:29
#:
msgid "Counter"
msgstr "Compteur"
#: templates/stats.html.ep:30
#:
msgid "Created"
msgstr "Créé le"
#: templates/api.html.ep:15 templates/index.html.ep:10 templates/index.html.ep:9
#:
msgid "Custom shortened text"
msgstr "Texte du raccourci personnalisé"
#: templates/api.html.ep:21 templates/api.html.ep:39
#:
msgid "Failure reason"
msgstr "Raison de l’échec"
#: templates/index.html.ep:12 templates/stats.html.ep:16
#:
msgid "Go!"
msgstr "Allons-y !"
#: 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 "Appuyez sur Entrée puis faites Ctrl+C pour copier le lien"
#: templates/api.html.ep:16
#:
msgid "If equal to \"json\", response will be in JSON format, HTML format otherwise"
msgstr "Si égal à \"json\", la réponse sera au format JSON, sinon ce sera une réponse en HTML"
#: templates/api.html.ep:21 templates/api.html.ep:39
#:
msgid "JSON: failure"
msgstr "JSON : échec"
#: templates/api.html.ep:20 templates/api.html.ep:38
#:
msgid "JSON: success"
msgstr "JSON : succès"
#: templates/layouts/default.html.ep:56
#:
msgid "License:"
msgstr "Licence :"
#: templates/stats.html.ep:9
#:
msgid "Logout from admin stats"
msgstr "Déconnexion des stats admin"
#: templates/stats.html.ep:53
#:
msgid "Next"
msgstr "Suivant"
#. ($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"
msgstr "Il n’y a plus d’URL raccourcie disponible. Veuillez réessayer ou contactez l’administrateur sur %1. Rappel de l’URL à raccourcir : %2"
#: templates/api.html.ep:12
#:
msgid "Parameters:"
msgstr "Paramètres :"
#: templates/stats.html.ep:51
#:
msgid "Previous"
msgstr "Précédent"
#: templates/api.html.ep:22
#:
msgid "Response for HTML format"
msgstr "Réponse pour le format HTML"
#: templates/api.html.ep:18 templates/api.html.ep:27 templates/api.html.ep:36
#:
msgid "Response:"
msgstr "Réponse :"
#: templates/stats.html.ep:28
#:
msgid "Shortened URL"
msgstr "URL raccourcie"
#: templates/layouts/default.html.ep:59 templates/stats.html.ep:4
#:
msgid "Statistics"
msgstr "Statistiques"
#. ($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."
msgstr "L'hôte de l'URL ou d'une de ses redirections (%1) est considéré comme nocif par Spamhaus. Je refuse de la raccourcir."
#. ($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."
msgstr "L'URL redirige 10 fois ou plus vers un autre site. Il est probable qu'il s'agisse d'une URL dangereuse (pourriel, hameçonnage, etc.). Je refuse de la raccourcir."
#. ($c->url_for('/')
#: lib/Lstu.pm:352
#: lib/Lstu.pm:369
msgid "The shortened URL %1 doesn't exist."
msgstr "L’URL raccourcie %1 n’existe pas"
#. ($custom_url)
#: lib/Lstu.pm:169
#: lib/Lstu.pm:186
msgid "The shortened text (%1) is already used. Please choose another one."
msgstr "Le texte du raccourci (%1) est déjà utilisé. Veuillez en choisir un autre"
#. ($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"
msgstr "Le texte du raccourci ne doit contenir que des chiffres, des lettres et les caractères - et _, ne peut être \"a\", \"api\" ou \"stats\" ou se terminer par \".json\". Rappel de l’URL à raccourcir : %1"
#: templates/stats.html.ep:27
#:
msgid "URL"
msgstr "URL"
#: templates/api.html.ep:14 templates/index.html.ep:5 templates/index.html.ep:6
#:
msgid "URL to shorten"
msgstr "URL à raccourcir"
#: templates/api.html.ep:22
#:
msgid "You will be redirected to the Lstu interface with a message giving the shortened URL"
msgstr "Vous aurez l’interface normale de Lstu avec un message indiquant l’URL raccourcie"
#: 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 "Vous serez redirigé vers l’URL cible ou vers la page d’accueil de Lstu avec un message indiquant la raison de l’échec"
#: templates/api.html.ep:14