i18n: Add i18n switch and fr translation

This commit is contained in:
Samuel Ortion 2022-08-18 16:32:29 +02:00
parent 2516efa805
commit 7a39330a6f
23 changed files with 458 additions and 51 deletions

View File

@ -1 +1,3 @@
- i18n switch - i18n switch (to keep on same page)
- /records pagination
- /records ajax bird contacts retrieval

View File

@ -65,7 +65,9 @@ a {
z-index: 1; z-index: 1;
} }
.button, input[type=submit], input[type=button] { .button,
input[type=submit],
input[type=button] {
background-color: #f1f1f1; background-color: #f1f1f1;
color: black; color: black;
border-radius: 5px; border-radius: 5px;
@ -97,7 +99,8 @@ a {
word-wrap: break-word; word-wrap: break-word;
} }
.button:hover, input:hover { .button:hover,
input:hover {
background-color: #F3F4F6; background-color: #F3F4F6;
text-decoration: none; text-decoration: none;
transition-duration: 0.1s; transition-duration: 0.1s;
@ -111,30 +114,30 @@ a {
} }
.button-main:focus:not(:focus-visible):not(.focus-visible) { .button-main:focus:not(:focus-visible):not(.focus-visible) {
box-shadow: none; box-shadow: none;
outline: none; outline: none;
} }
.button-main:hover { .button-main:hover {
background-color: #2c974b; background-color: #2c974b;
padding: 6px 16px; padding: 6px 16px;
} }
.button-main:focus { .button-main:focus {
box-shadow: rgba(46, 164, 79, .4) 0 0 0 3px; box-shadow: rgba(46, 164, 79, .4) 0 0 0 3px;
outline: none; outline: none;
} }
.button-main:disabled { .button-main:disabled {
background-color: #94d3a2; background-color: #94d3a2;
border-color: rgba(27, 31, 35, .1); border-color: rgba(27, 31, 35, .1);
color: rgba(255, 255, 255, .8); color: rgba(255, 255, 255, .8);
cursor: default; cursor: default;
} }
.button-main:active { .button-main:active {
background-color: #298e46; background-color: #298e46;
box-shadow: rgba(20, 70, 32, .2) 0 1px 0 inset; box-shadow: rgba(20, 70, 32, .2) 0 1px 0 inset;
} }
.button-main:active { .button-main:active {
@ -143,7 +146,8 @@ a {
transition: none 0s; transition: none 0s;
} }
.button:focus, input:focus { .button:focus,
input:focus {
outline: 1px transparent; outline: 1px transparent;
border: solid blue 1px; border: solid blue 1px;
} }
@ -179,7 +183,7 @@ header img.logo {
} }
main { main {
min-height: calc(100vh - (var(--header-height, 4em) + var(--footer-height, 4em)) ); min-height: calc(100vh - (var(--header-height, 4em) + var(--footer-height, 4em)));
padding: 5em; padding: 5em;
z-index: 0; z-index: 0;
} }
@ -201,11 +205,16 @@ footer a:hover {
font-style: italic; font-style: italic;
} }
li, td { li {
list-style: none;
}
li,
td {
align-items: center; align-items: center;
} }
/* .dropdown-button:hover { .dropdown-toggle:hover {
background-color: #900; background-color: #900;
color: white color: white
} }
@ -213,22 +222,58 @@ li, td {
.dropdown:hover .dropdown-content { .dropdown:hover .dropdown-content {
display: block; display: block;
} }
*/
.dropdown-content { .dropdown-content {
display: none; display: none;
position: absolute;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2); box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
z-index: 1; z-index: 1;
width: fit-content;
} }
canvas { canvas {
display: block; display: block;
height: 100%; height: 100%;
width: 100%; width: 100%;
} }
.language-selector {
position: absolute;
top: 0;
right: 0;
}
.language-selector .toggle {
position: absolute;
top: 0;
right: 0;
opacity: 0;
width: 5em;
height: 1em;
}
.touch {
cursor: pointer;
}
.touch::after {
content: "+";
}
.slide {
clear: both;
width: 100%;
height: 0px;
overflow: hidden;
text-align: center;
transition: height .4s ease;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
}
.toggle:checked + .slide {
height: fit-content;
}
.scientific-name { .scientific-name {
font-style: italic; font-style: italic;
} }
@ -294,4 +339,4 @@ canvas {
main { main {
padding: 1em; padding: 1em;
} }
} }

View File

@ -23,6 +23,7 @@
"symfony/yaml": "6.1.*", "symfony/yaml": "6.1.*",
"twig/extra-bundle": "^2.12|^3.0", "twig/extra-bundle": "^2.12|^3.0",
"twig/intl-extra": "^3.4", "twig/intl-extra": "^3.4",
"twig/string-extra": "^3.4",
"twig/twig": "^2.12|^3.0" "twig/twig": "^2.12|^3.0"
}, },
"config": { "config": {

74
www/composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "96fd1b588fa4ee292b8be380f2260cc1", "content-hash": "5ee7614277dd908e6485a36c9b423ace",
"packages": [ "packages": [
{ {
"name": "doctrine/annotations", "name": "doctrine/annotations",
@ -4951,6 +4951,78 @@
], ],
"time": "2022-06-10T08:33:05+00:00" "time": "2022-06-10T08:33:05+00:00"
}, },
{
"name": "twig/string-extra",
"version": "v3.4.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/string-extra.git",
"reference": "03608ae2e9c270a961e8cf1b75751e8635ad3e3c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/string-extra/zipball/03608ae2e9c270a961e8cf1b75751e8635ad3e3c",
"reference": "03608ae2e9c270a961e8cf1b75751e8635ad3e3c",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"symfony/string": "^5.0|^6.0",
"symfony/translation-contracts": "^1.1|^2|^3",
"twig/twig": "^2.7|^3.0"
},
"require-dev": {
"symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.2-dev"
}
},
"autoload": {
"psr-4": {
"Twig\\Extra\\String\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com",
"homepage": "http://fabien.potencier.org",
"role": "Lead Developer"
}
],
"description": "A Twig extension for Symfony String",
"homepage": "https://twig.symfony.com",
"keywords": [
"html",
"string",
"twig",
"unicode"
],
"support": {
"source": "https://github.com/twigphp/string-extra/tree/v3.4.0"
},
"funding": [
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/twig/twig",
"type": "tidelift"
}
],
"time": "2022-01-02T10:02:25+00:00"
},
{ {
"name": "twig/twig", "name": "twig/twig",
"version": "v3.4.2", "version": "v3.4.2",

View File

@ -0,0 +1,4 @@
<?php // dev.decrypt.private on Thu, 18 Aug 2022 11:24:08 +0000
// SYMFONY_DECRYPTION_SECRET=Wa3L9epQCNyArZ9uGqChJro5t3n97TKgwVyoqmHHZnCtzcDIHxxI6HD6Vd1HRW46d+I4Pc3aPKh6NMIJ309TeQ==
return "Y\xAD\xCB\xF5\xEAP\x08\xDC\x80\xAD\x9Fn\x1A\xA0\xA1\x26\xBA9\xB7y\xFD\xED2\xA0\xC1\x5C\xA8\xAAa\xC7fp\xAD\xCD\xC0\xC8\x1F\x1CH\xE8p\xFAU\xDDGEn\x3Aw\xE28\x3D\xCD\xDA\x3C\xA8z4\xC2\x09\xDFOSy";

View File

@ -0,0 +1,3 @@
<?php // dev.encrypt.public on Thu, 18 Aug 2022 11:24:08 +0000
return "\xAD\xCD\xC0\xC8\x1F\x1CH\xE8p\xFAU\xDDGEn\x3Aw\xE28\x3D\xCD\xDA\x3C\xA8z4\xC2\x09\xDFOSy";

View File

@ -0,0 +1,3 @@
<?php // prod.encrypt.public on Thu, 18 Aug 2022 11:25:20 +0000
return "\xFBm\xD4\xAF\xF1b\x88\x93\x96\xC3\x9DJSJ\x0A\xDB\xA0\xF6\xBCp\x98\x96\xC7\xA6\xD2\x82\x28\x28y3\xCF\x11";

View File

@ -5,6 +5,8 @@
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration # https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
parameters: parameters:
app.records_dir: '%env(resolve:RECORDS_DIR)%' app.records_dir: '%env(resolve:RECORDS_DIR)%'
app.supported_locales: 'en|fr'
app.default_locale: 'en'
services: services:
# default configuration for services in *this* file # default configuration for services in *this* file

View File

@ -13,6 +13,7 @@ class AuthController extends AbstractController
/** /**
* @Route("/auth", name="auth") * @Route("/auth", name="auth")
* @Route("/{_locale<%app.supported_locales%>}/auth", name="auth_i18n")
*/ */
public function index(Connection $connection) public function index(Connection $connection)
{ {
@ -21,6 +22,7 @@ class AuthController extends AbstractController
/** /**
* @Route("/auth/login", name="login") * @Route("/auth/login", name="login")
* @Route("/{_locale<%app.supported_locales%>}/auth/login", name="login_i18n")
*/ */
public function login() public function login()
{ {

View File

@ -12,7 +12,8 @@ class HomeController extends AbstractController
private Connection $connection; private Connection $connection;
/** /**
* @Route("/", name="home") * @Route("", name="home")
* @Route("/{_locale<%app.supported_locales%>}/", name="home_i18n")
*/ */
public function index(Connection $connection) public function index(Connection $connection)
{ {
@ -25,6 +26,7 @@ class HomeController extends AbstractController
/** /**
* @Route("/about", name="about") * @Route("/about", name="about")
* @Route("/{_locale<%app.supported_locales%>}/about", name="about_i18n")
*/ */
public function about() public function about()
{ {

View File

@ -12,6 +12,7 @@ class LogsController extends AbstractController
private $allowed_services = "recording analyzis miner plotter"; private $allowed_services = "recording analyzis miner plotter";
/** /**
* @Route("/logs/{service}", name="logs") * @Route("/logs/{service}", name="logs")
* @Route("/{_locale<%app.supported_locales%>}/logs/{service}", name="logs_i18n")
*/ */
public function logs($service = "all") public function logs($service = "all")
{ {

View File

@ -13,7 +13,8 @@ class RecordsController extends AbstractController
private Connection $connection; private Connection $connection;
/** /**
* @Route("/records/{date}", name="records_index") * @Route("/records", name="records")
* @Route("/{_locale<%app.supported_locales%>}/records/{date}", name="records_i18n")
*/ */
public function records_index($date = "now") public function records_index($date = "now")
{ {
@ -30,6 +31,7 @@ class RecordsController extends AbstractController
/** /**
* @Route("/records/delete/{basename}", name="record_delete") * @Route("/records/delete/{basename}", name="record_delete")
* @Route("/{_locale<%app.supported_locales%>}/records/delete/{basename}", name="record_delete_i18n")
*/ */
public function delete_record(Connection $connection, $basename) public function delete_record(Connection $connection, $basename)
{ {
@ -38,6 +40,16 @@ class RecordsController extends AbstractController
return $this->redirectToRoute('records_index'); return $this->redirectToRoute('records_index');
} }
/**
* @Route("/records/best", name="records_best")
* @Route("/{_locale<%app.supported_locales%>}/records/best", name="records_best_i18n")
*/
public function best_records(Connection $connection)
{
$this->render('records/best.html.twig', [
]);
}
private function list_records() private function list_records()
{ {
$records_path = $this->getParameter('app.records_dir') . "/out/*.wav"; $records_path = $this->getParameter('app.records_dir') . "/out/*.wav";

View File

@ -14,7 +14,8 @@ class ServicesController extends AbstractController
/** /**
* @Route("/services/status", name="service_status") * @Route("/services/status", name="services_status")
* @Route("/{_locale<%app.supported_locales%>}/services/status", name="service_status_i18n")
*/ */
public function service_status() { public function service_status() {
$status = array_map(function($service) { $status = array_map(function($service) {
@ -29,7 +30,8 @@ class ServicesController extends AbstractController
} }
/** /**
* @Route("/services/manage/{action}/{service}", name="service_manager") * @Route("/services/manage/{action}/{service}", name="services_manager")
* @Route("/{_locale<%app.supported_locales%>}/services/manage/{action}/{service}", name="service_manager_i18n")
*/ */
public function service_manage($action, $service="all") public function service_manage($action, $service="all")
{ {

View File

@ -10,8 +10,9 @@ class SpectroController extends AbstractController
{ {
/** /**
* @Route("/spectro", name="spectro") * @Route("/spectro", name="spectro")
* @Route("/{_locale<%app.supported_locales%>}/spectro", name="spectro_i18n")
*/ */
public function about() public function spectro()
{ {
return $this->render('spectro/index.html.twig', [ return $this->render('spectro/index.html.twig', [

View File

@ -0,0 +1,22 @@
<?php
namespace App\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Doctrine\DBAL\Connection;
class StatsController extends AbstractController
{
private Connection $connection;
/**
* @Route("/stats", name="stats")
* @Route("/{_locale<%app.supported_locales%>}/stats", name="stats_i18n")
*/
public function index(Connection $connection)
{
return $this->render("stats/index.html.twig");
}
}

View File

@ -14,6 +14,7 @@ class TodayController extends AbstractController
/** /**
* @Route("/today", name="today") * @Route("/today", name="today")
* @Route("/{_locale<%app.supported_locales%>}/today", name="today_i18n")
*/ */
public function today(Connection $connection) public function today(Connection $connection)
{ {
@ -22,6 +23,7 @@ class TodayController extends AbstractController
/** /**
* @Route("/today/species", name="today_species") * @Route("/today/species", name="today_species")
* @Route("/{_locale<%app.supported_locales%>}/today/species", name="today_species_i18n")
*/ */
public function today_species_page(Connection $connection) public function today_species_page(Connection $connection)
{ {
@ -35,6 +37,7 @@ class TodayController extends AbstractController
/** /**
* @Route("/today/species/{id}", name="today_species_id") * @Route("/today/species/{id}", name="today_species_id")
* @Route("/{_locale<%app.supported_locales%>}/today/species/{id}", name="today_species_id_i18n")
*/ */
public function today_species_by_id(Connection $connection, $id) public function today_species_by_id(Connection $connection, $id)
{ {
@ -49,6 +52,7 @@ class TodayController extends AbstractController
/** /**
* @Route("/today/{date}", name="today_date") * @Route("/today/{date}", name="today_date")
* @Route("/{_locale<%app.supported_locales%>}/today/{date}", name="today_date_i18n")
*/ */
public function today_date(Connection $connection, $date) public function today_date(Connection $connection, $date)
{ {
@ -57,6 +61,7 @@ class TodayController extends AbstractController
/** /**
* @Route("/today/{date}/species", name="today_species_date") * @Route("/today/{date}/species", name="today_species_date")
* @Route("/{_locale<%app.supported_locales%>}/today/{date}/species", name="today_species_date_i18n")
*/ */
public function today_species_by_date(Connection $connection, $date) public function today_species_by_date(Connection $connection, $date)
{ {
@ -69,6 +74,7 @@ class TodayController extends AbstractController
/** /**
* @Route("/today/{date}/species/{id}", name="today_species_id_and_date") * @Route("/today/{date}/species/{id}", name="today_species_id_and_date")
* @Route("/{_locale<%app.supported_locales%>}/today/{date}/species/{id}", name="today_species_id_and_date_i18n")
*/ */
public function today_species_by_id_and_date(Connection $connection, $date, $id) public function today_species_by_id_and_date(Connection $connection, $date, $id)
{ {
@ -141,4 +147,4 @@ class TodayController extends AbstractController
$result = $stmt->executeQuery(); $result = $stmt->executeQuery();
return $result->fetchAllAssociative(); return $result->fetchAllAssociative();
} }
} }

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="{{ app.request.locale }}">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title> <title>
@ -27,6 +27,7 @@
</div> </div>
</a> </a>
</header> </header>
{% include "utils/locale-switcher.html.twig" %}
<main> <main>
{% block content %} {% block content %}
<p>Welcome to BirdNET-stream !</p> <p>Welcome to BirdNET-stream !</p>

View File

@ -9,57 +9,51 @@
{% include 'utils/nav-item.html.twig' with { {% include 'utils/nav-item.html.twig' with {
route: 'home', route: 'home',
url: '/', url: '/',
name: 'Home'|trans text: 'Home'|trans
} %} } %}
{% include 'utils/nav-item.html.twig' with { {% include 'utils/nav-item.html.twig' with {
route: 'about', route: 'about',
url: '/about', url: '/about',
name: 'About'|trans text: 'About'|trans
} %} } %}
{% include 'utils/nav-item.html.twig' with { {% include 'utils/nav-item.html.twig' with {
route: 'today', route: 'today',
url: '/today', url: '/today',
name: "Today's Detections"|trans text: "Today's Detections"|trans
} %} } %}
{% include 'utils/nav-item.html.twig' with { {% include 'utils/nav-item.html.twig' with {
route: 'spectro', route: 'spectro',
url: '/spectro', url: '/spectro',
name: 'Live Spectrogram'|trans text: 'Live Spectrogram'|trans
} %} } %}
{% include 'utils/nav-item.html.twig' with { {% include 'utils/nav-item.html.twig' with {
route: 'stats', route: 'stats',
url: '/stats', url: '/stats',
name: 'Statistics'|trans text: 'Statistics'|trans
} %} } %}
<li class="dropdown"> <li class="dropdown">
{% include 'utils/nav-item.html.twig' with { {% include 'utils/nav-item.html.twig' with {
route: 'records', route: 'records',
url: '/records', url: '/records',
name: 'Recordings'|trans text: 'Recordings'|trans
} %} } %}
<ul class="dropdown-content"> <ul class="dropdown-content">
{% include 'utils/nav-item.html.twig' with { {% include 'utils/nav-item.html.twig' with {
route: 'bests', route: 'records_best',
url: '/records/best', url: '/records/best',
name: 'Best Recordings'|trans text: 'Best Recordings'|trans
} %} } %}
</ul> </ul>
</li> </li>
{% include 'utils/nav-item.html.twig' with {
route: 'bests',
url: '/records/best',
name: 'Best Recordings'|trans
} %}
{% include 'utils/nav-item.html.twig' with { {% include 'utils/nav-item.html.twig' with {
route: 'logs', route: 'logs',
url: '/logs', url: '/logs',
name: 'View Logs'|trans text: 'View Logs'|trans
} %} } %}
{% include 'utils/nav-item.html.twig' with { {% include 'utils/nav-item.html.twig' with {
route: 'status', route: 'services_status',
url: '/services/status', url: '/services/status',
name: 'Status'|trans text: 'Status'|trans
} %} } %}
</ul> </ul>
</div> </div>

View File

@ -0,0 +1 @@
<p>{{ "Not implemented yet"|trans </p>

View File

@ -0,0 +1,3 @@
{% block content %}
{{ "Not implemented yet"|trans }}
{% endblock %}

View File

@ -0,0 +1,28 @@
{% set current = app.request.get('_route')|replace({"_i18n": ""})~"_i18n" %}
{% macro lang_url(route, locale, name) %}
<a class="language-item"
href="{{
path(
route,
{
_locale: locale
}
)
}}">{{ name }}
</a>
{% endmacro %}
<li class="language-selector">
<label for="toggle" class="touch"
role="button">
{{ app.request.locale|locale_name(app.request.locale)|u.title }}
</label>
<input type="checkbox" name="dropdown-checkbox" class="toggle">
<ul class="slide">
<li>
{{ _self.lang_url(current, "en", "English") }}
</li>
<li>
{{ _self.lang_url(current, "fr", "Français") }}
</li>
</ul>
</li>

View File

@ -1,6 +1,6 @@
<li> <li>
<a class="{{ app.request.get('_route') matches '{' ~ route ~ '_*}' ? 'active' }}" <a class="{{ app.request.get('_route') matches '{' ~ route ~ '_*}' ? 'active' }}"
href="{{ url }}"> href="{{ path(route) }}">
{{ name }} {{ text }}
</a> </a>
</li> </li>

View File

@ -23,7 +23,7 @@
</trans-unit> </trans-unit>
<trans-unit id="1zd9FJ_" resname="This project is made with &amp;hearts; by Samuel ORTION."> <trans-unit id="1zd9FJ_" resname="This project is made with &amp;hearts; by Samuel ORTION.">
<source>This project is made with &amp;hearts; by Samuel ORTION.</source> <source>This project is made with &amp;hearts; by Samuel ORTION.</source>
<target><![CDATA[Ce projet est fait avec &hearts; par Samuel ORTION]]></target> <target>Ce projet est fait avec &amp;hearts; par Samuel ORTION.</target>
</trans-unit> </trans-unit>
<trans-unit id="wBHWCXv" resname="License"> <trans-unit id="wBHWCXv" resname="License">
<source>License</source> <source>License</source>
@ -37,6 +37,206 @@
<source>BirdNET-Analyzer, on which this project relies, is licensed under</source> <source>BirdNET-Analyzer, on which this project relies, is licensed under</source>
<target>BirdNET-Analyzer, sur qui ce projet repose, est sous licence</target> <target>BirdNET-Analyzer, sur qui ce projet repose, est sous licence</target>
</trans-unit> </trans-unit>
<trans-unit id="39aF.j_" resname="Frequency charts">
<source>Frequency charts</source>
<target>Graphe de fréquence</target>
</trans-unit>
<trans-unit id="SJtk1Aa" resname="No charts available">
<source>No charts available</source>
<target>Pas de graphe disponible</target>
</trans-unit>
<trans-unit id="OnhpU4i" resname="Home">
<source>Home</source>
<target>Accueil</target>
</trans-unit>
<trans-unit id="Lc4yjyd" resname="Today's Detections">
<source>Today's Detections</source>
<target>Détection aujourd'hui</target>
</trans-unit>
<trans-unit id="11.I7BE" resname="Live Spectrogram">
<source>Live Spectrogram</source>
<target>Spectrogramme en temps réel</target>
</trans-unit>
<trans-unit id="plYQfpn" resname="Statistics">
<source>Statistics</source>
<target>Statistiques</target>
</trans-unit>
<trans-unit id="YMVtZqE" resname="Recordings">
<source>Recordings</source>
<target>Enregistrements</target>
</trans-unit>
<trans-unit id="GiWvoLV" resname="Best Recordings">
<source>Best Recordings</source>
<target>Meilleurs Enregistrements</target>
</trans-unit>
<trans-unit id="4IfwRtw" resname="View Logs">
<source>View Logs</source>
<target>Voir les logs</target>
</trans-unit>
<trans-unit id="kg5BPH1" resname="Status">
<source>Status</source>
<target>Status</target>
</trans-unit>
<trans-unit id="mcQKtAW" resname="Date">
<source>Date</source>
<target>Date</target>
</trans-unit>
<trans-unit id="zFIH2Rd" resname="Enter a date in this format YYYY-MM-DD">
<source>Enter a date in this format YYYY-MM-DD</source>
<target>Entrez une date au format YYYY-MM-DD</target>
</trans-unit>
<trans-unit id="bMhRm5F" resname="Go">
<source>Go</source>
<target>Go</target>
</trans-unit>
<trans-unit id="6iEA3Im" resname="Logs">
<source>Logs</source>
<target>Logs</target>
</trans-unit>
<trans-unit id="yIMayeg" resname="No logs available">
<source>No logs available</source>
<target>Pas de logs disponible</target>
</trans-unit>
<trans-unit id="_RN0U0G" resname="Spectrogram">
<source>Spectrogram</source>
<target>Spectrogramme</target>
</trans-unit>
<trans-unit id="cOE9kUb" resname="Launch Live Spectrogram">
<source>Launch Live Spectrogram</source>
<target>Lancer le Spectrogramme en temps réel</target>
</trans-unit>
<trans-unit id="VF2TvYg" resname="No audio sources yet">
<source>No audio sources yet</source>
<target>Pas de source audio pour le moment</target>
</trans-unit>
<trans-unit id="b3yIXEw" resname="Quick Stats">
<source>Quick Stats</source>
<target>Statistiques rapides</target>
</trans-unit>
<trans-unit id="EVOzKuV" resname="Most recorded species">
<source>Most recorded species</source>
<target>Espèce la plus souvent enregistrée</target>
</trans-unit>
<trans-unit id="BpW1Y6z" resname="with">
<source>with</source>
<target>avec</target>
</trans-unit>
<trans-unit id="qlr0CE8" resname="contacts">
<source>contacts</source>
<target>contacts</target>
</trans-unit>
<trans-unit id="pHx6Sb8" resname="No species in database.">
<source>No species in database.</source>
<target>Aucune espèce dans la base de donnée.</target>
</trans-unit>
<trans-unit id="kbbkF9." resname="Last detected species">
<source>Last detected species</source>
<target>Dernière espèce détectée</target>
</trans-unit>
<trans-unit id="UfL722." resname="AI confidence">
<source>AI confidence</source>
<target>Niveau de confiance</target>
</trans-unit>
<trans-unit id="4PT3Z6y" resname="today">
<source>today</source>
<target>aujourd'hui</target>
</trans-unit>
<trans-unit id="uNMehSc" resname="on">
<source>on</source>
<target>le</target>
</trans-unit>
<trans-unit id="UXnWgGD" resname="No species in database">
<source>No species in database</source>
<target>Aucune espèce dans la base de données</target>
</trans-unit>
<trans-unit id="O.a8OVk" resname="Today's contacts for">
<source>Today's contacts for</source>
<target>Contacts d'aujourd'hui pour</target>
</trans-unit>
<trans-unit id="1XvGb5I" resname="Contacts on">
<source>Contacts on</source>
<target>Contacts le</target>
</trans-unit>
<trans-unit id="EMIrz0x" resname="for">
<source>for</source>
<target>pour</target>
</trans-unit>
<trans-unit id="tKc2V0D" resname="Stats">
<source>Stats</source>
<target>Stats</target>
</trans-unit>
<trans-unit id="j93Wzbi" resname="Contact count:">
<source>Contact count:</source>
<target>Nombre de contact:</target>
</trans-unit>
<trans-unit id="ALgyC6W" resname="Max confidence">
<source>Max confidence</source>
<target>Niveau de confiance maximal</target>
</trans-unit>
<trans-unit id="WTXVn0G" resname="Contact records">
<source>Contact records</source>
<target>Enregistrement du contact</target>
</trans-unit>
<trans-unit id="lxuXQjW" resname="Filename">
<source>Filename</source>
<target>Fichier</target>
</trans-unit>
<trans-unit id="M7k0ds9" resname="Time">
<source>Time</source>
<target>Heure</target>
</trans-unit>
<trans-unit id="ZCLj549" resname="Confidence">
<source>Confidence</source>
<target>Confiance</target>
</trans-unit>
<trans-unit id="vBuIkH0" resname="Audio">
<source>Audio</source>
<target>Audio</target>
</trans-unit>
<trans-unit id="I3eaEC5" resname="Select this record">
<source>Select this record</source>
<target>Sélectionner cet enregistrement</target>
</trans-unit>
<trans-unit id="NBh3Jvf" resname="Download audio file">
<source>Download audio file</source>
<target>Télécharger le fichier audio</target>
</trans-unit>
<trans-unit id="gp0zWYd" resname="No records this day for this species">
<source>No records this day for this species</source>
<target>Pas d'entrement ce jour pour cette espèce</target>
</trans-unit>
<trans-unit id="H8mjh2V" resname="Select all">
<source>Select all</source>
<target>Séléctionner tout</target>
</trans-unit>
<trans-unit id="0qtdRv7" resname="Delete selected">
<source>Delete selected</source>
<target>Supprimer la sélection</target>
</trans-unit>
<trans-unit id="XdPmSCB" resname="Today's detected species">
<source>Today's detected species</source>
<target>Espèces détectées aujourd'hui</target>
</trans-unit>
<trans-unit id="ujkYinn" resname="Detected species on">
<source>Detected species on</source>
<target>Espèces détectées le</target>
</trans-unit>
<trans-unit id="tZEkkkO" resname="No species detected this day">
<source>No species detected this day</source>
<target>Aucune espèce détectée ce jour</target>
</trans-unit>
<trans-unit id="AmHJKRh" resname="Services status">
<source>Services status</source>
<target>Status des services</target>
</trans-unit>
<trans-unit id="hb1Ij3K" resname="No status available">
<source>No status available</source>
<target>Aucun status disponible</target>
</trans-unit>
<trans-unit id="OzJoKh6" resname="Welcome to BirdNET-stream !">
<source>Welcome to BirdNET-stream !</source>
<target>Bienvenue sur BirdNET-stream !</target>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>